feat: fase 2+3 — expansion masiva multi-perfil + bug fixes + hardening

Fase 2 (expansion):
- Francesca: +6 etapas matematicas (5-10), +7 etapas lectura (3-9), +2 ortografia
- Sebastian: +8 etapas matematicas (4-11), +6 lectura, +3 historia, +3 geografia, +1 banderas
- Nuevas paginas: ortografia, lectura, geografia, matematicas
- ~900 ejercicios nuevos, paridad ~500 por perfil

Fase 3 (bug fixes + hardening):
- Fix: SessionLog auto-create en grade route
- Fix: engine cache (no borrar antes de revisar)
- Fix: FSRS cards actualizadas en flujo curriculum
- Fix: responseMs real (no hardcodeado 3000)
- Fix: options dentro de content en sebastian etapa-1
- Fix: trazo-letra consonantes crash
- Security: execFileSync anti-command-injection en TTS
- DB: 18 cascade deletes + indices + unique constraints
- APIs debug: reset, state, seed
- Docker: espeak-ng + prisma + user/group
- E2E: 23 tests nuevos (curriculum-flow.spec.ts)
- Code review: tailwind colors, middleware dev mode, eslint config

Verificado: tsc exit 0, build exit 0, 61 E2E tests pass
This commit is contained in:
renato97
2026-07-25 22:07:28 -03:00
parent 25614704dc
commit a3360ec6e4
67 changed files with 5294 additions and 213 deletions
+131
View File
@@ -0,0 +1,131 @@
import type { Stage } from "../types"
const lecturas = [
{
text: "En primavera los árboles se llenan de flores. Los pájaros hacen nidos. El clima es templado y los días son más largos.",
preguntas: [
{ q: "¿Qué pasa con los árboles en primavera?", op: ["Se llenan de flores", "Pierden las hojas", "Se cubren de nieve"], correcta: "Se llenan de flores" },
{ q: "¿Qué animales hacen nidos en primavera?", op: ["Los pájaros", "Los gatos", "Los perros"], correcta: "Los pájaros" },
{ q: "¿Cómo es el clima en primavera?", op: ["Templado", "Muy frío", "Muy caluroso"], correcta: "Templado" },
],
emoji: "🌸",
},
{
text: "En verano hace mucho calor. Los niños van a la playa o a la pileta. Comen helado para refrescarse. Los días son muy largos.",
preguntas: [
{ q: "¿Cómo es el clima en verano?", op: ["Hace mucho calor", "Hace frío", "Está templado"], correcta: "Hace mucho calor" },
{ q: "¿Qué comen los niños para refrescarse?", op: ["Helado", "Sopa", "Pan"], correcta: "Helado" },
{ q: "¿Adónde van los niños en verano?", op: ["A la playa o pileta", "A la escuela", "Al parque de nieve"], correcta: "A la playa o pileta" },
],
emoji: "☀️",
},
{
text: "En otoño las hojas de los árboles se ponen amarillas y marrones. El viento las hace caer. Hace más fresco y empieza el colegio.",
preguntas: [
{ q: "¿De qué color se ponen las hojas en otoño?", op: ["Amarillas y marrones", "Verdes y azules", "Rojas y naranjas"], correcta: "Amarillas y marrones" },
{ q: "¿Qué hace caer las hojas?", op: ["El viento", "La lluvia", "El sol"], correcta: "El viento" },
{ q: "¿Qué empieza en otoño?", op: ["El colegio", "Las vacaciones", "La navidad"], correcta: "El colegio" },
],
emoji: "🍂",
},
{
text: "En invierno hace mucho frío y a veces nieva. Los niños usan abrigo, bufanda y guantes. Beben chocolate caliente.",
preguntas: [
{ q: "¿Qué usan los niños en invierno?", op: ["Abrigo, bufanda y guantes", "Camiseta y short", "Traje de baño"], correcta: "Abrigo, bufanda y guantes" },
{ q: "¿Qué beben los niños?", op: ["Chocolate caliente", "Jugo frío", "Agua con hielo"], correcta: "Chocolate caliente" },
{ q: "¿Qué pasa a veces en invierno?", op: ["Nieva", "Hay sol fuerte", "Huele a flores"], correcta: "Nieva" },
],
emoji: "❄️",
},
{
text: "La lluvia es importante para las plantas. Cuando llueve, las flores crecen. Los animales beben agua de los charcos.",
preguntas: [
{ q: "¿Por qué es importante la lluvia?", op: ["Para las plantas", "Para jugar", "Para dormir"], correcta: "Para las plantas" },
{ q: "¿Qué pasa con las flores cuando llueve?", op: ["Crecen", "Se marchitan", "Se cierran"], correcta: "Crecen" },
{ q: "¿Qué hacen los animales con los charcos?", op: ["Beben agua", "Se bañan", "Saltan"], correcta: "Beben agua" },
],
emoji: "🌧️",
},
{
text: "Cuando el viento sopla fuerte, los árboles se mueven. Las hojas vuelan por el aire. A veces el viento tira cosas al piso.",
preguntas: [
{ q: "¿Qué pasa con los árboles cuando hay viento?", op: ["Se mueven", "Se caen", "Crecen más rápido"], correcta: "Se mueven" },
{ q: "¿Qué vuelan por el aire?", op: ["Las hojas", "Las piedras", "Los autos"], correcta: "Las hojas" },
{ q: "¿Qué puede tirar el viento?", op: ["Cosas al piso", "La pintura", "Las puertas"], correcta: "Cosas al piso" },
],
emoji: "💨",
},
{
text: "El arcoíris aparece después de la lluvia cuando sale el sol. Tiene 7 colores: rojo, naranja, amarillo, verde, azul, índigo y violeta.",
preguntas: [
{ q: "¿Cuándo aparece el arcoíris?", op: ["Después de la lluvia", "En invierno", "De noche"], correcta: "Después de la lluvia" },
{ q: "¿Cuántos colores tiene el arcoíris?", op: ["7", "5", "10"], correcta: "7" },
{ q: "¿Qué tiene que pasar para que aparezca?", op: ["Salir el sol", "Nevar", "Hacer frío"], correcta: "Salir el sol" },
],
emoji: "🌈",
},
{
text: "Las nubes están formadas por gotitas de agua. Cuando se juntan muchas, puede llover. Las nubes grises traen lluvia.",
preguntas: [
{ q: "¿De qué están hechas las nubes?", op: ["De gotitas de agua", "De algodón", "De humo"], correcta: "De gotitas de agua" },
{ q: "¿Qué color tienen las nubes de lluvia?", op: ["Grises", "Blancas", "Negras"], correcta: "Grises" },
{ q: "¿Qué pasa cuando se juntan muchas gotitas?", op: ["Puede llover", "Hace sol", "Sale el arcoíris"], correcta: "Puede llover" },
],
emoji: "☁️",
},
{
text: "El sol nos da luz y calor. Las plantas necesitan sol para crecer. Sin sol no habría vida en la Tierra.",
preguntas: [
{ q: "¿Qué nos da el sol?", op: ["Luz y calor", "Agua y viento", "Nieve y frío"], correcta: "Luz y calor" },
{ q: "¿Qué necesitan las plantas del sol?", op: ["Luz para crecer", "Agua para beber", "Sombra para dormir"], correcta: "Luz para crecer" },
{ q: "¿Qué pasaría sin sol?", op: ["No habría vida", "Haría más calor", "Las plantas crecerían más"], correcta: "No habría vida" },
],
emoji: "🌞",
},
{
text: "En las tormentas hay rayos y truenos. Primero vemos el relámpago y después escuchamos el trueno. La lluvia fuerte moja todo.",
preguntas: [
{ q: "¿Qué vemos primero en una tormenta?", op: ["El relámpago", "El trueno", "El viento"], correcta: "El relámpago" },
{ q: "¿Qué escuchamos después?", op: ["El trueno", "La lluvia", "El relámpago"], correcta: "El trueno" },
{ q: "¿Cómo es la lluvia en las tormentas?", op: ["Fuerte", "Suave", "Tibia"], correcta: "Fuerte" },
],
emoji: "⛈️",
},
]
const exercises: any[] = []
let idx = 0
for (const l of lecturas) {
for (const p of l.preguntas) {
exercises.push({
id: `fra5-estaciones-${idx}`,
stage: 5,
skillCode: `lectura-estaciones-${idx}`,
type: "lectura",
prerequisites: idx === 0 ? [`fra4-animales-29`] : [`fra5-estaciones-${idx - 1}`],
content: {
instruction: p.q,
text: l.text,
audioText: l.text,
emoji: l.emoji,
options: p.op.map((o) => ({
label: o,
correct: o === p.correcta,
id: o.toLowerCase().slice(0, 12),
})),
},
functionalContext: "Centro de interés Decroly: las estaciones. Vocabulario temporal y relaciones causa-efecto del clima.",
errorType: "omision-letra",
})
idx++
}
}
const stage: Stage = {
id: 5,
name: 'Centro de interés: "Las estaciones"',
description: "Textos sobre primavera, verano, otoño e invierno con preguntas de comprensión (método Decroly).",
exercises,
}
export default stage