5.8 KiB
CRM Database Schema — Enterprise RBAC + CRM
Architecture Overview
Enterprise-grade PostgreSQL schema implementing hierarchical Role-Based Access Control (RBAC) with a complete CRM system. Designed for production deployments with strict security requirements, audit compliance, and scalability to millions of records.
1. Hierarchical RBAC Model
Four roles arranged in a strict hierarchy by hierarchy_level (lower = higher privilege):
| Role | Level | Authority |
|---|---|---|
| SUPER_ADMIN | 1 | Unrestricted — create/delete users, assign roles, override all permissions |
| ADMIN | 2 | Operational — ban/suspend users, review reports, moderate activity. Cannot create accounts. |
| SALES_USER | 3 | CRM operations — leads, customers, opportunities, communications |
| DEVELOPER | 4 | Technical + CRM read access for post-sale project visibility |
Enforcement via PostgreSQL Triggers
enforce_create_user()(BEFORE INSERT ON users): Only SUPER_ADMIN (hierarchy_level = 1) can create new user accounts. Bootstrap case (created_by IS NULL) is allowed for initial setup.enforce_role_assignment()(BEFORE INSERT ON user_roles): Only SUPER_ADMIN can assign roles. Prevents privilege escalation by checking hierarchy levels.
Permission Model
Granular permissions stored in permissions table with (resource, action) pairs.
role_permissions maps roles to permissions. The has_permission(user_id, resource, action)
function provides application-layer authorization checks.
2. Ban & Suspension System
Two separate tables for enforcement flexibility:
banned_users: Permanent or time-limited bans. Supports reversal (by SUPER_ADMIN). Admins can create bans; SUPER_ADMIN can reverse or permanently delete banned users.suspended_users: Time-limited suspensions (always has expiry). Admins can create and lift suspensions.
Both tables are fully audited via dedicated trigger functions.
3. Session & Login Security
sessions: Stores hashed session tokens with expiry. Only one active session per token hash.login_attempts: Captures every login attempt (successful or failed) with IP address and user agent. Used for brute-force detection and audit.- Users have
failed_login_attemptsandlocked_untilfor account lockout policies.
4. Password Security
- All passwords hashed with bcrypt (cost factor 12)
password_change_requiredforces password change on first login (TRUE for all non-root test accounts)- Password hashes are opaque to the database — validation is application-layer only
5. UUID Primary Keys
- All tables use
UUID PRIMARY KEY DEFAULT uuid_generate_v4() - Fixed UUIDs used for seed data and system entities for referential transparency
- Prevents enumeration attacks and supports distributed ID generation
6. Audit Trail
Every mutation is logged to audit_logs via audit_trigger_function():
- Captures
(table_name, record_id, action, old_data, new_data, changed_by, ip_address) - Ban actions, suspension actions, and successful logins have dedicated audit triggers
- Indexed on
(table_name, record_id)for per-record lookup
Dedicated audit views:
v_active_bans— Currently active bans with user detailsv_active_suspensions— Currently active suspensionsv_user_permissions— Flattened permission report per user
7. Third Normal Form (3NF)
Customer model uses the discriminator pattern:
customers (parent — shared columns: status, owner, tags, score)
├── customer_type = 'individual' → individual_customers
└── customer_type = 'company' → company_customers
All lookup tables are normalized. Contact information, addresses, and notes are separate 1:N child tables.
8. Indexing Strategy
- Core indexes: FK columns, status/sort/date columns, unique constraints
- Partial indexes:
WHERE deleted_at IS NULLon soft-delete tables,WHERE is_active = TRUEon bans/suspensions,WHERE due_date < NOW()on overdue invoices - Full-text search: GIN indexes on customers, leads, products, communications, tasks
- Composite indexes: Common query patterns (e.g.,
opportunities(owner_id, stage_id))
9. Soft Delete
deleted_at TIMESTAMPTZon all business tables- Partial unique indexes ignore soft-deleted rows (e.g.,
WHERE deleted_at IS NULL) - Audit logs capture the full row snapshot before soft-delete
10. Test Accounts
| Username | Password | Role |
|---|---|---|
superadmin_demo |
SuperAdmin@2026 |
SUPER_ADMIN |
admin_demo |
AdminAccess@2026 |
ADMIN |
sales_demo |
SalesAccess@2026 |
SALES_USER |
dev_demo |
DevTesting@2026 |
DEVELOPER |
11. Migration Instructions
# Create database
psql -U postgres -c "CREATE DATABASE crm;"
# Run full migration
psql -U postgres -d crm -f database/migrations/run_all.sql
# Or step by step:
psql -U postgres -d crm -f database/migrations/001_schema.sql
psql -U postgres -d crm -f database/migrations/002_seed.sql
12. Security Rules Summary
| Rule | Enforcement |
|---|---|
| Only SUPER_ADMIN creates accounts | Trigger trg_enforce_create_user |
| Only SUPER_ADMIN assigns roles | Trigger trg_enforce_role_assignment |
| No privilege escalation | Level check in enforce_role_assignment() |
| bcrypt password hashing | Application-layer (cost=12) |
| Unique usernames/emails | Partial unique indexes |
| Force password change on first login | password_change_required column |
| Audit every login/logout | Trigger trg_audit_login on login_attempts |
| Audit every ban action | Trigger trg_audit_ban on banned_users |
| Audit every suspension action | Trigger trg_audit_suspension on suspended_users |