Database Design
Data storage approach and key decisions
Database Design
Databases
| Database | Purpose | Version |
|---|---|---|
| PostgreSQL | All HRMS data (employees, time-off, documents, etc.) | 17.x |
| MongoDB Atlas | AI vectors only (RAG embeddings, chat history) | Latest |
| Redis | Caching and job queues | 7.x |
Key Decisions
- Single PostgreSQL database for all tenants (row-level isolation via
tenantId) - No HRMS data in MongoDB - MongoDB is exclusively for AI service
- Prisma 5.x as ORM - Type-safe queries, automatic migrations
- Redis for caching - Permissions, dashboard stats, sessions
Multi-Tenancy
- Every table has
tenantIdcolumn (except Tenant itself) - Every query must filter by
tenantId - Complete data isolation between tenants
Row-Level Security (RLS)
In addition to application-level tenantId filtering, PostgreSQL RLS policies provide database-level isolation as a safety net:
-- Enable RLS on all tenant-scoped tables
ALTER TABLE employees ENABLE ROW LEVEL SECURITY;
ALTER TABLE departments ENABLE ROW LEVEL SECURITY;
ALTER TABLE time_off_requests ENABLE ROW LEVEL SECURITY;
-- ... repeat for all tables
-- Create policy for tenant isolation
CREATE POLICY tenant_isolation ON employees
FOR ALL
USING (tenant_id = current_setting('app.tenant_id')::uuid);
-- Set tenant context before queries (done by Prisma middleware)
SET app.tenant_id = 'uuid-of-current-tenant';Benefits:
- Prevents data leaks even if application code has bugs
- Defense in depth (application + database layer)
- Audit-friendly for compliance
Implementation:
- Prisma middleware sets
app.tenant_idfrom request context (viax-tenant-idheader) - RLS policies check
tenant_idcolumn againstapp.tenant_id - System admin queries bypass RLS with
SET ROLEor separate connection
See Database Schema for complete model definitions.
What Goes Where
PostgreSQL (HRMS)
- Tenants, users, roles, permissions
- Employees, departments
- Time-off requests and balances
- Documents metadata
- Team posts, goals, workflows
- Audit logs
MongoDB (AI Service Only)
- RAG document embeddings
- Chat sessions and history
- AI-generated summaries
Caching Strategy
| Cache | TTL | Invalidation |
|---|---|---|
| User permissions | 1 hour | On role change |
| Dashboard stats | 5 minutes | On data change |
Note: Sessions are stored in PostgreSQL via Auth.js PrismaAdapter (not Redis). See Phase 01 for auth implementation.
Don't cache: Real-time data, user-specific queries, sensitive data
Migration Rules
- Use Prisma Migrate for schema changes
- Test migrations on staging first
- Multi-step migrations for breaking changes
- Always have rollback plan
Schema details to be defined during implementation