Files
trace/src/db.mjs
T

80 lines
2.5 KiB
JavaScript
Raw Normal View History

import { DatabaseSync } from 'node:sqlite';
import { mkdirSync } from 'node:fs';
// Schema for the private incident notebook and the Git fix-candidate inbox.
// Deployment-receipt tables live in receipts.mjs, next to the code that
// actually owns that data — this file only owns the notebook's own shape.
const SCHEMA = `
PRAGMA journal_mode=WAL;
PRAGMA foreign_keys=ON;
CREATE TABLE IF NOT EXISTS incidents(
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
project TEXT,
status TEXT NOT NULL DEFAULT 'investigating',
severity TEXT NOT NULL DEFAULT 'annoyance',
detected_at TEXT NOT NULL,
symptom TEXT NOT NULL,
impact TEXT DEFAULT '',
root_cause TEXT DEFAULT '',
confidence TEXT DEFAULT 'unknown',
fix TEXT DEFAULT '',
verification TEXT DEFAULT '',
prevention TEXT DEFAULT '',
remaining_risk TEXT DEFAULT '',
lesson TEXT DEFAULT '',
public_summary TEXT DEFAULT '',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS timeline(
id INTEGER PRIMARY KEY AUTOINCREMENT,
incident_id TEXT NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
at TEXT NOT NULL,
kind TEXT NOT NULL,
body TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS hypotheses(
id INTEGER PRIMARY KEY AUTOINCREMENT,
incident_id TEXT NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
statement TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'untested',
evidence TEXT DEFAULT ''
);
CREATE TABLE IF NOT EXISTS candidates(
id INTEGER PRIMARY KEY AUTOINCREMENT,
repo TEXT NOT NULL,
sha TEXT NOT NULL,
committed_at TEXT NOT NULL,
subject TEXT NOT NULL,
paths TEXT DEFAULT '',
reason TEXT NOT NULL,
state TEXT NOT NULL DEFAULT 'new',
incident_id TEXT,
UNIQUE(repo, sha)
);`;
// Additive, best-effort migrations for columns that shipped after the
// initial schema. SQLite has no "ADD COLUMN IF NOT EXISTS", so each one is
// tried and a "duplicate column" failure is the expected steady state once
// it's already applied everywhere.
const MIGRATIONS = [
"ALTER TABLE incidents ADD COLUMN published_at TEXT DEFAULT ''",
"ALTER TABLE incidents ADD COLUMN public_slug TEXT DEFAULT ''",
];
export function openDb(path = 'data/trace.db') {
mkdirSync('data', { recursive: true });
mkdirSync('data/exports', { recursive: true });
const db = new DatabaseSync(path);
db.exec(SCHEMA);
for (const sql of MIGRATIONS) {
try {
db.exec(sql);
} catch (error) {
if (!String(error.message).includes('duplicate column')) throw error;
}
}
return db;
}