Files
pos-system/services/iam-service/docs/concepts/DATA-MODEL.md
Ho Ngoc Hai d8411abd24 Revise IAM Service Architecture documentation for clarity and comprehensiveness
- 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.
2026-01-02 00:30:26 +07:00

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

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: isActive flag

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: family for tracking token generations
  • Security: Revocation support with revokedAt
  • Device binding: Optional deviceId tracking
  • 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 eventData for 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 users
  • users:update:own - Update own profile
  • orders: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: expiresAt for time-limited access
  • Audit trail: grantedBy tracks 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 email 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

  1. Created: User logs in → Session created
  2. Active: Session valid, user making requests
  3. Inactive: No activity for extended period
  4. Expired: Past expiresAt timestamp
  5. Revoked: User logs out or admin revokes
  6. Deleted: Cleanup job removes expired sessions

Permission Lifecycle

  1. Created: Admin creates new permission
  2. Assigned: Permission granted to roles/users/groups
  3. Cached: Permission cached in Redis (5min TTL)
  4. Checked: Permission verified on resource access
  5. Revoked: Permission removed from role/user/group
  6. Invalidated: Cache cleared on permission change

Indexing Strategy

Performance Indexes

Model Index Columns Purpose
User email 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 time
  • UserRole(userId, expiresAt) - Active roles for user
  • Session(userId, isActive, expiresAt) - Active sessions for user

Database Migrations

Migration Strategy

  1. Forward-only migrations: Never rollback, always migrate forward
  2. Non-destructive changes: Add columns as nullable, then backfill
  3. Zero-downtime: Multi-phase migrations for production
  4. Versioning: Prisma migration history in _prisma_migrations table

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


Reference Files


Last Updated: January 2026 Version: 1.0.0 Status: Production Ready