@valentine-efagene/qshelter-common 2.0.138 → 2.0.139

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 (33) hide show
  1. package/dist/generated/client/browser.d.ts +20 -0
  2. package/dist/generated/client/client.d.ts +20 -0
  3. package/dist/generated/client/commonInputTypes.d.ts +120 -30
  4. package/dist/generated/client/enums.d.ts +23 -0
  5. package/dist/generated/client/enums.js +21 -1
  6. package/dist/generated/client/internal/class.d.ts +44 -0
  7. package/dist/generated/client/internal/class.js +2 -2
  8. package/dist/generated/client/internal/prismaNamespace.d.ts +401 -5
  9. package/dist/generated/client/internal/prismaNamespace.js +108 -0
  10. package/dist/generated/client/internal/prismaNamespaceBrowser.d.ts +116 -0
  11. package/dist/generated/client/internal/prismaNamespaceBrowser.js +108 -0
  12. package/dist/generated/client/models/ApplicationDocument.d.ts +290 -1
  13. package/dist/generated/client/models/ApprovalStage.d.ts +1605 -0
  14. package/dist/generated/client/models/ApprovalStage.js +1 -0
  15. package/dist/generated/client/models/ApprovalStageProgress.d.ts +2329 -0
  16. package/dist/generated/client/models/ApprovalStageProgress.js +1 -0
  17. package/dist/generated/client/models/DocumentApproval.d.ts +1611 -0
  18. package/dist/generated/client/models/DocumentApproval.js +1 -0
  19. package/dist/generated/client/models/DocumentDefinition.d.ts +1475 -0
  20. package/dist/generated/client/models/DocumentDefinition.js +1 -0
  21. package/dist/generated/client/models/DocumentReview.d.ts +0 -3
  22. package/dist/generated/client/models/DocumentationPhase.d.ts +167 -0
  23. package/dist/generated/client/models/DocumentationPlan.d.ts +270 -0
  24. package/dist/generated/client/models/Tenant.d.ts +1281 -131
  25. package/dist/generated/client/models/User.d.ts +824 -0
  26. package/dist/generated/client/models/index.d.ts +4 -0
  27. package/dist/generated/client/models/index.js +4 -0
  28. package/dist/generated/client/models.d.ts +4 -0
  29. package/dist/src/utils/documentation-enums.d.ts +10 -1
  30. package/dist/src/utils/documentation-enums.js +8 -0
  31. package/package.json +1 -1
  32. package/prisma/migrations/20260119190336_add_document_approval_workflow/migration.sql +134 -0
  33. package/prisma/schema.prisma +244 -5
@@ -8,7 +8,11 @@ export * from './ApplicationPhase';
8
8
  export * from './ApplicationRefund';
9
9
  export * from './ApplicationTermination';
10
10
  export * from './ApprovalRequest';
11
+ export * from './ApprovalStage';
12
+ export * from './ApprovalStageProgress';
11
13
  export * from './DeviceEndpoint';
14
+ export * from './DocumentApproval';
15
+ export * from './DocumentDefinition';
12
16
  export * from './DocumentRequirementRule';
13
17
  export * from './DocumentReview';
14
18
  export * from './DocumentTemplate';
@@ -8,7 +8,11 @@ export * from './ApplicationPhase';
8
8
  export * from './ApplicationRefund';
9
9
  export * from './ApplicationTermination';
10
10
  export * from './ApprovalRequest';
11
+ export * from './ApprovalStage';
12
+ export * from './ApprovalStageProgress';
11
13
  export * from './DeviceEndpoint';
14
+ export * from './DocumentApproval';
15
+ export * from './DocumentDefinition';
12
16
  export * from './DocumentRequirementRule';
13
17
  export * from './DocumentReview';
14
18
  export * from './DocumentTemplate';
@@ -29,6 +29,8 @@ export type * from './models/PropertyUnit.js';
29
29
  export type * from './models/PropertyAmenity.js';
30
30
  export type * from './models/DocumentationPlan.js';
31
31
  export type * from './models/DocumentationPlanStep.js';
32
+ export type * from './models/DocumentDefinition.js';
33
+ export type * from './models/ApprovalStage.js';
32
34
  export type * from './models/QuestionnairePlan.js';
33
35
  export type * from './models/QuestionnairePlanQuestion.js';
34
36
  export type * from './models/PaymentPlan.js';
@@ -55,6 +57,8 @@ export type * from './models/PaymentInstallment.js';
55
57
  export type * from './models/ApplicationPayment.js';
56
58
  export type * from './models/ApplicationDocument.js';
57
59
  export type * from './models/DocumentReview.js';
60
+ export type * from './models/ApprovalStageProgress.js';
61
+ export type * from './models/DocumentApproval.js';
58
62
  export type * from './models/DocumentTemplate.js';
59
63
  export type * from './models/OfferLetter.js';
60
64
  export type * from './models/ApplicationTermination.js';
@@ -1,9 +1,13 @@
1
1
  /**
2
2
  * Documentation-related enums for documentation plan steps.
3
3
  * Used in DocumentationPlanStep metadata to indicate upload responsibility.
4
+ *
5
+ * NOTE: The UploadedBy Prisma enum is now the source of truth.
6
+ * This constant object is kept for backward compatibility.
4
7
  */
5
8
  /**
6
9
  * Indicates who is responsible for uploading a document in a documentation step.
10
+ * @deprecated Use the UploadedBy Prisma enum instead
7
11
  */
8
12
  export declare const UPLOADED_BY: {
9
13
  /** Document is uploaded by the customer/applicant */
@@ -16,10 +20,15 @@ export declare const UPLOADED_BY: {
16
20
  readonly DEVELOPER: "DEVELOPER";
17
21
  /** Document is uploaded by the system (auto-generated) */
18
22
  readonly SYSTEM: "SYSTEM";
23
+ /** Document is uploaded by the platform staff */
24
+ readonly PLATFORM: "PLATFORM";
19
25
  /** Document is uploaded by a legal officer */
20
26
  readonly LEGAL: "LEGAL";
27
+ /** Document is uploaded by an insurer */
28
+ readonly INSURER: "INSURER";
21
29
  };
22
30
  /**
23
31
  * Type representing a valid uploadedBy value.
32
+ * @deprecated Use the UploadedBy Prisma enum instead
24
33
  */
25
- export type UploadedBy = (typeof UPLOADED_BY)[keyof typeof UPLOADED_BY];
34
+ export type UploadedByType = (typeof UPLOADED_BY)[keyof typeof UPLOADED_BY];
@@ -1,9 +1,13 @@
1
1
  /**
2
2
  * Documentation-related enums for documentation plan steps.
3
3
  * Used in DocumentationPlanStep metadata to indicate upload responsibility.
4
+ *
5
+ * NOTE: The UploadedBy Prisma enum is now the source of truth.
6
+ * This constant object is kept for backward compatibility.
4
7
  */
5
8
  /**
6
9
  * Indicates who is responsible for uploading a document in a documentation step.
10
+ * @deprecated Use the UploadedBy Prisma enum instead
7
11
  */
8
12
  export const UPLOADED_BY = {
9
13
  /** Document is uploaded by the customer/applicant */
@@ -16,6 +20,10 @@ export const UPLOADED_BY = {
16
20
  DEVELOPER: 'DEVELOPER',
17
21
  /** Document is uploaded by the system (auto-generated) */
18
22
  SYSTEM: 'SYSTEM',
23
+ /** Document is uploaded by the platform staff */
24
+ PLATFORM: 'PLATFORM',
19
25
  /** Document is uploaded by a legal officer */
20
26
  LEGAL: 'LEGAL',
27
+ /** Document is uploaded by an insurer */
28
+ INSURER: 'INSURER',
21
29
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valentine-efagene/qshelter-common",
3
- "version": "2.0.138",
3
+ "version": "2.0.139",
4
4
  "description": "Shared database schemas and utilities for QShelter services",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -0,0 +1,134 @@
1
+ -- AlterTable
2
+ ALTER TABLE `application_documents` ADD COLUMN `documentName` VARCHAR(191) NULL,
3
+ ADD COLUMN `documentType` VARCHAR(191) NULL,
4
+ MODIFY `status` ENUM('DRAFT', 'PENDING', 'PENDING_SIGNATURE', 'SENT', 'VIEWED', 'SIGNED', 'APPROVED', 'REJECTED', 'EXPIRED', 'CANCELLED', 'NEEDS_REUPLOAD') NOT NULL DEFAULT 'PENDING';
5
+
6
+ -- CreateTable
7
+ CREATE TABLE `document_definitions` (
8
+ `id` VARCHAR(191) NOT NULL,
9
+ `planId` VARCHAR(191) NOT NULL,
10
+ `documentType` VARCHAR(191) NOT NULL,
11
+ `documentName` VARCHAR(191) NOT NULL,
12
+ `uploadedBy` ENUM('CUSTOMER', 'LENDER', 'DEVELOPER', 'LEGAL', 'INSURER', 'PLATFORM') NOT NULL DEFAULT 'CUSTOMER',
13
+ `order` INTEGER NOT NULL,
14
+ `isRequired` BOOLEAN NOT NULL DEFAULT true,
15
+ `description` TEXT NULL,
16
+ `maxSizeBytes` INTEGER NULL,
17
+ `allowedMimeTypes` VARCHAR(191) NULL,
18
+ `expiryDays` INTEGER NULL,
19
+ `minFiles` INTEGER NOT NULL DEFAULT 1,
20
+ `maxFiles` INTEGER NOT NULL DEFAULT 1,
21
+ `condition` JSON NULL,
22
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
23
+ `updatedAt` DATETIME(3) NOT NULL,
24
+
25
+ INDEX `document_definitions_planId_idx`(`planId`),
26
+ PRIMARY KEY (`id`)
27
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
28
+
29
+ -- CreateTable
30
+ CREATE TABLE `approval_stages` (
31
+ `id` VARCHAR(191) NOT NULL,
32
+ `planId` VARCHAR(191) NOT NULL,
33
+ `name` VARCHAR(191) NOT NULL,
34
+ `order` INTEGER NOT NULL,
35
+ `reviewParty` ENUM('INTERNAL', 'BANK', 'DEVELOPER', 'LEGAL', 'GOVERNMENT', 'INSURER', 'CUSTOMER') NOT NULL,
36
+ `autoTransition` BOOLEAN NOT NULL DEFAULT false,
37
+ `waitForAllDocuments` BOOLEAN NOT NULL DEFAULT true,
38
+ `allowEarlyVisibility` BOOLEAN NOT NULL DEFAULT false,
39
+ `onRejection` ENUM('CASCADE_BACK', 'RESTART_CURRENT', 'RESTART_FROM_STAGE') NOT NULL DEFAULT 'CASCADE_BACK',
40
+ `restartFromStageOrder` INTEGER NULL,
41
+ `organizationId` VARCHAR(191) NULL,
42
+ `slaHours` INTEGER NULL,
43
+ `description` TEXT NULL,
44
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
45
+ `updatedAt` DATETIME(3) NOT NULL,
46
+
47
+ INDEX `approval_stages_planId_idx`(`planId`),
48
+ UNIQUE INDEX `approval_stages_planId_order_key`(`planId`, `order`),
49
+ PRIMARY KEY (`id`)
50
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
51
+
52
+ -- CreateTable
53
+ CREATE TABLE `approval_stage_progress` (
54
+ `id` VARCHAR(191) NOT NULL,
55
+ `tenantId` VARCHAR(191) NOT NULL,
56
+ `documentationPhaseId` VARCHAR(191) NOT NULL,
57
+ `approvalStageId` VARCHAR(191) NOT NULL,
58
+ `name` VARCHAR(191) NOT NULL,
59
+ `order` INTEGER NOT NULL,
60
+ `reviewParty` ENUM('INTERNAL', 'BANK', 'DEVELOPER', 'LEGAL', 'GOVERNMENT', 'INSURER', 'CUSTOMER') NOT NULL,
61
+ `autoTransition` BOOLEAN NOT NULL DEFAULT false,
62
+ `waitForAllDocuments` BOOLEAN NOT NULL DEFAULT true,
63
+ `allowEarlyVisibility` BOOLEAN NOT NULL DEFAULT false,
64
+ `onRejection` ENUM('CASCADE_BACK', 'RESTART_CURRENT', 'RESTART_FROM_STAGE') NOT NULL DEFAULT 'CASCADE_BACK',
65
+ `restartFromStageOrder` INTEGER NULL,
66
+ `status` ENUM('PENDING', 'IN_PROGRESS', 'AWAITING_TRANSITION', 'COMPLETED') NOT NULL DEFAULT 'PENDING',
67
+ `activatedAt` DATETIME(3) NULL,
68
+ `completedAt` DATETIME(3) NULL,
69
+ `completedById` VARCHAR(191) NULL,
70
+ `transitionComment` TEXT NULL,
71
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
72
+ `updatedAt` DATETIME(3) NOT NULL,
73
+
74
+ INDEX `approval_stage_progress_tenantId_idx`(`tenantId`),
75
+ INDEX `approval_stage_progress_documentationPhaseId_idx`(`documentationPhaseId`),
76
+ INDEX `approval_stage_progress_approvalStageId_idx`(`approvalStageId`),
77
+ INDEX `approval_stage_progress_status_idx`(`status`),
78
+ UNIQUE INDEX `approval_stage_progress_documentationPhaseId_order_key`(`documentationPhaseId`, `order`),
79
+ PRIMARY KEY (`id`)
80
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
81
+
82
+ -- CreateTable
83
+ CREATE TABLE `document_approvals` (
84
+ `id` VARCHAR(191) NOT NULL,
85
+ `tenantId` VARCHAR(191) NOT NULL,
86
+ `documentId` VARCHAR(191) NOT NULL,
87
+ `stageProgressId` VARCHAR(191) NOT NULL,
88
+ `reviewerId` VARCHAR(191) NOT NULL,
89
+ `reviewParty` ENUM('INTERNAL', 'BANK', 'DEVELOPER', 'LEGAL', 'GOVERNMENT', 'INSURER', 'CUSTOMER') NOT NULL,
90
+ `decision` ENUM('PENDING', 'APPROVED', 'REJECTED', 'CHANGES_REQUESTED', 'WAIVED') NOT NULL,
91
+ `comment` TEXT NULL,
92
+ `reviewedAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
93
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
94
+
95
+ INDEX `document_approvals_tenantId_idx`(`tenantId`),
96
+ INDEX `document_approvals_documentId_idx`(`documentId`),
97
+ INDEX `document_approvals_stageProgressId_idx`(`stageProgressId`),
98
+ INDEX `document_approvals_reviewerId_idx`(`reviewerId`),
99
+ INDEX `document_approvals_decision_idx`(`decision`),
100
+ PRIMARY KEY (`id`)
101
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
102
+
103
+ -- CreateIndex
104
+ CREATE INDEX `application_documents_documentType_idx` ON `application_documents`(`documentType`);
105
+
106
+ -- AddForeignKey
107
+ ALTER TABLE `document_definitions` ADD CONSTRAINT `document_definitions_planId_fkey` FOREIGN KEY (`planId`) REFERENCES `documentation_plans`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
108
+
109
+ -- AddForeignKey
110
+ ALTER TABLE `approval_stages` ADD CONSTRAINT `approval_stages_planId_fkey` FOREIGN KEY (`planId`) REFERENCES `documentation_plans`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
111
+
112
+ -- AddForeignKey
113
+ ALTER TABLE `approval_stage_progress` ADD CONSTRAINT `approval_stage_progress_tenantId_fkey` FOREIGN KEY (`tenantId`) REFERENCES `tenants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
114
+
115
+ -- AddForeignKey
116
+ ALTER TABLE `approval_stage_progress` ADD CONSTRAINT `approval_stage_progress_documentationPhaseId_fkey` FOREIGN KEY (`documentationPhaseId`) REFERENCES `documentation_phases`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
117
+
118
+ -- AddForeignKey
119
+ ALTER TABLE `approval_stage_progress` ADD CONSTRAINT `approval_stage_progress_approvalStageId_fkey` FOREIGN KEY (`approvalStageId`) REFERENCES `approval_stages`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
120
+
121
+ -- AddForeignKey
122
+ ALTER TABLE `approval_stage_progress` ADD CONSTRAINT `approval_stage_progress_completedById_fkey` FOREIGN KEY (`completedById`) REFERENCES `users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
123
+
124
+ -- AddForeignKey
125
+ ALTER TABLE `document_approvals` ADD CONSTRAINT `document_approvals_tenantId_fkey` FOREIGN KEY (`tenantId`) REFERENCES `tenants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
126
+
127
+ -- AddForeignKey
128
+ ALTER TABLE `document_approvals` ADD CONSTRAINT `document_approvals_documentId_fkey` FOREIGN KEY (`documentId`) REFERENCES `application_documents`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
129
+
130
+ -- AddForeignKey
131
+ ALTER TABLE `document_approvals` ADD CONSTRAINT `document_approvals_stageProgressId_fkey` FOREIGN KEY (`stageProgressId`) REFERENCES `approval_stage_progress`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
132
+
133
+ -- AddForeignKey
134
+ ALTER TABLE `document_approvals` ADD CONSTRAINT `document_approvals_reviewerId_fkey` FOREIGN KEY (`reviewerId`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -301,6 +301,36 @@ enum DocumentStatus {
301
301
  REJECTED
302
302
  EXPIRED
303
303
  CANCELLED
304
+ NEEDS_REUPLOAD // Document rejected, customer must re-upload
305
+ }
306
+
307
+ // =============================================================================
308
+ // APPROVAL STAGE ENUMS (Multi-stage document workflow)
309
+ // =============================================================================
310
+
311
+ /// Status of an approval stage in a documentation phase
312
+ enum StageStatus {
313
+ PENDING // Not yet activated
314
+ IN_PROGRESS // Activated, documents being reviewed
315
+ AWAITING_TRANSITION // All docs approved, waiting for explicit stage completion
316
+ COMPLETED // Stage completed, next stage can activate
317
+ }
318
+
319
+ /// Who uploads a document
320
+ enum UploadedBy {
321
+ CUSTOMER
322
+ LENDER
323
+ DEVELOPER
324
+ LEGAL
325
+ INSURER
326
+ PLATFORM // QShelter staff
327
+ }
328
+
329
+ /// What happens when a later stage rejects a document
330
+ enum RejectionBehavior {
331
+ CASCADE_BACK // Restart from Stage 1 (default - full re-vetting)
332
+ RESTART_CURRENT // Only current stage re-reviews after re-upload
333
+ RESTART_FROM_STAGE // Restart from specific stage (uses restartFromStageOrder)
304
334
  }
305
335
 
306
336
  enum OfferLetterType {
@@ -491,6 +521,12 @@ model User {
491
521
  // Document reviews by this user
492
522
  documentReviews DocumentReview[] @relation("DocumentReviewer")
493
523
 
524
+ // NEW: Document approval trail entries by this user
525
+ documentApprovals DocumentApproval[] @relation("DocumentApprovalReviewer")
526
+
527
+ // NEW: Approval stages completed by this user
528
+ completedStages ApprovalStageProgress[] @relation("StageCompletedBy")
529
+
494
530
  // Organization memberships (user can be employee of banks/developers)
495
531
  organizationMemberships OrganizationMember[]
496
532
 
@@ -783,6 +819,10 @@ model Tenant {
783
819
  questionnairePlans QuestionnairePlan[]
784
820
  documentReviews DocumentReview[]
785
821
 
822
+ // NEW: Approval stage progress and document approvals
823
+ approvalStageProgress ApprovalStageProgress[]
824
+ documentApprovals DocumentApproval[]
825
+
786
826
  // Organizations (Banks, Developers) operating on this tenant
787
827
  organizations Organization[]
788
828
 
@@ -1259,8 +1299,15 @@ model DocumentationPlan {
1259
1299
  createdAt DateTime @default(now())
1260
1300
  updatedAt DateTime @updatedAt
1261
1301
 
1262
- // Steps that make up this plan
1302
+ // Steps that make up this plan (DEPRECATED - use documentDefinitions + approvalStages)
1263
1303
  steps DocumentationPlanStep[]
1304
+
1305
+ // NEW: Document definitions (what documents to collect)
1306
+ documentDefinitions DocumentDefinition[]
1307
+
1308
+ // NEW: Approval stages (sequential workflow for reviewing documents)
1309
+ approvalStages ApprovalStage[]
1310
+
1264
1311
  // Used by property payment method phases (templates)
1265
1312
  methodPhases PropertyPaymentMethodPhase[]
1266
1313
  // Used by instantiated documentation phases
@@ -1335,6 +1382,93 @@ model DocumentationPlanStep {
1335
1382
  @@map("documentation_plan_steps")
1336
1383
  }
1337
1384
 
1385
+ // =============================================================================
1386
+ // DOCUMENT DEFINITION - What documents to collect (template)
1387
+ // =============================================================================
1388
+ // Defines a document requirement within a documentation plan.
1389
+ // This is separate from approval workflow - just defines WHAT to collect.
1390
+ // =============================================================================
1391
+
1392
+ model DocumentDefinition {
1393
+ id String @id @default(cuid())
1394
+ planId String
1395
+ plan DocumentationPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
1396
+
1397
+ // Document identification
1398
+ documentType String // ID_CARD, BANK_STATEMENT, EMPLOYMENT_LETTER, etc.
1399
+ documentName String // Human-readable: "Valid ID Card", "6 Months Bank Statement"
1400
+
1401
+ // Who uploads this document
1402
+ uploadedBy UploadedBy @default(CUSTOMER)
1403
+
1404
+ // Display order
1405
+ order Int
1406
+
1407
+ // Validation rules
1408
+ isRequired Boolean @default(true)
1409
+ description String? @db.Text // Instructions for the uploader
1410
+ maxSizeBytes Int? // Max file size allowed (e.g., 5242880 for 5MB)
1411
+ allowedMimeTypes String? // CSV: application/pdf,image/jpeg,image/png
1412
+ expiryDays Int? // Document must not be older than X days
1413
+ minFiles Int @default(1)
1414
+ maxFiles Int @default(1)
1415
+
1416
+ // Conditional logic (based on questionnaire answers)
1417
+ // NULL = always required
1418
+ // Example: { "questionKey": "mortgage_type", "operator": "EQUALS", "value": "JOINT" }
1419
+ condition Json?
1420
+
1421
+ createdAt DateTime @default(now())
1422
+ updatedAt DateTime @updatedAt
1423
+
1424
+ @@index([planId])
1425
+ @@map("document_definitions")
1426
+ }
1427
+
1428
+ // =============================================================================
1429
+ // APPROVAL STAGE - Sequential workflow stages for document review (template)
1430
+ // =============================================================================
1431
+ // Defines a stage in the approval workflow. Documents flow through stages
1432
+ // sequentially. Each stage can have different reviewers (INTERNAL, BANK, etc.)
1433
+ // =============================================================================
1434
+
1435
+ model ApprovalStage {
1436
+ id String @id @default(cuid())
1437
+ planId String
1438
+ plan DocumentationPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
1439
+
1440
+ name String // "QShelter Staff Review", "Bank Review"
1441
+ order Int // 1, 2, 3 - sequential order
1442
+ reviewParty ReviewParty // INTERNAL, BANK, DEVELOPER, LEGAL, etc.
1443
+
1444
+ // Stage behavior flags
1445
+ autoTransition Boolean @default(false) // Auto-complete when all docs approved? Default: require explicit approval
1446
+ waitForAllDocuments Boolean @default(true) // Wait for all docs approved before allowing transition
1447
+ allowEarlyVisibility Boolean @default(false) // Allow read-only view before stage activates
1448
+
1449
+ // Rejection behavior - what happens when this stage rejects a document
1450
+ onRejection RejectionBehavior @default(CASCADE_BACK)
1451
+ restartFromStageOrder Int? // If onRejection = RESTART_FROM_STAGE, which stage order to restart from
1452
+
1453
+ // Optional: specific organization (e.g., which bank)
1454
+ organizationId String?
1455
+
1456
+ // SLA (optional)
1457
+ slaHours Int? // Escalate if not completed within X hours
1458
+
1459
+ description String? @db.Text // Instructions for reviewers at this stage
1460
+
1461
+ createdAt DateTime @default(now())
1462
+ updatedAt DateTime @updatedAt
1463
+
1464
+ // Runtime instances
1465
+ stageProgress ApprovalStageProgress[]
1466
+
1467
+ @@unique([planId, order])
1468
+ @@index([planId])
1469
+ @@map("approval_stages")
1470
+ }
1471
+
1338
1472
  // =============================================================================
1339
1473
  // QUESTIONNAIRE PLAN DOMAIN - Reusable form templates with scoring
1340
1474
  // =============================================================================
@@ -2144,6 +2278,9 @@ model DocumentationPhase {
2144
2278
  // Child records
2145
2279
  steps DocumentationStep[]
2146
2280
 
2281
+ // NEW: Approval stage progress (tracks which stages are completed)
2282
+ stageProgress ApprovalStageProgress[]
2283
+
2147
2284
  @@index([tenantId])
2148
2285
  @@index([phaseId])
2149
2286
  @@index([currentStepId])
@@ -2516,15 +2653,19 @@ model ApplicationDocument {
2516
2653
  phaseId String? // Optional link to specific phase
2517
2654
  stepId String? // Optional link to specific step
2518
2655
 
2519
- name String
2656
+ // Document info
2657
+ documentType String? // ID_CARD, BANK_STATEMENT, etc. (matches DocumentDefinition.documentType)
2658
+ documentName String? // Human-readable name (copied from DocumentDefinition.documentName)
2659
+ name String // File name
2520
2660
  url String
2521
- type String // ID, BANK_STATEMENT, INCOME_PROOF, TITLE_DEED, SIGNATURE, etc.
2661
+ type String // ID, BANK_STATEMENT, INCOME_PROOF, TITLE_DEED, SIGNATURE, etc. (legacy, use documentType)
2522
2662
  uploadedById String?
2523
2663
  uploadedBy User? @relation("DocumentUploader", fields: [uploadedById], references: [id])
2524
2664
 
2525
2665
  status DocumentStatus @default(PENDING)
2526
2666
 
2527
- // Document versioning (for re-uploads after changes requested)
2667
+ // NO versioning - document is replaced on re-upload (url is updated)
2668
+ // Keep these fields for backward compatibility but don't use for new code
2528
2669
  version Int @default(1)
2529
2670
  replacesDocumentId String? // If this is a revision, points to original
2530
2671
  replacesDocument ApplicationDocument? @relation("DocumentRevisions", fields: [replacesDocumentId], references: [id])
@@ -2533,14 +2674,18 @@ model ApplicationDocument {
2533
2674
  createdAt DateTime @default(now())
2534
2675
  updatedAt DateTime @updatedAt
2535
2676
 
2536
- // Multi-party reviews for this document
2677
+ // OLD: Multi-party reviews (deprecated, use approvalTrail)
2537
2678
  reviews DocumentReview[]
2538
2679
 
2680
+ // NEW: Full approval trail across all stages
2681
+ approvalTrail DocumentApproval[]
2682
+
2539
2683
  @@index([tenantId])
2540
2684
  @@index([applicationId])
2541
2685
  @@index([phaseId])
2542
2686
  @@index([stepId])
2543
2687
  @@index([type])
2688
+ @@index([documentType])
2544
2689
  @@index([status])
2545
2690
  @@index([replacesDocumentId])
2546
2691
  @@map("application_documents")
@@ -2601,6 +2746,100 @@ model DocumentReview {
2601
2746
  @@map("document_reviews")
2602
2747
  }
2603
2748
 
2749
+ // =============================================================================
2750
+ // APPROVAL STAGE PROGRESS - Runtime tracking of stage completion per phase
2751
+ // =============================================================================
2752
+ // Tracks the progress of each approval stage within a documentation phase.
2753
+ // Created when a documentation phase is instantiated from a plan.
2754
+ // =============================================================================
2755
+
2756
+ model ApprovalStageProgress {
2757
+ id String @id @default(cuid())
2758
+ tenantId String
2759
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
2760
+ documentationPhaseId String
2761
+ documentationPhase DocumentationPhase @relation(fields: [documentationPhaseId], references: [id], onDelete: Cascade)
2762
+
2763
+ // Link to template
2764
+ approvalStageId String
2765
+ approvalStage ApprovalStage @relation(fields: [approvalStageId], references: [id])
2766
+
2767
+ // Stage info (denormalized for convenience)
2768
+ name String
2769
+ order Int
2770
+ reviewParty ReviewParty
2771
+
2772
+ // Behavior flags (copied from template)
2773
+ autoTransition Boolean @default(false)
2774
+ waitForAllDocuments Boolean @default(true)
2775
+ allowEarlyVisibility Boolean @default(false)
2776
+
2777
+ // Rejection behavior (copied from template)
2778
+ onRejection RejectionBehavior @default(CASCADE_BACK)
2779
+ restartFromStageOrder Int?
2780
+
2781
+ // Status tracking
2782
+ status StageStatus @default(PENDING)
2783
+ activatedAt DateTime?
2784
+ completedAt DateTime?
2785
+
2786
+ // Who completed this stage (when autoTransition = false)
2787
+ completedById String?
2788
+ completedBy User? @relation("StageCompletedBy", fields: [completedById], references: [id])
2789
+ transitionComment String? @db.Text // Optional comment when completing stage
2790
+
2791
+ createdAt DateTime @default(now())
2792
+ updatedAt DateTime @updatedAt
2793
+
2794
+ // Document approvals made during this stage
2795
+ documentApprovals DocumentApproval[]
2796
+
2797
+ @@unique([documentationPhaseId, order])
2798
+ @@index([tenantId])
2799
+ @@index([documentationPhaseId])
2800
+ @@index([approvalStageId])
2801
+ @@index([status])
2802
+ @@map("approval_stage_progress")
2803
+ }
2804
+
2805
+ // =============================================================================
2806
+ // DOCUMENT APPROVAL - Audit trail for document reviews per stage
2807
+ // =============================================================================
2808
+ // Records every review action taken on a document within a specific stage.
2809
+ // Provides full audit trail: who reviewed, what decision, when, with comments.
2810
+ // =============================================================================
2811
+
2812
+ model DocumentApproval {
2813
+ id String @id @default(cuid())
2814
+ tenantId String
2815
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
2816
+ documentId String
2817
+ document ApplicationDocument @relation(fields: [documentId], references: [id], onDelete: Cascade)
2818
+
2819
+ // Which stage this approval belongs to
2820
+ stageProgressId String
2821
+ stageProgress ApprovalStageProgress @relation(fields: [stageProgressId], references: [id], onDelete: Cascade)
2822
+
2823
+ // Reviewer info
2824
+ reviewerId String
2825
+ reviewer User @relation("DocumentApprovalReviewer", fields: [reviewerId], references: [id])
2826
+ reviewParty ReviewParty // INTERNAL, BANK, etc.
2827
+
2828
+ // Decision
2829
+ decision ReviewDecision // APPROVED, REJECTED, CHANGES_REQUESTED
2830
+ comment String? @db.Text // Required on rejection
2831
+
2832
+ reviewedAt DateTime @default(now())
2833
+ createdAt DateTime @default(now())
2834
+
2835
+ @@index([tenantId])
2836
+ @@index([documentId])
2837
+ @@index([stageProgressId])
2838
+ @@index([reviewerId])
2839
+ @@index([decision])
2840
+ @@map("document_approvals")
2841
+ }
2842
+
2604
2843
  // =============================================================================
2605
2844
  // OFFER LETTERS - Provisional and Final offer documents
2606
2845
  // =============================================================================