// 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" url = env("DATABASE_URL") } // Core Entities model User { id String @id @default(uuid()) email String @unique passwordHash String firstName String? lastName String? phone String? role UserRole @default(CUSTOMER) isActive Boolean @default(true) emailVerified Boolean @default(false) lastLogin DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations customer Customer? employee Employee? sessions Session[] auditLogs AuditLog[] @@index([email]) @@index([role]) @@index([isActive]) @@index([createdAt]) } enum UserRole { CUSTOMER LOAN_OFFICER UNDERWRITER SERVICING ADMIN FINANCIAL_OPERATIONS COMPLIANCE } model Session { id String @id @default(uuid()) userId String token String @unique refreshToken String? @unique expiresAt DateTime ipAddress String? userAgent String? createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([token]) } model Customer { id String @id @default(uuid()) userId String? @unique customerType CustomerType firstName String? lastName String? businessName String? taxId String? @unique dateOfBirth DateTime? email String phone String? address Json? kycStatus KYCStatus @default(PENDING) kycCompletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations user User? @relation(fields: [userId], references: [id], onDelete: Cascade) accounts Account[] applications Application[] interactions Interaction[] creditProfiles CreditProfile[] @@index([email]) @@index([customerType]) @@index([kycStatus]) } enum CustomerType { INDIVIDUAL BUSINESS } enum KYCStatus { PENDING IN_PROGRESS VERIFIED REJECTED } model Account { id String @id @default(uuid()) customerId String accountNumber String @unique accountType AccountType status AccountStatus @default(ACTIVE) balance Decimal @default(0) @db.Decimal(15, 2) currency String @default("USD") openedAt DateTime @default(now()) closedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade) loans Loan[] transactions Transaction[] @@index([customerId]) @@index([accountNumber]) @@index([accountType]) @@index([status]) @@index([openedAt]) } enum AccountType { CHECKING SAVINGS LOAN ESCROW } enum AccountStatus { ACTIVE INACTIVE CLOSED FROZEN } model Loan { id String @id @default(uuid()) accountId String applicationId String? @unique loanNumber String @unique productType LoanProductType status LoanStatus @default(PENDING) principalAmount Decimal @db.Decimal(15, 2) interestRate Decimal @db.Decimal(5, 4) termMonths Int paymentFrequency PaymentFrequency @default(MONTHLY) originationDate DateTime? firstPaymentDate DateTime? maturityDate DateTime? currentBalance Decimal @default(0) @db.Decimal(15, 2) totalPaid Decimal @default(0) @db.Decimal(15, 2) nextPaymentDate DateTime? nextPaymentAmount Decimal? @db.Decimal(15, 2) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations account Account @relation(fields: [accountId], references: [id], onDelete: Cascade) application Application? @relation(fields: [applicationId], references: [id]) transactions Transaction[] paymentSchedule PaymentSchedule[] escrowAccounts EscrowAccount[] delinquencies Delinquency[] workouts Workout[] collateral Collateral[] riskScores RiskScore[] valuations Valuation[] tokens Token[] participations Participation[] @@index([accountId]) @@index([loanNumber]) @@index([status]) @@index([productType]) @@index([originationDate]) @@index([maturityDate]) @@index([nextPaymentDate]) } enum LoanProductType { CONSUMER_PERSONAL CONSUMER_SECURED CONSUMER_UNSECURED COMMERCIAL_WORKING_CAPITAL COMMERCIAL_BRIDGE COMMERCIAL_EQUIPMENT RECEIVABLES_FINANCING EQUIPMENT_FINANCING } enum LoanStatus { PENDING UNDERWRITING APPROVED FUNDED SERVICING DELINQUENT DEFAULTED PAID_OFF CHARGED_OFF CANCELLED } enum PaymentFrequency { WEEKLY BIWEEKLY MONTHLY QUARTERLY ANNUALLY } model Transaction { id String @id @default(uuid()) accountId String loanId String? transactionType TransactionType amount Decimal @db.Decimal(15, 2) balance Decimal @db.Decimal(15, 2) description String? referenceNumber String? status TransactionStatus @default(PENDING) postedAt DateTime? createdAt DateTime @default(now()) // Relations account Account @relation(fields: [accountId], references: [id], onDelete: Cascade) loan Loan? @relation(fields: [loanId], references: [id]) @@index([accountId]) @@index([loanId]) @@index([transactionType]) @@index([status]) @@index([createdAt]) @@index([postedAt]) @@index([referenceNumber]) @@index([accountId, createdAt]) } enum TransactionType { DEPOSIT WITHDRAWAL PAYMENT INTEREST FEE REFUND ADJUSTMENT TRANSFER } enum TransactionStatus { PENDING PROCESSING COMPLETED FAILED CANCELLED } model Application { id String @id @default(uuid()) customerId String applicationType LoanProductType requestedAmount Decimal @db.Decimal(15, 2) purpose String? status ApplicationStatus @default(DRAFT) submittedAt DateTime? decisionDate DateTime? decision ApplicationDecision? decisionReason String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade) loan Loan? workflows Workflow[] creditPulls CreditPull[] documents Document[] complianceTokens ComplianceToken[] @@index([customerId]) @@index([status]) @@index([applicationType]) @@index([submittedAt]) @@index([decisionDate]) @@index([status, submittedAt]) } enum ApplicationStatus { DRAFT SUBMITTED UNDER_REVIEW APPROVED DENIED WITHDRAWN EXPIRED } enum ApplicationDecision { APPROVED DENIED REFERRED COUNTEROFFER } model Workflow { id String @id @default(uuid()) applicationId String workflowType WorkflowType status WorkflowStatus @default(PENDING) currentStep Int @default(0) startedAt DateTime @default(now()) completedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations application Application @relation(fields: [applicationId], references: [id], onDelete: Cascade) tasks Task[] @@index([applicationId]) @@index([status]) } enum WorkflowType { ORIGINATION UNDERWRITING APPROVAL DOCUMENTATION FUNDING } enum WorkflowStatus { PENDING IN_PROGRESS COMPLETED CANCELLED FAILED } model Task { id String @id @default(uuid()) workflowId String title String description String? status TaskStatus @default(PENDING) assignedTo String? dueDate DateTime? completedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade) @@index([workflowId]) @@index([assignedTo]) @@index([status]) } enum TaskStatus { PENDING IN_PROGRESS COMPLETED CANCELLED } model Document { id String @id @default(uuid()) applicationId String? loanId String? documentType DocumentType fileName String filePath String fileSize Int mimeType String uploadedBy String status DocumentStatus @default(PENDING) verifiedAt DateTime? createdAt DateTime @default(now()) // Relations application Application? @relation(fields: [applicationId], references: [id], onDelete: Cascade) @@index([applicationId]) @@index([loanId]) @@index([documentType]) } enum DocumentType { IDENTIFICATION INCOME_VERIFICATION BANK_STATEMENT TAX_RETURN BUSINESS_LICENSE FINANCIAL_STATEMENT COLLATERAL_DOCUMENT LOAN_AGREEMENT DISCLOSURE OTHER } enum DocumentStatus { PENDING VERIFIED REJECTED EXPIRED } // Servicing Entities model EscrowAccount { id String @id @default(uuid()) loanId String escrowType EscrowType balance Decimal @default(0) @db.Decimal(15, 2) monthlyPayment Decimal @db.Decimal(15, 2) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations loan Loan @relation(fields: [loanId], references: [id], onDelete: Cascade) disbursements EscrowDisbursement[] @@index([loanId]) } enum EscrowType { TAXES INSURANCE PMI OTHER } model EscrowDisbursement { id String @id @default(uuid()) escrowAccountId String amount Decimal @db.Decimal(15, 2) payee String description String? disbursedAt DateTime @default(now()) status DisbursementStatus @default(PENDING) // Relations escrowAccount EscrowAccount @relation(fields: [escrowAccountId], references: [id], onDelete: Cascade) @@index([escrowAccountId]) } enum DisbursementStatus { PENDING PROCESSED FAILED } model Delinquency { id String @id @default(uuid()) loanId String daysPastDue Int status DelinquencyStatus firstDelinquentDate DateTime resolvedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations loan Loan @relation(fields: [loanId], references: [id], onDelete: Cascade) collections Collection[] @@index([loanId]) @@index([status]) } enum DelinquencyStatus { CURRENT DELINQUENT_30 DELINQUENT_60 DELINQUENT_90 DELINQUENT_120_PLUS RESOLVED } model Collection { id String @id @default(uuid()) delinquencyId String actionType CollectionActionType notes String? nextActionDate DateTime? createdAt DateTime @default(now()) // Relations delinquency Delinquency @relation(fields: [delinquencyId], references: [id], onDelete: Cascade) @@index([delinquencyId]) } enum CollectionActionType { CALL EMAIL LETTER PAYMENT_PLAN FORBEARANCE CHARGE_OFF } model Workout { id String @id @default(uuid()) loanId String workoutType WorkoutType status WorkoutStatus @default(PENDING) terms Json? effectiveDate DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations loan Loan @relation(fields: [loanId], references: [id], onDelete: Cascade) @@index([loanId]) @@index([status]) } enum WorkoutType { MODIFICATION FORBEARANCE SHORT_SALE DEED_IN_LIEU } enum WorkoutStatus { PENDING APPROVED ACTIVE COMPLETED REJECTED } model Collateral { id String @id @default(uuid()) loanId String collateralType CollateralType description String value Decimal @db.Decimal(15, 2) location String? lienPosition Int? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations loan Loan @relation(fields: [loanId], references: [id], onDelete: Cascade) tokens CollateralToken[] @@index([loanId]) } enum CollateralType { REAL_ESTATE VEHICLE EQUIPMENT INVENTORY RECEIVABLES OTHER } model PaymentSchedule { id String @id @default(uuid()) loanId String paymentNumber Int dueDate DateTime principal Decimal @db.Decimal(15, 2) interest Decimal @db.Decimal(15, 2) total Decimal @db.Decimal(15, 2) status PaymentStatus @default(PENDING) paidAt DateTime? createdAt DateTime @default(now()) // Relations loan Loan @relation(fields: [loanId], references: [id], onDelete: Cascade) @@index([loanId]) @@index([dueDate]) @@index([status]) } enum PaymentStatus { PENDING PAID PARTIAL MISSED SKIPPED } // Compliance Entities model RegulatoryReport { id String @id @default(uuid()) reportType ReportType reportingPeriod DateTime status ReportStatus @default(DRAFT) submittedAt DateTime? data Json createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([reportType]) @@index([reportingPeriod]) } enum ReportType { DFPI_ANNUAL HMDA MORTGAGE_CALL_REPORT STATE_SPECIFIC } enum ReportStatus { DRAFT SUBMITTED ACCEPTED REJECTED } model Disclosure { id String @id @default(uuid()) applicationId String? loanId String? disclosureType DisclosureType content Json deliveredAt DateTime? acknowledgedAt DateTime? createdAt DateTime @default(now()) @@index([applicationId]) @@index([loanId]) @@index([disclosureType]) } enum DisclosureType { LOAN_ESTIMATE CLOSING_DISCLOSURE TILA RESPA STATE_SPECIFIC } model ComplianceCheck { id String @id @default(uuid()) entityType String entityId String checkType String passed Boolean details Json? createdAt DateTime @default(now()) @@index([entityType, entityId]) } model AuditLog { id String @id @default(uuid()) userId String? action String entityType String? entityId String? changes Json? ipAddress String? userAgent String? createdAt DateTime @default(now()) // Relations user User? @relation(fields: [userId], references: [id], onDelete: SetNull) @@index([userId]) @@index([entityType, entityId]) @@index([createdAt]) } model AdverseAction { id String @id @default(uuid()) applicationId String reason String noticeSentAt DateTime? createdAt DateTime @default(now()) @@index([applicationId]) } // Risk Entities model RiskScore { id String @id @default(uuid()) loanId String scoreType ScoreType score Decimal @db.Decimal(5, 2) factors Json? calculatedAt DateTime @default(now()) // Relations loan Loan @relation(fields: [loanId], references: [id], onDelete: Cascade) @@index([loanId]) @@index([scoreType]) } enum ScoreType { CREDIT DEFAULT_RISK PREPAYMENT_RISK FRAUD } model CreditPull { id String @id @default(uuid()) applicationId String bureau CreditBureau creditScore Int? reportData Json? pulledAt DateTime @default(now()) // Relations application Application @relation(fields: [applicationId], references: [id], onDelete: Cascade) @@index([applicationId]) @@index([bureau]) } enum CreditBureau { EXPERIAN EQUIFAX TRANSUNION } model Valuation { id String @id @default(uuid()) loanId String valuationType ValuationType value Decimal @db.Decimal(15, 2) source String effectiveDate DateTime createdAt DateTime @default(now()) // Relations loan Loan @relation(fields: [loanId], references: [id], onDelete: Cascade) @@index([loanId]) } enum ValuationType { AVM APPRAISAL MANUAL } // Funds Entities model Fund { id String @id @default(uuid()) fundName String @unique fundType FundType balance Decimal @default(0) @db.Decimal(15, 2) status FundStatus @default(ACTIVE) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt participations Participation[] @@index([fundType]) } enum FundType { WAREHOUSE_LINE INVESTOR_FUND OPERATING } enum FundStatus { ACTIVE INACTIVE CLOSED } model Participation { id String @id @default(uuid()) loanId String fundId String? participationType ParticipationType percentage Decimal @db.Decimal(5, 4) amount Decimal @db.Decimal(15, 2) status ParticipationStatus @default(ACTIVE) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations loan Loan @relation(fields: [loanId], references: [id], onDelete: Cascade) fund Fund? @relation(fields: [fundId], references: [id]) tokens ParticipationToken[] @@index([loanId]) @@index([fundId]) } enum ParticipationType { SYNDICATION PARTICIPATION ASSIGNMENT } enum ParticipationStatus { PENDING ACTIVE SOLD TERMINATED } // Tokenization Entities model Token { id String @id @default(uuid()) loanId String? tokenType TokenType tokenAddress String? @unique tokenId String? blockchain String metadata Json? createdAt DateTime @default(now()) // Relations loan Loan? @relation(fields: [loanId], references: [id], onDelete: Cascade) transactions TokenTransaction[] holders TokenHolder[] @@index([loanId]) @@index([tokenAddress]) @@index([tokenType]) } enum TokenType { LOAN_RECORD PARTICIPATION COLLATERAL RECEIVABLE COMPLIANCE PAYMENT } model TokenTransaction { id String @id @default(uuid()) tokenId String txHash String @unique fromAddress String? toAddress String? amount Decimal? @db.Decimal(15, 2) status TransactionStatus @default(PENDING) blockNumber BigInt? confirmedAt DateTime? createdAt DateTime @default(now()) // Relations token Token @relation(fields: [tokenId], references: [id], onDelete: Cascade) @@index([tokenId]) @@index([txHash]) } model TokenHolder { id String @id @default(uuid()) tokenId String address String balance Decimal @db.Decimal(15, 2) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations token Token @relation(fields: [tokenId], references: [id], onDelete: Cascade) @@index([tokenId]) @@index([address]) } model SmartContract { id String @id @default(uuid()) contractName String contractAddress String @unique blockchain String abi Json version String deployedAt DateTime @default(now()) @@index([contractAddress]) } model CollateralToken { id String @id @default(uuid()) collateralId String tokenAddress String @unique blockchain String createdAt DateTime @default(now()) // Relations collateral Collateral @relation(fields: [collateralId], references: [id], onDelete: Cascade) @@index([collateralId]) @@index([tokenAddress]) } model ParticipationToken { id String @id @default(uuid()) participationId String tokenAddress String @unique blockchain String createdAt DateTime @default(now()) // Relations participation Participation @relation(fields: [participationId], references: [id], onDelete: Cascade) @@index([participationId]) @@index([tokenAddress]) } model ReceivableToken { id String @id @default(uuid()) receivableId String tokenAddress String @unique blockchain String createdAt DateTime @default(now()) @@index([receivableId]) @@index([tokenAddress]) } model ComplianceToken { id String @id @default(uuid()) applicationId String eventType String tokenAddress String @unique blockchain String data Json? createdAt DateTime @default(now()) // Relations application Application @relation(fields: [applicationId], references: [id], onDelete: Cascade) @@index([applicationId]) @@index([tokenAddress]) } // Additional entities model Employee { id String @id @default(uuid()) userId String @unique employeeId String @unique department String? title String? hireDate DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([employeeId]) } model Interaction { id String @id @default(uuid()) customerId String interactionType InteractionType subject String? notes String? createdBy String createdAt DateTime @default(now()) // Relations customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade) @@index([customerId]) @@index([createdAt]) } enum InteractionType { CALL EMAIL MEETING NOTE DOCUMENT } model CreditProfile { id String @id @default(uuid()) customerId String creditScore Int? creditBureau CreditBureau? reportData Json? lastUpdated DateTime @default(now()) createdAt DateTime @default(now()) // Relations customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade) @@index([customerId]) }