Multi-Tenant Reporting Platform with Row-Level Security
Jurisdiction-precise reports for 180+ tenants in DACH, with guaranteed data isolation at the DB level.
Starting Point
Obsidian delivered regulatory reports to 180+ financial institutions in DACH. The existing platform was single-tenant replicated — every new customer = separate DB instance, separate deployment pipeline, 3 weeks onboarding time. Not scalable.
Our Approach
Multi-tenancy on a single shared Postgres (TimescaleDB extension for time series), with Row-Level Security policies as hard isolation. Every query runs in the context of a tenant ID set via connection settings — data leaks are physically impossible, not just through application logic.
Architecture
- TimescaleDB hypertables for report payloads (jurisdiction + period as composite keys)
- RLS policies per table with
current_setting('app.tenant_id') - Jurisdiction validation via PostgreSQL EXCLUDE constraints (no overlapping periods)
- React dashboard with per-tenant themes (white-label ready)
- AWS ECS deployment, Aurora Postgres backend
Result
180+ tenants on a single DB. Onboarding from 3 weeks to 15 minutes. 12,000 reports/month, P95 latency under 200ms. Zero data-leak incidents in 9 months of production.
What We Learned
RLS is underrated. Many teams write their own tenant isolation in the application layer — fragile, error-prone. Postgres-native RLS moves isolation to where it belongs: into the engine that holds the data.