# decisiones.md — Starter Kit RKM v6

Decisiones inferidas del código y los documentos del repo.

---

## 1. mysqli en lugar de PDO

**Decisión:** `Database` usa `new mysqli()`, no PDO.
**Por qué:** Compatibilidad directa con cPanel compartido y PHP 7.4+. Sin Composer, instalar PDO en algunos hostings es problemático. `mysqli` viene siempre habilitado.
**Descartado:** PDO (mencionado como "opcional" en el instalador). Se lista el check `pdo_mysql` pero nunca se usa en el código de producción.

---

## 2. Autoload propio sin Composer

**Decisión:** `spl_autoload_register` que escanea rutas fijas.
**Por qué:** Restricción absoluta: sin Composer en producción (cPanel, FTP). El autoload propio cubre todos los directorios del MVC.
**Descartado:** PSR-4 / Composer autoload. Costo: si una clase no está en las rutas listadas, falla silenciosamente.

---

## 3. Front Controller único (`public/index.php`)

**Decisión:** Todo pasa por `index.php` vía reescritura de .htaccess (`?url=`).
**Por qué:** Patrón MVC estándar. Centraliza sesión, autoload, errores y eventos en un solo punto.
**Descartado:** Múltiples entry points (aumentaría el riesgo de olvidar inicializar seguridad en alguno).

---

## 4. Router por convención + mapa explícito

**Decisión:** `user-admin` → `UserAdminController` automáticamente. Rutas que no siguen la convención se declaran en `Router::$routes[]`.
**Por qué:** Reduce boilerplate para el caso común. El mapa explícito cubre verbos especiales (`authenticate`, `send-reset`, etc.).
**Descartado:** Router con métodos HTTP (RESTful completo) — añadiría complejidad innecesaria para un kit de arranque.

---

## 5. Rate limiting en sesión PHP (no en BD)

**Decisión:** Los intentos fallidos de login se guardan en `$_SESSION['login_attempts'][$ip]`.
**Por qué:** Cero dependencias extra. Simple y suficiente para el MVP.
**Descartado:** Tabla en BD (como `sec_rate_limit` de los proyectos del Hotel). Pendiente si se requiere rate limit persistente entre reinicios de sesión o en múltiples servidores.

---

## 6. Caché por archivos con flock()

**Decisión:** `CacheService` almacena en `/cache/*.cache` con `flock()` y serialización.
**Por qué:** Sin Redis/Memcached en cPanel. `flock()` garantiza atomicidad básica. APCu mencionado en el docblock pero no implementado (fallback manual a archivos).
**Descartado:** APCu (no siempre disponible), Redis (requiere extensión y servidor separado).

---

## 7. PWA con estrategia mixta en Service Worker

**Decisión:** Network-first para HTML, Cache-first para assets.
**Por qué:** Las páginas HTML deben estar siempre actualizadas; los assets (CSS/JS) cambian poco y es aceptable servirlos desde caché.
**Descartado:** Cache-first para todo (riesgo de páginas desactualizadas); Network-only (anula la funcionalidad offline).

---

## 8. Offline sync con LocalStorage

**Decisión:** La cola offline usa `localStorage` con clave `rkm_offline_queue_v1`.
**Por qué:** Más simple que IndexedDB. Suficiente para volúmenes pequeños (máx. 50 items/batch).
**Descartado:** IndexedDB — el código mismo lo señala como mejora futura para operaciones masivas.

---

## 9. NotificationService con auditoría en todos los canales

**Decisión:** Cada canal (email, telegram) registra en `notifications` el resultado `sent/failed`.
**Por qué:** Trazabilidad completa sin tabla de log separada por canal.
**Descartado:** Solo loggear errores (perdería visibilidad de envíos exitosos).

---

## 10. Instalador autónomo (sin MVC)

**Decisión:** `public/install.php` es un wizard standalone de 3 pasos que no carga el MVC.
**Por qué:** El MVC requiere `config.local.php` y `installed.lock` para funcionar; el instalador es precisamente quien los crea.
**Descartado:** CLI installer (sin acceso SSH en producción).

---

## 11. schema.sql hardcodea el nombre de BD `feo`

**Decisión:** El `schema.sql` crea `DATABASE feo` y hace `USE feo`.
**Por qué:** [PENDIENTE: parece un artefacto de desarrollo. El instalador parchea esto con regex al ejecutar el schema.]
**Riesgo:** Si alguien ejecuta `schema.sql` directamente en producción, crea la BD `feo`. Ver errores-conocidos.md §1.
