Multi-tenant architecture
6 isolation layers defense-in-depth · RLS PostgreSQL native + pgsodium per-tenant encryption · 8 attack scenarios mitigated · 6 testing regimens (pre-commit a anual) · 8 data boundaries documentados. Tenant isolation que se PUEDE testear · NO solo afirmar.
6 isolation layers · defense-in-depth
| Layer | Descripción | Enforcement | Testing |
|---|---|---|---|
| Row-Level Security (RLS) · Postgres native | Cada row tabla tiene `clinic_id` foreign key · RLS policies enforce `clinic_id = current_setting('app.clinic_id')` para ALL SELECT/INSERT/UPDATE/DELETE | Database-level · imposible bypass desde application · zero trust application layer | Pre-commit · automated cross-tenant query tests · zero leakage allowed |
| Per-tenant encryption keys · pgsodium | PII columns (patient_name · phone · medical_history · conversation_messages) encriptados con key derivada por tenant · pgsodium secret box per-tenant unique | Database stored encryption · application no acceso plaintext sin descrypt explicit | Cross-tenant decrypt attempts logged + rejected · audit trail mandatory |
| JWT claims · tenant context propagation | JWT auth incluye `clinic_id` claim · backend extrae + sets Postgres session variable `app.clinic_id` · RLS policies usan | Cada API call valida JWT signature + claims · NO trust path para bypass | JWT manipulation attempts (signature · expired · wrong claims) rejected automated tests |
| Application-level tenant guards | ORM/SQL wrappers en `/admin.ts` validan `clinic_id` antes de queries · defense-in-depth contra RLS misconfiguration | Middleware obligatorio TODAS endpoints autenticated · zero direct DB access app layer | Unit tests negative scenarios · attempt other tenant data · expected throws |
| Audit logs per-tenant | Cada acción logged con tenant context · query own tenant logs only · cross-tenant log query attempts rejected | Log queries enforce RLS también · tenant cannot see other tenants logs | Audit log isolation verified weekly automated test |
| Resource quotas per-tenant | Rate limits · storage quotas · compute usage tracked per-tenant · prevents noisy neighbor | Cloudflare Workers Durable Objects per-tenant counter · Upstash Redis tenant-scoped rate limits | Load tests one tenant heavy traffic · verify other tenants unaffected |
8 attack scenarios · mitigated
Testing regimen · 6 cadences
- Pre-commit · automated cross-tenant query tests · zero leakage acceptable · runs on every PR
- Daily · automated penetration test cross-tenant access attempts · alerts si any pass · 0 expected
- Weekly · manual review audit logs cross-tenant attempts · pattern analysis · escalate suspicious
- Monthly · simulated breach scenario · tenant A tries access tenant B via all known attack vectors · documented results
- Trimestral · external review (ChatGPT auditor) · architecture decisions revisited · ADR si changes pattern
- Anual · external pen test (planned post-tracción) · specific cross-tenant scope · vendor specialized SaaS multi-tenant security
Data boundaries · 8 resources
| Resource | Scope |
|---|---|
| patient_messages · conversation history | Per-clinic strict · NO cross-clinic visibility · RLS enforced · pgsodium per-tenant encrypted |
| patient_profiles · PII | Per-clinic strict · cross-clinic patient (same person 2 clinics) NOT linked · GDPR aligned |
| clinic_config · own settings | Per-clinic write · own clinic only · admin role required |
| appointments · calendar entries | Per-clinic strict · NO shared resources · Cal.com integration scoped per-clinic |
| billing · Stripe customer_id | Per-clinic 1:1 mapping · invoices scoped · payment methods isolated |
| audit_logs · activity | Per-clinic own logs only · super admin can query cross-tenant for support con audit trail |
| Cloudflare Workers env vars · secrets | Global app-level NOT per-tenant · scoped via app logic + tenant context · NEVER tenant-specific secrets |
| Aggregate analytics · benchmarks | Cross-clinic AGGREGATED stats only (anonimizados · k≥5) · NO individual clinic data visible others |
Decisión arquitectónica: shared DB con RLS vs dedicated DB per-tenant. Trade-off: shared simplifies operations · scales better · cost-effective pre-revenue. Dedicated tendría perfect isolation pero requires 1 DB por cliente · 10x operational complexity · justifiable solo Enterprise contracts con custom SLA.
Roadmap: dedicated DB tier disponible post-tracción para clientes Enterprise que lo soliciten contractualmente (HIPAA-strict · 3000+ clinics chains · ISO 27001 certified prospects). Hasta entonces: shared con RLS + per-tenant encryption · tested rigurosamente.
¿Tu security team necesita architecture deep-dive?
Para Enterprise procurement · architecture diagram detallado · RLS policies sample · pgsodium implementation review · cross-tenant attack test suite resultados disponibles bajo NDA Enterprise.