@valentine-efagene/qshelter-common 2.0.137 → 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 (36) 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 +163 -73
  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 +405 -6
  9. package/dist/generated/client/internal/prismaNamespace.js +112 -1
  10. package/dist/generated/client/internal/prismaNamespaceBrowser.d.ts +120 -1
  11. package/dist/generated/client/internal/prismaNamespaceBrowser.js +112 -1
  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 +271 -40
  24. package/dist/generated/client/models/DocumentationPlanStep.d.ts +34 -1
  25. package/dist/generated/client/models/DocumentationStep.d.ts +64 -1
  26. package/dist/generated/client/models/Tenant.d.ts +1281 -131
  27. package/dist/generated/client/models/User.d.ts +824 -0
  28. package/dist/generated/client/models/index.d.ts +4 -0
  29. package/dist/generated/client/models/index.js +4 -0
  30. package/dist/generated/client/models.d.ts +4 -0
  31. package/dist/src/utils/documentation-enums.d.ts +10 -1
  32. package/dist/src/utils/documentation-enums.js +8 -0
  33. package/package.json +1 -1
  34. package/prisma/migrations/20260119180401_add_document_name_remove_required_doc_types/migration.sql +14 -0
  35. package/prisma/migrations/20260119190336_add_document_approval_workflow/migration.sql +134 -0
  36. package/prisma/schema.prisma +253 -12
@@ -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.137",
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,14 @@
1
+ /*
2
+ Warnings:
3
+
4
+ - You are about to drop the column `requiredDocumentTypes` on the `documentation_plans` table. All the data in the column will be lost.
5
+
6
+ */
7
+ -- AlterTable
8
+ ALTER TABLE `documentation_plan_steps` ADD COLUMN `documentName` VARCHAR(191) NULL;
9
+
10
+ -- AlterTable
11
+ ALTER TABLE `documentation_plans` DROP COLUMN `requiredDocumentTypes`;
12
+
13
+ -- AlterTable
14
+ ALTER TABLE `documentation_steps` ADD COLUMN `documentName` VARCHAR(191) NULL;
@@ -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
 
@@ -1256,14 +1296,18 @@ model DocumentationPlan {
1256
1296
  description String? @db.Text
1257
1297
  isActive Boolean @default(true)
1258
1298
 
1259
- // Document requirements for this plan
1260
- requiredDocumentTypes Json? // Array of document type strings, e.g., ["ID_CARD", "BANK_STATEMENT"]
1261
-
1262
1299
  createdAt DateTime @default(now())
1263
1300
  updatedAt DateTime @updatedAt
1264
1301
 
1265
- // Steps that make up this plan
1302
+ // Steps that make up this plan (DEPRECATED - use documentDefinitions + approvalStages)
1266
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
+
1267
1311
  // Used by property payment method phases (templates)
1268
1312
  methodPhases PropertyPaymentMethodPhase[]
1269
1313
  // Used by instantiated documentation phases
@@ -1286,6 +1330,9 @@ model DocumentationPlanStep {
1286
1330
 
1287
1331
  // Optional: which document type this step handles (for UPLOAD steps)
1288
1332
  documentType String?
1333
+ // Human-readable document name (e.g., "Valid ID Card" for ID_CARD)
1334
+ // If not provided, step name can be auto-generated: "Upload ${documentName}"
1335
+ documentName String?
1289
1336
  metadata Json?
1290
1337
 
1291
1338
  // Document validation rules (for UPLOAD steps)
@@ -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])
@@ -2304,10 +2441,12 @@ model DocumentationStep {
2304
2441
  documentationPhaseId String
2305
2442
  documentationPhase DocumentationPhase @relation(fields: [documentationPhaseId], references: [id], onDelete: Cascade)
2306
2443
 
2307
- name String
2308
- description String? @db.Text
2309
- stepType StepType
2310
- order Int
2444
+ name String
2445
+ // Human-readable document name (e.g., "Valid ID Card" for ID_CARD)
2446
+ documentName String?
2447
+ description String? @db.Text
2448
+ stepType StepType
2449
+ order Int
2311
2450
 
2312
2451
  status StepStatus @default(PENDING)
2313
2452
 
@@ -2514,15 +2653,19 @@ model ApplicationDocument {
2514
2653
  phaseId String? // Optional link to specific phase
2515
2654
  stepId String? // Optional link to specific step
2516
2655
 
2517
- 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
2518
2660
  url String
2519
- 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)
2520
2662
  uploadedById String?
2521
2663
  uploadedBy User? @relation("DocumentUploader", fields: [uploadedById], references: [id])
2522
2664
 
2523
2665
  status DocumentStatus @default(PENDING)
2524
2666
 
2525
- // 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
2526
2669
  version Int @default(1)
2527
2670
  replacesDocumentId String? // If this is a revision, points to original
2528
2671
  replacesDocument ApplicationDocument? @relation("DocumentRevisions", fields: [replacesDocumentId], references: [id])
@@ -2531,14 +2674,18 @@ model ApplicationDocument {
2531
2674
  createdAt DateTime @default(now())
2532
2675
  updatedAt DateTime @updatedAt
2533
2676
 
2534
- // Multi-party reviews for this document
2677
+ // OLD: Multi-party reviews (deprecated, use approvalTrail)
2535
2678
  reviews DocumentReview[]
2536
2679
 
2680
+ // NEW: Full approval trail across all stages
2681
+ approvalTrail DocumentApproval[]
2682
+
2537
2683
  @@index([tenantId])
2538
2684
  @@index([applicationId])
2539
2685
  @@index([phaseId])
2540
2686
  @@index([stepId])
2541
2687
  @@index([type])
2688
+ @@index([documentType])
2542
2689
  @@index([status])
2543
2690
  @@index([replacesDocumentId])
2544
2691
  @@map("application_documents")
@@ -2599,6 +2746,100 @@ model DocumentReview {
2599
2746
  @@map("document_reviews")
2600
2747
  }
2601
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
+
2602
2843
  // =============================================================================
2603
2844
  // OFFER LETTERS - Provisional and Final offer documents
2604
2845
  // =============================================================================