Saltar al contenido
Volver a proyectos

Aprender para Todos

Plataforma de estudio gratuita, de preescolar al examen nacional de ingreso, construida sin backend y sin cuenta: el progreso vive en el dispositivo del estudiante.

aprenderparatodos.cianci.com.br

Contexto

Proyecto social: una plataforma de estudio gratuita, organizada por etapa y año escolar, que cubre desde preescolar hasta la enseñanza media, incluyendo el ENEM (el examen nacional de ingreso a la universidad en Brasil) y su redacción. El público son estudiantes, familias que quieren acompañar, aspirantes al examen y docentes u ONG, en buena parte entrando desde el móvil.

Desafío

Sostener una plataforma educativa completa con un coste de operación cercano a cero y sin recoger datos personales de estudiantes, muchos de ellos menores de edad. Quitar el backend resuelve coste y privacidad de una vez, pero deja dos preguntas abiertas: dónde vive el progreso del alumno y cómo se crea contenido sin un CMS.

Mi papel

Arquitectura, desarrollo, modelado del dominio educativo, accesibilidad, pruebas, infraestructura y despliegue.

Responsabilidades

  • Arquitectura de la aplicación y del modelo de contenido.
  • Modelado del dominio educativo: etapas, años, áreas, itinerarios, módulos, lecciones y cuestionarios.
  • Capa de persistencia local sobre IndexedDB.
  • Accesibilidad como preferencia de primera clase.
  • Suite de pruebas y pipeline de CI.
  • Infraestructura AWS y despliegue en dos entornos.

Restricciones

  • Proyecto gratuito: el coste de operación tiene que caber en quien lo mantiene, indefinidamente.
  • El público incluye niños: cuenta y registro significan recoger datos personales de un menor.
  • Mobile first, con un dispositivo posiblemente modesto: cada KB de JavaScript lo paga el usuario.
  • Una base de contenido amplia (varias etapas, años y asignaturas) que debe crecer sin volverse un caos.

Arquitectura

  • Next.js 16 con App Router y export estático: ningún servidor de aplicación, ninguna base de datos en runtime.
  • Ninguna dependencia de runtime más allá del propio framework: next, react y react-dom. Sin librería de estado, de UI ni de acceso a IndexedDB.
  • Persistencia en el dispositivo: wrapper propio sobre IndexedDB, con un repositorio por dominio (progreso, cuestionarios, cuaderno de errores, plan de estudio, borradores, historial).
  • Preferencias pequeñas y síncronas en localStorage, separadas de IndexedDB para no bloquear el primer render.
  • Contenido como código TypeScript, con IDs branded para que el compilador rechace una referencia cruzada errónea entre entidades.
  • Pipeline editorial dentro del propio dominio: validadores puros que devuelven issues estructurados, informe de cobertura y estados editoriales explícitos.
  • Consola editorial local ejecutándose en el navegador, sin CMS y sin servidor.
  • Sobre versionado de exportación e importación de datos, validado a la entrada, como alternativa a sincronizar por servidor.

Principales decisiones técnicas

Sin backend: el progreso del estudiante vive en el dispositivo, en IndexedDB.

Por qué

Cuenta y base de datos significarían recoger datos personales de menores, asumir el deber de custodiarlos y pagar un servidor para siempre. Además pondrían una pantalla de registro entre el alumno y la lección. Sin backend, el coste de operación de un proyecto gratuito baja a hospedaje estático, y no existe dato de menor que se pueda filtrar.

Trade-offs

  • El progreso no se sincroniza entre dispositivos: cambiar de móvil empieza de cero.
  • Borrar los datos del navegador elimina el historial de estudio.
  • Sin servidor no hay telemetría agregada, ninguna visión de cómo se usa realmente el contenido.
  • Mitigación parcial: exportación e importación de datos en un sobre versionado, controlado por el usuario.

Cero dependencias de runtime más allá del framework.

Por qué

Cada KB de JavaScript lo paga justamente el dispositivo modesto que es el público objetivo. Y cada dependencia es mantenimiento futuro que un proyecto gratuito no puede costear a largo plazo. El Context de React y la API nativa de IndexedDB cubren lo que el producto necesita.

Trade-offs

  • Más código propio que mantener. El wrapper de IndexedDB, por ejemplo, es nuestro.
  • Se renuncia a las comodidades de librerías maduras (devtools, caché, utilidades).
  • A cambio: bundle pequeño, superficie de supply chain casi nula y ninguna rotura llegada de un tercero.

Contenido como código versionado, con pruebas que protegen la propia base de contenido.

Por qué

Un CMS traería de vuelta el servidor y la base de datos que la primera decisión eliminó. Con el contenido en TypeScript, el compilador garantiza su forma y el CI valida cobertura y pendientes antes del despliegue. Un error de contenido se convierte en build en rojo, no en bug en producción.

Trade-offs

  • La autoría pasa a exigir build y Git, lo que no sirve para un autor no técnico.
  • De ahí la consola editorial local: autoría en el navegador, con borrador en IndexedDB y exportación, sin reintroducir un servidor.
  • Una base de contenido grande se traduce en muchos archivos TypeScript que navegar.

Implementación

  • Itinerarios por etapa, año y asignatura, con lección y cuestionario canónicos por módulo.
  • Cuaderno de errores, plan de estudio, progreso y métricas, todo local.
  • Área de ENEM, incluida la redacción.
  • Múltiples perfiles en el mismo dispositivo, para cuando el móvil se comparte.
  • Accesibilidad en tres ejes (movimiento reducido, alto contraste y tamaño de texto), con el valor por defecto heredado de las preferencias del sistema operativo y sobrescritura persistida del usuario.
  • Exportación e importación de los datos del dispositivo, con validación y vista previa antes de importar.

Operación en producción

  • Export estático publicado en un bucket S3 privado, servido por CloudFront con OAC.
  • URLs limpias resueltas en el borde por una CloudFront Function en viewer-request.
  • Infraestructura provisionada con scripts idempotentes y versionados, con usuario IAM por entorno.
  • Caché separada por clase de asset: HTML revalidable, assets con hash inmutables.
  • El CI ejecuta pruebas, lint, build y una validación del export antes de cualquier despliegue.
  • Dos entornos: staging automático al hacer merge, producción solo por activación manual con confirmación explícita.
  • Sin servidor de aplicación en producción: no hay nada que operar, parchear ni escalar.

Resultados

  • Coste de operación limitado al hospedaje estático, lo que hace sostenible un proyecto gratuito.
  • Ningún dato del estudiante sale del dispositivo: no hay cuenta, ni base de datos, ni analytics.
  • Integridad del contenido protegida por pruebas que corren en el CI, cubriendo persistencia, dominio y la propia base de contenido.
  • Accesibilidad tratada como parte de la arquitectura y no como un ajuste posterior: hereda la preferencia del sistema y deja que el usuario la sobrescriba.
  • Cada bug de contenido se convirtió en una prueba permanente, en lugar de una corrección puntual.

Stack

  • Next.js 16
  • React 19
  • TypeScript
  • Tailwind CSS 4
  • IndexedDB
  • Vitest
  • AWS S3
  • AWS CloudFront
  • CloudFront Functions
  • GitHub Actions