Bloque A de la fase SaaS:
- Recuperación por email: código de un solo uso (solo su SHA-256 en BD),
caducidad 30 min, emitir uno nuevo invalida los anteriores, respuesta
idéntica exista o no la cuenta (anti-enumeración) y email asíncrono;
restablecer cierra todas las sesiones de la familia. MailService cae a
modo log sin SMTP configurado.
- LoginAttemptService: 5 fallos -> bloqueo con backoff exponencial (429 +
Retry-After) en login, PIN del panel y solicitudes de reset, comprobado
ANTES de evaluar credenciales.
- Registro exige aceptar la política de privacidad (privacy_accepted_at).
- Borrado definitivo de cuenta (RGPD) con confirmación por contraseña.
- CORS por configuración; seeder demo fail-safe (matchIfMissing=false,
activado explícito en el compose local); application-prod.yml.
- Liquibase 005 con rollback. 44 tests verdes incl. migración en Postgres.
Botón "Mañana ›" en la cabecera: muestra el día siguiente en solo
lectura para preparar la mochila la noche antes. La vista se calcula al
vuelo desde las plantillas SIN materializar DailyTask (los cambios del
panel de esa noche siguen entrando al generarse el día de verdad), con
ids sintéticos negativos no accionables, sin temporizador ni progreso.
Banner "Así será mañana" y estados vacíos propios. Test de integración:
la vista previa no persiste tareas del día siguiente.
La familia demo siembra el horario escolar real de 4º de primaria para
Leo (11 asignaturas nuevas bilingües + 29 entradas semanales en orden
cronológico; Piscina lleva la Toalla asociada). Nora y Mía conservan el
horario genérico. Test que fija el lunes completo de Leo.
buildTimer clavaba el contador en "0 min" el resto del día (Math.max(0,..)),
incluso en días sin cole. Ahora es función pura: sin tareas de mañana o con
la hora de salida ya pasada devuelve minutos null y el kiosko no lo pinta.
Test unitario determinista de los cinco casos.
Un día sin tareas muestra una tarjeta con la mascota del niño en vez de
una pantalla en blanco; la columna de tarde vacía tiene su propio mensaje.
El feedback de recompensa suma una vibración corta (Vibration API) que se
dispara junto al sonido sobre el mismo evento.
- Changeset 004: ON DELETE CASCADE en fk_routine_assignment_task; borrar
una rutina del catálogo arrastra sus asignaciones en vez de fallar (test).
- El orderIndex de la asignación multi-día lo calcula el backend al final
de CADA día destino (antes lo enviaba el front desde el día visible).
- MigrationIT con Testcontainers: el changelog completo y el mapeo JPA se
verifican contra Postgres 16 real (H2 no detecta su tipado estricto).
- DataSeeder delega en InitialDatasetService: una sola fuente de verdad
del dataset inicial; la demo solo añade sus extras.
- Eliminado .gitkeep de changes/ (WARN de Liquibase en cada arranque).
Tokens de movimiento centralizados (duraciones y curvas únicas), feedback
de pulsación visible e inmediato en tarjeta de tarea, TTS, chips, teclado
y navegación; áreas táctiles mínimas de 44-48px en controles pequeños;
tracking positivo en etiquetas en mayúsculas; touch-action manipulation
para eliminar el retardo de doble-tap en la tablet kiosko.
Postgres tipa el NULL pelado del SELECT como text y rechaza insertarlo
en routine_task.coins_reward (integer). H2 lo toleraba; Postgres no.
Se castea con CAST(NULL AS INTEGER). Validado arrancando contra
Postgres 16 real: los 5 changesets de 003 aplican y la app arranca.
Al registrar una familia se siembra el catálogo de materiales escolares
típicos y el catálogo de rutinas. Al dar de alta un niño se le asignan
las rutinas de tarde de L-V escaladas por su edad (tramos 8-9 / 10-11 /
12-14), reutilizando el catálogo de la familia.
CRUD del catálogo en /api/parents/routine-tasks y alta de una rutina
a varios días de una vez en ParentScheduleController. RoutineView
deriva la definición del catálogo e incluye routineTaskId.
Normaliza las rutinas de tarde replicando el patrón de las mañanas:
RoutineTask es el catálogo (gemela de Activity) y AfternoonRoutine
pasa a ser pura asignación niño+día. Incluye migración Liquibase 003
con consolidación de duplicados y rollback, y la cascada de monedas
(override del día -> catálogo -> coinsPerTask) en DayGenerationService.
Añade sábado y domingo a los selectores de día de Horario y Rutinas. El
backend ya generaba el día para cualquier día de la semana; solo faltaba
ofrecer el fin de semana en el panel.
Extrae app-emoji-picker y app-color-picker a shared/ y los usa en las
pestañas de niños, materiales, rutinas y recompensas, que tenían el mismo
problema: input de color a pelo y emoji escrito a mano. Ahora se elige el
icono de una rejilla de emojis y el color de la paleta del handoff.
Rediseña el alta de niño que era confusa: selector de mascota por emojis,
paleta de colores clicable, campos con etiqueta legible (la edad antes se
truncaba e impedía activar 'Añadir'), la hora de salida explicada como
opcional y tooltips en cada campo.
Añade la gestión de perfiles de hijo en el panel de padres (crear con
mascota/nombre/edad/color/hora de salida y borrar), que faltaba: una familia
recién registrada empieza sin niños y necesita poder añadirlos. El backend
(CRUD de Child) ya existía; faltaba la UI.
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.
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.