# 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_attempts` and `locked_until` for account lockout policies.

---

## 4. Password Security

- All passwords hashed with **bcrypt (cost factor 12)**
- `password_change_required` forces 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 details
- `v_active_suspensions` — Currently active suspensions
- `v_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 NULL` on soft-delete tables,
  `WHERE is_active = TRUE` on 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 TIMESTAMPTZ` on 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

```bash
# 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` |
