- Updated the document title to reflect the focus on IAM Service Architecture. - Expanded the overview section to provide a clearer description of the IAM Service's capabilities. - Enhanced the table of contents for better navigation. - Added detailed architecture diagrams illustrating the layered architecture and key components. - Included comprehensive sections on authentication flows, authorization models, caching strategies, and security architecture. - Improved overall structure and readability to facilitate understanding of the IAM Service's design and functionality. These changes aim to provide developers with a thorough understanding of the IAM Service architecture and its components.
34 KiB
IAM Service Data Model
Complete Database Schema & Entity Relationships
This document describes all database models, relationships, and data architecture patterns used in the IAM Service.
Table of Contents
- Overview
- Complete Entity Relationship Diagram
- Model Categories
- Core Authentication Models
- Authorization Models
- Social & OIDC Models
- Identity Management Models
- Access Management Models
- Governance Models
- Relationships & Constraints
- Data Lifecycle
- Indexing Strategy
Overview
The IAM Service uses PostgreSQL 14+ with Prisma ORM for type-safe database access. The data model consists of 30+ interconnected models organized into 6 logical domains.
Database Statistics
| Metric | Value |
|---|---|
| Total Models | 30+ |
| Total Relationships | 50+ |
| Enumerations | 11 |
| Unique Constraints | 20+ |
| Indexes | 60+ |
| Foreign Keys | 35+ |
Model Organization
graph TD
DataModel[IAM Data Model<br/>30+ Models]
DataModel --> CoreAuth[Core Authentication<br/>7 models]
DataModel --> Authorization[Authorization<br/>6 models]
DataModel --> SocialOIDC[Social & OIDC<br/>2 models]
DataModel --> Identity[Identity Management<br/>6 models]
DataModel --> Access[Access Management<br/>4 models]
DataModel --> Governance[Governance<br/>3 models]
CoreAuth --> User[User]
CoreAuth --> Session[Session]
CoreAuth --> RefreshToken[RefreshToken]
CoreAuth --> AuthEvent[AuthEvent]
CoreAuth --> SocialAccount[SocialAccount]
CoreAuth --> MFADevice[MFADevice]
CoreAuth --> Policy[Policy]
Authorization --> Role[Role]
Authorization --> Permission[Permission]
Authorization --> UserRole[UserRole]
Authorization --> RolePermission[RolePermission]
Authorization --> UserPermission[UserPermission]
Authorization --> GroupPermission[GroupPermission]
Identity --> Organization[Organization]
Identity --> Group[Group]
Identity --> GroupMember[GroupMember]
Identity --> UserProfile[UserProfile]
Identity --> IdentityVerification[IdentityVerification]
Access --> AccessRequest[AccessRequest]
Access --> AccessRequestApprover[AccessRequestApprover]
Access --> AccessReview[AccessReview]
Access --> AccessReviewItem[AccessReviewItem]
Governance --> ComplianceReport[ComplianceReport]
Governance --> PolicyTemplate[PolicyTemplate]
Governance --> RiskScore[RiskScore]
style DataModel fill:#e1f5fe
style CoreAuth fill:#fff3e0
style Authorization fill:#f3e5f5
style SocialOIDC fill:#e8f5e9
style Identity fill:#fce4ec
style Access fill:#ffccbc
style Governance fill:#c8e6c9
Complete Entity Relationship Diagram
This diagram shows all 30+ models and their relationships:
erDiagram
%% ============================================================================
%% Core Authentication Domain
%% ============================================================================
User ||--o{ UserRole : "has"
User ||--o{ UserPermission : "has direct"
User ||--o{ Session : "has"
User ||--o{ RefreshToken : "has"
User ||--o{ SocialAccount : "linked to"
User ||--o{ MFADevice : "has"
User ||--o{ AuthEvent : "generates"
Role ||--o{ UserRole : "assigned to users"
Role ||--o{ RolePermission : "has"
Permission ||--o{ RolePermission : "granted to roles"
Permission ||--o{ UserPermission : "granted to users"
Permission ||--o{ GroupPermission : "granted to groups"
%% ============================================================================
%% Identity Management Domain
%% ============================================================================
Organization ||--o{ User : "contains"
Organization ||--o{ Group : "contains"
Organization ||--o{ Policy : "has"
Organization ||--o{ Organization : "parent/child"
Group ||--o{ GroupMember : "has members"
Group ||--o{ GroupPermission : "has permissions"
User ||--o{ GroupMember : "member of"
User ||--|| UserProfile : "has profile"
User ||--o{ IdentityVerification : "has verifications"
%% ============================================================================
%% Access Management Domain
%% ============================================================================
User ||--o{ AccessRequest : "creates"
AccessRequest ||--o{ AccessRequestApprover : "has approvers"
AccessReview ||--o{ AccessReviewItem : "contains items"
%% ============================================================================
%% Governance Domain
%% ============================================================================
User ||--o{ RiskScore : "has risk scores"
%% ============================================================================
%% Model Details
%% ============================================================================
User {
string id PK "cuid primary key"
string email UK "unique email address"
string username UK "unique username"
string passwordHash "bcrypt hashed password"
boolean isActive "account active status"
boolean emailVerified "email verified flag"
boolean mfaEnabled "MFA enabled flag"
string mfaSecret "TOTP secret (encrypted)"
datetime lastLoginAt "last login timestamp"
int loginCount "total login count"
string organizationId FK "organization reference"
datetime createdAt "creation timestamp"
datetime updatedAt "last update timestamp"
}
Role {
string id PK "cuid primary key"
string name UK "unique role name"
string displayName "human-readable name"
string description "role description"
boolean isSystem "system role flag"
datetime createdAt "creation timestamp"
datetime updatedAt "last update timestamp"
}
Permission {
string id PK "cuid primary key"
string resource "resource type"
string action "action type"
string scope "access scope"
string description "permission description"
datetime createdAt "creation timestamp"
}
UserRole {
string id PK "cuid primary key"
string userId FK "user reference"
string roleId FK "role reference"
string grantedBy "granter user ID"
datetime expiresAt "expiration timestamp"
datetime createdAt "creation timestamp"
}
RolePermission {
string id PK "cuid primary key"
string roleId FK "role reference"
string permissionId FK "permission reference"
datetime createdAt "creation timestamp"
}
UserPermission {
string id PK "cuid primary key"
string userId FK "user reference"
string permissionId FK "permission reference"
boolean granted "grant or deny"
string grantedBy "granter user ID"
datetime expiresAt "expiration timestamp"
datetime createdAt "creation timestamp"
}
Session {
string id PK "cuid primary key"
string userId FK "user reference"
string deviceId "device identifier"
string deviceName "device name"
string ipAddress "IP address"
string userAgent "user agent string"
string fingerprint "device fingerprint"
boolean isActive "session active flag"
datetime expiresAt "expiration timestamp"
datetime createdAt "creation timestamp"
datetime lastActivityAt "last activity timestamp"
}
RefreshToken {
string id PK "cuid primary key"
string userId FK "user reference"
string token UK "token value"
string family "token family ID"
string deviceId "device identifier"
string ipAddress "IP address"
string userAgent "user agent string"
datetime expiresAt "expiration timestamp"
datetime revokedAt "revocation timestamp"
datetime createdAt "creation timestamp"
}
SocialAccount {
string id PK "cuid primary key"
string userId FK "user reference"
enum provider "OAuth provider"
string providerId "provider user ID"
string email "provider email"
string name "provider name"
string avatar "avatar URL"
text accessToken "OAuth access token"
text refreshToken "OAuth refresh token"
datetime expiresAt "token expiration"
datetime createdAt "creation timestamp"
datetime updatedAt "last update timestamp"
}
MFADevice {
string id PK "cuid primary key"
string userId FK "user reference"
enum type "MFA type (TOTP/WEBAUTHN)"
string name "device name"
string secret "TOTP secret"
string credentialId "WebAuthn credential ID"
text publicKey "WebAuthn public key"
int counter "WebAuthn counter"
boolean isActive "device active flag"
datetime lastUsedAt "last use timestamp"
datetime createdAt "creation timestamp"
}
AuthEvent {
string id PK "cuid primary key"
string userId FK "user reference"
string eventType "event type"
json eventData "event details"
string ipAddress "IP address"
string userAgent "user agent string"
boolean success "success flag"
text errorMessage "error message"
datetime timestamp "event timestamp"
}
Policy {
string id PK "cuid primary key"
string name UK "unique policy name"
string description "policy description"
string resource "target resource"
json condition "policy conditions"
string effect "ALLOW or DENY"
int priority "evaluation priority"
boolean isActive "policy active flag"
string organizationId FK "organization reference"
datetime createdAt "creation timestamp"
datetime updatedAt "last update timestamp"
}
Organization {
string id PK "cuid primary key"
string name "organization name"
string domain UK "organization domain"
string parentId FK "parent organization ID"
json settings "organization settings"
boolean isActive "active flag"
datetime createdAt "creation timestamp"
datetime updatedAt "last update timestamp"
}
Group {
string id PK "cuid primary key"
string name "group name"
string organizationId FK "organization reference"
string description "group description"
boolean isActive "active flag"
datetime createdAt "creation timestamp"
datetime updatedAt "last update timestamp"
}
GroupMember {
string id PK "cuid primary key"
string userId FK "user reference"
string groupId FK "group reference"
string role "member role"
datetime joinedAt "join timestamp"
datetime expiresAt "expiration timestamp"
}
GroupPermission {
string id PK "cuid primary key"
string groupId FK "group reference"
string permissionId FK "permission reference"
datetime createdAt "creation timestamp"
}
UserProfile {
string id PK "cuid primary key"
string userId UK "user reference"
string firstName "first name"
string lastName "last name"
string phone "phone number"
boolean phoneVerified "phone verified flag"
string avatarUrl "avatar URL"
json customFields "custom attributes"
json preferences "user preferences"
json metadata "additional metadata"
datetime createdAt "creation timestamp"
datetime updatedAt "last update timestamp"
}
IdentityVerification {
string id PK "cuid primary key"
string userId FK "user reference"
enum type "verification type"
enum status "verification status"
string method "verification method"
string token UK "verification token"
datetime verifiedAt "verification timestamp"
datetime expiresAt "expiration timestamp"
json metadata "verification details"
datetime createdAt "creation timestamp"
}
AccessRequest {
string id PK "cuid primary key"
string userId FK "user reference"
string resource "target resource"
string action "requested action"
string reason "request reason"
enum status "request status"
datetime requestedAt "request timestamp"
datetime reviewedAt "review timestamp"
string reviewedBy "reviewer user ID"
datetime expiresAt "expiration timestamp"
json metadata "request metadata"
}
AccessRequestApprover {
string id PK "cuid primary key"
string requestId FK "request reference"
string approverId "approver user ID"
enum status "approval status"
string comments "approval comments"
datetime reviewedAt "review timestamp"
}
AccessReview {
string id PK "cuid primary key"
string name "review name"
string description "review description"
enum type "review type"
enum status "review status"
datetime startDate "start date"
datetime endDate "end date"
string createdBy "creator user ID"
datetime createdAt "creation timestamp"
datetime completedAt "completion timestamp"
}
AccessReviewItem {
string id PK "cuid primary key"
string reviewId FK "review reference"
string userId "target user ID"
string resource "target resource"
json access "current access details"
enum status "review item status"
string reviewedBy "reviewer user ID"
datetime reviewedAt "review timestamp"
string comments "review comments"
}
ComplianceReport {
string id PK "cuid primary key"
enum type "compliance type"
string name "report name"
datetime periodStart "period start"
datetime periodEnd "period end"
enum status "report status"
json data "report data"
datetime generatedAt "generation timestamp"
string generatedBy "generator user ID"
datetime createdAt "creation timestamp"
datetime updatedAt "last update timestamp"
}
PolicyTemplate {
string id PK "cuid primary key"
string name "template name"
enum category "policy category"
string description "template description"
json content "template structure"
string version "template version"
boolean isActive "active flag"
datetime createdAt "creation timestamp"
datetime updatedAt "last update timestamp"
}
RiskScore {
string id PK "cuid primary key"
string userId FK "user reference"
int score "risk score (0-100)"
enum level "risk level"
json factors "risk factors"
datetime calculatedAt "calculation timestamp"
}
Model Categories
1. Core Authentication (7 models)
Purpose: Handle user authentication, sessions, and security events.
| Model | Purpose | Key Features |
|---|---|---|
| User | Core user entity | Email/username, password hash, MFA, active status |
| Session | Active user sessions | Device tracking, fingerprinting, expiration |
| RefreshToken | Long-lived tokens | Token rotation, family tracking, revocation |
| AuthEvent | Audit log events | Event sourcing, compliance, troubleshooting |
| SocialAccount | OAuth accounts | Google, Facebook, GitHub integration |
| MFADevice | MFA devices | TOTP, WebAuthn support |
| Policy | ABAC policies | JSON logic, conditions, priority |
2. Authorization (6 models)
Purpose: Manage roles, permissions, and access control.
| Model | Purpose | Key Features |
|---|---|---|
| Role | Named collections of permissions | ADMIN, MANAGER, USER, custom roles |
| Permission | Granular access rights | resource:action:scope format |
| UserRole | User-role assignments | Expiration, temporary grants |
| RolePermission | Role-permission mappings | Many-to-many relationship |
| UserPermission | Direct user permissions | Override roles, grant/deny |
| GroupPermission | Group permissions | Inherited by group members |
3. Social & OIDC (2 models)
Purpose: External authentication integration.
| Model | Purpose | Key Features |
|---|---|---|
| SocialAccount | OAuth provider accounts | Access tokens, refresh tokens, profile |
| MFADevice | Multi-factor auth devices | TOTP secrets, WebAuthn credentials |
4. Identity Management (6 models)
Purpose: User profiles, organizations, groups, verification.
| Model | Purpose | Key Features |
|---|---|---|
| Organization | Multi-tenant organizations | Hierarchy, settings, isolation |
| Group | User groups | Organization-scoped, permissions |
| GroupMember | Group membership | Roles, expiration |
| UserProfile | Extended user info | Name, phone, avatar, custom fields |
| IdentityVerification | Email/phone/document verification | OTP tokens, status tracking |
5. Access Management (4 models)
Purpose: Access requests, reviews, analytics.
| Model | Purpose | Key Features |
|---|---|---|
| AccessRequest | Access request workflows | Approval chains, expiration |
| AccessRequestApprover | Multi-person approval | Approval status, comments |
| AccessReview | Access certification campaigns | Periodic, adhoc, certification |
| AccessReviewItem | Individual review items | Approve, revoke, no change |
6. Governance (3 models)
Purpose: Compliance, policies, risk management.
| Model | Purpose | Key Features |
|---|---|---|
| ComplianceReport | GDPR, SOC2, ISO27001 reports | Period-based, generation |
| PolicyTemplate | Reusable policy templates | Versioning, categories |
| RiskScore | User risk scoring | Factors, levels, tracking |
Core Authentication Models
User Model
model User {
id String @id @default(cuid())
email String @unique
username String? @unique
passwordHash String? // Nullable for social-only users
isActive Boolean @default(true)
emailVerified Boolean @default(false)
mfaEnabled Boolean @default(false)
mfaSecret String?
lastLoginAt DateTime?
loginCount Int @default(0)
organizationId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Key Features:
- Primary identifier:
id(CUID for distributed generation) - Unique constraints:
email,username - Password hashing: bcrypt (cost factor 12)
- MFA support: TOTP secret stored
- Audit fields:
lastLoginAt,loginCount - Soft delete:
isActiveflag
Session Model
model Session {
id String @id @default(cuid())
userId String
deviceId String
deviceName String?
ipAddress String
userAgent String?
fingerprint String? // Device fingerprint
isActive Boolean @default(true)
expiresAt DateTime
createdAt DateTime @default(now())
lastActivityAt DateTime @default(now())
}
Key Features:
- Device tracking:
deviceId,deviceName,fingerprint - Security: IP address, user agent tracking
- Activity monitoring:
lastActivityAt - Expiration: Auto-expire based on
expiresAt
RefreshToken Model
model RefreshToken {
id String @id @default(cuid())
userId String
token String @unique
family String? // Token family for rotation
deviceId String?
ipAddress String?
userAgent String?
expiresAt DateTime
revokedAt DateTime?
createdAt DateTime @default(now())
}
Key Features:
- Token rotation:
familyfor tracking token generations - Security: Revocation support with
revokedAt - Device binding: Optional
deviceIdtracking - Long-lived: 7-day expiration
AuthEvent Model (Audit Log)
model AuthEvent {
id String @id @default(cuid())
userId String?
eventType String // LOGIN, LOGOUT, MFA_ENABLED, etc.
eventData Json
ipAddress String?
userAgent String?
success Boolean @default(true)
errorMessage String? @db.Text
timestamp DateTime @default(now())
}
Key Features:
- Event sourcing: All auth events logged
- Compliance: GDPR, SOC2 audit trail
- Troubleshooting: Success/failure tracking
- Flexible: JSON
eventDatafor any event type
Authorization Models
RBAC Relationship
graph LR
User[User<br/>alice@example.com] --> UserRole[UserRole<br/>Assignment]
UserRole --> Role[Role<br/>ADMIN]
Role --> RolePerm1[RolePermission]
Role --> RolePerm2[RolePermission]
RolePerm1 --> Perm1[Permission<br/>users:*:all]
RolePerm2 --> Perm2[Permission<br/>products:*:all]
User --> DirectPerm[UserPermission<br/>Direct Override]
DirectPerm --> Perm3[Permission<br/>analytics:read:all]
style User fill:#e1f5fe
style Role fill:#f3e5f5
style Perm1 fill:#fff3e0
style Perm2 fill:#fff3e0
style Perm3 fill:#ffccbc
Permission Model
Format: resource:action:scope
model Permission {
id String @id @default(cuid())
resource String // users, products, orders
action String // create, read, update, delete
scope String? // own, team, all
description String?
createdAt DateTime @default(now())
@@unique([resource, action, scope])
}
Examples:
users:read:all- Read all usersusers:update:own- Update own profileorders:delete:all- Delete any order (admin)
UserRole Model (with Expiration)
model UserRole {
id String @id @default(cuid())
userId String
roleId String
grantedBy String? // Who granted this role
expiresAt DateTime? // Temporary assignment
createdAt DateTime @default(now())
@@unique([userId, roleId])
}
Key Features:
- Temporary roles:
expiresAtfor time-limited access - Audit trail:
grantedBytracks who assigned role - Unique constraint: One assignment per user-role pair
Social & OIDC Models
SocialAccount Model
model SocialAccount {
id String @id @default(cuid())
userId String
provider Provider // GOOGLE, FACEBOOK, GITHUB
providerId String // ID from provider
email String?
name String?
avatar String?
accessToken String? @db.Text
refreshToken String? @db.Text
expiresAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([provider, providerId])
}
enum Provider {
GOOGLE
FACEBOOK
GITHUB
APPLE
MICROSOFT
}
Key Features:
- Multiple providers per user
- Token storage for API calls
- Profile information caching
- Unique per provider-providerId
Identity Management Models
Organization Hierarchy
graph TD
RootOrg[Organization<br/>Acme Corp]
RootOrg --> Div1[Organization<br/>Engineering]
RootOrg --> Div2[Organization<br/>Sales]
Div1 --> Team1[Organization<br/>Frontend Team]
Div1 --> Team2[Organization<br/>Backend Team]
Div2 --> Team3[Organization<br/>North America]
Div2 --> Team4[Organization<br/>Europe]
Team1 --> User1[User: Alice]
Team1 --> User2[User: Bob]
Team2 --> User3[User: Charlie]
style RootOrg fill:#e1f5fe
style Div1 fill:#fff3e0
style Div2 fill:#fff3e0
style Team1 fill:#e8f5e9
style Team2 fill:#e8f5e9
Organization Model
model Organization {
id String @id @default(cuid())
name String
domain String? @unique
parentId String? // Self-referencing hierarchy
settings Json?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Self-referencing relationship
parent Organization? @relation("OrganizationHierarchy", fields: [parentId], references: [id])
children Organization[] @relation("OrganizationHierarchy")
}
Key Features:
- Hierarchical structure (parent-child)
- Domain-based organization
- Custom settings (JSON)
- Multi-tenancy support
Group Model
model Group {
id String @id @default(cuid())
name String
organizationId String?
description String?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
members GroupMember[]
permissions GroupPermission[]
@@unique([organizationId, name])
}
Key Features:
- Organization-scoped groups
- Members and permissions
- Unique names within organization
UserProfile Model
model UserProfile {
id String @id @default(cuid())
userId String @unique
firstName String?
lastName String?
phone String?
phoneVerified Boolean @default(false)
avatarUrl String?
customFields Json? // Extended attributes
preferences Json? // User preferences
metadata Json? // Additional data
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Key Features:
- Extended user information
- Custom fields (JSON) for flexibility
- Phone verification support
- Avatar management
Access Management Models
Access Request Workflow
stateDiagram-v2
[*] --> PENDING: User creates request
PENDING --> APPROVED: All approvers approve
PENDING --> REJECTED: Any approver rejects
PENDING --> CANCELLED: User cancels
PENDING --> EXPIRED: Timeout
APPROVED --> [*]: Access granted
REJECTED --> [*]: Access denied
CANCELLED --> [*]: Request cancelled
EXPIRED --> [*]: Request expired
AccessRequest Model
model AccessRequest {
id String @id @default(cuid())
userId String
resource String
action String
reason String?
status RequestStatus @default(PENDING)
requestedAt DateTime @default(now())
reviewedAt DateTime?
reviewedBy String?
expiresAt DateTime?
metadata Json?
approvers AccessRequestApprover[]
}
enum RequestStatus {
PENDING
APPROVED
REJECTED
EXPIRED
CANCELLED
}
Key Features:
- Multi-person approval support
- Expiration for temporary access
- Metadata for custom workflows
- Audit trail (reviewedBy, reviewedAt)
Governance Models
ComplianceReport Model
model ComplianceReport {
id String @id @default(cuid())
type ComplianceType
name String
periodStart DateTime
periodEnd DateTime
status ReportStatus @default(DRAFT)
data Json?
generatedAt DateTime?
generatedBy String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum ComplianceType {
GDPR // General Data Protection Regulation
SOC2 // Service Organization Control 2
ISO27001 // Information Security Management
HIPAA // Health Insurance Portability and Accountability Act
CUSTOM // Custom compliance framework
}
enum ReportStatus {
DRAFT
GENERATED
PUBLISHED
ARCHIVED
}
Key Features:
- Multiple compliance frameworks
- Period-based reporting
- Status tracking
- Flexible data structure (JSON)
RiskScore Model
model RiskScore {
id String @id @default(cuid())
userId String
score Int // 0-100
level RiskLevel
factors Json // Risk factors
calculatedAt DateTime @default(now())
}
enum RiskLevel {
LOW
MEDIUM
HIGH
CRITICAL
}
Risk Factors (in JSON):
{
"failedLogins": 3,
"unusualLocation": true,
"newDevice": true,
"highPrivilegeAccess": false,
"inactivityDays": 45,
"openAccessRequests": 2
}
Relationships & Constraints
Primary Relationships
User (1) ───< UserRole (many) >─── Role (1)
User (1) ───< UserPermission (many) >─── Permission (1)
Role (1) ───< RolePermission (many) >─── Permission (1)
Group (1) ───< GroupPermission (many) >─── Permission (1)
Group (1) ───< GroupMember (many) >─── User (1)
Organization (1) ───< User (many)
Organization (1) ───< Group (many)
Organization (1) ───< Organization (many) [self-referencing]
User (1) ──── UserProfile (1) [one-to-one]
User (1) ───< Session (many)
User (1) ───< RefreshToken (many)
User (1) ───< SocialAccount (many)
User (1) ───< MFADevice (many)
User (1) ───< AccessRequest (many)
AccessRequest (1) ───< AccessRequestApprover (many)
AccessReview (1) ───< AccessReviewItem (many)
Unique Constraints
| Model | Unique Constraint | Purpose |
|---|---|---|
| User | One email per user | |
| User | username | One username per user |
| Role | name | One role name |
| Permission | [resource, action, scope] | One permission per resource-action-scope |
| UserRole | [userId, roleId] | One assignment per user-role |
| Organization | domain | One organization per domain |
| Group | [organizationId, name] | Unique names within organization |
| SocialAccount | [provider, providerId] | One account per provider-providerId |
Cascade Deletes
ON DELETE CASCADE:
- User deleted → Delete all UserRoles, Sessions, RefreshTokens, etc.
- Role deleted → Delete all RolePermissions
- Organization deleted → Set users' organizationId to null
- Group deleted → Delete all GroupMembers
ON DELETE SET NULL:
- Organization deleted → Users remain, organizationId set to null
- AuthEvent user deleted → Event remains, userId set to null (for audit)
Data Lifecycle
User Lifecycle
stateDiagram-v2
[*] --> Created: register()
Created --> Active: Email verified
Created --> Inactive: Never verified
Active --> Deactivated: Deactivate account
Active --> Locked: Too many failed logins
Active --> MFAEnabled: Enable MFA
Deactivated --> Active: Reactivate
Locked --> Active: Unlock after timeout
MFAEnabled --> Active: Disable MFA
Active --> Deleted: Delete account (soft)
Deactivated --> Deleted: Delete account
Deleted --> [*]: Hard delete after retention period
Session Lifecycle
- Created: User logs in → Session created
- Active: Session valid, user making requests
- Inactive: No activity for extended period
- Expired: Past
expiresAttimestamp - Revoked: User logs out or admin revokes
- Deleted: Cleanup job removes expired sessions
Permission Lifecycle
- Created: Admin creates new permission
- Assigned: Permission granted to roles/users/groups
- Cached: Permission cached in Redis (5min TTL)
- Checked: Permission verified on resource access
- Revoked: Permission removed from role/user/group
- Invalidated: Cache cleared on permission change
Indexing Strategy
Performance Indexes
| Model | Index Columns | Purpose |
|---|---|---|
| User | Fast login lookup | |
| User | username | Username lookup |
| User | organizationId | Tenant filtering |
| Session | userId | User's sessions |
| Session | deviceId | Device tracking |
| Session | expiresAt | Cleanup job |
| RefreshToken | userId | User's tokens |
| RefreshToken | token | Token lookup |
| RefreshToken | family | Token rotation |
| AuthEvent | [userId, timestamp] | User audit trail |
| AuthEvent | [eventType, timestamp] | Event type queries |
| UserRole | userId | User's roles |
| UserRole | roleId | Role members |
| UserRole | expiresAt | Expiration cleanup |
| Permission | resource | Resource permissions |
| AccessRequest | userId | User's requests |
| AccessRequest | status | Pending requests |
Composite Indexes
For efficient querying:
AuthEvent(userId, timestamp)- User audit logs ordered by timeUserRole(userId, expiresAt)- Active roles for userSession(userId, isActive, expiresAt)- Active sessions for user
Database Migrations
Migration Strategy
- Forward-only migrations: Never rollback, always migrate forward
- Non-destructive changes: Add columns as nullable, then backfill
- Zero-downtime: Multi-phase migrations for production
- Versioning: Prisma migration history in
_prisma_migrationstable
Example Migration Phases
Phase 1 - Add column:
ALTER TABLE users ADD COLUMN new_field VARCHAR(255);
Phase 2 - Backfill data:
UPDATE users SET new_field = 'default_value' WHERE new_field IS NULL;
Phase 3 - Make required:
ALTER TABLE users ALTER COLUMN new_field SET NOT NULL;
Data Retention
| Data Type | Retention Period | Cleanup Strategy |
|---|---|---|
| Active Users | Indefinite | Soft delete |
| Inactive Users | 2 years | Hard delete |
| Sessions | 30 days after expiry | Automatic cleanup |
| Refresh Tokens | 7 days after expiry | Automatic cleanup |
| AuthEvents | 7 years | Compliance requirement |
| Access Requests | 3 years | Compliance requirement |
| Compliance Reports | 7 years | Legal requirement |
| Risk Scores | 1 year | Rolling window |
Next Steps
- ARCHITECTURE.md - System architecture and flows
- CORE-CONCEPTS.md - IAM fundamentals
- SECURITY-MODEL.md - Security architecture
- API Reference - API endpoints
Reference Files
- Prisma Schema: prisma/schema.prisma
- Repositories: src/repositories/
- Migrations: prisma/migrations/
Last Updated: January 2026 Version: 1.0.0 Status: Production Ready