dt-common-device 1.3.0 → 2.0.0

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 (132) hide show
  1. package/TROUBLESHOOTING.md +184 -0
  2. package/dist/config/config.d.ts +9 -2
  3. package/dist/config/config.js +97 -14
  4. package/dist/constants/Event.d.ts +75 -0
  5. package/dist/constants/Event.js +78 -0
  6. package/dist/db/db.d.ts +1 -0
  7. package/dist/db/db.js +18 -2
  8. package/dist/device/local/entities/AlertBuilder.d.ts +87 -0
  9. package/dist/device/local/entities/AlertBuilder.example.d.ts +11 -0
  10. package/dist/device/local/entities/AlertBuilder.example.js +117 -0
  11. package/dist/device/local/entities/AlertBuilder.js +179 -0
  12. package/dist/device/local/entities/IssueBuilder.d.ts +109 -0
  13. package/dist/device/local/entities/IssueBuilder.example.d.ts +16 -0
  14. package/dist/device/local/entities/IssueBuilder.example.js +196 -0
  15. package/dist/device/local/entities/IssueBuilder.js +237 -0
  16. package/dist/device/local/entities/index.d.ts +2 -0
  17. package/dist/device/local/entities/index.js +7 -0
  18. package/dist/device/local/interfaces/IDevice.d.ts +10 -9
  19. package/dist/device/local/interfaces/IDevice.js +7 -0
  20. package/dist/device/local/models/Alert.model.d.ts +28 -0
  21. package/dist/device/local/models/Alert.model.js +222 -0
  22. package/dist/device/local/models/Issue.model.d.ts +28 -0
  23. package/dist/device/local/models/Issue.model.js +260 -0
  24. package/dist/device/local/repository/Alert.repository.d.ts +106 -0
  25. package/dist/device/local/repository/Alert.repository.js +374 -0
  26. package/dist/device/local/repository/Device.repository.d.ts +10 -2
  27. package/dist/device/local/repository/Device.repository.js +153 -30
  28. package/dist/device/local/repository/Hub.repository.d.ts +1 -1
  29. package/dist/device/local/repository/Hub.repository.js +60 -18
  30. package/dist/device/local/repository/Issue.repository.d.ts +113 -0
  31. package/dist/device/local/repository/Issue.repository.js +401 -0
  32. package/dist/device/local/repository/Schedule.repository.d.ts +1 -1
  33. package/dist/device/local/repository/Schedule.repository.js +14 -18
  34. package/dist/device/local/services/Alert.service.d.ts +135 -5
  35. package/dist/device/local/services/Alert.service.js +471 -7
  36. package/dist/device/local/services/AlertService.example.d.ts +55 -0
  37. package/dist/device/local/services/AlertService.example.js +148 -0
  38. package/dist/device/local/services/Device.service.d.ts +8 -5
  39. package/dist/device/local/services/Device.service.js +58 -40
  40. package/dist/device/local/services/Issue.service.d.ts +168 -0
  41. package/dist/device/local/services/Issue.service.js +642 -0
  42. package/dist/device/local/services/IssueService.example.d.ts +68 -0
  43. package/dist/device/local/services/IssueService.example.js +177 -0
  44. package/dist/device/local/services/index.d.ts +7 -5
  45. package/dist/device/local/services/index.js +21 -11
  46. package/dist/events/BaseEventHandler.d.ts +43 -0
  47. package/dist/events/BaseEventHandler.js +111 -0
  48. package/dist/events/BaseEventTransformer.d.ts +26 -0
  49. package/dist/events/BaseEventTransformer.js +72 -0
  50. package/dist/events/DeviceEventHandler.d.ts +15 -0
  51. package/dist/events/DeviceEventHandler.js +152 -0
  52. package/dist/events/DeviceEventTransformerFactory.d.ts +27 -0
  53. package/dist/events/DeviceEventTransformerFactory.js +116 -0
  54. package/dist/events/EventHandler.d.ts +11 -0
  55. package/dist/events/EventHandler.js +106 -0
  56. package/dist/events/EventHandlerOrchestrator.d.ts +35 -0
  57. package/dist/events/EventHandlerOrchestrator.js +141 -0
  58. package/dist/events/EventProcessingService.d.ts +43 -0
  59. package/dist/events/EventProcessingService.js +243 -0
  60. package/dist/events/InternalEventSubscription.d.ts +44 -0
  61. package/dist/events/InternalEventSubscription.js +152 -0
  62. package/dist/events/index.d.ts +9 -0
  63. package/dist/events/index.js +21 -0
  64. package/dist/events/interfaces/DeviceEvent.d.ts +48 -0
  65. package/dist/events/interfaces/DeviceEvent.js +2 -0
  66. package/dist/events/interfaces/IEventHandler.d.ts +23 -0
  67. package/dist/events/interfaces/IEventHandler.js +2 -0
  68. package/dist/events/interfaces/IEventTransformer.d.ts +7 -0
  69. package/dist/events/interfaces/IEventTransformer.js +2 -0
  70. package/dist/events/interfaces/IInternalEvent.d.ts +42 -0
  71. package/dist/events/interfaces/IInternalEvent.js +2 -0
  72. package/dist/events/interfaces/index.d.ts +4 -0
  73. package/dist/events/interfaces/index.js +20 -0
  74. package/dist/index.d.ts +6 -2
  75. package/dist/index.js +9 -2
  76. package/dist/types/alert.types.d.ts +57 -0
  77. package/dist/types/alert.types.js +22 -0
  78. package/dist/types/config.types.d.ts +15 -4
  79. package/dist/types/index.d.ts +2 -0
  80. package/dist/types/index.js +2 -0
  81. package/dist/types/issue.types.d.ts +90 -0
  82. package/dist/types/issue.types.js +40 -0
  83. package/dist/utils/http-utils.d.ts +13 -0
  84. package/dist/utils/http-utils.js +117 -0
  85. package/package.json +2 -1
  86. package/src/config/config.ts +117 -14
  87. package/src/{device/local/events/Events.ts → constants/Event.ts} +34 -13
  88. package/src/db/db.ts +14 -5
  89. package/src/device/local/entities/AlertBuilder.example.ts +126 -0
  90. package/src/device/local/entities/AlertBuilder.ts +202 -0
  91. package/src/device/local/entities/IssueBuilder.example.ts +210 -0
  92. package/src/device/local/entities/IssueBuilder.ts +263 -0
  93. package/src/device/local/entities/README.md +173 -0
  94. package/src/device/local/entities/index.ts +2 -0
  95. package/src/device/local/interfaces/IDevice.ts +11 -9
  96. package/src/device/local/models/Alert.model.md +319 -0
  97. package/src/device/local/models/Alert.model.ts +283 -0
  98. package/src/device/local/models/Issue.model.md +386 -0
  99. package/src/device/local/models/Issue.model.ts +350 -0
  100. package/src/device/local/models/README.md +312 -0
  101. package/src/device/local/repository/Alert.repository.ts +465 -0
  102. package/src/device/local/repository/Device.repository.ts +241 -32
  103. package/src/device/local/repository/Hub.repository.ts +74 -18
  104. package/src/device/local/repository/Issue.repository.ts +517 -0
  105. package/src/device/local/repository/Schedule.repository.ts +28 -22
  106. package/src/device/local/services/Alert.service.ts +617 -5
  107. package/src/device/local/services/AlertService.example.ts +229 -0
  108. package/src/device/local/services/Device.service.ts +70 -50
  109. package/src/device/local/services/Issue.service.ts +872 -0
  110. package/src/device/local/services/IssueService.example.ts +307 -0
  111. package/src/device/local/services/index.ts +7 -5
  112. package/src/events/BaseEventHandler.ts +145 -0
  113. package/src/events/BaseEventTransformer.ts +97 -0
  114. package/src/events/DeviceEventHandler.ts +211 -0
  115. package/src/events/DeviceEventTransformerFactory.ts +77 -0
  116. package/src/{device/local/events → events}/EventHandler.ts +19 -15
  117. package/src/events/EventHandlerOrchestrator.ts +119 -0
  118. package/src/events/EventProcessingService.ts +248 -0
  119. package/src/events/InternalEventSubscription.ts +219 -0
  120. package/src/events/index.ts +9 -0
  121. package/src/events/interfaces/DeviceEvent.ts +56 -0
  122. package/src/events/interfaces/IEventHandler.ts +28 -0
  123. package/src/events/interfaces/IEventTransformer.ts +8 -0
  124. package/src/events/interfaces/IInternalEvent.ts +47 -0
  125. package/src/events/interfaces/index.ts +4 -0
  126. package/src/index.ts +9 -2
  127. package/src/types/alert.types.ts +64 -0
  128. package/src/types/config.types.ts +17 -4
  129. package/src/types/index.ts +2 -0
  130. package/src/types/issue.types.ts +98 -0
  131. package/src/utils/http-utils.ts +143 -0
  132. package/src/device/local/events/index.ts +0 -2
@@ -0,0 +1,319 @@
1
+ # Alert Model Documentation
2
+
3
+ This document describes the Mongoose implementation of the Alert model, which was converted from a Prisma schema to provide comprehensive alert management functionality.
4
+
5
+ ## Overview
6
+
7
+ The Alert model provides a complete alert management system with the following features:
8
+
9
+ - **Alert Management**: Create, read, update, and delete alerts
10
+ - **Severity Levels**: Assign severity levels (INFO, LOW, MEDIUM, HIGH, CRITICAL)
11
+ - **Categories**: Categorize alerts (DEVICE_OFFLINE, DEVICE_BATTERY_LOW, etc.)
12
+ - **Entity References**: Link alerts to various entities (DEVICE, HUB, etc.)
13
+ - **Read Status**: Track read/unread status
14
+ - **Active Status**: Activate/deactivate alerts
15
+ - **Snooze Functionality**: Temporarily suppress alerts until a specified date
16
+ - **Soft Deletion**: Support for soft deletion with recovery capability
17
+ - **Statistics**: Comprehensive alert statistics and reporting
18
+
19
+ ## Model Structure
20
+
21
+ ### Core Fields
22
+
23
+ | Field | Type | Required | Description |
24
+ | ------------- | ------------- | -------- | ------------------------------------- |
25
+ | `_id` | String | Yes | MongoDB ObjectId (auto-generated) |
26
+ | `category` | AlertCategory | Yes | Alert category (DEVICE_OFFLINE, etc.) |
27
+ | `propertyId` | String | Yes | Property UUID reference |
28
+ | `title` | String | Yes | Alert title |
29
+ | `description` | String | Yes | Alert description |
30
+ | `entityId` | String | No | Generic entity reference UUID |
31
+ | `entityType` | EntityType | Yes | Entity type (DEVICE, HUB, etc.) |
32
+ | `severity` | AlertSeverity | Yes | Alert severity (default: MEDIUM) |
33
+ | `isRead` | Boolean | Yes | Read status flag (default: false) |
34
+ | `isActive` | Boolean | Yes | Active status flag (default: true) |
35
+ | `isDeleted` | Boolean | Yes | Soft deletion flag (default: false) |
36
+ | `snoozeUntil` | Date | No | Snooze expiration date |
37
+ | `createdBy` | String | No | User UUID who created the alert |
38
+ | `updatedBy` | String | No | User UUID who last updated |
39
+ | `createdAt` | Date | Yes | Creation timestamp |
40
+ | `updatedAt` | Date | Yes | Last update timestamp |
41
+
42
+ ### Enums
43
+
44
+ #### AlertCategory
45
+
46
+ ```typescript
47
+ enum AlertCategory {
48
+ READINESS = "READINESS",
49
+ OPERATIONS = "OPERATIONS",
50
+ SECURITY = "SECURITY",
51
+ ENERGY = "ENERGY",
52
+ OTHER = "OTHER",
53
+ }
54
+ ```
55
+
56
+ #### AlertSeverity
57
+
58
+ ```typescript
59
+ enum AlertSeverity {
60
+ INFO = "INFO",
61
+ LOW = "LOW",
62
+ MEDIUM = "MEDIUM",
63
+ HIGH = "HIGH",
64
+ CRITICAL = "CRITICAL",
65
+ }
66
+ ```
67
+
68
+ #### EntityType
69
+
70
+ ```typescript
71
+ enum EntityType {
72
+ DEVICE = "DEVICE",
73
+ COLLECTION = "COLLECTION",
74
+ USER = "USER",
75
+ INTEGRATION = "INTEGRATION",
76
+ PROPERTY = "PROPERTY",
77
+ HUB = "HUB",
78
+ SCHEDULE = "SCHEDULE",
79
+ ALERT = "ALERT",
80
+ OTHER = "OTHER",
81
+ }
82
+ ```
83
+
84
+ ## Usage Examples
85
+
86
+ ### Basic CRUD Operations
87
+
88
+ #### Creating an Alert
89
+
90
+ ```typescript
91
+ import { AlertService } from "../services/Alert.service";
92
+ import {
93
+ AlertCategory,
94
+ EntityType,
95
+ AlertSeverity,
96
+ } from "../../../types/alert.types";
97
+
98
+ const alertService = new AlertService();
99
+
100
+ const newAlert = await alertService.createAlert({
101
+ category: AlertCategory.READINESS,
102
+ propertyId: "property-uuid",
103
+ title: "Device Offline",
104
+ description: "Device has been offline for more than 5 minutes",
105
+ entityId: "device-uuid",
106
+ entityType: EntityType.DEVICE,
107
+ severity: AlertSeverity.HIGH,
108
+ createdBy: "user-uuid",
109
+ });
110
+ ```
111
+
112
+ #### Getting Alerts
113
+
114
+ ```typescript
115
+ // Get all alerts for a property
116
+ const propertyAlerts = await alertService.getAlertsByProperty("property-uuid");
117
+
118
+ // Get alerts by severity
119
+ const criticalAlerts = await alertService.getAlertsBySeverity(
120
+ AlertSeverity.CRITICAL
121
+ );
122
+
123
+ // Get unread alerts
124
+ const unreadAlerts = await alertService.getUnreadAlerts();
125
+
126
+ // Get alerts with filters
127
+ const filteredAlerts = await alertService.getAlerts({
128
+ propertyId: "property-uuid",
129
+ severity: AlertSeverity.HIGH,
130
+ isActive: true,
131
+ limit: 10,
132
+ skip: 0,
133
+ });
134
+ ```
135
+
136
+ #### Updating an Alert
137
+
138
+ ```typescript
139
+ // Mark alert as read
140
+ await alertService.markAsRead(alertId, "user-uuid");
141
+
142
+ // Snooze alert for 24 hours
143
+ const snoozeUntil = new Date(Date.now() + 24 * 60 * 60 * 1000);
144
+ await alertService.snoozeAlert(alertId, snoozeUntil, "user-uuid");
145
+
146
+ // Deactivate alert
147
+ await alertService.deactivateAlert(alertId, "user-uuid");
148
+
149
+ // Update alert details
150
+ await alertService.updateAlert(alertId, {
151
+ title: "Updated Alert Title",
152
+ description: "Updated description",
153
+ updatedBy: "user-uuid",
154
+ });
155
+ ```
156
+
157
+ ### Advanced Operations
158
+
159
+ #### Snooze Management
160
+
161
+ ```typescript
162
+ // Snooze an alert until tomorrow
163
+ const tomorrow = new Date();
164
+ tomorrow.setDate(tomorrow.getDate() + 1);
165
+ await alertService.snoozeAlert(alertId, tomorrow, "user-uuid");
166
+
167
+ // Remove snooze
168
+ await alertService.unsnoozeAlert(alertId, "user-uuid");
169
+
170
+ // Get expired snooze alerts
171
+ const expiredAlerts = await alertService.getExpiredSnoozeAlerts();
172
+ ```
173
+
174
+ #### Alert Statistics
175
+
176
+ ```typescript
177
+ // Get overall statistics
178
+ const stats = await alertService.getAlertStatistics();
179
+
180
+ // Get property-specific statistics
181
+ const propertyStats = await alertService.getAlertStatistics("property-uuid");
182
+
183
+ console.log(`Total alerts: ${stats.total}`);
184
+ console.log(`Active alerts: ${stats.active}`);
185
+ console.log(`Unread alerts: ${stats.unread}`);
186
+ console.log(`Snoozed alerts: ${stats.snoozed}`);
187
+ console.log(`Critical alerts: ${stats.bySeverity.CRITICAL}`);
188
+ console.log(`Readiness alerts: ${stats.byCategory.READINESS}`);
189
+ ```
190
+
191
+ #### Repository Pattern Usage
192
+
193
+ For more advanced data access patterns, use the repository:
194
+
195
+ ```typescript
196
+ import { AlertRepository } from "../repository/Alert.repository";
197
+
198
+ const alertRepo = new AlertRepository();
199
+
200
+ // Bulk operations
201
+ await alertRepo.bulkUpdate(["alert1", "alert2"], {
202
+ isRead: true,
203
+ updatedBy: "user-uuid",
204
+ });
205
+
206
+ // Count alerts
207
+ const count = await alertRepo.count({
208
+ propertyId: "property-uuid",
209
+ severity: AlertSeverity.HIGH,
210
+ });
211
+
212
+ // Advanced filtering with sorting
213
+ const alerts = await alertRepo.findAll({
214
+ propertyId: "property-uuid",
215
+ sort: { severity: -1, createdAt: -1 },
216
+ limit: 50,
217
+ });
218
+ ```
219
+
220
+ ## Business Rules
221
+
222
+ ### Severity Assignment
223
+
224
+ Default severity is automatically determined based on the alert category:
225
+
226
+ | Category | Default Severity |
227
+ | ---------- | ---------------- |
228
+ | READINESS | HIGH |
229
+ | OPERATIONS | MEDIUM |
230
+ | SECURITY | CRITICAL |
231
+ | ENERGY | MEDIUM |
232
+ | OTHER | LOW |
233
+
234
+ ### Snooze Validation
235
+
236
+ - Snooze dates must be in the future
237
+ - Attempting to set a past snooze date will throw an error
238
+ - Expired snooze alerts are automatically detected
239
+
240
+ ### Critical Alert Protection
241
+
242
+ - Critical alerts cannot be deleted (soft or hard delete)
243
+ - Attempting to delete a critical alert will throw an error
244
+
245
+ ### Monitoring and Logging
246
+
247
+ The service automatically logs important events:
248
+
249
+ - Unread alerts count
250
+ - Critical alerts count
251
+ - High severity alerts count
252
+ - Expired snooze alerts
253
+
254
+ ## Indexes
255
+
256
+ The model includes the following indexes for optimal performance:
257
+
258
+ - `propertyId` (single field)
259
+ - `entityId` (single field)
260
+ - `entityType` (single field)
261
+ - `severity` (single field)
262
+ - `isRead` (single field)
263
+ - `isActive` (single field)
264
+ - `createdAt` (single field)
265
+ - `{ propertyId: 1, isActive: 1, isRead: 1 }` (compound)
266
+ - `{ entityId: 1, entityType: 1 }` (compound)
267
+
268
+ ## Middleware
269
+
270
+ The model includes pre-save and pre-update middleware that automatically:
271
+
272
+ - Updates the `updatedAt` timestamp on save
273
+ - Updates the `updatedAt` timestamp on update operations
274
+
275
+ ## Virtual Fields
276
+
277
+ - `isSnoozed`: Returns `true` if the alert is currently snoozed
278
+ - `isSnoozeExpired`: Returns `true` if the alert snooze has expired
279
+
280
+ ## Error Handling
281
+
282
+ All operations include comprehensive error handling with descriptive error messages. The service and repository layers wrap database operations in try-catch blocks and provide meaningful error messages.
283
+
284
+ Common error scenarios:
285
+
286
+ - **Invalid snooze date**: "Snooze date must be in the future"
287
+ - **Critical alert deletion**: "Cannot delete critical alerts"
288
+ - **Missing required fields**: "Alert title must be at least 3 characters long"
289
+ - **Invalid filters**: "Limit must be between 1 and 100"
290
+
291
+ ## Best Practices
292
+
293
+ 1. **Use Appropriate Severity**: Choose severity levels based on business impact
294
+ 2. **Set Meaningful Titles**: Use descriptive titles for better alert identification
295
+ 3. **Use Snooze Wisely**: Only snooze alerts when appropriate, not as a permanent solution
296
+ 4. **Monitor Statistics**: Regularly check alert statistics for insights
297
+ 5. **Handle Expired Snoozes**: Implement processes to handle expired snooze alerts
298
+ 6. **Use Categories**: Properly categorize alerts for better organization
299
+ 7. **Set Entity References**: Link alerts to specific entities when possible
300
+ 8. **Use Soft Deletion**: Always use soft deletion for audit trails
301
+ 9. **Validate Input**: Always validate alert data before creation
302
+ 10. **Monitor Critical Alerts**: Implement immediate notification for critical alerts
303
+
304
+ ## Migration from Prisma
305
+
306
+ This Mongoose model maintains full compatibility with the original Prisma schema:
307
+
308
+ - All fields and types are preserved
309
+ - Indexes match the Prisma schema
310
+ - Relationships are maintained through foreign key references
311
+ - Collection name matches Prisma (`dt_alerts`)
312
+
313
+ The model provides additional features beyond the Prisma schema:
314
+
315
+ - Instance methods for common operations
316
+ - Static methods for complex queries
317
+ - Virtual fields for computed properties
318
+ - Comprehensive business logic validation
319
+ - Built-in monitoring and logging
@@ -0,0 +1,283 @@
1
+ import mongoose, { Schema, Model } from "mongoose";
2
+ import {
3
+ AlertCategory,
4
+ AlertSeverity,
5
+ EntityType,
6
+ AlertDocument as IAlertDocument,
7
+ CreateAlertData,
8
+ UpdateAlertData,
9
+ } from "../../../types/alert.types";
10
+
11
+ // Interface for instance methods
12
+ interface IAlertMethods {
13
+ markAsRead(updatedBy: string): void;
14
+ markAsUnread(updatedBy: string): void;
15
+ activate(updatedBy: string): void;
16
+ deactivate(updatedBy: string): void;
17
+ snooze(until: Date, updatedBy: string): void;
18
+ unsnooze(updatedBy: string): void;
19
+ }
20
+
21
+ // Interface for static methods
22
+ interface IAlertModel extends Model<IAlertDocument, {}, IAlertMethods> {
23
+ findByProperty(
24
+ propertyId: string,
25
+ includeDeleted?: boolean
26
+ ): Promise<IAlertDocument[]>;
27
+ findByEntity(
28
+ entityId: string,
29
+ entityType: EntityType,
30
+ includeDeleted?: boolean
31
+ ): Promise<IAlertDocument[]>;
32
+ findByCategory(
33
+ category: AlertCategory,
34
+ includeDeleted?: boolean
35
+ ): Promise<IAlertDocument[]>;
36
+ findBySeverity(
37
+ severity: AlertSeverity,
38
+ includeDeleted?: boolean
39
+ ): Promise<IAlertDocument[]>;
40
+ findActive(includeDeleted?: boolean): Promise<IAlertDocument[]>;
41
+ findUnread(includeDeleted?: boolean): Promise<IAlertDocument[]>;
42
+ findSnoozed(includeDeleted?: boolean): Promise<IAlertDocument[]>;
43
+ findExpiredSnooze(includeDeleted?: boolean): Promise<IAlertDocument[]>;
44
+ }
45
+
46
+ // Main Alert schema
47
+ const AlertSchema = new Schema<IAlertDocument, IAlertModel, IAlertMethods>(
48
+ {
49
+ category: {
50
+ type: String,
51
+ enum: Object.values(AlertCategory),
52
+ required: true,
53
+ },
54
+ propertyId: {
55
+ type: String,
56
+ required: true,
57
+ index: true,
58
+ },
59
+ title: {
60
+ type: String,
61
+ required: true,
62
+ trim: true,
63
+ },
64
+ description: {
65
+ type: String,
66
+ required: true,
67
+ trim: true,
68
+ },
69
+ entityId: {
70
+ type: String,
71
+ index: true,
72
+ },
73
+ entityType: {
74
+ type: String,
75
+ enum: Object.values(EntityType),
76
+ required: true,
77
+ index: true,
78
+ },
79
+ severity: {
80
+ type: String,
81
+ enum: Object.values(AlertSeverity),
82
+ default: AlertSeverity.MEDIUM,
83
+ },
84
+ isRead: {
85
+ type: Boolean,
86
+ default: false,
87
+ index: true,
88
+ },
89
+ isActive: {
90
+ type: Boolean,
91
+ default: true,
92
+ index: true,
93
+ },
94
+ isDeleted: {
95
+ type: Boolean,
96
+ default: false,
97
+ },
98
+ snoozeUntil: {
99
+ type: Date,
100
+ },
101
+ createdBy: {
102
+ type: String,
103
+ },
104
+ updatedBy: {
105
+ type: String,
106
+ },
107
+ createdAt: {
108
+ type: Date,
109
+ default: Date.now,
110
+ },
111
+ updatedAt: {
112
+ type: Date,
113
+ default: Date.now,
114
+ },
115
+ },
116
+ {
117
+ timestamps: true,
118
+ collection: "dt_alerts",
119
+ }
120
+ );
121
+
122
+ // Compound indexes to match Prisma schema
123
+ AlertSchema.index({ propertyId: 1, isActive: 1, isRead: 1 });
124
+ AlertSchema.index({ entityId: 1, entityType: 1 });
125
+ AlertSchema.index({ createdAt: 1 });
126
+
127
+ // Pre-save middleware to update the updatedAt field
128
+ AlertSchema.pre("save", function (next) {
129
+ this.updatedAt = new Date();
130
+ next();
131
+ });
132
+
133
+ // Pre-update middleware to update the updatedAt field
134
+ AlertSchema.pre(
135
+ ["updateOne", "findOneAndUpdate", "updateMany"],
136
+ function (next) {
137
+ this.set({ updatedAt: new Date() });
138
+ next();
139
+ }
140
+ );
141
+
142
+ // Instance methods
143
+ AlertSchema.methods.markAsRead = function (updatedBy: string): void {
144
+ this.isRead = true;
145
+ this.updatedBy = updatedBy;
146
+ };
147
+
148
+ AlertSchema.methods.markAsUnread = function (updatedBy: string): void {
149
+ this.isRead = false;
150
+ this.updatedBy = updatedBy;
151
+ };
152
+
153
+ AlertSchema.methods.activate = function (updatedBy: string): void {
154
+ this.isActive = true;
155
+ this.updatedBy = updatedBy;
156
+ };
157
+
158
+ AlertSchema.methods.deactivate = function (updatedBy: string): void {
159
+ this.isActive = false;
160
+ this.updatedBy = updatedBy;
161
+ };
162
+
163
+ AlertSchema.methods.snooze = function (until: Date, updatedBy: string): void {
164
+ this.snoozeUntil = until;
165
+ this.updatedBy = updatedBy;
166
+ };
167
+
168
+ AlertSchema.methods.unsnooze = function (updatedBy: string): void {
169
+ this.snoozeUntil = undefined;
170
+ this.updatedBy = updatedBy;
171
+ };
172
+
173
+ // Static methods
174
+ AlertSchema.statics.findByProperty = function (
175
+ propertyId: string,
176
+ includeDeleted = false
177
+ ) {
178
+ const query: any = { propertyId };
179
+ if (!includeDeleted) {
180
+ query.isDeleted = false;
181
+ }
182
+ return this.find(query).sort({ createdAt: -1 });
183
+ };
184
+
185
+ AlertSchema.statics.findByEntity = function (
186
+ entityId: string,
187
+ entityType: EntityType,
188
+ includeDeleted = false
189
+ ) {
190
+ const query: any = { entityId, entityType };
191
+ if (!includeDeleted) {
192
+ query.isDeleted = false;
193
+ }
194
+ return this.find(query).sort({ createdAt: -1 });
195
+ };
196
+
197
+ AlertSchema.statics.findByCategory = function (
198
+ category: AlertCategory,
199
+ includeDeleted = false
200
+ ) {
201
+ const query: any = { category };
202
+ if (!includeDeleted) {
203
+ query.isDeleted = false;
204
+ }
205
+ return this.find(query).sort({ createdAt: -1 });
206
+ };
207
+
208
+ AlertSchema.statics.findBySeverity = function (
209
+ severity: AlertSeverity,
210
+ includeDeleted = false
211
+ ) {
212
+ const query: any = { severity };
213
+ if (!includeDeleted) {
214
+ query.isDeleted = false;
215
+ }
216
+ return this.find(query).sort({ severity: -1, createdAt: -1 });
217
+ };
218
+
219
+ AlertSchema.statics.findActive = function (includeDeleted = false) {
220
+ const query: any = { isActive: true };
221
+ if (!includeDeleted) {
222
+ query.isDeleted = false;
223
+ }
224
+ return this.find(query).sort({ severity: -1, createdAt: -1 });
225
+ };
226
+
227
+ AlertSchema.statics.findUnread = function (includeDeleted = false) {
228
+ const query: any = { isRead: false };
229
+ if (!includeDeleted) {
230
+ query.isDeleted = false;
231
+ }
232
+ return this.find(query).sort({ severity: -1, createdAt: -1 });
233
+ };
234
+
235
+ AlertSchema.statics.findSnoozed = function (includeDeleted = false) {
236
+ const query: any = { snoozeUntil: { $exists: true, $ne: null } };
237
+ if (!includeDeleted) {
238
+ query.isDeleted = false;
239
+ }
240
+ return this.find(query).sort({ snoozeUntil: 1 });
241
+ };
242
+
243
+ AlertSchema.statics.findExpiredSnooze = function (includeDeleted = false) {
244
+ const query: any = {
245
+ snoozeUntil: { $lt: new Date() },
246
+ isActive: true,
247
+ };
248
+ if (!includeDeleted) {
249
+ query.isDeleted = false;
250
+ }
251
+ return this.find(query).sort({ snoozeUntil: 1 });
252
+ };
253
+
254
+ // Virtual for snooze status
255
+ AlertSchema.virtual("isSnoozed").get(function () {
256
+ return this.snoozeUntil && this.snoozeUntil > new Date();
257
+ });
258
+
259
+ AlertSchema.virtual("isSnoozeExpired").get(function () {
260
+ return this.snoozeUntil && this.snoozeUntil <= new Date();
261
+ });
262
+
263
+ // Ensure virtuals are serialized
264
+ AlertSchema.set("toJSON", { virtuals: true });
265
+ AlertSchema.set("toObject", { virtuals: true });
266
+
267
+ // Create and export the model
268
+ export const AlertModel = mongoose.model<IAlertDocument, IAlertModel>(
269
+ "Alert",
270
+ AlertSchema
271
+ );
272
+
273
+ // Export the schema for potential reuse
274
+ export { AlertSchema };
275
+
276
+ // Export types for external use
277
+ export type {
278
+ IAlertDocument,
279
+ CreateAlertData,
280
+ UpdateAlertData,
281
+ IAlertMethods,
282
+ IAlertModel,
283
+ };