// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" } // ============================================ // User Management & Authentication // ============================================ model User { id String @id @default(cuid()) entraOid String? @unique @map("entra_oid") email String @unique displayName String? @map("display_name") department String? jobTitle String? @map("job_title") photoUrl String? @map("photo_url") office String? isActive Boolean @default(true) @map("is_active") lastLoginAt DateTime? @map("last_login_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") userRoles UserRole[] createdTasks Task[] @relation("TaskCreatedBy") completedTasks Task[] @relation("TaskCompletedBy") taskAssignments TaskAssignment[] taskNotes TaskNote[] @relation("TaskNoteAuthor") createdTemplates TaskTemplate[] syncLogs SyncLog[] auditLogs AuditLog[] notifications Notification[] notificationPrefs NotificationPreference[] createdPolicyGroups PolicyGroup[] advocateClients Client[] @relation("ClientAdvocate") clientMemberships ClientMember[] shapeImportRuns ShapeImportRun[] @@map("users") } model Role { id String @id @default(cuid()) name String @unique description String? permissions Json @default("{}") createdAt DateTime @default(now()) @map("created_at") userRoles UserRole[] entraGroupMappings EntraGroupRoleMapping[] @@map("roles") } model UserRole { id String @id @default(cuid()) userId String @map("user_id") roleId String @map("role_id") createdAt DateTime @default(now()) @map("created_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) @@unique([userId, roleId]) @@map("user_roles") } model EntraGroupRoleMapping { id String @id @default(cuid()) entraGroupId String @map("entra_group_id") roleId String @map("role_id") createdAt DateTime @default(now()) @map("created_at") role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) @@unique([entraGroupId, roleId]) @@map("entra_group_role_mappings") } // ============================================ // Client & Policy Management // ============================================ model Designation { id String @id @default(cuid()) name String @unique description String? color String rules String? displayOrder Int @map("display_order") isActive Boolean @default(true) @map("is_active") afwAnotId String? @unique @map("afw_anot_id") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") clientsDesignation1 Client[] @relation("ClientDesignation1") clientsDesignation2 Client[] @relation("ClientDesignation2") taskTemplates TaskTemplate[] @@map("designations") } model Client { id String @id @default(cuid()) amsCustomerId String @unique @map("ams_customer_id") name String addressLine1 String? @map("address_line1") addressLine2 String? @map("address_line2") city String? state String? zipCode String? @map("zip_code") phone String? email String? producerCode String? @map("producer_code") amsCreatedAt DateTime? @map("ams_created_at") amsModifiedAt DateTime? @map("ams_modified_at") designationId String? @map("designation_id") designation2Id String? @map("designation2_id") claimsAdvocateId String? @map("claims_advocate_id") parentClientId String? @map("parent_client_id") notes String? @db.Text customFields Json @default("{}") @map("custom_fields") renewalDate DateTime? @map("renewal_date") setupCompletedAt DateTime? @map("setup_completed_at") lastSyncedAt DateTime? @map("last_synced_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") designation Designation? @relation("ClientDesignation1", fields: [designationId], references: [id]) designation2 Designation? @relation("ClientDesignation2", fields: [designation2Id], references: [id]) claimsAdvocate User? @relation("ClientAdvocate", fields: [claimsAdvocateId], references: [id]) parentClient Client? @relation("ClientParent", fields: [parentClientId], references: [id]) subsidiaries Client[] @relation("ClientParent") policies Policy[] tasks Task[] policyGroups PolicyGroup[] members ClientMember[] contacts ClientContact[] @@index([name]) @@index([designationId]) @@index([designation2Id]) @@index([claimsAdvocateId]) @@index([parentClientId]) @@map("clients") } model ClientContact { id String @id @default(cuid()) clientId String @map("client_id") label String name String title String? phone String? mobilePhone String? @map("mobile_phone") email String? notes String? @db.Text source String @default("manual") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") client Client @relation(fields: [clientId], references: [id], onDelete: Cascade) @@unique([clientId, name, label, source], name: "client_contact_dedup") @@index([clientId]) @@map("client_contacts") } model ClientMember { id String @id @default(cuid()) clientId String @map("client_id") userId String @map("user_id") createdAt DateTime @default(now()) @map("created_at") client Client @relation(fields: [clientId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([clientId, userId]) @@index([clientId]) @@index([userId]) @@map("client_members") } model PolicyGroup { id String @id @default(cuid()) clientId String @map("client_id") name String renewalDate DateTime @map("renewal_date") notes String? @db.Text createdBy String? @map("created_by") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") client Client @relation(fields: [clientId], references: [id], onDelete: Cascade) creator User? @relation(fields: [createdBy], references: [id]) policies Policy[] tasks Task[] @@index([clientId]) @@index([renewalDate]) @@map("policy_groups") } model Policy { id String @id @default(cuid()) amsPolicyId String @unique @map("ams_policy_id") clientId String @map("client_id") policyGroupId String? @map("policy_group_id") policyNumber String? @map("policy_number") policyType String? @map("policy_type") effectiveDate DateTime? @map("effective_date") expirationDate DateTime @map("expiration_date") carrierName String? @map("carrier_name") writingCompanyName String? @map("writing_company_name") premiumAmount Decimal? @map("premium_amount") @db.Decimal(12, 2) status String? billMethod String? @map("bill_method") businessType String? @map("business_type") department String? executiveName String? @map("executive_name") csrName String? @map("csr_name") additionalRep1 String? @map("additional_rep1") additionalRep2 String? @map("additional_rep2") additionalExec1 String? @map("additional_exec1") additionalExec2 String? @map("additional_exec2") amsCreatedAt DateTime? @map("ams_created_at") amsModifiedAt DateTime? @map("ams_modified_at") lastSyncedAt DateTime? @map("last_synced_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") client Client @relation(fields: [clientId], references: [id], onDelete: Cascade) policyGroup PolicyGroup? @relation(fields: [policyGroupId], references: [id]) tasks Task[] @@index([clientId]) @@index([policyGroupId]) @@index([expirationDate]) @@index([department]) @@map("policies") } // ============================================ // Task Management // ============================================ enum TaskStatus { NOT_STARTED IN_PROGRESS COMPLETED BLOCKED NA CANCELLED } enum TaskPriority { LOW MEDIUM HIGH URGENT } enum TaskTiming { PRE_RENEWAL POST_RENEWAL } enum DepartmentType { PERSONAL_LINES COMMERCIAL_LINES CLAIMS BENEFITS OTHER } model TaskTemplate { id String @id @default(cuid()) name String description String? @db.Text department DepartmentType timing TaskTiming daysOffset Int @map("days_offset") defaultPriority TaskPriority @map("default_priority") taskGroup String? @map("task_group") isActive Boolean @default(true) @map("is_active") displayOrder Int? @map("display_order") designationId String? @map("designation_id") createdBy String? @map("created_by") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") designation Designation? @relation(fields: [designationId], references: [id]) creator User? @relation(fields: [createdBy], references: [id]) tasks Task[] @@index([designationId]) @@map("task_templates") } model Task { id String @id @default(cuid()) title String description String? @db.Text department DepartmentType timing TaskTiming daysOffset Int @map("days_offset") dueDate DateTime @map("due_date") status TaskStatus @default(NOT_STARTED) priority TaskPriority clientId String @map("client_id") policyId String? @map("policy_id") policyGroupId String? @map("policy_group_id") templateId String? @map("template_id") createdBy String? @map("created_by") completedAt DateTime? @map("completed_at") completedBy String? @map("completed_by") notes String? @db.Text isAdHoc Boolean @default(false) @map("is_ad_hoc") naReason String? @map("na_reason") @db.Text cancelledReason String? @map("cancelled_reason") @db.Text taskGroup String? @map("task_group") imageRightFiled Boolean? @map("image_right_filed") reminderDate DateTime? @map("reminder_date") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") client Client @relation(fields: [clientId], references: [id], onDelete: Cascade) policy Policy? @relation(fields: [policyId], references: [id]) policyGroup PolicyGroup? @relation(fields: [policyGroupId], references: [id]) template TaskTemplate? @relation(fields: [templateId], references: [id]) creator User? @relation("TaskCreatedBy", fields: [createdBy], references: [id]) completer User? @relation("TaskCompletedBy", fields: [completedBy], references: [id]) assignments TaskAssignment[] taskNotes TaskNote[] @@index([clientId]) @@index([policyId]) @@index([policyGroupId]) @@index([status]) @@index([dueDate]) @@index([department]) @@map("tasks") } model TaskAssignment { id String @id @default(cuid()) taskId String @map("task_id") userId String @map("user_id") assignedAt DateTime @default(now()) @map("assigned_at") task Task @relation(fields: [taskId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([taskId, userId]) @@map("task_assignments") } model TaskNote { id String @id @default(cuid()) taskId String @map("task_id") userId String @map("user_id") content String @db.Text createdAt DateTime @default(now()) @map("created_at") task Task @relation(fields: [taskId], references: [id], onDelete: Cascade) user User @relation("TaskNoteAuthor", fields: [userId], references: [id]) @@index([taskId]) @@map("task_notes") } // ============================================ // Sync & System Management // ============================================ model SyncLog { id String @id @default(cuid()) syncType String @map("sync_type") startedAt DateTime @default(now()) @map("started_at") completedAt DateTime? @map("completed_at") status String rowsProcessed Int @default(0) @map("rows_processed") rowsInserted Int @default(0) @map("rows_inserted") rowsUpdated Int @default(0) @map("rows_updated") errorMessage String? @map("error_message") @db.Text triggeredBy String? @map("triggered_by") user User? @relation(fields: [triggeredBy], references: [id]) @@index([syncType]) @@index([startedAt]) @@map("sync_logs") } model SyncConfig { id String @id @default(cuid()) key String @unique value String @db.Text updatedAt DateTime @updatedAt @map("updated_at") @@map("sync_config") } model AppSetting { key String @id value String @db.Text updatedAt DateTime @updatedAt @map("updated_at") @@map("app_settings") } model AuditLog { id String @id @default(cuid()) userId String? @map("user_id") action String entityType String @map("entity_type") entityId String? @map("entity_id") oldValues Json? @map("old_values") newValues Json? @map("new_values") ipAddress String? @map("ip_address") userAgent String? @map("user_agent") @db.Text createdAt DateTime @default(now()) @map("created_at") user User? @relation(fields: [userId], references: [id]) @@index([userId]) @@index([entityType]) @@index([createdAt]) @@map("audit_logs") } // ============================================ // Notifications // ============================================ model Notification { id String @id @default(cuid()) userId String @map("user_id") type String title String message String @db.Text relatedEntityType String? @map("related_entity_type") relatedEntityId String? @map("related_entity_id") isRead Boolean @default(false) @map("is_read") createdAt DateTime @default(now()) @map("created_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId, isRead]) @@index([createdAt]) @@map("notifications") } model ShapeImportRun { id String @id @default(cuid()) startedAt DateTime @default(now()) @map("started_at") completedAt DateTime? @map("completed_at") status String // pending | running | completed | failed dryRun Boolean @default(true) @map("dry_run") driveId String @map("drive_id") folderPath String @default("Claims/SHAPE Accounts") @map("folder_path") triggeredBy String? @map("triggered_by") stats Json? user User? @relation(fields: [triggeredBy], references: [id]) logLines ShapeImportLog[] @@index([startedAt]) @@map("shape_import_runs") } model ShapeImportLog { id String @id @default(cuid()) runId String @map("run_id") seq Int line String @db.Text createdAt DateTime @default(now()) @map("created_at") run ShapeImportRun @relation(fields: [runId], references: [id], onDelete: Cascade) @@index([runId, seq]) @@map("shape_import_logs") } model NotificationPreference { id String @id @default(cuid()) userId String @map("user_id") notificationType String @map("notification_type") inApp Boolean @default(true) @map("in_app") email Boolean @default(false) teams Boolean @default(false) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([userId, notificationType]) @@map("notification_preferences") }