- deny() now marks is_active:false instead of deleting the record
- New GET /professionals/rejected endpoint (pro_state:3)
- findPendingApprovals now filters only pro_state:1
- Admin list: third tab 'No aprobados' with approve/review actions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: deactivate and set-pending endpoints for status control
- Admin detail: Aprobar/Rechazar/Desactivar/En revisión buttons based on current state
- Admin detail: Documentos section showing ID photo and certificate
- Admin detail: deny now confirms before deleting
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: include email and phone in users select for professionals
- Admin detail page: RETHUS section shows cedula+code with copy buttons
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Detail page: use Number() before toFixed() since Prisma returns Decimal objects
- Service upsert: create professionals with is_active:false so they appear as pending
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Flutter reads 'professional_state' but Prisma returns 'pro_state'.
Add professional_state alias in me() response so proState is read correctly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PATCH /professionals/me now works for first-time submissions.
Creates the record with pro_state=1 if user has no professional entry.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- schema.prisma: modelo message_logs (channel, recipient, body, status, error)
- email-otp.service.ts: lee config SMTP desde DB (settings.smtp_config), registra log en message_logs
- sms.service.ts: registra log en message_logs tras cada envío (éxito y error)
- auth.module.ts: agrega PrismaModule, JWT expira en 90d
- settings.controller.ts: GET/PATCH /settings/smtp + GET /settings/message-logs
- settings.service.ts: método getMessageLogs con paginación y filtro por canal
- settings.module.ts: importa AuthModule + EmailOtpService
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- schema.prisma: url = env("DATABASE_URL") era requerido por prisma migrate deploy
- Dockerfile: cambiar && por ; para que el servidor arranque aunque migrate falle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Prisma schema: rethus_code y rethus_validated en tabla professionals
- Migración 0001: ALTER TABLE agrega ambas columnas
- DTO: rethus_code y rethus_validated en CreateProfessionalDto y UpdateProfessionalDto
- Service: nuevo método validateRethus, rethus_code incluido en requestProfessional
- Controller: endpoint POST /professionals/:id/validate-rethus (JWT protegido)
- Admin listado pendientes: columna RETHUS con ícono verde/amarillo y enlace al detalle
- Admin detalle profesional: card de validación RETHUS con botón consultar Minsalud y marcar como validado
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /settings retorna {} en lugar de undefined cuando no hay configuracion
(evita error jsonDecode en Flutter que dejaba soporte en gris)
- Autocomplete: agrega components=country:co, radius 20km, remove types=address
para mostrar mas resultados cercanos al usuario
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend: agrega PATCH /users/:id y PATCH /professionals/:id (protegidos).
Admin: pagina de usuario con edicion de nombre/telefono/ciudad/genero;
pagina de profesional con dos secciones editables independientes
(datos personales y perfil profesional).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: GET /settings/maps-key (public) + PATCH /settings/maps (protected)
- Admin: sección para guardar/ver estado de la Maps API key
- Flutter web carga la key dinámicamente desde el backend
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- CRUD completo para countries, regions y cities
- GET /settings/policy/:key — página HTML pública para políticas
- GET/PATCH /settings/policies/:key — admin endpoints protegidos
Admin:
- /locations: árbol interactivo País → Región → Ciudad con add/edit/delete
- /settings: editor de Política de Privacidad y Términos con enlace público copiable
- Sidebar: Ciudades → Ubicaciones
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Flutter client calls jsonDecode on response body — empty void response
throws FormatException even when SMS was sent successfully.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- Add SmsService + SmsModule: send OTP via u-site.app provider, 5-min TTL
- Auth endpoints: POST /auth/send-otp, POST /auth/phone (login by phone+code),
POST /auth/verify-phone (link), PATCH /auth/change-password
- is_phone_verified included in JWT token response
- GET /comments (admin, JWT-protected) with author/destination names
Admin:
- Users list: link to detail page per row
- User detail: inline edit form (name, city, phone) with PATCH /users/:id
- Services list: link to detail page per row
- Service detail: status change dropdown (PATCH /services/:id/status)
- New Comments page: summary stats + full table with star ratings
- New SMS settings page: configure API key + send test SMS
- Sidebar: added Comments and SMS entries
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- services.module: import NotificationsModule
- services.service: inject NotificationsService, notify the other party
(user or professional) when service status changes to accepted/denied/
cancelled/active/completed
- ARQUITECTURA.md: updated to reflect current migration state (all migrated)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>