# Handoff tecnico para siguiente IA

Este documento resume el estado real del proyecto `MallorcaTrabaja`, lo ya implementado, lo pendiente y como continuar sin romper compatibilidad.

## 1) Estado actual del proyecto

### Stack operativo
- Backend: Laravel 12 + Sanctum + API REST (`/api/v1`)
- DB: MySQL/MariaDB (tests con sqlite in-memory)
- Web: Blade + Bootstrap, con auth web real para `/admin/*`
- Pagos: Stripe Checkout real via `stripe/stripe-php` con fallback local
- Push: HTTP v1 FCM (Firebase Cloud Messaging) con log-only mode
- Mobile: Flutter 3.44.0 con app shell (6 tabs: empleos, postulaciones, housing, rutas, servicios, mensajes), sesion segura, pago E2E, chat REST
- SDK Flutter instalado en `C:\dev\flutter` (PATH de usuario configurado)

### Fases ya ejecutadas
- Fase 1: usuarios/auth, empleos, habitaciones, compartir coche
- Fase 2: matching/scoring, recomendaciones, notificaciones base
- Fase 3:
  - marketplace de servicios y comisiones
  - moderacion antifraude, reportes y configuracion editable
  - tickets internos con SLA, comentarios timeline y kanban
- Fase 3 (extensiones historicas):
  - adjuntos seguros tickets/fraud + escalado SLA (database + mail markdown)
  - tablero admin avanzado, KPI SLA, export CSV
  - auth web real para `/admin/*`
  - vista detalle ticket admin + vista auditoria filtrable
  - comando `attachments:prune`
  - scaffolding pagos Stripe (gateway, HMAC, webhook, modelo `Payment`)
  - Flutter primer flow E2E (login + listado + detalle + apply)
- Fase 3 (cerrada EN ESTE handoff):
  - **Stripe production-ready**: `composer require stripe/stripe-php` instalado, `StripePaymentGateway::createCheckoutSession()` llama a `\Stripe\Checkout\Session::create()` cuando `STRIPE_SECRET` empieza con `sk_`; fallback automatico a session local `cs_local_*` si la API falla o no esta configurada. Verificacion de webhook ya era compatible.
  - **PushNotificationDispatcher** (FCM HTTP v1): `App\Services\Push\PushNotificationDispatcher` envia notifs a todos los `DeviceToken` de un usuario, limpia tokens `404/410` (NotRegistered), y entra en modo `log-only` si `FCM_PROJECT_ID`/`FCM_ACCESS_TOKEN` no estan configurados. Integrado en `support:notify-sla-overdue` para envios overdue y escalados.
  - **Flutter SDK 3.44.0** instalado y verificado: `flutter pub get`, `flutter analyze` (0 issues) y `flutter test` (1/1) verdes.
  - **TokenStorage seguro**: migrado a `flutter_secure_storage ^9.2.4` (Keychain iOS, Keystore Android, libsecret Linux). Migracion automatica de tokens legacy en `SharedPreferences`.
  - **Detalle habitacion + ruta** con tap desde el listado, info del propietario/conductor y boton `Copiar contacto` (Clipboard).
  - Mock channel del secure storage en widget tests para que `flutter test` corra sin device.

## 2) Rutas y modulos clave (estado actual)

### API publica (`/api/v1`, sin auth)
- `POST /register`, `POST /login`
- `POST /payments/webhook` (firma `Stripe-Signature` HMAC-SHA256 requerida)

### API auth Sanctum (`auth:sanctum`)
- `POST /logout`, `GET /me`
- `apiResource jobs` + `POST /jobs/{job}/apply` + `GET /my/job-applications`
- `apiResource housing-listings`
- `apiResource ride-offers`
- `service-categories`, `service-companies`, `service-offers`, `service-requests`, `service-matches`
- `recommendations` + `POST /recommendations/generate`
- Pagos: `POST /payments/initiate`, `GET /payments/{payment}`
- Device tokens: `POST /device-tokens`, `DELETE /device-tokens`
- `support-tickets` + comentarios + adjuntos
- `fraud-reports` + adjuntos

### API admin metricas y moderacion
- `GET /admin/kpis/services`, `/commissions`, `/support-tickets`
- `GET /admin/support-tickets/export.csv`
- `GET /admin/moderation/service-requests`
- `POST /admin/moderation/service-requests/{id}/review`
- `GET /admin/moderation/audit-logs`
- `GET|PUT /admin/fraud-config`

### Rutas web publicas
- `GET /` (HomeController)
- `GET /payments/return?session=...` (confirmacion humana tras checkout)

### Rutas web admin (auth `web` + `EnsureUserHasAdminRole`)
- `GET|POST /admin/login`, `POST /admin/logout`
- `GET /admin/dashboard`
- `GET /admin/support-tickets-board`
- `GET /admin/support-tickets/{ticket}` (detalle con timeline)
- `POST /admin/support-tickets/{ticket}/comments`
- `POST /admin/support-tickets/{ticket}/comments/{comment}/attachments`
- `GET /admin/support-tickets/{ticket}/attachments/{attachment}/download`
- `GET /admin/audit-logs`

### Comandos artisan
- `php artisan support:notify-sla-overdue` (cada 30 min, ahora con push FCM ademas de database + mail)
- `php artisan attachments:prune [--dry-run] [--disk=local]` (diario 03:30 dry-run)

## 3) Modelo de dominio

Entidades:
- Empleo: `Job`, `JobApplication`
- Vivienda: `HousingListing`
- Movilidad: `RideOffer`
- Marketplace: `ServiceCategory`, `ServiceCompany`, `ServiceOffer`, `ServiceRequest`, `ServiceMatch`
- Pagos: `Payment`
- Push: `DeviceToken`
- Soporte: `SupportTicket`, `SupportTicketComment`, `SupportTicketCommentAttachment`
- Antifraude: `FraudReport`, `FraudReportAttachment`
- Gobernanza: `ModerationAuditLog`, `PlatformSetting`

Servicios de negocio:
- `App\Services\Matching\MatchScoringService`
- `App\Services\Matching\RecommendationService`
- `App\Services\Marketplace\ServiceMarketplaceService`
- `App\Services\Marketplace\ServiceFraudDetectionService`
- `App\Services\Marketplace\FraudConfigService`
- `App\Services\Moderation\ModerationAuditService`
- `App\Services\Storage\SecureAttachmentStorage`
- `App\Services\Support\SupportTicketSlaService`
- `App\Services\Support\SupportTicketQueryService`
- `App\Services\Support\SupportTicketKpiService`
- `App\Services\Payments\PaymentGateway` (interface)
- `App\Services\Payments\StripePaymentGateway` (conectado a Stripe real con fallback)
- `App\Services\Push\PushNotificationDispatcher` (NUEVO: FCM HTTP v1)

## 4) Convenciones (no romper)

- Roles aceptados: `trabajador`, `empresa`, `propietario`, `proveedor_servicios`, `administrador`, `moderador` (alias `admin` aceptado).
- Respuestas API en JSON en `/api/*`, EXCEPTO:
  - `*/download` (binario)
  - `*.csv` (text/csv)
  - rutas con `Content-Type: application/json` entrante (webhooks)
- Validaciones via `FormRequest`.
- Auditoria en `moderation_audit_logs` para acciones sensibles.
- Storage privado disk `local` en path `{module}/{entity_id}/{uuid}.{ext}`.
- Auth web admin con guard `web`, redirect a `route('admin.login')` para guests.
- Pagos:
  - `Payment::STATUS_PENDING|PAID|FAILED|REFUNDED`.
  - `StripePaymentGateway::isLiveMode()` -> true si `secret` empieza por `sk_`.
  - Si la API real de Stripe falla, fallback a `cs_local_*` y se loguea warning.
  - Webhook firmado HMAC-SHA256 (mismo esquema que Stripe).
- Push:
  - Si `FCM_PROJECT_ID` y `FCM_ACCESS_TOKEN` ausentes -> log-only.
  - Status 404/410 limpia el `DeviceToken` automaticamente.
  - El access token se asume OAuth2 valido; integrar `google/auth` o `kreait/firebase-php` para refresh.
- Device tokens: `platform` permitido `android|ios|web`, `(user_id, token)` unique.

## 5) Estado de calidad

- Tests backend: **92 verdes** (registro seguro, perfil, portal web, ranking Fase 4).
- Pint sin diferencias.
- Flutter analyze: **No issues found**.
- Flutter test: 1/1 verde (widget test gate).
- Rutas registradas y funcionales.

Comandos utiles:
- `php artisan test`
- `vendor/bin/pint --test`
- `php artisan route:list`
- `php artisan support:notify-sla-overdue`
- `php artisan attachments:prune --dry-run`
- `flutter pub get` / `flutter analyze` / `flutter test` desde `mobile_app/`

## 6) App Flutter

Estructura `mobile_app/lib/`:
- `main.dart` - bootstrap providers + `_AuthGate`.
- `src/core/api_client.dart` - HTTP cliente con Bearer, `setOnUnauthorized`, endpoints jobs/housing/rides/servicios/pagos/device-tokens.
- `src/core/token_storage.dart` - `flutter_secure_storage` con migracion legacy.
- `src/core/auth_controller.dart` - restore + login/logout + hook 401 + registro push.
- `src/core/push_registration_service.dart` - Firebase Messaging opcional + `POST /device-tokens`.
- `src/features/auth/login_page.dart`.
- `src/features/shell/app_shell.dart` - NavigationBar 6 tabs + acceso a recomendaciones.
- `src/features/jobs/`: jobs_page, jobs_controller, job_detail_page, my_applications_page.
- `src/features/housing/`: housing_page, housing_detail_page.
- `src/features/rides/`: rides_page, ride_detail_page.
- `src/features/services/`: services_page (listado propias), service_request_create_page (formulario) y payment_status_page (abre checkout + consulta estado).
- `src/features/chat/`: conversations_page, chat_thread_page (polling), contact_chat (abrir chat desde detalle).
- `src/features/recommendations/`: recommendations_page.
- `src/widgets/geo_search_panel.dart` - filtros lat/lng/radio en listados.
- `src/features/home/` - legacy (categorias servicios; a deprecar).

## 6b) Cierre integral (implementado)

- Registro API restringido a roles no-staff (`PublicUserRoles`).
- Perfil: `GET|PATCH /api/v1/me` (`UserProfileController`).
- Portal web usuario: `/cuenta/*` (login, registro, panel, publicar empleo/habitacion/ruta).
- Portal y admin web usan proxies backend (`/cuenta/api/*`, `/admin/api/*`) para evitar token manual/expuesto en frontend.
- App Flutter: registro, perfil, publicar listings, soporte con adjuntos, fraude, categorias servicios.
- CI: `.github/workflows/ci.yml` (backend + mobile).
- Fase 4 base: `config/regions.php`, `EnhancedRankingService`, `docs/PHASE4_ROADMAP.md`.
- Checklist go-live: `docs/GO_LIVE_CHECKLIST.md`.
- Readiness automatizado: comando `php artisan platform:readiness-check`.

## 7) Pendiente prioritario

### P1 - SMTP real para mailer — **APLAZADO (decision producto)**
- Hoy `MAIL_MAILER=log` (emails SLA/escalado solo en `storage/logs/laravel.log`). Suficiente para MVP.
- El propietario prefiere **no depender de terceros de pago** y valorar SMTP propio mas adelante; ver `docs/EMAIL_OPTIONS.md`.
- Cuando se active: configurar `MAIL_*` + DNS (SPF/DKIM) y verificar plantillas markdown SLA/escalado.

### P1 - Pantalla "crear solicitud de servicio" + pago E2E
- Backend listo (`POST /service-requests`, `POST /payments/initiate`, `GET /payments/{id}`).
- **HECHO**: UI Flutter con formulario, abre `redirect_url` con `url_launcher` (navegador externo) y al volver consulta `GET /payments/{id}` para mostrar estado.

### P2 - Refresh OAuth2 para FCM
- **HECHO**: `google/auth` + `FcmAccessTokenProvider` lee `FCM_CREDENTIALS` (service account JSON) y cachea OAuth ~55 min; sigue aceptando `FCM_ACCESS_TOKEN` manual.

### P2 - Integrar firebase_messaging en Flutter
- **HECHO (scaffold)**: `PushRegistrationService` inicializa Firebase via `--dart-define` (`FIREBASE_*`), pide permisos, registra token con `POST /device-tokens` tras login/restore y lo elimina al logout. Handler background minimo.
- **Pendiente operativo (usuario)**: proyecto Firebase real; guia paso a paso en `docs/FIREBASE_SETUP.md`.

### P2 - Realtime chat
- **HECHO (REST + polling)**: tablas + API + Flutter tab **Mensajes** con polling ~4s. **Sin proceso extra en servidor** (`BROADCAST_CONNECTION=log`).
- Reverb/WebSocket: **no prioritario** (requiere proceso daemon; ver `docs/REVERB.md` solo si en el futuro se quiere realtime sin polling).

### P3 - Observabilidad
- **HECHO (MVP)**: middleware `LogStructuredApiRequests`, canal `json` → `storage/logs/structured.jsonl`, `GET /api/v1/health`. Ver `docs/OBSERVABILITY.md`.
- **Aplazado**: Telescope, Prometheus, OpenTelemetry (requieren stack adicional en servidor).

### P3 - Geo busquedas
- **HECHO (backend)**: `GeoSearchService` (Haversine MySQL; bounding box SQLite en tests), query `lat`, `lng`, `radius_km` en jobs/housing/rides/service-requests; test `GeoSearchTest`.
- **HECHO (Flutter)**: `GeoSearchPanel` en Empleos, Habitaciones y Rutas.
- **Opcional futuro**: indices spatial MySQL si el volumen de datos lo exige.

## 8) Riesgos y deuda tecnica abierta

- Mailer en `log` por decision (email aplazado); ver `docs/EMAIL_OPTIONS.md`.
- FCM en log-only por defecto hasta configurar `FCM_PROJECT_ID` + (`FCM_CREDENTIALS` o `FCM_ACCESS_TOKEN`).
- Chat por polling; no requiere Reverb ni ventanas/procesos extra.
- Flutter push: codigo listo; requiere credenciales Firebase en build (`--dart-define=FIREBASE_*`).

## 9) Plan de trabajo sugerido para la siguiente IA

1. **Firebase/FCM real** cuando el propietario cree el proyecto (`docs/FIREBASE_SETUP.md`).
2. **Email SMTP** solo si lo pide el usuario (`docs/EMAIL_OPTIONS.md`).
3. **Reverb/WebSocket** solo si se acepta proceso daemon en servidor (`docs/REVERB.md`).
4. **HECHO (Flutter)**: borrar fotos, mapa OSM con pin, compartir/copiar enlace https (`SHARE_BASE_URL/open/{tipo}/{id}`) + fallback `mallorcatrabaja://`. Ver `docs/APP_LINKS.md`.
5. **HECHO (seed)**: `ListingPhotoSeeder` descarga fotos de prueba desde picsum.photos (Internet, no generadas).

## 10) Criterios de no regresion

- No romper endpoints existentes.
- Mantener tests actuales en verde (80 backend al cierre de este handoff).
- Anadir tests nuevos por cada capability.
- Mantener formato de respuesta JSON consistente (excepto `*/download`, `*.csv` y webhooks).
- Registrar auditoria en acciones sensibles.
- No publicar contenido de archivos privados sin autenticacion.
- Toda ruta `/admin/*` web debe pasar por auth + check rol staff.
- Webhooks deben verificar firma HMAC antes de actualizar estado.
- `StripePaymentGateway` debe mantener su comportamiento de fallback (devolver session local si Stripe falla); no romper los tests existentes.
- `PushNotificationDispatcher` debe seguir aceptando ausencia de credenciales (log-only) para no romper escenarios sin FCM.
- Flutter: `TokenStorage` debe seguir aceptando inyeccion de `FlutterSecureStorage` y mantener la migracion legacy desde `SharedPreferences`.

## 11) Cambios introducidos en ESTE handoff

### Composer
- `+ stripe/stripe-php ^20.1`

### Pub
- `+ flutter_secure_storage ^9.2.4`
- `+ shared_preferences ^2.3.2` (ya presente, requerido por migracion legacy)
- `+ url_launcher ^6.3.2` (abrir Stripe Checkout en navegador)

### Migraciones nuevas
- (ninguna en este turno; `device_tokens` y `payments` ya estaban)

### Archivos nuevos backend
- `app/Services/Push/PushNotificationDispatcher.php`
- `tests/Feature/Push/PushNotificationDispatcherTest.php`

### Archivos modificados backend
- `app/Services/Payments/StripePaymentGateway.php` (integracion real con `\Stripe\StripeClient`, fallback a session local + warning).
- `app/Models/User.php` (relacion `deviceTokens()` y limpieza de imports duplicados).
- `app/Console/Commands/NotifyOverdueSupportTickets.php` (inyecta `PushNotificationDispatcher`; envia push tanto en overdue como en escalado).
- `app/Providers/AppServiceProvider.php` (binding `PushNotificationDispatcher` singleton).
- `config/services.php` (claves `fcm.project_id`, `fcm.access_token`).
- `tests/Feature/SupportTicketSlaCommandTest.php` (test extra que valida push real en SLA con Http::fake).

### Archivos nuevos Flutter
- `mobile_app/lib/src/features/housing/housing_detail_page.dart`
- `mobile_app/lib/src/features/rides/ride_detail_page.dart`
- `mobile_app/lib/src/features/services/services_page.dart`
- `mobile_app/lib/src/features/services/service_request_create_page.dart`
- `mobile_app/lib/src/features/services/payment_status_page.dart`

### Archivos modificados Flutter
- `mobile_app/pubspec.yaml` (`flutter_secure_storage`).
- `mobile_app/lib/src/core/token_storage.dart` (totalmente reescrito sobre `FlutterSecureStorage`, con inyeccion para tests y migracion legacy).
- `mobile_app/lib/src/core/api_client.dart` (endpoints servicios + crear solicitud + listado; pagos ya consumidos por UI).
- `mobile_app/lib/src/features/housing/housing_page.dart` (`onTap` navega al detalle).
- `mobile_app/lib/src/features/rides/rides_page.dart` (`onTap` navega al detalle).
- `mobile_app/lib/src/features/shell/app_shell.dart` (nuevo tab Servicios).
- `mobile_app/test/widget_test.dart` (mock channel `plugins.it_nomads.com/flutter_secure_storage`).

### Infra local (no commited)
- Flutter SDK 3.44.0 instalado en `C:\dev\flutter` y anadido al PATH de usuario.

### Tests
- Backend: **74 verdes, 269 assertions** (+5 vs. handoff anterior).
- Flutter: `flutter analyze` sin issues, `flutter test` 1/1.
- Pint: passed.
