CAIRL Database Schema
Overview
CAIRL uses PostgreSQL as the primary database with Drizzle ORM for type-safe database operations. All sensitive data is encrypted at rest, and the schema is designed with privacy-first principles.
Core Tables
waitlist
Early adopters and launch waitlist.
{
id: uuid (PK)
email: varchar(255) UNIQUE NOT NULL
createdAt: timestamp NOT NULL
source: varchar(50) DEFAULT 'coming_soon'
metadata: jsonb
}
Purpose: Collect email addresses for launch notifications
Privacy: Email addresses are the only PII collected, used solely for launch communications
users
Primary user identity table.
{
id: uuid (PK)
email: varchar(255) UNIQUE NOT NULL
phoneNumber: varchar(20)
emailVerified: boolean DEFAULT false
phoneVerified: boolean DEFAULT false
// Profile
firstName: varchar(100)
lastName: varchar(100)
dateOfBirth: timestamp
// KYC Status
kycStatus: varchar(50) DEFAULT 'pending' // pending, verified, rejected
kycVerifiedAt: timestamp
// Security
passwordHash: text
twoFactorEnabled: boolean DEFAULT false
// Timestamps
createdAt: timestamp NOT NULL
updatedAt: timestamp NOT NULL
lastLoginAt: timestamp
}
Purpose: Core user identity and authentication
Privacy:
passwordHashuses bcrypt with appropriate costphoneNumberstored encrypted- Name fields optional (for verification only)
dateOfBirthused for age verification, stored encrypted
Indexes:
email(unique)createdAt(for analytics)
identity_documents
Encrypted storage references for identity documents.
{
id: uuid (PK)
userId: uuid FK -> users.id
// Document Details
documentType: varchar(50) NOT NULL // passport, drivers_license, national_id
documentNumber: varchar(100) // encrypted
issuingCountry: varchar(2) // ISO country code
expiryDate: timestamp
// Storage References (S3)
frontImageUrl: text // encrypted S3 path
backImageUrl: text // encrypted S3 path
selfieUrl: text // encrypted S3 path
// Verification
verificationStatus: varchar(50) DEFAULT 'pending'
verifiedAt: timestamp
verifiedBy: varchar(50) // system, manual, third_party
// Timestamps
createdAt: timestamp NOT NULL
updatedAt: timestamp NOT NULL
}
Purpose: Track identity document submissions and verification status
Privacy:
- Document images stored in S3 with encryption at rest (AES-256)
- S3 paths encrypted in database
documentNumberencrypted (only decrypted for verification)- Documents automatically deleted after verification (configurable retention)
Security:
- Access logged in audit_log
- Viewing requires MFA
- Download restricted to authorized personnel
Indexes:
userIdverificationStatus
verification_sessions
Track verification attempts and codes.
{
id: uuid (PK)
userId: uuid FK -> users.id
// Session Details
sessionType: varchar(50) NOT NULL // email, phone, document, biometric
status: varchar(50) DEFAULT 'pending' // pending, completed, failed, expired
// Verification Data
verificationCode: varchar(10) // hashed
codeExpiresAt: timestamp
attempts: integer DEFAULT 0
maxAttempts: integer DEFAULT 3
// Context
ipAddress: varchar(50) // for fraud detection
userAgent: text
metadata: jsonb
// Timestamps
createdAt: timestamp NOT NULL
completedAt: timestamp
expiresAt: timestamp
}
Purpose: Manage verification flows (email, phone, document)
Security:
verificationCodehashed before storage- Rate limiting by IP address
- Automatic expiration (5-15 minutes depending on type)
- Max attempts lockout
Indexes:
userIdstatuscreatedAt(for cleanup)
consent_records
Track user consent for data processing and sharing.
{
id: uuid (PK)
userId: uuid FK -> users.id
// Consent Details
consentType: varchar(100) NOT NULL
consentGiven: boolean NOT NULL
consentVersion: varchar(20) NOT NULL
// Context
ipAddress: varchar(50)
userAgent: text
// Timestamps
createdAt: timestamp NOT NULL
revokedAt: timestamp
}
Purpose: GDPR compliance and consent management
Consent Types:
data_processing: General data processingidentity_verification: ID document processingdata_sharing: Sharing verified identitymarketing: Marketing communicationsanalytics: Usage analytics
Privacy:
- Consent required before any data processing
- Granular consent types
- Easy revocation
- Audit trail of all consent changes
Indexes:
userId, consentTypecreatedAt
audit_log
Comprehensive audit trail of all sensitive operations.
{
id: uuid (PK)
userId: uuid FK -> users.id (nullable)
// Event Details
eventType: varchar(100) NOT NULL
eventCategory: varchar(50) NOT NULL
description: text
// Context
ipAddress: varchar(50)
userAgent: text
metadata: jsonb
// Timestamp
createdAt: timestamp NOT NULL
}
Purpose: Security auditing, compliance, debugging
Event Categories:
auth: Login, logout, password changesverification: Verification attempts and completionsdata_access: Views of sensitive datadata_modification: Updates to user dataconsent: Consent changesadmin: Administrative actions
Privacy:
- No PII in logs (reference IDs only)
- Logs retained for 90 days
- Access restricted to authorized personnel
Indexes:
userIdeventCategorycreatedAt(for time-range queries)
Data Relationships
users (1) -> (n) identity_documents
users (1) -> (n) verification_sessions
users (1) -> (n) consent_records
users (1) -> (n) audit_log
Data Lifecycle
User Registration
- Create user record with email
- Create consent record for data processing
- Send email verification (creates verification_session)
- Log in audit_log
Identity Verification
- User uploads document (stored in S3)
- Create identity_documents record
- Create verification_session for document review
- Admin/system reviews document
- Update verification status
- Log all steps in audit_log
Data Deletion (GDPR Right to Erasure)
- User requests deletion
- Soft delete user account (mark as deleted)
- Schedule hard delete after grace period (30 days)
- Delete S3 documents
- Anonymize audit logs (remove userId reference)
- Permanently delete all records
- Send confirmation email
Security Measures
Encryption
At Rest:
- Database: PostgreSQL encryption (AWS RDS)
- S3 Documents: AES-256 encryption
- Sensitive fields: Application-level encryption
In Transit:
- TLS 1.3 for all connections
- Certificate pinning for mobile apps
Access Control
Database:
- Least privilege principle
- Application uses limited permissions account
- Admin access requires MFA
- Read replicas for analytics (no PII)
Application:
- Row-level security for multi-tenancy (future)
- API authentication required
- Rate limiting on all endpoints
Backup & Recovery
Backups:
- Automated daily backups (encrypted)
- Point-in-time recovery (7 days)
- Offsite backup storage
- Quarterly recovery drills
Retention:
- Production backups: 30 days
- Compliance backups: 7 years (anonymized)
Performance
Indexing Strategy
- Primary keys: UUID v4
- Foreign keys: All indexed
- Query patterns: Indexes on common filters
- Composite indexes for complex queries
Query Optimization
- Use Drizzle ORM prepared statements
- Connection pooling (max 10 connections)
- Read replicas for heavy queries
- Caching for frequently accessed data
Monitoring
- Slow query log (> 500ms)
- Connection pool metrics
- Table size monitoring
- Index usage analysis
Migration Strategy
Schema Changes
- Write migration in Drizzle Kit
- Test on staging environment
- Review for backward compatibility
- Deploy during maintenance window
- Monitor for issues
- Rollback plan ready
Data Migrations
- Create backup before migration
- Test migration on backup data
- Run migration with progress tracking
- Verify data integrity
- Update application code if needed
Compliance
GDPR
- ✅ Data minimization
- ✅ Purpose limitation
- ✅ Storage limitation
- ✅ Right to access (export user data)
- ✅ Right to erasure (deletion process)
- ✅ Right to rectification (update endpoints)
- ✅ Data portability (JSON export)
- ✅ Consent management
SOC 2
- ✅ Access controls documented
- ✅ Audit logging comprehensive
- ✅ Encryption at rest and in transit
- ✅ Backup and recovery procedures
- ✅ Change management process
Last Updated: 2026-01-23
Version: 1.0
Status: Active
Schema Location: /src/db/schema.ts