> ## Documentation Index
> Fetch the complete documentation index at: https://internal.softcrum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ADR-002 — Multi-tenancy: schema compartido, RLS, cell-ready

> Estado: Propuesto (RECONSTRUCCIÓN — requiere validación) · Fecha: 2026-08-17 (reconstruido) Refs: ../constitution/founding-constitution.md.

Estado: **Propuesto (RECONSTRUCCIÓN — requiere validación)** · Fecha: 2026-08-17 (reconstruido)
Refs: [`../constitution/founding-constitution.md`](/es/constitution/founding-constitution)

> Traducción. Autoritativo: [`../../adr/adr-002-multi-tenancy-model.md`](/adr/adr-002-multi-tenancy-model).
>
> ⚠️ 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 con `tenant_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

Si `cell_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.
