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.
- package/TROUBLESHOOTING.md +184 -0
- package/dist/config/config.d.ts +9 -2
- package/dist/config/config.js +97 -14
- package/dist/constants/Event.d.ts +75 -0
- package/dist/constants/Event.js +78 -0
- package/dist/db/db.d.ts +1 -0
- package/dist/db/db.js +18 -2
- package/dist/device/local/entities/AlertBuilder.d.ts +87 -0
- package/dist/device/local/entities/AlertBuilder.example.d.ts +11 -0
- package/dist/device/local/entities/AlertBuilder.example.js +117 -0
- package/dist/device/local/entities/AlertBuilder.js +179 -0
- package/dist/device/local/entities/IssueBuilder.d.ts +109 -0
- package/dist/device/local/entities/IssueBuilder.example.d.ts +16 -0
- package/dist/device/local/entities/IssueBuilder.example.js +196 -0
- package/dist/device/local/entities/IssueBuilder.js +237 -0
- package/dist/device/local/entities/index.d.ts +2 -0
- package/dist/device/local/entities/index.js +7 -0
- package/dist/device/local/interfaces/IDevice.d.ts +10 -9
- package/dist/device/local/interfaces/IDevice.js +7 -0
- package/dist/device/local/models/Alert.model.d.ts +28 -0
- package/dist/device/local/models/Alert.model.js +222 -0
- package/dist/device/local/models/Issue.model.d.ts +28 -0
- package/dist/device/local/models/Issue.model.js +260 -0
- package/dist/device/local/repository/Alert.repository.d.ts +106 -0
- package/dist/device/local/repository/Alert.repository.js +374 -0
- package/dist/device/local/repository/Device.repository.d.ts +10 -2
- package/dist/device/local/repository/Device.repository.js +153 -30
- package/dist/device/local/repository/Hub.repository.d.ts +1 -1
- package/dist/device/local/repository/Hub.repository.js +60 -18
- package/dist/device/local/repository/Issue.repository.d.ts +113 -0
- package/dist/device/local/repository/Issue.repository.js +401 -0
- package/dist/device/local/repository/Schedule.repository.d.ts +1 -1
- package/dist/device/local/repository/Schedule.repository.js +14 -18
- package/dist/device/local/services/Alert.service.d.ts +135 -5
- package/dist/device/local/services/Alert.service.js +471 -7
- package/dist/device/local/services/AlertService.example.d.ts +55 -0
- package/dist/device/local/services/AlertService.example.js +148 -0
- package/dist/device/local/services/Device.service.d.ts +8 -5
- package/dist/device/local/services/Device.service.js +58 -40
- package/dist/device/local/services/Issue.service.d.ts +168 -0
- package/dist/device/local/services/Issue.service.js +642 -0
- package/dist/device/local/services/IssueService.example.d.ts +68 -0
- package/dist/device/local/services/IssueService.example.js +177 -0
- package/dist/device/local/services/index.d.ts +7 -5
- package/dist/device/local/services/index.js +21 -11
- package/dist/events/BaseEventHandler.d.ts +43 -0
- package/dist/events/BaseEventHandler.js +111 -0
- package/dist/events/BaseEventTransformer.d.ts +26 -0
- package/dist/events/BaseEventTransformer.js +72 -0
- package/dist/events/DeviceEventHandler.d.ts +15 -0
- package/dist/events/DeviceEventHandler.js +152 -0
- package/dist/events/DeviceEventTransformerFactory.d.ts +27 -0
- package/dist/events/DeviceEventTransformerFactory.js +116 -0
- package/dist/events/EventHandler.d.ts +11 -0
- package/dist/events/EventHandler.js +106 -0
- package/dist/events/EventHandlerOrchestrator.d.ts +35 -0
- package/dist/events/EventHandlerOrchestrator.js +141 -0
- package/dist/events/EventProcessingService.d.ts +43 -0
- package/dist/events/EventProcessingService.js +243 -0
- package/dist/events/InternalEventSubscription.d.ts +44 -0
- package/dist/events/InternalEventSubscription.js +152 -0
- package/dist/events/index.d.ts +9 -0
- package/dist/events/index.js +21 -0
- package/dist/events/interfaces/DeviceEvent.d.ts +48 -0
- package/dist/events/interfaces/DeviceEvent.js +2 -0
- package/dist/events/interfaces/IEventHandler.d.ts +23 -0
- package/dist/events/interfaces/IEventHandler.js +2 -0
- package/dist/events/interfaces/IEventTransformer.d.ts +7 -0
- package/dist/events/interfaces/IEventTransformer.js +2 -0
- package/dist/events/interfaces/IInternalEvent.d.ts +42 -0
- package/dist/events/interfaces/IInternalEvent.js +2 -0
- package/dist/events/interfaces/index.d.ts +4 -0
- package/dist/events/interfaces/index.js +20 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +9 -2
- package/dist/types/alert.types.d.ts +57 -0
- package/dist/types/alert.types.js +22 -0
- package/dist/types/config.types.d.ts +15 -4
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/issue.types.d.ts +90 -0
- package/dist/types/issue.types.js +40 -0
- package/dist/utils/http-utils.d.ts +13 -0
- package/dist/utils/http-utils.js +117 -0
- package/package.json +2 -1
- package/src/config/config.ts +117 -14
- package/src/{device/local/events/Events.ts → constants/Event.ts} +34 -13
- package/src/db/db.ts +14 -5
- package/src/device/local/entities/AlertBuilder.example.ts +126 -0
- package/src/device/local/entities/AlertBuilder.ts +202 -0
- package/src/device/local/entities/IssueBuilder.example.ts +210 -0
- package/src/device/local/entities/IssueBuilder.ts +263 -0
- package/src/device/local/entities/README.md +173 -0
- package/src/device/local/entities/index.ts +2 -0
- package/src/device/local/interfaces/IDevice.ts +11 -9
- package/src/device/local/models/Alert.model.md +319 -0
- package/src/device/local/models/Alert.model.ts +283 -0
- package/src/device/local/models/Issue.model.md +386 -0
- package/src/device/local/models/Issue.model.ts +350 -0
- package/src/device/local/models/README.md +312 -0
- package/src/device/local/repository/Alert.repository.ts +465 -0
- package/src/device/local/repository/Device.repository.ts +241 -32
- package/src/device/local/repository/Hub.repository.ts +74 -18
- package/src/device/local/repository/Issue.repository.ts +517 -0
- package/src/device/local/repository/Schedule.repository.ts +28 -22
- package/src/device/local/services/Alert.service.ts +617 -5
- package/src/device/local/services/AlertService.example.ts +229 -0
- package/src/device/local/services/Device.service.ts +70 -50
- package/src/device/local/services/Issue.service.ts +872 -0
- package/src/device/local/services/IssueService.example.ts +307 -0
- package/src/device/local/services/index.ts +7 -5
- package/src/events/BaseEventHandler.ts +145 -0
- package/src/events/BaseEventTransformer.ts +97 -0
- package/src/events/DeviceEventHandler.ts +211 -0
- package/src/events/DeviceEventTransformerFactory.ts +77 -0
- package/src/{device/local/events → events}/EventHandler.ts +19 -15
- package/src/events/EventHandlerOrchestrator.ts +119 -0
- package/src/events/EventProcessingService.ts +248 -0
- package/src/events/InternalEventSubscription.ts +219 -0
- package/src/events/index.ts +9 -0
- package/src/events/interfaces/DeviceEvent.ts +56 -0
- package/src/events/interfaces/IEventHandler.ts +28 -0
- package/src/events/interfaces/IEventTransformer.ts +8 -0
- package/src/events/interfaces/IInternalEvent.ts +47 -0
- package/src/events/interfaces/index.ts +4 -0
- package/src/index.ts +9 -2
- package/src/types/alert.types.ts +64 -0
- package/src/types/config.types.ts +17 -4
- package/src/types/index.ts +2 -0
- package/src/types/issue.types.ts +98 -0
- package/src/utils/http-utils.ts +143 -0
- 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
|
+
};
|