@checkstack/incident-backend 0.4.25 → 0.5.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @checkstack/incident-backend
2
2
 
3
+ ## 0.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @checkstack/catalog-common@1.5.1
8
+ - @checkstack/incident-common@0.4.8
9
+ - @checkstack/catalog-backend@0.6.1
10
+
11
+ ## 0.5.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 298bf42: ### Notification System Optimizations
16
+
17
+ **System context in notifications**: All notification senders (healthcheck, incident, maintenance, dependency) now include the affected system name in the notification title and body. Users can immediately identify which system is affected without clicking through to the detail page.
18
+
19
+ **Upstream notification deduplication**: When an upstream dependency goes down affecting multiple downstream systems, the dependency notification sidecar now sends **one personalized notification per user** instead of one notification per affected system. Each user's notification lists only the systems they are subscribed to, with a link to the upstream root cause system. This prevents notification floods for users subscribed to groups containing many dependent systems.
20
+
21
+ **New catalog endpoint**: Added `getSystemGroupIds` S2S RPC endpoint on the catalog to resolve which catalog groups contain a given system, used by the dependency plugin for efficient subscriber resolution during batched notification dispatch.
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [298bf42]
26
+ - @checkstack/catalog-common@1.5.0
27
+ - @checkstack/catalog-backend@0.6.0
28
+
3
29
  ## 0.4.25
4
30
 
5
31
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/incident-backend",
3
- "version": "0.4.25",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "checkstack": {
@@ -16,7 +16,7 @@
16
16
  "@checkstack/backend-api": "0.12.0",
17
17
  "@checkstack/incident-common": "0.4.7",
18
18
  "@checkstack/catalog-common": "1.4.1",
19
- "@checkstack/catalog-backend": "0.5.1",
19
+ "@checkstack/catalog-backend": "0.5.4",
20
20
  "@checkstack/auth-common": "0.6.2",
21
21
  "@checkstack/command-backend": "0.1.19",
22
22
  "@checkstack/signal-common": "0.1.9",
@@ -115,7 +115,7 @@ describe("notifyAffectedSystems", () => {
115
115
 
116
116
  expect(mockCatalogClient.notifySystemSubscribers).toHaveBeenCalledWith(
117
117
  expect.objectContaining({
118
- title: "Incident reported",
118
+ title: "Incident reported: sys-1",
119
119
  body: expect.stringContaining("reported"),
120
120
  }),
121
121
  );
@@ -134,7 +134,7 @@ describe("notifyAffectedSystems", () => {
134
134
 
135
135
  expect(mockCatalogClient.notifySystemSubscribers).toHaveBeenCalledWith(
136
136
  expect.objectContaining({
137
- title: "Incident reopened",
137
+ title: "Incident reopened: sys-1",
138
138
  body: expect.stringContaining("reopened"),
139
139
  }),
140
140
  );
@@ -180,4 +180,50 @@ describe("notifyAffectedSystems", () => {
180
180
  expect(mockLogger.warn).toHaveBeenCalled();
181
181
  });
182
182
  });
183
+
184
+ describe("system name inclusion", () => {
185
+ it("should include system name in title and body when systemNames map is provided", async () => {
186
+ const systemNames = new Map([
187
+ ["sys-1", "Production Database"],
188
+ ]);
189
+
190
+ await notifyAffectedSystems({
191
+ catalogClient: mockCatalogClient as never,
192
+ logger: mockLogger as never,
193
+ incidentId: "inc-1",
194
+ incidentTitle: "DB Outage",
195
+ systemIds: ["sys-1"],
196
+ systemNames,
197
+ action: "created",
198
+ severity: "critical",
199
+ });
200
+
201
+ expect(mockCatalogClient.notifySystemSubscribers).toHaveBeenCalledWith(
202
+ expect.objectContaining({
203
+ title: "Incident reported: Production Database",
204
+ body: expect.stringContaining("**Production Database**"),
205
+ }),
206
+ );
207
+ });
208
+
209
+ it("should fall back to systemId when systemNames map is not provided", async () => {
210
+ await notifyAffectedSystems({
211
+ catalogClient: mockCatalogClient as never,
212
+ logger: mockLogger as never,
213
+ incidentId: "inc-1",
214
+ incidentTitle: "Test Incident",
215
+ systemIds: ["sys-1"],
216
+ action: "resolved",
217
+ severity: "minor",
218
+ });
219
+
220
+ expect(mockCatalogClient.notifySystemSubscribers).toHaveBeenCalledWith(
221
+ expect.objectContaining({
222
+ title: "Incident resolved: sys-1",
223
+ body: expect.stringContaining("**sys-1**"),
224
+ }),
225
+ );
226
+ });
227
+ });
183
228
  });
229
+
@@ -39,6 +39,7 @@ export async function notifyAffectedSystems(props: {
39
39
  incidentId: string;
40
40
  incidentTitle: string;
41
41
  systemIds: string[];
42
+ systemNames?: Map<string, string>;
42
43
  action: "created" | "updated" | "resolved" | "reopened";
43
44
  severity: string;
44
45
  }): Promise<void> {
@@ -48,6 +49,7 @@ export async function notifyAffectedSystems(props: {
48
49
  incidentId,
49
50
  incidentTitle,
50
51
  systemIds,
52
+ systemNames,
51
53
  action,
52
54
  severity,
53
55
  } = props;
@@ -69,11 +71,14 @@ export async function notifyAffectedSystems(props: {
69
71
  const uniqueSystemIds = [...new Set(systemIds)];
70
72
 
71
73
  for (const systemId of uniqueSystemIds) {
74
+ // Resolve system name from provided map, or fall back to systemId
75
+ const systemName = systemNames?.get(systemId) ?? systemId;
76
+
72
77
  try {
73
78
  await catalogClient.notifySystemSubscribers({
74
79
  systemId,
75
- title: `Incident ${actionText}`,
76
- body: `Incident **"${incidentTitle}"** has been ${actionText} for a system you're subscribed to.`,
80
+ title: `Incident ${actionText}: ${systemName}`,
81
+ body: `Incident **"${incidentTitle}"** has been ${actionText} affecting **${systemName}**.`,
77
82
  importance,
78
83
  action: { label: "View Incident", url: incidentDetailPath },
79
84
  includeGroupSubscribers: true,
@@ -87,3 +92,4 @@ export async function notifyAffectedSystems(props: {
87
92
  }
88
93
  }
89
94
  }
95
+