@checkstack/anomaly-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 +125 -0
- package/drizzle/0000_soft_amphibian.sql +20 -0
- package/drizzle/0001_warm_spyke.sql +13 -0
- package/drizzle/0002_peaceful_krista_starr.sql +13 -0
- package/drizzle/0003_easy_maginty.sql +2 -0
- package/drizzle/meta/0000_snapshot.json +152 -0
- package/drizzle/meta/0001_snapshot.json +232 -0
- package/drizzle/meta/0002_snapshot.json +307 -0
- package/drizzle/meta/0003_snapshot.json +323 -0
- package/drizzle/meta/_journal.json +34 -0
- package/drizzle.config.ts +7 -0
- package/package.json +39 -0
- package/src/config.ts +8 -0
- package/src/detector.test.ts +894 -0
- package/src/detector.ts +361 -0
- package/src/drift-evaluator.test.ts +383 -0
- package/src/drift-evaluator.ts +231 -0
- package/src/index.ts +4 -0
- package/src/jobs/baseline-analyzer.ts +269 -0
- package/src/notification.ts +139 -0
- package/src/plugin.ts +85 -0
- package/src/router-cache.ts +89 -0
- package/src/router.ts +74 -0
- package/src/schema.ts +87 -0
- package/src/service.ts +163 -0
- package/tsconfig.json +6 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# @checkstack/anomaly-backend
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8d1ef12: ## Anomaly Detection & UI Improvements
|
|
8
|
+
|
|
9
|
+
### Anomaly Detection Enhancements (Phase 2)
|
|
10
|
+
|
|
11
|
+
- **`@checkstack/anomaly-backend`**: Implemented background baseline analyzer jobs and anomaly trend deviation detection mechanics.
|
|
12
|
+
- **`@checkstack/anomaly-common`**: Added new baseline statistical logic and inference rules.
|
|
13
|
+
- **`@checkstack/anomaly-frontend`**: Added new Anomaly Widget and refactored system detail rendering to be more human-readable.
|
|
14
|
+
- **`@checkstack/dashboard-frontend`**: Refined the global anomaly widget and fixed hardcoded access gating to render appropriately.
|
|
15
|
+
- **`@checkstack/healthcheck-backend`**: Connected executor telemetry to the anomaly pipeline.
|
|
16
|
+
- **`@checkstack/healthcheck-frontend`**: Reconciled baseline display consistency in Drawer and charts.
|
|
17
|
+
|
|
18
|
+
### Notification Identifiers
|
|
19
|
+
|
|
20
|
+
- **`@checkstack/incident-backend`**: Resolved system IDs to human-readable System Names within Incident notifications to eliminate ID-only alert content.
|
|
21
|
+
- **`@checkstack/maintenance-backend`**: Adopted the same resolution strategy for Maintenance notifications to keep parity.
|
|
22
|
+
|
|
23
|
+
### UI Experience
|
|
24
|
+
|
|
25
|
+
- **`@checkstack/incident-frontend`**: Fixed the "Back to X" BackLink to properly use `react-router` hook `useNavigate` instead of doing a full application reload.
|
|
26
|
+
- **`@checkstack/healthcheck-frontend`**: Implemented `useNavigate` for seamless SPA back-linking.
|
|
27
|
+
- **`@checkstack/integration-frontend`**: Updated connections and delivery logs links to navigate without hard reloads.
|
|
28
|
+
|
|
29
|
+
- 8d1ef12: Phase 2 of anomaly detection: trend drift detection.
|
|
30
|
+
|
|
31
|
+
The background baseline analyzer now computes a linear regression slope across each field's chronologically-ordered history and runs a `detectDrift` evaluator that catches gradual "creeping degradation" never reaching the 3σ spike threshold. Drifts share the same `anomalies` table as spike anomalies via a new `kind` column (`spike` | `drift`, default `spike`); the existing suspicious → anomaly → recovered lifecycle is reused, ticking at the analyzer's hourly cadence with a default 2-run confirmation window.
|
|
32
|
+
|
|
33
|
+
User-facing additions: a Trend Drift toggle and threshold slider on both the template and assignment anomaly settings panels (with per-field overrides), drift rows in the System Anomaly widget, dashed regression-line overlays on the auto-generated line charts, and a new `ANOMALY_TREND_DETECTED` signal for live UI updates. Plugin authors can disable drift per chartable field via `x-anomaly-drift-enabled: false` or tighten/loosen it via `x-anomaly-drift-threshold`.
|
|
34
|
+
|
|
35
|
+
- 8d1ef12: ## Per-entity caching with single-flight + safe invalidation across the dashboard hot paths
|
|
36
|
+
|
|
37
|
+
### `@checkstack/cache-api`
|
|
38
|
+
|
|
39
|
+
- **Breaking** for backend implementors: `CacheProvider` now requires `deleteByPrefix(prefix: string): Promise<number>` for family-level invalidation. The in-memory provider implements it; downstream providers (Redis, etc.) must add it before upgrading.
|
|
40
|
+
- `createScopedCache` forwards `deleteByPrefix` and keeps prefixes scoped to the calling plugin.
|
|
41
|
+
|
|
42
|
+
### `@checkstack/cache-utils` (new package)
|
|
43
|
+
|
|
44
|
+
High-level read-through caching helpers built on `CacheProvider`:
|
|
45
|
+
|
|
46
|
+
- `createCachedScope({ cacheManager, pluginId })` returns a scope with `wrap`, `wrapMany`, `invalidate`, and `invalidatePrefix`.
|
|
47
|
+
- **Single-flight**: concurrent cache misses for the same key share one loader.
|
|
48
|
+
- **Per-entity bulk caching** via `wrapMany` so list/bulk RPCs cache by id rather than by the full input shape — overlapping callers share entries and invalidation stays exact.
|
|
49
|
+
- **Race-safe invalidation** via per-key epoch counters: a loader started before a mutation cannot repopulate the cache with stale data after the mutation invalidates it. The mutation invariant is `db.write → cache.invalidate (await) → signals.emit`.
|
|
50
|
+
- Cache failures fall through to the loader so a cache outage cannot break reads.
|
|
51
|
+
|
|
52
|
+
### `@checkstack/backend`
|
|
53
|
+
|
|
54
|
+
- The internal null `CacheProvider` (used when no cache backend is configured) now implements the new `deleteByPrefix` method as a no-op. Patch bump only — no behavior change for existing callers.
|
|
55
|
+
|
|
56
|
+
### `@checkstack/healthcheck-backend`
|
|
57
|
+
|
|
58
|
+
- `getSystemHealthStatus` and `getBulkSystemHealthStatus` now read through a per-system cache (`healthcheck:status:<systemId>`), eliminating N database queries per dashboard refresh for unchanged systems.
|
|
59
|
+
- Mutation paths (configuration CRUD, system associations, satellite ingest, queue-driven check runs, system/satellite removal hooks) invalidate affected keys before broadcasting their signals so frontend refetches always observe fresh data.
|
|
60
|
+
|
|
61
|
+
### `@checkstack/incident-backend`
|
|
62
|
+
|
|
63
|
+
- `listIncidents`, `getIncident`, `getIncidentsForSystem`, and `getBulkIncidentsForSystems` now read through a scoped cache:
|
|
64
|
+
- per-incident at `incident:<id>`
|
|
65
|
+
- per-system at `system:<systemId>`
|
|
66
|
+
- per-filter-shape at `list:<stable-stringify(filters)>` for the few list shapes the dashboard polls
|
|
67
|
+
- Mutations (`createIncident`, `updateIncident`, `addUpdate`, `resolveIncident`, `deleteIncident`) invalidate the incident, every affected system, and every cached list before broadcasting `INCIDENT_UPDATED`.
|
|
68
|
+
- The catalog `systemDeleted` cleanup hook drops that system's cached entries.
|
|
69
|
+
|
|
70
|
+
### `@checkstack/maintenance-backend`
|
|
71
|
+
|
|
72
|
+
- `listMaintenances`, `getMaintenance`, `getMaintenancesForSystem`, and `getBulkMaintenancesForSystems` use the same per-entity / per-system / per-filter-shape pattern as incidents.
|
|
73
|
+
- Mutations (`createMaintenance`, `updateMaintenance`, `addUpdate`, `closeMaintenance`, `deleteMaintenance`) invalidate before broadcasting `MAINTENANCE_UPDATED`.
|
|
74
|
+
|
|
75
|
+
### `@checkstack/catalog-backend`
|
|
76
|
+
|
|
77
|
+
- Topology reads (`getEntities`, `getSystems`, `getSystem`, `getGroups`, `getSystemGroupIds`) cache under the `entity:` family (25s TTL).
|
|
78
|
+
- Views (`getViews`) and per-system contacts (`getSystemContacts`) cache in their own families.
|
|
79
|
+
- System / group / membership mutations drop the entire `entity:` family (every reader joins the same tables); view and contact mutations drop only their respective scopes.
|
|
80
|
+
|
|
81
|
+
### `@checkstack/slo-backend`
|
|
82
|
+
|
|
83
|
+
- `listObjectives`, `getObjective`, `getObjectivesForSystem`, and `getBulkObjectivesForSystems` cache results including the expensive `engine.computeStatus` output.
|
|
84
|
+
- Per-entity caching for the bulk handler so dashboards with overlapping system sets share entries.
|
|
85
|
+
- Mutations (`createObjective`, `updateObjective`, `deleteObjective`) invalidate before broadcasting `SLO_STATUS_CHANGED`.
|
|
86
|
+
|
|
87
|
+
### `@checkstack/anomaly-backend`
|
|
88
|
+
|
|
89
|
+
- New `router-cache.ts` adds a cache scope distinct from the existing detector baseline cache, keyed by stable filter hash.
|
|
90
|
+
- `getAnomalies` and `getAnomalyBaselines` cache through this scope (15s TTL).
|
|
91
|
+
- The detector invalidates the router cache before broadcasting `ANOMALY_STATE_CHANGED` on every state transition (suspicious/anomaly/recovered).
|
|
92
|
+
- Config mutations also invalidate.
|
|
93
|
+
|
|
94
|
+
### `@checkstack/notification-backend`
|
|
95
|
+
|
|
96
|
+
- `getUnreadCount`, `getNotifications`, and `getSubscriptions` cache per-user.
|
|
97
|
+
- `markAsRead`, `deleteNotification`, `notifyUsers`, and `notifyGroups` invalidate every affected user's cache before sending realtime signals to that user.
|
|
98
|
+
- `subscribe` and `unsubscribe` invalidate the user's subscription cache.
|
|
99
|
+
|
|
100
|
+
### `@checkstack/announcement-backend`
|
|
101
|
+
|
|
102
|
+
- `getActiveAnnouncements` caches per-user (or anonymous) and per-`includeDismissed` flag (45s TTL — admin-driven, slowly changing).
|
|
103
|
+
- `listAllAnnouncements` caches under a single key.
|
|
104
|
+
- `dismissAnnouncement` only drops that user's cache; `createAnnouncement`, `updateAnnouncement`, `deleteAnnouncement` drop every user's cache before broadcasting `ANNOUNCEMENT_UPDATED`.
|
|
105
|
+
- The auth `userDeleted` cleanup hook drops that user's cached entries.
|
|
106
|
+
|
|
107
|
+
- 8d1ef12: Added Categorical Anomaly Detection (Dominance Drift) support for non-numeric healthcheck values, and introduced Slider UI components for sensitivity and confirmation window anomaly settings.
|
|
108
|
+
|
|
109
|
+
### Patch Changes
|
|
110
|
+
|
|
111
|
+
- Updated dependencies [8d1ef12]
|
|
112
|
+
- Updated dependencies [8d1ef12]
|
|
113
|
+
- Updated dependencies [8d1ef12]
|
|
114
|
+
- Updated dependencies [8d1ef12]
|
|
115
|
+
- Updated dependencies [8d1ef12]
|
|
116
|
+
- Updated dependencies [8d1ef12]
|
|
117
|
+
- @checkstack/healthcheck-common@0.12.0
|
|
118
|
+
- @checkstack/anomaly-common@0.2.0
|
|
119
|
+
- @checkstack/healthcheck-backend@0.18.0
|
|
120
|
+
- @checkstack/common@0.7.0
|
|
121
|
+
- @checkstack/cache-api@0.2.0
|
|
122
|
+
- @checkstack/cache-utils@0.2.0
|
|
123
|
+
- @checkstack/backend-api@0.13.0
|
|
124
|
+
- @checkstack/catalog-common@1.5.2
|
|
125
|
+
- @checkstack/queue-api@0.2.14
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
CREATE TYPE "anomaly_direction" AS ENUM('above', 'below', 'changed');--> statement-breakpoint
|
|
2
|
+
CREATE TYPE "anomaly_state" AS ENUM('suspicious', 'anomaly', 'recovered');--> statement-breakpoint
|
|
3
|
+
CREATE TABLE "anomalies" (
|
|
4
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
5
|
+
"system_id" text NOT NULL,
|
|
6
|
+
"configuration_id" uuid NOT NULL,
|
|
7
|
+
"field_path" text NOT NULL,
|
|
8
|
+
"state" "anomaly_state" NOT NULL,
|
|
9
|
+
"direction" "anomaly_direction" NOT NULL,
|
|
10
|
+
"baseline_value" double precision,
|
|
11
|
+
"baseline_std_dev" double precision,
|
|
12
|
+
"observed_value" text NOT NULL,
|
|
13
|
+
"deviation" double precision NOT NULL,
|
|
14
|
+
"suspicious_run_count" integer DEFAULT 0 NOT NULL,
|
|
15
|
+
"confirmation_threshold" integer NOT NULL,
|
|
16
|
+
"started_at" timestamp DEFAULT now() NOT NULL,
|
|
17
|
+
"confirmed_at" timestamp,
|
|
18
|
+
"recovered_at" timestamp,
|
|
19
|
+
"metadata" jsonb
|
|
20
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
CREATE TABLE "anomaly_baselines" (
|
|
2
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
3
|
+
"system_id" text NOT NULL,
|
|
4
|
+
"configuration_id" uuid NOT NULL,
|
|
5
|
+
"field_path" text NOT NULL,
|
|
6
|
+
"mean" double precision NOT NULL,
|
|
7
|
+
"std_dev" double precision NOT NULL,
|
|
8
|
+
"trend_slope" double precision NOT NULL,
|
|
9
|
+
"sample_count" integer NOT NULL,
|
|
10
|
+
"computed_at" timestamp NOT NULL,
|
|
11
|
+
"dominant_value" text,
|
|
12
|
+
"dominant_ratio" double precision
|
|
13
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
CREATE TABLE "anomaly_assignments" (
|
|
2
|
+
"system_id" text NOT NULL,
|
|
3
|
+
"configuration_id" uuid NOT NULL,
|
|
4
|
+
"config" jsonb NOT NULL,
|
|
5
|
+
CONSTRAINT "anomaly_assignments_pk" UNIQUE("system_id","configuration_id")
|
|
6
|
+
);
|
|
7
|
+
--> statement-breakpoint
|
|
8
|
+
CREATE TABLE "anomaly_configurations" (
|
|
9
|
+
"configuration_id" uuid PRIMARY KEY NOT NULL,
|
|
10
|
+
"config" jsonb NOT NULL
|
|
11
|
+
);
|
|
12
|
+
--> statement-breakpoint
|
|
13
|
+
ALTER TABLE "anomaly_baselines" ADD CONSTRAINT "anomaly_baselines_unique_path" UNIQUE("system_id","configuration_id","field_path");
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "962cd9d5-a65d-44b9-a4f4-5326ea588ef0",
|
|
3
|
+
"prevId": "00000000-0000-0000-0000-000000000000",
|
|
4
|
+
"version": "7",
|
|
5
|
+
"dialect": "postgresql",
|
|
6
|
+
"tables": {
|
|
7
|
+
"public.anomalies": {
|
|
8
|
+
"name": "anomalies",
|
|
9
|
+
"schema": "",
|
|
10
|
+
"columns": {
|
|
11
|
+
"id": {
|
|
12
|
+
"name": "id",
|
|
13
|
+
"type": "uuid",
|
|
14
|
+
"primaryKey": true,
|
|
15
|
+
"notNull": true,
|
|
16
|
+
"default": "gen_random_uuid()"
|
|
17
|
+
},
|
|
18
|
+
"system_id": {
|
|
19
|
+
"name": "system_id",
|
|
20
|
+
"type": "text",
|
|
21
|
+
"primaryKey": false,
|
|
22
|
+
"notNull": true
|
|
23
|
+
},
|
|
24
|
+
"configuration_id": {
|
|
25
|
+
"name": "configuration_id",
|
|
26
|
+
"type": "uuid",
|
|
27
|
+
"primaryKey": false,
|
|
28
|
+
"notNull": true
|
|
29
|
+
},
|
|
30
|
+
"field_path": {
|
|
31
|
+
"name": "field_path",
|
|
32
|
+
"type": "text",
|
|
33
|
+
"primaryKey": false,
|
|
34
|
+
"notNull": true
|
|
35
|
+
},
|
|
36
|
+
"state": {
|
|
37
|
+
"name": "state",
|
|
38
|
+
"type": "anomaly_state",
|
|
39
|
+
"typeSchema": "public",
|
|
40
|
+
"primaryKey": false,
|
|
41
|
+
"notNull": true
|
|
42
|
+
},
|
|
43
|
+
"direction": {
|
|
44
|
+
"name": "direction",
|
|
45
|
+
"type": "anomaly_direction",
|
|
46
|
+
"typeSchema": "public",
|
|
47
|
+
"primaryKey": false,
|
|
48
|
+
"notNull": true
|
|
49
|
+
},
|
|
50
|
+
"baseline_value": {
|
|
51
|
+
"name": "baseline_value",
|
|
52
|
+
"type": "double precision",
|
|
53
|
+
"primaryKey": false,
|
|
54
|
+
"notNull": false
|
|
55
|
+
},
|
|
56
|
+
"baseline_std_dev": {
|
|
57
|
+
"name": "baseline_std_dev",
|
|
58
|
+
"type": "double precision",
|
|
59
|
+
"primaryKey": false,
|
|
60
|
+
"notNull": false
|
|
61
|
+
},
|
|
62
|
+
"observed_value": {
|
|
63
|
+
"name": "observed_value",
|
|
64
|
+
"type": "text",
|
|
65
|
+
"primaryKey": false,
|
|
66
|
+
"notNull": true
|
|
67
|
+
},
|
|
68
|
+
"deviation": {
|
|
69
|
+
"name": "deviation",
|
|
70
|
+
"type": "double precision",
|
|
71
|
+
"primaryKey": false,
|
|
72
|
+
"notNull": true
|
|
73
|
+
},
|
|
74
|
+
"suspicious_run_count": {
|
|
75
|
+
"name": "suspicious_run_count",
|
|
76
|
+
"type": "integer",
|
|
77
|
+
"primaryKey": false,
|
|
78
|
+
"notNull": true,
|
|
79
|
+
"default": 0
|
|
80
|
+
},
|
|
81
|
+
"confirmation_threshold": {
|
|
82
|
+
"name": "confirmation_threshold",
|
|
83
|
+
"type": "integer",
|
|
84
|
+
"primaryKey": false,
|
|
85
|
+
"notNull": true
|
|
86
|
+
},
|
|
87
|
+
"started_at": {
|
|
88
|
+
"name": "started_at",
|
|
89
|
+
"type": "timestamp",
|
|
90
|
+
"primaryKey": false,
|
|
91
|
+
"notNull": true,
|
|
92
|
+
"default": "now()"
|
|
93
|
+
},
|
|
94
|
+
"confirmed_at": {
|
|
95
|
+
"name": "confirmed_at",
|
|
96
|
+
"type": "timestamp",
|
|
97
|
+
"primaryKey": false,
|
|
98
|
+
"notNull": false
|
|
99
|
+
},
|
|
100
|
+
"recovered_at": {
|
|
101
|
+
"name": "recovered_at",
|
|
102
|
+
"type": "timestamp",
|
|
103
|
+
"primaryKey": false,
|
|
104
|
+
"notNull": false
|
|
105
|
+
},
|
|
106
|
+
"metadata": {
|
|
107
|
+
"name": "metadata",
|
|
108
|
+
"type": "jsonb",
|
|
109
|
+
"primaryKey": false,
|
|
110
|
+
"notNull": false
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"indexes": {},
|
|
114
|
+
"foreignKeys": {},
|
|
115
|
+
"compositePrimaryKeys": {},
|
|
116
|
+
"uniqueConstraints": {},
|
|
117
|
+
"policies": {},
|
|
118
|
+
"checkConstraints": {},
|
|
119
|
+
"isRLSEnabled": false
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"enums": {
|
|
123
|
+
"public.anomaly_direction": {
|
|
124
|
+
"name": "anomaly_direction",
|
|
125
|
+
"schema": "public",
|
|
126
|
+
"values": [
|
|
127
|
+
"above",
|
|
128
|
+
"below",
|
|
129
|
+
"changed"
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
"public.anomaly_state": {
|
|
133
|
+
"name": "anomaly_state",
|
|
134
|
+
"schema": "public",
|
|
135
|
+
"values": [
|
|
136
|
+
"suspicious",
|
|
137
|
+
"anomaly",
|
|
138
|
+
"recovered"
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"schemas": {},
|
|
143
|
+
"sequences": {},
|
|
144
|
+
"roles": {},
|
|
145
|
+
"policies": {},
|
|
146
|
+
"views": {},
|
|
147
|
+
"_meta": {
|
|
148
|
+
"columns": {},
|
|
149
|
+
"schemas": {},
|
|
150
|
+
"tables": {}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "9d7f7e5f-e844-43fb-b70c-3f137e0e6fd8",
|
|
3
|
+
"prevId": "962cd9d5-a65d-44b9-a4f4-5326ea588ef0",
|
|
4
|
+
"version": "7",
|
|
5
|
+
"dialect": "postgresql",
|
|
6
|
+
"tables": {
|
|
7
|
+
"public.anomalies": {
|
|
8
|
+
"name": "anomalies",
|
|
9
|
+
"schema": "",
|
|
10
|
+
"columns": {
|
|
11
|
+
"id": {
|
|
12
|
+
"name": "id",
|
|
13
|
+
"type": "uuid",
|
|
14
|
+
"primaryKey": true,
|
|
15
|
+
"notNull": true,
|
|
16
|
+
"default": "gen_random_uuid()"
|
|
17
|
+
},
|
|
18
|
+
"system_id": {
|
|
19
|
+
"name": "system_id",
|
|
20
|
+
"type": "text",
|
|
21
|
+
"primaryKey": false,
|
|
22
|
+
"notNull": true
|
|
23
|
+
},
|
|
24
|
+
"configuration_id": {
|
|
25
|
+
"name": "configuration_id",
|
|
26
|
+
"type": "uuid",
|
|
27
|
+
"primaryKey": false,
|
|
28
|
+
"notNull": true
|
|
29
|
+
},
|
|
30
|
+
"field_path": {
|
|
31
|
+
"name": "field_path",
|
|
32
|
+
"type": "text",
|
|
33
|
+
"primaryKey": false,
|
|
34
|
+
"notNull": true
|
|
35
|
+
},
|
|
36
|
+
"state": {
|
|
37
|
+
"name": "state",
|
|
38
|
+
"type": "anomaly_state",
|
|
39
|
+
"typeSchema": "public",
|
|
40
|
+
"primaryKey": false,
|
|
41
|
+
"notNull": true
|
|
42
|
+
},
|
|
43
|
+
"direction": {
|
|
44
|
+
"name": "direction",
|
|
45
|
+
"type": "anomaly_direction",
|
|
46
|
+
"typeSchema": "public",
|
|
47
|
+
"primaryKey": false,
|
|
48
|
+
"notNull": true
|
|
49
|
+
},
|
|
50
|
+
"baseline_value": {
|
|
51
|
+
"name": "baseline_value",
|
|
52
|
+
"type": "double precision",
|
|
53
|
+
"primaryKey": false,
|
|
54
|
+
"notNull": false
|
|
55
|
+
},
|
|
56
|
+
"baseline_std_dev": {
|
|
57
|
+
"name": "baseline_std_dev",
|
|
58
|
+
"type": "double precision",
|
|
59
|
+
"primaryKey": false,
|
|
60
|
+
"notNull": false
|
|
61
|
+
},
|
|
62
|
+
"observed_value": {
|
|
63
|
+
"name": "observed_value",
|
|
64
|
+
"type": "text",
|
|
65
|
+
"primaryKey": false,
|
|
66
|
+
"notNull": true
|
|
67
|
+
},
|
|
68
|
+
"deviation": {
|
|
69
|
+
"name": "deviation",
|
|
70
|
+
"type": "double precision",
|
|
71
|
+
"primaryKey": false,
|
|
72
|
+
"notNull": true
|
|
73
|
+
},
|
|
74
|
+
"suspicious_run_count": {
|
|
75
|
+
"name": "suspicious_run_count",
|
|
76
|
+
"type": "integer",
|
|
77
|
+
"primaryKey": false,
|
|
78
|
+
"notNull": true,
|
|
79
|
+
"default": 0
|
|
80
|
+
},
|
|
81
|
+
"confirmation_threshold": {
|
|
82
|
+
"name": "confirmation_threshold",
|
|
83
|
+
"type": "integer",
|
|
84
|
+
"primaryKey": false,
|
|
85
|
+
"notNull": true
|
|
86
|
+
},
|
|
87
|
+
"started_at": {
|
|
88
|
+
"name": "started_at",
|
|
89
|
+
"type": "timestamp",
|
|
90
|
+
"primaryKey": false,
|
|
91
|
+
"notNull": true,
|
|
92
|
+
"default": "now()"
|
|
93
|
+
},
|
|
94
|
+
"confirmed_at": {
|
|
95
|
+
"name": "confirmed_at",
|
|
96
|
+
"type": "timestamp",
|
|
97
|
+
"primaryKey": false,
|
|
98
|
+
"notNull": false
|
|
99
|
+
},
|
|
100
|
+
"recovered_at": {
|
|
101
|
+
"name": "recovered_at",
|
|
102
|
+
"type": "timestamp",
|
|
103
|
+
"primaryKey": false,
|
|
104
|
+
"notNull": false
|
|
105
|
+
},
|
|
106
|
+
"metadata": {
|
|
107
|
+
"name": "metadata",
|
|
108
|
+
"type": "jsonb",
|
|
109
|
+
"primaryKey": false,
|
|
110
|
+
"notNull": false
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"indexes": {},
|
|
114
|
+
"foreignKeys": {},
|
|
115
|
+
"compositePrimaryKeys": {},
|
|
116
|
+
"uniqueConstraints": {},
|
|
117
|
+
"policies": {},
|
|
118
|
+
"checkConstraints": {},
|
|
119
|
+
"isRLSEnabled": false
|
|
120
|
+
},
|
|
121
|
+
"public.anomaly_baselines": {
|
|
122
|
+
"name": "anomaly_baselines",
|
|
123
|
+
"schema": "",
|
|
124
|
+
"columns": {
|
|
125
|
+
"id": {
|
|
126
|
+
"name": "id",
|
|
127
|
+
"type": "uuid",
|
|
128
|
+
"primaryKey": true,
|
|
129
|
+
"notNull": true,
|
|
130
|
+
"default": "gen_random_uuid()"
|
|
131
|
+
},
|
|
132
|
+
"system_id": {
|
|
133
|
+
"name": "system_id",
|
|
134
|
+
"type": "text",
|
|
135
|
+
"primaryKey": false,
|
|
136
|
+
"notNull": true
|
|
137
|
+
},
|
|
138
|
+
"configuration_id": {
|
|
139
|
+
"name": "configuration_id",
|
|
140
|
+
"type": "uuid",
|
|
141
|
+
"primaryKey": false,
|
|
142
|
+
"notNull": true
|
|
143
|
+
},
|
|
144
|
+
"field_path": {
|
|
145
|
+
"name": "field_path",
|
|
146
|
+
"type": "text",
|
|
147
|
+
"primaryKey": false,
|
|
148
|
+
"notNull": true
|
|
149
|
+
},
|
|
150
|
+
"mean": {
|
|
151
|
+
"name": "mean",
|
|
152
|
+
"type": "double precision",
|
|
153
|
+
"primaryKey": false,
|
|
154
|
+
"notNull": true
|
|
155
|
+
},
|
|
156
|
+
"std_dev": {
|
|
157
|
+
"name": "std_dev",
|
|
158
|
+
"type": "double precision",
|
|
159
|
+
"primaryKey": false,
|
|
160
|
+
"notNull": true
|
|
161
|
+
},
|
|
162
|
+
"trend_slope": {
|
|
163
|
+
"name": "trend_slope",
|
|
164
|
+
"type": "double precision",
|
|
165
|
+
"primaryKey": false,
|
|
166
|
+
"notNull": true
|
|
167
|
+
},
|
|
168
|
+
"sample_count": {
|
|
169
|
+
"name": "sample_count",
|
|
170
|
+
"type": "integer",
|
|
171
|
+
"primaryKey": false,
|
|
172
|
+
"notNull": true
|
|
173
|
+
},
|
|
174
|
+
"computed_at": {
|
|
175
|
+
"name": "computed_at",
|
|
176
|
+
"type": "timestamp",
|
|
177
|
+
"primaryKey": false,
|
|
178
|
+
"notNull": true
|
|
179
|
+
},
|
|
180
|
+
"dominant_value": {
|
|
181
|
+
"name": "dominant_value",
|
|
182
|
+
"type": "text",
|
|
183
|
+
"primaryKey": false,
|
|
184
|
+
"notNull": false
|
|
185
|
+
},
|
|
186
|
+
"dominant_ratio": {
|
|
187
|
+
"name": "dominant_ratio",
|
|
188
|
+
"type": "double precision",
|
|
189
|
+
"primaryKey": false,
|
|
190
|
+
"notNull": false
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"indexes": {},
|
|
194
|
+
"foreignKeys": {},
|
|
195
|
+
"compositePrimaryKeys": {},
|
|
196
|
+
"uniqueConstraints": {},
|
|
197
|
+
"policies": {},
|
|
198
|
+
"checkConstraints": {},
|
|
199
|
+
"isRLSEnabled": false
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"enums": {
|
|
203
|
+
"public.anomaly_direction": {
|
|
204
|
+
"name": "anomaly_direction",
|
|
205
|
+
"schema": "public",
|
|
206
|
+
"values": [
|
|
207
|
+
"above",
|
|
208
|
+
"below",
|
|
209
|
+
"changed"
|
|
210
|
+
]
|
|
211
|
+
},
|
|
212
|
+
"public.anomaly_state": {
|
|
213
|
+
"name": "anomaly_state",
|
|
214
|
+
"schema": "public",
|
|
215
|
+
"values": [
|
|
216
|
+
"suspicious",
|
|
217
|
+
"anomaly",
|
|
218
|
+
"recovered"
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
"schemas": {},
|
|
223
|
+
"sequences": {},
|
|
224
|
+
"roles": {},
|
|
225
|
+
"policies": {},
|
|
226
|
+
"views": {},
|
|
227
|
+
"_meta": {
|
|
228
|
+
"columns": {},
|
|
229
|
+
"schemas": {},
|
|
230
|
+
"tables": {}
|
|
231
|
+
}
|
|
232
|
+
}
|