# Red de prestadores de servicios en web_mycode

Fecha: 2026-07-27

## Objetivo

Integrar en `web_mycode` toda la red de prestadores ya disponible en
`api_mycode`, en este orden:

1. portal privado para propietarios de prestadores;
2. moderación y catálogos en el panel administrativo;
3. directorio y mapa públicos.

La implementación debe conservar el login clásico de los usuarios, el login
administrativo separado y la arquitectura Clean/MVVM definida por el
proyecto.

## Alcance funcional

### Portal del prestador

El propietario usa una cuenta clásica con rol `user`. El portal incluye:

- acceso con correo y contraseña;
- segundo factor TOTP y código de recuperación;
- registro, verificación de correo y recuperación de contraseña;
- creación y edición del perfil comercial;
- asignación de categorías;
- creación y edición de sucursales;
- selección de ubicación en mapa;
- servicios, especialidades y características por sucursal;
- horarios normales y excepciones;
- contactos públicos y privados;
- logo, portada e imágenes;
- envío de verificaciones y documentos;
- vista previa y envío del prestador a revisión;
- visualización de estado, rechazo, suspensión y nivel de verificación.

El inicio de sesión social con Google o Apple no forma parte de esta entrega.
El API seguirá soportándolo y podrá agregarse después sin modificar la sesión
del portal.

### Panel administrativo

El panel existente incorpora:

- listado paginado de prestadores;
- filtros por estado, verificación, tipo, alcance, categoría, región, comuna,
  fecha y texto;
- ficha administrativa completa;
- aprobación, rechazo, suspensión, restauración y verificación;
- historial de cambios de estado;
- revisión de verificaciones;
- descarga protegida de documentos;
- CRUD de categorías, servicios, especialidades y características;
- visibilidad y habilitación de acciones según permisos administrativos.

### Directorio público

El sitio público incorpora:

- listado paginado de prestadores publicados;
- búsqueda textual y filtros de catálogo;
- filtros por región, comuna, verificación, emergencia, abierto ahora,
  atención 24 horas y atención domiciliaria;
- búsqueda por cercanía con radios de 5, 10, 25, 50, 100 y 200 km;
- resultados sincronizados con marcadores del mapa;
- ficha pública de sucursal;
- horarios, servicios, características, imágenes y contactos;
- enlaces de llamada, WhatsApp, web y navegación.

El API continúa siendo la autoridad para decidir qué prestadores y sucursales
pueden publicarse.

## Enfoques considerados

### BFF Laravel, Blade y JavaScript modular

Es el enfoque seleccionado. Mantiene los JWT en la sesión del servidor,
reutiliza los patrones actuales de `AdminSessionManager`,
`ApiMyCodeHttpClient` y bridges, y permite render inicial para SEO.

### SPA con JWT en el navegador

Reduciría algunas rutas web, pero expondría el token al contexto JavaScript,
duplicaría manejo de autenticación y contradiría la seguridad actual.

### Frontend nuevo en Vue o React

Facilitaría estados complejos, pero exigiría una reescritura, nuevas
dependencias y dos arquitecturas de frontend. No se justifica para esta
integración.

## Arquitectura

Las dependencias respetarán:

`Presentation -> Application -> Domain <- Infrastructure`

### Presentación

Se agregarán controladores delgados bajo:

- `app/Presentation/Http/Controllers/Web` para directorio y portal;
- `app/Presentation/Http/Controllers/Bridge` para operaciones BFF;
- `app/Presentation/Http/Controllers/Admin` para shells administrativas.

Las vistas Blade serán shells y componentes. La lógica de formulario, mapa y
estado vivirá en módulos JavaScript y las reglas de negocio en Application.

### Aplicación

Casos de uso separados cubrirán:

- inicio y cierre de sesión del prestador;
- verificación de segundo factor;
- registro y verificación de correo;
- consulta del prestador propio;
- normalización de respuestas y errores del API;
- construcción de consultas públicas;
- autorización de rutas permitidas en los bridges;
- adaptación de cargas JSON y multipart.

Cada clase tendrá una responsabilidad y los archivos nuevos se mantendrán
preferentemente bajo 150 líneas.

### Dominio

Objetos y enumeraciones locales expresarán:

- estados del prestador;
- tipos y niveles de verificación;
- radios de búsqueda;
- permisos administrativos de prestadores;
- rutas y operaciones permitidas.

No se duplicarán las reglas de publicación ni la persistencia del API.

### Infraestructura

`ApiMyCodeHttpClient` se ampliará mediante componentes enfocados para:

- requests JSON autenticados;
- descargas binarias;
- uploads multipart con streams;
- propagación segura de cabeceras necesarias;
- timeouts y normalización de fallos de conexión.

No se reenviarán cookies, cabeceras arbitrarias ni rutas proporcionadas
libremente por el navegador.

## Autenticación y sesiones

### Prestadores

Se creará una sesión web independiente de la administrativa:

- `provider_api_token`;
- `provider_user`;
- datos temporales de 2FA limitados a la sesión.

El flujo será:

1. el navegador envía credenciales al controlador web;
2. `web_mycode` llama a `POST /auth/login`;
3. si el API responde `requires_2fa`, se guarda el token temporal y se pide
   TOTP o recuperación;
4. al verificar, el JWT definitivo se guarda en la sesión del servidor;
5. el navegador recibe únicamente el usuario sanitizado y el estado;
6. los bridges agregan `Authorization: Bearer` al llamar al API.

La sesión se regenera al iniciar sesión y se invalida al cerrar sesión. Un JWT
inválido o expirado limpia la sesión.

### Administradores

Se conserva `/admin/login` y `AdminSessionManager`. Las funciones de
prestadores se agregan al panel existente y usan exclusivamente la sesión
administrativa.

### Seguridad

- ningún JWT se escribe en HTML, logs, `localStorage` o `sessionStorage`;
- todas las mutaciones web requieren CSRF;
- se validan método, ruta, identificadores y payload antes de hacer proxy;
- las descargas de verificaciones requieren sesión y permiso;
- los errores upstream se filtran antes de responder al navegador;
- 401 cierra sesión; 403 muestra suspensión o falta de permiso; 422 se
  asocia a campos; 429 conserva `Retry-After`; 5xx usa un mensaje neutro.

## Rutas web y bridges

### Portal

- `/mi-prestador/login`
- `/mi-prestador/registro`
- `/mi-prestador/verificar-email`
- `/mi-prestador/recuperar-clave`
- `/mi-prestador/2fa`
- `/mi-prestador`
- `/mi-prestador/perfil`
- `/mi-prestador/sucursales`
- `/mi-prestador/sucursales/{location}`
- `/mi-prestador/revision`

Las rutas privadas usan middleware de sesión del prestador.

### Bridge del prestador

Las rutas bajo `/api/bridge/provider` representan operaciones concretas y no
un proxy genérico. Cubren perfil, categorías, sucursales, operaciones de
sucursal, contactos, medios, imágenes, verificaciones y envío a revisión.

### Administración

- `/admin/service-providers`
- `/admin/service-providers/{provider}`
- `/admin/service-provider-verifications/{verification}`
- `/admin/service-catalogs`

El bridge administrativo expone únicamente endpoints de moderación,
verificación, documentos y catálogos.

### Público

- `/prestadores`
- `/prestadores/cerca`
- `/prestadores/{location}`

El listado y la ficha tienen render inicial en servidor. Las búsquedas
dinámicas usan endpoints web públicos controlados que consultan al API.

## Experiencia del portal

El portal usa un flujo por etapas, con navegación persistente y guardado por
sección:

1. identidad comercial;
2. categorías;
3. sucursales;
4. servicios y atributos;
5. horarios y excepciones;
6. contactos y medios;
7. verificaciones;
8. revisión y envío.

Cada etapa muestra completitud y errores. No se requiere terminar una etapa
para guardar otra, salvo cuando el API necesita primero el identificador del
prestador o sucursal.

Estados:

- `draft`: editable y enviable a revisión;
- `pending_review`: editable según lo permitido por el API, con aviso;
- `published`: publicado y editable;
- `rejected`: editable, muestra motivo y permite reenviar;
- `suspended`: lectura y aviso de suspensión, sin acciones no permitidas.
- `archived`: lectura histórica, sin acciones de publicación.

## Mapas y ubicación

Se conservará Google Maps para ser consistente con las páginas existentes.
La clave pasará a `GOOGLE_MAPS_API_KEY` y a configuración Laravel; no quedará
escrita directamente en Blade.

El portal tendrá selector de marcador y geocodificación. El directorio tendrá
marcadores, ajuste de viewport, selección sincronizada con tarjetas y
geolocalización opcional. Si el usuario deniega ubicación, el directorio
seguirá funcionando con filtros manuales.

Si falta la clave, las páginas siguen mostrando listado, dirección y filtros;
solamente se reemplaza el mapa por un aviso no bloqueante.

## Catálogos

El frontend cargará los catálogos desde
`/api/v1/public/service-catalogs/{catalog}`. Los formularios conservarán los
campos pivot definidos por el API:

- categoría principal;
- disponibilidad, precios, moneda, cita y notas de servicios;
- valores tipados de características.

Las dependencias categoría/subcategoría y alcance se aplicarán en la interfaz,
pero el API seguirá validando la autoridad final.

## Archivos

- logo: JPG, PNG o WebP hasta 4 MB;
- portada e imágenes: JPG, PNG o WebP hasta 8 MB;
- verificación: PDF, JPG o PNG hasta 10 MB.

La validación del navegador mejora la experiencia, pero no reemplaza la del
servidor. Los uploads se enviarán como multipart mediante streams y nunca se
serializarán dentro de JSON cifrado.

## Accesibilidad, idioma y responsive

- español e inglés mediante archivos `resources/lang`;
- etiquetas, errores y estados traducidos;
- navegación por teclado;
- foco visible y anunciado después de errores;
- controles de mapa con alternativa textual;
- tablas administrativas adaptadas a tarjetas en pantallas pequeñas;
- contraste y estados no dependientes solamente del color.

## Pruebas

La implementación seguirá ciclos TDD.

### PHP

- unidad para sesiones, rutas permitidas, payloads y normalizadores;
- feature para login, 2FA, registro y cierre de sesión;
- feature para protección de portal y bridges;
- feature para moderación, permisos y descargas;
- feature para directorio, filtros, SEO y degradación sin mapa;
- validación explícita de que ningún JWT aparece en respuestas.

### JavaScript

- estado y navegación del portal;
- construcción de payloads;
- filtros del directorio;
- sincronización lista/mapa;
- acciones administrativas;
- manejo de errores y sesión expirada.

### Gates

- `php artisan test`;
- `php artisan architecture:audit --strict`;
- suites JavaScript;
- `npm run production`;
- inspección de tamaño de archivos;
- prueba de navegador de los tres flujos principales.

## Entrega y versión

La implementación se hará en `codex/service-provider-network-web`, aislada de
los cambios locales existentes en `public/`.

Los commits intermedios mantienen `VERSION=1.1.3`. La entrega completa cambia
la versión a `1.2.0`, porque agrega funcionalidad pública y privada nueva sin
romper contratos existentes.

No se desplegará ni se fusionará en `master` hasta que todas las verificaciones
pasen. La integración preservará los cambios locales del checkout principal.

## Criterios de aceptación

La entrega está completa cuando:

1. un usuario clásico puede registrarse, verificar su correo, iniciar sesión
   con o sin 2FA y administrar todo su prestador;
2. puede enviar el prestador a revisión y ver su estado;
3. un administrador autorizado puede revisar, moderar, verificar y administrar
   catálogos;
4. el público puede buscar prestadores, usar filtros y mapa, y abrir una ficha;
5. los JWT permanecen únicamente en sesiones del servidor;
6. no queda ninguna clave de Google Maps escrita en el código;
7. todos los gates de pruebas, arquitectura y build pasan;
8. `VERSION` queda en `1.2.0`.
