01
el reto
IAgency, una academia colombiana de formación en IA, llevaba su promoción con tres herramientas prestadas: el curso vivía en Hotmart, la conversación con las alumnas en WhatsApp y la agenda de las sesiones individuales en un Excel. Cada una funcionaba por su cuenta; juntas, no se hablaban. Nadie podía decir, en un momento dado, por dónde iba una alumna: qué había visto del curso, qué había preguntado, cuándo tenía cita.
El encargo inicial cabía en una frase: una pantalla de acceso con un enlace al curso alojado en Hotmart. Creció a medida que cada herramienta prestada enseñaba su límite: un contenido que no se puede abrir tanda por tanda, una conversación de trabajo mezclada con los mensajes personales, una cita cobrada a mano.
Dos condiciones enmarcaban el resto, y no se movieron: las alumnas entran desde el móvil, y el alojamiento es un compartido de Hostinger, sin contenedor, sin build en el servidor, sin node_modules en el paquete.
02
la solución
Una aplicación web privada, diseñada y desarrollada desde cero, donde el contenido, la mensajería, la agenda con cobro y los avisos viven en el mismo sitio. La alumna ve ahí su curso, sus clases en vivo, las grabaciones de sus sesiones 1:1, sus objetivos y su certificado; el equipo gestiona todo eso desde el mismo portal, sin tocar nunca la base de datos.
La decisión estructural es un contrato: un único fichero OpenAPI describe las 116 operaciones de la API, y Orval genera de él dos paquetes que nadie edita a mano: los esquemas Zod con los que el servidor valida la entrada y da forma a la salida, y los hooks de TanStack Query que consume el frontend. La API y la pantalla ya no pueden desincronizarse en silencio: el typecheck cae antes que la usuaria.
La segunda regla, escrita en el código, es que el portal es de la clienta: ninguna integración puede tumbarlo. Google, el asistente, el correo, el push y el pago apagan su función, lo dicen por pantalla, y lo demás sigue. Vale para las siete.
03
el resultado
En producción, con alumnas reales. Hotmart, WhatsApp y el Excel de la agenda quedaron fuera: el contenido propio se abre tanda por tanda en fecha fija o «a los X días de empezar tu tanda», la mensajería lleva adjuntos detrás de la sesión, y una sesión con coach se reserva y se paga sin salir de la página.
A día de hoy: ~34.000 líneas de TypeScript, 37 tablas, 116 operaciones de API, 123 handlers de Express repartidos en 18 routers y 107 commits en cuatro meses.
Lo que me llevo está sobre todo en las averías. Un alojamiento que suspende el buzón por «actividad sospechosa», sin ningún intruso: era el propio portal, un anuncio saliendo como treinta envíos a la vez. Una verificación de marca de Google fallada dos veces porque el robot descargaba una SPA vacía detrás de un login. Un `drizzle-kit push --force` que propuso vaciar la tabla de alumnas. Cada una dejó una regla escrita en algún sitio: en el código, en el package.json, o en el documento de control que se lee antes de tocar nada.