@valentine-efagene/qshelter-common 2.0.143 → 2.0.145

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/generated/client/browser.d.ts +20 -11
  2. package/dist/generated/client/client.d.ts +20 -11
  3. package/dist/generated/client/commonInputTypes.d.ts +324 -234
  4. package/dist/generated/client/enums.d.ts +38 -24
  5. package/dist/generated/client/enums.js +33 -21
  6. package/dist/generated/client/internal/class.d.ts +44 -22
  7. package/dist/generated/client/internal/class.js +2 -2
  8. package/dist/generated/client/internal/prismaNamespace.d.ts +438 -204
  9. package/dist/generated/client/internal/prismaNamespace.js +140 -52
  10. package/dist/generated/client/internal/prismaNamespaceBrowser.d.ts +147 -55
  11. package/dist/generated/client/internal/prismaNamespaceBrowser.js +140 -52
  12. package/dist/generated/client/models/Application.d.ts +669 -1
  13. package/dist/generated/client/models/ApplicationDocument.d.ts +577 -1
  14. package/dist/generated/client/models/ApplicationOrganization.d.ts +2385 -0
  15. package/dist/generated/client/models/ApplicationOrganization.js +1 -0
  16. package/dist/generated/client/models/BankDocumentRequirement.d.ts +1932 -0
  17. package/dist/generated/client/models/BankDocumentRequirement.js +1 -0
  18. package/dist/generated/client/models/DocumentExpiryWarning.d.ts +1141 -0
  19. package/dist/generated/client/models/DocumentExpiryWarning.js +1 -0
  20. package/dist/generated/client/models/EventHandler.d.ts +0 -158
  21. package/dist/generated/client/models/EventType.d.ts +0 -134
  22. package/dist/generated/client/models/Organization.d.ts +390 -0
  23. package/dist/generated/client/models/PropertyMedia.d.ts +0 -7
  24. package/dist/generated/client/models/PropertyPaymentMethod.d.ts +192 -3
  25. package/dist/generated/client/models/PropertyVariant.d.ts +0 -7
  26. package/dist/generated/client/models/ScheduledJob.d.ts +1317 -0
  27. package/dist/generated/client/models/ScheduledJob.js +1 -0
  28. package/dist/generated/client/models/StateTransitionDefinition.d.ts +1104 -0
  29. package/dist/generated/client/models/StateTransitionDefinition.js +1 -0
  30. package/dist/generated/client/models/StateTransitionLog.d.ts +1383 -0
  31. package/dist/generated/client/models/StateTransitionLog.js +1 -0
  32. package/dist/generated/client/models/Tenant.d.ts +1314 -1314
  33. package/dist/generated/client/models/index.d.ts +4 -2
  34. package/dist/generated/client/models/index.js +4 -2
  35. package/dist/generated/client/models.d.ts +4 -2
  36. package/dist/src/prisma/tenant.js +2 -0
  37. package/package.json +1 -1
  38. package/prisma/schema.prisma +333 -134
@@ -410,33 +410,6 @@ enum EventHandlerType {
410
410
  LOCK_UNIT // Lock the property unit for the applicant, supersede competing applications
411
411
  }
412
412
 
413
- /// Actor Type - Who triggered an event
414
- enum ActorType {
415
- USER
416
- API_KEY
417
- SYSTEM
418
- WEBHOOK
419
- }
420
-
421
- /// Workflow Event Status
422
- enum WorkflowEventStatus {
423
- PENDING
424
- PROCESSING
425
- COMPLETED
426
- FAILED
427
- SKIPPED
428
- }
429
-
430
- /// Handler Execution Status
431
- enum ExecutionStatus {
432
- PENDING
433
- RUNNING
434
- COMPLETED
435
- FAILED
436
- RETRYING
437
- SKIPPED
438
- }
439
-
440
413
  /// Permission effect (Allow/Deny)
441
414
  enum PermissionEffect {
442
415
  ALLOW
@@ -679,6 +652,12 @@ model Organization {
679
652
  tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
680
653
  members OrganizationMember[]
681
654
 
655
+ // Applications where this organization is involved
656
+ applicationAssignments ApplicationOrganization[]
657
+
658
+ // Bank-specific document requirements (for BANK type organizations)
659
+ documentRequirements BankDocumentRequirement[]
660
+
682
661
  // Properties developed by this organization (for DEVELOPERs)
683
662
  // developedProperties Property[] @relation("PropertyDeveloper")
684
663
 
@@ -728,6 +707,83 @@ model OrganizationMember {
728
707
  @@map("organization_members")
729
708
  }
730
709
 
710
+ // =============================================================================
711
+ // BANK DOCUMENT REQUIREMENTS - Bank-specific document overlays
712
+ // =============================================================================
713
+ // Banks have different risk appetites and compliance requirements.
714
+ // For a standardized product (e.g., NHF Mortgage), the payment structure is fixed
715
+ // but document requirements vary by bank.
716
+ //
717
+ // This model defines OVERLAY rules:
718
+ // - Base documents come from DocumentationPlan
719
+ // - Bank adds/modifies requirements via BankDocumentRequirement
720
+ //
721
+ // When switching banks mid-application:
722
+ // 1. Keep all existing approved documents
723
+ // 2. Query new bank's requirements
724
+ // 3. Calculate delta (what's missing)
725
+ // 4. Customer uploads only the delta
726
+ // =============================================================================
727
+
728
+ /// How the bank's requirement modifies the base requirement
729
+ enum BankDocumentModifier {
730
+ REQUIRED // Bank requires this document (add if not in base)
731
+ OPTIONAL // Bank makes this optional (override base if required)
732
+ NOT_REQUIRED // Bank doesn't need this (skip even if in base)
733
+ STRICTER // Bank has stricter version (e.g., 12 months instead of 6)
734
+ }
735
+
736
+ /// Bank Document Requirement - Bank-specific document rules
737
+ model BankDocumentRequirement {
738
+ id String @id @default(cuid())
739
+ tenantId String
740
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
741
+
742
+ // Which bank this applies to
743
+ organizationId String
744
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
745
+
746
+ // Which phase type this applies to (e.g., KYC, VERIFICATION)
747
+ phaseType String
748
+
749
+ // Optional: specific payment method (NULL = applies to all)
750
+ paymentMethodId String?
751
+ paymentMethod PropertyPaymentMethod? @relation(fields: [paymentMethodId], references: [id])
752
+
753
+ // Document identification
754
+ documentType String // ID_CARD, BANK_STATEMENT, EMPLOYMENT_LETTER, etc.
755
+ documentName String // Human-readable override (e.g., "12 Months Bank Statement")
756
+
757
+ // How this modifies the base requirement
758
+ modifier BankDocumentModifier @default(REQUIRED)
759
+
760
+ // Bank-specific rules
761
+ description String? @db.Text // Bank's specific instructions
762
+ expiryDays Int? // Bank's validity period (may be stricter than base)
763
+ minFiles Int? // Bank may require more files
764
+ maxFiles Int?
765
+ allowedMimeTypes String? // Bank may restrict file types
766
+
767
+ // Bank-specific validation (JSON schema)
768
+ // Example: { "bankStatementMonths": 12, "minimumBalance": 500000 }
769
+ validationRules Json?
770
+
771
+ // Priority for conflict resolution (higher = takes precedence)
772
+ priority Int @default(100)
773
+
774
+ isActive Boolean @default(true)
775
+ createdAt DateTime @default(now())
776
+ updatedAt DateTime @updatedAt
777
+
778
+ @@unique([organizationId, phaseType, documentType, paymentMethodId])
779
+ @@index([tenantId])
780
+ @@index([organizationId])
781
+ @@index([phaseType])
782
+ @@index([documentType])
783
+ @@index([paymentMethodId])
784
+ @@map("bank_document_requirements")
785
+ }
786
+
731
787
  model Tenant {
732
788
  id String @id @default(cuid())
733
789
  name String
@@ -765,10 +821,9 @@ model Tenant {
765
821
  apiKeys ApiKey[]
766
822
 
767
823
  // Event-driven workflow
768
- eventChannels EventChannel[]
769
- eventTypes EventType[]
770
- eventHandlers EventHandler[]
771
- workflowEvents WorkflowEvent[]
824
+ eventChannels EventChannel[]
825
+ eventTypes EventType[]
826
+ eventHandlers EventHandler[]
772
827
 
773
828
  // Property transfer requests
774
829
  propertyTransferRequests PropertyTransferRequest[]
@@ -803,7 +858,6 @@ model Tenant {
803
858
  propertyVariantMedia PropertyVariantMedia[]
804
859
  propertyUnits PropertyUnit[]
805
860
  propertyAmenities PropertyAmenity[]
806
- eventHandlerExecutions EventHandlerExecution[]
807
861
  amenities Amenity[]
808
862
  socials Social[]
809
863
  wallets Wallet[]
@@ -815,9 +869,15 @@ model Tenant {
815
869
  questionnairePhaseReviews QuestionnairePhaseReview[]
816
870
  documentReviews DocumentReview[]
817
871
 
872
+ // Bank-specific document requirements
873
+ bankDocumentRequirements BankDocumentRequirement[]
874
+
818
875
  // Organizations (Banks, Developers) operating on this tenant
819
876
  organizations Organization[]
820
877
 
878
+ // Application organization assignments
879
+ applicationOrganizations ApplicationOrganization[]
880
+
821
881
  @@index([subdomain])
822
882
  @@map("tenants")
823
883
  }
@@ -1570,6 +1630,9 @@ model PropertyPaymentMethod {
1570
1630
  changeRulesFrom DocumentRequirementRule[] @relation("RuleFromMethod")
1571
1631
  changeRulesTo DocumentRequirementRule[] @relation("RuleToMethod")
1572
1632
 
1633
+ // Bank-specific document requirements for this payment method
1634
+ bankDocumentRequirements BankDocumentRequirement[]
1635
+
1573
1636
  @@unique([tenantId, name]) // Unique per tenant
1574
1637
  @@index([tenantId])
1575
1638
  @@map("property_payment_methods")
@@ -1914,6 +1977,17 @@ model Application {
1914
1977
  paymentMethodId String? // PropertyPaymentMethod used to create this contract
1915
1978
  paymentMethod PropertyPaymentMethod? @relation(fields: [paymentMethodId], references: [id])
1916
1979
 
1980
+ // =========================================================================
1981
+ // PAYMENT METHOD VERSION SNAPSHOT
1982
+ // =========================================================================
1983
+ // Captures the payment method configuration at application creation time.
1984
+ // This ensures existing applications continue with original terms even if
1985
+ // the payment method template is later modified.
1986
+ // =========================================================================
1987
+ paymentMethodSnapshot Json? // Full snapshot of PropertyPaymentMethod + phases at creation
1988
+ paymentMethodSnapshotAt DateTime? // When the snapshot was taken
1989
+ paymentMethodSnapshotHash String? // Hash to detect if template changed since snapshot
1990
+
1917
1991
  // Contract identification
1918
1992
  applicationNumber String @unique
1919
1993
  title String
@@ -1971,6 +2045,9 @@ model Application {
1971
2045
  // Refund requests
1972
2046
  refunds ApplicationRefund[]
1973
2047
 
2048
+ // Organization assignments - which orgs are involved in this application
2049
+ organizations ApplicationOrganization[]
2050
+
1974
2051
  @@index([tenantId])
1975
2052
  @@index([propertyUnitId])
1976
2053
  @@index([buyerId])
@@ -1982,6 +2059,104 @@ model Application {
1982
2059
  @@map("applications")
1983
2060
  }
1984
2061
 
2062
+ // =============================================================================
2063
+ // APPLICATION ORGANIZATION - Binds organizations to specific applications
2064
+ // =============================================================================
2065
+ // Tracks which organizations (banks, developers, legal firms) are involved
2066
+ // in a specific application. This enables:
2067
+ // 1. Validation that only assigned developers can upload sales offers
2068
+ // 2. Only assigned banks can upload preapproval/mortgage offer letters
2069
+ // 3. Multi-bank application support (future: apply to multiple banks)
2070
+ // =============================================================================
2071
+
2072
+ /// Role that an organization plays in an application
2073
+ enum ApplicationOrganizationRole {
2074
+ DEVELOPER // Property developer - uploads sales offer letters
2075
+ LENDER // Bank/financial institution - provides mortgage
2076
+ LEGAL // Legal firm - handles conveyancing
2077
+ INSURER // Insurance company
2078
+ GOVERNMENT // Government agency (land registry, etc.)
2079
+ }
2080
+
2081
+ /// Status of organization's involvement in the application
2082
+ enum ApplicationOrganizationStatus {
2083
+ PENDING // Awaiting organization's response/engagement
2084
+ ACTIVE // Organization is actively participating
2085
+ COMPLETED // Organization's role is complete
2086
+ DECLINED // Organization declined to participate
2087
+ WITHDRAWN // Organization withdrew from the application
2088
+ }
2089
+
2090
+ model ApplicationOrganization {
2091
+ id String @id @default(cuid())
2092
+ tenantId String
2093
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
2094
+ applicationId String
2095
+ application Application @relation(fields: [applicationId], references: [id], onDelete: Cascade)
2096
+
2097
+ // Which organization is involved
2098
+ organizationId String
2099
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
2100
+
2101
+ // What role does this organization play
2102
+ role ApplicationOrganizationRole
2103
+ status ApplicationOrganizationStatus @default(PENDING)
2104
+
2105
+ // Who assigned this organization (admin or system)
2106
+ assignedById String?
2107
+ assignedAt DateTime @default(now())
2108
+
2109
+ // For multi-bank applications: track if this is the selected lender
2110
+ // Multiple banks can be PENDING, but only one should be ACTIVE for LENDER role
2111
+ isPrimary Boolean @default(false)
2112
+
2113
+ // Organization-specific terms (e.g., bank's offered interest rate)
2114
+ offeredTerms Json? // { interestRate, termMonths, conditions, etc. }
2115
+ termsOfferedAt DateTime?
2116
+ termsAcceptedAt DateTime?
2117
+ termsDeclinedAt DateTime?
2118
+ declineReason String? @db.Text
2119
+
2120
+ // Tracking
2121
+ activatedAt DateTime?
2122
+ completedAt DateTime?
2123
+ withdrawnAt DateTime?
2124
+
2125
+ // =========================================================================
2126
+ // SLA TRACKING - Monitor bank responsiveness
2127
+ // =========================================================================
2128
+ // When documentation is complete, clock starts for bank to respond.
2129
+ // If they're slow, admin can reassign to another bank.
2130
+ // =========================================================================
2131
+ slaHours Int? // Expected response time (e.g., 48 hours)
2132
+ slaStartedAt DateTime? // When clock started (e.g., when docs were complete)
2133
+ slaBreachedAt DateTime? // When SLA was breached (set by cron job)
2134
+ slaBreachNotified Boolean @default(false) // Was admin notified of breach?
2135
+
2136
+ // Reminder tracking
2137
+ reminderCount Int @default(0)
2138
+ lastReminderSentAt DateTime?
2139
+ nextReminderAt DateTime?
2140
+
2141
+ // Escalation
2142
+ escalatedAt DateTime?
2143
+ escalatedToUserId String? // Admin handling the escalation
2144
+ escalationNotes String? @db.Text
2145
+
2146
+ createdAt DateTime @default(now())
2147
+ updatedAt DateTime @updatedAt
2148
+
2149
+ @@unique([applicationId, organizationId, role]) // One org per role per application
2150
+ @@index([tenantId])
2151
+ @@index([applicationId])
2152
+ @@index([organizationId])
2153
+ @@index([role])
2154
+ @@index([status])
2155
+ @@index([isPrimary])
2156
+ @@index([slaBreachedAt])
2157
+ @@map("application_organizations")
2158
+ }
2159
+
1985
2160
  // =============================================================================
1986
2161
  // CONTRACT REFUNDS - Track refund requests for overpayments or cancellations
1987
2162
  // =============================================================================
@@ -2182,8 +2357,8 @@ model QuestionnairePhaseReview {
2182
2357
  notes String? @db.Text
2183
2358
 
2184
2359
  // Snapshot of scores at time of review (for audit)
2185
- scoreAtReview Int? // The totalScore when this review was made
2186
- passedAtReview Boolean? // The passed flag when this review was made
2360
+ scoreAtReview Int? // The totalScore when this review was made
2361
+ passedAtReview Boolean? // The passed flag when this review was made
2187
2362
 
2188
2363
  createdAt DateTime @default(now())
2189
2364
 
@@ -2478,6 +2653,29 @@ model ApplicationDocument {
2478
2653
  uploadedById String?
2479
2654
  uploadedBy User? @relation("DocumentUploader", fields: [uploadedById], references: [id])
2480
2655
 
2656
+ // =========================================================================
2657
+ // UPLOADER VALIDATION - Enforces who can upload this document
2658
+ // =========================================================================
2659
+ // expectedUploader is set from DocumentDefinition.uploadedBy at phase creation
2660
+ // Allows validation that correct party is uploading (e.g., developer uploads sales offer)
2661
+ expectedUploader UploadedBy? // CUSTOMER, LENDER, DEVELOPER, LEGAL, PLATFORM, etc.
2662
+ // If expectedUploader is LENDER/DEVELOPER, track which org should upload
2663
+ expectedOrganizationId String?
2664
+
2665
+ // =========================================================================
2666
+ // DOCUMENT EXPIRY - Time-sensitive document tracking
2667
+ // =========================================================================
2668
+ // Documents like bank statements have a shelf life. If application takes too long,
2669
+ // documents may need to be re-uploaded.
2670
+ // =========================================================================
2671
+ documentDate DateTime? // When the document was issued/created (e.g., bank statement date)
2672
+ expiresAt DateTime? // When this document expires (computed from documentDate + expiryDays)
2673
+ expiryDays Int? // Number of days this document type is valid (copied from DocumentDefinition)
2674
+ isExpired Boolean @default(false) // Denormalized flag, updated by cron job
2675
+ expiredAt DateTime? // When the document was marked expired
2676
+ expiryWarningAt DateTime? // When expiry warning was sent
2677
+ revalidatedAt DateTime? // If document was re-uploaded after expiry
2678
+
2481
2679
  status DocumentStatus @default(PENDING)
2482
2680
 
2483
2681
  // NO versioning - document is replaced on re-upload (url is updated)
@@ -2504,6 +2702,8 @@ model ApplicationDocument {
2504
2702
  @@index([documentType])
2505
2703
  @@index([status])
2506
2704
  @@index([replacesDocumentId])
2705
+ @@index([isExpired])
2706
+ @@index([expiresAt])
2507
2707
  @@map("application_documents")
2508
2708
  }
2509
2709
 
@@ -3033,9 +3233,6 @@ model EventType {
3033
3233
  /// Handlers subscribed to this event type
3034
3234
  handlers EventHandler[]
3035
3235
 
3036
- /// Actual event instances of this type
3037
- events WorkflowEvent[]
3038
-
3039
3236
  createdAt DateTime @default(now())
3040
3237
  updatedAt DateTime @updatedAt
3041
3238
 
@@ -3086,9 +3283,6 @@ model EventHandler {
3086
3283
  /// e.g., "$.payload.status == 'approved'"
3087
3284
  filterCondition String? @db.Text
3088
3285
 
3089
- /// Handler execution logs
3090
- executions EventHandlerExecution[]
3091
-
3092
3286
  /// Step attachments - steps that have attached this handler
3093
3287
  stepAttachments StepEventAttachment[]
3094
3288
 
@@ -3104,100 +3298,6 @@ model EventHandler {
3104
3298
  @@map("event_handlers")
3105
3299
  }
3106
3300
 
3107
- /// Workflow Event - An actual event instance that occurred
3108
- /// This is the audit log of all events in the system
3109
- model WorkflowEvent {
3110
- id String @id @default(cuid())
3111
- tenantId String
3112
- tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
3113
-
3114
- /// The type of this event
3115
- eventTypeId String
3116
- eventType EventType @relation(fields: [eventTypeId], references: [id], onDelete: Cascade)
3117
-
3118
- /// The event payload (actual data)
3119
- payload Json
3120
-
3121
- /// Optional correlation ID to link related events
3122
- correlationId String?
3123
-
3124
- /// Optional causation ID (which event caused this one)
3125
- causationId String?
3126
-
3127
- /// Source of the event (service name, user action, etc.)
3128
- source String
3129
-
3130
- /// Actor who triggered the event (user ID, API key ID, "system")
3131
- actorId String?
3132
- actorType ActorType @default(SYSTEM)
3133
-
3134
- /// Event status
3135
- status WorkflowEventStatus @default(PENDING)
3136
-
3137
- /// Error message if processing failed
3138
- error String? @db.Text
3139
-
3140
- /// When the event was processed
3141
- processedAt DateTime?
3142
-
3143
- /// Handler executions for this event
3144
- executions EventHandlerExecution[]
3145
-
3146
- createdAt DateTime @default(now())
3147
-
3148
- @@index([tenantId])
3149
- @@index([eventTypeId])
3150
- @@index([correlationId])
3151
- @@index([causationId])
3152
- @@index([status])
3153
- @@index([createdAt])
3154
- @@map("workflow_events")
3155
- }
3156
-
3157
- /// Event Handler Execution - Log of a handler processing an event
3158
- model EventHandlerExecution {
3159
- id String @id @default(cuid())
3160
- tenantId String
3161
- tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
3162
-
3163
- /// The event being processed
3164
- eventId String
3165
- event WorkflowEvent @relation(fields: [eventId], references: [id], onDelete: Cascade)
3166
-
3167
- /// The handler that processed this event
3168
- handlerId String
3169
- handler EventHandler @relation(fields: [handlerId], references: [id], onDelete: Cascade)
3170
-
3171
- /// Execution status
3172
- status ExecutionStatus @default(PENDING)
3173
-
3174
- /// Attempt number (1 for first try, increments on retry)
3175
- attempt Int @default(1)
3176
-
3177
- /// Input to the handler (may be transformed payload)
3178
- input Json?
3179
-
3180
- /// Output from the handler
3181
- output Json?
3182
-
3183
- /// Error details if failed
3184
- error String? @db.Text
3185
- errorCode String?
3186
-
3187
- /// Timing
3188
- startedAt DateTime?
3189
- completedAt DateTime?
3190
- durationMs Int?
3191
-
3192
- createdAt DateTime @default(now())
3193
-
3194
- @@index([tenantId])
3195
- @@index([eventId])
3196
- @@index([handlerId])
3197
- @@index([status])
3198
- @@map("event_handler_executions")
3199
- }
3200
-
3201
3301
  // =============================================================================
3202
3302
  // EVENT OUTBOX - For guaranteed event delivery to SQS queues
3203
3303
  // =============================================================================
@@ -3504,3 +3604,102 @@ model WorkflowBlocker {
3504
3604
  @@index([tenantId, isOverdue, blockerActor]) // For SLA violation queries
3505
3605
  @@map("workflow_blockers")
3506
3606
  }
3607
+
3608
+ // =============================================================================
3609
+ // DOCUMENT EXPIRY JOB - Scheduled job tracking for document expiration checks
3610
+ // =============================================================================
3611
+ // Tracks scheduled jobs for checking document expiration across applications.
3612
+ // This supports a cron-based approach where a Lambda runs periodically to:
3613
+ // 1. Find documents nearing expiry (warning)
3614
+ // 2. Mark expired documents
3615
+ // 3. Notify customers to re-upload
3616
+ // 4. Optionally block phase progression if critical documents expired
3617
+ // =============================================================================
3618
+
3619
+ /// Job status for scheduled background jobs
3620
+ enum ScheduledJobStatus {
3621
+ PENDING
3622
+ RUNNING
3623
+ COMPLETED
3624
+ FAILED
3625
+ CANCELLED
3626
+ }
3627
+
3628
+ /// Type of scheduled job
3629
+ enum ScheduledJobType {
3630
+ DOCUMENT_EXPIRY_CHECK // Check for expired documents
3631
+ SLA_BREACH_CHECK // Check for SLA breaches
3632
+ PAYMENT_REMINDER // Send payment reminders
3633
+ DOCUMENT_EXPIRY_WARNING // Warn about documents nearing expiry
3634
+ }
3635
+
3636
+ /// Scheduled Job - Tracks execution of background jobs
3637
+ model ScheduledJob {
3638
+ id String @id @default(cuid())
3639
+ tenantId String? // NULL = system-wide job, set = tenant-specific
3640
+
3641
+ jobType ScheduledJobType
3642
+ status ScheduledJobStatus @default(PENDING)
3643
+
3644
+ // Scheduling
3645
+ scheduledAt DateTime // When the job should run
3646
+ startedAt DateTime? // When job started executing
3647
+ completedAt DateTime? // When job finished
3648
+ durationMs Int? // Execution time
3649
+
3650
+ // Job parameters
3651
+ parameters Json? // Job-specific configuration
3652
+
3653
+ // Results
3654
+ itemsProcessed Int @default(0)
3655
+ itemsAffected Int @default(0) // Documents expired, SLAs breached, etc.
3656
+ errorCount Int @default(0)
3657
+ errors Json? // Array of error details
3658
+ summary String? @db.Text // Human-readable summary
3659
+
3660
+ // Retry handling
3661
+ attemptNumber Int @default(1)
3662
+ maxAttempts Int @default(3)
3663
+ nextRetryAt DateTime?
3664
+
3665
+ createdAt DateTime @default(now())
3666
+ updatedAt DateTime @updatedAt
3667
+
3668
+ @@index([tenantId])
3669
+ @@index([jobType])
3670
+ @@index([status])
3671
+ @@index([scheduledAt])
3672
+ @@index([jobType, status, scheduledAt])
3673
+ @@map("scheduled_jobs")
3674
+ }
3675
+
3676
+ /// Document Expiry Warning - Track warnings sent for expiring documents
3677
+ model DocumentExpiryWarning {
3678
+ id String @id @default(cuid())
3679
+ tenantId String
3680
+ documentId String
3681
+
3682
+ // Warning details
3683
+ expiresAt DateTime // When document will expire
3684
+ daysUntil Int // Days until expiry at time of warning
3685
+ warningSent DateTime @default(now())
3686
+
3687
+ // Customer notification tracking
3688
+ notificationSent Boolean @default(false)
3689
+ notificationId String? // Reference to notification service
3690
+
3691
+ // Resolution tracking
3692
+ resolved Boolean @default(false)
3693
+ resolvedAt DateTime?
3694
+ resolvedBy String? // User who resolved (re-uploaded document)
3695
+ newDocumentId String? // ID of the replacement document
3696
+
3697
+ createdAt DateTime @default(now())
3698
+
3699
+ @@unique([documentId, daysUntil]) // One warning per document per threshold
3700
+ @@index([tenantId])
3701
+ @@index([documentId])
3702
+ @@index([expiresAt])
3703
+ @@index([resolved])
3704
+ @@map("document_expiry_warnings")
3705
+ }