Example Decision
See what an architecture decision looks like in MANTRA — a standard format that AI can understand and enforce automatically.
This is a real example of an architecture decision in MANTRA. Every decision follows a 68-column format that enables AI assistants to understand, search, check compliance, and enforce your team's rules automatically.
4×4 Taxonomy
Use PostgreSQL with Row-Level Security (RLS) for multi-tenant data isolation across all backend services
The backend team experienced 2 cross-tenant data leakage incidents in Q4 2025 due to missing tenant_id filters at the application level. RLS moves enforcement to the database level so leakage is technically impossible even if a developer forgets to add a filter. This reduces developer cognitive load and permanently eliminates an entire class of bugs.
All tenant tables must use RLS. Filter at DB level, not application. Eliminates cross-tenant data leakage risk.
Decision Drivers
Why this decision was needed
- 2 cross-tenant data leakage incidents in Q4 2025
- Application-level tenant_id filters frequently missed by developers
- Security audit recommended defense-in-depth at database level
- New team members joining Q1 2026 — need automatic guardrails
Positive Consequences
- +Cross-tenant data leakage becomes technically impossible
- +Developers don't need to remember tenant_id filter on every query
- +Compliance audits easier — isolation provable at DB level
- +New developer onboarding safer — can't accidentally leak data
Negative Consequences
- −Query performance reduced ~2-5% due to RLS policy evaluation overhead
- −Migrating existing tables requires planned downtime
- −Query debugging becomes more complex due to hidden RLS filters
Alternatives Considered
Filter tenant_id in every query at application code level. Previously used, but proven prone to human error.
Each tenant gets their own database. Perfect isolation but operational cost too high for a startup.
Each tenant gets their own schema in one database. Better than separate DBs but still hard to maintain.
Affected Areas
Constraints
Rules that MUST be followed — violations are detected automatically
Every table with tenant data MUST have a tenant_id NOT NULL column
CREATE TABLE orders (id uuid, tenant_id uuid NOT NULL, ...);
CREATE TABLE orders (id uuid, ...); -- tenant_id missing
Every table with tenant_id MUST have an active RLS policy
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON orders USING (tenant_id = current_setting('app.tenant_id')::uuid);-- Table has tenant_id but no RLS policy enabled
Raw SQL queries are PROHIBITED without explicit tenant_id filter
SELECT * FROM orders WHERE tenant_id = $1 AND status = $2
SELECT * FROM orders WHERE status = 'active' -- no tenant_id filter
Cross-tenant JOINs are PROHIBITED in a single query
SELECT o.* FROM orders o WHERE o.tenant_id = $1
SELECT a.*, b.* FROM tenant_a.orders a JOIN tenant_b.orders b ON ...
Invariants
Conditions that MUST always hold true at runtime
- I1 No cross-tenant data leakage is possible through any database query
- I2 tenant_id column cannot be NULL on tables with RLS policies
- I3 RLS policies must be active in all environments (development, staging, production)
Anti-Patterns
Patterns that are explicitly FORBIDDEN
- X1 Disabling RLS to “speed up” queries in production
- X2 Using superuser connections that bypass RLS for API endpoints
- X3 Hardcoding tenant_id in application code instead of reading from session context
Enforcement Results
Automated check results against the codebase based on this decision's constraints.
tenant_id column present (NOT NULL), RLS policy active
Line 47: SELECT query without explicit tenant_id filter
All queries use parameterized tenant_id
Table analytics_events: RLS policy not enabled
2 PASS, 1 WARNING, 1 FAIL — 1 critical violation needs immediate fix.
Version History
Every change is recorded in append-only fashion — nothing can be silently deleted or modified.
Initial decision: use PostgreSQL RLS for multi-tenant isolation
Add constraint C-004: prohibit cross-tenant JOINs
Supersede v1.1.0: add NOT NULL invariant, anti-patterns, CI/CD enforcement, adoption status ENFORCING
Related Decisions
This decision is connected to other decisions in the dependency graph.
JWT authentication must include tenant_id claim
RLS policy reads tenant_id from session variable set by JWT claim
API rate limiting 1000 req/min per tenant
Rate limiting also uses tenant_id for quota isolation
Audit logging required for all data mutations
Audit logs must record tenant_id for traceability