@valentine-efagene/qshelter-common 2.0.21 → 2.0.22

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 (50) hide show
  1. package/dist/generated/client/browser.d.ts +45 -30
  2. package/dist/generated/client/client.d.ts +45 -30
  3. package/dist/generated/client/commonInputTypes.d.ts +40 -0
  4. package/dist/generated/client/internal/class.d.ts +93 -60
  5. package/dist/generated/client/internal/class.js +2 -2
  6. package/dist/generated/client/internal/prismaNamespace.d.ts +1050 -720
  7. package/dist/generated/client/internal/prismaNamespace.js +313 -190
  8. package/dist/generated/client/internal/prismaNamespaceBrowser.d.ts +344 -215
  9. package/dist/generated/client/internal/prismaNamespaceBrowser.js +313 -190
  10. package/dist/generated/client/models/Amenity.d.ts +168 -1
  11. package/dist/generated/client/models/Contract.d.ts +2037 -298
  12. package/dist/generated/client/models/ContractDocument.d.ts +299 -12
  13. package/dist/generated/client/models/ContractEvent.d.ts +1052 -0
  14. package/dist/generated/client/models/ContractEvent.js +1 -0
  15. package/dist/generated/client/models/ContractInstallment.d.ts +1656 -0
  16. package/dist/generated/client/models/ContractInstallment.js +1 -0
  17. package/dist/generated/client/models/ContractPayment.d.ts +2026 -0
  18. package/dist/generated/client/models/ContractPayment.js +1 -0
  19. package/dist/generated/client/models/ContractPhase.d.ts +2467 -0
  20. package/dist/generated/client/models/ContractPhase.js +1 -0
  21. package/dist/generated/client/models/ContractPhaseStep.d.ts +1678 -0
  22. package/dist/generated/client/models/ContractPhaseStep.js +1 -0
  23. package/dist/generated/client/models/ContractPhaseStepApproval.d.ts +1249 -0
  24. package/dist/generated/client/models/ContractPhaseStepApproval.js +1 -0
  25. package/dist/generated/client/models/ContractTransition.d.ts +1118 -0
  26. package/dist/generated/client/models/ContractTransition.js +1 -0
  27. package/dist/generated/client/models/DomainEvent.d.ts +1240 -0
  28. package/dist/generated/client/models/DomainEvent.js +1 -0
  29. package/dist/generated/client/models/PaymentPlan.d.ts +325 -1062
  30. package/dist/generated/client/models/Property.d.ts +154 -684
  31. package/dist/generated/client/models/PropertyPaymentMethod.d.ts +1498 -0
  32. package/dist/generated/client/models/PropertyPaymentMethod.js +1 -0
  33. package/dist/generated/client/models/PropertyPaymentMethodLink.d.ts +1158 -0
  34. package/dist/generated/client/models/PropertyPaymentMethodLink.js +1 -0
  35. package/dist/generated/client/models/PropertyPaymentMethodPhase.d.ts +1656 -0
  36. package/dist/generated/client/models/PropertyPaymentMethodPhase.js +1 -0
  37. package/dist/generated/client/models/PropertyUnit.d.ts +1598 -0
  38. package/dist/generated/client/models/PropertyUnit.js +1 -0
  39. package/dist/generated/client/models/PropertyVariant.d.ts +2079 -0
  40. package/dist/generated/client/models/PropertyVariant.js +1 -0
  41. package/dist/generated/client/models/PropertyVariantAmenity.d.ts +1080 -0
  42. package/dist/generated/client/models/PropertyVariantAmenity.js +1 -0
  43. package/dist/generated/client/models/PropertyVariantMedia.d.ts +1189 -0
  44. package/dist/generated/client/models/PropertyVariantMedia.js +1 -0
  45. package/dist/generated/client/models/User.d.ts +684 -427
  46. package/dist/generated/client/models/index.d.ts +15 -12
  47. package/dist/generated/client/models/index.js +15 -12
  48. package/dist/generated/client/models.d.ts +15 -12
  49. package/package.json +1 -1
  50. package/prisma/schema.prisma +541 -267
@@ -49,12 +49,15 @@ model User {
49
49
  socials Social[]
50
50
 
51
51
  // Relations to other domains
52
- properties Property[]
53
- mortgages Mortgage[] @relation("MortgageBorrower")
54
- paymentPlans PaymentPlan[]
55
- contracts Contract[] @relation("ContractBuyer")
56
- soldContracts Contract[] @relation("ContractSeller")
57
- payments Payment[]
52
+ properties Property[]
53
+ contracts Contract[] @relation("ContractBuyer")
54
+ soldContracts Contract[] @relation("ContractSeller")
55
+ contractPayments ContractPayment[] @relation("ContractPayer")
56
+
57
+ // Phase step assignments and approvals
58
+ assignedSteps ContractPhaseStep[] @relation("PhaseStepAssignee")
59
+ stepApprovals ContractPhaseStepApproval[] @relation("PhaseStepApprover")
60
+ uploadedDocs ContractDocument[] @relation("DocumentUploader")
58
61
 
59
62
  @@index([email])
60
63
  @@index([tenantId])
@@ -262,6 +265,10 @@ model Settings {
262
265
  // =============================================================================
263
266
  // PROPERTY DOMAIN
264
267
  // =============================================================================
268
+ // Property = listing/project (e.g., "Sunrise Estate")
269
+ // PropertyVariant = configuration with specs & price (e.g., "3-Bed Corner - Finished")
270
+ // PropertyUnit = individual sellable unit (e.g., "Unit A1")
271
+ // =============================================================================
265
272
 
266
273
  model Property {
267
274
  id String @id @default(cuid())
@@ -269,21 +276,16 @@ model Property {
269
276
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
270
277
  title String
271
278
  category String // SALE, RENT, LEASE
272
- propertyType String // APARTMENT, HOUSE, LAND, COMMERCIAL
279
+ propertyType String // APARTMENT, HOUSE, LAND, COMMERCIAL, ESTATE, TOWNHOUSE
273
280
  country String
274
281
  currency String // USD, NGN, etc
275
282
  city String
276
283
  district String?
277
284
  zipCode String?
278
285
  streetAddress String?
279
- nBedrooms String
280
- nBathrooms String
281
- nParkingSpots String
282
- price Float
283
286
  longitude Float?
284
287
  latitude Float?
285
- area Float?
286
- status String @default("DRAFT") // DRAFT, PUBLISHED, SOLD, RENTED
288
+ status String @default("DRAFT") // DRAFT, PUBLISHED, SOLD_OUT, ARCHIVED
287
289
  description String? @db.Text
288
290
  displayImageId String?
289
291
  displayImage PropertyMedia? @relation("DisplayImage", fields: [displayImageId], references: [id], onDelete: SetNull)
@@ -292,17 +294,18 @@ model Property {
292
294
  createdAt DateTime @default(now())
293
295
  updatedAt DateTime @updatedAt
294
296
 
295
- documents PropertyDocument[]
296
- media PropertyMedia[] @relation("PropertyMedia")
297
- amenities PropertyAmenity[]
298
- mortgages Mortgage[]
299
- paymentPlans PaymentPlan[]
300
- contracts Contract[]
297
+ // Relations
298
+ documents PropertyDocument[]
299
+ media PropertyMedia[] @relation("PropertyMedia")
300
+ amenities PropertyAmenity[] // Shared amenities (gym, pool, security)
301
+ paymentMethods PropertyPaymentMethodLink[]
302
+ variants PropertyVariant[]
301
303
 
302
304
  @@index([userId])
303
305
  @@index([category])
304
306
  @@index([propertyType])
305
307
  @@index([city])
308
+ @@index([status])
306
309
  @@map("properties")
307
310
  }
308
311
 
@@ -338,15 +341,134 @@ model PropertyDocument {
338
341
  }
339
342
 
340
343
  model Amenity {
341
- id String @id @default(cuid())
342
- name String @unique
343
- createdAt DateTime @default(now())
344
- updatedAt DateTime @updatedAt
344
+ id String @id @default(cuid())
345
+ name String @unique
346
+ category String? // PROPERTY, VARIANT, BOTH - helps filter which amenities to show
347
+ icon String? // Icon name/URL for UI
348
+ createdAt DateTime @default(now())
349
+ updatedAt DateTime @updatedAt
345
350
  properties PropertyAmenity[]
351
+ variants PropertyVariantAmenity[]
346
352
 
353
+ @@index([category])
347
354
  @@map("amenities")
348
355
  }
349
356
 
357
+ // =============================================================================
358
+ // PROPERTY VARIANT & UNIT MODELS
359
+ // =============================================================================
360
+
361
+ // PropertyVariant = specific configuration with its own price and amenities
362
+ // e.g., "3-Bedroom Corner Piece - Fully Finished", "2-Bedroom Standard - Carcass"
363
+ model PropertyVariant {
364
+ id String @id @default(cuid())
365
+ propertyId String
366
+ property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
367
+
368
+ name String // "Corner Piece - Finished", "Standard - Carcass"
369
+ description String? @db.Text
370
+
371
+ // Specifications
372
+ nBedrooms Int?
373
+ nBathrooms Int?
374
+ nParkingSpots Int?
375
+ area Float? // Square meters/feet
376
+
377
+ // Pricing
378
+ price Float
379
+ pricePerSqm Float? // Computed or set manually
380
+
381
+ // Inventory counters (denormalized for performance, updated via triggers/service)
382
+ totalUnits Int @default(1)
383
+ availableUnits Int @default(1)
384
+ reservedUnits Int @default(0)
385
+ soldUnits Int @default(0)
386
+
387
+ // Status
388
+ status String @default("AVAILABLE") // AVAILABLE, LOW_STOCK, SOLD_OUT, ARCHIVED
389
+ isActive Boolean @default(true)
390
+ createdAt DateTime @default(now())
391
+ updatedAt DateTime @updatedAt
392
+
393
+ // Relations
394
+ amenities PropertyVariantAmenity[]
395
+ units PropertyUnit[]
396
+ media PropertyVariantMedia[]
397
+
398
+ @@index([propertyId])
399
+ @@index([status])
400
+ @@index([price])
401
+ @@map("property_variants")
402
+ }
403
+
404
+ // PropertyVariantAmenity = amenities specific to a variant
405
+ // e.g., "Finished Kitchen", "Smart Home System", "Private Garden"
406
+ model PropertyVariantAmenity {
407
+ variantId String
408
+ amenityId String
409
+ variant PropertyVariant @relation(fields: [variantId], references: [id], onDelete: Cascade)
410
+ amenity Amenity @relation(fields: [amenityId], references: [id], onDelete: Cascade)
411
+ createdAt DateTime @default(now())
412
+
413
+ @@id([variantId, amenityId])
414
+ @@map("property_variant_amenities")
415
+ }
416
+
417
+ // PropertyVariantMedia = images/videos specific to a variant
418
+ model PropertyVariantMedia {
419
+ id String @id @default(cuid())
420
+ variantId String
421
+ variant PropertyVariant @relation(fields: [variantId], references: [id], onDelete: Cascade)
422
+ url String
423
+ type String // IMAGE, VIDEO, FLOOR_PLAN, 3D_TOUR
424
+ caption String?
425
+ order Int @default(0)
426
+ createdAt DateTime @default(now())
427
+ updatedAt DateTime @updatedAt
428
+
429
+ @@index([variantId])
430
+ @@map("property_variant_media")
431
+ }
432
+
433
+ // PropertyUnit = individual sellable/rentable unit within a variant
434
+ // e.g., "Unit A1", "Block B - Flat 3", "Plot 15"
435
+ model PropertyUnit {
436
+ id String @id @default(cuid())
437
+ variantId String
438
+ variant PropertyVariant @relation(fields: [variantId], references: [id], onDelete: Cascade)
439
+
440
+ unitNumber String // "A1", "B-3", "Plot 15"
441
+ floorNumber Int? // For apartments
442
+ blockName String? // "Block A", "Tower 1"
443
+
444
+ // Unit-specific overrides (if different from variant)
445
+ priceOverride Float? // If this specific unit has a different price
446
+ areaOverride Float? // If this specific unit has a different area
447
+ notes String? @db.Text // Internal notes about this unit
448
+
449
+ // Status tracking
450
+ status String @default("AVAILABLE") // AVAILABLE, RESERVED, SOLD, RENTED, UNAVAILABLE
451
+
452
+ // Reservation/hold
453
+ reservedAt DateTime?
454
+ reservedUntil DateTime?
455
+ reservedById String?
456
+
457
+ // Ownership tracking (once sold)
458
+ ownerId String?
459
+
460
+ createdAt DateTime @default(now())
461
+ updatedAt DateTime @updatedAt
462
+
463
+ // Relations
464
+ contracts Contract[]
465
+
466
+ @@unique([variantId, unitNumber])
467
+ @@index([variantId])
468
+ @@index([status])
469
+ @@map("property_units")
470
+ }
471
+
350
472
  model PropertyAmenity {
351
473
  propertyId String
352
474
  amenityId String
@@ -359,305 +481,457 @@ model PropertyAmenity {
359
481
  }
360
482
 
361
483
  // =============================================================================
362
- // MORTGAGE DOMAIN
484
+ // PAYMENT PLAN DOMAIN - Reusable installment structure templates
363
485
  // =============================================================================
364
486
 
365
- model Mortgage {
366
- id String @id @default(cuid())
367
- propertyId String
368
- property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
369
- borrowerId String
370
- borrower User @relation("MortgageBorrower", fields: [borrowerId], references: [id], onDelete: Cascade)
371
- mortgageTypeId String?
372
- mortgageType MortgageType? @relation(fields: [mortgageTypeId], references: [id])
373
- downpaymentPlanId String?
374
- downpaymentPlan MortgageDownpaymentPlan? @relation(fields: [downpaymentPlanId], references: [id])
375
- principal Float
376
- downPayment Float
377
- downPaymentPaid Float @default(0)
378
- termMonths Int
379
- interestRate Float
380
- monthlyPayment Float
381
- status String @default("DRAFT") // DRAFT, PENDING, ACTIVE, COMPLETED, CANCELLED
382
- state String @default("DRAFT") // FSM state
383
- stateMetadata String? @db.Text // JSON metadata
384
- lastReminderSentAt DateTime?
385
- createdAt DateTime @default(now())
386
- updatedAt DateTime @updatedAt
487
+ // PaymentPlan = reusable structure for how payments are scheduled
488
+ // Examples: "Monthly360" (360 monthly payments), "Weekly52", "OneTime"
489
+ model PaymentPlan {
490
+ id String @id @default(cuid())
491
+ name String @unique
492
+ description String? @db.Text
493
+ isActive Boolean @default(true)
494
+
495
+ // Structure configuration
496
+ paymentFrequency String // MONTHLY, BIWEEKLY, WEEKLY, ONE_TIME, CUSTOM
497
+ customFrequencyDays Int?
498
+ numberOfInstallments Int // 1 for one-time, 360 for 30yr monthly, etc
499
+ calculateInterestDaily Boolean @default(false)
500
+ gracePeriodDays Int @default(0)
387
501
 
388
- documents MortgageDocument[]
389
- steps MortgageStep[]
390
- transitions MortgageTransition[]
391
- transitionEvents MortgageTransitionEvent[]
502
+ createdAt DateTime @default(now())
503
+ updatedAt DateTime @updatedAt
392
504
 
393
- @@index([propertyId])
394
- @@index([borrowerId])
395
- @@index([status])
396
- @@index([state])
397
- @@map("mortgages")
505
+ // Used by property payment method phases (templates)
506
+ methodPhases PropertyPaymentMethodPhase[]
507
+ // Used by instantiated contract phases
508
+ contractPhases ContractPhase[]
509
+
510
+ @@map("payment_plans")
398
511
  }
399
512
 
400
- model MortgageType {
401
- id String @id @default(cuid())
402
- name String @unique
403
- description String? @db.Text
404
- createdAt DateTime @default(now())
405
- updatedAt DateTime @updatedAt
406
- mortgages Mortgage[]
513
+ // =============================================================================
514
+ // PROPERTY PAYMENT METHOD DOMAIN - Product offerings per property
515
+ // =============================================================================
407
516
 
408
- @@map("mortgage_types")
409
- }
517
+ // PropertyPaymentMethod = how a property can be purchased (e.g., "Standard Mortgage", "Cash", "Rent-to-Own")
518
+ model PropertyPaymentMethod {
519
+ id String @id @default(cuid())
520
+ name String // "Standard Mortgage", "Flexible Payment", "Cash Purchase"
521
+ description String? @db.Text
522
+ isActive Boolean @default(true)
410
523
 
411
- model MortgageDocument {
412
- id String @id @default(cuid())
413
- mortgageId String
414
- mortgage Mortgage @relation(fields: [mortgageId], references: [id], onDelete: Cascade)
415
- name String
416
- url String
417
- type String // INCOME_PROOF, ID, etc
418
- createdAt DateTime @default(now())
419
- updatedAt DateTime @updatedAt
524
+ // Global method configuration
525
+ allowEarlyPayoff Boolean @default(true)
526
+ earlyPayoffPenaltyRate Float?
527
+ autoActivatePhases Boolean @default(true)
528
+ requiresManualApproval Boolean @default(false)
420
529
 
421
- @@index([mortgageId])
422
- @@map("mortgage_documents")
423
- }
530
+ createdAt DateTime @default(now())
531
+ updatedAt DateTime @updatedAt
424
532
 
425
- model MortgageStep {
426
- id String @id @default(cuid())
427
- mortgageId String
428
- mortgage Mortgage @relation(fields: [mortgageId], references: [id], onDelete: Cascade)
429
- name String
430
- description String? @db.Text
431
- order Int
432
- isCompleted Boolean @default(false)
433
- completedAt DateTime?
434
- createdAt DateTime @default(now())
435
- updatedAt DateTime @updatedAt
533
+ // Many-to-many with properties
534
+ properties PropertyPaymentMethodLink[]
535
+ // Phases that make up this method (templates)
536
+ phases PropertyPaymentMethodPhase[]
537
+ // Contracts using this method
538
+ contracts Contract[]
436
539
 
437
- @@index([mortgageId])
438
- @@map("mortgage_steps")
540
+ @@map("property_payment_methods")
439
541
  }
440
542
 
441
- model MortgageDownpaymentPlan {
442
- id String @id @default(cuid())
443
- totalAmount Float
444
- paidAmount Float @default(0)
445
- status String @default("PENDING") // PENDING, ACTIVE, COMPLETED
446
- startDate DateTime
447
- endDate DateTime
448
- createdAt DateTime @default(now())
449
- updatedAt DateTime @updatedAt
543
+ // Many-to-many link between Property and PaymentMethod
544
+ model PropertyPaymentMethodLink {
545
+ propertyId String
546
+ property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
547
+ paymentMethodId String
548
+ paymentMethod PropertyPaymentMethod @relation(fields: [paymentMethodId], references: [id], onDelete: Cascade)
450
549
 
451
- mortgages Mortgage[]
452
- installments MortgageDownpaymentInstallment[]
453
- payments MortgageDownpaymentPayment[]
550
+ // Method-specific overrides for this property
551
+ isDefault Boolean @default(false)
552
+ isActive Boolean @default(true)
553
+ createdAt DateTime @default(now())
454
554
 
455
- @@map("mortgage_downpayment_plans")
555
+ @@id([propertyId, paymentMethodId])
556
+ @@map("property_payment_method_links")
456
557
  }
457
558
 
458
- model MortgageDownpaymentInstallment {
459
- id String @id @default(cuid())
460
- planId String
461
- plan MortgageDownpaymentPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
462
- amount Float
463
- dueDate DateTime
464
- isPaid Boolean @default(false)
465
- paidDate DateTime?
466
- createdAt DateTime @default(now())
467
- updatedAt DateTime @updatedAt
559
+ // Phase template within a PropertyPaymentMethod (e.g., documentation, downpayment, mortgage)
560
+ // phaseCategory determines the FSM type: DOCUMENTATION or PAYMENT
561
+ model PropertyPaymentMethodPhase {
562
+ id String @id @default(cuid())
563
+ paymentMethodId String
564
+ paymentMethod PropertyPaymentMethod @relation(fields: [paymentMethodId], references: [id], onDelete: Cascade)
565
+ paymentPlanId String? // Only for PAYMENT phases
566
+ paymentPlan PaymentPlan? @relation(fields: [paymentPlanId], references: [id])
468
567
 
469
- @@index([planId])
470
- @@map("mortgage_downpayment_installments")
471
- }
568
+ name String
569
+ description String? @db.Text
472
570
 
473
- model MortgageDownpaymentPayment {
474
- id String @id @default(cuid())
475
- planId String
476
- plan MortgageDownpaymentPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
477
- amount Float
478
- paymentMethod String
479
- reference String?
480
- status String @default("PENDING")
481
- createdAt DateTime @default(now())
482
- updatedAt DateTime @updatedAt
571
+ // Phase classification
572
+ phaseCategory String // DOCUMENTATION, PAYMENT
573
+ phaseType String // Admin-defined: KYC, VERIFICATION, DOWNPAYMENT, MORTGAGE, BALLOON, CUSTOM, etc.
574
+ order Int
483
575
 
484
- @@index([planId])
485
- @@map("mortgage_downpayment_payments")
486
- }
576
+ // Financial configuration (for PAYMENT phases)
577
+ interestRate Float?
578
+ percentOfPrice Float? // e.g., 10.0 for 10% downpayment
487
579
 
488
- model MortgageTransition {
489
- id String @id @default(cuid())
490
- mortgageId String
491
- mortgage Mortgage @relation(fields: [mortgageId], references: [id], onDelete: Cascade)
492
- fromState String
493
- toState String
494
- trigger String
495
- metadata String? @db.Text // JSON
496
- transitionedAt DateTime @default(now())
580
+ // Activation rules
581
+ requiresPreviousPhaseCompletion Boolean @default(true)
582
+ minimumCompletionPercentage Float?
497
583
 
498
- @@index([mortgageId])
499
- @@map("mortgage_transitions")
500
- }
584
+ // For DOCUMENTATION phases: define required steps
585
+ requiredDocumentTypes String? // CSV: ID,BANK_STATEMENT,INCOME_PROOF
586
+ stepDefinitions String? @db.Text // JSON: [{name, stepType, order}]
501
587
 
502
- model MortgageTransitionEvent {
503
- id String @id @default(cuid())
504
- mortgageId String
505
- mortgage Mortgage @relation(fields: [mortgageId], references: [id], onDelete: Cascade)
506
- event String
507
- data String? @db.Text // JSON
508
- createdAt DateTime @default(now())
588
+ createdAt DateTime @default(now())
589
+ updatedAt DateTime @updatedAt
509
590
 
510
- @@index([mortgageId])
511
- @@map("mortgage_transition_events")
591
+ @@index([paymentMethodId])
592
+ @@index([paymentPlanId])
593
+ @@index([phaseCategory])
594
+ @@map("property_payment_method_phases")
512
595
  }
513
596
 
514
597
  // =============================================================================
515
- // PAYMENT & CONTRACT DOMAIN
598
+ // CONTRACT DOMAIN - Unified agreement model (replaces Mortgage, PurchasePlan, etc.)
599
+ // =============================================================================
600
+ // Contract is the canonical agreement. "Mortgage" is just a product configuration
601
+ // that creates a Contract with specific phases (documentation, downpayment, long-term payment).
602
+ // Phases can be DOCUMENTATION (FSM for approvals) or PAYMENT (PaymentPlan-driven installments).
516
603
  // =============================================================================
517
604
 
518
- model PaymentPlan {
519
- id String @id @default(cuid())
520
- propertyId String
521
- property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
522
- buyerId String?
523
- buyer User? @relation(fields: [buyerId], references: [id])
524
- planType String // MORTGAGE, INSTALLMENT, RENT_TO_OWN, LEASE, OUTRIGHT_PURCHASE, CUSTOM
525
- name String
526
- description String? @db.Text
527
- totalAmount Float
528
- downPaymentAmount Float @default(0)
529
- downPaymentPaid Float @default(0)
530
- principalAmount Float
531
- interestRate Float @default(0)
532
- totalInterest Float @default(0)
533
- state String @default("DRAFT") // FSM state
534
- stateMetadata String? @db.Text
535
- createdAt DateTime @default(now())
536
- updatedAt DateTime @updatedAt
537
-
538
- contract Contract?
539
- schedules PaymentSchedule[]
540
- payments Payment[]
541
-
542
- @@index([propertyId])
605
+ model Contract {
606
+ id String @id @default(cuid())
607
+ // Link to specific unit being purchased/rented
608
+ propertyUnitId String
609
+ propertyUnit PropertyUnit @relation(fields: [propertyUnitId], references: [id], onDelete: Cascade)
610
+ buyerId String
611
+ buyer User @relation("ContractBuyer", fields: [buyerId], references: [id], onDelete: Cascade)
612
+ sellerId String?
613
+ seller User? @relation("ContractSeller", fields: [sellerId], references: [id])
614
+ paymentMethodId String? // PropertyPaymentMethod used to create this contract
615
+ paymentMethod PropertyPaymentMethod? @relation(fields: [paymentMethodId], references: [id])
616
+
617
+ // Contract identification
618
+ contractNumber String @unique
619
+ title String
620
+ description String? @db.Text
621
+ contractType String // Admin-defined: MORTGAGE, INSTALLMENT, RENT_TO_OWN, CASH, LEASE, etc.
622
+
623
+ // Financial summary (computed from phases)
624
+ totalAmount Float // Total contract value (from unit price or negotiated)
625
+ downPayment Float @default(0)
626
+ downPaymentPaid Float @default(0)
627
+ principal Float? // Financed amount (if applicable)
628
+ interestRate Float? // Overall interest rate (if applicable)
629
+ termMonths Int? // Total term (if applicable)
630
+ periodicPayment Float? // Computed periodic payment (if applicable)
631
+ totalPaidToDate Float @default(0)
632
+ totalInterestPaid Float @default(0)
633
+
634
+ // FSM state
635
+ status String @default("DRAFT") // DRAFT, PENDING, ACTIVE, COMPLETED, CANCELLED, TERMINATED
636
+ state String @default("DRAFT") // FSM state for workflow
637
+ currentPhaseId String?
638
+
639
+ // Timing
640
+ nextPaymentDueDate DateTime?
641
+ lastReminderSentAt DateTime?
642
+ startDate DateTime?
643
+ endDate DateTime?
644
+ signedAt DateTime?
645
+ terminatedAt DateTime?
646
+ createdAt DateTime @default(now())
647
+ updatedAt DateTime @updatedAt
648
+
649
+ // Relations
650
+ phases ContractPhase[]
651
+ documents ContractDocument[]
652
+ payments ContractPayment[]
653
+ transitions ContractTransition[]
654
+ events ContractEvent[]
655
+
656
+ @@index([propertyUnitId])
543
657
  @@index([buyerId])
658
+ @@index([sellerId])
659
+ @@index([paymentMethodId])
660
+ @@index([status])
544
661
  @@index([state])
545
- @@map("payment_plans")
662
+ @@map("contracts")
546
663
  }
547
664
 
548
- model PaymentSchedule {
549
- id String @id @default(cuid())
550
- planId String
551
- plan PaymentPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
552
- name String
553
- frequency String // MONTHLY, WEEKLY, QUARTERLY, CUSTOM
554
- startDate DateTime
555
- endDate DateTime?
556
- isActive Boolean @default(true)
557
- createdAt DateTime @default(now())
558
- updatedAt DateTime @updatedAt
665
+ // Phase within a contract - can be DOCUMENTATION or PAYMENT type
666
+ // Admin names phases freely (e.g., "KYC Documents", "Downpayment", "Monthly Mortgage")
667
+ model ContractPhase {
668
+ id String @id @default(cuid())
669
+ contractId String
670
+ contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
671
+ paymentPlanId String? // Only for PAYMENT phases
672
+ paymentPlan PaymentPlan? @relation(fields: [paymentPlanId], references: [id])
673
+
674
+ // Admin-defined naming
675
+ name String
676
+ description String? @db.Text
677
+
678
+ // Phase classification
679
+ phaseCategory String // DOCUMENTATION, PAYMENT
680
+ phaseType String // Admin-defined: DOWNPAYMENT, MORTGAGE, KYC, VERIFICATION, BALLOON, CUSTOM, etc.
681
+ order Int
682
+
683
+ // FSM state for this phase
684
+ status String @default("PENDING") // PENDING, IN_PROGRESS, AWAITING_APPROVAL, ACTIVE, COMPLETED, SKIPPED, FAILED
685
+
686
+ // Financial details (for PAYMENT phases)
687
+ totalAmount Float?
688
+ paidAmount Float @default(0)
689
+ remainingAmount Float?
690
+ interestRate Float?
691
+
692
+ // Timing
693
+ dueDate DateTime?
694
+ startDate DateTime?
695
+ endDate DateTime?
696
+ activatedAt DateTime?
697
+ completedAt DateTime?
698
+
699
+ // Activation rules
700
+ requiresPreviousPhaseCompletion Boolean @default(true)
701
+ minimumCompletionPercentage Float?
702
+
703
+ createdAt DateTime @default(now())
704
+ updatedAt DateTime @updatedAt
705
+
706
+ // Relations
707
+ installments ContractInstallment[]
708
+ payments ContractPayment[]
709
+ steps ContractPhaseStep[] // For DOCUMENTATION phases (FSM steps)
710
+
711
+ @@index([contractId])
712
+ @@index([paymentPlanId])
713
+ @@index([phaseCategory])
714
+ @@index([status])
715
+ @@index([order])
716
+ @@map("contract_phases")
717
+ }
718
+
719
+ // Steps within a DOCUMENTATION phase (FSM for document collection/approval)
720
+ model ContractPhaseStep {
721
+ id String @id @default(cuid())
722
+ phaseId String
723
+ phase ContractPhase @relation(fields: [phaseId], references: [id], onDelete: Cascade)
724
+
725
+ name String
726
+ description String? @db.Text
727
+ stepType String // UPLOAD, REVIEW, SIGNATURE, APPROVAL, EXTERNAL_CHECK, WAIT
728
+ order Int
729
+
730
+ status String @default("PENDING") // PENDING, IN_PROGRESS, COMPLETED, FAILED, SKIPPED
731
+
732
+ // Assignment
733
+ assigneeId String?
734
+ assignee User? @relation("PhaseStepAssignee", fields: [assigneeId], references: [id])
735
+
736
+ // Required document types for UPLOAD steps
737
+ requiredDocumentTypes String? // CSV: ID,BANK_STATEMENT,INCOME_PROOF
738
+
739
+ // Timing
740
+ dueDate DateTime?
741
+ completedAt DateTime?
742
+
743
+ createdAt DateTime @default(now())
744
+ updatedAt DateTime @updatedAt
745
+
746
+ approvals ContractPhaseStepApproval[]
747
+
748
+ @@index([phaseId])
749
+ @@index([status])
750
+ @@index([order])
751
+ @@map("contract_phase_steps")
752
+ }
753
+
754
+ // Approvals for documentation steps
755
+ model ContractPhaseStepApproval {
756
+ id String @id @default(cuid())
757
+ stepId String
758
+ step ContractPhaseStep @relation(fields: [stepId], references: [id], onDelete: Cascade)
759
+ approverId String?
760
+ approver User? @relation("PhaseStepApprover", fields: [approverId], references: [id])
761
+
762
+ decision String // APPROVED, REJECTED, REQUEST_CHANGES
763
+ comment String? @db.Text
764
+ decidedAt DateTime @default(now())
559
765
 
560
- installments PaymentInstallment[]
561
- payments Payment[]
766
+ createdAt DateTime @default(now())
562
767
 
563
- @@index([planId])
564
- @@map("payment_schedules")
768
+ @@index([stepId])
769
+ @@map("contract_phase_step_approvals")
565
770
  }
566
771
 
567
- model PaymentInstallment {
568
- id String @id @default(cuid())
569
- scheduleId String
570
- schedule PaymentSchedule @relation(fields: [scheduleId], references: [id], onDelete: Cascade)
772
+ // Installments within a PAYMENT phase
773
+ model ContractInstallment {
774
+ id String @id @default(cuid())
775
+ phaseId String
776
+ phase ContractPhase @relation(fields: [phaseId], references: [id], onDelete: Cascade)
777
+
571
778
  installmentNumber Int
572
- amount Float
573
- principalAmount Float
574
- interestAmount Float
575
- dueDate DateTime
576
- status String @default("PENDING") // PENDING, PAID, OVERDUE, WAIVED
577
- paidAmount Float @default(0)
578
- paidDate DateTime?
579
- lateFee Float @default(0)
580
- createdAt DateTime @default(now())
581
- updatedAt DateTime @updatedAt
582
-
583
- payments Payment[]
584
-
585
- @@index([scheduleId])
779
+
780
+ amount Float
781
+ principalAmount Float @default(0)
782
+ interestAmount Float @default(0)
783
+
784
+ dueDate DateTime
785
+ status String @default("PENDING") // PENDING, PAID, OVERDUE, PARTIALLY_PAID, WAIVED
786
+
787
+ paidAmount Float @default(0)
788
+ paidDate DateTime?
789
+
790
+ lateFee Float @default(0)
791
+ lateFeeWaived Boolean @default(false)
792
+ gracePeriodDays Int @default(0)
793
+ gracePeriodEndDate DateTime?
794
+
795
+ createdAt DateTime @default(now())
796
+ updatedAt DateTime @updatedAt
797
+
798
+ payments ContractPayment[]
799
+
800
+ @@index([phaseId])
586
801
  @@index([dueDate])
587
802
  @@index([status])
588
- @@map("payment_installments")
589
- }
590
-
591
- model Payment {
592
- id String @id @default(cuid())
593
- planId String
594
- plan PaymentPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
595
- scheduleId String?
596
- schedule PaymentSchedule? @relation(fields: [scheduleId], references: [id])
597
- installmentId String?
598
- installment PaymentInstallment? @relation(fields: [installmentId], references: [id])
599
- payerId String?
600
- payer User? @relation(fields: [payerId], references: [id])
803
+ @@map("contract_installments")
804
+ }
805
+
806
+ // Unified payment record for contracts
807
+ model ContractPayment {
808
+ id String @id @default(cuid())
809
+ contractId String
810
+ contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
811
+ phaseId String?
812
+ phase ContractPhase? @relation(fields: [phaseId], references: [id])
813
+ installmentId String?
814
+ installment ContractInstallment? @relation(fields: [installmentId], references: [id])
815
+ payerId String?
816
+ payer User? @relation("ContractPayer", fields: [payerId], references: [id])
817
+
601
818
  amount Float
602
- principalAmount Float @default(0)
603
- interestAmount Float @default(0)
604
- lateFeeAmount Float @default(0)
605
- paymentMethod String // BANK_TRANSFER, CREDIT_CARD, WALLET, etc
606
- status String @default("INITIATED") // INITIATED, PENDING, PROCESSING, COMPLETED, FAILED, CANCELLED, REFUNDED
607
- reference String? @unique
608
- gatewayResponse String? @db.Text // JSON
609
- processedAt DateTime?
610
- createdAt DateTime @default(now())
611
- updatedAt DateTime @updatedAt
612
-
613
- @@index([planId])
819
+ principalAmount Float @default(0)
820
+ interestAmount Float @default(0)
821
+ lateFeeAmount Float @default(0)
822
+
823
+ paymentMethod String // BANK_TRANSFER, CREDIT_CARD, WALLET, CASH, CHECK
824
+ status String @default("INITIATED") // INITIATED, PENDING, COMPLETED, FAILED, REFUNDED
825
+
826
+ reference String? @unique
827
+ gatewayResponse String? @db.Text // JSON
828
+
829
+ processedAt DateTime?
830
+ createdAt DateTime @default(now())
831
+ updatedAt DateTime @updatedAt
832
+
833
+ @@index([contractId])
834
+ @@index([phaseId])
835
+ @@index([installmentId])
614
836
  @@index([payerId])
615
837
  @@index([status])
616
838
  @@index([reference])
617
- @@map("payments")
839
+ @@map("contract_payments")
618
840
  }
619
841
 
620
- model Contract {
621
- id String @id @default(cuid())
622
- propertyId String
623
- property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
624
- paymentPlanId String? @unique
625
- paymentPlan PaymentPlan? @relation(fields: [paymentPlanId], references: [id])
626
- buyerId String?
627
- buyer User? @relation("ContractBuyer", fields: [buyerId], references: [id])
628
- sellerId String?
629
- seller User? @relation("ContractSeller", fields: [sellerId], references: [id])
630
- contractType String // MORTGAGE, SALE_AGREEMENT, LEASE_AGREEMENT, etc
631
- contractNumber String @unique
632
- title String
633
- description String? @db.Text
634
- status String @default("DRAFT") // DRAFT, PENDING_SIGNATURE, ACTIVE, COMPLETED, TERMINATED
635
- startDate DateTime?
636
- endDate DateTime?
637
- signedAt DateTime?
638
- terminatedAt DateTime?
639
- createdAt DateTime @default(now())
640
- updatedAt DateTime @updatedAt
842
+ // Contract documents (owned by contract, linked to phases/steps as needed)
843
+ model ContractDocument {
844
+ id String @id @default(cuid())
845
+ contractId String
846
+ contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
847
+ phaseId String? // Optional link to specific phase
848
+ stepId String? // Optional link to specific step
641
849
 
642
- documents ContractDocument[]
850
+ name String
851
+ url String
852
+ type String // ID, BANK_STATEMENT, INCOME_PROOF, TITLE_DEED, SIGNATURE, etc.
853
+ uploadedById String?
854
+ uploadedBy User? @relation("DocumentUploader", fields: [uploadedById], references: [id])
643
855
 
644
- @@index([propertyId])
645
- @@index([buyerId])
646
- @@index([sellerId])
856
+ status String @default("PENDING") // PENDING, APPROVED, REJECTED
857
+
858
+ createdAt DateTime @default(now())
859
+ updatedAt DateTime @updatedAt
860
+
861
+ @@index([contractId])
862
+ @@index([phaseId])
863
+ @@index([stepId])
864
+ @@index([type])
647
865
  @@index([status])
648
- @@map("contracts")
866
+ @@map("contract_documents")
649
867
  }
650
868
 
651
- model ContractDocument {
869
+ // FSM transitions for audit
870
+ model ContractTransition {
871
+ id String @id @default(cuid())
872
+ contractId String
873
+ contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
874
+ fromState String
875
+ toState String
876
+ trigger String
877
+ metadata String? @db.Text // JSON
878
+ transitionedAt DateTime @default(now())
879
+
880
+ @@index([contractId])
881
+ @@map("contract_transitions")
882
+ }
883
+
884
+ // Domain events for audit and integration
885
+ model ContractEvent {
652
886
  id String @id @default(cuid())
653
887
  contractId String
654
888
  contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
655
- name String
656
- url String
657
- type String
889
+ event String
890
+ data String? @db.Text // JSON
658
891
  createdAt DateTime @default(now())
659
- updatedAt DateTime @updatedAt
660
892
 
661
893
  @@index([contractId])
662
- @@map("contract_documents")
894
+ @@map("contract_events")
895
+ }
896
+
897
+ // =============================================================================
898
+ // EVENT OUTBOX - For guaranteed event delivery to SQS queues
899
+ // =============================================================================
900
+
901
+ model DomainEvent {
902
+ id String @id @default(cuid())
903
+
904
+ // Event identification
905
+ eventType String // MORTGAGE.CREATED, PHASE.ACTIVATED, PAYMENT.COMPLETED, etc
906
+ aggregateType String // Mortgage, MortgagePhase, MortgagePayment, Property, etc
907
+ aggregateId String
908
+
909
+ // Routing - which queue(s) should receive this
910
+ queueName String // notifications, payments, mortgage-steps, accounting, etc
911
+
912
+ // Event payload (all data needed by consumers)
913
+ payload String @db.Text // JSON
914
+
915
+ // Metadata
916
+ occurredAt DateTime @default(now())
917
+ actorId String? // User who triggered the event
918
+ actorRole String? // Role of the actor
919
+
920
+ // Processing status
921
+ status String @default("PENDING") // PENDING, PROCESSING, SENT, FAILED
922
+ processedAt DateTime?
923
+ sentAt DateTime?
924
+ failureCount Int @default(0)
925
+ lastError String? @db.Text
926
+ nextRetryAt DateTime?
927
+
928
+ createdAt DateTime @default(now())
929
+ updatedAt DateTime @updatedAt
930
+
931
+ @@index([status, nextRetryAt])
932
+ @@index([eventType])
933
+ @@index([aggregateType, aggregateId])
934
+ @@index([queueName])
935
+ @@index([occurredAt])
936
+ @@map("domain_events")
663
937
  }