feat: schéma Drizzle/SQLite (machines, snapshots, executions)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
// server/db/client.ts
|
||||
import Database from "better-sqlite3";
|
||||
import { drizzle } from "drizzle-orm/better-sqlite3";
|
||||
import { mkdirSync } from "node:fs";
|
||||
import { dirname } from "node:path";
|
||||
import { env } from "../env.js";
|
||||
import * as schema from "./schema.js";
|
||||
|
||||
mkdirSync(dirname(env.dbPath), { recursive: true });
|
||||
const sqlite = new Database(env.dbPath);
|
||||
sqlite.pragma("journal_mode = WAL");
|
||||
sqlite.pragma("foreign_keys = ON");
|
||||
|
||||
export const db = drizzle(sqlite, { schema });
|
||||
export { schema };
|
||||
@@ -0,0 +1,7 @@
|
||||
// server/db/migrate.ts
|
||||
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
||||
import { db } from "./client.js";
|
||||
|
||||
export function runMigrations(): void {
|
||||
migrate(db, { migrationsFolder: "./server/db/migrations" });
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
CREATE TABLE `executions` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`machine_id` text NOT NULL,
|
||||
`action` text NOT NULL,
|
||||
`mode` text DEFAULT 'manual' NOT NULL,
|
||||
`started_at` text NOT NULL,
|
||||
`finished_at` text,
|
||||
`status` text NOT NULL,
|
||||
`result_json` text,
|
||||
`report_path` text,
|
||||
`raw_log_path` text,
|
||||
FOREIGN KEY (`machine_id`) REFERENCES `machines`(`id`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `machines` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`hostname` text NOT NULL,
|
||||
`port` integer DEFAULT 22 NOT NULL,
|
||||
`os_family` text DEFAULT 'unknown' NOT NULL,
|
||||
`username` text NOT NULL,
|
||||
`enc_password` text NOT NULL,
|
||||
`enc_sudo_password` text,
|
||||
`apt_proxy_mode` text DEFAULT 'direct' NOT NULL,
|
||||
`apt_proxy_url` text,
|
||||
`status` text DEFAULT 'unknown' NOT NULL,
|
||||
`last_checked_at` text,
|
||||
`created_at` text NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `snapshots` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`machine_id` text NOT NULL,
|
||||
`checked_at` text NOT NULL,
|
||||
`status` text NOT NULL,
|
||||
`payload_json` text NOT NULL,
|
||||
FOREIGN KEY (`machine_id`) REFERENCES `machines`(`id`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
@@ -0,0 +1,277 @@
|
||||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "6aec3f17-e17f-4e7c-950c-c11592a58541",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"tables": {
|
||||
"executions": {
|
||||
"name": "executions",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"machine_id": {
|
||||
"name": "machine_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"action": {
|
||||
"name": "action",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"mode": {
|
||||
"name": "mode",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'manual'"
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"finished_at": {
|
||||
"name": "finished_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"result_json": {
|
||||
"name": "result_json",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"report_path": {
|
||||
"name": "report_path",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"raw_log_path": {
|
||||
"name": "raw_log_path",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"executions_machine_id_machines_id_fk": {
|
||||
"name": "executions_machine_id_machines_id_fk",
|
||||
"tableFrom": "executions",
|
||||
"tableTo": "machines",
|
||||
"columnsFrom": [
|
||||
"machine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"machines": {
|
||||
"name": "machines",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"hostname": {
|
||||
"name": "hostname",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"port": {
|
||||
"name": "port",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 22
|
||||
},
|
||||
"os_family": {
|
||||
"name": "os_family",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'unknown'"
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"enc_password": {
|
||||
"name": "enc_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"enc_sudo_password": {
|
||||
"name": "enc_sudo_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"apt_proxy_mode": {
|
||||
"name": "apt_proxy_mode",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'direct'"
|
||||
},
|
||||
"apt_proxy_url": {
|
||||
"name": "apt_proxy_url",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'unknown'"
|
||||
},
|
||||
"last_checked_at": {
|
||||
"name": "last_checked_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"snapshots": {
|
||||
"name": "snapshots",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"machine_id": {
|
||||
"name": "machine_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"checked_at": {
|
||||
"name": "checked_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"payload_json": {
|
||||
"name": "payload_json",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"snapshots_machine_id_machines_id_fk": {
|
||||
"name": "snapshots_machine_id_machines_id_fk",
|
||||
"tableFrom": "snapshots",
|
||||
"tableTo": "machines",
|
||||
"columnsFrom": [
|
||||
"machine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "sqlite",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "6",
|
||||
"when": 1780599514478,
|
||||
"tag": "0000_brainy_dakota_north",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// server/db/schema.ts
|
||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
|
||||
export const machines = sqliteTable("machines", {
|
||||
id: text("id").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
hostname: text("hostname").notNull(),
|
||||
port: integer("port").notNull().default(22),
|
||||
osFamily: text("os_family").notNull().default("unknown"),
|
||||
username: text("username").notNull(),
|
||||
encPassword: text("enc_password").notNull(),
|
||||
encSudoPassword: text("enc_sudo_password"),
|
||||
aptProxyMode: text("apt_proxy_mode").notNull().default("direct"),
|
||||
aptProxyUrl: text("apt_proxy_url"),
|
||||
status: text("status").notNull().default("unknown"),
|
||||
lastCheckedAt: text("last_checked_at"),
|
||||
createdAt: text("created_at").notNull(),
|
||||
});
|
||||
|
||||
export const snapshots = sqliteTable("snapshots", {
|
||||
id: text("id").primaryKey(),
|
||||
machineId: text("machine_id").notNull().references(() => machines.id, { onDelete: "cascade" }),
|
||||
checkedAt: text("checked_at").notNull(),
|
||||
status: text("status").notNull(),
|
||||
payloadJson: text("payload_json").notNull(),
|
||||
});
|
||||
|
||||
export const executions = sqliteTable("executions", {
|
||||
id: text("id").primaryKey(),
|
||||
machineId: text("machine_id").notNull().references(() => machines.id, { onDelete: "cascade" }),
|
||||
action: text("action").notNull(),
|
||||
mode: text("mode").notNull().default("manual"),
|
||||
startedAt: text("started_at").notNull(),
|
||||
finishedAt: text("finished_at"),
|
||||
status: text("status").notNull(),
|
||||
resultJson: text("result_json"),
|
||||
reportPath: text("report_path"),
|
||||
rawLogPath: text("raw_log_path"),
|
||||
});
|
||||
Reference in New Issue
Block a user