Lo que aprendí lanzando un SaaS multi-tenant casi en solitario
Las decisiones de arquitectura que volvería a tomar, las que desharía, y por qué la infraestructura "aburrida" fue la mejor decisión que tomé construyendo Forzive.
Construir un SaaS multi-tenant en solitario es una serie de apuestas contra tu propio tiempo futuro. Cada abstracción ingeniosa es una deuda que pagas después, solo, normalmente a las 11 de la noche. Tras llevar Forzive desde un repo vacío hasta gimnasios que operan todo su negocio sobre él, esto es lo que de verdad aguantó — y lo que haría distinto.
La infraestructura aburrida fue la mejor decisión que tomé
La tentación, en solitario, es buscar el stack más vistoso para que el trabajo se sienta moderno. Yo fui al revés: una base de datos Postgres, una app Next.js, un despliegue. Sin microservicios, sin colas de mensajes que no necesitaba, sin Kubernetes. Cuando algo se rompía, había exactamente un lugar donde mirar.
La multi-tenancy vive en la capa de datos, no en la arquitectura. Cada tenant es una porción con alcance por fila de la misma base de datos, y un único middleware resuelve el tenant a partir del subdominio. Eso es todo. La versión "interesante" con una base de datos por tenant me habría enterrado en migraciones y gestión de conexiones sin ningún beneficio temprano.
Aplica el aislamiento de tenants en la capa de datos, no por disciplina
El bug más aterrador en software multi-tenant es una consulta que olvida su WHERE tenantId = ?. No puedes confiar en recordarlo en cada llamada — en algún momento no lo harás. Acoté la tenancy en un solo lugar: un helper de consultas que se niega a ejecutarse sin un contexto de tenant. Si el aislamiento es estructural, una versión cansada de ti no puede filtrar datos entre gimnasios.
Acompáñalo con datos de prueba que contengan dos tenants desde el día uno. La mayoría de las fugas entre tenants se esconden hasta que existe un segundo tenant; si tu base de datos de desarrollo siempre tiene dos, el bug aparece mientras construyes, no después de que un cliente lo reporte.
Lo que desharía
- Ajustes prematuros. Hice configurables cosas que todos los tenants dejaron en su valor por defecto. Cada interruptor era UI, almacenamiento y una rama en la lógica — para nada. Lanza la opinión; añade el ajuste cuando un cliente lo pida dos veces.
- Jobs en segundo plano hechos a mano. Mi primera versión del cobro recurrente era un script cron con bloqueo casero. Funcionaba casi siempre, que es el peor resultado — fallaba rara vez y en silencio. Un runner de jobs de verdad desde el inicio me habría ahorrado un mes de misterio.
- Saltarme la observabilidad. Añadí logging estructurado tarde. Antes de eso, "¿está lento para todos o para un gimnasio?" era incontestable. Lo primero que instalaría la próxima vez son tiempos por tenant.
La meta-lección
En solitario, tu recurso más escaso no es el cómputo ni el dinero — es la versión de ti de dentro de seis meses que tiene que entender este código. Cada decisión es en realidad una decisión sobre el tiempo de esa persona. Aburrido, estructural, dos-tenants-en-los-datos aburrido — eso es lo que la mantiene cuerda.
Construye el sistema que aún puedas operar en tu peor día, no el que se ve mejor en una pizarra.