feat: app completa recordaLexia (fases 1-5)

App web familiar de rutinas visuales para niños con TDAH: muestra cada día el
material del cole y las rutinas de tarde, con gamificación por monedas y tienda
de recompensas. Multi-niño y bilingüe ES/CA. Uso doméstico/homelab.

Backend (Spring Boot 3.5 / Java 21 / Gradle):
- Dominio por capas, PostgreSQL + Liquibase, datos semilla.
- API REST con DTOs: /today, toggle con monedas y bonos de bloque/día, monedero,
  tienda/canje, ajustes y CRUD del panel de padres.
- Seguridad ligera por PIN (BCrypt + sesion en memoria), sin Keycloak.
- Tests JUnit: generacion del dia, monedas/bonos con reversion, canje, seguridad.

Frontend (Angular 19, standalone + signals):
- Perfiles, Home (Tablero y Foco), Tienda y panel de padres (5 pestañas).
- Tipografia OpenDyslexic conmutable (accesibilidad), i18n ES/CA, TTS y sonido.
- Tokens de diseño fieles al handoff (paleta, animaciones, monedas voladoras).

Empaquetado:
- Docker multi-stage + docker-compose (PostgreSQL + backend + Nginx).
- Decisiones de arquitectura documentadas en docs/adr.
This commit is contained in:
Jaume Garriga Maestre
2026-06-21 10:48:57 +02:00
commit 52e559a159
160 changed files with 29022 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
# ADR 0003 — Decisiones de dominio y seguridad (Fase 2 backend)
- **Estado:** aceptada
- **Fecha:** 2026-06-21
- **Fase:** 2 (dominio + API + seguridad)
## Contexto
El contrato de backend deja varias decisiones "a tu criterio". Se documentan aquí
las tomadas al implementar el dominio, la lógica de negocio y la seguridad.
## Decisiones
1. **i18n por columnas embebidas** `label_es` / `label_ca` (no tabla de
traducciones). Encaja con el shape de los DTOs y simplifica las consultas.
2. **Capas, sin hexagonal completa.** Entidad JPA como modelo de dominio (con
comportamiento donde aporta: monedero en `Child`, marcado en `DailyTask`), DTOs
tipo `record` en el borde. **Nunca se exponen entidades**.
3. **Mañana vs. tarde.** La mañana se modela con `Activity` (catálogo) +
`WeeklyTemplateEntry` (asignación por día). La tarde con `AfternoonRoutine`
directa por día. Se evita una FK polimórfica.
4. **Eventos = banner, no tareas.** Los `SpecialEvent` (examen/deberes) se muestran
en el banner informativo del día (`specialEvents[]`), NO se materializan como
`DailyTask` marcables (coherente con el prototipo). El enum `TaskOrigin.EVENT`
queda disponible por si se decide lo contrario más adelante.
5. **Bonos reconciliables.** El bono de bloque y el de día se modelan como
transacciones de monedas con el mismo motivo: +importe al otorgar, -importe al
revertir. "Suma neta > 0" indica bono activo. Hace el marcar/desmarcar robusto
ante cualquier secuencia.
6. **Seguridad ligera.** PIN de padres con hash BCrypt; al validarlo se abre una
sesión en memoria identificada por un valor opaco (cabecera `X-Parent-Session`).
`/api/parents/**` exige rol PARENT; el resto (kiosko del niño) es abierto. Todo
encapsulado en el paquete `security` para poder sustituirlo por Keycloak.
7. **Semilla por `DataSeeder`** (ApplicationRunner, solo si la BD está vacía), no
por Liquibase. Más mantenible y tipado. Desactivable con
`recordalexia.seed.enabled=false` (lo usan los tests).
8. **Tests sobre H2** (modo PostgreSQL) con Liquibase. Se valorará Testcontainers
en una iteración posterior para fidelidad total con PostgreSQL.
## Consecuencias
- Los textos visibles siempre viajan en ES y CA; el frontend elige idioma.
- Cambiar a Keycloak no afecta a controladores ni servicios de negocio.
- La zona horaria del negocio (Europe/Madrid) se centraliza en un `Clock` inyectable.