@valentine-efagene/qshelter-common 2.0.103 → 2.0.104

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.
@@ -49,6 +49,8 @@ export * from './PropertyVariantAmenity';
49
49
  export * from './PropertyVariantMedia';
50
50
  export * from './QuestionnaireField';
51
51
  export * from './QuestionnairePhase';
52
+ export * from './QuestionnairePlan';
53
+ export * from './QuestionnairePlanQuestion';
52
54
  export * from './RefreshToken';
53
55
  export * from './Role';
54
56
  export * from './RolePermission';
@@ -49,6 +49,8 @@ export * from './PropertyVariantAmenity';
49
49
  export * from './PropertyVariantMedia';
50
50
  export * from './QuestionnaireField';
51
51
  export * from './QuestionnairePhase';
52
+ export * from './QuestionnairePlan';
53
+ export * from './QuestionnairePlanQuestion';
52
54
  export * from './RefreshToken';
53
55
  export * from './Role';
54
56
  export * from './RolePermission';
@@ -27,6 +27,8 @@ export type * from './models/PropertyUnit.js';
27
27
  export type * from './models/PropertyAmenity.js';
28
28
  export type * from './models/DocumentationPlan.js';
29
29
  export type * from './models/DocumentationPlanStep.js';
30
+ export type * from './models/QuestionnairePlan.js';
31
+ export type * from './models/QuestionnairePlanQuestion.js';
30
32
  export type * from './models/PaymentPlan.js';
31
33
  export type * from './models/PropertyPaymentMethod.js';
32
34
  export type * from './models/PropertyPaymentMethodLink.js';
@@ -30,6 +30,8 @@ const OPTIONAL_TENANT_MODELS = [
30
30
  "paymentPlan",
31
31
  // DocumentationPlan can be global template (tenantId = null) or tenant-specific
32
32
  "documentationPlan",
33
+ // QuestionnairePlan can be global template (tenantId = null) or tenant-specific
34
+ "questionnairePlan",
33
35
  // Role can be global template (tenantId = null) or tenant-specific
34
36
  "role",
35
37
  // Permission can be global template or tenant-specific
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valentine-efagene/qshelter-common",
3
- "version": "2.0.103",
3
+ "version": "2.0.104",
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",
@@ -567,6 +567,7 @@ model Tenant {
567
567
  settings Settings[]
568
568
  domainEvents DomainEvent[]
569
569
  workflowBlockers WorkflowBlocker[]
570
+ questionnairePlans QuestionnairePlan[]
570
571
 
571
572
  @@index([subdomain])
572
573
  @@map("tenants")
@@ -1077,6 +1078,91 @@ model DocumentationPlanStep {
1077
1078
  @@map("documentation_plan_steps")
1078
1079
  }
1079
1080
 
1081
+ // =============================================================================
1082
+ // QUESTIONNAIRE PLAN DOMAIN - Reusable form templates with scoring
1083
+ // =============================================================================
1084
+ // QuestionnairePlan = reusable structure for prequalification/screening forms
1085
+ // Examples: "Mortgage Prequalification", "Affordability Assessment", "Risk Screening"
1086
+ // =============================================================================
1087
+
1088
+ model QuestionnairePlan {
1089
+ id String @id @default(cuid())
1090
+ tenantId String? // NULL = global template available to all tenants
1091
+ tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1092
+ name String
1093
+ description String? @db.Text
1094
+ version Int @default(1)
1095
+ isActive Boolean @default(true)
1096
+
1097
+ // Scoring configuration
1098
+ passingScore Int? // Minimum score to pass (null = no auto-scoring)
1099
+ scoringStrategy ScoringStrategy @default(SUM)
1100
+ autoDecisionEnabled Boolean @default(false) // Auto-pass/fail based on score
1101
+
1102
+ // Metadata
1103
+ estimatedMinutes Int? // Estimated time to complete
1104
+ category QuestionnaireCategory @default(PREQUALIFICATION)
1105
+
1106
+ createdAt DateTime @default(now())
1107
+ updatedAt DateTime @updatedAt
1108
+
1109
+ // Questions that make up this plan
1110
+ questions QuestionnairePlanQuestion[]
1111
+
1112
+ // Used by property payment method phases (templates)
1113
+ methodPhases PropertyPaymentMethodPhase[]
1114
+
1115
+ // Used by instantiated questionnaire phases
1116
+ questionnairePhases QuestionnairePhase[]
1117
+
1118
+ @@unique([tenantId, name, version])
1119
+ @@index([tenantId])
1120
+ @@index([category])
1121
+ @@map("questionnaire_plans")
1122
+ }
1123
+
1124
+ // Question template within a QuestionnairePlan
1125
+ model QuestionnairePlanQuestion {
1126
+ id String @id @default(cuid())
1127
+ questionnairePlanId String
1128
+ questionnairePlan QuestionnairePlan @relation(fields: [questionnairePlanId], references: [id], onDelete: Cascade)
1129
+
1130
+ // Question identification
1131
+ questionKey String // Unique key for this question (e.g., "annual_income")
1132
+ questionText String @db.Text // The actual question text
1133
+ helpText String? @db.Text // Optional help/tooltip text
1134
+
1135
+ // Field configuration
1136
+ questionType QuestionType
1137
+ order Int
1138
+
1139
+ // Validation
1140
+ isRequired Boolean @default(true)
1141
+ validationRules Json? // { min: 0, max: 1000000, pattern: "^[0-9]+$" }
1142
+
1143
+ // Options for SELECT/MULTI_SELECT/RADIO
1144
+ // [{ value: "employed", label: "Employed", score: 10 }, ...]
1145
+ options Json?
1146
+
1147
+ // Scoring
1148
+ scoreWeight Int @default(1) // Multiplier for this question's score
1149
+ scoringRules Json? // { "employed": 10, "self_employed": 7, "unemployed": 0 } or ranges
1150
+
1151
+ // Conditional logic (branching)
1152
+ // { "questionKey": "employment_status", "equals": "employed" }
1153
+ showIf Json?
1154
+
1155
+ // Metadata for grouping
1156
+ category String? // Group questions (e.g., "income", "employment", "property")
1157
+
1158
+ createdAt DateTime @default(now())
1159
+ updatedAt DateTime @updatedAt
1160
+
1161
+ @@unique([questionnairePlanId, questionKey])
1162
+ @@index([questionnairePlanId])
1163
+ @@map("questionnaire_plan_questions")
1164
+ }
1165
+
1080
1166
  // =============================================================================
1081
1167
  // PAYMENT PLAN DOMAIN - Reusable installment structure templates
1082
1168
  // =============================================================================
@@ -1202,6 +1288,8 @@ model PropertyPaymentMethodPhase {
1202
1288
  paymentPlan PaymentPlan? @relation(fields: [paymentPlanId], references: [id])
1203
1289
  documentationPlanId String? // Only for DOCUMENTATION phases
1204
1290
  documentationPlan DocumentationPlan? @relation(fields: [documentationPlanId], references: [id])
1291
+ questionnairePlanId String? // Only for QUESTIONNAIRE phases
1292
+ questionnairePlan QuestionnairePlan? @relation(fields: [questionnairePlanId], references: [id])
1205
1293
 
1206
1294
  name String
1207
1295
  description String? @db.Text
@@ -1245,6 +1333,7 @@ model PropertyPaymentMethodPhase {
1245
1333
  @@index([paymentMethodId])
1246
1334
  @@index([paymentPlanId])
1247
1335
  @@index([documentationPlanId])
1336
+ @@index([questionnairePlanId])
1248
1337
  @@index([phaseCategory])
1249
1338
  @@map("property_payment_method_phases")
1250
1339
  }
@@ -1378,6 +1467,44 @@ enum FieldType {
1378
1467
  FILE // File upload (single)
1379
1468
  }
1380
1469
 
1470
+ // =============================================================================
1471
+ // QUESTIONNAIRE PLAN ENUMS - For scoring and categorization
1472
+ // =============================================================================
1473
+
1474
+ enum QuestionType {
1475
+ TEXT
1476
+ NUMBER
1477
+ CURRENCY
1478
+ DATE
1479
+ SELECT
1480
+ MULTI_SELECT
1481
+ RADIO
1482
+ CHECKBOX
1483
+ FILE_UPLOAD
1484
+ PHONE
1485
+ EMAIL
1486
+ ADDRESS
1487
+ PERCENTAGE
1488
+ YEARS_MONTHS
1489
+ }
1490
+
1491
+ enum ScoringStrategy {
1492
+ SUM // Add up all scores
1493
+ AVERAGE // Average of all scores
1494
+ WEIGHTED_SUM // Sum with weights (score * weight)
1495
+ MIN_ALL // Must meet minimum on all questions
1496
+ CUSTOM // Use custom scoring function
1497
+ }
1498
+
1499
+ enum QuestionnaireCategory {
1500
+ PREQUALIFICATION // Initial eligibility screening
1501
+ AFFORDABILITY // Income/expense assessment
1502
+ PROPERTY_INTENT // What property are they looking for
1503
+ RISK_ASSESSMENT // Credit/risk questions
1504
+ COMPLIANCE // KYC/AML questions
1505
+ CUSTOM
1506
+ }
1507
+
1381
1508
  // Questionnaire field template within a QUESTIONNAIRE phase
1382
1509
  model PaymentMethodPhaseField {
1383
1510
  id String @id @default(cuid())
@@ -1635,10 +1762,20 @@ model QuestionnairePhase {
1635
1762
  phaseId String @unique
1636
1763
  phase ApplicationPhase @relation(fields: [phaseId], references: [id], onDelete: Cascade)
1637
1764
 
1765
+ // Questionnaire plan reference (if created from a plan)
1766
+ questionnairePlanId String?
1767
+ questionnairePlan QuestionnairePlan? @relation(fields: [questionnairePlanId], references: [id])
1768
+
1638
1769
  // Progress tracking
1639
1770
  completedFieldsCount Int @default(0)
1640
1771
  totalFieldsCount Int @default(0)
1641
1772
 
1773
+ // Scoring results (from QuestionnairePlan scoring)
1774
+ totalScore Int?
1775
+ passingScore Int? // Copied from plan at creation
1776
+ passed Boolean?
1777
+ scoredAt DateTime?
1778
+
1642
1779
  // Computed results (for UNDERWRITING phases)
1643
1780
  underwritingScore Float?
1644
1781
  debtToIncomeRatio Float?
@@ -1656,6 +1793,7 @@ model QuestionnairePhase {
1656
1793
 
1657
1794
  @@index([tenantId])
1658
1795
  @@index([phaseId])
1796
+ @@index([questionnairePlanId])
1659
1797
  @@map("questionnaire_phases")
1660
1798
  }
1661
1799