# arquitectura.md — Starter Kit RKM v6

## Stack

| Capa | Tecnología |
|---|---|
| Lenguaje | PHP 8.2 (compatible 7.4) |
| Base de datos | MySQL/MariaDB — driver `mysqli` + Prepared Statements |
| Frontend | Bootstrap 5, jQuery 3.7, DataTables, Font Awesome 6, Bootstrap Icons |
| Vendored | PHPMailer (opcional, en `/vendor/phpmailer/`) |
| Assets QR | html5-qrcode (vendored) |
| Entorno dev | MAMP (macOS), DocumentRoot → `/public` |
| Entorno prod | cPanel + Apache — sin SSH, sin Composer, sin CLI |

## Mapa de carpetas

```
rkm7/
├── app/
│   ├── core/          Router, Controller, Model, Autoload, ErrorHandler, EventDispatcher
│   ├── controllers/   Un archivo por controlador; /api/ para endpoints JSON
│   ├── middleware/    AuthMiddleware, PermissionMiddleware
│   ├── models/        Un archivo por entidad
│   ├── services/      AuthService, CacheService, MailService, MigrationService,
│   │                  NotificationService, SyncService
│   ├── helpers/       Funciones sueltas: csrf, logger, network, breadcrumb
│   ├── mobile/        QRScanner.js (demo)
│   ├── reports/       ExcelReport, PdfReport (clases esqueleto)
│   └── views/
│       ├── layouts/   header.php, footer.php
│       ├── auth/      login, forgot-password, reset-password
│       ├── dashboard/ index
│       ├── admin/     users/, roles/, permissions/, migrations/
│       ├── emails/    notification.php (template HTML)
│       └── recursos/  CSS/JS por vista (convención propia)
├── config/
│   ├── config.php         Constantes globales (BASE_URL, APP_ROOT, MAIL_*, TELEGRAM_*)
│   ├── config.local.php   Credenciales reales — generado por el instalador, no versionar
│   ├── database.php       Clase Database (mysqli)
│   ├── version.php        APP_VERSION constante
│   └── installed.lock     Bloquea el instalador una vez configurado
├── public/
│   ├── index.php          Front Controller único
│   ├── install.php        Wizard autónomo (3 pasos, sin MVC)
│   ├── .htaccess          Rewrite rules + security headers
│   ├── manifest.json      PWA
│   ├── service-worker.js  Cache-first assets / Network-first HTML
│   └── assets/
│       ├── vendor/        Bootstrap, DataTables, jQuery, Font Awesome, html5-qrcode
│       ├── css/           Estilos globales y por módulo
│       └── js/            app.js, offline-sync.js, qr-scanner.js, sw-register.js
├── sql/
│   ├── schema.sql         Tablas base (crea DB "feo" — ver errores-conocidos.md)
│   ├── seed.sql           Roles, usuario admin, permisos iniciales
│   ├── optimize.sql       Índices adicionales
│   ├── 004_password_resets.sql  Tabla password_resets
│   └── migrations.sql     Tabla migrations + registros de migraciones ya aplicadas
├── cache/                 Archivos de caché (CacheService, prefijo rkm_*.cache)
├── logs/                  app.log y error.log (solo append)
└── vendor/
    └── phpmailer/src/     PHPMailer manual — no incluido, instalar aparte
```

## Diagramas

### Arquitectura por capas

```mermaid
flowchart TB
  U[Usuario<br/>Celular / PC<br/>PWA instalada o Web] -->|HTTP/HTTPS| W[Servidor Web<br/>Apache/Nginx]
  W --> FC[public/index.php<br/>Front Controller]

  FC --> RT[Router<br/>app/core/Router.php]
  RT --> CT[Controllers<br/>app/controllers/*]

  CT --> MW[Middleware<br/>Auth / Permission]
  MW -->|allow| CT

  CT --> SV[Services<br/>app/services/*]
  SV --> MD[Models<br/>app/models/*]
  MD --> DB[(MySQL/MariaDB)]

  CT --> VW[Views<br/>views/*<br/>Layouts/Partials]

  CT --> EV[EventDispatcher<br/>app/core/EventDispatcher.php]
  SV --> EV
  EV --> NT[NotificationService<br/>Email/Telegram/Internal]
  NT --> NM[NotificationModel]
  NM --> DB

  SV --> AU[AuditModel]
  AU --> DB

  VW --> AS[Assets<br/>Bootstrap 5 + Iconos<br/>JS Offline/QR]
  AS --> U

  U --> SW[Service Worker<br/>public/service-worker.js]
  U --> MF[Manifest<br/>public/manifest.json]
  SW --> CA[(Cache Storage)]
  U --> IDB[(LocalStorage/IndexedDB<br/>cola offline)]
```

### Offline Sync

```mermaid
sequenceDiagram
  participant UI as UI (PWA)
  participant JS as offline-sync.js
  participant LS as LocalStorage (cola)
  participant API as PHP (OfflineSyncController@store)
  participant DB as MySQL
  UI->>JS: Submit
  alt Online
    JS->>API: POST /offline-sync/store (JSON)
    API->>DB: INSERT audit_logs (ejemplo)
    DB-->>API: OK
    API-->>JS: OK
  else Offline
    JS->>LS: enqueue(payload)
    LS-->>JS: OK
  end
  UI->>JS: window.online
  JS->>LS: read queue
  loop items
    JS->>API: POST /offline-sync/store
    API->>DB: INSERT audit_logs
    DB-->>API: OK
    API-->>JS: OK
  end
  JS->>LS: clear sent
  JS-->>UI: toast "Sincronización completada"
```

### Eventos + Notificaciones

```mermaid
sequenceDiagram
  participant SV as Service/Controller
  participant EV as EventDispatcher
  participant NS as NotificationService
  participant MS as MailService
  participant NM as NotificationModel
  participant DB as MySQL
  SV->>EV: dispatch(event,data)
  EV->>NS: listener(event)
  par Email
    NS->>MS: send()
  and Interno
    NS->>NM: insert()
    NM->>DB: INSERT notifications
  end
```

## Flujo de datos (request normal)

```
Browser → Apache → public/.htaccess
  → index.php (Front Controller)
      1. config.php + database.php + Autoload
      2. Helpers (csrf, logger, network, breadcrumb)
      3. Verificar installed.lock → redirigir a install.php si falta
      4. ErrorHandler::register()
      5. session_start()
      6. EventDispatcher listeners registrados
      7. Router::dispatch()
          → mapeo explícito O convención PascalCase+Controller
          → Controller::método($param1, $param2)
              → Middleware (AuthMiddleware / PermissionMiddleware)
              → Service → Model → mysqli → MySQL
              → view() / json() / redirect()
```

## Autoload

`spl_autoload_register` escanea en orden: `core/`, `controllers/`, `controllers/api/`, `models/`, `services/`, `middleware/`, `helpers/`, `generators/`, `reports/`. Sin Composer. Una clase = un archivo con el mismo nombre.

## Tablas en BD

| Tabla | Propósito |
|---|---|
| `users` | Usuarios del sistema |
| `roles` | Roles (admin, user) |
| `permissions` | Permisos atómicos |
| `role_permissions` | N:M roles ↔ permisos |
| `notifications` | Historial de notificaciones (internal/email/telegram) |
| `audit_logs` | Trazabilidad de acciones offline |
| `mail_queue` | Cola de emails (tabla existe, procesador no implementado) |
| `password_resets` | Tokens de recuperación de contraseña (TTL 2h) |
| `migrations` | Control de migraciones aplicadas |

## Qué NO existe

- Tests (unitarios o de integración).
- Procesador de la cola `mail_queue` (tabla existe, worker no).
- Paginación en listados de admin.
- Push Notifications del navegador (manifest y SW presentes, Web Push API no).
- Panel para ver/limpiar el caché (CacheService existe, no hay UI).
- Docker/docker-compose (mencionado en CHANGELOG v4 como "diseño", no implementado).
- Rate limiter persistente en BD (el login usa rate limit en sesión PHP).
- Multi-idioma / i18n.
