@valentine-efagene/qshelter-common 2.0.150 → 2.0.152

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 (34) hide show
  1. package/dist/generated/client/browser.d.ts +13 -2
  2. package/dist/generated/client/client.d.ts +15 -4
  3. package/dist/generated/client/client.js +2 -2
  4. package/dist/generated/client/commonInputTypes.d.ts +50 -190
  5. package/dist/generated/client/enums.d.ts +7 -34
  6. package/dist/generated/client/enums.js +6 -30
  7. package/dist/generated/client/internal/class.d.ts +29 -7
  8. package/dist/generated/client/internal/class.js +2 -2
  9. package/dist/generated/client/internal/prismaNamespace.d.ts +185 -34
  10. package/dist/generated/client/internal/prismaNamespace.js +42 -13
  11. package/dist/generated/client/internal/prismaNamespaceBrowser.d.ts +46 -13
  12. package/dist/generated/client/internal/prismaNamespaceBrowser.js +42 -13
  13. package/dist/generated/client/models/ApplicationOrganization.d.ts +308 -67
  14. package/dist/generated/client/models/ApprovalStage.d.ts +210 -91
  15. package/dist/generated/client/models/ApprovalStageProgress.d.ts +258 -69
  16. package/dist/generated/client/models/DocumentApproval.d.ts +196 -65
  17. package/dist/generated/client/models/DocumentReview.d.ts +475 -86
  18. package/dist/generated/client/models/Organization.d.ts +424 -52
  19. package/dist/generated/client/models/OrganizationMember.d.ts +42 -169
  20. package/dist/generated/client/models/OrganizationType.d.ts +1982 -0
  21. package/dist/generated/client/models/OrganizationType.js +1 -0
  22. package/dist/generated/client/models/OrganizationTypeAssignment.d.ts +1159 -0
  23. package/dist/generated/client/models/OrganizationTypeAssignment.js +1 -0
  24. package/dist/generated/client/models/Property.d.ts +59 -120
  25. package/dist/generated/client/models/Tenant.d.ts +575 -4
  26. package/dist/generated/client/models/User.d.ts +0 -12
  27. package/dist/generated/client/models/index.d.ts +2 -0
  28. package/dist/generated/client/models/index.js +2 -0
  29. package/dist/generated/client/models.d.ts +2 -0
  30. package/package.json +1 -1
  31. package/prisma/migrations/20260125090213_remove_is_published_use_status_enum/migration.sql +10 -0
  32. package/prisma/migrations/20260125102448_org_types_many_to_many/migration.sql +153 -0
  33. package/prisma/migrations/20260125103700_20260125102448_org_types_many_to_many_fix/migration.sql +5 -0
  34. package/prisma/schema.prisma +121 -81
@@ -760,18 +760,6 @@ export type UserNullableScalarRelationFilter = {
760
760
  is?: Prisma.UserWhereInput | null;
761
761
  isNot?: Prisma.UserWhereInput | null;
762
762
  };
763
- export type StringFieldUpdateOperationsInput = {
764
- set?: string;
765
- };
766
- export type NullableStringFieldUpdateOperationsInput = {
767
- set?: string | null;
768
- };
769
- export type BoolFieldUpdateOperationsInput = {
770
- set?: boolean;
771
- };
772
- export type DateTimeFieldUpdateOperationsInput = {
773
- set?: Date | string;
774
- };
775
763
  export type NullableDateTimeFieldUpdateOperationsInput = {
776
764
  set?: Date | string | null;
777
765
  };
@@ -30,6 +30,8 @@ export * from './OAuthState';
30
30
  export * from './OfferLetter';
31
31
  export * from './Organization';
32
32
  export * from './OrganizationMember';
33
+ export * from './OrganizationType';
34
+ export * from './OrganizationTypeAssignment';
33
35
  export * from './PasswordReset';
34
36
  export * from './PaymentInstallment';
35
37
  export * from './PaymentMethodChangeRequest';
@@ -30,6 +30,8 @@ export * from './OAuthState';
30
30
  export * from './OfferLetter';
31
31
  export * from './Organization';
32
32
  export * from './OrganizationMember';
33
+ export * from './OrganizationType';
34
+ export * from './OrganizationTypeAssignment';
33
35
  export * from './PasswordReset';
34
36
  export * from './PaymentInstallment';
35
37
  export * from './PaymentMethodChangeRequest';
@@ -1,3 +1,5 @@
1
+ export type * from './models/OrganizationType.js';
2
+ export type * from './models/OrganizationTypeAssignment.js';
1
3
  export type * from './models/User.js';
2
4
  export type * from './models/Role.js';
3
5
  export type * from './models/Permission.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valentine-efagene/qshelter-common",
3
- "version": "2.0.150",
3
+ "version": "2.0.152",
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,10 @@
1
+ /*
2
+ Warnings:
3
+
4
+ - You are about to drop the column `isPublished` on the `properties` table. All the data in the column will be lost.
5
+ - You are about to alter the column `status` on the `properties` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(5))`.
6
+
7
+ */
8
+ -- AlterTable
9
+ ALTER TABLE `properties` DROP COLUMN `isPublished`,
10
+ MODIFY `status` ENUM('DRAFT', 'PUBLISHED', 'SOLD_OUT', 'ARCHIVED') NOT NULL DEFAULT 'DRAFT';
@@ -0,0 +1,153 @@
1
+ /*
2
+ Warnings:
3
+
4
+ - You are about to drop the column `role` on the `application_organizations` table. All the data in the column will be lost.
5
+ - You are about to drop the column `reviewParty` on the `approval_stage_progress` table. All the data in the column will be lost.
6
+ - You are about to drop the column `organizationId` on the `approval_stages` table. All the data in the column will be lost.
7
+ - You are about to drop the column `reviewParty` on the `approval_stages` table. All the data in the column will be lost.
8
+ - You are about to drop the column `reviewParty` on the `document_approvals` table. All the data in the column will be lost.
9
+ - You are about to drop the column `reviewParty` on the `document_reviews` table. All the data in the column will be lost.
10
+ - You are about to drop the column `approvalLimit` on the `organization_members` table. All the data in the column will be lost.
11
+ - You are about to drop the column `canApprove` on the `organization_members` table. All the data in the column will be lost.
12
+ - You are about to drop the column `role` on the `organization_members` table. All the data in the column will be lost.
13
+ - You are about to drop the column `type` on the `organizations` table. All the data in the column will be lost.
14
+ - A unique constraint covering the columns `[applicationId,assignedAsTypeId]` on the table `application_organizations` will be added. If there are existing duplicate values, this will fail.
15
+ - A unique constraint covering the columns `[documentId,organizationId]` on the table `document_reviews` will be added. If there are existing duplicate values, this will fail.
16
+ - Added the required column `assignedAsTypeId` to the `application_organizations` table without a default value. This is not possible if the table is not empty.
17
+ - Added the required column `organizationTypeId` to the `approval_stage_progress` table without a default value. This is not possible if the table is not empty.
18
+ - Added the required column `organizationTypeId` to the `approval_stages` table without a default value. This is not possible if the table is not empty.
19
+ - Added the required column `organizationTypeId` to the `document_approvals` table without a default value. This is not possible if the table is not empty.
20
+
21
+ */
22
+ -- DropForeignKey
23
+ ALTER TABLE `application_organizations` DROP FOREIGN KEY `application_organizations_applicationId_fkey`;
24
+
25
+ -- DropForeignKey
26
+ ALTER TABLE `document_reviews` DROP FOREIGN KEY `document_reviews_documentId_fkey`;
27
+
28
+ -- DropIndex
29
+ DROP INDEX `application_organizations_applicationId_organizationId_role_key` ON `application_organizations`;
30
+
31
+ -- DropIndex
32
+ DROP INDEX `application_organizations_role_idx` ON `application_organizations`;
33
+
34
+ -- DropIndex
35
+ DROP INDEX `document_reviews_documentId_reviewParty_organizationId_key` ON `document_reviews`;
36
+
37
+ -- DropIndex
38
+ DROP INDEX `document_reviews_reviewParty_idx` ON `document_reviews`;
39
+
40
+ -- DropIndex
41
+ DROP INDEX `organization_members_role_idx` ON `organization_members`;
42
+
43
+ -- DropIndex
44
+ DROP INDEX `organizations_type_idx` ON `organizations`;
45
+
46
+ -- AlterTable
47
+ ALTER TABLE `application_organizations` DROP COLUMN `role`,
48
+ ADD COLUMN `assignedAsTypeId` VARCHAR(191) NOT NULL;
49
+
50
+ -- AlterTable
51
+ ALTER TABLE `approval_stage_progress` DROP COLUMN `reviewParty`,
52
+ ADD COLUMN `organizationTypeId` VARCHAR(191) NOT NULL;
53
+
54
+ -- AlterTable
55
+ ALTER TABLE `approval_stages` DROP COLUMN `organizationId`,
56
+ DROP COLUMN `reviewParty`,
57
+ ADD COLUMN `organizationTypeId` VARCHAR(191) NOT NULL;
58
+
59
+ -- AlterTable
60
+ ALTER TABLE `document_approvals` DROP COLUMN `reviewParty`,
61
+ ADD COLUMN `organizationTypeId` VARCHAR(191) NOT NULL;
62
+
63
+ -- AlterTable
64
+ ALTER TABLE `document_reviews` DROP COLUMN `reviewParty`,
65
+ ADD COLUMN `organizationTypeId` VARCHAR(191) NULL;
66
+
67
+ -- AlterTable
68
+ ALTER TABLE `organization_members` DROP COLUMN `approvalLimit`,
69
+ DROP COLUMN `canApprove`,
70
+ DROP COLUMN `role`,
71
+ ADD COLUMN `joinedAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3);
72
+
73
+ -- AlterTable
74
+ ALTER TABLE `organizations` DROP COLUMN `type`;
75
+
76
+ -- CreateTable
77
+ CREATE TABLE `organization_types` (
78
+ `id` VARCHAR(191) NOT NULL,
79
+ `tenantId` VARCHAR(191) NOT NULL,
80
+ `code` VARCHAR(191) NOT NULL,
81
+ `name` VARCHAR(191) NOT NULL,
82
+ `description` TEXT NULL,
83
+ `isSystemType` BOOLEAN NOT NULL DEFAULT false,
84
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
85
+ `updatedAt` DATETIME(3) NOT NULL,
86
+
87
+ INDEX `organization_types_tenantId_idx`(`tenantId`),
88
+ INDEX `organization_types_code_idx`(`code`),
89
+ UNIQUE INDEX `organization_types_tenantId_code_key`(`tenantId`, `code`),
90
+ PRIMARY KEY (`id`)
91
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
92
+
93
+ -- CreateTable
94
+ CREATE TABLE `organization_type_assignments` (
95
+ `id` VARCHAR(191) NOT NULL,
96
+ `organizationId` VARCHAR(191) NOT NULL,
97
+ `typeId` VARCHAR(191) NOT NULL,
98
+ `isPrimary` BOOLEAN NOT NULL DEFAULT false,
99
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
100
+
101
+ INDEX `organization_type_assignments_organizationId_idx`(`organizationId`),
102
+ INDEX `organization_type_assignments_typeId_idx`(`typeId`),
103
+ UNIQUE INDEX `organization_type_assignments_organizationId_typeId_key`(`organizationId`, `typeId`),
104
+ PRIMARY KEY (`id`)
105
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
106
+
107
+ -- CreateIndex
108
+ CREATE INDEX `application_organizations_assignedAsTypeId_idx` ON `application_organizations`(`assignedAsTypeId`);
109
+
110
+ -- CreateIndex
111
+ CREATE UNIQUE INDEX `application_organizations_applicationId_assignedAsTypeId_key` ON `application_organizations`(`applicationId`, `assignedAsTypeId`);
112
+
113
+ -- CreateIndex
114
+ CREATE INDEX `approval_stages_organizationTypeId_idx` ON `approval_stages`(`organizationTypeId`);
115
+
116
+ -- CreateIndex
117
+ CREATE INDEX `document_approvals_organizationTypeId_idx` ON `document_approvals`(`organizationTypeId`);
118
+
119
+ -- CreateIndex
120
+ CREATE INDEX `document_reviews_organizationId_idx` ON `document_reviews`(`organizationId`);
121
+
122
+ -- CreateIndex
123
+ CREATE INDEX `document_reviews_organizationTypeId_idx` ON `document_reviews`(`organizationTypeId`);
124
+
125
+ -- CreateIndex
126
+ CREATE UNIQUE INDEX `document_reviews_documentId_organizationId_key` ON `document_reviews`(`documentId`, `organizationId`);
127
+
128
+ -- AddForeignKey
129
+ ALTER TABLE `organization_types` ADD CONSTRAINT `organization_types_tenantId_fkey` FOREIGN KEY (`tenantId`) REFERENCES `tenants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
130
+
131
+ -- AddForeignKey
132
+ ALTER TABLE `organization_type_assignments` ADD CONSTRAINT `organization_type_assignments_organizationId_fkey` FOREIGN KEY (`organizationId`) REFERENCES `organizations`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
133
+
134
+ -- AddForeignKey
135
+ ALTER TABLE `organization_type_assignments` ADD CONSTRAINT `organization_type_assignments_typeId_fkey` FOREIGN KEY (`typeId`) REFERENCES `organization_types`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
136
+
137
+ -- AddForeignKey
138
+ ALTER TABLE `approval_stages` ADD CONSTRAINT `approval_stages_organizationTypeId_fkey` FOREIGN KEY (`organizationTypeId`) REFERENCES `organization_types`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
139
+
140
+ -- AddForeignKey
141
+ ALTER TABLE `application_organizations` ADD CONSTRAINT `application_organizations_assignedAsTypeId_fkey` FOREIGN KEY (`assignedAsTypeId`) REFERENCES `organization_types`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
142
+
143
+ -- AddForeignKey
144
+ ALTER TABLE `document_reviews` ADD CONSTRAINT `document_reviews_organizationId_fkey` FOREIGN KEY (`organizationId`) REFERENCES `organizations`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
145
+
146
+ -- AddForeignKey
147
+ ALTER TABLE `document_reviews` ADD CONSTRAINT `document_reviews_organizationTypeId_fkey` FOREIGN KEY (`organizationTypeId`) REFERENCES `organization_types`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
148
+
149
+ -- AddForeignKey
150
+ ALTER TABLE `approval_stage_progress` ADD CONSTRAINT `approval_stage_progress_organizationTypeId_fkey` FOREIGN KEY (`organizationTypeId`) REFERENCES `organization_types`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
151
+
152
+ -- AddForeignKey
153
+ ALTER TABLE `document_approvals` ADD CONSTRAINT `document_approvals_organizationTypeId_fkey` FOREIGN KEY (`organizationTypeId`) REFERENCES `organization_types`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -0,0 +1,5 @@
1
+ -- AddForeignKey
2
+ ALTER TABLE `application_organizations` ADD CONSTRAINT `application_organizations_applicationId_fkey` FOREIGN KEY (`applicationId`) REFERENCES `applications`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
3
+
4
+ -- AddForeignKey
5
+ ALTER TABLE `document_reviews` ADD CONSTRAINT `document_reviews_documentId_fkey` FOREIGN KEY (`documentId`) REFERENCES `application_documents`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -51,6 +51,13 @@ enum PaymentFrequency {
51
51
  CUSTOM
52
52
  }
53
53
 
54
+ enum PropertyStatus {
55
+ DRAFT
56
+ PUBLISHED
57
+ SOLD_OUT
58
+ ARCHIVED
59
+ }
60
+
54
61
  enum ApplicationStatus {
55
62
  DRAFT
56
63
  PENDING
@@ -196,17 +203,69 @@ enum ApprovalDecision {
196
203
  }
197
204
 
198
205
  // =============================================================================
199
- // ORGANIZATION ENUMS (Banks, Developers, etc.)
206
+ // ORGANIZATION TYPE - Lookup table for organization types (replaces enum)
207
+ // =============================================================================
208
+ // Organizations can have multiple types via OrganizationTypeAssignment.
209
+ // Example: QShelter can be both PLATFORM and DEVELOPER.
210
+ // System types are seeded during tenant bootstrap and cannot be deleted.
200
211
  // =============================================================================
201
212
 
202
- /// Type of organization on the platform
203
- enum OrganizationType {
204
- PLATFORM // The platform operator (e.g., QShelter) - the tenant's own organization
205
- BANK // Financial institution providing mortgages (e.g., Access Bank, GTBank)
206
- DEVELOPER // Property developer building and selling properties
207
- LEGAL // Legal firms handling conveyancing and documentation
208
- INSURER // Insurance companies providing property or mortgage insurance
209
- GOVERNMENT // Government agencies (e.g., land registry, tax authorities)
213
+ model OrganizationType {
214
+ id String @id @default(cuid())
215
+ tenantId String
216
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
217
+ code String // "PLATFORM", "BANK", "DEVELOPER", "LEGAL", "INSURER", "GOVERNMENT"
218
+ name String // Human-readable: "Platform Operator", "Bank/Lender", etc.
219
+ description String? @db.Text
220
+
221
+ // System types are seeded during bootstrap and cannot be deleted
222
+ isSystemType Boolean @default(false)
223
+
224
+ createdAt DateTime @default(now())
225
+ updatedAt DateTime @updatedAt
226
+
227
+ // Organizations with this type
228
+ organizations OrganizationTypeAssignment[]
229
+
230
+ // Applications assigned to orgs acting as this type
231
+ applicationOrganizations ApplicationOrganization[]
232
+
233
+ // Approval stages that require this type of organization
234
+ approvalStages ApprovalStage[]
235
+
236
+ // Document reviews performed by orgs acting as this type (audit snapshot)
237
+ documentReviews DocumentReview[]
238
+
239
+ // Approval stage progress instances
240
+ approvalStageProgress ApprovalStageProgress[]
241
+
242
+ // Document approvals
243
+ documentApprovals DocumentApproval[]
244
+
245
+ @@unique([tenantId, code])
246
+ @@index([tenantId])
247
+ @@index([code])
248
+ @@map("organization_types")
249
+ }
250
+
251
+ /// Links organizations to their types (many-to-many)
252
+ /// An organization can have multiple types (e.g., QShelter is PLATFORM + DEVELOPER)
253
+ model OrganizationTypeAssignment {
254
+ id String @id @default(cuid())
255
+ organizationId String
256
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
257
+ typeId String
258
+ orgType OrganizationType @relation(fields: [typeId], references: [id], onDelete: Cascade)
259
+
260
+ // Which type is the primary one for display purposes
261
+ isPrimary Boolean @default(false)
262
+
263
+ createdAt DateTime @default(now())
264
+
265
+ @@unique([organizationId, typeId])
266
+ @@index([organizationId])
267
+ @@index([typeId])
268
+ @@map("organization_type_assignments")
210
269
  }
211
270
 
212
271
  /// Status of an organization
@@ -217,14 +276,6 @@ enum OrganizationStatus {
217
276
  INACTIVE // No longer active
218
277
  }
219
278
 
220
- /// Role of a member within an organization
221
- enum OrganizationRole {
222
- ADMIN // Can manage org settings, members, and full operations
223
- MANAGER // Can approve transactions within limits (checker)
224
- OFFICER // Regular employee, can initiate actions (maker)
225
- VIEWER // Read-only access to organization data
226
- }
227
-
228
279
  // =============================================================================
229
280
  // CONTRACT TERMINATION / CANCELLATION ENUMS
230
281
  // =============================================================================
@@ -267,21 +318,9 @@ enum CompletionCriterion {
267
318
  }
268
319
 
269
320
  // =============================================================================
270
- // MULTI-PARTY DOCUMENT REVIEW ENUMS
271
- // =============================================================================
272
- // Enables different organizations to review the same document independently
321
+ // DOCUMENT REVIEW ENUMS
273
322
  // =============================================================================
274
323
 
275
- enum ReviewParty {
276
- INTERNAL // Your internal team (compliance, underwriting, etc.)
277
- BANK // Partner bank/lender
278
- DEVELOPER // Property developer
279
- LEGAL // Legal team
280
- GOVERNMENT // Government agencies (e.g., land registry)
281
- INSURER // Insurance company
282
- CUSTOMER // Customer acknowledgment/signature
283
- }
284
-
285
324
  enum ReviewDecision {
286
325
  PENDING // Review not yet performed
287
326
  APPROVED // Document approved by this party
@@ -616,9 +655,12 @@ model Organization {
616
655
  id String @id @default(cuid())
617
656
  tenantId String
618
657
  name String // e.g., "Access Bank PLC", "Lekki Gardens Ltd"
619
- type OrganizationType // PLATFORM, BANK, DEVELOPER, LEGAL, INSURER, GOVERNMENT
620
658
  status OrganizationStatus @default(PENDING)
621
659
 
660
+ // Organization types (many-to-many via OrganizationTypeAssignment)
661
+ // An org can have multiple types (e.g., QShelter is PLATFORM + DEVELOPER)
662
+ types OrganizationTypeAssignment[]
663
+
622
664
  // Platform organization flag - marks the tenant's own organization
623
665
  isPlatformOrg Boolean @default(false)
624
666
 
@@ -660,41 +702,39 @@ model Organization {
660
702
  // Bank-specific document requirements (for BANK type organizations)
661
703
  documentRequirements BankDocumentRequirement[]
662
704
 
705
+ // Document reviews performed by this organization
706
+ documentReviews DocumentReview[]
707
+
663
708
  // Properties developed by this organization (for DEVELOPERs)
664
709
  // developedProperties Property[] @relation("PropertyDeveloper")
665
710
 
666
711
  @@unique([tenantId, bankCode]) // Bank codes unique within tenant
667
712
  @@unique([tenantId, cacNumber]) // CAC numbers unique within tenant
668
713
  @@index([tenantId])
669
- @@index([type])
670
714
  @@index([status])
671
715
  @@map("organizations")
672
716
  }
673
717
 
674
- /// OrganizationMember: Links users to organizations with roles and permissions
675
- /// Supports maker-checker workflows via canApprove and approvalLimit
718
+ /// OrganizationMember: Links users to organizations
719
+ /// User's own roles (via UserRole) determine their abilities within the org
676
720
  model OrganizationMember {
677
- id String @id @default(cuid())
721
+ id String @id @default(cuid())
678
722
  organizationId String
679
723
  userId String
680
- role OrganizationRole @default(OFFICER)
681
724
 
682
725
  // Employee details
683
- title String? // Job title (e.g., "Loan Officer", "Project Manager")
726
+ title String? // Job title (e.g., "Loan Officer", "Mortgage Operations Officer")
684
727
  department String? // Department within organization
685
728
  employeeId String? // Internal employee ID
686
729
 
687
730
  // Status
688
731
  isActive Boolean @default(true)
689
732
 
690
- // Maker-Checker workflow permissions
691
- canApprove Boolean @default(false) // Can this member approve transactions?
692
- approvalLimit Decimal? // Maximum amount this member can approve (null = unlimited)
693
-
694
733
  // Invitation/onboarding tracking
695
734
  invitedAt DateTime?
696
735
  acceptedAt DateTime?
697
736
  invitedBy String? // User ID who invited this member
737
+ joinedAt DateTime @default(now())
698
738
 
699
739
  createdAt DateTime @default(now())
700
740
  updatedAt DateTime @updatedAt
@@ -705,7 +745,6 @@ model OrganizationMember {
705
745
  @@unique([organizationId, userId]) // User can only be member once per org
706
746
  @@index([userId])
707
747
  @@index([organizationId])
708
- @@index([role])
709
748
  @@map("organization_members")
710
749
  }
711
750
 
@@ -879,6 +918,7 @@ model Tenant {
879
918
 
880
919
  // Application organization assignments
881
920
  applicationOrganizations ApplicationOrganization[]
921
+ organizationTypes OrganizationType[]
882
922
 
883
923
  @@index([subdomain])
884
924
  @@map("tenants")
@@ -1112,11 +1152,10 @@ model Property {
1112
1152
  streetAddress String?
1113
1153
  longitude Float?
1114
1154
  latitude Float?
1115
- status String @default("DRAFT") // DRAFT, PUBLISHED, SOLD_OUT, ARCHIVED
1155
+ status PropertyStatus @default(DRAFT)
1116
1156
  description String? @db.Text
1117
1157
  displayImageId String?
1118
1158
  displayImage PropertyMedia? @relation("DisplayImage", fields: [displayImageId], references: [id], onDelete: SetNull)
1119
- isPublished Boolean @default(false)
1120
1159
  publishedAt DateTime?
1121
1160
  createdAt DateTime @default(now())
1122
1161
  updatedAt DateTime @updatedAt
@@ -1419,7 +1458,7 @@ model DocumentDefinition {
1419
1458
  // APPROVAL STAGE - Sequential workflow stages for document review (template)
1420
1459
  // =============================================================================
1421
1460
  // Defines a stage in the approval workflow. Documents flow through stages
1422
- // sequentially. Each stage can have different reviewers (INTERNAL, BANK, etc.)
1461
+ // sequentially. Each stage requires a specific organization type to review.
1423
1462
  // =============================================================================
1424
1463
 
1425
1464
  model ApprovalStage {
@@ -1427,9 +1466,10 @@ model ApprovalStage {
1427
1466
  planId String
1428
1467
  plan DocumentationPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
1429
1468
 
1430
- name String // "QShelter Staff Review", "Bank Review"
1431
- order Int // 1, 2, 3 - sequential order
1432
- reviewParty ReviewParty // INTERNAL, BANK, DEVELOPER, LEGAL, etc.
1469
+ name String // "QShelter Review", "Bank Review"
1470
+ order Int // 1, 2, 3 - sequential order
1471
+ organizationTypeId String // Which type of org should review at this stage
1472
+ organizationType OrganizationType @relation(fields: [organizationTypeId], references: [id])
1433
1473
 
1434
1474
  // Stage behavior flags
1435
1475
  autoTransition Boolean @default(false) // Auto-complete when all docs approved? Default: require explicit approval
@@ -1440,9 +1480,6 @@ model ApprovalStage {
1440
1480
  onRejection RejectionBehavior @default(CASCADE_BACK)
1441
1481
  restartFromStageOrder Int? // If onRejection = RESTART_FROM_STAGE, which stage order to restart from
1442
1482
 
1443
- // Optional: specific organization (e.g., which bank)
1444
- organizationId String?
1445
-
1446
1483
  // SLA (optional)
1447
1484
  slaHours Int? // Escalate if not completed within X hours
1448
1485
 
@@ -1456,6 +1493,7 @@ model ApprovalStage {
1456
1493
 
1457
1494
  @@unique([planId, order])
1458
1495
  @@index([planId])
1496
+ @@index([organizationTypeId])
1459
1497
  @@map("approval_stages")
1460
1498
  }
1461
1499
 
@@ -2073,18 +2111,9 @@ model Application {
2073
2111
  // in a specific application. This enables:
2074
2112
  // 1. Validation that only assigned developers can upload sales offers
2075
2113
  // 2. Only assigned banks can upload preapproval/mortgage offer letters
2076
- // 3. Multi-bank application support (future: apply to multiple banks)
2114
+ // 3. Flexible type-based assignment (org assigned acting as specific type)
2077
2115
  // =============================================================================
2078
2116
 
2079
- /// Role that an organization plays in an application
2080
- enum ApplicationOrganizationRole {
2081
- DEVELOPER // Property developer - uploads sales offer letters
2082
- LENDER // Bank/financial institution - provides mortgage
2083
- LEGAL // Legal firm - handles conveyancing
2084
- INSURER // Insurance company
2085
- GOVERNMENT // Government agency (land registry, etc.)
2086
- }
2087
-
2088
2117
  /// Status of organization's involvement in the application
2089
2118
  enum ApplicationOrganizationStatus {
2090
2119
  PENDING // Awaiting organization's response/engagement
@@ -2105,8 +2134,11 @@ model ApplicationOrganization {
2105
2134
  organizationId String
2106
2135
  organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
2107
2136
 
2108
- // What role does this organization play
2109
- role ApplicationOrganizationRole
2137
+ // Which type the org is acting as on this application
2138
+ // (org must have this type in their OrganizationTypeAssignment)
2139
+ assignedAsTypeId String
2140
+ assignedAsType OrganizationType @relation(fields: [assignedAsTypeId], references: [id])
2141
+
2110
2142
  status ApplicationOrganizationStatus @default(PENDING)
2111
2143
 
2112
2144
  // Who assigned this organization (admin or system)
@@ -2153,11 +2185,11 @@ model ApplicationOrganization {
2153
2185
  createdAt DateTime @default(now())
2154
2186
  updatedAt DateTime @updatedAt
2155
2187
 
2156
- @@unique([applicationId, organizationId, role]) // One org per role per application
2188
+ @@unique([applicationId, assignedAsTypeId]) // One org per type per application
2157
2189
  @@index([tenantId])
2158
2190
  @@index([applicationId])
2159
2191
  @@index([organizationId])
2160
- @@index([role])
2192
+ @@index([assignedAsTypeId])
2161
2193
  @@index([status])
2162
2194
  @@index([isPrimary])
2163
2195
  @@index([slaBreachedAt])
@@ -2723,8 +2755,9 @@ model ApplicationDocument {
2723
2755
  // =============================================================================
2724
2756
  // DOCUMENT REVIEW - Multi-party review tracking
2725
2757
  // =============================================================================
2726
- // Tracks reviews by different organizations for the same document
2727
- // Enables internal approval -> external approval workflows
2758
+ // Tracks reviews by different organizations for the same document.
2759
+ // organizationId is NULL for customer self-attestations/signatures.
2760
+ // For org reviews, organizationTypeId captures which type the org was acting as.
2728
2761
  // =============================================================================
2729
2762
 
2730
2763
  model DocumentReview {
@@ -2734,12 +2767,14 @@ model DocumentReview {
2734
2767
  documentId String
2735
2768
  document ApplicationDocument @relation(fields: [documentId], references: [id], onDelete: Cascade)
2736
2769
 
2737
- // Who is reviewing
2738
- reviewParty ReviewParty // INTERNAL, BANK, DEVELOPER, LEGAL, etc.
2739
- organizationId String? // External organization ID if applicable
2740
- reviewerId String? // User who performed the review
2741
- reviewer User? @relation("DocumentReviewer", fields: [reviewerId], references: [id])
2742
- reviewerName String? // Denormalized for audit trail
2770
+ // Who is reviewing - NULL organizationId means customer self-review
2771
+ organizationId String? // Organization performing the review (null = customer)
2772
+ organization Organization? @relation(fields: [organizationId], references: [id])
2773
+ organizationTypeId String? // Which type the org was acting as (audit snapshot)
2774
+ organizationType OrganizationType? @relation(fields: [organizationTypeId], references: [id])
2775
+ reviewerId String? // User who performed the review
2776
+ reviewer User? @relation("DocumentReviewer", fields: [reviewerId], references: [id])
2777
+ reviewerName String? // Denormalized for audit trail
2743
2778
 
2744
2779
  // Review state
2745
2780
  decision ReviewDecision @default(PENDING)
@@ -2765,10 +2800,12 @@ model DocumentReview {
2765
2800
  createdAt DateTime @default(now())
2766
2801
  updatedAt DateTime @updatedAt
2767
2802
 
2768
- @@unique([documentId, reviewParty, organizationId]) // One review per party per org per doc
2803
+ // Unique: one review per org per doc (null org = customer review)
2804
+ @@unique([documentId, organizationId])
2769
2805
  @@index([tenantId])
2770
2806
  @@index([documentId])
2771
- @@index([reviewParty])
2807
+ @@index([organizationId])
2808
+ @@index([organizationTypeId])
2772
2809
  @@index([decision])
2773
2810
  @@index([reviewerId])
2774
2811
  @@index([parentReviewId])
@@ -2794,9 +2831,10 @@ model ApprovalStageProgress {
2794
2831
  approvalStage ApprovalStage @relation(fields: [approvalStageId], references: [id])
2795
2832
 
2796
2833
  // Stage info (denormalized for convenience)
2797
- name String
2798
- order Int
2799
- reviewParty ReviewParty
2834
+ name String
2835
+ order Int
2836
+ organizationTypeId String // Which type of org should review at this stage
2837
+ organizationType OrganizationType @relation(fields: [organizationTypeId], references: [id])
2800
2838
 
2801
2839
  // Behavior flags (copied from template)
2802
2840
  autoTransition Boolean @default(false)
@@ -2850,9 +2888,10 @@ model DocumentApproval {
2850
2888
  stageProgress ApprovalStageProgress @relation(fields: [stageProgressId], references: [id], onDelete: Cascade)
2851
2889
 
2852
2890
  // Reviewer info
2853
- reviewerId String
2854
- reviewer User @relation("DocumentApprovalReviewer", fields: [reviewerId], references: [id])
2855
- reviewParty ReviewParty // INTERNAL, BANK, etc.
2891
+ reviewerId String
2892
+ reviewer User @relation("DocumentApprovalReviewer", fields: [reviewerId], references: [id])
2893
+ organizationTypeId String // Which type the reviewer's org was acting as
2894
+ organizationType OrganizationType @relation(fields: [organizationTypeId], references: [id])
2856
2895
 
2857
2896
  // Decision
2858
2897
  decision ReviewDecision // APPROVED, REJECTED, CHANGES_REQUESTED
@@ -2865,6 +2904,7 @@ model DocumentApproval {
2865
2904
  @@index([documentId])
2866
2905
  @@index([stageProgressId])
2867
2906
  @@index([reviewerId])
2907
+ @@index([organizationTypeId])
2868
2908
  @@index([decision])
2869
2909
  @@map("document_approvals")
2870
2910
  }