Opciones de modelo de datos SaaS multitenant para un backend sin código
Las elecciones de modelo de datos SaaS multitenant influyen en seguridad, informes y rendimiento. Compara tenant_id, esquemas separados y bases de datos separadas con compensaciones claras.

El problema: mantener a los inquilinos separados sin ralentizar\n\nLa multi-tenancy significa que un producto de software atiende a muchos clientes (inquilinos), y cada inquilino debe ver solo sus propios datos. Lo difícil es hacerlo de forma consistente: no solo en una pantalla, sino en cada llamada API, panel de administración, exportación y trabajo en segundo plano.\n\nTu modelo de datos afecta las operaciones diarias más de lo que muchos equipos esperan. Moldea permisos, informes, velocidad de consultas a medida que creces, y cuánto riesgo tiene un “pequeño” bug. Olvidar un filtro puede filtrar datos. Aislar demasiado puede convertir los informes en una tarea engorrosa.\n\nHay tres maneras comunes de estructurar un modelo de datos SaaS multitenant:\n\n- Una base de datos donde cada tabla incluye un tenant_id\n- Esquemas separados por inquilino dentro de una base de datos\n- Bases de datos separadas por inquilino\n\nAunque construyas visualmente en un backend sin código, las mismas compensaciones aplican. Herramientas como AppMaster generan código backend real y estructuras de base de datos a partir de tu diseño, así que las decisiones de modelado temprano aparecen rápidamente en el comportamiento y rendimiento en producción.\n\nImagina una herramienta de helpdesk. Si cada fila de ticket tiene tenant_id, es fácil consultar “todos los tickets abiertos”, pero debes garantizar controles de inquilino en todos lados. Si cada inquilino tiene su propio esquema o base de datos, el aislamiento es más fuerte por defecto, pero el reporting entre inquilinos (como “tiempo medio de cierre entre clientes”) requiere más trabajo.\n\nEl objetivo es una separación en la que confíes sin añadir fricción a informes, soporte y crecimiento.\n\n## Forma rápida para elegir: 4 preguntas que lo clarifican\n\nNo empieces con teoría de bases de datos. Empieza por cómo se usará el producto y qué necesitarás operar cada semana.\n\n### Cuatro preguntas que suelen dejar la respuesta obvia\n\n1) ¿Qué tan sensibles son los datos y estás bajo reglas estrictas? Salud, finanzas y contratos estrictos suelen empujarte hacia un aislamiento más fuerte (esquema separado o base de datos separada). Puede reducir riesgo y facilitar auditorías.\n\n2) ¿Necesitas reporting entre inquilinos con frecuencia? Si periódicamente necesitas métricas “todos los clientes” (uso, ingresos, rendimiento), una única base de datos con tenant_id suele ser lo más simple. Las bases de datos separadas hacen esto más difícil porque hay que consultar muchos lugares y combinar resultados.\n\n3) ¿Qué tan distintos serán los inquilinos entre sí? Si necesitan campos personalizados, flujos distintos o integraciones únicas, los esquemas o bases de datos separados pueden reducir la probabilidad de que los cambios se filtren. Si la mayoría comparten la misma estructura, usar tenant_id es más limpio.\n\n4) ¿Qué puede operar tu equipo de forma realista? Más aislamiento normalmente implica más trabajo: más backups, más migraciones, más piezas en movimiento y más puntos donde puede esconderse un fallo.\n\nUn enfoque práctico es prototipar tus dos opciones principales y luego probar los puntos dolorosos reales: reglas de permisos, consultas de reporting y cómo se despliegan los cambios a medida que el modelo evoluciona.\n\n## Enfoque 1: una base de datos con tenant_id en cada fila\n\nEste es el arreglo más común: todos los clientes comparten las mismas tablas y cada registro propiedad de un inquilino lleva un tenant_id. Es operativamente simple porque ejecutas una sola base de datos y un solo conjunto de migraciones.\n\nLa regla es estricta: si una fila pertenece a un inquilino, debe incluir tenant_id, y cada consulta debe filtrar por él. Las tablas con alcance por inquilino suelen incluir usuarios, roles, proyectos, tickets, facturas, mensajes, metadatos de archivos y tablas de unión que conectan datos del inquilino.\n\nPara reducir fugas, trata tenant_id como no negociable:\n\n- Haz tenant_id obligatorio (NOT NULL) en las tablas de inquilinos\n- Añade índices que empiecen con tenant_id (por ejemplo, tenant_id, created_at)\n- Incluye tenant_id en las reglas de unicidad (como email único por inquilino)\n- Pasa tenant_id en cada API y flujo de negocio, no solo en formularios de UI\n- Haz cumplir esto en el backend, no solo en filtros del cliente\n\nEn PostgreSQL, las políticas de row-level security pueden añadir una red de seguridad fuerte, especialmente cuando las consultas se generan dinámicamente.\n\nLos datos de referencia suelen caer en dos categorías: tablas compartidas (como países) sin tenant_id, y catálogos con scope por inquilino (como etiquetas personalizadas o pipelines) que sí incluyen tenant_id.\n\nSi construyes con AppMaster, un hábito simple previene la mayoría de incidentes: asigna tenant_id desde el inquilino del usuario autenticado antes de cualquier create o read en tu lógica de Business Process, y mantén ese patrón consistente.\n\n## Impacto en permisos: qué cambia con cada enfoque\n\nLos permisos son donde la multi-tenancy triunfa o falla. El diseño de datos que elijas cambia cómo almacenas usuarios, cómo acotas consultas y cómo evitas momentos “ups” en pantallas administrativas.\n\nCon una única base de datos y tenant_id en cada fila, los equipos suelen usar una tabla de Users compartida y conectar cada usuario a un inquilino y a uno o varios roles. La regla grande sigue siendo la misma: cada lectura y escritura debe incluir el scope de inquilino, incluso para tablas “pequeñas” como settings, tags o logs.\n\nCon esquemas separados, a menudo mantienes una capa de identidad compartida (login, password, MFA) en un lugar, mientras que los datos del inquilino viven en un esquema por inquilino. Los permisos pasan a ser en parte un problema de enrutamiento: la app debe apuntar consultas al esquema correcto antes de que corra la lógica de negocio.\n\nCon bases de datos separadas, el aislamiento es más fuerte, pero la lógica de permisos se traslada a la infraestructura: elegir la conexión correcta, gestionar credenciales y manejar cuentas de personal “global”.\n\nEn los tres enfoques, algunos patrones reducen consistentemente el riesgo entre inquilinos:\n\n- Pon tenant_id en la sesión o en las claims del token de autenticación y trátalo como obligatorio.\n- Centraliza las comprobaciones de inquilino en un solo lugar (middleware o un Business Process compartido), no esparcidas por endpoints.\n- En herramientas de administración, muestra claramente el contexto de inquilino y exige un cambio explícito de inquilino.\n- Para acceso de soporte, usa impersonación con un log de auditoría.\n\nEn AppMaster, esto normalmente significa guardar el contexto del inquilino justo después de la autenticación y reutilizarlo en endpoints API y Business Processes para que cada consulta permanezca acotada. Un agente de soporte debería ver órdenes solo después de que la app haya establecido el contexto de inquilino, no porque la UI haya filtrado correctamente.\n\n## Informes y rendimiento con un modelo tenant_id\n\nCon el enfoque de una sola base de datos y tenant_id, el reporting suele ser directo. Los dashboards globales (MRR, registros, uso) pueden ejecutarse con una sola consulta para todos, y los informes por inquilino son la misma consulta con un filtro.\n\nLa compensación es el rendimiento a lo largo del tiempo. A medida que las tablas crecen, un inquilino muy activo puede convertirse en un “vecino ruidoso” generando muchas filas, más escrituras y haciendo que consultas comunes vayan más lentas si la base tiene que escanear demasiado.\n\nEl indexado mantiene sano este modelo. La mayoría de lecturas con scope por inquilino deben poder usar un índice que empiece con tenant_id, de modo que la base de datos acceda directamente al segmento de datos de ese inquilino.\n\nUna buena base:\n\n- Añade índices compuestos donde tenant_id sea la primera columna (por ejemplo, tenant_id + created_at, tenant_id + status, tenant_id + user_id)\n- Mantén índices verdaderamente globales solo cuando necesites consultas entre inquilinos\n- Vigila joins y filtros que “olviden” tenant_id, lo que puede causar escaneos lentos\n\nLa retención y las eliminaciones también necesitan plan porque el historial de un inquilino puede hinchar tablas para todos. Si los inquilinos tienen políticas de retención distintas, considera borrados lógicos más archivado programado por inquilino, o mover filas antiguas a una tabla de archivo indexada por tenant_id.\n\n## Enfoque 2: esquemas separados por inquilino\n\nCon esquemas separados, aún usas una sola base de datos PostgreSQL, pero cada inquilino obtiene su propio esquema (por ejemplo, tenant_42). Las tablas dentro de ese esquema pertenecen solo a ese inquilino. Puede sentirse como dar a cada cliente una “mini base de datos” sin el overhead de ejecutar muchas bases de datos.\n\nUna configuración común mantiene servicios globales en un esquema compartido y los datos de inquilinos en esquemas por inquilino. La separación suele decidirse por lo que debe compartirse entre todos los clientes frente a lo que nunca debe mezclarse.\n\nDivisión típica:\n\n- Esquema compartido: tabla de tenants, planes, registros de facturación, feature flags, ajustes de auditoría\n- Esquema del inquilino: tablas de negocio como órdenes, tickets, inventario, proyectos, campos personalizados\n- Cualquiera de los dos (depende del producto): usuarios y roles, sobre todo si los usuarios pueden acceder a múltiples inquilinos\n\nEste modelo reduce el riesgo de joins entre inquilinos porque las tablas viven en distintos namespaces. También puede facilitar respaldar o restaurar un inquilino apuntando a un esquema.\n\nLas migraciones son lo que sorprende a los equipos. Cuando añades una tabla o columna nueva, debes aplicar el cambio a cada esquema de inquilino. Con 10 inquilinos es manejable. Con 1.000, necesitas un proceso: rastrear versiones de esquema, ejecutar migraciones por lotes y fallar de forma segura para que un inquilino roto no bloquee al resto.\n\nLos servicios compartidos como auth y facturación suelen vivir fuera de los esquemas de inquilinos. Un patrón práctico es auth compartida (una tabla de usuarios con una tabla de membresía por inquilino) y facturación compartida (IDs de cliente de Stripe, facturas), mientras que los esquemas de inquilinos almacenan datos de negocio propiedad del inquilino.\n\nSi usas AppMaster, planifica temprano cómo los modelos del Data Designer se mapean a esquemas compartidos vs de inquilino, y mantén los servicios globales estables para que los esquemas de inquilino puedan evolucionar sin romper login o pagos.\n\n## Informes y rendimiento con esquemas separados\n\nLos esquemas separados ofrecen separación más fuerte por defecto que un puro filtro tenant_id porque las tablas son físicamente distintas y los permisos pueden aplicarse por esquema.\n\nEl reporting es excelente cuando la mayoría de informes son por inquilino. Las consultas permanecen simples porque lees las tablas de un solo inquilino sin filtrar constantemente tablas compartidas. Este modelo también soporta inquilinos “especiales” que necesitan tablas extra o columnas personalizadas sin obligar a todos los demás a cargarlas.\n\nDonde los esquemas empiezan a complicar es en el reporting agregado entre todos los inquilinos. O necesitas una capa de reporting que pueda consultar muchos esquemas, o mantienes tablas de resumen compartidas en un esquema común.\n\nPatrones comunes:\n\n- Dashboards por inquilino que consultan solo el esquema de ese inquilino\n- Un esquema central de analytics con rollups nocturnos desde cada inquilino\n- Jobs de exportación que copian datos de inquilino a un formato apto para un data warehouse\n\nEl rendimiento suele ser sólido para cargas por inquilino. Los índices son más pequeños por inquilino y las escrituras intensas en un esquema son menos propensas a afectar a otros. La contrapartida es la sobrecarga operativa: provisionar un nuevo inquilino significa crear un esquema, ejecutar migraciones y mantener todos los esquemas alineados cuando cambia el modelo.\n\nLos esquemas son una buena opción cuando quieres aislamiento más estricto sin el coste de muchas bases de datos, o cuando esperas personalización por inquilino.\n\n## Enfoque 3: base de datos separada por inquilino\n\nCon una base de datos separada por inquilino, cada cliente obtiene su propia base de datos (o su propia base de datos en el mismo servidor). Esta es la opción más aislada: si los datos de un inquilino se corrompen, configuran mal o tienen una carga intensa, es mucho menos probable que afecte a otros.\n\nEncaja bien en entornos regulados (salud, finanzas, gobierno) o con clientes enterprise que esperan separación estricta, reglas de retención personalizadas o rendimiento dedicado.\n\nEl onboarding se convierte en un workflow de aprovisionamiento. Cuando un nuevo inquilino se registra, tu sistema necesita crear o clonar una base de datos, aplicar el esquema base (tablas, índices, constraints), crear y almacenar credenciales de forma segura y enrutar las solicitudes API a la base de datos correcta.\n\nSi construyes con AppMaster, la elección de diseño clave es dónde mantienes el directorio de inquilinos (un mapa central de inquilino a conexión de base de datos) y cómo aseguras que cada petición use la conexión correcta.\n\nLas actualizaciones y migraciones son la principal compensación. Un cambio de esquema ya no es “ejecutar una vez”, sino “ejecutar para cada inquilino”. Eso añade trabajo operativo y riesgo, por lo que los equipos suelen versionar esquemas y ejecutar migraciones como jobs controlados que rastrean progreso por inquilino.\n\nLa ventaja es el control. Puedes migrar primero inquilinos grandes, vigilar rendimiento y luego desplegar cambios gradualmente.\n\n## Informes y rendimiento con bases de datos separadas\n\nLas bases de datos separadas son las más sencillas de razonar. Las lecturas accidentales entre inquilinos son mucho menos probables, y un error de permisos tiende a afectar solo a un inquilino.\n\nEl rendimiento también es una fortaleza. Consultas pesadas, grandes importaciones o un informe desbocado en el Inquilino A no ralentizarán al Inquilino B. Esto protege contra vecinos ruidosos y permite ajustar recursos por inquilino.\n\nLa compensación aparece en el reporting. El análisis global entre todos los inquilinos es lo más difícil porque los datos están físicamente separados. Patrones que funcionan en la práctica incluyen copiar eventos clave o tablas a una base de reporting central, enviar eventos a un almacén tipo warehouse, ejecutar informes por inquilino y agregar resultados (cuando el número de inquilinos es pequeño) y mantener métricas de producto separadas de los datos de cliente.\n\nEl coste operativo es otro factor importante. Más bases de datos significan más backups, upgrades, monitorización y respuesta a incidentes. También podrías alcanzar límites de conexiones antes, porque cada inquilino puede necesitar su propio pool de conexiones.\n\n## Errores comunes que provocan fugas de datos o dolores posteriores\n\nLa mayoría de problemas multitenant no son fallos de gran diseño. Son omisiones pequeñas que crecen hasta convertirse en bugs de seguridad, reporting enmarañado y limpiezas costosas. La multi-tenancy funciona cuando la separación por inquilino es un hábito, no una característica que añades luego.\n\nUna fuga común es olvidar el campo de inquilino en una tabla, especialmente tablas de unión como user_roles, invoice_items o tags. Todo parece bien hasta que un informe o búsqueda hace join a través de esa tabla y extrae filas de otro inquilino.\n\nOtro problema frecuente son dashboards de administración que eluden el filtrado de inquilino. A menudo empieza como “solo para soporte” y luego se reutiliza. Las herramientas sin código no cambian el riesgo: cada consulta, business process y endpoint que lea datos de inquilinos necesita el mismo scope.\n\nLos IDs también pueden jugarte en contra. Si compartes IDs legibles por humanos entre inquilinos (como order_number = 1001) y asumes que son globalmente únicos, las herramientas de soporte e integraciones mezclarán registros. Mantén identificadores con scope por inquilino separados de las claves primarias internas e incluye contexto de inquilino en las búsquedas.\n\nFinalmente, los equipos subestiman migraciones y backups a medida que escalan. Lo que es fácil con 10 inquilinos puede ser lento y arriesgado con 1.000.\n\nVerificaciones rápidas que previenen la mayoría del dolor:\n\n- Haz explícita la propiedad por inquilino en cada tabla, incluidas las tablas de unión.\n- Usa un único patrón de scoping de inquilino y reutilízalo en todos lados.\n- Asegura que los informes y exportaciones no puedan ejecutarse sin scope de inquilino (salvo que sean verdaderamente globales).\n- Evita identificadores ambiguos por inquilino en APIs y herramientas de soporte.\n- Practica restauración y pasos de migración temprano, no después de crecer.\n\nEjemplo: un agente de soporte busca “invoice 1001” y extrae el inquilino equivocado porque la búsqueda omitió el scope. Es un bug pequeño con un gran impacto.\n\n## Lista de comprobación rápida antes de decidir\n\nAntes de fijar un modelo multitenant, ejecuta algunas pruebas. El objetivo es atrapar fugas de datos temprano y confirmar que la elección funciona cuando las tablas crecen.\n\n### Comprobaciones rápidas que puedes hacer en un día\n\n- Prueba de aislamiento: crea dos inquilinos (A y B), añade registros similares y verifica que cada lectura y actualización esté acotada al inquilino activo. No confíes solo en filtros de UI.\n- Prueba de ruptura de permisos: inicia sesión como un usuario del Inquilino A y trata de abrir, editar o borrar un registro del Inquilino B cambiando solo el ID del registro. Si algo tiene éxito, trátalo como un bloqueo de liberación.\n- Seguridad en la ruta de escritura: confirma que los nuevos registros siempre reciben el valor de inquilino correcto (o caen en el esquema/base de datos correcta), incluso cuando se crean vía jobs en segundo plano, importaciones o automatizaciones.\n- Ensayo de reporting: confirma que puedes hacer reporting solo por inquilino y “todos los inquilinos” (para personal interno), con reglas claras sobre quién puede ver la vista global.\n- Chequeo de rendimiento: añade una estrategia de índices ahora (especialmente para (tenant_id, created_at) y otros filtros comunes), y mide al menos una consulta lenta a propósito para saber cómo se ve lo “malo”.\n\nPara concretar la prueba de reporting, elige dos preguntas que sabes que necesitarás (una por inquilino y otra global) y ejecútalas contra datos de muestra.\n\nsql\n-- Tenant-only: last 30 days, one tenant\nSELECT count(*)\nFROM tickets\nWHERE tenant_id = :tenant_id\n AND created_at \u003e= now() - interval '30 days';\n\n-- Global (admin): compare tenants\nSELECT tenant_id, count(*)\nFROM tickets\nWHERE created_at \u003e= now() - interval '30 days'\nGROUP BY tenant_id;\n\n\nSi prototipas en AppMaster, integra estas comprobaciones en tus flujos de Business Process (read, write, delete) y genera dos inquilinos en el Data Designer. Cuando estas pruebas pasen con volumen realista de datos, puedes comprometerte con confianza.\n\n## Escenario ejemplo: desde los primeros clientes hasta escalar\n\nUna compañía de 20 personas lanza un portal de clientes: facturas, tickets y un dashboard simple. Esperan 10 inquilinos el primer mes, con un plan de crecer a 1.000 en el año siguiente.\n\nAl principio, el modelo más simple suele ser una base de datos donde cada tabla que almacene datos de clientes incluya tenant_id. Es rápido de construir, fácil de reportar y evita duplicar configuraciones.\n\nCon 10 inquilinos, el mayor riesgo no es el rendimiento. Es los permisos. Un filtro olvidado (por ejemplo, una consulta “listar facturas” que olvida tenant_id) puede filtrar datos. El equipo debe aplicar comprobaciones de inquilino en un lugar consistente (lógica de negocio compartida o patrones de API reutilizables) y tratar el scoping de inquilino como no negociable.\n\nAl pasar de 10 a 1.000 inquilinos, las necesidades cambian. El reporting se vuelve más pesado, el soporte pide “exporta todo para este inquilino” y algunos inquilinos grandes empiezan a dominar tráfico y ralentizar tablas compartidas.\n\nUn camino de mejora práctico suele ser:\n\n1) Mantener la misma lógica de aplicación y reglas de permisos, pero mover inquilinos de alto volumen a esquemas separados.\n2) Para los inquilinos más grandes (o clientes con cumplimiento estricto), moverlos a bases de datos separadas.\n3) Mantener una capa de reporting compartida que lea de todos los inquilinos y programar informes pesados fuera de horas pico.\n\nElige el modelo más sencillo que mantenga los datos seguros hoy, y planifica una migración para el problema de “unos pocos inquilinos enormes” en lugar de optimizar por eso el primer día.\n\n## Siguientes pasos: elige un modelo y protótipalo en un backend sin código\n\nElige según lo que necesites proteger primero: aislamiento de datos, simplicidad operativa o escalado por inquilino. La confianza viene de construir un pequeño prototipo y tratar de romperlo con casos reales de permisos y reporting.\n\nUna guía simple de inicio:\n\n- Si la mayoría de inquilinos son pequeños y necesitas reporting entre inquilinos sencillo, comienza con una base de datos y un tenant_id en cada fila.\n- Si necesitas separación más estricta pero quieres seguir gestionando una base de datos, considera esquemas separados por inquilino.\n- Si los inquilinos exigen aislamiento firme (cumplimiento, backups dedicados, riesgo de vecino ruidoso), contempla una base de datos separada por inquilino.\n\nAntes de construir, escribe los límites de inquilino en lenguaje claro. Define roles (owner, admin, agent, viewer), qué puede hacer cada uno y qué significa “global” (planes, plantillas, logs de auditoría). Decide cómo debe funcionar el reporting: ¿solo por inquilino o “todos los inquilinos” para personal interno?\n\nSi usas AppMaster, puedes prototipar estos patrones rápidamente: modela tablas en el Data Designer (incluyendo tenant_id, restricciones únicas y los índices de los que dependerán tus consultas), y luego aplica reglas en el Business Process Editor para que cada lectura y escritura permanezca acotada. Si necesitas un punto de referencia de la plataforma, AppMaster está disponible en appmaster.io.\n\nUna prueba práctica final: crea dos inquilinos (A y B), agrega usuarios y órdenes similares y ejecuta los mismos flujos para ambos. Intenta exportar un informe para el inquilino A y luego, a propósito, pasa IDs del inquilino B a los mismos endpoints. Tu prototipo solo será “suficientemente seguro” cuando esos intentos fallen siempre y tus informes clave sigan siendo rápidos con volúmenes realistas de datos.
FAQ
Predetermina a una única base de datos con un tenant_id en cada tabla perteneciente a inquilinos si quieres operaciones sencillas y análisis entre inquilinos frecuentes. Pasa a esquemas separados cuando necesites mayor aislamiento o personalización por inquilino sin gestionar muchas bases de datos. Elige bases de datos separadas cuando requisitos de cumplimiento o clientes enterprise exijan separación fuerte y control de rendimiento por inquilino.
Trata el scope de inquilino como obligatorio en el backend, no como un filtro de UI. Haz que tenant_id sea requerido en las tablas de inquilinos y siempre dérivalo del contexto del usuario autenticado en lugar de confiar en la entrada del cliente. Añade una red de seguridad como Row-Level Security de PostgreSQL si encaja en tu stack, y crea pruebas que intenten acceder a registros de otro inquilino cambiando solo un ID.
Coloca tenant_id como la primera columna en los índices que coincidan con tus filtros comunes, para que la base de datos pueda localizar rápidamente la porción de datos de un inquilino. Una base es indexar (tenant_id, created_at) para vistas temporales y añadir (tenant_id, status) o (tenant_id, user_id) para filtros de panel frecuentes. También haz que las restricciones de unicidad sean con alcance por inquilino, por ejemplo, “email único por inquilino”.
Los esquemas separados reducen las joins accidentales entre inquilinos porque las tablas viven en distintos espacios de nombres, y puedes gestionar permisos a nivel de esquema. La desventaja principal son las migraciones: cada esquema necesita el mismo cambio, y eso se complica cuando el número de inquilinos crece. Es un punto intermedio adecuado cuando quieres más aislamiento que tenant_id pero seguir administrando una sola base de datos.
Las bases de datos separadas minimizan el radio de impacto: un pico de rendimiento, una mala configuración o una corrupción probablemente se quedarán en un solo inquilino. El costo es la sobrecarga operativa: aprovisionamiento, backups, monitorización y migraciones se multiplican por número de inquilinos. También tendrás que gestionar un directorio de inquilinos confiable y enrutamiento para que cada llamada API use la conexión correcta.
Con tenant_id en una sola base de datos, el reporting global es más simple porque los dashboards son consultas sin el filtro de inquilino. Con esquemas o bases de datos separadas, lo habitual es copiar eventos clave o resúmenes a un almacén de reporting compartido de forma programada. Mantén la regla simple: métricas del producto ván al layer de reporting, los datos de clientes permanecen aislados.
Haz explícito el contexto de inquilino en las herramientas de soporte y exige un cambio de inquilino intencional antes de ver registros. Si usas impersonación, registra quién accedió a qué y cuándo, y limita el tiempo de acceso. Evita flujos de soporte que acepten solo un ID de registro sin contexto de inquilino, porque así surgen errores como “invoice 1001” que exponen datos de otro cliente.
Si los inquilinos necesitan campos o flujos distintos, los esquemas o bases de datos separadas reducen la probabilidad de que cambios de un cliente afecten a otros. Si la mayoría son similares, conserva un modelo compartido con tenant_id y maneja diferencias con opciones configurables (feature flags) o campos opcionales. Evita tablas “casi globales” que mezclen significados compartidos y específicos sin una propiedad clara.
Define el límite de inquilino desde el principio: decide dónde se guarda el contexto tras la autenticación y garantiza que cada lectura/escritura lo use. En AppMaster, esto implica normalmente establecer tenant_id desde el usuario autenticado en la lógica de Business Process antes de crear o consultar registros de inquilinos, de modo que los endpoints no lo olviden. Trata esto como un patrón reutilizable y no algo que se implemente por pantalla.
Crea dos inquilinos con datos similares e intenta romper el aislamiento cambiando solo IDs de registro durante lecturas, actualizaciones y borrados. Verifica que jobs en background, importaciones y exportaciones escriban en el scope correcto de inquilino, porque esos caminos suelen olvidarse. También ejecuta un informe por inquilino y uno global con volumen de muestra realista para confirmar rendimiento y reglas de acceso.


