Files
recordalexia/docs/adr/0004-multi-tenant-y-auth.md
Jaume Garriga Maestre 24a0c8a0dd feat: cuentas de familia (multi-tenant), registro/login y preferencias
Convierte recordaLexia de una sola familia a multi-familia, con cuentas
propias y persistencia de preferencias.

Backend:
- Tenant Family (email único + contraseña BCrypt + PIN + prefs de cuenta);
  family_id en child/activity/material_item/reward; aislamiento por familia
  (acceso cruzado responde 404).
- Auth propia (sin Keycloak): registro/login email+contraseña, sesiones de
  familia persistidas en BD (sobreviven a reinicios), panel de padres tras PIN.
- Liquibase 002-multitenant; seeder crea una familia demo.
- Tests de aislamiento entre familias, registro/login y gate del panel.

Frontend:
- Login, registro y pantalla de cuenta; guards (sesion + PIN) e interceptor
  de sesion global; perfiles scopeados a la familia.

Preferencias:
- OpenDyslexic persistida por nino (child.dyslexiaFont) y default de cuenta.

Decisiones en docs/adr/0004.
2026-06-21 13:11:34 +02:00

2.1 KiB

ADR 0004 — Multi-tenant + registro/login propio (email/contraseña)

  • Estado: aceptada
  • Fecha: 2026-06-21
  • Supersede (parcialmente): ADR 0002/0003 en lo relativo a "auth ligera sin cuentas".

Contexto

El contrato original definía la app como una sola familia, con auth ligera (PIN de padres) y datos globales. El usuario pide convertirla en multi-familia (multi-tenant) con registro/login propio y persistencia de preferencias.

Decisión

  1. Tenant = Family (cuenta con email único + contraseña BCrypt + PIN + prefs). Las entidades raíz (child, activity, material_item, reward) llevan family_id. El resto cuelga del niño.
  2. Aislamiento: toda consulta raíz se filtra por la familia de la sesión; las operaciones por id verifican pertenencia y, si no, responden 404 (no 403, para no filtrar existencia).
  3. Sesión de familia ligada al dispositivo, persistida en BD (family_session) para sobrevivir a reinicios (clave para el kiosko). Cabecera X-Auth-Session. Toda la API exige sesión válida; el niño NO se loguea (el adulto deja la sesión abierta en la tablet).
  4. Panel de padres: además de la sesión, exige desbloqueo con PIN (POST /api/parents/unlock), que concede el rol PARENT durante 30 min.
  5. Sin Keycloak: auth propia encapsulada en el paquete security (AuthService, SessionAuthService, SessionAuthFilter).
  6. Preferencia OpenDyslexic pasa a campo por niño (child.dyslexia_font) + un default de cuenta (family.default_dyslexia_font).

Consecuencias

  • Registro abierto (cualquiera crea una familia). Rate-limiting y verificación de email quedan como mejora futura (homelab).
  • La migración del esquema (002-multitenant.yaml) añade family_id NOT NULL; en BD ya poblada habría que hacer backfill (en este proyecto se parte de BD limpia con docker compose down -v).
  • La sesión de 30 días en el dispositivo es un compromiso UX/seguridad razonable para un kiosko doméstico; revocable borrando la fila de family_session.
  • Sustituir la auth por un IdP externo (Keycloak) solo afectaría al paquete security.