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,350 @@
1
+ import mongoose, { Schema, Model } from "mongoose";
2
+ import {
3
+ IssuesCategory,
4
+ EntityType,
5
+ IssueStatus,
6
+ IssuePriority,
7
+ IssueComment,
8
+ IssueDocument as IIssueDocument,
9
+ CreateIssueData,
10
+ UpdateIssueData,
11
+ AddCommentData,
12
+ } from "../../../types/issue.types";
13
+
14
+ // Comment sub-schema
15
+ const CommentSchema = new Schema<IssueComment>(
16
+ {
17
+ id: { type: String, required: true },
18
+ userId: { type: String, required: true },
19
+ content: { type: String, required: true },
20
+ createdAt: { type: Date, default: Date.now },
21
+ updatedAt: { type: Date },
22
+ },
23
+ { _id: false }
24
+ );
25
+
26
+ // Interface for instance methods
27
+ interface IIssueMethods {
28
+ addComment(commentData: AddCommentData): void;
29
+ updateComment(commentId: string, content: string, userId: string): boolean;
30
+ removeComment(commentId: string): boolean;
31
+ resolve(resolvedBy: string): void;
32
+ reopen(updatedBy: string): void;
33
+ assign(userId: string, assignedBy: string): void;
34
+ unassign(unassignedBy: string): void;
35
+ }
36
+
37
+ // Interface for static methods
38
+ interface IIssueModel extends Model<IIssueDocument, {}, IIssueMethods> {
39
+ findByProperty(
40
+ propertyId: string,
41
+ includeDeleted?: boolean
42
+ ): Promise<IIssueDocument[]>;
43
+ findByAssignee(
44
+ assignedTo: string,
45
+ includeDeleted?: boolean
46
+ ): Promise<IIssueDocument[]>;
47
+ findByEntity(
48
+ entityId: string,
49
+ entityType: EntityType,
50
+ includeDeleted?: boolean
51
+ ): Promise<IIssueDocument[]>;
52
+ findByStatus(
53
+ status: IssueStatus,
54
+ includeDeleted?: boolean
55
+ ): Promise<IIssueDocument[]>;
56
+ findByPriority(
57
+ priority: IssuePriority,
58
+ includeDeleted?: boolean
59
+ ): Promise<IIssueDocument[]>;
60
+ findOverdue(includeDeleted?: boolean): Promise<IIssueDocument[]>;
61
+ findUpcoming(
62
+ days?: number,
63
+ includeDeleted?: boolean
64
+ ): Promise<IIssueDocument[]>;
65
+ }
66
+
67
+ // Main Issue schema
68
+ const IssueSchema = new Schema<IIssueDocument, IIssueModel, IIssueMethods>(
69
+ {
70
+ category: {
71
+ type: String,
72
+ enum: Object.values(IssuesCategory),
73
+ required: true,
74
+ },
75
+ propertyId: {
76
+ type: String,
77
+ required: true,
78
+ index: true,
79
+ },
80
+ title: {
81
+ type: String,
82
+ required: true,
83
+ trim: true,
84
+ },
85
+ description: {
86
+ type: String,
87
+ required: true,
88
+ trim: true,
89
+ },
90
+ entityId: {
91
+ type: String,
92
+ index: true,
93
+ },
94
+ entityType: {
95
+ type: String,
96
+ enum: Object.values(EntityType),
97
+ required: true,
98
+ index: true,
99
+ },
100
+ status: {
101
+ type: String,
102
+ enum: Object.values(IssueStatus),
103
+ default: IssueStatus.PENDING,
104
+ index: true,
105
+ },
106
+ priority: {
107
+ type: String,
108
+ enum: Object.values(IssuePriority),
109
+ default: IssuePriority.MEDIUM,
110
+ },
111
+ assignedTo: {
112
+ type: String,
113
+ index: true,
114
+ },
115
+ createdBy: {
116
+ type: String,
117
+ required: true,
118
+ },
119
+ updatedBy: {
120
+ type: String,
121
+ },
122
+ isDeleted: {
123
+ type: Boolean,
124
+ default: false,
125
+ },
126
+ createdAt: {
127
+ type: Date,
128
+ default: Date.now,
129
+ },
130
+ updatedAt: {
131
+ type: Date,
132
+ default: Date.now,
133
+ },
134
+ resolvedAt: {
135
+ type: Date,
136
+ },
137
+ dueDate: {
138
+ type: Date,
139
+ },
140
+ comments: {
141
+ type: [CommentSchema],
142
+ default: [],
143
+ },
144
+ },
145
+ {
146
+ timestamps: true,
147
+ collection: "dt_issues",
148
+ }
149
+ );
150
+
151
+ IssueSchema.index({ propertyId: 1, status: 1 });
152
+ IssueSchema.index({ assignedTo: 1, status: 1 });
153
+ IssueSchema.index({ entityId: 1, entityType: 1 });
154
+
155
+ // Pre-save middleware to update the updatedAt field
156
+ IssueSchema.pre("save", function (next) {
157
+ this.updatedAt = new Date();
158
+ next();
159
+ });
160
+
161
+ // Pre-update middleware to update the updatedAt field
162
+ IssueSchema.pre(
163
+ ["updateOne", "findOneAndUpdate", "updateMany"],
164
+ function (next) {
165
+ this.set({ updatedAt: new Date() });
166
+ next();
167
+ }
168
+ );
169
+
170
+ // Instance methods
171
+ IssueSchema.methods.addComment = function (commentData: AddCommentData): void {
172
+ const comment: IssueComment = {
173
+ id: new mongoose.Types.ObjectId().toString(),
174
+ userId: commentData.userId,
175
+ content: commentData.content,
176
+ createdAt: new Date(),
177
+ };
178
+
179
+ if (!this.comments) {
180
+ this.comments = [];
181
+ }
182
+
183
+ this.comments.push(comment);
184
+ };
185
+
186
+ IssueSchema.methods.updateComment = function (
187
+ commentId: string,
188
+ content: string,
189
+ userId: string
190
+ ): boolean {
191
+ if (!this.comments) return false;
192
+
193
+ const comment = this.comments.find((c: IssueComment) => c.id === commentId);
194
+ if (comment) {
195
+ comment.content = content;
196
+ comment.updatedAt = new Date();
197
+ return true;
198
+ }
199
+ return false;
200
+ };
201
+
202
+ IssueSchema.methods.removeComment = function (commentId: string): boolean {
203
+ if (!this.comments) return false;
204
+
205
+ const initialLength = this.comments.length;
206
+ this.comments = this.comments.filter((c: IssueComment) => c.id !== commentId);
207
+ return this.comments.length < initialLength;
208
+ };
209
+
210
+ IssueSchema.methods.resolve = function (resolvedBy: string): void {
211
+ this.status = IssueStatus.RESOLVED;
212
+ this.resolvedAt = new Date();
213
+ this.updatedBy = resolvedBy;
214
+ };
215
+
216
+ IssueSchema.methods.reopen = function (updatedBy: string): void {
217
+ this.status = IssueStatus.PENDING;
218
+ this.resolvedAt = undefined;
219
+ this.updatedBy = updatedBy;
220
+ };
221
+
222
+ IssueSchema.methods.assign = function (
223
+ userId: string,
224
+ assignedBy: string
225
+ ): void {
226
+ this.assignedTo = userId;
227
+ this.updatedBy = assignedBy;
228
+ };
229
+
230
+ IssueSchema.methods.unassign = function (unassignedBy: string): void {
231
+ this.assignedTo = undefined;
232
+ this.updatedBy = unassignedBy;
233
+ };
234
+
235
+ // Static methods
236
+ IssueSchema.statics.findByProperty = function (
237
+ propertyId: string,
238
+ includeDeleted = false
239
+ ) {
240
+ const query: any = { propertyId };
241
+ if (!includeDeleted) {
242
+ query.isDeleted = false;
243
+ }
244
+ return this.find(query).sort({ createdAt: -1 });
245
+ };
246
+
247
+ IssueSchema.statics.findByAssignee = function (
248
+ assignedTo: string,
249
+ includeDeleted = false
250
+ ) {
251
+ const query: any = { assignedTo };
252
+ if (!includeDeleted) {
253
+ query.isDeleted = false;
254
+ }
255
+ return this.find(query).sort({ priority: -1, createdAt: -1 });
256
+ };
257
+
258
+ IssueSchema.statics.findByEntity = function (
259
+ entityId: string,
260
+ entityType: EntityType,
261
+ includeDeleted = false
262
+ ) {
263
+ const query: any = { entityId, entityType };
264
+ if (!includeDeleted) {
265
+ query.isDeleted = false;
266
+ }
267
+ return this.find(query).sort({ createdAt: -1 });
268
+ };
269
+
270
+ IssueSchema.statics.findByStatus = function (
271
+ status: IssueStatus,
272
+ includeDeleted = false
273
+ ) {
274
+ const query: any = { status };
275
+ if (!includeDeleted) {
276
+ query.isDeleted = false;
277
+ }
278
+ return this.find(query).sort({ priority: -1, createdAt: -1 });
279
+ };
280
+
281
+ IssueSchema.statics.findByPriority = function (
282
+ priority: IssuePriority,
283
+ includeDeleted = false
284
+ ) {
285
+ const query: any = { priority };
286
+ if (!includeDeleted) {
287
+ query.isDeleted = false;
288
+ }
289
+ return this.find(query).sort({ createdAt: -1 });
290
+ };
291
+
292
+ IssueSchema.statics.findOverdue = function (includeDeleted = false) {
293
+ const query: any = {
294
+ dueDate: { $lt: new Date() },
295
+ status: {
296
+ $nin: [IssueStatus.RESOLVED, IssueStatus.CLOSED, IssueStatus.CANCELLED],
297
+ },
298
+ };
299
+ if (!includeDeleted) {
300
+ query.isDeleted = false;
301
+ }
302
+ return this.find(query).sort({ dueDate: 1 });
303
+ };
304
+
305
+ IssueSchema.statics.findUpcoming = function (
306
+ days: number = 7,
307
+ includeDeleted = false
308
+ ) {
309
+ const futureDate = new Date();
310
+ futureDate.setDate(futureDate.getDate() + days);
311
+
312
+ const query: any = {
313
+ dueDate: { $gte: new Date(), $lte: futureDate },
314
+ status: {
315
+ $nin: [IssueStatus.RESOLVED, IssueStatus.CLOSED, IssueStatus.CANCELLED],
316
+ },
317
+ };
318
+ if (!includeDeleted) {
319
+ query.isDeleted = false;
320
+ }
321
+ return this.find(query).sort({ dueDate: 1 });
322
+ };
323
+
324
+ // Virtual for soft delete
325
+ IssueSchema.virtual("isActive").get(function () {
326
+ return !this.isDeleted;
327
+ });
328
+
329
+ // Ensure virtuals are serialized
330
+ IssueSchema.set("toJSON", { virtuals: true });
331
+ IssueSchema.set("toObject", { virtuals: true });
332
+
333
+ // Create and export the model
334
+ export const IssueModel = mongoose.model<IIssueDocument, IIssueModel>(
335
+ "Issue",
336
+ IssueSchema
337
+ );
338
+
339
+ // Export the schema for potential reuse
340
+ export { IssueSchema };
341
+
342
+ // Export types for external use
343
+ export type {
344
+ IIssueDocument,
345
+ CreateIssueData,
346
+ UpdateIssueData,
347
+ AddCommentData,
348
+ IIssueMethods,
349
+ IIssueModel,
350
+ };
@@ -0,0 +1,312 @@
1
+ # Local Device Models
2
+
3
+ This directory contains Mongoose models for local device management, implementing Prisma schema compatibility.
4
+
5
+ ## Models
6
+
7
+ ### Alert Model (`Alert.model.ts`)
8
+
9
+ A comprehensive alert management system with snooze functionality, severity levels, and read status tracking.
10
+
11
+ **📖 [Detailed Documentation](./Alert.model.md)**
12
+
13
+ #### Key Features
14
+
15
+ - **Severity Management**: INFO, LOW, MEDIUM, HIGH, CRITICAL levels
16
+ - **Snooze Functionality**: Temporarily suppress alerts until specified date
17
+ - **Read Status**: Track read/unread status with automatic logging
18
+ - **Category System**: READINESS, OPERATIONS, SECURITY, ENERGY, OTHER
19
+ - **Entity References**: Link alerts to devices, hubs, and other entities
20
+ - **Statistics**: Comprehensive alert statistics and monitoring
21
+
22
+ #### Quick Example
23
+
24
+ ```typescript
25
+ import { AlertService } from "../services/Alert.service";
26
+ import {
27
+ AlertCategory,
28
+ AlertSeverity,
29
+ EntityType,
30
+ } from "../../../types/alert.types";
31
+
32
+ const alertService = new AlertService();
33
+
34
+ // Create a critical alert
35
+ const alert = await alertService.createAlert({
36
+ category: AlertCategory.READINESS,
37
+ propertyId: "property-123",
38
+ title: "Device Offline",
39
+ description: "Device has been offline for more than 5 minutes",
40
+ entityId: "device-456",
41
+ entityType: EntityType.DEVICE,
42
+ severity: AlertSeverity.HIGH,
43
+ createdBy: "user-789",
44
+ });
45
+
46
+ // Snooze for 24 hours
47
+ await alertService.snoozeAlert(
48
+ alert._id,
49
+ new Date(Date.now() + 24 * 60 * 60 * 1000),
50
+ "user-789"
51
+ );
52
+ ```
53
+
54
+ ### Issue Model (`Issue.model.ts`)
55
+
56
+ A comprehensive issue tracking system with assignment, comments, and resolution workflow.
57
+
58
+ **📖 [Detailed Documentation](./Issue.model.md)**
59
+
60
+ #### Key Features
61
+
62
+ - **Status Workflow**: OPEN → IN_PROGRESS → RESOLVED → CLOSED
63
+ - **Assignment System**: Assign issues to users with validation
64
+ - **Comment System**: Add, update, and remove comments on issues
65
+ - **Priority Management**: LOW, MEDIUM, HIGH, CRITICAL with overdue calculation
66
+ - **Due Date Tracking**: Set and monitor due dates with automatic overdue detection
67
+ - **Search & Statistics**: Full-text search and comprehensive reporting
68
+
69
+ #### Quick Example
70
+
71
+ ```typescript
72
+ import { IssueService } from "../services/Issue.service";
73
+ import {
74
+ IssueCategory,
75
+ IssuePriority,
76
+ EntityType,
77
+ } from "../../../types/issue.types";
78
+
79
+ const issueService = new IssueService();
80
+
81
+ // Create an issue
82
+ const issue = await issueService.createIssue({
83
+ category: IssueCategory.READINESS,
84
+ propertyId: "property-123",
85
+ title: "Device Connection Issue",
86
+ description: "Device is not responding to commands",
87
+ entityId: "device-456",
88
+ entityType: EntityType.DEVICE,
89
+ priority: IssuePriority.HIGH,
90
+ createdBy: "user-789",
91
+ dueDate: new Date("2024-01-15"),
92
+ });
93
+
94
+ // Assign and start progress
95
+ await issueService.assignIssue(issue._id, "tech-user-123", "user-789");
96
+ await issueService.updateIssue(issue._id, {
97
+ status: IssueStatus.IN_PROGRESS,
98
+ updatedBy: "tech-user-123",
99
+ });
100
+
101
+ // Add comment
102
+ await issueService.addComment(issue._id, {
103
+ userId: "tech-user-123",
104
+ content: "Investigating the connection issue",
105
+ });
106
+ ```
107
+
108
+ ## Architecture
109
+
110
+ ### Clean Architecture Pattern
111
+
112
+ Both models follow a clean architecture pattern with clear separation of concerns:
113
+
114
+ ```
115
+ Service Layer (Business Logic)
116
+
117
+ Repository Layer (Data Access)
118
+
119
+ Model Layer (Data Structure)
120
+ ```
121
+
122
+ #### Service Layer
123
+
124
+ - **Business Logic**: Validation, business rules, workflow management
125
+ - **Error Handling**: Comprehensive error messages and validation
126
+ - **Monitoring**: Built-in logging for important events
127
+ - **Repository Usage**: All data access through repository layer
128
+
129
+ #### Repository Layer
130
+
131
+ - **Data Access**: CRUD operations with error handling
132
+ - **Query Optimization**: Efficient filtering and sorting
133
+ - **Bulk Operations**: Support for bulk updates and deletes
134
+ - **Statistics**: Aggregation and reporting functions
135
+
136
+ #### Model Layer
137
+
138
+ - **Schema Definition**: Mongoose schemas with validation
139
+ - **Instance Methods**: Common operations on individual documents
140
+ - **Static Methods**: Complex queries and filtering
141
+ - **Virtual Fields**: Computed properties
142
+ - **Middleware**: Pre/post save hooks for automation
143
+
144
+ ## Common Patterns
145
+
146
+ ### Business Rules Implementation
147
+
148
+ Both models implement business rules in the service layer:
149
+
150
+ ```typescript
151
+ // Alert Service - Severity Assignment
152
+ private determineDefaultSeverity(category: AlertCategory): AlertSeverity {
153
+ const categorySeverities: Record<AlertCategory, AlertSeverity> = {
154
+ [AlertCategory.READINESS]: AlertSeverity.HIGH,
155
+ [AlertCategory.SECURITY]: AlertSeverity.CRITICAL,
156
+ // ... more mappings
157
+ };
158
+ return categorySeverities[category] || AlertSeverity.MEDIUM;
159
+ }
160
+
161
+ // Issue Service - Status Transitions
162
+ private validateStatusTransition(currentStatus: IssueStatus, newStatus: IssueStatus): void {
163
+ const validTransitions = {
164
+ [IssueStatus.OPEN]: [IssueStatus.IN_PROGRESS],
165
+ [IssueStatus.IN_PROGRESS]: [IssueStatus.RESOLVED],
166
+ [IssueStatus.RESOLVED]: [IssueStatus.CLOSED, IssueStatus.OPEN],
167
+ // ... more transitions
168
+ };
169
+ // Validation logic
170
+ }
171
+ ```
172
+
173
+ ### Error Handling
174
+
175
+ Consistent error handling across all layers:
176
+
177
+ ```typescript
178
+ // Repository Layer
179
+ try {
180
+ return await AlertModel.findById(id);
181
+ } catch (error) {
182
+ throw new Error(
183
+ `Failed to find alert by ID: ${
184
+ error instanceof Error ? error.message : "Unknown error"
185
+ }`
186
+ );
187
+ }
188
+
189
+ // Service Layer
190
+ if (!id) {
191
+ throw new Error("Alert ID is required");
192
+ }
193
+ ```
194
+
195
+ ### Monitoring and Logging
196
+
197
+ Built-in monitoring for important events:
198
+
199
+ ```typescript
200
+ // Alert monitoring
201
+ if (stats.bySeverity[AlertSeverity.CRITICAL] > 0) {
202
+ console.error(
203
+ `Alert: ${
204
+ stats.bySeverity[AlertSeverity.CRITICAL]
205
+ } critical alerts require immediate attention`
206
+ );
207
+ }
208
+
209
+ // Issue monitoring
210
+ if (stats.overdue > 0) {
211
+ console.warn(`Alert: ${stats.overdue} overdue issues require attention`);
212
+ }
213
+ ```
214
+
215
+ ## Best Practices
216
+
217
+ ### 1. **Use Service Layer for Business Logic**
218
+
219
+ Always use the service layer for operations that involve business rules, validation, or workflow management.
220
+
221
+ ### 2. **Use Repository Layer for Data Access**
222
+
223
+ Use the repository layer for direct data access operations, bulk operations, and complex queries.
224
+
225
+ ### 3. **Validate Input Data**
226
+
227
+ Always validate input data before processing to ensure data integrity.
228
+
229
+ ### 4. **Handle Errors Gracefully**
230
+
231
+ Use try-catch blocks and provide meaningful error messages for better debugging.
232
+
233
+ ### 5. **Use Soft Deletion**
234
+
235
+ Always use soft deletion unless explicitly required to permanently remove data.
236
+
237
+ ### 6. **Monitor Important Events**
238
+
239
+ Implement logging for critical events like overdue issues, critical alerts, and status changes.
240
+
241
+ ### 7. **Use TypeScript Interfaces**
242
+
243
+ Leverage TypeScript interfaces for type safety and better development experience.
244
+
245
+ ### 8. **Follow Naming Conventions**
246
+
247
+ Use consistent naming conventions across all layers for better maintainability.
248
+
249
+ ### 9. **Document Business Rules**
250
+
251
+ Clearly document business rules and validation logic for future reference.
252
+
253
+ ### 10. **Test Business Logic**
254
+
255
+ Write tests for business logic to ensure rules are correctly implemented.
256
+
257
+ ## Migration from Prisma
258
+
259
+ Both models maintain full compatibility with their original Prisma schemas:
260
+
261
+ - ✅ All fields and types preserved
262
+ - ✅ Indexes match Prisma schema
263
+ - ✅ Relationships maintained through foreign key references
264
+ - ✅ Collection names match Prisma (`dt_alerts`, `dt_issues`)
265
+
266
+ Additional features beyond Prisma:
267
+
268
+ - ✅ Instance methods for common operations
269
+ - ✅ Static methods for complex queries
270
+ - ✅ Virtual fields for computed properties
271
+ - ✅ Comprehensive business logic validation
272
+ - ✅ Built-in monitoring and logging
273
+ - ✅ Comment management system (Issues)
274
+ - ✅ Snooze functionality (Alerts)
275
+ - ✅ Overdue calculation logic (Issues)
276
+
277
+ ## Quick Start
278
+
279
+ 1. **Import Services**:
280
+
281
+ ```typescript
282
+ import { AlertService, IssueService } from "../services";
283
+ ```
284
+
285
+ 2. **Create Instances**:
286
+
287
+ ```typescript
288
+ const alertService = new AlertService();
289
+ const issueService = new IssueService();
290
+ ```
291
+
292
+ 3. **Use Business Logic**:
293
+
294
+ ```typescript
295
+ // Create alert with automatic severity assignment
296
+ const alert = await alertService.createAlert(alertData);
297
+
298
+ // Create issue with workflow validation
299
+ const issue = await issueService.createIssue(issueData);
300
+ ```
301
+
302
+ 4. **Monitor and Report**:
303
+ ```typescript
304
+ // Get statistics
305
+ const alertStats = await alertService.getAlertStatistics();
306
+ const issueStats = await issueService.getIssueStatistics();
307
+ ```
308
+
309
+ For detailed usage examples and advanced features, refer to the individual model documentation:
310
+
311
+ - [Alert Model Documentation](./Alert.model.md)
312
+ - [Issue Model Documentation](./Issue.model.md)