Build MVP with Pi installer and atomic updates

This commit is contained in:
2026-07-31 18:17:27 +02:00
parent e575ed2b2f
commit c52def7c37
35 changed files with 7762 additions and 1 deletions
+47
View File
@@ -0,0 +1,47 @@
import { mkdirSync } from "node:fs";
import { dirname } from "node:path";
import Database from "better-sqlite3";
export type CompanionDatabase = Database.Database;
export function openDatabase(path: string): CompanionDatabase {
if (path !== ":memory:") mkdirSync(dirname(path), { recursive: true, mode: 0o750 });
const database = new Database(path);
database.pragma("journal_mode = WAL");
database.pragma("foreign_keys = ON");
database.pragma("busy_timeout = 5000");
migrate(database);
return database;
}
function migrate(database: CompanionDatabase): void {
database.exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE COLLATE NOCASE,
password_hash TEXT NOT NULL,
role TEXT NOT NULL CHECK (role = 'admin'),
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS sessions (
id_hash TEXT PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
expires_at TEXT NOT NULL,
created_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS sessions_expiry_idx ON sessions(expires_at);
CREATE TABLE IF NOT EXISTS audit_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
actor_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
action TEXT NOT NULL,
result TEXT NOT NULL CHECK (result IN ('success', 'failure')),
ip_address TEXT,
details_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL
);
`);
}