Cómo está hecho
Proyecto personal de Alan Teixidó. En producción y de uso diario. Estas son las decisiones.
La uso yo, cada día
82
commits en 3 días de producción · contados el 1 sept
- En producción desde el 29 de agosto de 2026. Se construye y se usa a la vez, desde el móvil.
- Los datos de la cuenta del autor son reales, no de prueba: 1384 actividades importadas (2018 → hoy), 82 noches con hipnograma, y las salidas nuevas entrando solas por webhook.
- El heatmap de constancia decía 30 días y pintaba 7: faltaba el histórico de pasos. Se cazó usándola.
- Los deltas comparaban un lunes a medias contra una semana entera. Se cazó usándola.
- La cabecera de entrenos contaba 50 actividades habiendo más de mil. Se cazó usándola.
El entrenador: el servidor calcula, el modelo solo redacta
18
herramientas tipadas
- Cada cifra que cita existe en una tabla. Los agregados se precalculan en servidor.
- Tiene prohibida la aritmética propia y reformatear valores: los recibe ya en el formato de la app.
- Las estimaciones se marcan como estimaciones. Lo ambiguo se pregunta antes de guardar.
- Un árbol de decisión delimita su ámbito: valora entrenos con los datos delante; nada clínico.
- Su memoria guarda solo afirmaciones literales del usuario, con cita y fecha, editables y borrables en /memoria.
Los límites de la API, descubiertos midiendo
8.073
muestras de pulso en una noche
- Los rollups diarios de Google Health rechazan rangos largos, y el tope depende del tipo: ~90 días para pasos, ~14 para calorías totales. No está documentado; se probó.
- La serie de pulso va a una muestra cada 2,5 s en lo reciente y se adelgaza a minutos en el histórico.
- Hay campos que existen solo desde una fecha (los microdespertares, desde julio). Un dato ausente se guarda como null, nunca como cero.
- Cada límite queda anotado en el código con la fecha en que se verificó.
Arquitectura
24/24
tablas con RLS, contadas ahora
- Next.js 16 (App Router, server components) sobre Vercel. Las páginas públicas funcionan sin JavaScript.
- Supabase: Postgres 17 en eu-west-1 (Irlanda) con row-level security en todas las tablas, auditadas una a una.
- Gráficas SVG a medida, sin librerías de charting: hipnograma, curvas sincronizadas con crosshair, heatmaps, la franja de forma.
- Los upserts fusionan con lo existente: un reimport no puede pisar datos con nulos. Se aprendió del único incidente del proyecto, y quedó escrito.
Integraciones
1384
actividades desde 2018, contadas ahora
- Strava entra por webhook: verificación GET, deduplicación por evento, update = refetch, delete = borrado local.
- Backfills reanudables con control de cuota: el trabajo se trocea y cada tanda continúa donde quedó la anterior.
- Los streams de cada actividad se piden una vez y quedan cacheados para siempre.
- La meteo de cada salida (Open-Meteo, histórico desde 1940) se guarda junto a la actividad, nunca se pide en render.
Cuatro decisiones de producto
82
noches con hipnograma, contadas ahora
Describir sin diagnosticar
Comparaciones contra el propio histórico y los objetivos del usuario. Nunca tablas poblacionales, y la fórmula de cada número a la vista.
Dato ausente ≠ cero
Las series pintan huecos y cada media declara cuántos días tiene detrás.
La IA propone, el usuario confirma
Nada subjetivo se guarda solo. La propuesta queda registrada junto a si se aceptó o se corrigió, para auditarla.
Deltas solo entre tramos equivalentes
Nunca un lunes a medias contra una semana entera.
Estado: fase privada, con tres puertas
Cuentas por invitación. El registro abierto está deliberadamente cerrado hasta pasar:
- La verificación de Google para scopes de salud, con su evaluación de seguridad (CASA) anual.
- El paso de la IA a un tier de pago con límite por usuario.
- La revisión legal del tratamiento de datos de salud — categoría especial del RGPD.
Contexto de mercado
Google Health Premium cobra suscripción por puntuación de recuperación, análisis de sueño avanzado y un coach conversacional con Gemini sobre tus mismos datos. Fit hace ese trabajo gratis y con las fórmulas a la vista — con menos pulido, sin certificaciones clínicas y para un solo par de fuentes. Es contexto, no argumento de venta: quien compare, que compare con esto delante.
El código
El repositorio es privado: la app guarda datos de salud reales y sus migraciones y semillas van con ellos. Esta página y la demo son el sustituto público.
Cambios recientes
Los últimos commits, tal cual · lista generada el 1 sept. Si la fecha se queda vieja, es que el flujo de build se saltó un paso: preferible a mentir en silencio.
- 1 septDemo con el Entrenador a la vista (conversacion de ejemplo en columna lateral, VFC, puntuacion y semana) y …
- 1 septLogin vivo: lineas topograficas de la identidad derivando en bucle, marca flotando, tarjeta con tilt al raton
- 1 septMovimiento con el sistema propio: login con marca a trazo y entrada escalonada, revelado por scroll en la l…
- 1 septCinta de sueno con crosshair de hora: al pasar dedo o raton se lee la hora mirada, con linea vertical; movi…
- 1 septVFC: RMSSD=0 es relleno de la fuente (18 noches pre-jul), no dato - se descarta como ausente; base real 82,…
- 1 septVFC nocturna (mediana RMSSD por noche): siempre como desviacion sobre base propia con banda, cruce con carg…