Commit Graph
67 Commits
Author SHA1 Message Date
Lizandro GuarnizoandClaude Sonnet 4.6 86c6f3e6b7 Add persistent volume for uploads to survive redeployments
Files uploaded by users were lost on every container rebuild.
Named volume uploads_data mounts to /app/uploads and is managed by Coolify.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 17:55:29 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 aa241d733d Set STORAGE_URL so uploaded files get public URLs
Without this, files were saved with http://localhost:3000/uploads/... URLs
which are unreachable from the browser. Now uses the public backend domain.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 17:54:21 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 7935e48fae Add status management and documents view to pro detail page
- 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>
2026-06-28 17:49:28 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 efb48e017f Show email/phone in pro detail and improve RETHUS section
- 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>
2026-06-28 17:47:01 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 f845350911 Fix Decimal.toFixed crash and new professionals default is_active
- 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>
2026-06-28 17:39:56 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 053f2d0b56 Fix pro_state field name mismatch in /auth/me response
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>
2026-06-28 17:38:10 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 5380a894b1 Fix useParams null crash on detail pages
useParams() can return null during SSR — destructuring null throws TypeError.
Use optional chaining params?.id to prevent the crash.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 17:35:42 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 d1f93d6d13 Add Ver button to active professionals in admin list
Active professionals now have a link to the detail page where
they can be edited, RETHUS validated, etc.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 17:27:59 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 d551739d0c Fix upsert: create professional record if none exists
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>
2026-06-28 17:20:35 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 ce769dfe8d Fix professional 500 error, add SMTP config UI and message history page
- Fix route ordering in professionals.controller: PATCH me was captured by PATCH :id causing 500
- Admin settings: add SMTP email config section (host, port, user, pass, sender)
- Admin sidebar: add Mensajes link
- Admin: new /mensajes page with SMS/email history, channel filter and pagination

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 17:08:59 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 6da45ac9d1 chore: JWT expira en 365 días (1 año)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 11:38:59 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 30588effec feat: endpoint GET /locations/cities/all para lista plana de ciudades
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 11:38:26 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 522adc3b74 feat: SMTP config en DB, historial mensajes, JWT 90d, email OTP con Prisma
- 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>
2026-06-28 11:35:17 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a9b5e413e3 feat: página admin /admin-sugerencias + enlace en sidebar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 19:46:30 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 8a1f9687cd feat: filtrar profesionales por ciudad con query param ?city=
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 19:26:33 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 f94c2f96b0 fix: POST /suggestions requiere JWT (solo usuarios autenticados)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 19:23:20 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 c919bb737f fix: reemplazar Textarea (no existe) con textarea nativo en página sugerencias
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 19:19:52 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 42d41eb199 feat: módulo de sugerencias (backend) + página pública /sugerencias (admin)
- Backend: POST /suggestions (público) + GET /suggestions (JWT admin)
- Admin: página pública /sugerencias con formulario de sugerencias
- schema.prisma: modelo suggestions
- AuthGuard + Sidebar: /sugerencias como ruta pública

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 19:05:58 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 4e932c2347 revert: quitar url del datasource que rompió prisma generate en build
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 18:56:00 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a7562bca71 fix: quitar dummy URL de prisma generate, no necesita conexión real
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 18:54:46 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 446c79fbfe fix: quitar prisma migrate deploy del CMD, se corre manualmente
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 18:53:07 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 8c05b09f28 fix: prisma generate usa DATABASE_URL dummy en build (no necesita conexión real)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 18:52:47 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 21d7707bc0 fix: agregar DATABASE_URL al datasource de Prisma y CMD no-fatal para migrate
- 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>
2026-06-27 18:50:44 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 f2bd710694 fix: correr prisma migrate deploy al arrancar el servidor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 18:29:56 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 c1e9dba2d1 feat: campo RETHUS con validación manual desde el admin
- 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>
2026-06-27 18:23:55 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 46fcb57edf fix: settings siempre retorna objeto, autocomplete Colombia con bias de ubicacion
- 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>
2026-06-27 10:11:13 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 f66b1a9bc1 fix: agregar campos soporte faltantes en admin settings
- support_title, support_description, support_days, support_hours
  (los que lee la app Flutter para la pantalla de soporte)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 09:54:16 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 7e68fcc2bb feat: email OTP para vincular correo al perfil
- EmailOtpService: genera/verifica codigo 6 digitos via SMTP
  (requiere env vars: SMTP_HOST, SMTP_USER, SMTP_PASS, EMAIL_FROM)
- POST /auth/send-email-otp: envia codigo al correo indicado
- POST /auth/link-email-otp: verifica codigo y vincula email+pass
- nodemailer agregado como dependencia

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 09:35:01 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 d3ca99fa1b feat: agregar endpoint /autocomplete en admin Next.js
Proxy a Google Places Autocomplete API:
- Lee la API key de /settings/maps-key del backend
- Acepta params: input, location
- Devuelve { results: [{ formatted_address, place_id }] }
- Headers CORS para permitir acceso desde app.prosapp.co

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 08:51:51 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 abc19505ae feat: edicion de usuarios y profesionales desde el admin
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>
2026-06-27 08:22:40 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 e7afbf6d7b feat: restore global settings with proper fields in settings page
Restores: version Android/iOS, horario soporte, email/telefono soporte,
modo mantenimiento. Organizado en secciones: Ajustes generales,
Integraciones (Maps), Documentos legales.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 08:02:29 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 3e1632e776 feat: Google Maps API key management in admin settings
- 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>
2026-06-27 07:59:19 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 39c4301d1b feat: full locations CRUD + legal policies in settings
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>
2026-06-27 07:45:53 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 5c740420e9 fix: return JSON body from send-otp endpoint
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>
2026-06-26 22:11:29 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a067e5d260 fix: handle network errors and non-JSON SMS responses as 400 not 500
Catch fetch network errors and non-JSON response bodies to prevent
unhandled exceptions from becoming opaque 500s.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 19:21:18 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 5c3e3c4bc8 fix: handle null in service status select onValueChange
TypeScript error: Select onValueChange passes string | null, not string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 16:44:49 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a81a01a06d feat: use real ProsApp logo in admin login and sidebar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 16:15:05 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 a5c1dd7c33 feat: improve admin login UI and sidebar branding
- Login page: split layout with gradient panel (desktop) + form,
  ProsApp logo mark, feature list, consistent blue brand colors
- Sidebar: replace plain text with logo mark + brand name

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 16:12:56 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 7783cac3fe feat: SMS OTP auth, phone verification gate, admin comments/edit/status pages
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>
2026-06-25 15:53:32 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 1c2f0ca71a fix: strip leading + from phone number before sending to SMS provider
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 15:26:57 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 6e4cc7436d feat: send FCM push notification on service status change + update docs
- 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>
2026-06-18 12:49:27 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 130e52ddcd fix: align Flutter API repositories with backend routes (Fase 3 prep)
- api_service_repository: use correct endpoints (services/me, services/professional,
  professional/requests, professional/history, professional/calendar, etc.)
  instead of generic /services?userId= query params
- api_service_repository: fix status conversion string↔enum, createService DTO fields,
  handle paginated {data,meta} response, stub setProfessionalScored/setUserScored
  (backend sets these automatically on POST /comments)
- api_score_repository: fix comment endpoints to /comments/user/:id and
  /comments/professional/:id; handle paginated response
- api_professional_repository + api_user_repository: handle paginated {data,meta}
  response from GET /professionals

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 18:23:14 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 e3e9509222 fix: pin PORT per service to isolate from global Coolify env var
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 09:23:05 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 d0e70dff0a fix: map admin port 5173:3001 to match Next.js runtime port
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 09:18:51 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 5d263aab96 fix: map backend port 3001:3001 to match app runtime port
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 09:15:02 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 34ee7be531 fix: correct EXPOSE port to 3001 to match app runtime port
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 08:54:20 -05:00
Lizandro Guarnizo ac7fe193cd hola 2026-06-17 07:47:29 -05:00
Lizandro GuarnizoandClaude Haiku 4.5 3fa0f5bd5f fix: add Tailwind CSS config to enable style compilation
Tailwind CSS 4 requires explicit content paths configuration. Without this,
the @tailwindcss/postcss plugin cannot find files to process, preventing
styles from being generated for the admin interface.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-16 22:28:40 -05:00
Lizandro Guarnizo e4799a8bf7 style: apply ProsApp brand color #26b5f0 to admin theme 2026-06-04 08:58:16 -05:00
Lizandro Guarnizo 668aa152bf fix: add admin.prosapp.co to CORS allowed origins 2026-06-04 08:46:18 -05:00