Tenant Isolation & RLS
How Optserv uses Row-Level Security to enforce company-scoped data access, no cross-tenant data leakage.
Optserv is a multi-tenant platform. Multiple companies share the same database infrastructure, but their data is completely isolated from each other through Row-Level Security (RLS).
What is RLS?
Row-Level Security is a PostgreSQL feature that enforces access rules at the database query level. Instead of relying on application code to filter data, the database itself enforces policies that determine which rows a given user can see or modify.
With RLS, a query like SELECT * FROM employees doesn't return all employees in the database, it automatically returns only the employees in the authenticated user's company.
How Optserv uses RLS
Every table in Optserv's database has RLS policies applied. These policies check:
- Company scope, is this row owned by the user's company?
- Role scope, does the user's role allow them to access this row?
Example: An employee querying the attendance table sees only rows where company_id = their_company AND employee_id = their_employee_id. A manager sees rows in their department. HR sees all rows in their company.
Crucially: these policies are evaluated by the database engine, not by application code. Even if a bug in application code accidentally removed a filter clause, the RLS policy would prevent cross-company data from returning.
Defense in depth
RLS is one layer of a defense-in-depth stack:
Request
└── UI gating (role-aware navigation)
└── Route check (server-side auth validation)
└── Edge Function / RPC (role and company check before writes)
└── RLS (database-level row filter — always on)
All four layers must pass for data to be accessed or modified. A failure at any layer blocks the request.
Cross-tenant isolation guarantee
No authenticated user can query data from another company. The company_id check in RLS policies is enforced on every query, including:
- Direct table queries
- Joins across tables
- Aggregations and reporting queries
- Write operations (INSERT, UPDATE, DELETE)
This guarantee holds even in the event of:
- Application code bugs (forgot to add a WHERE clause)
- Malformed API requests
- Unexpected query patterns
Students and RLS
Student accounts in the School / OptClass flow have their own RLS scope. Student queries return only that student's records: not other students' data, and certainly not any staff data. The student RLS policies are distinct from the staff RLS policies.