Casi todas las reescrituras de SaaS que nos han llamado a rescatar se remontan a las tres mismas palabras que pronunció el equipo original ya en el primer mes: «eso lo añadiremos más tarde». La multitenencia, el control de acceso por roles, la facturación de verdad. Parecen cosas que se acoplan una vez que se tienen clientes. Son justo lo contrario: son la forma misma del edificio, y no se pueden cambiar los cimientos una vez levantados los muros sin demolerlo todo.
Hemos construido plataformas que hoy funcionan en más de 40 países sobre una única base de código. La razón que lo hizo posible es tan aburrida como unánime: la tenencia, el acceso y la facturación se decidieron desde el primer día, antes de la primera función. Así son estas decisiones, y esto es lo que cuesta posponerlas.
01Por qué los equipos lo esquivan (y por qué es una trampa)
La presión es real. Tiene un único cliente piloto, una demo la semana que viene y un backlog de funciones que de verdad parecen el producto. La multitenencia es invisible para ese primer cliente —no puede verla—, así que parece un adorno superfluo. El equipo construye, pues, una aplicación de inquilino único «de momento» y promete generalizarla más adelante.
La trampa es que «inquilino único de momento» filtra una suposición en cada capa: que existe exactamente una sola organización en el mundo. Esa suposición acaba en sus consultas, su autenticación, sus cachés, sus tareas en segundo plano, sus rutas de archivo. Retirarla más tarde no es una refactorización: es una reescritura, porque la suposición no está en un solo sitio, está en todas partes.
Añadir la tenencia desde el primer día le cuesta quizá dos semanas de arquitectura y disciplina. Añadirla en el segundo año —cuando ya tiene clientes reales, datos reales y expectativas reales de disponibilidad— es una reescritura de varios meses bajo carga, con una migración de datos que no se puede permitir fallar. El trabajo no desaparece si lo pospone. Se acumula.
02El inquilino es la primera columna
Nuestra regla es sencilla: cada fila que pertenece a un cliente lleva un tenant_id, y no existe ningún camino de código capaz de consultar sin él. No una convención que la gente recuerde, sino una restricción que la base de datos y el framework imponen, de modo que olvidarlo se vuelve imposible en lugar de simplemente desaconsejado.
La versión más limpia que utilizamos se apoya en la propia base de datos. Las políticas de seguridad a nivel de fila significan que la frontera entre inquilinos se impone una capa por debajo del código de aplicación, donde un bug del ORM o una cláusula WHERE olvidada no puede filtrar los datos de un cliente a otro. La aplicación establece el inquilino actual en la conexión; la base de datos se niega a devolver cualquier otra cosa.
-- la frontera vive por debajo de la app, no dentro de ella ALTER TABLE orders ENABLE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation ON orders USING (tenant_id = current_setting('app.tenant')::uuid); -- la app fija el inquilino por petición; una cláusula WHERE -- olvidada ahora devuelve cero filas en vez de los datos de otro SET app.tenant = 'a91f…'; SELECT * FROM orders; -- solo los pedidos de este inquilino, siempre
Esta única decisión retira de su lista de preocupaciones, y de forma permanente, toda una categoría de bugs catastróficos: la fuga de datos entre inquilinos. Son los dos días de trabajo con mayor apalancamiento de todo el proyecto.
El bug más costoso en SaaS es el que muestra a un cliente los datos de otro cliente. Diseñe su arquitectura para que no pueda ocurrir, no para que sea improbable.
— Sobre el aislamiento como restricción03El RBAC no es una página de ajustes
El segundo «más tarde» que se convierte en reescritura es el control de acceso. Los equipos lanzan con un mundo implícito de dos roles —admin y usuario— codificado a fuego en sentencias if repartidas por toda la base de código. Luego un cliente corporativo pide un rol «solo facturación», o un «auditor de solo lectura», y descubre lógica de permisos en doscientos sitios.
Modelamos los permisos como datos desde el principio: los roles, los permisos y las asignaciones entre ellos viven en tablas, y cada acción protegida le formula una pregunta a una única autoridad central: «¿puede este actor hacer esta cosa sobre este recurso, dentro de este inquilino?». Añadir un rol se convierte en una fila, no en una release. Eso es lo que permite que una plataforma diga que sí al organigrama del cliente corporativo sin tocar el código de aplicación.
- Los permisos son verbos sobre recursos —
invoice:read,invoice:void—, no niveles vagos como «manager». - Los roles son conjuntos de permisos que un inquilino puede componer, de modo que dos clientes pueden entender cosas distintas por «admin».
- Cada verificación pasa por una sola puerta. Una lógica de autorización en un solo sitio es auditable; las sentencias
ifdispersas son un pasivo.
04La facturación es un producto, no fontanería
La facturación es donde «lo añadiremos más tarde» más duele, porque cuando la añade ya tiene clientes con acuerdos cerrados con un apretón de manos, datos incoherentes sobre quién debe qué y ningún concepto limpio de suscripción. Acoplar la facturación a posteriori significa reconciliar dinero, y es el único sitio donde un bug no es solo molesto: es un reembolso, un litigio o un problema de conformidad.
Diseñamos el modelo de facturación al mismo tiempo que el modelo de inquilino: planes, suscripciones, uso, facturas y el ciclo de vida que los conecta. Aunque a los primeros clientes se les facture manualmente, el modelo de datos está ahí desde el primer día, de modo que activar más adelante planes de autoservicio es una función, no una migración de todo el historial de sus ingresos.
Una base de código, un modelo de despliegue, muchos inquilinos.
Ningún fork por cliente que mantener o dejar divergir.
Aislamiento impuesto a nivel de base de datos, no por convención.
05Cuarenta países, una sola base de código
Llegar a más de 40 países parece una historia de escalado. En realidad es una historia de configuración. La plataforma no tiene ramas de código específicas de cada país: tiene un modelo de inquilino lo bastante rico como para expresar como datos lo que difiere de una región a otra: moneda, reglas fiscales, idioma, formatos de fecha, menciones legales en una factura.
Cuando la frontera entre «código» y «configuración» se traza correctamente desde el primer día, un país nuevo es una tarea de incorporación, no un proyecto de ingeniería. Cuando se traza mal, cada nuevo mercado es un fork, y en menos de un año mantiene una docena de versiones sutilmente distintas de la misma aplicación y entrega cada corrección una docena de veces. El resultado «una sola base de código» se deriva de decisiones tomadas antes del primer cliente.
El beneficio de hacer esto desde el primer día no se ve el primer mes: se ve el tercer año, cuando entrega una función una sola vez y 40 países la reciben simultáneamente, mientras su competidor de inquilino único todavía la está fusionando en su séptimo fork de cliente.
06La checklist del primer día
Si va a poner en marcha una plataforma SaaS este trimestre, estas son las decisiones que debe tomar antes de escribir la menor función, no porque sean urgentes, sino porque son irreversibles:
- Ponga un
tenant_iden todo e impóngalo por debajo de la aplicación. Seguridad a nivel de fila o equivalente. Haga que una consulta entre inquilinos sea imposible, no improbable. - Modele los permisos como datos. Roles y asignaciones en tablas, una sola puerta de autorización central. Añadir un rol debería ser una fila.
- Construya pronto el modelo de datos de facturación. Planes, suscripciones, facturas, aunque al principio facture a mano. No acople el dinero a posteriori.
- Separe el código de la configuración. Todo lo que varíe según el cliente o la región es un dato. El país número 41 debería ser un formulario de incorporación.
- Escriba primero el camino de aprovisionamiento de inquilinos. Crear limpiamente un nuevo inquilino, con valores por defecto sensatos, es su operación más ejecutada. Automatícela desde el primer día.
Nada de esto es exótico. Son unas pocas semanas de disciplina al inicio a cambio de no tener que hacer nunca la reescritura. Los equipos que llegan a 40 países sobre una sola base de código no tuvieron suerte: simplemente se negaron a decir «más tarde» respecto a las tres cosas que no se pueden añadir más tarde.

