@checkstack/dependency-backend 0.2.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/CHANGELOG.md ADDED
@@ -0,0 +1,44 @@
1
+ # @checkstack/dependency-backend
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3f36a64: Add System Dependencies plugin
8
+
9
+ Introduces the system dependencies feature with three new core plugins and
10
+ extends the catalog with a new SystemEditorSlot extension point.
11
+
12
+ **New plugins:**
13
+
14
+ - **dependency-common**: Shared Zod schemas, RPC contract with resource-level access control, signal definitions, and routes
15
+ - **dependency-backend**: Drizzle schema, DependencyService with cycle detection, WarningEvaluationService with transitive impact matrix, RPC router with signal broadcasting, and per-user canvas node position persistence
16
+ - **dependency-frontend**: DependencyBadge (dashboard), DependencyAlert (system details), DependencyEditor (system editor dialog), and interactive DependencyMapPage (React Flow canvas)
17
+
18
+ **Catalog extensions:**
19
+
20
+ - **catalog-common**: New `SystemEditorSlot` for plugin-injected sections in the system editor dialog
21
+ - **catalog-frontend**: `SystemEditor` renders the slot after TeamAccessEditor for existing systems
22
+
23
+ **Key capabilities:**
24
+
25
+ - Directional dependency edges between systems (source depends on target)
26
+ - Three impact types: informational, degraded, critical
27
+ - Transitive multi-hop warning propagation with toggle switch
28
+ - Cycle detection at creation time with graphical chain visualization
29
+ - Health check-level dependency rules
30
+ - Interactive dependency map with drag-to-connect, edge click editor, and auto-saving node positions
31
+ - Inline editing of dependencies in both the system editor and the map canvas
32
+ - Team-based resource-level access control on all mutation endpoints
33
+ - Realtime signal-driven UI updates
34
+
35
+ ### Patch Changes
36
+
37
+ - Updated dependencies [1f191cf]
38
+ - Updated dependencies [3f36a64]
39
+ - @checkstack/healthcheck-common@0.9.0
40
+ - @checkstack/healthcheck-backend@0.11.0
41
+ - @checkstack/dependency-common@0.2.0
42
+ - @checkstack/catalog-common@1.3.0
43
+ - @checkstack/backend-api@0.10.1
44
+ - @checkstack/catalog-backend@0.2.21
@@ -0,0 +1,30 @@
1
+ CREATE TYPE "impact_type" AS ENUM('informational', 'degraded', 'critical');--> statement-breakpoint
2
+ CREATE TABLE "dependencies" (
3
+ "id" text PRIMARY KEY NOT NULL,
4
+ "source_system_id" text NOT NULL,
5
+ "target_system_id" text NOT NULL,
6
+ "impact_type" "impact_type" DEFAULT 'degraded' NOT NULL,
7
+ "transitive" boolean DEFAULT false NOT NULL,
8
+ "label" text,
9
+ "created_at" timestamp DEFAULT now() NOT NULL,
10
+ "updated_at" timestamp DEFAULT now() NOT NULL,
11
+ CONSTRAINT "uq_dependency_edge" UNIQUE("source_system_id","target_system_id")
12
+ );
13
+ --> statement-breakpoint
14
+ CREATE TABLE "dependency_health_check_rules" (
15
+ "id" text PRIMARY KEY NOT NULL,
16
+ "dependency_id" text NOT NULL,
17
+ "health_check_id" text NOT NULL,
18
+ "override_impact_type" "impact_type" NOT NULL
19
+ );
20
+ --> statement-breakpoint
21
+ CREATE TABLE "node_positions" (
22
+ "id" text PRIMARY KEY NOT NULL,
23
+ "user_id" text NOT NULL,
24
+ "system_id" text NOT NULL,
25
+ "x" real NOT NULL,
26
+ "y" real NOT NULL,
27
+ "updated_at" timestamp DEFAULT now() NOT NULL
28
+ );
29
+ --> statement-breakpoint
30
+ ALTER TABLE "dependency_health_check_rules" ADD CONSTRAINT "dependency_health_check_rules_dependency_id_dependencies_id_fk" FOREIGN KEY ("dependency_id") REFERENCES "dependencies"("id") ON DELETE cascade ON UPDATE no action;
@@ -0,0 +1,5 @@
1
+ CREATE TABLE "dependency_derived_states" (
2
+ "system_id" text PRIMARY KEY NOT NULL,
3
+ "derived_state" text NOT NULL,
4
+ "updated_at" timestamp DEFAULT now() NOT NULL
5
+ );
@@ -0,0 +1,206 @@
1
+ {
2
+ "id": "0323d914-6ed6-48c8-ae0f-c16c62157ae6",
3
+ "prevId": "00000000-0000-0000-0000-000000000000",
4
+ "version": "7",
5
+ "dialect": "postgresql",
6
+ "tables": {
7
+ "public.dependencies": {
8
+ "name": "dependencies",
9
+ "schema": "",
10
+ "columns": {
11
+ "id": {
12
+ "name": "id",
13
+ "type": "text",
14
+ "primaryKey": true,
15
+ "notNull": true
16
+ },
17
+ "source_system_id": {
18
+ "name": "source_system_id",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true
22
+ },
23
+ "target_system_id": {
24
+ "name": "target_system_id",
25
+ "type": "text",
26
+ "primaryKey": false,
27
+ "notNull": true
28
+ },
29
+ "impact_type": {
30
+ "name": "impact_type",
31
+ "type": "impact_type",
32
+ "typeSchema": "public",
33
+ "primaryKey": false,
34
+ "notNull": true,
35
+ "default": "'degraded'"
36
+ },
37
+ "transitive": {
38
+ "name": "transitive",
39
+ "type": "boolean",
40
+ "primaryKey": false,
41
+ "notNull": true,
42
+ "default": false
43
+ },
44
+ "label": {
45
+ "name": "label",
46
+ "type": "text",
47
+ "primaryKey": false,
48
+ "notNull": false
49
+ },
50
+ "created_at": {
51
+ "name": "created_at",
52
+ "type": "timestamp",
53
+ "primaryKey": false,
54
+ "notNull": true,
55
+ "default": "now()"
56
+ },
57
+ "updated_at": {
58
+ "name": "updated_at",
59
+ "type": "timestamp",
60
+ "primaryKey": false,
61
+ "notNull": true,
62
+ "default": "now()"
63
+ }
64
+ },
65
+ "indexes": {},
66
+ "foreignKeys": {},
67
+ "compositePrimaryKeys": {},
68
+ "uniqueConstraints": {
69
+ "uq_dependency_edge": {
70
+ "name": "uq_dependency_edge",
71
+ "nullsNotDistinct": false,
72
+ "columns": [
73
+ "source_system_id",
74
+ "target_system_id"
75
+ ]
76
+ }
77
+ },
78
+ "policies": {},
79
+ "checkConstraints": {},
80
+ "isRLSEnabled": false
81
+ },
82
+ "public.dependency_health_check_rules": {
83
+ "name": "dependency_health_check_rules",
84
+ "schema": "",
85
+ "columns": {
86
+ "id": {
87
+ "name": "id",
88
+ "type": "text",
89
+ "primaryKey": true,
90
+ "notNull": true
91
+ },
92
+ "dependency_id": {
93
+ "name": "dependency_id",
94
+ "type": "text",
95
+ "primaryKey": false,
96
+ "notNull": true
97
+ },
98
+ "health_check_id": {
99
+ "name": "health_check_id",
100
+ "type": "text",
101
+ "primaryKey": false,
102
+ "notNull": true
103
+ },
104
+ "override_impact_type": {
105
+ "name": "override_impact_type",
106
+ "type": "impact_type",
107
+ "typeSchema": "public",
108
+ "primaryKey": false,
109
+ "notNull": true
110
+ }
111
+ },
112
+ "indexes": {},
113
+ "foreignKeys": {
114
+ "dependency_health_check_rules_dependency_id_dependencies_id_fk": {
115
+ "name": "dependency_health_check_rules_dependency_id_dependencies_id_fk",
116
+ "tableFrom": "dependency_health_check_rules",
117
+ "tableTo": "dependencies",
118
+ "columnsFrom": [
119
+ "dependency_id"
120
+ ],
121
+ "columnsTo": [
122
+ "id"
123
+ ],
124
+ "onDelete": "cascade",
125
+ "onUpdate": "no action"
126
+ }
127
+ },
128
+ "compositePrimaryKeys": {},
129
+ "uniqueConstraints": {},
130
+ "policies": {},
131
+ "checkConstraints": {},
132
+ "isRLSEnabled": false
133
+ },
134
+ "public.node_positions": {
135
+ "name": "node_positions",
136
+ "schema": "",
137
+ "columns": {
138
+ "id": {
139
+ "name": "id",
140
+ "type": "text",
141
+ "primaryKey": true,
142
+ "notNull": true
143
+ },
144
+ "user_id": {
145
+ "name": "user_id",
146
+ "type": "text",
147
+ "primaryKey": false,
148
+ "notNull": true
149
+ },
150
+ "system_id": {
151
+ "name": "system_id",
152
+ "type": "text",
153
+ "primaryKey": false,
154
+ "notNull": true
155
+ },
156
+ "x": {
157
+ "name": "x",
158
+ "type": "real",
159
+ "primaryKey": false,
160
+ "notNull": true
161
+ },
162
+ "y": {
163
+ "name": "y",
164
+ "type": "real",
165
+ "primaryKey": false,
166
+ "notNull": true
167
+ },
168
+ "updated_at": {
169
+ "name": "updated_at",
170
+ "type": "timestamp",
171
+ "primaryKey": false,
172
+ "notNull": true,
173
+ "default": "now()"
174
+ }
175
+ },
176
+ "indexes": {},
177
+ "foreignKeys": {},
178
+ "compositePrimaryKeys": {},
179
+ "uniqueConstraints": {},
180
+ "policies": {},
181
+ "checkConstraints": {},
182
+ "isRLSEnabled": false
183
+ }
184
+ },
185
+ "enums": {
186
+ "public.impact_type": {
187
+ "name": "impact_type",
188
+ "schema": "public",
189
+ "values": [
190
+ "informational",
191
+ "degraded",
192
+ "critical"
193
+ ]
194
+ }
195
+ },
196
+ "schemas": {},
197
+ "sequences": {},
198
+ "roles": {},
199
+ "policies": {},
200
+ "views": {},
201
+ "_meta": {
202
+ "columns": {},
203
+ "schemas": {},
204
+ "tables": {}
205
+ }
206
+ }
@@ -0,0 +1,238 @@
1
+ {
2
+ "id": "34392d71-c645-4176-afb9-bb37bb4c7feb",
3
+ "prevId": "0323d914-6ed6-48c8-ae0f-c16c62157ae6",
4
+ "version": "7",
5
+ "dialect": "postgresql",
6
+ "tables": {
7
+ "public.dependencies": {
8
+ "name": "dependencies",
9
+ "schema": "",
10
+ "columns": {
11
+ "id": {
12
+ "name": "id",
13
+ "type": "text",
14
+ "primaryKey": true,
15
+ "notNull": true
16
+ },
17
+ "source_system_id": {
18
+ "name": "source_system_id",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true
22
+ },
23
+ "target_system_id": {
24
+ "name": "target_system_id",
25
+ "type": "text",
26
+ "primaryKey": false,
27
+ "notNull": true
28
+ },
29
+ "impact_type": {
30
+ "name": "impact_type",
31
+ "type": "impact_type",
32
+ "typeSchema": "public",
33
+ "primaryKey": false,
34
+ "notNull": true,
35
+ "default": "'degraded'"
36
+ },
37
+ "transitive": {
38
+ "name": "transitive",
39
+ "type": "boolean",
40
+ "primaryKey": false,
41
+ "notNull": true,
42
+ "default": false
43
+ },
44
+ "label": {
45
+ "name": "label",
46
+ "type": "text",
47
+ "primaryKey": false,
48
+ "notNull": false
49
+ },
50
+ "created_at": {
51
+ "name": "created_at",
52
+ "type": "timestamp",
53
+ "primaryKey": false,
54
+ "notNull": true,
55
+ "default": "now()"
56
+ },
57
+ "updated_at": {
58
+ "name": "updated_at",
59
+ "type": "timestamp",
60
+ "primaryKey": false,
61
+ "notNull": true,
62
+ "default": "now()"
63
+ }
64
+ },
65
+ "indexes": {},
66
+ "foreignKeys": {},
67
+ "compositePrimaryKeys": {},
68
+ "uniqueConstraints": {
69
+ "uq_dependency_edge": {
70
+ "name": "uq_dependency_edge",
71
+ "nullsNotDistinct": false,
72
+ "columns": [
73
+ "source_system_id",
74
+ "target_system_id"
75
+ ]
76
+ }
77
+ },
78
+ "policies": {},
79
+ "checkConstraints": {},
80
+ "isRLSEnabled": false
81
+ },
82
+ "public.dependency_derived_states": {
83
+ "name": "dependency_derived_states",
84
+ "schema": "",
85
+ "columns": {
86
+ "system_id": {
87
+ "name": "system_id",
88
+ "type": "text",
89
+ "primaryKey": true,
90
+ "notNull": true
91
+ },
92
+ "derived_state": {
93
+ "name": "derived_state",
94
+ "type": "text",
95
+ "primaryKey": false,
96
+ "notNull": true
97
+ },
98
+ "updated_at": {
99
+ "name": "updated_at",
100
+ "type": "timestamp",
101
+ "primaryKey": false,
102
+ "notNull": true,
103
+ "default": "now()"
104
+ }
105
+ },
106
+ "indexes": {},
107
+ "foreignKeys": {},
108
+ "compositePrimaryKeys": {},
109
+ "uniqueConstraints": {},
110
+ "policies": {},
111
+ "checkConstraints": {},
112
+ "isRLSEnabled": false
113
+ },
114
+ "public.dependency_health_check_rules": {
115
+ "name": "dependency_health_check_rules",
116
+ "schema": "",
117
+ "columns": {
118
+ "id": {
119
+ "name": "id",
120
+ "type": "text",
121
+ "primaryKey": true,
122
+ "notNull": true
123
+ },
124
+ "dependency_id": {
125
+ "name": "dependency_id",
126
+ "type": "text",
127
+ "primaryKey": false,
128
+ "notNull": true
129
+ },
130
+ "health_check_id": {
131
+ "name": "health_check_id",
132
+ "type": "text",
133
+ "primaryKey": false,
134
+ "notNull": true
135
+ },
136
+ "override_impact_type": {
137
+ "name": "override_impact_type",
138
+ "type": "impact_type",
139
+ "typeSchema": "public",
140
+ "primaryKey": false,
141
+ "notNull": true
142
+ }
143
+ },
144
+ "indexes": {},
145
+ "foreignKeys": {
146
+ "dependency_health_check_rules_dependency_id_dependencies_id_fk": {
147
+ "name": "dependency_health_check_rules_dependency_id_dependencies_id_fk",
148
+ "tableFrom": "dependency_health_check_rules",
149
+ "tableTo": "dependencies",
150
+ "columnsFrom": [
151
+ "dependency_id"
152
+ ],
153
+ "columnsTo": [
154
+ "id"
155
+ ],
156
+ "onDelete": "cascade",
157
+ "onUpdate": "no action"
158
+ }
159
+ },
160
+ "compositePrimaryKeys": {},
161
+ "uniqueConstraints": {},
162
+ "policies": {},
163
+ "checkConstraints": {},
164
+ "isRLSEnabled": false
165
+ },
166
+ "public.node_positions": {
167
+ "name": "node_positions",
168
+ "schema": "",
169
+ "columns": {
170
+ "id": {
171
+ "name": "id",
172
+ "type": "text",
173
+ "primaryKey": true,
174
+ "notNull": true
175
+ },
176
+ "user_id": {
177
+ "name": "user_id",
178
+ "type": "text",
179
+ "primaryKey": false,
180
+ "notNull": true
181
+ },
182
+ "system_id": {
183
+ "name": "system_id",
184
+ "type": "text",
185
+ "primaryKey": false,
186
+ "notNull": true
187
+ },
188
+ "x": {
189
+ "name": "x",
190
+ "type": "real",
191
+ "primaryKey": false,
192
+ "notNull": true
193
+ },
194
+ "y": {
195
+ "name": "y",
196
+ "type": "real",
197
+ "primaryKey": false,
198
+ "notNull": true
199
+ },
200
+ "updated_at": {
201
+ "name": "updated_at",
202
+ "type": "timestamp",
203
+ "primaryKey": false,
204
+ "notNull": true,
205
+ "default": "now()"
206
+ }
207
+ },
208
+ "indexes": {},
209
+ "foreignKeys": {},
210
+ "compositePrimaryKeys": {},
211
+ "uniqueConstraints": {},
212
+ "policies": {},
213
+ "checkConstraints": {},
214
+ "isRLSEnabled": false
215
+ }
216
+ },
217
+ "enums": {
218
+ "public.impact_type": {
219
+ "name": "impact_type",
220
+ "schema": "public",
221
+ "values": [
222
+ "informational",
223
+ "degraded",
224
+ "critical"
225
+ ]
226
+ }
227
+ },
228
+ "schemas": {},
229
+ "sequences": {},
230
+ "roles": {},
231
+ "policies": {},
232
+ "views": {},
233
+ "_meta": {
234
+ "columns": {},
235
+ "schemas": {},
236
+ "tables": {}
237
+ }
238
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "postgresql",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "7",
8
+ "when": 1776457754929,
9
+ "tag": "0000_safe_dark_phoenix",
10
+ "breakpoints": true
11
+ },
12
+ {
13
+ "idx": 1,
14
+ "version": "7",
15
+ "when": 1776463159555,
16
+ "tag": "0001_cooing_bedlam",
17
+ "breakpoints": true
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from "drizzle-kit";
2
+
3
+ export default defineConfig({
4
+ schema: "./src/schema.ts",
5
+ out: "./drizzle",
6
+ dialect: "postgresql",
7
+ });
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@checkstack/dependency-backend",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "main": "src/index.ts",
6
+ "checkstack": {
7
+ "type": "backend"
8
+ },
9
+ "scripts": {
10
+ "typecheck": "tsc --noEmit",
11
+ "generate": "drizzle-kit generate",
12
+ "lint": "bun run lint:code",
13
+ "lint:code": "eslint . --max-warnings 0"
14
+ },
15
+ "dependencies": {
16
+ "@checkstack/backend-api": "0.10.0",
17
+ "@checkstack/dependency-common": "0.1.0",
18
+ "@checkstack/catalog-common": "1.2.11",
19
+ "@checkstack/catalog-backend": "0.2.20",
20
+ "@checkstack/healthcheck-common": "0.8.4",
21
+ "@checkstack/healthcheck-backend": "0.10.7",
22
+ "@checkstack/maintenance-common": "0.4.8",
23
+ "@checkstack/incident-common": "0.4.6",
24
+ "@checkstack/signal-common": "0.1.8",
25
+ "@checkstack/common": "0.6.4",
26
+ "drizzle-orm": "^0.45.0",
27
+ "zod": "^4.2.1",
28
+ "@orpc/server": "^1.13.2"
29
+ },
30
+ "devDependencies": {
31
+ "@checkstack/drizzle-helper": "0.0.4",
32
+ "@checkstack/scripts": "0.1.2",
33
+ "@checkstack/test-utils-backend": "0.1.15",
34
+ "@checkstack/tsconfig": "0.0.4",
35
+ "@types/bun": "^1.0.0",
36
+ "typescript": "^5.0.0"
37
+ }
38
+ }
package/src/hooks.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { createHook } from "@checkstack/backend-api";
2
+
3
+ /**
4
+ * Dependency hooks for cross-plugin communication.
5
+ * Other plugins can subscribe to these hooks to react to dependency changes.
6
+ */
7
+ export const dependencyHooks = {
8
+ /**
9
+ * Emitted when a dependency is created.
10
+ */
11
+ dependencyCreated: createHook<{
12
+ dependencyId: string;
13
+ sourceSystemId: string;
14
+ targetSystemId: string;
15
+ impactType: string;
16
+ }>("dependency.created"),
17
+
18
+ /**
19
+ * Emitted when a dependency is updated.
20
+ */
21
+ dependencyUpdated: createHook<{
22
+ dependencyId: string;
23
+ sourceSystemId: string;
24
+ targetSystemId: string;
25
+ impactType: string;
26
+ }>("dependency.updated"),
27
+
28
+ /**
29
+ * Emitted when a dependency is deleted.
30
+ */
31
+ dependencyDeleted: createHook<{
32
+ dependencyId: string;
33
+ sourceSystemId: string;
34
+ targetSystemId: string;
35
+ }>("dependency.deleted"),
36
+ } as const;