Un fichero de base de datos por cliente.
El aislamiento entre clientes de iForja no es una condición en una consulta: es un fichero distinto en el disco. Cada tenant tiene su propia base de datos SQLite y su propia cadena de auditoría, y la sesión se abre contra una sola de ellas.
La consecuencia práctica es la que le importa a quien responde de los datos: para que un cliente vea los de otro no basta con un fallo en una consulta — habría que abrir a propósito el fichero equivocado. Y las operaciones que más duelen en un multi-tenant compartido (restaurar a un solo cliente, borrarlo del todo, entregarle sus datos) se resuelven con cp, rm y una copia.
El aislamiento vive en el sistema de ficheros, no en una condición de la consulta.
El fallo clásico del multi-tenant compartido es una consulta a la que se le olvida el filtro por tenant. Aquí ese fallo no tiene consecuencias: la sesión está abierta contra el fichero de un solo tenant, y en ese fichero no hay filas de nadie más que puedan aparecer.
La identidad del tenant se deriva del token firmado del usuario. Una cabecera manipulada por el cliente no cambia a qué fichero se abre la sesión, y las rutas están confinadas para que un identificador malformado no pueda salirse del directorio que le corresponde.
Dar de baja a un cliente es borrar un fichero. Restaurar a uno solo al estado de ayer es copiar un fichero, sin parar a los demás ni montar una restauración selectiva. Atender un derecho de supresión del RGPD deja de ser un proyecto y pasa a ser una operación de sistema de ficheros.
Esto es lo que vas a encontrar en tu equipo.
Un directorio por tenant y, dentro, su base de datos. Puedes listarlo
con ls ahora
mismo durante la prueba de 30 días: si vieras un solo fichero con los
datos de todos, esta página estaría mintiendo.
# Un fichero por tenant. No hay tablas compartidas entre ellos.
runtime/state/forja/
├── tenants/
│ ├── acme/
│ │ └── forja.db # datos y cadena de auditoría de «acme»
│ ├── contoso/
│ │ └── forja.db # datos y cadena de auditoría de «contoso»
│ └── ...
└── forja.db # tenant por defecto
# Copia de seguridad de UN tenant, sin tocar a los demás:
cp runtime/state/forja/tenants/acme/forja.db /backup/acme-$(date +%F).db
# Verificar la cadena de ESE tenant, con su propia sesión:
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:9000/api/audit/verify
# El identificador de tenant sale del token firmado, NUNCA de una cabecera
# que el cliente pueda cambiar. Pedir datos de otro tenant no devuelve
# menos filas: no llega siquiera a abrir su fichero. Tres escenarios donde separar de verdad los datos deja de ser opcional.
Una sola instalación sirve a varios clientes de tu cartera sin montar infraestructura separada por cuenta, y sin el riesgo del multi-tenant compartido: dar de baja a uno es borrar su fichero.
Banca retail, banca privada, corporate y mesa de tesorería trabajan con la misma instalación y datos separados. Una consulta mal escrita en una línea de negocio no puede alcanzar los datos de otra.
Grupos con presencia en varios países operan una sola plataforma con los datos de cada filial en su propio fichero. Entregar a una filial todos sus datos, o solo los suyos, es copiar un fichero.
La cadena de auditoría y el aislamiento se refuerzan.
La cadena de auditoría sella quién hizo qué; el aislamiento por fichero garantiza sobre qué cliente lo hizo, y hace que cada cadena se pueda verificar y exportar por separado. Es esa combinación la que permite responder a un supervisor sin arrastrar datos de terceros al expediente.