# Resumen de Cambios (25/02/26) # Marcelo Fecha de trabajo: 2026-02-25 Proyecto: `/opt/ACVE` ## 1) Objetivo de la sesion Implementar el backlog solicitado: - Mas mini-games con calificacion ligada al perfil. - Recomendaciones de estudio por perfil/progreso. - Certificados al completar curso. - Ver cursos inscritos (`enrolled`). - Cambiar `Start Course` por `Continue` cuando ya esta inscrito. - Actualizar Case Studies con contenido de Andres. Tambien se resolvio operativa de entorno para Prisma/Node y baseline de migraciones sobre Supabase. --- ## 2) Features implementadas ## 2.1 Mini-games (3 interactivos) + persistencia + perfil - Se expandieron los mini-games a 3 modulos interactivos: - `translation` - `term-matching` - `contract-clauses` - Se paso de historial localStorage a acciones server-side con persistencia DB (si tablas ya migradas). - Se agrego calculo de calificacion global de mini-games para perfil (promedio de ultimo intento por juego). Archivos: - `lib/data/mockPractice.ts` - `types/practice.ts` - `app/(protected)/practice/[slug]/actions.ts` - `app/(protected)/practice/[slug]/page.tsx` - `lib/recommendations.ts` - `app/(protected)/profile/page.tsx` ## 2.2 Recomendaciones de estudio (deterministicas) - Se implemento motor de recomendaciones por reglas: - basado en score de mini-games y progreso/cursos. - prioriza cursos ya inscritos e incompletos. - fallback por nivel objetivo (beginner/intermediate/advanced). - Se muestra bloque “Recommended next” en perfil. Archivos: - `lib/recommendations.ts` - `app/(protected)/profile/page.tsx` - `app/(protected)/courses/[slug]/learn/actions.ts` (refresh de recomendaciones al completar leccion) ## 2.3 Certificados automáticos + descarga PDF - Emision automatica al llegar a 100% de lecciones completadas (idempotente por curso/usuario). - Endpoint de descarga PDF: - `/api/certificates/[id]/pdf` - Integracion en: - `Profile` (listado de certificados) - `My Courses` (download cuando existe certificado) Archivos: - `lib/certificates.ts` - `app/api/certificates/[id]/pdf/route.ts` - `app/(protected)/courses/[slug]/learn/actions.ts` - `app/(protected)/profile/page.tsx` - `app/(protected)/my-courses/page.tsx` ## 2.4 UX: completion modal + confetti + CTA de certificado - Al completar curso por primera vez (cuando se emite certificado nuevo): - aparece modal de “Course completed” - animacion de confetti - boton `Download PDF` - boton `Open Profile` Archivo: - `components/courses/StudentClassroomClient.tsx` ## 2.5 Vista de cursos inscritos - Nueva ruta protegida: - `/my-courses` - Muestra progreso por curso, CTA `Continue/Review`, y descarga de certificado si aplica. Archivo: - `app/(protected)/my-courses/page.tsx` ## 2.6 Cambio Start -> Continue - En detalle de curso (`/courses/[slug]`): - si usuario inscrito: `Continue` - si no inscrito: `Start Course` - no autenticado: `Login to start` Archivo: - `app/(public)/courses/[slug]/page.tsx` ## 2.7 Profile del alumno - Nueva ruta protegida: - `/profile` - Incluye: - score mini-games - desglose latest/best por mini-game - recomendaciones - certificados + descarga Archivo: - `app/(protected)/profile/page.tsx` ## 2.8 Navbar - Se agregaron enlaces para usuario autenticado: - `My Courses` - `Profile` Archivo: - `components/Navbar.tsx` ## 2.9 Case Studies actualizados con Andres - Se reemplazo contenido mock por: - Marbury v. Madison - Miranda v. Arizona - Brown v. Board of Education - Se modelaron campos nuevos: - `summaryEs` - `legalOutcomeEs` - `category` - `difficulty` - `keyTerms` estructurado (termino + definicion) - `quizPrompt` - Se actualizaron lista y detalle para mostrar contenido legal en espanol. Archivos: - `types/caseStudy.ts` - `lib/data/mockCaseStudies.ts` - `app/(public)/case-studies/page.tsx` - `app/(public)/case-studies/[slug]/page.tsx` --- ## 3) Cambios de datos (Prisma schema) Se actualizaron modelos en `prisma/schema.prisma`: - Nuevos: - `MiniGame` - `MiniGameQuestion` - `MiniGameAttempt` - `StudyRecommendation` - enum `MiniGameDifficulty` - Ajustes: - `Certificate`: - `certificateNumber` (unique) - `pdfVersion` - `@@unique([userId, courseId])` - `Profile`: - relaciones a mini-games/recomendaciones - `Course`: - relacion inversa `recommendations StudyRecommendation[]` (se corrigio tras error P1012) Seed actualizado: - `prisma/seed.ts` para sembrar 3 mini-games y preguntas. --- ## 4) Node 24+ / Prisma / Supabase (incidentes y fix) ## 4.1 Problema detectado - En Node `18.19.1`, Prisma CLI (`v7.3.0`) fallaba con: - `ERR_REQUIRE_ESM` (zeptomatch / @prisma/dev) - Resultado: - no funcionaba correctamente `prisma generate/migrate`. ## 4.2 Fix aplicado - Se trabajo con Node `24.14.0`. - Se agrego `.nvmrc` con `24`. - Se reinstalaron dependencias (`npm ci`). - Se agregaron scripts Prisma en `package.json`: - `prisma:generate` - `prisma:status` - `prisma:migrate:dev` - `prisma:migrate:deploy` - `prisma:seed` - Se corrigio `prisma.config.ts` seed command: - `npx ts-node prisma/seed.ts` ## 4.3 Baseline y drift en Supabase - No existia `prisma/migrations` historico en repo. - Se intento baseline inicial con comando viejo (`--to-url`) y genero SQL vacio. - Se corrigio usando Prisma 7: - `--to-config-datasource` - Se genero baseline real (`~8148 bytes`) y se marco aplicado. - Estado final reportado: - `Database schema is up to date!` Nota: - Hubo dos carpetas baseline: - `20260225_baseline` (invalida / vacia) - `20260225_baseline_v2` (valida) --- ## 5) Archivos nuevos creados - `task_implementation.md` - `resumen_cambios.md` - `app/(protected)/my-courses/page.tsx` - `app/(protected)/profile/page.tsx` - `app/(protected)/practice/[slug]/actions.ts` - `app/api/certificates/[id]/pdf/route.ts` - `lib/certificates.ts` - `lib/recommendations.ts` --- ## 6) Validaciones ejecutadas Se ejecutaron en distintos momentos: - `npm run lint` -> OK - `npx tsc --noEmit` -> OK - `npm run build` -> compilacion/lint/types OK en varios intentos; hubo un fallo intermitente de worker de Next durante static generation sin stack especifico en esta sesion. - `npm run prisma:generate` -> OK (Node 24) - `npm run prisma:status` -> OK tras baseline correcto --- ## 7) Estado funcional actual - Certificado automatico: funcionando. - Descarga PDF: funcionando. - Modal de finalizacion + confetti: funcionando. - Profile muestra certificados/recomendaciones: implementado. - My Courses: implementado. - Case Studies actualizados: implementado. Observacion de UX: - El diseno del certificado actual es basico/tecnico (no final de branding visual). --- ## 8) Implicaciones y pendientes recomendados 1. Limpiar migracion baseline invalida: - revisar si se debe eliminar `prisma/migrations/20260225_baseline` del historial. 2. Confirmar estrategia de migraciones por entorno: - `migrate dev` solo en DB de desarrollo. - `migrate deploy` en staging/prod. 3. Mejorar UI de certificado/modal: - plantilla de certificado con branding final. - polish de animacion/confetti. 4. QA end-to-end: - flujo completo desde completar curso hasta ver certificado en `Profile` y `My Courses`. 5. Verificar consistencia en Supabase: - mantener `DATABASE_URL` (pooler) para runtime app. - mantener `DIRECT_URL` (5432) para Prisma migrate. --- ## 9) Resumen ejecutivo - Se implementaron todos los ejes funcionales del backlog. - Se desbloqueo el problema estructural de Prisma (Node 18 -> Node 24). - Se normalizo flujo de migraciones con baseline real en Supabase. - Ya existe flujo real de completion + certificado + descarga + visibilidad en perfil/cursos. # Daniel ## Resumen de cambios (sesión 25/02/26) ### 1) Catálogo y publicación de cursos - **Problema:** Los cursos publicados no aparecían de inmediato en el catálogo y hacía falta refrescar la página a mano. - **Causa:** No se revalidaba la ruta pública `/courses` al guardar un curso. - **Solución:** En la acción `updateCourse` se agregó `revalidatePath("/courses")` y revalidación con `"page"` y `"layout"` para la página de edición del curso, para que el catálogo y el formulario de edición muestren datos actualizados sin refrescar. ### 2) Estado y nivel del curso que volvían a valores anteriores al guardar - **Problema:** Al cambiar Estado (Borrador → Publicado) o Nivel (p. ej. Intermedio → Principiante) y dar "Guardar Cambios", el formulario seguía mostrando el valor anterior hasta hacer un refresco manual. - **Causas:** (1) Los inputs de nivel y estado son no controlados (`defaultValue`); React no actualiza el valor en re-renders. (2) `router.refresh()` a veces seguía sirviendo una versión en caché del RSC. - **Soluciones:** - En la página de edición del curso se puso `export const dynamic = "force-dynamic"` para no cachear la ruta. - Al componente `TeacherEditCourseForm` se le pasó un `key` que incluye `course.updatedAt` para forzar un nuevo montaje cuando cambian los datos del curso y así aplicar los nuevos `defaultValue`. - Tras guardar con éxito se reemplazó `router.refresh()` por `router.push(\`/teacher/courses/${course.slug}/edit\`)` para forzar una navegación y cargar datos frescos. - **Archivos:** `app/(protected)/teacher/actions.ts`, `app/(protected)/teacher/courses/[slug]/edit/page.tsx`, `components/teacher/TeacherEditCourseForm.tsx`. ### 3) Vista previa gratuita para usuarios sin sesión - **Objetivo:** Que los usuarios no autenticados puedan ver lecciones marcadas como "free preview" y que en la ficha del curso se indique cuáles son y se ofrezca un CTA para verlas. - **Cambios:** - Se movió la ruta de aprendizaje de **`app/(protected)/courses/[slug]/learn`** a **`app/(public)/courses/[slug]/learn`** (page + actions) para que no quede detrás de un layout que exija autenticación. - Se actualizó el import en `StudentClassroomClient` para usar las acciones en la nueva ruta pública. - En la página de detalle del curso (landing): - Se incluyó `isFreePreview` en la consulta de lecciones. - En "Course structure preview" se muestra un indicador "Free preview" (pill amarillo) en las lecciones que lo son. - Para invitados: si hay al menos una lección en free preview, se muestra el botón principal "Watch free preview" con enlace a `/courses/[slug]/learn?lesson=[id]`, y como secundario "Login to unlock all lessons" con `redirectTo=/courses/[slug]` para que tras iniciar sesión vuelvan a la ficha y puedan inscribirse/comprar. - **Archivos:** `app/(public)/courses/[slug]/learn/page.tsx`, `app/(public)/courses/[slug]/learn/actions.ts`, `app/(public)/courses/[slug]/page.tsx`, `components/courses/StudentClassroomClient.tsx`. Eliminados los archivos bajo `app/(protected)/courses/[slug]/learn/`. ### 4) Botón "Editar Título" en módulos - **Problema:** El botón "Editar Título" en cada módulo del plan de estudios no hacía nada. - **Solución:** - Nueva acción de servidor `updateModuleTitle(moduleId, title)` en teacher actions: valida que el módulo sea del profesor, actualiza el título en BD y revalida las rutas correspondientes. - En el formulario de edición del curso: al hacer clic en "Editar Título" se muestra un campo de texto inline con el título actual y botones "Guardar" y "Cancelar"; Enter guarda, Escape cancela. Tras guardar se navega a la misma página de edición para ver el título actualizado. - **Archivos:** `app/(protected)/teacher/actions.ts`, `components/teacher/TeacherEditCourseForm.tsx`.