@valentine-efagene/qshelter-common 2.0.19 → 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 (52) 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/dist/src/config/config.service.d.ts +0 -1
  50. package/dist/src/config/config.service.js +0 -1
  51. package/package.json +2 -1
  52. package/prisma/schema.prisma +544 -269
@@ -6,8 +6,9 @@
6
6
  // =============================================================================
7
7
 
8
8
  generator client {
9
- provider = "prisma-client"
10
- output = "../generated/client"
9
+ provider = "prisma-client"
10
+ output = "../generated/client"
11
+ engineType = "client"
11
12
  }
12
13
 
13
14
  datasource db {
@@ -48,12 +49,15 @@ model User {
48
49
  socials Social[]
49
50
 
50
51
  // Relations to other domains
51
- properties Property[]
52
- mortgages Mortgage[] @relation("MortgageBorrower")
53
- paymentPlans PaymentPlan[]
54
- contracts Contract[] @relation("ContractBuyer")
55
- soldContracts Contract[] @relation("ContractSeller")
56
- 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")
57
61
 
58
62
  @@index([email])
59
63
  @@index([tenantId])
@@ -261,6 +265,10 @@ model Settings {
261
265
  // =============================================================================
262
266
  // PROPERTY DOMAIN
263
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
+ // =============================================================================
264
272
 
265
273
  model Property {
266
274
  id String @id @default(cuid())
@@ -268,21 +276,16 @@ model Property {
268
276
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
269
277
  title String
270
278
  category String // SALE, RENT, LEASE
271
- propertyType String // APARTMENT, HOUSE, LAND, COMMERCIAL
279
+ propertyType String // APARTMENT, HOUSE, LAND, COMMERCIAL, ESTATE, TOWNHOUSE
272
280
  country String
273
281
  currency String // USD, NGN, etc
274
282
  city String
275
283
  district String?
276
284
  zipCode String?
277
285
  streetAddress String?
278
- nBedrooms String
279
- nBathrooms String
280
- nParkingSpots String
281
- price Float
282
286
  longitude Float?
283
287
  latitude Float?
284
- area Float?
285
- status String @default("DRAFT") // DRAFT, PUBLISHED, SOLD, RENTED
288
+ status String @default("DRAFT") // DRAFT, PUBLISHED, SOLD_OUT, ARCHIVED
286
289
  description String? @db.Text
287
290
  displayImageId String?
288
291
  displayImage PropertyMedia? @relation("DisplayImage", fields: [displayImageId], references: [id], onDelete: SetNull)
@@ -291,17 +294,18 @@ model Property {
291
294
  createdAt DateTime @default(now())
292
295
  updatedAt DateTime @updatedAt
293
296
 
294
- documents PropertyDocument[]
295
- media PropertyMedia[] @relation("PropertyMedia")
296
- amenities PropertyAmenity[]
297
- mortgages Mortgage[]
298
- paymentPlans PaymentPlan[]
299
- 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[]
300
303
 
301
304
  @@index([userId])
302
305
  @@index([category])
303
306
  @@index([propertyType])
304
307
  @@index([city])
308
+ @@index([status])
305
309
  @@map("properties")
306
310
  }
307
311
 
@@ -337,15 +341,134 @@ model PropertyDocument {
337
341
  }
338
342
 
339
343
  model Amenity {
340
- id String @id @default(cuid())
341
- name String @unique
342
- createdAt DateTime @default(now())
343
- 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
344
350
  properties PropertyAmenity[]
351
+ variants PropertyVariantAmenity[]
345
352
 
353
+ @@index([category])
346
354
  @@map("amenities")
347
355
  }
348
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
+
349
472
  model PropertyAmenity {
350
473
  propertyId String
351
474
  amenityId String
@@ -358,305 +481,457 @@ model PropertyAmenity {
358
481
  }
359
482
 
360
483
  // =============================================================================
361
- // MORTGAGE DOMAIN
484
+ // PAYMENT PLAN DOMAIN - Reusable installment structure templates
362
485
  // =============================================================================
363
486
 
364
- model Mortgage {
365
- id String @id @default(cuid())
366
- propertyId String
367
- property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
368
- borrowerId String
369
- borrower User @relation("MortgageBorrower", fields: [borrowerId], references: [id], onDelete: Cascade)
370
- mortgageTypeId String?
371
- mortgageType MortgageType? @relation(fields: [mortgageTypeId], references: [id])
372
- downpaymentPlanId String?
373
- downpaymentPlan MortgageDownpaymentPlan? @relation(fields: [downpaymentPlanId], references: [id])
374
- principal Float
375
- downPayment Float
376
- downPaymentPaid Float @default(0)
377
- termMonths Int
378
- interestRate Float
379
- monthlyPayment Float
380
- status String @default("DRAFT") // DRAFT, PENDING, ACTIVE, COMPLETED, CANCELLED
381
- state String @default("DRAFT") // FSM state
382
- stateMetadata String? @db.Text // JSON metadata
383
- lastReminderSentAt DateTime?
384
- createdAt DateTime @default(now())
385
- 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)
386
501
 
387
- documents MortgageDocument[]
388
- steps MortgageStep[]
389
- transitions MortgageTransition[]
390
- transitionEvents MortgageTransitionEvent[]
502
+ createdAt DateTime @default(now())
503
+ updatedAt DateTime @updatedAt
391
504
 
392
- @@index([propertyId])
393
- @@index([borrowerId])
394
- @@index([status])
395
- @@index([state])
396
- @@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")
397
511
  }
398
512
 
399
- model MortgageType {
400
- id String @id @default(cuid())
401
- name String @unique
402
- description String? @db.Text
403
- createdAt DateTime @default(now())
404
- updatedAt DateTime @updatedAt
405
- mortgages Mortgage[]
513
+ // =============================================================================
514
+ // PROPERTY PAYMENT METHOD DOMAIN - Product offerings per property
515
+ // =============================================================================
406
516
 
407
- @@map("mortgage_types")
408
- }
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)
409
523
 
410
- model MortgageDocument {
411
- id String @id @default(cuid())
412
- mortgageId String
413
- mortgage Mortgage @relation(fields: [mortgageId], references: [id], onDelete: Cascade)
414
- name String
415
- url String
416
- type String // INCOME_PROOF, ID, etc
417
- createdAt DateTime @default(now())
418
- 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)
419
529
 
420
- @@index([mortgageId])
421
- @@map("mortgage_documents")
422
- }
530
+ createdAt DateTime @default(now())
531
+ updatedAt DateTime @updatedAt
423
532
 
424
- model MortgageStep {
425
- id String @id @default(cuid())
426
- mortgageId String
427
- mortgage Mortgage @relation(fields: [mortgageId], references: [id], onDelete: Cascade)
428
- name String
429
- description String? @db.Text
430
- order Int
431
- isCompleted Boolean @default(false)
432
- completedAt DateTime?
433
- createdAt DateTime @default(now())
434
- 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[]
435
539
 
436
- @@index([mortgageId])
437
- @@map("mortgage_steps")
540
+ @@map("property_payment_methods")
438
541
  }
439
542
 
440
- model MortgageDownpaymentPlan {
441
- id String @id @default(cuid())
442
- totalAmount Float
443
- paidAmount Float @default(0)
444
- status String @default("PENDING") // PENDING, ACTIVE, COMPLETED
445
- startDate DateTime
446
- endDate DateTime
447
- createdAt DateTime @default(now())
448
- 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)
449
549
 
450
- mortgages Mortgage[]
451
- installments MortgageDownpaymentInstallment[]
452
- payments MortgageDownpaymentPayment[]
550
+ // Method-specific overrides for this property
551
+ isDefault Boolean @default(false)
552
+ isActive Boolean @default(true)
553
+ createdAt DateTime @default(now())
453
554
 
454
- @@map("mortgage_downpayment_plans")
555
+ @@id([propertyId, paymentMethodId])
556
+ @@map("property_payment_method_links")
455
557
  }
456
558
 
457
- model MortgageDownpaymentInstallment {
458
- id String @id @default(cuid())
459
- planId String
460
- plan MortgageDownpaymentPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
461
- amount Float
462
- dueDate DateTime
463
- isPaid Boolean @default(false)
464
- paidDate DateTime?
465
- createdAt DateTime @default(now())
466
- 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])
467
567
 
468
- @@index([planId])
469
- @@map("mortgage_downpayment_installments")
470
- }
568
+ name String
569
+ description String? @db.Text
471
570
 
472
- model MortgageDownpaymentPayment {
473
- id String @id @default(cuid())
474
- planId String
475
- plan MortgageDownpaymentPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
476
- amount Float
477
- paymentMethod String
478
- reference String?
479
- status String @default("PENDING")
480
- createdAt DateTime @default(now())
481
- 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
482
575
 
483
- @@index([planId])
484
- @@map("mortgage_downpayment_payments")
485
- }
576
+ // Financial configuration (for PAYMENT phases)
577
+ interestRate Float?
578
+ percentOfPrice Float? // e.g., 10.0 for 10% downpayment
486
579
 
487
- model MortgageTransition {
488
- id String @id @default(cuid())
489
- mortgageId String
490
- mortgage Mortgage @relation(fields: [mortgageId], references: [id], onDelete: Cascade)
491
- fromState String
492
- toState String
493
- trigger String
494
- metadata String? @db.Text // JSON
495
- transitionedAt DateTime @default(now())
580
+ // Activation rules
581
+ requiresPreviousPhaseCompletion Boolean @default(true)
582
+ minimumCompletionPercentage Float?
496
583
 
497
- @@index([mortgageId])
498
- @@map("mortgage_transitions")
499
- }
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}]
500
587
 
501
- model MortgageTransitionEvent {
502
- id String @id @default(cuid())
503
- mortgageId String
504
- mortgage Mortgage @relation(fields: [mortgageId], references: [id], onDelete: Cascade)
505
- event String
506
- data String? @db.Text // JSON
507
- createdAt DateTime @default(now())
588
+ createdAt DateTime @default(now())
589
+ updatedAt DateTime @updatedAt
508
590
 
509
- @@index([mortgageId])
510
- @@map("mortgage_transition_events")
591
+ @@index([paymentMethodId])
592
+ @@index([paymentPlanId])
593
+ @@index([phaseCategory])
594
+ @@map("property_payment_method_phases")
511
595
  }
512
596
 
513
597
  // =============================================================================
514
- // 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).
515
603
  // =============================================================================
516
604
 
517
- model PaymentPlan {
518
- id String @id @default(cuid())
519
- propertyId String
520
- property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
521
- buyerId String?
522
- buyer User? @relation(fields: [buyerId], references: [id])
523
- planType String // MORTGAGE, INSTALLMENT, RENT_TO_OWN, LEASE, OUTRIGHT_PURCHASE, CUSTOM
524
- name String
525
- description String? @db.Text
526
- totalAmount Float
527
- downPaymentAmount Float @default(0)
528
- downPaymentPaid Float @default(0)
529
- principalAmount Float
530
- interestRate Float @default(0)
531
- totalInterest Float @default(0)
532
- state String @default("DRAFT") // FSM state
533
- stateMetadata String? @db.Text
534
- createdAt DateTime @default(now())
535
- updatedAt DateTime @updatedAt
536
-
537
- contract Contract?
538
- schedules PaymentSchedule[]
539
- payments Payment[]
540
-
541
- @@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])
542
657
  @@index([buyerId])
658
+ @@index([sellerId])
659
+ @@index([paymentMethodId])
660
+ @@index([status])
543
661
  @@index([state])
544
- @@map("payment_plans")
662
+ @@map("contracts")
545
663
  }
546
664
 
547
- model PaymentSchedule {
548
- id String @id @default(cuid())
549
- planId String
550
- plan PaymentPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
551
- name String
552
- frequency String // MONTHLY, WEEKLY, QUARTERLY, CUSTOM
553
- startDate DateTime
554
- endDate DateTime?
555
- isActive Boolean @default(true)
556
- createdAt DateTime @default(now())
557
- 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())
558
765
 
559
- installments PaymentInstallment[]
560
- payments Payment[]
766
+ createdAt DateTime @default(now())
561
767
 
562
- @@index([planId])
563
- @@map("payment_schedules")
768
+ @@index([stepId])
769
+ @@map("contract_phase_step_approvals")
564
770
  }
565
771
 
566
- model PaymentInstallment {
567
- id String @id @default(cuid())
568
- scheduleId String
569
- 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
+
570
778
  installmentNumber Int
571
- amount Float
572
- principalAmount Float
573
- interestAmount Float
574
- dueDate DateTime
575
- status String @default("PENDING") // PENDING, PAID, OVERDUE, WAIVED
576
- paidAmount Float @default(0)
577
- paidDate DateTime?
578
- lateFee Float @default(0)
579
- createdAt DateTime @default(now())
580
- updatedAt DateTime @updatedAt
581
-
582
- payments Payment[]
583
-
584
- @@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])
585
801
  @@index([dueDate])
586
802
  @@index([status])
587
- @@map("payment_installments")
588
- }
589
-
590
- model Payment {
591
- id String @id @default(cuid())
592
- planId String
593
- plan PaymentPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
594
- scheduleId String?
595
- schedule PaymentSchedule? @relation(fields: [scheduleId], references: [id])
596
- installmentId String?
597
- installment PaymentInstallment? @relation(fields: [installmentId], references: [id])
598
- payerId String?
599
- 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
+
600
818
  amount Float
601
- principalAmount Float @default(0)
602
- interestAmount Float @default(0)
603
- lateFeeAmount Float @default(0)
604
- paymentMethod String // BANK_TRANSFER, CREDIT_CARD, WALLET, etc
605
- status String @default("INITIATED") // INITIATED, PENDING, PROCESSING, COMPLETED, FAILED, CANCELLED, REFUNDED
606
- reference String? @unique
607
- gatewayResponse String? @db.Text // JSON
608
- processedAt DateTime?
609
- createdAt DateTime @default(now())
610
- updatedAt DateTime @updatedAt
611
-
612
- @@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])
613
836
  @@index([payerId])
614
837
  @@index([status])
615
838
  @@index([reference])
616
- @@map("payments")
839
+ @@map("contract_payments")
617
840
  }
618
841
 
619
- model Contract {
620
- id String @id @default(cuid())
621
- propertyId String
622
- property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)
623
- paymentPlanId String? @unique
624
- paymentPlan PaymentPlan? @relation(fields: [paymentPlanId], references: [id])
625
- buyerId String?
626
- buyer User? @relation("ContractBuyer", fields: [buyerId], references: [id])
627
- sellerId String?
628
- seller User? @relation("ContractSeller", fields: [sellerId], references: [id])
629
- contractType String // MORTGAGE, SALE_AGREEMENT, LEASE_AGREEMENT, etc
630
- contractNumber String @unique
631
- title String
632
- description String? @db.Text
633
- status String @default("DRAFT") // DRAFT, PENDING_SIGNATURE, ACTIVE, COMPLETED, TERMINATED
634
- startDate DateTime?
635
- endDate DateTime?
636
- signedAt DateTime?
637
- terminatedAt DateTime?
638
- createdAt DateTime @default(now())
639
- 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
640
849
 
641
- 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])
642
855
 
643
- @@index([propertyId])
644
- @@index([buyerId])
645
- @@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])
646
865
  @@index([status])
647
- @@map("contracts")
866
+ @@map("contract_documents")
648
867
  }
649
868
 
650
- 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 {
651
886
  id String @id @default(cuid())
652
887
  contractId String
653
888
  contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
654
- name String
655
- url String
656
- type String
889
+ event String
890
+ data String? @db.Text // JSON
657
891
  createdAt DateTime @default(now())
658
- updatedAt DateTime @updatedAt
659
892
 
660
893
  @@index([contractId])
661
- @@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")
662
937
  }