ADR-002: Normalización de las rutinas de tarde (catálogo + asignación)
| Metadata |
Valor |
| Estado |
Aceptado (implementado) |
| Fecha |
2026-07-12 |
| Autor(es) |
Jaume Garriga Maestre |
| Supersede |
— |
Contexto
El modelo original de AfternoonRoutine mezclaba en una fila la definición de
la rutina (labelEs/labelCa, emoji, color, monedas) y su asignación (niño, día,
orden). Para tener "Merendar" de lunes a viernes había que crear la misma rutina
cinco veces, y editar el emoji exigía tocar cinco filas. El usuario lo detectó como
fricción real de uso.
Las mañanas ya estaban bien normalizadas: Activity (catálogo por familia) +
WeeklyTemplateEntry (asignación niño+día+orden+override de monedas). Las tardes
eran la anomalía.
Opciones Consideradas
Opción A: Mantener el modelo y duplicar en la UI ("crear en varios días")
| Pros |
Contras |
| Sin migración de datos |
La duplicación persiste en BD: editar sigue costando N filas |
| Cambio solo de frontend |
La asimetría mañana/tarde se consolida |
Opción B: Reutilizar Activity también para las tardes
| Pros |
Contras |
| Una sola entidad de catálogo |
Semántica forzada: Activity arrastra material del cole (N:M) que la rutina no necesita |
| Menos código |
Acopla dos conceptos de dominio distintos |
Opción C: Nueva entidad RoutineTask gemela de Activity (elegida)
| Pros |
Contras |
| Simetría total mañana/tarde: mismo patrón mental y de código |
Migración de datos con deduplicación |
| Definir una vez, asignar a N días y N niños |
Una entidad y un CRUD más |
| Monedas con cascada: override por día → catálogo → niño |
|
Decisión
Opción C. RoutineTask = catálogo por familia (labels, emoji, color, monedas
por defecto). AfternoonRoutine queda como pura asignación (child + dayOfWeek + routineTask + orderIndex + coinsReward como override). La migración Liquibase
(changeset 003) consolida los duplicados existentes por clave natural
(familia + labels + emoji + color) sin pérdida; el changeset 004 añade
ON DELETE CASCADE para que borrar del catálogo arrastre las asignaciones
(el modelo mental del padre).
Trade-offs
Optimizamos para:
- Coste de edición del padre: cambiar una rutina se hace UNA vez y se propaga.
- Consistencia del dominio: un solo patrón (catálogo+asignación) para todo el día.
Sacrificamos:
- Simplicidad de una tabla única: aceptable; el patrón ya existía en mañanas.
- Riesgo puntual de migración: mitigado con rollback explícito por changeset y
verificación contra Postgres real (Testcontainers,
MigrationIT).
Asunciones que podrían invalidar esta decisión:
- Si apareciera la necesidad de rutinas con material asociado (como Activity),
reconsiderar la unificación con
Activity (Opción B) en lugar de duplicar N:M.
Consecuencias
- (+) Alta multi-día en una llamada (
POST /routines con lista de días).
- (+) Cascada de monedas expresiva: día > catálogo >
coinsPerTask del niño.
- (−) Lección aprendida en la migración: H2 no detecta el tipado estricto de
Postgres (
CAST(NULL AS INTEGER)); por eso existe MigrationIT con Testcontainers.
Criterios de Éxito
Referencias
backend/.../domain/RoutineTask.java, domain/AfternoonRoutine.java
backend/src/main/resources/db/changelog/changes/003-routine-catalog.yaml, 004-routine-task-cascade.yaml
- Artefactos SDD en engram:
sdd/rutinas-reutilizables/{proposal,spec,design,tasks,verify-report}