@checkstack/incident-backend 1.12.0 → 1.13.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 +88 -0
- package/drizzle/0007_colorful_true_believers.sql +2 -0
- package/drizzle/meta/0007_snapshot.json +391 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +15 -15
- package/src/schema.ts +39 -21
- package/src/status-page-widget.ts +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,93 @@
|
|
|
1
1
|
# @checkstack/incident-backend
|
|
2
2
|
|
|
3
|
+
## 1.13.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [1f20b5a]
|
|
8
|
+
- Updated dependencies [5e704cd]
|
|
9
|
+
- @checkstack/ai-backend@0.10.12
|
|
10
|
+
- @checkstack/automation-backend@0.11.3
|
|
11
|
+
- @checkstack/catalog-backend@1.8.1
|
|
12
|
+
- @checkstack/catalog-common@2.7.2
|
|
13
|
+
- @checkstack/incident-common@1.10.2
|
|
14
|
+
- @checkstack/status-page-common@0.6.2
|
|
15
|
+
- @checkstack/backend-api@0.32.1
|
|
16
|
+
- @checkstack/status-page-backend@0.6.1
|
|
17
|
+
- @checkstack/command-backend@0.2.24
|
|
18
|
+
- @checkstack/integration-backend@0.7.6
|
|
19
|
+
|
|
20
|
+
## 1.13.0
|
|
21
|
+
|
|
22
|
+
### Minor Changes
|
|
23
|
+
|
|
24
|
+
- bd41130: perf(incident): add indexes for reverse system lookup and update status derivation
|
|
25
|
+
|
|
26
|
+
Add two Postgres indexes to speed up hot read paths:
|
|
27
|
+
|
|
28
|
+
- `incident_systems_system_idx` on `incident_systems (system_id)` - the junction
|
|
29
|
+
primary key leads with `incident_id`, leaving the `system_id` direction
|
|
30
|
+
unindexed. This index serves the reverse lookup used by
|
|
31
|
+
`getIncidentsForSystem` / `getActiveHealthOverrides`, which fans out per
|
|
32
|
+
system on every status-page render.
|
|
33
|
+
- `incident_updates_incident_created_idx` on
|
|
34
|
+
`incident_updates (incident_id, created_at)` - serves the status-derivation
|
|
35
|
+
query (`WHERE incident_id, status_change IS NOT NULL ORDER BY created_at DESC
|
|
36
|
+
LIMIT 1`) and the bulk timeline fetch.
|
|
37
|
+
|
|
38
|
+
- bd41130: fix(status-page): scope email subscriptions to published environments and author-selected systems
|
|
39
|
+
|
|
40
|
+
Two correctness fixes to status-page email subscriptions:
|
|
41
|
+
|
|
42
|
+
- **Health notifications now respect the page's published environments.** A
|
|
43
|
+
per-environment health transition carries the environment it happened in
|
|
44
|
+
(`originEnvironmentId`, threaded through `notifyForSubscription` ->
|
|
45
|
+
`NotificationAudienceEvent` -> the status-page fan-out). A page that publishes
|
|
46
|
+
a specific environment set is now skipped for a change in an environment it
|
|
47
|
+
does not publish - so a `development` failure never emails a prod-only page's
|
|
48
|
+
subscribers, even for a system that is also shown in prod. Pages publishing all
|
|
49
|
+
environments, and env-less sources (incident, maintenance, whole-system health
|
|
50
|
+
rollup), are unaffected.
|
|
51
|
+
- **Notifications are scoped per category to the widgets the author placed.** The
|
|
52
|
+
send-time fan-out now surfaces a notification only through widgets of its own
|
|
53
|
+
category: a health status change reaches a page only through a HEALTH widget
|
|
54
|
+
(`banner` / `systemHealth` / `groupStatus` / `uptime`, which now implement
|
|
55
|
+
`resolveScopedSystems` and declare `subscriptionCategory: "health"`), an
|
|
56
|
+
incident only through an incident widget, and so on. A page that lists a
|
|
57
|
+
system's incidents but never its health no longer emails health subscribers
|
|
58
|
+
about it, and a health-only page now correctly surfaces its systems for
|
|
59
|
+
subscription. Health widgets also participate in the public subscribe picker.
|
|
60
|
+
|
|
61
|
+
BREAKING CHANGE: on a page publishing a specific environment set, health
|
|
62
|
+
subscribers now only receive changes that occurred in a published environment
|
|
63
|
+
(previously any environment of a surfaced system triggered a notification), and a
|
|
64
|
+
notification is surfaced only by a widget of its own category (previously any
|
|
65
|
+
scoping widget on the page could surface any category). Legacy subscribers (NULL
|
|
66
|
+
categories) and all-environment pages are unchanged; no data migration is needed.
|
|
67
|
+
|
|
68
|
+
### Patch Changes
|
|
69
|
+
|
|
70
|
+
- Updated dependencies [bd41130]
|
|
71
|
+
- Updated dependencies [bd41130]
|
|
72
|
+
- Updated dependencies [bd41130]
|
|
73
|
+
- Updated dependencies [bd41130]
|
|
74
|
+
- Updated dependencies [bd41130]
|
|
75
|
+
- Updated dependencies [bd41130]
|
|
76
|
+
- Updated dependencies [bd41130]
|
|
77
|
+
- @checkstack/backend-api@0.32.0
|
|
78
|
+
- @checkstack/auth-common@0.14.0
|
|
79
|
+
- @checkstack/cache-utils@0.3.0
|
|
80
|
+
- @checkstack/catalog-backend@1.8.0
|
|
81
|
+
- @checkstack/ai-backend@0.10.11
|
|
82
|
+
- @checkstack/notification-common@1.7.0
|
|
83
|
+
- @checkstack/status-page-backend@0.6.0
|
|
84
|
+
- @checkstack/automation-backend@0.11.2
|
|
85
|
+
- @checkstack/command-backend@0.2.23
|
|
86
|
+
- @checkstack/integration-backend@0.7.5
|
|
87
|
+
- @checkstack/catalog-common@2.7.1
|
|
88
|
+
- @checkstack/incident-common@1.10.1
|
|
89
|
+
- @checkstack/status-page-common@0.6.1
|
|
90
|
+
|
|
3
91
|
## 1.12.0
|
|
4
92
|
|
|
5
93
|
### Minor Changes
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "a430b9d2-36ed-4c87-a41a-6f9e2a7517c7",
|
|
3
|
+
"prevId": "ff7f73e0-3d6b-47a4-b759-000739af4ee6",
|
|
4
|
+
"version": "7",
|
|
5
|
+
"dialect": "postgresql",
|
|
6
|
+
"tables": {
|
|
7
|
+
"public.incident_links": {
|
|
8
|
+
"name": "incident_links",
|
|
9
|
+
"schema": "",
|
|
10
|
+
"columns": {
|
|
11
|
+
"id": {
|
|
12
|
+
"name": "id",
|
|
13
|
+
"type": "text",
|
|
14
|
+
"primaryKey": true,
|
|
15
|
+
"notNull": true
|
|
16
|
+
},
|
|
17
|
+
"incident_id": {
|
|
18
|
+
"name": "incident_id",
|
|
19
|
+
"type": "text",
|
|
20
|
+
"primaryKey": false,
|
|
21
|
+
"notNull": true
|
|
22
|
+
},
|
|
23
|
+
"label": {
|
|
24
|
+
"name": "label",
|
|
25
|
+
"type": "text",
|
|
26
|
+
"primaryKey": false,
|
|
27
|
+
"notNull": false
|
|
28
|
+
},
|
|
29
|
+
"url": {
|
|
30
|
+
"name": "url",
|
|
31
|
+
"type": "text",
|
|
32
|
+
"primaryKey": false,
|
|
33
|
+
"notNull": true
|
|
34
|
+
},
|
|
35
|
+
"visibility": {
|
|
36
|
+
"name": "visibility",
|
|
37
|
+
"type": "incident_content_visibility",
|
|
38
|
+
"typeSchema": "public",
|
|
39
|
+
"primaryKey": false,
|
|
40
|
+
"notNull": true,
|
|
41
|
+
"default": "'public'"
|
|
42
|
+
},
|
|
43
|
+
"created_at": {
|
|
44
|
+
"name": "created_at",
|
|
45
|
+
"type": "timestamp",
|
|
46
|
+
"primaryKey": false,
|
|
47
|
+
"notNull": true,
|
|
48
|
+
"default": "now()"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"indexes": {
|
|
52
|
+
"incident_links_incident_url_unique": {
|
|
53
|
+
"name": "incident_links_incident_url_unique",
|
|
54
|
+
"columns": [
|
|
55
|
+
{
|
|
56
|
+
"expression": "incident_id",
|
|
57
|
+
"isExpression": false,
|
|
58
|
+
"asc": true,
|
|
59
|
+
"nulls": "last"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"expression": "url",
|
|
63
|
+
"isExpression": false,
|
|
64
|
+
"asc": true,
|
|
65
|
+
"nulls": "last"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"isUnique": true,
|
|
69
|
+
"concurrently": false,
|
|
70
|
+
"method": "btree",
|
|
71
|
+
"with": {}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"foreignKeys": {
|
|
75
|
+
"incident_links_incident_id_incidents_id_fk": {
|
|
76
|
+
"name": "incident_links_incident_id_incidents_id_fk",
|
|
77
|
+
"tableFrom": "incident_links",
|
|
78
|
+
"tableTo": "incidents",
|
|
79
|
+
"columnsFrom": [
|
|
80
|
+
"incident_id"
|
|
81
|
+
],
|
|
82
|
+
"columnsTo": [
|
|
83
|
+
"id"
|
|
84
|
+
],
|
|
85
|
+
"onDelete": "cascade",
|
|
86
|
+
"onUpdate": "no action"
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"compositePrimaryKeys": {},
|
|
90
|
+
"uniqueConstraints": {},
|
|
91
|
+
"policies": {},
|
|
92
|
+
"checkConstraints": {},
|
|
93
|
+
"isRLSEnabled": false
|
|
94
|
+
},
|
|
95
|
+
"public.incident_systems": {
|
|
96
|
+
"name": "incident_systems",
|
|
97
|
+
"schema": "",
|
|
98
|
+
"columns": {
|
|
99
|
+
"incident_id": {
|
|
100
|
+
"name": "incident_id",
|
|
101
|
+
"type": "text",
|
|
102
|
+
"primaryKey": false,
|
|
103
|
+
"notNull": true
|
|
104
|
+
},
|
|
105
|
+
"system_id": {
|
|
106
|
+
"name": "system_id",
|
|
107
|
+
"type": "text",
|
|
108
|
+
"primaryKey": false,
|
|
109
|
+
"notNull": true
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"indexes": {
|
|
113
|
+
"incident_systems_system_idx": {
|
|
114
|
+
"name": "incident_systems_system_idx",
|
|
115
|
+
"columns": [
|
|
116
|
+
{
|
|
117
|
+
"expression": "system_id",
|
|
118
|
+
"isExpression": false,
|
|
119
|
+
"asc": true,
|
|
120
|
+
"nulls": "last"
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"isUnique": false,
|
|
124
|
+
"concurrently": false,
|
|
125
|
+
"method": "btree",
|
|
126
|
+
"with": {}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"foreignKeys": {
|
|
130
|
+
"incident_systems_incident_id_incidents_id_fk": {
|
|
131
|
+
"name": "incident_systems_incident_id_incidents_id_fk",
|
|
132
|
+
"tableFrom": "incident_systems",
|
|
133
|
+
"tableTo": "incidents",
|
|
134
|
+
"columnsFrom": [
|
|
135
|
+
"incident_id"
|
|
136
|
+
],
|
|
137
|
+
"columnsTo": [
|
|
138
|
+
"id"
|
|
139
|
+
],
|
|
140
|
+
"onDelete": "cascade",
|
|
141
|
+
"onUpdate": "no action"
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"compositePrimaryKeys": {
|
|
145
|
+
"incident_systems_incident_id_system_id_pk": {
|
|
146
|
+
"name": "incident_systems_incident_id_system_id_pk",
|
|
147
|
+
"columns": [
|
|
148
|
+
"incident_id",
|
|
149
|
+
"system_id"
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"uniqueConstraints": {},
|
|
154
|
+
"policies": {},
|
|
155
|
+
"checkConstraints": {},
|
|
156
|
+
"isRLSEnabled": false
|
|
157
|
+
},
|
|
158
|
+
"public.incident_updates": {
|
|
159
|
+
"name": "incident_updates",
|
|
160
|
+
"schema": "",
|
|
161
|
+
"columns": {
|
|
162
|
+
"id": {
|
|
163
|
+
"name": "id",
|
|
164
|
+
"type": "text",
|
|
165
|
+
"primaryKey": true,
|
|
166
|
+
"notNull": true
|
|
167
|
+
},
|
|
168
|
+
"incident_id": {
|
|
169
|
+
"name": "incident_id",
|
|
170
|
+
"type": "text",
|
|
171
|
+
"primaryKey": false,
|
|
172
|
+
"notNull": true
|
|
173
|
+
},
|
|
174
|
+
"message": {
|
|
175
|
+
"name": "message",
|
|
176
|
+
"type": "text",
|
|
177
|
+
"primaryKey": false,
|
|
178
|
+
"notNull": true
|
|
179
|
+
},
|
|
180
|
+
"status_change": {
|
|
181
|
+
"name": "status_change",
|
|
182
|
+
"type": "incident_status",
|
|
183
|
+
"typeSchema": "public",
|
|
184
|
+
"primaryKey": false,
|
|
185
|
+
"notNull": false
|
|
186
|
+
},
|
|
187
|
+
"visibility": {
|
|
188
|
+
"name": "visibility",
|
|
189
|
+
"type": "incident_content_visibility",
|
|
190
|
+
"typeSchema": "public",
|
|
191
|
+
"primaryKey": false,
|
|
192
|
+
"notNull": true,
|
|
193
|
+
"default": "'public'"
|
|
194
|
+
},
|
|
195
|
+
"created_at": {
|
|
196
|
+
"name": "created_at",
|
|
197
|
+
"type": "timestamp",
|
|
198
|
+
"primaryKey": false,
|
|
199
|
+
"notNull": true,
|
|
200
|
+
"default": "now()"
|
|
201
|
+
},
|
|
202
|
+
"edited_at": {
|
|
203
|
+
"name": "edited_at",
|
|
204
|
+
"type": "timestamp",
|
|
205
|
+
"primaryKey": false,
|
|
206
|
+
"notNull": false
|
|
207
|
+
},
|
|
208
|
+
"edit_history": {
|
|
209
|
+
"name": "edit_history",
|
|
210
|
+
"type": "jsonb",
|
|
211
|
+
"primaryKey": false,
|
|
212
|
+
"notNull": true,
|
|
213
|
+
"default": "'[]'::jsonb"
|
|
214
|
+
},
|
|
215
|
+
"created_by": {
|
|
216
|
+
"name": "created_by",
|
|
217
|
+
"type": "text",
|
|
218
|
+
"primaryKey": false,
|
|
219
|
+
"notNull": false
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
"indexes": {
|
|
223
|
+
"incident_updates_incident_created_idx": {
|
|
224
|
+
"name": "incident_updates_incident_created_idx",
|
|
225
|
+
"columns": [
|
|
226
|
+
{
|
|
227
|
+
"expression": "incident_id",
|
|
228
|
+
"isExpression": false,
|
|
229
|
+
"asc": true,
|
|
230
|
+
"nulls": "last"
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"expression": "created_at",
|
|
234
|
+
"isExpression": false,
|
|
235
|
+
"asc": true,
|
|
236
|
+
"nulls": "last"
|
|
237
|
+
}
|
|
238
|
+
],
|
|
239
|
+
"isUnique": false,
|
|
240
|
+
"concurrently": false,
|
|
241
|
+
"method": "btree",
|
|
242
|
+
"with": {}
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
"foreignKeys": {
|
|
246
|
+
"incident_updates_incident_id_incidents_id_fk": {
|
|
247
|
+
"name": "incident_updates_incident_id_incidents_id_fk",
|
|
248
|
+
"tableFrom": "incident_updates",
|
|
249
|
+
"tableTo": "incidents",
|
|
250
|
+
"columnsFrom": [
|
|
251
|
+
"incident_id"
|
|
252
|
+
],
|
|
253
|
+
"columnsTo": [
|
|
254
|
+
"id"
|
|
255
|
+
],
|
|
256
|
+
"onDelete": "cascade",
|
|
257
|
+
"onUpdate": "no action"
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
"compositePrimaryKeys": {},
|
|
261
|
+
"uniqueConstraints": {},
|
|
262
|
+
"policies": {},
|
|
263
|
+
"checkConstraints": {},
|
|
264
|
+
"isRLSEnabled": false
|
|
265
|
+
},
|
|
266
|
+
"public.incidents": {
|
|
267
|
+
"name": "incidents",
|
|
268
|
+
"schema": "",
|
|
269
|
+
"columns": {
|
|
270
|
+
"id": {
|
|
271
|
+
"name": "id",
|
|
272
|
+
"type": "text",
|
|
273
|
+
"primaryKey": true,
|
|
274
|
+
"notNull": true
|
|
275
|
+
},
|
|
276
|
+
"title": {
|
|
277
|
+
"name": "title",
|
|
278
|
+
"type": "text",
|
|
279
|
+
"primaryKey": false,
|
|
280
|
+
"notNull": true
|
|
281
|
+
},
|
|
282
|
+
"description": {
|
|
283
|
+
"name": "description",
|
|
284
|
+
"type": "text",
|
|
285
|
+
"primaryKey": false,
|
|
286
|
+
"notNull": false
|
|
287
|
+
},
|
|
288
|
+
"status": {
|
|
289
|
+
"name": "status",
|
|
290
|
+
"type": "incident_status",
|
|
291
|
+
"typeSchema": "public",
|
|
292
|
+
"primaryKey": false,
|
|
293
|
+
"notNull": true,
|
|
294
|
+
"default": "'investigating'"
|
|
295
|
+
},
|
|
296
|
+
"severity": {
|
|
297
|
+
"name": "severity",
|
|
298
|
+
"type": "incident_severity",
|
|
299
|
+
"typeSchema": "public",
|
|
300
|
+
"primaryKey": false,
|
|
301
|
+
"notNull": true,
|
|
302
|
+
"default": "'major'"
|
|
303
|
+
},
|
|
304
|
+
"suppress_notifications": {
|
|
305
|
+
"name": "suppress_notifications",
|
|
306
|
+
"type": "boolean",
|
|
307
|
+
"primaryKey": false,
|
|
308
|
+
"notNull": true,
|
|
309
|
+
"default": false
|
|
310
|
+
},
|
|
311
|
+
"health_override": {
|
|
312
|
+
"name": "health_override",
|
|
313
|
+
"type": "incident_health_override",
|
|
314
|
+
"typeSchema": "public",
|
|
315
|
+
"primaryKey": false,
|
|
316
|
+
"notNull": false
|
|
317
|
+
},
|
|
318
|
+
"created_at": {
|
|
319
|
+
"name": "created_at",
|
|
320
|
+
"type": "timestamp",
|
|
321
|
+
"primaryKey": false,
|
|
322
|
+
"notNull": true,
|
|
323
|
+
"default": "now()"
|
|
324
|
+
},
|
|
325
|
+
"updated_at": {
|
|
326
|
+
"name": "updated_at",
|
|
327
|
+
"type": "timestamp",
|
|
328
|
+
"primaryKey": false,
|
|
329
|
+
"notNull": true,
|
|
330
|
+
"default": "now()"
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
"indexes": {},
|
|
334
|
+
"foreignKeys": {},
|
|
335
|
+
"compositePrimaryKeys": {},
|
|
336
|
+
"uniqueConstraints": {},
|
|
337
|
+
"policies": {},
|
|
338
|
+
"checkConstraints": {},
|
|
339
|
+
"isRLSEnabled": false
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
"enums": {
|
|
343
|
+
"public.incident_health_override": {
|
|
344
|
+
"name": "incident_health_override",
|
|
345
|
+
"schema": "public",
|
|
346
|
+
"values": [
|
|
347
|
+
"degraded",
|
|
348
|
+
"unhealthy"
|
|
349
|
+
]
|
|
350
|
+
},
|
|
351
|
+
"public.incident_severity": {
|
|
352
|
+
"name": "incident_severity",
|
|
353
|
+
"schema": "public",
|
|
354
|
+
"values": [
|
|
355
|
+
"minor",
|
|
356
|
+
"major",
|
|
357
|
+
"critical"
|
|
358
|
+
]
|
|
359
|
+
},
|
|
360
|
+
"public.incident_status": {
|
|
361
|
+
"name": "incident_status",
|
|
362
|
+
"schema": "public",
|
|
363
|
+
"values": [
|
|
364
|
+
"investigating",
|
|
365
|
+
"identified",
|
|
366
|
+
"fixing",
|
|
367
|
+
"monitoring",
|
|
368
|
+
"resolved"
|
|
369
|
+
]
|
|
370
|
+
},
|
|
371
|
+
"public.incident_content_visibility": {
|
|
372
|
+
"name": "incident_content_visibility",
|
|
373
|
+
"schema": "public",
|
|
374
|
+
"values": [
|
|
375
|
+
"public",
|
|
376
|
+
"logged_in",
|
|
377
|
+
"internal"
|
|
378
|
+
]
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
"schemas": {},
|
|
382
|
+
"sequences": {},
|
|
383
|
+
"roles": {},
|
|
384
|
+
"policies": {},
|
|
385
|
+
"views": {},
|
|
386
|
+
"_meta": {
|
|
387
|
+
"columns": {},
|
|
388
|
+
"schemas": {},
|
|
389
|
+
"tables": {}
|
|
390
|
+
}
|
|
391
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/incident-backend",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.1",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -14,23 +14,23 @@
|
|
|
14
14
|
"lint:code": "eslint . --max-warnings 0"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@checkstack/ai-backend": "0.10.
|
|
17
|
+
"@checkstack/ai-backend": "0.10.12",
|
|
18
18
|
"@checkstack/ai-common": "0.6.6",
|
|
19
|
-
"@checkstack/backend-api": "0.
|
|
19
|
+
"@checkstack/backend-api": "0.32.1",
|
|
20
20
|
"@checkstack/cache-api": "0.3.19",
|
|
21
|
-
"@checkstack/cache-utils": "0.
|
|
22
|
-
"@checkstack/incident-common": "1.10.
|
|
23
|
-
"@checkstack/catalog-common": "2.7.
|
|
24
|
-
"@checkstack/catalog-backend": "1.
|
|
25
|
-
"@checkstack/notification-common": "1.
|
|
26
|
-
"@checkstack/auth-common": "0.
|
|
27
|
-
"@checkstack/command-backend": "0.2.
|
|
21
|
+
"@checkstack/cache-utils": "0.3.0",
|
|
22
|
+
"@checkstack/incident-common": "1.10.2",
|
|
23
|
+
"@checkstack/catalog-common": "2.7.2",
|
|
24
|
+
"@checkstack/catalog-backend": "1.8.1",
|
|
25
|
+
"@checkstack/notification-common": "1.7.0",
|
|
26
|
+
"@checkstack/auth-common": "0.14.0",
|
|
27
|
+
"@checkstack/command-backend": "0.2.24",
|
|
28
28
|
"@checkstack/signal-common": "0.2.17",
|
|
29
|
-
"@checkstack/status-page-backend": "0.
|
|
30
|
-
"@checkstack/status-page-common": "0.6.
|
|
31
|
-
"@checkstack/integration-backend": "0.7.
|
|
29
|
+
"@checkstack/status-page-backend": "0.6.1",
|
|
30
|
+
"@checkstack/status-page-common": "0.6.2",
|
|
31
|
+
"@checkstack/integration-backend": "0.7.6",
|
|
32
32
|
"@checkstack/integration-common": "0.9.8",
|
|
33
|
-
"@checkstack/automation-backend": "0.11.
|
|
33
|
+
"@checkstack/automation-backend": "0.11.3",
|
|
34
34
|
"@checkstack/automation-common": "0.10.0",
|
|
35
35
|
"@checkstack/common": "0.22.0",
|
|
36
36
|
"drizzle-orm": "^0.45.0",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@checkstack/drizzle-helper": "0.0.6",
|
|
43
43
|
"@checkstack/scripts": "0.7.3",
|
|
44
|
-
"@checkstack/test-utils-backend": "0.1.
|
|
44
|
+
"@checkstack/test-utils-backend": "0.1.58",
|
|
45
45
|
"@checkstack/tsconfig": "0.0.7",
|
|
46
46
|
"@types/bun": "^1.0.0",
|
|
47
47
|
"@types/pg": "^8.20.0",
|
package/src/schema.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
primaryKey,
|
|
7
7
|
boolean,
|
|
8
8
|
uniqueIndex,
|
|
9
|
+
index,
|
|
9
10
|
jsonb,
|
|
10
11
|
} from "drizzle-orm/pg-core";
|
|
11
12
|
import type { IncidentUpdateEditSnapshot } from "@checkstack/incident-common";
|
|
@@ -82,33 +83,50 @@ export const incidentSystems = pgTable(
|
|
|
82
83
|
},
|
|
83
84
|
(t) => ({
|
|
84
85
|
pk: primaryKey(t.incidentId, t.systemId),
|
|
86
|
+
// Reverse lookup (getIncidentsForSystem / getActiveHealthOverrides): the PK
|
|
87
|
+
// leads with incident_id, so the system_id direction is otherwise unindexed
|
|
88
|
+
// and fans out per system per status-page render.
|
|
89
|
+
systemIdx: index("incident_systems_system_idx").on(t.systemId),
|
|
85
90
|
}),
|
|
86
91
|
);
|
|
87
92
|
|
|
88
93
|
/**
|
|
89
94
|
* Status updates for incidents
|
|
90
95
|
*/
|
|
91
|
-
export const incidentUpdates = pgTable(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
96
|
+
export const incidentUpdates = pgTable(
|
|
97
|
+
"incident_updates",
|
|
98
|
+
{
|
|
99
|
+
id: text("id").primaryKey(),
|
|
100
|
+
incidentId: text("incident_id")
|
|
101
|
+
.notNull()
|
|
102
|
+
.references(() => incidents.id, { onDelete: "cascade" }),
|
|
103
|
+
message: text("message").notNull(),
|
|
104
|
+
statusChange: incidentStatusEnum("status_change"),
|
|
105
|
+
visibility: incidentVisibilityEnum("visibility")
|
|
106
|
+
.notNull()
|
|
107
|
+
.default("public"),
|
|
108
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
109
|
+
// Set when the update is edited in place (null = never edited).
|
|
110
|
+
editedAt: timestamp("edited_at"),
|
|
111
|
+
// Prior versions archived on each in-place edit (oldest first). Durable,
|
|
112
|
+
// globally-readable history of edits (jsonb, defaults to an empty array so
|
|
113
|
+
// existing rows backfill cleanly). Manager-facing; the read path strips it
|
|
114
|
+
// for non-manager audiences (see read-visibility).
|
|
115
|
+
editHistory: jsonb("edit_history")
|
|
116
|
+
.$type<IncidentUpdateEditSnapshot[]>()
|
|
117
|
+
.notNull()
|
|
118
|
+
.default([]),
|
|
119
|
+
createdBy: text("created_by"),
|
|
120
|
+
},
|
|
121
|
+
(t) => ({
|
|
122
|
+
// Serves the status-derivation query (WHERE incident_id, status_change IS
|
|
123
|
+
// NOT NULL ORDER BY created_at DESC LIMIT 1) and the bulk timeline fetch.
|
|
124
|
+
incidentCreatedIdx: index("incident_updates_incident_created_idx").on(
|
|
125
|
+
t.incidentId,
|
|
126
|
+
t.createdAt,
|
|
127
|
+
),
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
112
130
|
|
|
113
131
|
/**
|
|
114
132
|
* Hotlinks attached to an incident — e.g. a Jira ticket, runbook, or chat
|
|
@@ -138,6 +138,9 @@ const incidents: WidgetTypeDefinition = {
|
|
|
138
138
|
groupIds: c.groupIds,
|
|
139
139
|
});
|
|
140
140
|
},
|
|
141
|
+
// This widget surfaces the INCIDENT category: a page emails incident
|
|
142
|
+
// subscribers about a system only when this widget shows it.
|
|
143
|
+
subscriptionCategory: "incident",
|
|
141
144
|
// Send-time scoping for the subscriber fan-out uses the SAME expansion as the
|
|
142
145
|
// DTO resolve, so a page never emails about a system its widget does not show.
|
|
143
146
|
resolveScopedSystems: ({ config, ctx }) => effectiveScope(config, ctx),
|