# Prompt para el nuevo proyecto en Emergent
## App: Plataforma modular de gestión (primer módulo: Guías de Despacho)

---

> **Cómo usar este archivo:**
> 1. En el chat actual (`multisistemas.cl`), hacé clic en **"Save to GitHub"** para tener un respaldo del código fuente actual (opcional pero recomendado).
> 2. En el dashboard de Emergent, creá un **proyecto nuevo**.
> 3. Copiá TODO el contenido entre las líneas `===` de más abajo y pegalo como **primer mensaje** del nuevo proyecto.
> 4. El agente del nuevo proyecto construirá la app limpia, multi-tenant, con el módulo Guías completo + shell de futuros módulos + R2 listo.

---

================================================================
PROMPT PARA PEGAR EN EL NUEVO PROYECTO (copialo desde aquí 👇)
================================================================

Quiero construir una **plataforma SaaS modular multi-tenant** en español (Chile) para empresas, con arquitectura preparada para múltiples módulos en el futuro pero arrancando con **un solo módulo funcional: Guías de Despacho**.

# Stack obligatorio
- **Backend:** FastAPI (Python) + Motor (MongoDB async) + JWT auth + APScheduler
- **Frontend:** React 18 + React Router + Tailwind + Shadcn/UI + Sonner toasts + Lucide icons
- **Base de datos:** MongoDB con GridFS para archivos
- **Idioma de toda la UI:** Español (Chile)
- **Modelos Pydantic** usando `PyObjectId` annotated type (ObjectId → str para JSON safety)
- **Datetimes** siempre `datetime.now(timezone.utc).isoformat()`

# Arquitectura general

## Multi-tenant
- Modelo `Empresa` con: `id` (uuid), `nombre`, `rut`, `subdominio`, `logo_url`, `primary_color`, `nombre_area_seguridad`, `motivos_rechazo` (lista), `modulos_asignados` (lista de códigos de módulo), `created_at`.
- Todos los documentos de negocio llevan `empresa_id` y todas las queries filtran por `empresa_id` del usuario logueado.
- Roles disponibles: `superadmin`, `admin`, `gerente`, `solicitante`, `seguridad`.

## Shell de plataforma (incluso si hoy solo hay 1 módulo)
- **HomePage** post-login: muestra grilla de módulos asignados a la empresa del usuario. Si la empresa tiene 1 solo módulo, redirige directo a él. Si tiene varios, el usuario elige.
- **Sidebar / panel lateral**: muestra dinámicamente los items del módulo activo, filtrados por rol del usuario.
- **Switcher de módulos** (icono arriba del sidebar) para cambiar de módulo sin volver al HomePage.
- Diccionario central de módulos:
  ```python
  MODULOS_DISPONIBLES = [
      {"codigo": "guias_despacho", "nombre": "Guías de Despacho", "icon": "FileText", "ruta_base": "/guias"},
      # Futuros: bomberos, ordenes_servicio, diesel, alarmas_ls, integrador_codelco, etc.
  ]
  ```
- Endpoint `GET /api/modulos/empresa` retorna los módulos asignados a la empresa del usuario.

## Autenticación (usá el playbook de auth de Emergent)
- JWT con `email`, `rol`, `empresa_id` en el payload.
- Bcrypt para passwords (campo `password_hash`).
- Endpoints: `POST /api/auth/login`, `GET /api/auth/me`, `POST /api/auth/logout`.
- Brute force protection: bloqueo tras 5 intentos fallidos por 15 min.
- Password reset endpoint para admin/superadmin (idempotente).

## Storage abstraction (CRÍTICO)
Crear `/app/backend/lib/storage.py` con interfaz:
```python
class StorageBackend(ABC):
    async def save(self, filename, content, content_type, metadata) -> str: ...
    async def load(self, filename) -> tuple[bytes, str]: ...  # (content, content_type)
    async def delete(self, filename) -> None: ...

class GridFSBackend(StorageBackend): ...  # implementación actual
class R2Backend(StorageBackend): ...      # stub con TODO, listo para activar
```
- Factory que lee `STORAGE_BACKEND` de `.env` (`gridfs` por default, `r2` cuando se active).
- Variables R2 a documentar en `.env.example`: `R2_ACCOUNT_ID`, `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `R2_BUCKET`, `R2_PUBLIC_URL`.
- Toda la subida y descarga de archivos del módulo Guías debe pasar por `StorageBackend`, no por GridFS directo. Esto permite cambiar a Cloudflare R2 en el futuro sin tocar lógica de negocio.

## Compresión de archivos (debe estar desde el día 1)
- **Imágenes (frontend):** helper `/app/frontend/src/lib/compressImage.js` — Canvas API, max 1920px lado mayor, JPEG quality 0.82. Aplicar en TODOS los uploads de imágenes.
- **PDFs (backend):** helper `_compress_pdf_bytes` usando `pikepdf` + PIL — recodifica imágenes embebidas a JPEG q=75, downsamplea a max 1700px. Aplicar antes de guardar en storage. Si no reduce >5%, mantener original. Logs: `[PDF compress] {origKB}KB -> {newKB}KB`.

# Módulo único inicial: Guías de Despacho

## Resumen funcional
Gestión de guías/facturas de despacho de mercancías. Flujo: **solicitante crea → gerente autoriza → seguridad despacha** en punto de salida.

## Roles y permisos
- **solicitante**: crea guías (`/guias/crear`), ve solo sus propias guías (`/guias/mis-guias`).
- **gerente** (también llamado "autorizador"): aprueba/rechaza guías pendientes (`/guias/aprobar`), ve todas (`/guias/todos`), puede **subir documento firmado** solo cuando la guía está en estado `pendiente`.
- **seguridad** (también llamado "Protección Industrial" o "P.I."): tras login redirige directo a `/guias/todos`; puede despachar/rechazar en punto de salida (`/guias/punto-salida`), tiene acceso a escáner QR (`/guias/escaner`) y todas las guías.
- **admin**: ve y hace todo dentro de su empresa, gestiona usuarios.
- **superadmin**: ve todas las empresas.

## Páginas del módulo
| Ruta | Componente | Roles |
|---|---|---|
| `/guias/dashboard` | DashboardPage (KPIs por estado) | admin, gerente, seguridad, superadmin |
| `/guias/crear` | CrearGuiaPage | solicitante, admin |
| `/guias/mis-guias` | MisGuiasPage (solo propias) | solicitante, admin |
| `/guias/aprobar` | AprobarGuiasPage (pendientes asignadas) | gerente, admin |
| `/guias/todos` | DocumentosPage (todas) | admin, gerente, seguridad, superadmin |
| `/guias/documento/:id` | DocumentoDetallePage | todos los autenticados |
| `/guias/punto-salida` | PuntoSalidaPage (escaneo + listado por despachar) | seguridad, admin |
| `/guias/escaner` | EscanerQRPage | seguridad, admin |
| `/guias/reportes` | ReportesGuiasPage | admin, gerente, seguridad, superadmin |
| `/guias/configuracion` | ConfiguracionGuiasPage (tipos de doc, motivos rechazo, push) | admin, superadmin |
| `/guias/usuarios` | UsuariosPage (CRUD usuarios de la empresa) | admin |
| `/qr/:id` | QRRedirectRoute (público con login) | — |

## Modelo Documento (guía/factura)
```
id (uuid), folio (auto: GD-YYYY-NNNNNN), folio_fisico (N° guía o factura - obligatorio),
tipo_documento_id, tipo_documento_nombre,
patente_tracto, patente_semiremolque,
nombre_conductor, rut_conductor,
rut_empresa, razon_social,
vehiculo_info {marca, modelo},
descripcion, items [{descripcion, cantidad, unidad}],
documento_adjunto_url,                  # PDF/imagen del folio físico
documento_firma_aprobador_url,          # PDF/imagen firmada por gerente
documento_fma002_url,                   # opcional: residuos no peligrosos
es_residuo_no_peligroso (bool),
imagenes_carga: [url] (max 5),
aprobador_id, aprobador_nombre,
estado: 'pendiente' | 'autorizado' | 'rechazado' | 'despachado',
usuario_solicitante_id, usuario_solicitante_nombre,
empresa_id,
aprobacion: {aprobador_id, aprobador_nombre, fecha, estado, observacion},
punto_salida: {responsable_id, responsable_nombre, fecha_verificacion, estado, motivos_rechazo[], observacion},
created_at, updated_at
```

## Endpoints backend (todos bajo `/api`)
```
POST   /documentos                          (solicitante, admin) crear guía
GET    /documentos                          (auth) listar según rol (solicitante ve propias, gerente ve donde es aprobador)
GET    /documentos/todos                    (admin, seguridad, superadmin, gerente) ver todas
GET    /documentos/{id}                     (auth) detalle
POST   /documentos/upload-adjunto           (solicitante, admin) subir PDF/imagen → comprime y guarda en storage
POST   /documentos/{id}/upload-firma-aprobador (gerente, admin, superadmin) subir doc firmado (solo si estado=pendiente)
GET    /documentos/adjunto/{filename}       (público con auth) servir archivo desde storage
POST   /documentos/{id}/aprobar             (gerente) aprobar/rechazar
POST   /documentos/{id}/despachar           (seguridad) despachar/rechazar en P.I.
GET    /documentos/{id}/historial           (auth) timeline de acciones
GET    /guias/exportar-excel?fecha_inicio&fecha_fin&estado  (admin, seguridad, superadmin) reporte Excel
GET    /configuracion/guias                 (admin) config de tipos doc + motivos rechazo
PUT    /configuracion/guias                 (admin) actualizar
GET    /usuarios                            (admin) listar usuarios de la empresa
POST   /usuarios                            (admin) crear
PUT    /usuarios/{id}                       (admin) editar
DELETE /usuarios/{id}                       (admin) eliminar
```

## Funcionalidades clave detalladas

### Preview de archivos
- Imágenes: tag `<img>` con click para abrir modal.
- PDFs: `<iframe>` dentro del modal (NO `<img>`).
- Modal de preview soporta ambos formatos con botón Descargar y Abrir en nueva pestaña.

### Notificaciones Push (PWA) — desde el día 1
- VAPID keys (generar y guardar en `.env`: `VAPID_PUBLIC_KEY`, `VAPID_PRIVATE_KEY`, `VAPID_SUBJECT`).
- Service worker en `/app/frontend/public/sw.js` con sonido custom.
- Endpoints:
  - `POST /api/guias/push/subscribe`, `DELETE /api/guias/push/subscribe/{endpoint_hash}`
  - `GET /api/guias/push/config`, `PUT /api/guias/push/config` (matriz por rol × evento)
  - `POST /api/guias/push/test` (envía notificación de prueba al usuario)
- Eventos: `nueva_guia`, `guia_aprobada`, `guia_rechazada`, `guia_despachada`, `doc_firmado`.
- Configuración por tenant: matriz `rol × evento → activo (bool)`.
- Botón "Instalar como PWA" visible si `beforeinstallprompt` está disponible.
- Manifest con icons, short_name, theme_color.

### Generación QR
- Cada guía tiene un QR en el detalle (`<QRCodeSVG value={origin+'/qr/'+doc.id} />`).
- Ruta `/qr/:id` redirige a `/guias/documento/:id` (o login → redirect).

### Búsqueda y filtros en `/guias/todos`
- Search box: filtra por `folio`, `folio_fisico` (N° guía/factura), `patente`, `rut_destino`, `razon_social`, `solicitante`, `aprobador`, `conductor`.
- Filter por `estado` (pendiente/autorizado/rechazado/despachado).
- Tabla con columnas: Folio | **N° Guía/Factura** | Tipo | Patente | Empresa Destino | Conductor | Solicitante | Autorizador | Fecha | Estado | Acciones.
- Exportar a Excel con rango de fechas opcional.

### Detalle de documento
- Hero con folio + estado.
- Cards: Info general (incluye **N° guía/factura prominente**), Conductor, Vehículo, Empresa destino, Items, Documentos e Imágenes, Aprobación, Punto de Salida.
- Sidebar: QR + Timeline de historial.
- Botones de acción según rol+estado:
  - Gerente con estado pendiente: **Aprobar** | **Rechazar** | **Adjuntar documento firmado**.
  - Seguridad con estado autorizado: **Despachar** | **Rechazar P.I.** (con motivos preseleccionados).
- Dialog de acción con observación obligatoria si es rechazo.

### Compresión
- Toda imagen subida pasa por `compressImage` (frontend, Canvas API, max 1920px, q=0.82).
- Todo PDF subido pasa por `_compress_pdf_bytes` (backend, pikepdf + PIL).
- Log de compresión visible en backend logs.

## Layout / navegación del módulo
Sidebar items por rol:
- **admin**: Dashboard, Guías, Reportes, Usuarios, Carga Masiva, Configuración, Historial
- **solicitante**: Dashboard, Nueva Guía, Mis Guías
- **gerente**: Dashboard, Aprobar Guías, Todas las Guías, Reportes, Historial
- **seguridad**: Todas las Guías (primero), Punto de Salida, Reportes
- **superadmin**: Dashboard, Guías, Reportes, Aprobar, Historial, Configuración

# Datos semilla (seed inicial)

## Empresas
```
1) {
  id: uuid, nombre: "Empresa Demo S.A.", rut: "76.123.456-7",
  subdominio: "demo", primary_color: "#3B82F6",
  nombre_area_seguridad: "Seguridad", motivos_rechazo: [...defaults...],
  modulos_asignados: ["guias_despacho"]
}
2) {
  id: uuid, nombre: "Minera Los Pelambres", rut: "96790240-3",
  subdominio: "mlp", primary_color: "#F97316",
  nombre_area_seguridad: "Protección Industrial",
  motivos_rechazo: [
    "Sello roto", "Carga incompleta", "Documentación incorrecta",
    "Vehículo no autorizado", "Personal no identificado",
    "Emisión de guía superior a 24 horas",
    "Fotografía de carga no concuerda con revisión de PI"
  ],
  modulos_asignados: ["guias_despacho"]
}
```

## Usuarios (todos con password `Test1234!`)
```
Empresa Demo:
  admin@demo.com       rol=admin       nombre="Admin Demo"
  solicitante@demo.com rol=solicitante nombre="Juan Solicitante"
  gerente@demo.com     rol=gerente     nombre="María Gerente"
  seguridad@demo.com   rol=seguridad   nombre="Pedro Seguridad"

Empresa MLP (Minera Los Pelambres):
  admin@mlp.cl         rol=admin       nombre="Admin MLP"
  solicitante@mlp.cl   rol=solicitante nombre="Personal Solicitante"
  gerente@mlp.cl       rol=gerente     nombre="Gerente Autorizador"
  pi@mlp.cl            rol=seguridad   nombre="Persona Protección Industrial"

Superadmin global (sin empresa):
  superadmin@plataforma.cl rol=superadmin nombre="Super Admin"
```
El seed debe ser **idempotente** (no duplicar si ya existen) y debe guardar también el password en `test_credentials.md`.

# Estructura de archivos esperada
```
/app/
├── backend/
│   ├── server.py              # entry FastAPI + montaje de routers
│   ├── lib/
│   │   ├── storage.py         # ⭐ abstracción StorageBackend (GridFS + R2 stub)
│   │   ├── pdf_compress.py    # helper _compress_pdf_bytes
│   │   ├── auth.py            # JWT + bcrypt + dependencies (require_roles)
│   │   └── push.py            # VAPID + pywebpush
│   ├── routes/
│   │   ├── auth.py
│   │   ├── empresas.py
│   │   ├── usuarios.py
│   │   ├── modulos.py
│   │   └── guias/
│   │       ├── documentos.py
│   │       ├── configuracion.py
│   │       ├── reportes.py
│   │       └── push.py
│   ├── models/
│   │   ├── base.py            # BaseDocument + PyObjectId
│   │   ├── empresa.py
│   │   ├── usuario.py
│   │   └── documento.py
│   ├── seed.py                # idempotente
│   ├── requirements.txt
│   └── .env (no commitear)
├── frontend/
│   ├── public/
│   │   ├── sw.js
│   │   └── manifest.json
│   └── src/
│       ├── components/
│       │   ├── Layout.jsx     # shell con sidebar + module switcher
│       │   ├── ModuleSwitcher.jsx
│       │   └── ui/ (shadcn)
│       ├── context/
│       │   ├── AuthContext.jsx
│       │   └── ThemeContext.jsx
│       ├── lib/
│       │   ├── api.js
│       │   ├── compressImage.js   # ⭐ helper compartido
│       │   └── push.js
│       ├── pages/
│       │   ├── LoginPage.jsx
│       │   ├── HomePage.jsx        # grilla de módulos asignados
│       │   ├── guias/
│       │   │   ├── DashboardPage.jsx
│       │   │   ├── CrearGuiaPage.jsx
│       │   │   ├── MisGuiasPage.jsx
│       │   │   ├── AprobarGuiasPage.jsx
│       │   │   ├── DocumentosPage.jsx
│       │   │   ├── DocumentoDetallePage.jsx
│       │   │   ├── PuntoSalidaPage.jsx
│       │   │   ├── EscanerQRPage.jsx
│       │   │   ├── ReportesGuiasPage.jsx
│       │   │   ├── ConfiguracionGuiasPage.jsx
│       │   │   └── UsuariosPage.jsx
│       └── App.js (rutas + ProtectedRoute + redirects por rol)
└── memory/
    ├── PRD.md
    └── test_credentials.md
```

# Decisiones de diseño visual
- Estilo industrial (esta app es para minería, transporte, seguridad).
- Borders gruesos (`border-2`), uppercase headers, fonts heavy (heading bold + black uppercase tracking-tight).
- Status badges con colores: `pendiente`=amber, `autorizado`=blue, `despachado`=success, `rechazado`=destructive.
- Cada empresa puede tener su `primary_color` aplicado dinámicamente via CSS variable.
- Dark mode soportado.
- `data-testid` en CADA elemento interactivo (kebab-case descriptivo).

# Redirects clave del login
- Si usuario tiene 1 solo módulo → redirige directo a la ruta base de ese módulo.
- Si rol=`seguridad` y módulo guías está activo → directo a `/guias/todos` (NO a punto-salida).
- Si usuario tiene varios módulos → muestra HomePage con grilla.

# Plan de ejecución que debés seguir
1. **Mostrame primero el plan** con `ask_human` antes de codear: stack, modelos, rutas, qué módulos del shell, qué integraciones (push, GridFS).
2. **Auth primero** — usá `integration_playbook_expert_v2` para el playbook de JWT auth (Emergent recomienda un patrón específico).
3. **Storage abstraction después** — implementala antes de subir el primer archivo.
4. **Módulo Guías completo** — paso a paso con tests E2E (curl + screenshot).
5. **PWA + Push** al final.
6. **Seed idempotente y `test_credentials.md`** actualizados.
7. **Testing agent al final** una sola vez (no múltiples llamadas para ahorrar créditos).

# IMPORTANTE
- Respondé SIEMPRE en español.
- El usuario es no-técnico desde el lado de deployment: explicale qué tiene que hacer en cada paso (no asumas que conoce comandos de git, MongoDB, etc.).
- Cuando termines un módulo, indicale: "ahora hacé clic en Deploy para subirlo a producción".
- NO uses screenshot tool ni testing agent en cada cambio chico (ahorra créditos): solo al cerrar el módulo completo.

¿Tenés alguna pregunta antes de arrancar?

================================================================
FIN DEL PROMPT (copialo hasta aquí 👆)
================================================================
