@checkmate-monitor/maintenance-common 0.1.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,38 @@
1
+ # @checkmate-monitor/maintenance-common
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - eff5b4e: Add standalone maintenance scheduling plugin
8
+
9
+ - New `@checkmate-monitor/maintenance-common` package with Zod schemas, permissions, oRPC contract, and extension slots
10
+ - New `@checkmate-monitor/maintenance-backend` package with Drizzle schema, service, and oRPC router
11
+ - New `@checkmate-monitor/maintenance-frontend` package with admin page and system detail panel
12
+ - Shared `DateTimePicker` component added to `@checkmate-monitor/ui`
13
+ - Database migrations for maintenances, maintenance_systems, and maintenance_updates tables
14
+
15
+ - 4dd644d: Enable external application (API key) access to management endpoints
16
+
17
+ Changed `userType: "user"` to `userType: "authenticated"` for 52 endpoints across 5 packages, allowing external applications (service accounts with API keys) to call these endpoints programmatically while maintaining RBAC permission checks:
18
+
19
+ - **incident-common**: createIncident, updateIncident, addUpdate, resolveIncident, deleteIncident
20
+ - **maintenance-common**: createMaintenance, updateMaintenance, addUpdate, closeMaintenance, deleteMaintenance
21
+ - **catalog-common**: System CRUD, Group CRUD, addSystemToGroup, removeSystemFromGroup
22
+ - **healthcheck-common**: Configuration management, system associations, retention config, detailed history
23
+ - **integration-common**: Subscription management, connection management, event discovery, delivery logs
24
+
25
+ This enables automation use cases such as:
26
+
27
+ - Creating incidents from external monitoring systems (Prometheus, Grafana)
28
+ - Scheduling maintenances from CI/CD pipelines
29
+ - Managing catalog systems from infrastructure-as-code tools
30
+ - Configuring health checks from deployment scripts
31
+
32
+ ### Patch Changes
33
+
34
+ - Updated dependencies [ffc28f6]
35
+ - Updated dependencies [b55fae6]
36
+ - @checkmate-monitor/common@0.1.0
37
+ - @checkmate-monitor/signal-common@0.1.0
38
+ - @checkmate-monitor/frontend-api@0.0.2
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@checkmate-monitor/maintenance-common",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": {
7
+ "import": "./src/index.ts"
8
+ }
9
+ },
10
+ "dependencies": {
11
+ "@checkmate-monitor/common": "workspace:*",
12
+ "@checkmate-monitor/frontend-api": "workspace:*",
13
+ "@checkmate-monitor/signal-common": "workspace:*",
14
+ "@orpc/contract": "^1.13.2",
15
+ "zod": "^4.2.1"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.7.2",
19
+ "@checkmate-monitor/tsconfig": "workspace:*",
20
+ "@checkmate-monitor/scripts": "workspace:*"
21
+ },
22
+ "scripts": {
23
+ "typecheck": "tsc --noEmit",
24
+ "lint": "bun run lint:code",
25
+ "lint:code": "eslint . --max-warnings 0"
26
+ }
27
+ }
package/src/index.ts ADDED
@@ -0,0 +1,47 @@
1
+ export { permissions, permissionList } from "./permissions";
2
+ export {
3
+ maintenanceContract,
4
+ MaintenanceApi,
5
+ type MaintenanceContract,
6
+ } from "./rpc-contract";
7
+ export {
8
+ MaintenanceStatusEnum,
9
+ MaintenanceSchema,
10
+ MaintenanceWithSystemsSchema,
11
+ MaintenanceUpdateSchema,
12
+ MaintenanceDetailSchema,
13
+ CreateMaintenanceInputSchema,
14
+ UpdateMaintenanceInputSchema,
15
+ AddMaintenanceUpdateInputSchema,
16
+ type MaintenanceStatus,
17
+ type Maintenance,
18
+ type MaintenanceWithSystems,
19
+ type MaintenanceUpdate,
20
+ type MaintenanceDetail,
21
+ type CreateMaintenanceInput,
22
+ type UpdateMaintenanceInput,
23
+ type AddMaintenanceUpdateInput,
24
+ } from "./schemas";
25
+ export { MaintenanceDetailsSlot, MaintenanceStatusSlot } from "./slots";
26
+ export * from "./plugin-metadata";
27
+ export { maintenanceRoutes } from "./routes";
28
+
29
+ // =============================================================================
30
+ // REALTIME SIGNALS
31
+ // =============================================================================
32
+
33
+ import { createSignal } from "@checkmate-monitor/signal-common";
34
+ import { z } from "zod";
35
+
36
+ /**
37
+ * Broadcast when a maintenance is created, updated, or closed.
38
+ * Frontend components listening to this signal can refetch state for affected systems.
39
+ */
40
+ export const MAINTENANCE_UPDATED = createSignal(
41
+ "maintenance.updated",
42
+ z.object({
43
+ maintenanceId: z.string(),
44
+ systemIds: z.array(z.string()),
45
+ action: z.enum(["created", "updated", "closed"]),
46
+ })
47
+ );
@@ -0,0 +1,19 @@
1
+ import { createPermission, type Permission } from "@checkmate-monitor/common";
2
+
3
+ export const permissions = {
4
+ /** Read access to maintenances - granted to all authenticated users by default */
5
+ maintenanceRead: createPermission(
6
+ "maintenance",
7
+ "read",
8
+ "View planned maintenances",
9
+ { isAuthenticatedDefault: true, isPublicDefault: true }
10
+ ),
11
+ /** Manage maintenances - create, edit, delete, and add updates */
12
+ maintenanceManage: createPermission(
13
+ "maintenance",
14
+ "manage",
15
+ "Manage planned maintenances"
16
+ ),
17
+ } as const satisfies Record<string, Permission>;
18
+
19
+ export const permissionList = Object.values(permissions);
@@ -0,0 +1,9 @@
1
+ import { definePluginMetadata } from "@checkmate-monitor/common";
2
+
3
+ /**
4
+ * Plugin metadata for the maintenance plugin.
5
+ * Exported from the common package so both backend and frontend can reference it.
6
+ */
7
+ export const pluginMetadata = definePluginMetadata({
8
+ pluginId: "maintenance",
9
+ });
package/src/routes.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { createRoutes } from "@checkmate-monitor/common";
2
+
3
+ /**
4
+ * Route definitions for the maintenance plugin.
5
+ * Import and use these routes in both frontend plugins and for link generation.
6
+ *
7
+ * @example Frontend plugin usage
8
+ * ```tsx
9
+ * import { maintenanceRoutes } from "@checkmate-monitor/maintenance-common";
10
+ *
11
+ * createFrontendPlugin({
12
+ * routes: [
13
+ * { route: maintenanceRoutes.routes.config, element: <ConfigPage /> },
14
+ * ],
15
+ * });
16
+ * ```
17
+ *
18
+ * @example Link generation
19
+ * ```tsx
20
+ * import { maintenanceRoutes } from "@checkmate-monitor/maintenance-common";
21
+ * import { usePluginRoute } from "@checkmate-monitor/frontend-api";
22
+ *
23
+ * const getRoute = usePluginRoute();
24
+ * <Link to={getRoute(maintenanceRoutes.routes.config)}>Maintenances</Link>
25
+ * ```
26
+ */
27
+ export const maintenanceRoutes = createRoutes("maintenance", {
28
+ config: "/config",
29
+ systemHistory: "/system/:systemId/history",
30
+ detail: "/:maintenanceId",
31
+ });
@@ -0,0 +1,110 @@
1
+ import { oc } from "@orpc/contract";
2
+ import { z } from "zod";
3
+ import {
4
+ createClientDefinition,
5
+ type ProcedureMetadata,
6
+ } from "@checkmate-monitor/common";
7
+ import { permissions } from "./permissions";
8
+ import { pluginMetadata } from "./plugin-metadata";
9
+ import {
10
+ MaintenanceWithSystemsSchema,
11
+ MaintenanceDetailSchema,
12
+ MaintenanceUpdateSchema,
13
+ CreateMaintenanceInputSchema,
14
+ UpdateMaintenanceInputSchema,
15
+ AddMaintenanceUpdateInputSchema,
16
+ MaintenanceStatusEnum,
17
+ } from "./schemas";
18
+
19
+ const _base = oc.$meta<ProcedureMetadata>({});
20
+
21
+ export const maintenanceContract = {
22
+ /** List all maintenances with optional status filter */
23
+ listMaintenances: _base
24
+ .meta({
25
+ userType: "public",
26
+ permissions: [permissions.maintenanceRead.id],
27
+ })
28
+ .input(
29
+ z
30
+ .object({
31
+ status: MaintenanceStatusEnum.optional(),
32
+ systemId: z.string().optional(),
33
+ })
34
+ .optional()
35
+ )
36
+ .output(z.array(MaintenanceWithSystemsSchema)),
37
+
38
+ /** Get a single maintenance with all details */
39
+ getMaintenance: _base
40
+ .meta({
41
+ userType: "public",
42
+ permissions: [permissions.maintenanceRead.id],
43
+ })
44
+ .input(z.object({ id: z.string() }))
45
+ .output(MaintenanceDetailSchema.nullable()),
46
+
47
+ /** Get active or upcoming maintenances for a specific system */
48
+ getMaintenancesForSystem: _base
49
+ .meta({
50
+ userType: "public",
51
+ permissions: [permissions.maintenanceRead.id],
52
+ })
53
+ .input(z.object({ systemId: z.string() }))
54
+ .output(z.array(MaintenanceWithSystemsSchema)),
55
+
56
+ /** Create a new maintenance */
57
+ createMaintenance: _base
58
+ .meta({
59
+ userType: "authenticated",
60
+ permissions: [permissions.maintenanceManage.id],
61
+ })
62
+ .input(CreateMaintenanceInputSchema)
63
+ .output(MaintenanceWithSystemsSchema),
64
+
65
+ /** Update an existing maintenance */
66
+ updateMaintenance: _base
67
+ .meta({
68
+ userType: "authenticated",
69
+ permissions: [permissions.maintenanceManage.id],
70
+ })
71
+ .input(UpdateMaintenanceInputSchema)
72
+ .output(MaintenanceWithSystemsSchema),
73
+
74
+ /** Add a status update to a maintenance */
75
+ addUpdate: _base
76
+ .meta({
77
+ userType: "authenticated",
78
+ permissions: [permissions.maintenanceManage.id],
79
+ })
80
+ .input(AddMaintenanceUpdateInputSchema)
81
+ .output(MaintenanceUpdateSchema),
82
+
83
+ /** Close a maintenance early (sets status to completed) */
84
+ closeMaintenance: _base
85
+ .meta({
86
+ userType: "authenticated",
87
+ permissions: [permissions.maintenanceManage.id],
88
+ })
89
+ .input(z.object({ id: z.string(), message: z.string().optional() }))
90
+ .output(MaintenanceWithSystemsSchema),
91
+
92
+ /** Delete a maintenance */
93
+ deleteMaintenance: _base
94
+ .meta({
95
+ userType: "authenticated",
96
+ permissions: [permissions.maintenanceManage.id],
97
+ })
98
+ .input(z.object({ id: z.string() }))
99
+ .output(z.object({ success: z.boolean() })),
100
+ };
101
+
102
+ // Export contract type
103
+ export type MaintenanceContract = typeof maintenanceContract;
104
+
105
+ // Export client definition for type-safe forPlugin usage
106
+ // Use: const client = rpcApi.forPlugin(MaintenanceApi);
107
+ export const MaintenanceApi = createClientDefinition(
108
+ maintenanceContract,
109
+ pluginMetadata
110
+ );
package/src/schemas.ts ADDED
@@ -0,0 +1,96 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Maintenance status enum values
5
+ */
6
+ export const MaintenanceStatusEnum = z.enum([
7
+ "scheduled",
8
+ "in_progress",
9
+ "completed",
10
+ "cancelled",
11
+ ]);
12
+ export type MaintenanceStatus = z.infer<typeof MaintenanceStatusEnum>;
13
+
14
+ /**
15
+ * Core maintenance entity schema
16
+ */
17
+ export const MaintenanceSchema = z.object({
18
+ id: z.string(),
19
+ title: z.string(),
20
+ description: z.string().optional(),
21
+ status: MaintenanceStatusEnum,
22
+ startAt: z.date(),
23
+ endAt: z.date(),
24
+ createdAt: z.date(),
25
+ updatedAt: z.date(),
26
+ });
27
+ export type Maintenance = z.infer<typeof MaintenanceSchema>;
28
+
29
+ /**
30
+ * Maintenance with related systems
31
+ */
32
+ export const MaintenanceWithSystemsSchema = MaintenanceSchema.extend({
33
+ systemIds: z.array(z.string()),
34
+ });
35
+ export type MaintenanceWithSystems = z.infer<
36
+ typeof MaintenanceWithSystemsSchema
37
+ >;
38
+
39
+ /**
40
+ * Maintenance update schema - status updates posted to a maintenance
41
+ */
42
+ export const MaintenanceUpdateSchema = z.object({
43
+ id: z.string(),
44
+ maintenanceId: z.string(),
45
+ message: z.string(),
46
+ statusChange: MaintenanceStatusEnum.optional(),
47
+ createdAt: z.date(),
48
+ createdBy: z.string().optional(),
49
+ });
50
+ export type MaintenanceUpdate = z.infer<typeof MaintenanceUpdateSchema>;
51
+
52
+ /**
53
+ * Full maintenance detail with systems and updates
54
+ */
55
+ export const MaintenanceDetailSchema = MaintenanceWithSystemsSchema.extend({
56
+ updates: z.array(MaintenanceUpdateSchema),
57
+ });
58
+ export type MaintenanceDetail = z.infer<typeof MaintenanceDetailSchema>;
59
+
60
+ // Input schemas for mutations
61
+ export const CreateMaintenanceInputSchema = z
62
+ .object({
63
+ title: z.string().min(1, "Title is required"),
64
+ description: z.string().optional(),
65
+ startAt: z.date(),
66
+ endAt: z.date(),
67
+ systemIds: z.array(z.string()).min(1, "At least one system is required"),
68
+ })
69
+ .refine((data) => data.endAt > data.startAt, {
70
+ message: "End date must be after start date",
71
+ path: ["endAt"],
72
+ });
73
+ export type CreateMaintenanceInput = z.infer<
74
+ typeof CreateMaintenanceInputSchema
75
+ >;
76
+
77
+ export const UpdateMaintenanceInputSchema = z.object({
78
+ id: z.string(),
79
+ title: z.string().min(1).optional(),
80
+ description: z.string().nullable().optional(),
81
+ startAt: z.date().optional(),
82
+ endAt: z.date().optional(),
83
+ systemIds: z.array(z.string()).min(1).optional(),
84
+ });
85
+ export type UpdateMaintenanceInput = z.infer<
86
+ typeof UpdateMaintenanceInputSchema
87
+ >;
88
+
89
+ export const AddMaintenanceUpdateInputSchema = z.object({
90
+ maintenanceId: z.string(),
91
+ message: z.string().min(1, "Message is required"),
92
+ statusChange: MaintenanceStatusEnum.optional(),
93
+ });
94
+ export type AddMaintenanceUpdateInput = z.infer<
95
+ typeof AddMaintenanceUpdateInputSchema
96
+ >;
package/src/slots.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { createSlot } from "@checkmate-monitor/frontend-api";
2
+ import type { MaintenanceWithSystems } from "./schemas";
3
+
4
+ /**
5
+ * Slot for extending maintenance detail views.
6
+ * Plugins can add additional content or actions to maintenance details.
7
+ */
8
+ export const MaintenanceDetailsSlot = createSlot<{
9
+ maintenance: MaintenanceWithSystems;
10
+ }>("plugin.maintenance.details");
11
+
12
+ /**
13
+ * Slot for adding custom status indicators to maintenances.
14
+ * Can be used to show external integrations, alerts, etc.
15
+ */
16
+ export const MaintenanceStatusSlot = createSlot<{
17
+ maintenance: MaintenanceWithSystems;
18
+ }>("plugin.maintenance.status");
package/tsconfig.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "@checkmate-monitor/tsconfig/common.json",
3
+ "include": [
4
+ "src"
5
+ ]
6
+ }