# Ecosistema Limpioo

> Documento maestro del ecosistema **Limpioo**: integra los dos proyectos del workspace (`limpioo` + `limpioo.console`) y describe cómo se relacionan a nivel de código, datos, infraestructura y procesos.
>
> Cada afirmación de este documento ha sido verificada contra el código fuente y se cita el archivo concreto (y línea cuando aplica). Las divergencias detectadas entre los `README.md` de cada proyecto y la realidad del código quedan recogidas en la sección [12. Discrepancias documentación ↔ código](#12-discrepancias-documentación--código).

---

## Índice

1. [Resumen del ecosistema](#1-resumen-del-ecosistema)
2. [Mapa de proyectos](#2-mapa-de-proyectos)
3. [Diagrama de arquitectura conjunta](#3-diagrama-de-arquitectura-conjunta)
4. [Modelo de datos compartido](#4-modelo-de-datos-compartido)
5. [Puntos de interconexión verificados](#5-puntos-de-interconexión-verificados)
6. [Flujo cross-project: Preview (console → limpioo)](#6-flujo-cross-project-preview-console--limpioo)
7. [Flujo cross-project: Provisioning (console → runtime)](#7-flujo-cross-project-provisioning-console--runtime)
8. [Detección de entornos](#8-detección-de-entornos)
9. [Cifrado y seguridad](#9-cifrado-y-seguridad)
10. [Integraciones externas comunes](#10-integraciones-externas-comunes)
11. [Tooling cross-project](#11-tooling-cross-project)
12. [Discrepancias documentación ↔ código](#12-discrepancias-documentación--código)
13. [Deuda técnica común](#13-deuda-técnica-común)
14. [Documentación de referencia](#14-documentación-de-referencia)

---

## 1. Resumen del ecosistema

El ecosistema **Limpioo** está compuesto por dos aplicaciones PHP independientes que comparten infraestructura (MariaDB, Apache/Nginx, Brevo SMTP, FCM, Redsys, Verifacti) y un esquema de datos coordinado:

| Proyecto | Audiencia | Función principal |
|---|---|---|
| [limpioo](../limpioo/) | Cliente final (conductor del túnel de lavado) | Webapp pública para iniciar lavados puntuales, suscripciones LPR, gestión familiar y pagos. |
| [limpioo.console](.) | Operadores / propietarios de instalación | Back-office multi-tenant para administrar ventas, devoluciones, suscripciones, recompensas, facturación AEAT (Verifacti) e impresión de tickets. |

Aunque cada proyecto se despliega por separado, **comparten la misma base de datos maestra `limpioo`** y **escriben/leen sobre los mismos esquemas de tenant `limpioo_userdb_<id>`**. La consola provisiona los tenants y el cliente final opera sobre ellos.

---

## 2. Mapa de proyectos

| Aspecto | `limpioo` | `limpioo.console` |
|---|---|---|
| Document root | [limpioo/public/](../limpioo/public/) | [limpioo.console/public/](public/) |
| Entry HTTP principal | [public/index.php](../limpioo/public/index.php) | [public/index.php](public/index.php) |
| Configuración | [includes/config.php](../limpioo/includes/config.php) | [includes/config.php](includes/config.php) |
| Helpers globales | [includes/global.php](../limpioo/includes/global.php) | [includes/global.php](includes/global.php) |
| Esquema BD maestra | [database/admin/v2.0/](../limpioo/database/admin/v2.0/) | [database/admin/v2.0/database.sql](database/admin/v2.0/database.sql) |
| Esquema BD tenant | [database/application/v2.0/](../limpioo/database/application/v2.0/) | [database/application/v2.0/database.sql](database/application/v2.0/database.sql) |
| Sesión | Cookie cifrada `NETSESSID` (AES-256-CTR) | PHP session sobre tabla `limpioo.sessions` (DatabaseSessionHandler) |
| Pago interactivo | Redsys SIS redirección + callback `notify.php` | No (cobra mediante limpioo) |
| Pago recurrente | Redsys REST MIT (`charge.php` cron) | No |
| Generación QR | No | Sí ([ajax/code/make.php](ajax/code/make.php), [public/makecode.php](public/makecode.php)) |
| Facturación AEAT | No | Sí (Verifacti, [ajax/sales/invoice/](ajax/sales/invoice/)) |
| Impresión térmica | No | Sí ([scripts/limpioo.print.py](scripts/limpioo.print.py)) |

---

## 3. Diagrama de arquitectura conjunta

```mermaid
flowchart TB
    subgraph Clientes
        U[Cliente final<br/>navegador móvil]
        O[Operador<br/>back-office]
    end

    subgraph Webapp_Limpioo[limpioo · webapp pública]
        L_IDX[public/index.php<br/>flujo de lavado + PREVIEW_MODE]
        L_CHK[public/checkout.php]
        L_NOTIFY[public/notify.php<br/>callback Redsys]
        L_INV[public/invite.php<br/>familiares]
        L_CRON[includes/cron/charge.php<br/>cobros MIT]
        L_PREV[includes/preview/preview.php]
        L_API[includes/api/<br/>fcm-token, send-notification]
    end

    subgraph Console[limpioo.console · back-office multi-tenant]
        C_IDX[public/index.php<br/>dashboard]
        C_SAL[public/sales.php<br/>ventas híbridas]
        C_SUB[public/appsubscriptions.php]
        C_REW[public/apprewards.php]
        C_QR[public/makecode.php<br/>generación QR]
        C_AJAX[ajax/sales/* /code/* /auth/*]
        C_SES[includes/SessionHandler.php]
        C_DM[includes/DataManager.php<br/>backup SIF cifrado]
    end

    subgraph DB[(MariaDB)]
        DBM[(BD maestra<br/>limpioo)]
        DBT1[(tenant<br/>limpioo_userdb_1)]
        DBT2[(tenant<br/>limpioo_userdb_2)]
        DBN[(tenant<br/>limpioo_userdb_N)]
    end

    subgraph Externos[Servicios externos]
        REDSYS[Redsys SIS / REST]
        FCM[Firebase Cloud Messaging]
        BREVO[Brevo SMTP]
        VERIF[Verifacti / AEAT]
        NETWASH[API Netwash<br/>app/1.0/device/*]
    end

    U --> L_IDX
    O --> C_IDX
    L_IDX -- ?in=KEY 32c termina g --> L_PREV
    L_IDX -- GET /app/1.0/device/preview --> NETWASH
    C_REW -- POST /app/1.0/device/preview/create --> NETWASH
    C_SUB -- POST /app/1.0/device/preview/create --> NETWASH
    L_CHK --> REDSYS
    REDSYS -.callback.-> L_NOTIFY
    L_CRON --> REDSYS
    L_API --> FCM
    L_NOTIFY --> BREVO
    C_AJAX --> VERIF
    C_AJAX --> DBT1 & DBT2 & DBN
    L_IDX --> DBT1 & DBT2 & DBN
    C_SES --> DBM
    L_API --> DBM
    C_AJAX --> DBM
```

---

## 4. Modelo de datos compartido

### 4.1 Base de datos maestra `limpioo`

Tablas compartidas por ambos proyectos (mismo esquema definido en [limpioo.console/database/admin/v2.0/database.sql](database/admin/v2.0/database.sql)):

| Tabla | Escribe | Lee | Propósito |
|---|---|---|---|
| `users_databases` | console (`signup/post.php`) | console (`signin`), limpioo (resolución) | Catálogo de tenants. Campos: `id`, `db_name`, `db_username`, `db_password_enc`, `iv`, `tag`, `api_key`. Verificado en [database/admin/v2.0/database.sql L38-L54](database/admin/v2.0/database.sql#L38). |
| `sessions` | console (`SessionHandler`) | console | Sesiones PHP persistentes (TTL 30 días, regen 24h). Verificado en [includes/SessionHandler.php L14, L32-L33](includes/SessionHandler.php#L14). |
| `user_uuid_databases` | limpioo (registro), console | ambos | Mapeo `uuid → db_id` para resolución del tenant a partir del UUID del cliente. |
| `fcm_tokens` (master) | limpioo `api/fcm-token.php` | limpioo `api/send-notification.php`, console | Tokens FCM del cliente final. |

### 4.2 Base de datos por tenant `limpioo_userdb_<id>`

Cada operador tiene su propia BD. Tablas relevantes (definidas en [limpioo.console/database/application/v2.0/database.sql](database/application/v2.0/database.sql) y mantenidas también en [limpioo/database/application/v2.0/](../limpioo/database/application/v2.0/)):

| Tabla | Quién escribe | Para qué |
|---|---|---|
| `users` | limpioo (registro/login) | Datos del cliente final |
| `log` | limpioo (`checkout`, `notify`, `checkmail`), console (correcciones) | Histórico de lavados puntuales (legacy) |
| `qr` | console (`ajax/code/make.php`) | Cabecera de venta QR |
| `qr_items` | console | Líneas de la venta QR |
| `qr_usage_log` | limpioo (consumo del QR) | Trazabilidad de redenciones |
| `subscriptions` | limpioo (alta/cancel), console (lectura, cancelación operativa) | Suscripciones LPR |
| `subscription_members` | limpioo (`invite_member`, `remove_member`) | Familiares dentro de una suscripción |
| `tokenization` | limpioo (`notify` Redsys) | Token Redsys MIT por usuario |
| `rewards` | limpioo, console | Programa de recompensas |
| `globals` | console | Configuración del operador (instalación, AEAT, etc.) |
| `codes` | console | Códigos promocionales |
| `uses` | limpioo, console | Consumos de códigos |
| `fcm_tokens` (tenant) | limpioo | Tokens push |

> **Verificado**: La tabla `subscriptions` define `UNIQUE KEY uq_uuid_subscription_id (uuid, subscription_id)`. El índice `(uuid, item_id, license_plate, THING)` existe pero es secundario y no UNIQUE. El README de `limpioo` ya refleja correctamente este esquema.

---

## 5. Puntos de interconexión verificados

Los dos proyectos se comunican exclusivamente a través de:

1. **Base de datos compartida** (maestra + tenants).
2. **API HTTP `Netwash`** (mismos endpoints `/app/1.0/device/*` consumidos por ambos).
3. **Convenciones de URL/QR** (formato `?in=<KEY>` reconocido por limpioo).

| Punto de unión | Productor | Consumidor | Verificación |
|---|---|---|---|
| QR de venta (`?in=<KEY>` 32 chars terminada en letra distinta de `g`) | console (`makecode.php`, `ajax/code/make.php`) | limpioo (`public/index.php`) | [limpioo/public/index.php L405](../limpioo/public/index.php#L405) |
| QR de **preview** (`?in=<KEY>` 32 chars terminada en `g`) | console (`POST /app/1.0/device/preview/create` desde `apprewards.php` y `appsubscriptions.php`) | limpioo (`public/index.php` activa `$PREVIEW_MODE`) | [limpioo/public/index.php L405](../limpioo/public/index.php#L405): `$PREVIEW_MODE = (strlen($KEY) === 32 && substr($KEY, -1) === 'g');` · [public/apprewards.php L1034](public/apprewards.php#L1034) · [public/appsubscriptions.php L660](public/appsubscriptions.php#L660) |
| API consulta preview | limpioo `index.php` GET `/app/1.0/device/preview` | API Netwash | [limpioo/public/index.php L567-L568](../limpioo/public/index.php#L567) |
| Renderizado de preview sin BD | limpioo `includes/preview/preview.php` lee `$_GET['D']` (base64 + JSON) | UI cliente | [limpioo/includes/preview/preview.php L29](../limpioo/includes/preview/preview.php#L29) |
| Provisioning de tenant | console `ajax/auth/signup/post.php` crea BD `limpioo_userdb_<id>` | limpioo (consulta vía `users_databases`) | [ajax/auth/signup/post.php L93](ajax/auth/signup/post.php#L93) |
| Resolución del tenant en runtime | console `ajax/auth/signin/post.php` carga credenciales descifradas en sesión | limpioo: `includes/global.php` (`getUserDatabasesFromMaster`, `loadUserDatabases`) | [ajax/auth/signin/post.php L92-L98](ajax/auth/signin/post.php#L92) |
| Tokens FCM | limpioo (`api/fcm-token.php`) | limpioo (`api/send-notification.php`) y console | [includes/api/fcm-token.php](../limpioo/includes/api/fcm-token.php), [includes/api/send-notification.php](../limpioo/includes/api/send-notification.php) |

---

## 6. Flujo cross-project: Preview (console → limpioo)

Permite mostrar al cliente una vista previa de un producto/recompensa sin consumir saldo ni tocar la BD.

```mermaid
sequenceDiagram
    participant Op as Operador (console)
    participant CON as console / apprewards.php · appsubscriptions.php
    participant API as API Netwash
    participant CLI as Cliente final
    participant LIM as limpioo / index.php
    participant PRV as limpioo / preview.php

    Op->>CON: Click "Generar preview"
    CON->>API: POST /app/1.0/device/preview/create
    API-->>CON: previewKey (32 chars, sufijo "g")
    CON-->>Op: QR con URL ?in=previewKey
    Op-->>CLI: Muestra/escanea QR
    CLI->>LIM: GET /?in=<previewKey>
    LIM->>LIM: $PREVIEW_MODE = (len==32 && acaba en "g")
    LIM->>API: GET /app/1.0/device/preview?key=...
    API-->>LIM: Datos del producto (JSON)
    LIM->>PRV: Render con $_GET['D'] (base64+JSON)
    PRV-->>CLI: Vista previa renderizada
```

---

## 7. Flujo cross-project: Provisioning (console → runtime)

Cómo se crea un tenant desde la consola y cómo lo localiza después limpioo en runtime.

```mermaid
sequenceDiagram
    participant Op as Operador
    participant SU as console / ajax/auth/signup/post.php
    participant DBM as MariaDB master (limpioo)
    participant DBT as MariaDB tenant
    participant SI as console / ajax/auth/signin/post.php
    participant LIM as limpioo / includes/global.php
    participant CLI as Cliente final

    Op->>SU: Registro
    SU->>DBM: CREATE DATABASE limpioo_userdb_<uid>
    SU->>DBM: CREATE USER + GRANT ALL PRIVILEGES
    SU->>DBT: Importa schema desde plantilla v2.0
    SU->>DBM: INSERT users_databases (db_password_enc + iv + tag, AES-256-GCM)
    Op->>SI: Login
    SI->>DBM: SELECT credenciales
    SI->>SI: Descifra (AES-256-GCM)
    SI->>SI: $_SESSION = {user_id,email,server,username,password,dbname,apikey,...}
    CLI->>LIM: Petición con UUID
    LIM->>DBM: SELECT user_uuid_databases WHERE uuid=?
    LIM->>DBM: SELECT users_databases WHERE id=?
    LIM->>DBT: Conecta y opera
```

---

## 8. Detección de entornos

Ambos proyectos siguen el **mismo patrón de tres niveles** (verificado):

| Nivel | `limpioo` | `limpioo.console` |
|---|---|---|
| 1 (Apache/Nginx `SetEnv` o env del proceso) | `getenv('LIMPIOO_ENV')` | `getenv('LIMPIOO_CONSOLE_ENV')` |
| 2 (`includes/env.local.php`, opcional) | constante `LIMPIOO_ENV_LOCAL` | constante `LIMPIOO_CONSOLE_ENV_LOCAL` |
| 3 (default) | `production` | `production` |

Verificado en [limpioo/includes/config.php L20-L27](../limpioo/includes/config.php#L20) y [limpioo.console/includes/config.php L23-L42](includes/config.php#L23).

Las constantes opcionales en `limpioo.console/includes/config.php` están protegidas con `defined() ? constant() : null` para evitar warnings de IntelliSense cuando `env.local.php` no existe.

---

## 9. Cifrado y seguridad

| Dato | Algoritmo | Lugar | Verificación |
|---|---|---|---|
| Cookie `NETSESSID` (limpioo) y datos sensibles de cliente | **AES-256-CTR** | [limpioo/includes/global.php L53, L608, L616](../limpioo/includes/global.php#L53) | Funciones `encrypt()`/`decrypt()` |
| Credenciales de tenant (`db_password_enc`) | **AES-256-GCM** | [ajax/auth/signup/post.php L34](ajax/auth/signup/post.php#L34) | Almacena `iv` + `tag` |
| Sesiones PHP (console) | DB session handler con TTL 30 días, regen 24h | [includes/SessionHandler.php L14, L32-L33](includes/SessionHandler.php#L14) | Tabla `limpioo.sessions` |
| Backup SIF (console) | Cifrado simétrico | [includes/DataManager.php](includes/DataManager.php) | Backup/restore cifrado |

---

## 10. Integraciones externas comunes

| Servicio | Uso desde `limpioo` | Uso desde `limpioo.console` |
|---|---|---|
| **Redsys** | Pago interactivo (`checkout.php`), callback (`notify.php`), MIT recurrente (`includes/cron/charge.php`) | — (los pagos los origina limpioo) |
| **Brevo SMTP** | Emails de verificación, recibos, notificaciones | Emails operativos (alertas, restauraciones) |
| **Firebase Cloud Messaging** | `includes/api/fcm-token.php` (registro), `send-notification.php` (envío) | Lectura/uso de tokens del cliente para notificaciones operativas |
| **Verifacti / AEAT** | — | [ajax/sales/invoice/add.php](ajax/sales/invoice/add.php), [ajax/sales/invoice/annulment/doit.php](ajax/sales/invoice/annulment/doit.php) |
| **API Netwash (`/app/1.0/device/*`)** | GET `/preview`, etc. | POST `/preview/create`, gestión de dispositivos |

---

## 11. Tooling cross-project

| Herramienta | Ubicación | Función |
|---|---|---|
| `deploy.sh` | [scripts/deploy.sh](scripts/deploy.sh) | Despliegue. Detecta y configura el directorio hermano `limpioo` automáticamente ([deploy.sh L26-L42](scripts/deploy.sh#L26)). |
| `verify_ecosystem.php` | [tests/verify_ecosystem.php](tests/verify_ecosystem.php) | Comprueba la convivencia de ambos proyectos, sus configuraciones, BDs y secretos. |
| `cleanup_temp_qr.sh` | [scripts/cleanup_temp_qr.sh](scripts/cleanup_temp_qr.sh) | Mantenimiento de QR temporales generados por la consola. |
| `limpioo.print.py` | [scripts/limpioo.print.py](scripts/limpioo.print.py) | Daemon Python para impresión térmica de tickets. |

---

## 12. Discrepancias documentación ↔ código

Resultado de la auditoría documental contra el código real:

| # | Afirmación documental | Realidad en el código | Severidad |
|---|---|---|---|
| 1 | ~~README de limpioo: `subscriptions` tiene `UNIQUE(uuid, item_id, license_plate)`.~~ **RESUELTO**: el README ahora documenta correctamente `UNIQUE KEY uq_uuid_subscription_id (uuid, subscription_id)` ([database.sql](../limpioo/database/application/v2.0/database.sql)). | Coincide con el código. | Resuelta |
| 2 | Algunas referencias a "credenciales centralizadas" en READMEs. | Las credenciales `newuser`/`n#wus#r` siguen hardcoded en al menos 8 ubicaciones (ver §13). | **Media** — deuda técnica conocida pero no totalmente reflejada. |
| 3 | No documentado en READMEs: `limpioo/includes/api/fcm-token.php` también usa credenciales hardcoded ([L68](../limpioo/includes/api/fcm-token.php#L68)). | Verificado en código. | **Media** — añadir a la lista de deuda. |

El resto de afirmaciones verificadas (preview flow, sesiones, cifrado, env, endpoints AJAX, ventas híbridas, deploy, verify_ecosystem) **coinciden con el código**.

---

## 13. Deuda técnica común

### Credenciales MySQL hardcoded `newuser` / `n#wus#r`

Verificado en los siguientes archivos:

- [limpioo/includes/global.php L111-L112](../limpioo/includes/global.php#L111)
- [limpioo/includes/api/fcm-token.php L68](../limpioo/includes/api/fcm-token.php#L68)
- [limpioo.console/includes/global.php L133-L134](includes/global.php#L133)
- [limpioo.console/includes/DataManager.php L16-L17](includes/DataManager.php#L16)
- [limpioo.console/includes/SessionHandler.php L26-L27](includes/SessionHandler.php#L26)
- [limpioo.console/ajax/auth/signup/post.php L27-L28](ajax/auth/signup/post.php#L27)
- [limpioo.console/ajax/auth/signin/post.php L17-L18](ajax/auth/signin/post.php#L17)
- [limpioo.console/scripts/deploy.sh L133](scripts/deploy.sh#L133)

> **Recomendación**: centralizar en `env.local.php` (`LIMPIOO_DB_USER` / `LIMPIOO_DB_PASS`) y eliminar las copias inline.

### Otras notas

- `DEBUG_BILLING_INTERVAL_DAYS` está fijada a **1** ([limpioo/includes/global.php L36](../limpioo/includes/global.php#L36)), correcto para entornos de prueba pero conviene auditar antes de producción.
- `ajax/sales/refund.php` contiene código de depuración activo (valor simulado y forzado del tipo de gateway) según el README de la consola; debe revisarse antes de cobrar refunds reales.

---

## 14. Documentación de referencia

- [limpioo/README.md](../limpioo/README.md) — Webapp cliente: flujo de lavado, suscripciones LPR, preview, pagos Redsys, FCM, multi-tenant.
- [limpioo.console/README.md](README.md) — Back-office: ventas híbridas, devoluciones, QR, Verifacti, sesiones, DataManager.
- [limpioo.console/docs/data-manager.md](docs/data-manager.md) — Backup/restore SIF cifrado.
- [limpioo.console/docs/ticket-pdf-system.md](docs/ticket-pdf-system.md) — Sistema de tickets PDF.
- [limpioo/docs/SALESFORCE.md](../limpioo/docs/SALESFORCE.md) — Integración con Salesforce.

---

_Última verificación contra código: ver historial git de este archivo. Si modificas el código en cualquiera de los dos proyectos, actualiza también este documento y la sección §12 si introduces o cierras alguna discrepancia._
