@valentine-efagene/qshelter-common 2.0.74 → 2.0.76

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 (36) hide show
  1. package/dist/generated/client/browser.d.ts +5 -5
  2. package/dist/generated/client/client.d.ts +5 -5
  3. package/dist/generated/client/internal/class.d.ts +11 -11
  4. package/dist/generated/client/internal/class.js +2 -2
  5. package/dist/generated/client/internal/prismaNamespace.d.ts +95 -95
  6. package/dist/generated/client/internal/prismaNamespace.js +25 -25
  7. package/dist/generated/client/internal/prismaNamespaceBrowser.d.ts +27 -27
  8. package/dist/generated/client/internal/prismaNamespaceBrowser.js +25 -25
  9. package/dist/generated/client/models/Contract.d.ts +155 -155
  10. package/dist/generated/client/models/index.d.ts +3 -0
  11. package/dist/generated/client/models/index.js +3 -0
  12. package/dist/generated/client/models.d.ts +1 -1
  13. package/dist/src/events/bus/event-bus.service.d.ts +84 -0
  14. package/dist/src/events/bus/event-bus.service.js +372 -0
  15. package/dist/src/events/bus/event-bus.types.d.ts +73 -0
  16. package/dist/src/events/bus/event-bus.types.js +22 -0
  17. package/dist/src/events/index.d.ts +5 -6
  18. package/dist/src/events/index.js +7 -8
  19. package/dist/src/events/notifications/event-publisher.d.ts +41 -0
  20. package/dist/src/events/notifications/event-publisher.js +111 -0
  21. package/dist/src/events/notifications/notification-enums.d.ts +46 -0
  22. package/dist/src/events/notifications/notification-enums.js +59 -0
  23. package/dist/src/events/notifications/notification-event.d.ts +76 -0
  24. package/dist/src/events/notifications/notification-event.js +1 -0
  25. package/dist/src/events/unified/unified-event.service.d.ts +157 -0
  26. package/dist/src/events/unified/unified-event.service.js +177 -0
  27. package/dist/src/events/workflow/event-config.service.d.ts +123 -0
  28. package/dist/src/events/workflow/event-config.service.js +416 -0
  29. package/dist/src/events/workflow/event-seeder.d.ts +80 -0
  30. package/dist/src/events/workflow/event-seeder.js +343 -0
  31. package/dist/src/events/workflow/workflow-event.service.d.ts +230 -0
  32. package/dist/src/events/workflow/workflow-event.service.js +682 -0
  33. package/dist/src/events/workflow/workflow-types.d.ts +364 -0
  34. package/dist/src/events/workflow/workflow-types.js +22 -0
  35. package/package.json +4 -1
  36. package/prisma/schema.prisma +87 -79
@@ -0,0 +1,364 @@
1
+ /**
2
+ * Event-Driven Workflow Types
3
+ *
4
+ * These types define the structure for a configurable event system
5
+ * where admins can define event types, channels, and handlers.
6
+ *
7
+ * Architecture:
8
+ * 1. EventChannel - Logical grouping of events (e.g., "CONTRACTS", "PAYMENTS")
9
+ * 2. EventType - Specific event types (e.g., "DOCUMENT_UPLOADED", "STEP_COMPLETED")
10
+ * 3. EventHandler - What to do when an event fires (send email, call webhook, etc.)
11
+ * 4. WorkflowEvent - Actual event instances (audit log)
12
+ * 5. EventHandlerExecution - Log of handler executions
13
+ *
14
+ * Handler types are business-friendly so non-technical admins can configure them:
15
+ * - SEND_EMAIL: Send an email to someone
16
+ * - SEND_SMS: Send a text message
17
+ * - SEND_PUSH: Send a push notification
18
+ * - CALL_WEBHOOK: Call an external API
19
+ * - ADVANCE_WORKFLOW: Move workflow forward
20
+ * - RUN_AUTOMATION: Execute business logic
21
+ */
22
+ export type { EventHandlerType, ActorType, WorkflowEventStatus, ExecutionStatus, } from '../../../generated/client/enums';
23
+ /**
24
+ * Configuration for SEND_EMAIL handler type
25
+ * Sends an email notification to specified recipients
26
+ */
27
+ export interface SendEmailHandlerConfig {
28
+ type: 'SEND_EMAIL';
29
+ /** Email template name (e.g., "documentApproved", "paymentReminder") */
30
+ template: string;
31
+ /**
32
+ * Notification type for the notification service.
33
+ * This maps to templates in the notification service.
34
+ */
35
+ notificationType: string;
36
+ /**
37
+ * Who to send the email to. Use JSONPath to extract from event payload.
38
+ * Examples: "$.buyer.email", "$.user.email"
39
+ */
40
+ recipientPath: string;
41
+ /**
42
+ * Map event payload fields to template variables
43
+ * Example: { "userName": "$.buyer.firstName", "amount": "$.payment.amount" }
44
+ */
45
+ templateData?: Record<string, string>;
46
+ /** Static data to always include in template */
47
+ staticData?: Record<string, unknown>;
48
+ /** Priority level */
49
+ priority?: 'low' | 'normal' | 'high' | 'urgent';
50
+ }
51
+ /**
52
+ * Configuration for SEND_SMS handler type
53
+ * Sends an SMS text message
54
+ */
55
+ export interface SendSmsHandlerConfig {
56
+ type: 'SEND_SMS';
57
+ /** SMS template name */
58
+ template: string;
59
+ /**
60
+ * Notification type for the notification service.
61
+ */
62
+ notificationType: string;
63
+ /**
64
+ * Phone number path in event payload
65
+ * Example: "$.buyer.phone"
66
+ */
67
+ recipientPath: string;
68
+ /** Map event payload fields to template variables */
69
+ templateData?: Record<string, string>;
70
+ /** Static data to always include in template */
71
+ staticData?: Record<string, unknown>;
72
+ }
73
+ /**
74
+ * Configuration for SEND_PUSH handler type
75
+ * Sends a push notification to user's device
76
+ */
77
+ export interface SendPushHandlerConfig {
78
+ type: 'SEND_PUSH';
79
+ /** Push notification title */
80
+ title: string;
81
+ /** Push notification body (can use {{variables}}) */
82
+ body: string;
83
+ /**
84
+ * Notification type for the notification service.
85
+ */
86
+ notificationType: string;
87
+ /**
88
+ * User ID path in event payload (to find their device)
89
+ * Example: "$.buyer.id"
90
+ */
91
+ recipientPath: string;
92
+ /** Deep link to open in app */
93
+ deepLink?: string;
94
+ /** Map event payload fields to notification variables */
95
+ templateData?: Record<string, string>;
96
+ /** Static data to always include in notification */
97
+ staticData?: Record<string, unknown>;
98
+ }
99
+ /**
100
+ * Configuration for CALL_WEBHOOK handler type
101
+ * Calls an external API endpoint
102
+ */
103
+ export interface CallWebhookHandlerConfig {
104
+ type: 'CALL_WEBHOOK';
105
+ /** The URL to call */
106
+ url: string;
107
+ /** HTTP method */
108
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
109
+ /** Optional headers to include */
110
+ headers?: Record<string, string>;
111
+ /**
112
+ * Map event payload fields to request body
113
+ * Example: { "orderId": "$.contract.id", "status": "$.status" }
114
+ */
115
+ bodyMapping?: Record<string, string>;
116
+ /** Timeout in milliseconds (default: 30000) */
117
+ timeoutMs?: number;
118
+ }
119
+ /**
120
+ * Configuration for ADVANCE_WORKFLOW handler type
121
+ * Advances or modifies a workflow step
122
+ */
123
+ export interface AdvanceWorkflowHandlerConfig {
124
+ type: 'ADVANCE_WORKFLOW';
125
+ /** What action to take */
126
+ action: 'complete_step' | 'skip_step' | 'fail_step' | 'activate_phase';
127
+ /**
128
+ * Step ID path in event payload (if action targets a specific step)
129
+ * Example: "$.stepId"
130
+ */
131
+ stepIdPath?: string;
132
+ /**
133
+ * Phase ID path in event payload (if action targets a phase)
134
+ * Example: "$.phaseId"
135
+ */
136
+ phaseIdPath?: string;
137
+ /** Static step ID (if not using path) */
138
+ stepId?: string;
139
+ /** Static workflow ID */
140
+ workflowId?: string;
141
+ /** Static phase ID */
142
+ phaseId?: string;
143
+ /** Additional data to pass to the action */
144
+ data?: Record<string, unknown>;
145
+ /** Reason to record for the action */
146
+ reason?: string;
147
+ }
148
+ /**
149
+ * Configuration for RUN_AUTOMATION handler type
150
+ * Executes internal business logic
151
+ */
152
+ export interface RunAutomationHandlerConfig {
153
+ type: 'RUN_AUTOMATION';
154
+ /** The automation to run (registered automation name) */
155
+ automation: string;
156
+ /**
157
+ * Map event payload fields to automation inputs
158
+ * Example: { "contractId": "$.contract.id", "amount": "$.payment.amount" }
159
+ */
160
+ inputMapping?: Record<string, string>;
161
+ }
162
+ /**
163
+ * Union type for all handler configurations
164
+ */
165
+ export type HandlerConfig = SendEmailHandlerConfig | SendSmsHandlerConfig | SendPushHandlerConfig | CallWebhookHandlerConfig | AdvanceWorkflowHandlerConfig | RunAutomationHandlerConfig;
166
+ /**
167
+ * Input for emitting an event
168
+ */
169
+ export interface EmitEventInput {
170
+ /** Event type code (e.g., "DOCUMENT_UPLOADED") */
171
+ eventType: string;
172
+ /** Event payload */
173
+ payload: Record<string, unknown>;
174
+ /** Source of the event (service name) */
175
+ source: string;
176
+ /** Actor information */
177
+ actor?: {
178
+ id: string;
179
+ type: 'USER' | 'API_KEY' | 'SYSTEM' | 'WEBHOOK';
180
+ };
181
+ /** Correlation ID for tracing related events */
182
+ correlationId?: string;
183
+ /** Causation ID (which event caused this one) */
184
+ causationId?: string;
185
+ }
186
+ /**
187
+ * Event with full metadata (returned from queries)
188
+ */
189
+ export interface WorkflowEventData {
190
+ id: string;
191
+ tenantId: string;
192
+ eventTypeId: string;
193
+ eventTypeCode: string;
194
+ channelCode: string;
195
+ payload: Record<string, unknown>;
196
+ source: string;
197
+ actorId: string | null;
198
+ actorType: 'USER' | 'API_KEY' | 'SYSTEM' | 'WEBHOOK';
199
+ status: 'PENDING' | 'PROCESSING' | 'COMPLETED' | 'FAILED' | 'SKIPPED';
200
+ correlationId: string | null;
201
+ causationId: string | null;
202
+ error: string | null;
203
+ processedAt: Date | null;
204
+ createdAt: Date;
205
+ }
206
+ /**
207
+ * Result of processing an event
208
+ */
209
+ export interface ProcessEventResult {
210
+ eventId: string;
211
+ status: 'PENDING' | 'PROCESSING' | 'COMPLETED' | 'FAILED' | 'SKIPPED';
212
+ handlersExecuted: number;
213
+ handlersSucceeded: number;
214
+ handlersFailed: number;
215
+ errors: Array<{
216
+ handlerId: string;
217
+ handlerName: string;
218
+ error: string;
219
+ }>;
220
+ }
221
+ /**
222
+ * Input for creating an event channel
223
+ */
224
+ export interface CreateEventChannelInput {
225
+ code: string;
226
+ name: string;
227
+ description?: string;
228
+ enabled?: boolean;
229
+ }
230
+ /**
231
+ * Input for updating an event channel
232
+ */
233
+ export interface UpdateEventChannelInput {
234
+ name?: string;
235
+ description?: string;
236
+ enabled?: boolean;
237
+ }
238
+ /**
239
+ * Input for creating an event type
240
+ */
241
+ export interface CreateEventTypeInput {
242
+ channelId: string;
243
+ code: string;
244
+ name: string;
245
+ description?: string;
246
+ payloadSchema?: Record<string, unknown>;
247
+ enabled?: boolean;
248
+ }
249
+ /**
250
+ * Input for updating an event type
251
+ */
252
+ export interface UpdateEventTypeInput {
253
+ name?: string;
254
+ description?: string;
255
+ payloadSchema?: Record<string, unknown>;
256
+ enabled?: boolean;
257
+ }
258
+ /**
259
+ * Input for creating an event handler
260
+ *
261
+ * Handler types are business-friendly names:
262
+ * - SEND_EMAIL: Send email notification
263
+ * - SEND_SMS: Send SMS text message
264
+ * - SEND_PUSH: Send push notification
265
+ * - CALL_WEBHOOK: Call external API
266
+ * - ADVANCE_WORKFLOW: Move workflow forward
267
+ * - RUN_AUTOMATION: Execute business logic
268
+ */
269
+ export interface CreateEventHandlerInput {
270
+ eventTypeId: string;
271
+ name: string;
272
+ description?: string;
273
+ handlerType: 'SEND_EMAIL' | 'SEND_SMS' | 'SEND_PUSH' | 'CALL_WEBHOOK' | 'ADVANCE_WORKFLOW' | 'RUN_AUTOMATION';
274
+ config: HandlerConfig;
275
+ priority?: number;
276
+ enabled?: boolean;
277
+ maxRetries?: number;
278
+ retryDelayMs?: number;
279
+ filterCondition?: string;
280
+ }
281
+ /**
282
+ * Input for updating an event handler
283
+ */
284
+ export interface UpdateEventHandlerInput {
285
+ name?: string;
286
+ description?: string;
287
+ config?: HandlerConfig;
288
+ priority?: number;
289
+ enabled?: boolean;
290
+ maxRetries?: number;
291
+ retryDelayMs?: number;
292
+ filterCondition?: string;
293
+ }
294
+ /**
295
+ * Event channel with related data
296
+ */
297
+ export interface EventChannelWithTypes {
298
+ id: string;
299
+ tenantId: string;
300
+ code: string;
301
+ name: string;
302
+ description: string | null;
303
+ enabled: boolean;
304
+ eventTypes: Array<{
305
+ id: string;
306
+ code: string;
307
+ name: string;
308
+ enabled: boolean;
309
+ }>;
310
+ createdAt: Date;
311
+ updatedAt: Date;
312
+ }
313
+ /**
314
+ * Event type with related data
315
+ */
316
+ export interface EventTypeWithHandlers {
317
+ id: string;
318
+ tenantId: string;
319
+ channelId: string;
320
+ channel: {
321
+ code: string;
322
+ name: string;
323
+ };
324
+ code: string;
325
+ name: string;
326
+ description: string | null;
327
+ payloadSchema: Record<string, unknown> | null;
328
+ enabled: boolean;
329
+ handlers: Array<{
330
+ id: string;
331
+ name: string;
332
+ handlerType: string;
333
+ enabled: boolean;
334
+ }>;
335
+ createdAt: Date;
336
+ updatedAt: Date;
337
+ }
338
+ /**
339
+ * Event handler with related data
340
+ */
341
+ export interface EventHandlerWithType {
342
+ id: string;
343
+ tenantId: string;
344
+ eventTypeId: string;
345
+ eventType: {
346
+ code: string;
347
+ name: string;
348
+ channel: {
349
+ code: string;
350
+ name: string;
351
+ };
352
+ };
353
+ name: string;
354
+ description: string | null;
355
+ handlerType: string;
356
+ config: HandlerConfig;
357
+ priority: number;
358
+ enabled: boolean;
359
+ maxRetries: number;
360
+ retryDelayMs: number;
361
+ filterCondition: string | null;
362
+ createdAt: Date;
363
+ updatedAt: Date;
364
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Event-Driven Workflow Types
3
+ *
4
+ * These types define the structure for a configurable event system
5
+ * where admins can define event types, channels, and handlers.
6
+ *
7
+ * Architecture:
8
+ * 1. EventChannel - Logical grouping of events (e.g., "CONTRACTS", "PAYMENTS")
9
+ * 2. EventType - Specific event types (e.g., "DOCUMENT_UPLOADED", "STEP_COMPLETED")
10
+ * 3. EventHandler - What to do when an event fires (send email, call webhook, etc.)
11
+ * 4. WorkflowEvent - Actual event instances (audit log)
12
+ * 5. EventHandlerExecution - Log of handler executions
13
+ *
14
+ * Handler types are business-friendly so non-technical admins can configure them:
15
+ * - SEND_EMAIL: Send an email to someone
16
+ * - SEND_SMS: Send a text message
17
+ * - SEND_PUSH: Send a push notification
18
+ * - CALL_WEBHOOK: Call an external API
19
+ * - ADVANCE_WORKFLOW: Move workflow forward
20
+ * - RUN_AUTOMATION: Execute business logic
21
+ */
22
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valentine-efagene/qshelter-common",
3
- "version": "2.0.74",
3
+ "version": "2.0.76",
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",
@@ -29,11 +29,14 @@
29
29
  ],
30
30
  "dependencies": {
31
31
  "@aws-sdk/client-dynamodb": "^3.962.0",
32
+ "@aws-sdk/client-eventbridge": "^3.700.0",
32
33
  "@aws-sdk/client-secrets-manager": "^3.500.0",
33
34
  "@aws-sdk/client-sns": "^3.500.0",
35
+ "@aws-sdk/client-sqs": "^3.700.0",
34
36
  "@aws-sdk/client-ssm": "^3.500.0",
35
37
  "@aws-sdk/util-dynamodb": "^3.962.0",
36
38
  "@prisma/client": "^7.0.0",
39
+ "axios": "^1.13.2",
37
40
  "dotenv": "^17.2.3",
38
41
  "prisma": "^7.0.0"
39
42
  },
@@ -211,12 +211,12 @@ enum OfferLetterStatus {
211
211
  /// Handler Type - What kind of action the handler performs
212
212
  /// These are business-friendly names that admins can understand
213
213
  enum EventHandlerType {
214
- SEND_EMAIL // Send an email notification to recipient(s)
215
- SEND_SMS // Send an SMS text message
216
- SEND_PUSH // Send a push notification
217
- CALL_WEBHOOK // Call an external API/webhook
214
+ SEND_EMAIL // Send an email notification to recipient(s)
215
+ SEND_SMS // Send an SMS text message
216
+ SEND_PUSH // Send a push notification
217
+ CALL_WEBHOOK // Call an external API/webhook
218
218
  ADVANCE_WORKFLOW // Advance or complete a workflow step
219
- RUN_AUTOMATION // Execute internal business logic
219
+ RUN_AUTOMATION // Execute internal business logic
220
220
  }
221
221
 
222
222
  /// Actor Type - Who triggered an event
@@ -430,33 +430,33 @@ model Tenant {
430
430
  // =============================================================================
431
431
 
432
432
  model ApiKey {
433
- id String @id @default(cuid())
434
- tenantId String
435
- tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
433
+ id String @id @default(cuid())
434
+ tenantId String
435
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
436
436
 
437
437
  // Identification
438
- name String // Human-readable name (e.g., "Paystack Integration")
439
- description String? @db.Text // Optional description
440
- provider String // Partner/vendor name (e.g., "paystack", "flutterwave")
438
+ name String // Human-readable name (e.g., "Paystack Integration")
439
+ description String? @db.Text // Optional description
440
+ provider String // Partner/vendor name (e.g., "paystack", "flutterwave")
441
441
 
442
442
  // Secret management (NEVER store raw secret in DB)
443
- secretRef String // AWS Secrets Manager ARN or name
443
+ secretRef String // AWS Secrets Manager ARN or name
444
444
 
445
445
  // Permissions - scopes this API key is allowed to request
446
446
  // Examples: ["contract:read", "payment:*", "property:read"]
447
- scopes Json // JSON array of scope strings
447
+ scopes Json // JSON array of scope strings
448
448
 
449
449
  // Lifecycle
450
- enabled Boolean @default(true)
451
- expiresAt DateTime? // Optional expiration date
452
- lastUsedAt DateTime? // Updated on each token exchange
453
- revokedAt DateTime? // Set when key is revoked
454
- revokedBy String? // User ID who revoked
450
+ enabled Boolean @default(true)
451
+ expiresAt DateTime? // Optional expiration date
452
+ lastUsedAt DateTime? // Updated on each token exchange
453
+ revokedAt DateTime? // Set when key is revoked
454
+ revokedBy String? // User ID who revoked
455
455
 
456
456
  // Audit
457
- createdBy String? // User ID who created
458
- createdAt DateTime @default(now())
459
- updatedAt DateTime @updatedAt
457
+ createdBy String? // User ID who created
458
+ createdAt DateTime @default(now())
459
+ updatedAt DateTime @updatedAt
460
460
 
461
461
  @@index([tenantId])
462
462
  @@index([provider])
@@ -994,7 +994,7 @@ model PaymentMethodPhaseStep {
994
994
  /// Step Event Attachment - Links event handlers to step template triggers
995
995
  /// When a step transitions (complete, reject, etc.), attached handlers fire
996
996
  model StepEventAttachment {
997
- id String @id @default(cuid())
997
+ id String @id @default(cuid())
998
998
  stepId String
999
999
  step PaymentMethodPhaseStep @relation(fields: [stepId], references: [id], onDelete: Cascade)
1000
1000
 
@@ -1104,7 +1104,6 @@ model Contract {
1104
1104
  phases ContractPhase[]
1105
1105
  documents ContractDocument[]
1106
1106
  payments ContractPayment[]
1107
- events ContractEvent[]
1108
1107
  terminations ContractTermination[]
1109
1108
  offerLetters OfferLetter[]
1110
1109
 
@@ -1121,6 +1120,9 @@ model Contract {
1121
1120
  // Transfer requests where this contract is the target (created after approval)
1122
1121
  incomingTransferRequests PropertyTransferRequest[] @relation("TargetContract")
1123
1122
 
1123
+ // Audit trail
1124
+ events ContractEvent[]
1125
+
1124
1126
  @@index([tenantId])
1125
1127
  @@index([propertyUnitId])
1126
1128
  @@index([buyerId])
@@ -1212,6 +1214,44 @@ model ContractPhase {
1212
1214
  @@map("contract_phases")
1213
1215
  }
1214
1216
 
1217
+ // =============================================================================
1218
+ // CONTRACT EVENTS - Audit trail for contract lifecycle
1219
+ // =============================================================================
1220
+ // Tracks all significant events in a contract's lifecycle for audit, compliance,
1221
+ // and debugging. Unlike DomainEvent (which is for inter-service communication),
1222
+ // ContractEvent is purely for historical tracking and state machine transitions.
1223
+ // =============================================================================
1224
+ model ContractEvent {
1225
+ id String @id @default(cuid())
1226
+ contractId String
1227
+ contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
1228
+
1229
+ // Event classification
1230
+ eventType String // STATE.TRANSITION, PHASE.ACTIVATED, PAYMENT.COMPLETED, CONTRACT.CREATED, etc.
1231
+ eventGroup String? // STATE_CHANGE, PAYMENT, DOCUMENT, NOTIFICATION (for filtering)
1232
+
1233
+ // For state transitions (optional - only populated for STATE.TRANSITION events)
1234
+ fromState String?
1235
+ toState String?
1236
+ trigger String?
1237
+
1238
+ // Event payload (all event-specific data)
1239
+ data Json?
1240
+
1241
+ // Actor tracking
1242
+ actorId String?
1243
+ actorType String? // USER, SYSTEM, WEBHOOK
1244
+
1245
+ // Timing
1246
+ occurredAt DateTime @default(now())
1247
+
1248
+ @@index([contractId])
1249
+ @@index([eventType])
1250
+ @@index([eventGroup])
1251
+ @@index([occurredAt])
1252
+ @@map("contract_events")
1253
+ }
1254
+
1215
1255
  // Steps within a DOCUMENTATION phase (FSM for document collection/approval)
1216
1256
  model DocumentationStep {
1217
1257
  id String @id @default(cuid())
@@ -1403,38 +1443,6 @@ model ContractDocument {
1403
1443
  @@map("contract_documents")
1404
1444
  }
1405
1445
 
1406
- // Contract domain events (FSM transitions, payments, documents, etc.)
1407
- model ContractEvent {
1408
- id String @id @default(cuid())
1409
- contractId String
1410
- contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
1411
-
1412
- // Event classification
1413
- eventType String // STATE.TRANSITION, PHASE.ACTIVATED, PAYMENT.COMPLETED, etc.
1414
- eventGroup String? // STATE_CHANGE, PAYMENT, DOCUMENT, NOTIFICATION (for filtering)
1415
-
1416
- // For state transitions (optional - only populated for STATE.TRANSITION events)
1417
- fromState String?
1418
- toState String?
1419
- trigger String?
1420
-
1421
- // Event payload (all event-specific data)
1422
- data Json?
1423
-
1424
- // Actor tracking
1425
- actorId String?
1426
- actorType String? // USER, SYSTEM, WEBHOOK
1427
-
1428
- // Timing
1429
- occurredAt DateTime @default(now())
1430
-
1431
- @@index([contractId])
1432
- @@index([eventType])
1433
- @@index([eventGroup])
1434
- @@index([occurredAt])
1435
- @@map("contract_events")
1436
- }
1437
-
1438
1446
  // =============================================================================
1439
1447
  // OFFER LETTERS - Provisional and Final offer documents
1440
1448
  // =============================================================================
@@ -1760,9 +1768,9 @@ model DocumentRequirementRule {
1760
1768
  /// Event Channel - A logical grouping of events
1761
1769
  /// Channels help organize events and route them to appropriate handlers
1762
1770
  model EventChannel {
1763
- id String @id @default(cuid())
1764
- tenantId String
1765
- tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1771
+ id String @id @default(cuid())
1772
+ tenantId String
1773
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1766
1774
 
1767
1775
  /// Unique code for the channel (e.g., "CONTRACTS", "PAYMENTS")
1768
1776
  code String
@@ -1772,7 +1780,7 @@ model EventChannel {
1772
1780
  description String? @db.Text
1773
1781
 
1774
1782
  /// Whether this channel is active
1775
- enabled Boolean @default(true)
1783
+ enabled Boolean @default(true)
1776
1784
 
1777
1785
  /// Event types that belong to this channel
1778
1786
  eventTypes EventType[]
@@ -1788,9 +1796,9 @@ model EventChannel {
1788
1796
  /// Event Type - Defines a type of event that can occur
1789
1797
  /// Each event type belongs to a channel and can have multiple handlers
1790
1798
  model EventType {
1791
- id String @id @default(cuid())
1792
- tenantId String
1793
- tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1799
+ id String @id @default(cuid())
1800
+ tenantId String
1801
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1794
1802
 
1795
1803
  /// The channel this event type belongs to
1796
1804
  channelId String
@@ -1828,9 +1836,9 @@ model EventType {
1828
1836
  /// Event Handler - Defines what should happen when an event fires
1829
1837
  /// Handlers can be internal (call a service), external (webhook), or workflow triggers
1830
1838
  model EventHandler {
1831
- id String @id @default(cuid())
1832
- tenantId String
1833
- tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1839
+ id String @id @default(cuid())
1840
+ tenantId String
1841
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
1834
1842
 
1835
1843
  /// The event type this handler responds to
1836
1844
  eventTypeId String
@@ -2053,7 +2061,7 @@ model PropertyTransferRequest {
2053
2061
  sourceTotalAmount Float? // Original contract total
2054
2062
  targetTotalAmount Float? // New contract total (based on target property)
2055
2063
  priceAdjustment Float? // Difference (positive = buyer owes more)
2056
- paymentsMigrated Int? // Number of payments migrated
2064
+ paymentsMigrated Int? // Number of payments migrated
2057
2065
 
2058
2066
  // Result - new contract created after approval
2059
2067
  targetContractId String?
@@ -2078,21 +2086,21 @@ model PropertyTransferRequest {
2078
2086
  // =============================================================================
2079
2087
 
2080
2088
  enum ApprovalRequestType {
2081
- PROPERTY_TRANSFER // Property unit transfer between contracts
2082
- PROPERTY_UPDATE // Property/unit listing update requiring approval
2083
- USER_WORKFLOW // User workflow step approval
2084
- CREDIT_CHECK // Credit check result review
2089
+ PROPERTY_TRANSFER // Property unit transfer between contracts
2090
+ PROPERTY_UPDATE // Property/unit listing update requiring approval
2091
+ USER_WORKFLOW // User workflow step approval
2092
+ CREDIT_CHECK // Credit check result review
2085
2093
  CONTRACT_TERMINATION // Contract termination approval
2086
- REFUND_APPROVAL // Refund request approval
2094
+ REFUND_APPROVAL // Refund request approval
2087
2095
  }
2088
2096
 
2089
2097
  enum ApprovalRequestStatus {
2090
- PENDING // Awaiting review
2091
- IN_REVIEW // Assigned to reviewer
2092
- APPROVED // Approved by reviewer
2093
- REJECTED // Rejected by reviewer
2094
- CANCELLED // Cancelled by requestor
2095
- EXPIRED // Auto-expired (if TTL configured)
2098
+ PENDING // Awaiting review
2099
+ IN_REVIEW // Assigned to reviewer
2100
+ APPROVED // Approved by reviewer
2101
+ REJECTED // Rejected by reviewer
2102
+ CANCELLED // Cancelled by requestor
2103
+ EXPIRED // Auto-expired (if TTL configured)
2096
2104
  }
2097
2105
 
2098
2106
  enum ApprovalRequestPriority {
@@ -2119,7 +2127,7 @@ model ApprovalRequest {
2119
2127
 
2120
2128
  // Request metadata
2121
2129
  title String @db.VarChar(255) // Human-readable title for the request
2122
- description String? @db.Text // Detailed description
2130
+ description String? @db.Text // Detailed description
2123
2131
 
2124
2132
  // Payload for any additional context (JSON)
2125
2133
  payload Json? // Flexible data storage for type-specific details
@@ -2137,7 +2145,7 @@ model ApprovalRequest {
2137
2145
  reviewedBy User? @relation("ApprovalReviewer", fields: [reviewedById], references: [id])
2138
2146
 
2139
2147
  // Review details
2140
- reviewNotes String? @db.Text // Reviewer's notes/comments
2148
+ reviewNotes String? @db.Text // Reviewer's notes/comments
2141
2149
  decision ApprovalDecision? // APPROVED, REJECTED, REQUEST_CHANGES
2142
2150
 
2143
2151
  // Expiration