@valentine-efagene/qshelter-common 2.0.40 → 2.0.42

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.
@@ -42,6 +42,7 @@ export * from './Settings';
42
42
  export * from './Social';
43
43
  export * from './Tenant';
44
44
  export * from './Transaction';
45
+ export * from './UnderwritingDecision';
45
46
  export * from './User';
46
47
  export * from './UserRole';
47
48
  export * from './UserSuspension';
@@ -42,6 +42,7 @@ export * from './Settings';
42
42
  export * from './Social';
43
43
  export * from './Tenant';
44
44
  export * from './Transaction';
45
+ export * from './UnderwritingDecision';
45
46
  export * from './User';
46
47
  export * from './UserRole';
47
48
  export * from './UserSuspension';
@@ -43,6 +43,7 @@ export type * from './models/DocumentTemplate.js';
43
43
  export type * from './models/OfferLetter.js';
44
44
  export type * from './models/ContractTermination.js';
45
45
  export type * from './models/Prequalification.js';
46
+ export type * from './models/UnderwritingDecision.js';
46
47
  export type * from './models/PaymentMethodChangeRequest.js';
47
48
  export type * from './models/DocumentRequirementRule.js';
48
49
  export type * from './models/DomainEvent.js';
@@ -26,6 +26,9 @@ export declare enum NotificationType {
26
26
  OFFER_LETTER_SENT = "offerLetterSent",
27
27
  OFFER_LETTER_SIGNED = "offerLetterSigned",
28
28
  OFFER_LETTER_EXPIRED = "offerLetterExpired",
29
+ UNDERWRITING_APPROVED = "underwritingApproved",
30
+ UNDERWRITING_REJECTED = "underwritingRejected",
31
+ UNDERWRITING_CONDITIONAL = "underwritingConditional",
29
32
  ADMIN_CONTRIBUTION_RECEIVED = "adminContributionReceived",
30
33
  ADMIN_PROPERTY_ALLOCATION = "adminPropertyAllocation",
31
34
  ADMIN_INVITE = "adminInviteAdmin",
@@ -34,6 +34,10 @@ export var NotificationType;
34
34
  NotificationType["OFFER_LETTER_SENT"] = "offerLetterSent";
35
35
  NotificationType["OFFER_LETTER_SIGNED"] = "offerLetterSigned";
36
36
  NotificationType["OFFER_LETTER_EXPIRED"] = "offerLetterExpired";
37
+ // Underwriting
38
+ NotificationType["UNDERWRITING_APPROVED"] = "underwritingApproved";
39
+ NotificationType["UNDERWRITING_REJECTED"] = "underwritingRejected";
40
+ NotificationType["UNDERWRITING_CONDITIONAL"] = "underwritingConditional";
37
41
  // Admin
38
42
  NotificationType["ADMIN_CONTRIBUTION_RECEIVED"] = "adminContributionReceived";
39
43
  NotificationType["ADMIN_PROPERTY_ALLOCATION"] = "adminPropertyAllocation";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valentine-efagene/qshelter-common",
3
- "version": "2.0.40",
3
+ "version": "2.0.42",
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,77 @@
1
+ -- AlterTable
2
+ ALTER TABLE `contract_documents` MODIFY `status` ENUM('DRAFT', 'PENDING', 'PENDING_SIGNATURE', 'SENT', 'VIEWED', 'SIGNED', 'APPROVED', 'REJECTED', 'EXPIRED', 'CANCELLED') NOT NULL DEFAULT 'PENDING';
3
+
4
+ -- CreateTable
5
+ CREATE TABLE `document_templates` (
6
+ `id` VARCHAR(191) NOT NULL,
7
+ `tenantId` VARCHAR(191) NOT NULL,
8
+ `name` VARCHAR(191) NOT NULL,
9
+ `code` VARCHAR(191) NOT NULL,
10
+ `description` VARCHAR(191) NULL,
11
+ `version` INTEGER NOT NULL DEFAULT 1,
12
+ `htmlTemplate` TEXT NOT NULL,
13
+ `cssStyles` TEXT NULL,
14
+ `mergeFields` JSON NULL,
15
+ `isActive` BOOLEAN NOT NULL DEFAULT true,
16
+ `isDefault` BOOLEAN NOT NULL DEFAULT false,
17
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
18
+ `updatedAt` DATETIME(3) NOT NULL,
19
+
20
+ INDEX `document_templates_tenantId_idx`(`tenantId`),
21
+ INDEX `document_templates_code_idx`(`code`),
22
+ UNIQUE INDEX `document_templates_tenantId_code_version_key`(`tenantId`, `code`, `version`),
23
+ PRIMARY KEY (`id`)
24
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
25
+
26
+ -- CreateTable
27
+ CREATE TABLE `offer_letters` (
28
+ `id` VARCHAR(191) NOT NULL,
29
+ `tenantId` VARCHAR(191) NOT NULL,
30
+ `contractId` VARCHAR(191) NOT NULL,
31
+ `templateId` VARCHAR(191) NOT NULL,
32
+ `letterNumber` VARCHAR(191) NOT NULL,
33
+ `type` ENUM('PROVISIONAL', 'FINAL') NOT NULL,
34
+ `status` ENUM('DRAFT', 'GENERATED', 'SENT', 'VIEWED', 'SIGNED', 'EXPIRED', 'CANCELLED') NOT NULL DEFAULT 'DRAFT',
35
+ `htmlContent` TEXT NULL,
36
+ `pdfUrl` VARCHAR(191) NULL,
37
+ `pdfKey` VARCHAR(191) NULL,
38
+ `mergeData` JSON NULL,
39
+ `sentAt` DATETIME(3) NULL,
40
+ `viewedAt` DATETIME(3) NULL,
41
+ `signedAt` DATETIME(3) NULL,
42
+ `signatureIp` VARCHAR(191) NULL,
43
+ `signatureData` JSON NULL,
44
+ `expiresAt` DATETIME(3) NULL,
45
+ `expiredAt` DATETIME(3) NULL,
46
+ `cancelledAt` DATETIME(3) NULL,
47
+ `cancelReason` VARCHAR(191) NULL,
48
+ `generatedById` VARCHAR(191) NULL,
49
+ `sentById` VARCHAR(191) NULL,
50
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
51
+ `updatedAt` DATETIME(3) NOT NULL,
52
+
53
+ UNIQUE INDEX `offer_letters_letterNumber_key`(`letterNumber`),
54
+ INDEX `offer_letters_tenantId_idx`(`tenantId`),
55
+ INDEX `offer_letters_contractId_idx`(`contractId`),
56
+ INDEX `offer_letters_type_idx`(`type`),
57
+ INDEX `offer_letters_status_idx`(`status`),
58
+ PRIMARY KEY (`id`)
59
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
60
+
61
+ -- AddForeignKey
62
+ ALTER TABLE `document_templates` ADD CONSTRAINT `document_templates_tenantId_fkey` FOREIGN KEY (`tenantId`) REFERENCES `tenants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
63
+
64
+ -- AddForeignKey
65
+ ALTER TABLE `offer_letters` ADD CONSTRAINT `offer_letters_tenantId_fkey` FOREIGN KEY (`tenantId`) REFERENCES `tenants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
66
+
67
+ -- AddForeignKey
68
+ ALTER TABLE `offer_letters` ADD CONSTRAINT `offer_letters_contractId_fkey` FOREIGN KEY (`contractId`) REFERENCES `contracts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
69
+
70
+ -- AddForeignKey
71
+ ALTER TABLE `offer_letters` ADD CONSTRAINT `offer_letters_templateId_fkey` FOREIGN KEY (`templateId`) REFERENCES `document_templates`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
72
+
73
+ -- AddForeignKey
74
+ ALTER TABLE `offer_letters` ADD CONSTRAINT `offer_letters_generatedById_fkey` FOREIGN KEY (`generatedById`) REFERENCES `users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
75
+
76
+ -- AddForeignKey
77
+ ALTER TABLE `offer_letters` ADD CONSTRAINT `offer_letters_sentById_fkey` FOREIGN KEY (`sentById`) REFERENCES `users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
@@ -0,0 +1,31 @@
1
+ -- CreateTable
2
+ CREATE TABLE `underwriting_decisions` (
3
+ `id` VARCHAR(191) NOT NULL,
4
+ `tenantId` VARCHAR(191) NOT NULL,
5
+ `prequalificationId` VARCHAR(191) NOT NULL,
6
+ `decision` ENUM('APPROVE', 'REJECT', 'CONDITIONAL') NOT NULL,
7
+ `score` DOUBLE NULL,
8
+ `reasons` JSON NULL,
9
+ `conditions` JSON NULL,
10
+ `rulesVersion` VARCHAR(191) NULL,
11
+ `ruleResults` JSON NULL,
12
+ `externalChecks` JSON NULL,
13
+ `isManualReview` BOOLEAN NOT NULL DEFAULT false,
14
+ `reviewedBy` VARCHAR(191) NULL,
15
+ `reviewedAt` DATETIME(3) NULL,
16
+ `reviewNotes` TEXT NULL,
17
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
18
+ `updatedAt` DATETIME(3) NOT NULL,
19
+
20
+ INDEX `underwriting_decisions_tenantId_idx`(`tenantId`),
21
+ INDEX `underwriting_decisions_prequalificationId_idx`(`prequalificationId`),
22
+ INDEX `underwriting_decisions_decision_idx`(`decision`),
23
+ INDEX `underwriting_decisions_createdAt_idx`(`createdAt`),
24
+ PRIMARY KEY (`id`)
25
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
26
+
27
+ -- AddForeignKey
28
+ ALTER TABLE `underwriting_decisions` ADD CONSTRAINT `underwriting_decisions_tenantId_fkey` FOREIGN KEY (`tenantId`) REFERENCES `tenants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
29
+
30
+ -- AddForeignKey
31
+ ALTER TABLE `underwriting_decisions` ADD CONSTRAINT `underwriting_decisions_prequalificationId_fkey` FOREIGN KEY (`prequalificationId`) REFERENCES `prequalifications`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -178,6 +178,12 @@ enum OfferLetterStatus {
178
178
  CANCELLED
179
179
  }
180
180
 
181
+ enum UnderwritingDecisionKind {
182
+ APPROVE
183
+ REJECT
184
+ CONDITIONAL
185
+ }
186
+
181
187
  // =============================================================================
182
188
  // USER & AUTH DOMAIN
183
189
  // =============================================================================
@@ -316,6 +322,9 @@ model Tenant {
316
322
  documentTemplates DocumentTemplate[]
317
323
  offerLetters OfferLetter[]
318
324
 
325
+ // Underwriting
326
+ underwritingDecisions UnderwritingDecision[]
327
+
319
328
  @@index([subdomain])
320
329
  @@map("tenants")
321
330
  }
@@ -1218,10 +1227,10 @@ model DocumentTemplate {
1218
1227
  name String // "Provisional Offer Letter", "Final Offer Letter"
1219
1228
  code String // PROVISIONAL_OFFER, FINAL_OFFER
1220
1229
  description String?
1221
- version Int @default(1)
1230
+ version Int @default(1)
1222
1231
 
1223
1232
  // Template content (Handlebars)
1224
- htmlTemplate String @db.Text
1233
+ htmlTemplate String @db.Text
1225
1234
  cssStyles String? @db.Text
1226
1235
 
1227
1236
  // Merge field definitions for UI
@@ -1242,9 +1251,9 @@ model DocumentTemplate {
1242
1251
  }
1243
1252
 
1244
1253
  model OfferLetter {
1245
- id String @id @default(cuid())
1254
+ id String @id @default(cuid())
1246
1255
  tenantId String
1247
- tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1256
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1248
1257
  contractId String
1249
1258
  contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
1250
1259
 
@@ -1253,29 +1262,29 @@ model OfferLetter {
1253
1262
  template DocumentTemplate @relation(fields: [templateId], references: [id])
1254
1263
 
1255
1264
  // Letter details
1256
- letterNumber String @unique // OL-XXXXXX
1265
+ letterNumber String @unique // OL-XXXXXX
1257
1266
  type OfferLetterType
1258
1267
  status OfferLetterStatus @default(DRAFT)
1259
1268
 
1260
1269
  // Generated document
1261
- htmlContent String? @db.Text // Rendered HTML
1262
- pdfUrl String? // S3 URL of generated PDF
1263
- pdfKey String? // S3 key for deletion/access
1270
+ htmlContent String? @db.Text // Rendered HTML
1271
+ pdfUrl String? // S3 URL of generated PDF
1272
+ pdfKey String? // S3 key for deletion/access
1264
1273
 
1265
1274
  // Merge data used (snapshot for audit)
1266
1275
  mergeData Json? // All data merged into template
1267
1276
 
1268
1277
  // Signing workflow
1269
- sentAt DateTime?
1270
- viewedAt DateTime?
1271
- signedAt DateTime?
1272
- signatureIp String?
1278
+ sentAt DateTime?
1279
+ viewedAt DateTime?
1280
+ signedAt DateTime?
1281
+ signatureIp String?
1273
1282
  signatureData Json? // {method, timestamp, metadata}
1274
1283
 
1275
1284
  // Validity
1276
- expiresAt DateTime?
1277
- expiredAt DateTime?
1278
- cancelledAt DateTime?
1285
+ expiresAt DateTime?
1286
+ expiredAt DateTime?
1287
+ cancelledAt DateTime?
1279
1288
  cancelReason String?
1280
1289
 
1281
1290
  // Audit
@@ -1439,6 +1448,9 @@ model Prequalification {
1439
1448
  contractId String? @unique
1440
1449
  contract Contract? @relation(fields: [contractId], references: [id])
1441
1450
 
1451
+ // Underwriting decisions for this prequalification
1452
+ underwritingDecisions UnderwritingDecision[]
1453
+
1442
1454
  createdAt DateTime @default(now())
1443
1455
  updatedAt DateTime @updatedAt
1444
1456
 
@@ -1449,6 +1461,54 @@ model Prequalification {
1449
1461
  @@map("prequalifications")
1450
1462
  }
1451
1463
 
1464
+ // =============================================================================
1465
+ // UNDERWRITING DECISION - Automated/manual credit decisions
1466
+ // =============================================================================
1467
+ // Records each underwriting decision for a prequalification. Multiple decisions
1468
+ // may exist if re-evaluation occurs (e.g., after document submission).
1469
+ // =============================================================================
1470
+
1471
+ model UnderwritingDecision {
1472
+ id String @id @default(cuid())
1473
+ tenantId String
1474
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1475
+
1476
+ // Link to prequalification being evaluated
1477
+ prequalificationId String
1478
+ prequalification Prequalification @relation(fields: [prequalificationId], references: [id], onDelete: Cascade)
1479
+
1480
+ // Decision outcome
1481
+ decision UnderwritingDecisionKind
1482
+
1483
+ // Scoring and rationale
1484
+ score Float? // Computed risk score (0-100)
1485
+ reasons Json? // Array of reason codes/messages for decision
1486
+ conditions Json? // Array of conditions for CONDITIONAL decisions
1487
+
1488
+ // Rule engine metadata
1489
+ rulesVersion String? // Version of rules/model used
1490
+ ruleResults Json? // Detailed rule evaluation results
1491
+
1492
+ // External data references (credit bureau, verifications)
1493
+ externalChecks Json? // { creditBureau: {...}, incomeVerification: {...} }
1494
+
1495
+ // Manual review (if escalated)
1496
+ isManualReview Boolean @default(false)
1497
+ reviewedBy String? // Admin who reviewed
1498
+ reviewedAt DateTime?
1499
+ reviewNotes String? @db.Text
1500
+
1501
+ // Audit
1502
+ createdAt DateTime @default(now())
1503
+ updatedAt DateTime @updatedAt
1504
+
1505
+ @@index([tenantId])
1506
+ @@index([prequalificationId])
1507
+ @@index([decision])
1508
+ @@index([createdAt])
1509
+ @@map("underwriting_decisions")
1510
+ }
1511
+
1452
1512
  // =============================================================================
1453
1513
  // PAYMENT METHOD CHANGE REQUEST - Mid-contract payment method changes
1454
1514
  // =============================================================================