[ Trabajo seleccionado ] / 2026
Notas
>>> Resumen
Registro de calificaciones académicas: ponderaciones complejas, nota necesaria para aprobar, horario con IA, avisos y enlaces de solo lectura.
- Rol
- Diseño y desarrollo
- Stack
- Next.js, React, TypeScript, Tailwind CSS, Supabase, PostgreSQL, Vercel
- Año
- 2026
>>> Detalles
Una web app para llevar todas las calificaciones de una titulación y saber, en todo momento, cuánto necesitas sacar para aprobar. Es multiusuario (acceso con Google), instalable como PWA y está en español.
- +Jerarquía opcional titulación → curso → periodo → asignatura → evaluaciones, con varias titulaciones y selector global.
- +Ponderaciones por categorías, pesos individuales, subpartes y series periódicas (Práctica 1…N), con escala, decimales y redondeo configurables.
- +Reglas de evaluación: nota mínima por parte, descartar la peor nota, recuperaciones, tope máximo y puntos extra.
- +Nota necesaria, simulador «qué pasaría si», mejor y peor caso, y medias del periodo y la titulación ponderadas por ECTS.
- +Horario por periodo, con un asistente de IA que propone el horario y deja revisarlo antes de guardarlo.
- +Calendario, avisos por push y correo, y sincronización opcional con Google Calendar.
- +Enlaces de solo lectura revocables y con caducidad, exportación e importación (JSON, CSV, PDF) y plantillas de asignatura.
- +Aislamiento por usuario con RLS en todas las tablas y 758 tests, entre ellos pruebas de propiedades sobre el motor de cálculo.
>>> Caso de estudio
- 2
- Días de desarrollo
- 80
- Commits
- 758
- Tests
- 37
- Migraciones
* Días y commits salen del historial de git (20 y 21/10/2026); los tests, de `npm test` (Vitest, 60 archivos, todos en verde); las migraciones, de `supabase/migrations`.
[ 01 ] Reto
Las guías docentes mezclan pesos por categoría, notas mínimas, recuperaciones y «se descarta la peor», y una hoja de cálculo no contesta a lo único que importa a mitad de curso: cuánto necesito sacar para aprobar. Quería una herramienta propia, multiusuario y que funcionara en el móvil, donde cada alumno solo vea sus datos y el cálculo fuera lo bastante fiable como para fiarse de él.
[ 02 ] Solución
Un motor de cálculo en TypeScript puro, con aritmética decimal, que resuelve ponderaciones, reglas, nota necesaria, simulador y medias por ECTS. Encima, una app Next.js con Supabase: acceso con Google, RLS en todas las tablas, adjuntos en un bucket privado y avisos por push y correo desde un cron en la base de datos. Añade un horario por periodo con asistente de IA que enseña una vista previa antes de guardar, sincronización opcional con Google Calendar, enlaces de solo lectura revocables y una PWA instalable que se puede consultar sin conexión.
[ 03 ] Resultado
Una app en producción en notas.broslunas.com, con 758 tests (incluidas pruebas de propiedades del motor), 19 archivos SQL que comprueban el RLS y 37 migraciones, construida en dos días según el historial de git.
[ Decisiones técnicas ]
01El motor de cálculo es una librería pura con aritmética decimal
- Alternativa descartada
Calcular en los componentes o en la base de datos con números de coma flotante.
- Por qué
src/lib/gradingno depende de la interfaz ni de la base de datos y usadecimal.js, así que los redondeos no arrastran errores de coma flotante. Se prueba con ejemplos y con pruebas de propiedades (fast-check), y la interfaz solo pinta lo que devuelve, incluida la traza de «¿cómo se calcula?».
02RLS en todas las tablas, comprobado con SQL
- Alternativa descartada
Filtrar por usuario en el servidor y confiar en que ninguna consulta se olvide.
- Por qué
Cada tabla filtra por
user_id = auth.uid()en la propia base de datos. Hay 19 archivos SQL ensupabase/testsque se ejecutan connpm run test:rlscontra la base enlazada, de modo que un fallo de aislamiento se detecta antes de llegar a producción.
03Documentar y preguntar antes de programar
- Alternativa descartada
Empezar por la interfaz e ir descubriendo los requisitos sobre la marcha.
- Por qué
docs/recoge requisitos, modelo de dominio, arquitectura y fases con criterios de aceptación, y cada módulo grande (rendimiento, calendario, horario) tuvo su cuestionario de decisiones. Cambiar de opinión costó editar un documento, no rehacer código.
04La IA propone, el usuario confirma
- Alternativa descartada
Dejar que el asistente escriba el horario directamente en la base de datos.
- Por qué
El asistente genera el horario y también lo edita en lenguaje natural, pero siempre pasa por una vista previa editable; si hay varias clases candidatas, pregunta. Solo se guarda lo que el usuario acepta, así un error del modelo nunca llega a los datos.
05Sin conexión solo se lee
- Alternativa descartada
Edición sin conexión con sincronización y resolución de conflictos.
- Por qué
La PWA guarda en caché lo ya cargado para consultar las notas sin red, pero editar exige conexión. Con varios dispositivos por usuario, evitar los conflictos de fusión pesaba más que poder apuntar una nota en el metro.