../constitution/founding-constitution.md
Traducción. Autoritativo: ../../adr/adr-002-multi-tenancy-model.md.
⚠️ Reconstruido a partir del material que tenemos, no recuperado. Etiquetas: [derived] tiene
respaldo en el repositorio · [inferred] es deducido · [proposed] es un hueco que llené.
Contexto
Había tres formas disponibles: una base por tenant, un schema por tenant, o un schema compartido con aislamiento por fila. Las dos primeras aíslan perfecto y dejan de escalar a unos cientos de tenants — migraciones, pools de conexión y respaldos se multiplican. La tercera escala y pone toda la carga del aislamiento en hacer bien una sola cosa, siempre. [inferred]Decisión
Schema compartido contenant_id en toda tabla con alcance de tenant, aislado por row-level
security. [derived]
La RLS es el límite, no una segunda capa detrás de las verificaciones de aplicación. [derived] Un
bug de aplicación no debe poder cruzar un tenant, y eso solo es cierto si la base se niega.
El acceso a la base va solo por getDb(tenantCtx). [derived] No hay camino a una conexión sin
contexto de tenant.
Toda tabla con alcance de tenant lleva además cell_id, presente desde la primera migración y
sin uso. [derived] Es la costura del particionamiento regional: cuando haya que fijar un tenant a una
región, la columna ya está y ya viene poblada.
Toda restricción de unicidad sobre datos con tenant incluye tenant_id. [derived — agregado 2026-08-17]
Consecuencias
- Una migración, un pool, un respaldo, para cualquier cantidad de tenants.
- El particionamiento regional se vuelve un problema de enrutamiento y no una migración. − Cada tabla necesita RLS y cada política de RLS necesita un test de denegación. Una política olvidada es una brecha. − Los efectos de vecino ruidoso son reales y se manejan con rate limiting y cuotas, no con aislamiento.
Lo que no pude determinar
Sicell_id se pensó como identificador físico de región o como clave lógica de shard.
[inferred] — lo traté como región, que es como se lee el material de residencia de datos.