refactor(db): rename redirect_path→redirect, add uid/addLog helpers, simplify Caddy CRUD

- Rename caddy.redirect_path to caddy.redirect across schema, server, frontend and docs
- Remove obsolete ALTER TABLE migration (fresh-install model has no migrations)
- Move uid() from server.ts to server-db.ts for shared use
- Add addLog() general helper (prepared statement, shared timestamp support) and
  replace ~24 inline INSERT INTO logs calls throughout server.ts
- Caddy CRUD now takes CaddyRouteInput object instead of positional arguments;
  add/update reuse getCaddyRouteById() to avoid duplicate SELECT
This commit is contained in:
Brückner
2026-06-10 15:08:35 +02:00
parent 515052fbda
commit be007791dc
4 changed files with 117 additions and 125 deletions

View File

@ -3,6 +3,9 @@ import path from 'path';
export const DB_FILE = path.join(process.cwd(), 'ghostgrid.db');
/** App-generated primary key: `${prefix}-${epochMs}-${rand}` (e.g. `log-…`, `dev-…`). */
export const uid = (prefix: string) => `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
console.log(`[Database] Connecting to SQLite database at: ${DB_FILE}`);
const db = new Database(DB_FILE);
@ -91,14 +94,11 @@ db.exec(`
upstream TEXT NOT NULL,
tls INTEGER NOT NULL DEFAULT 1,
compress INTEGER NOT NULL DEFAULT 1,
redirect_path TEXT NOT NULL DEFAULT '',
redirect TEXT NOT NULL DEFAULT '',
created_at TEXT DEFAULT (datetime('now'))
);
`);
// redirect_path was added later; ensure it exists on databases created before it.
try { db.exec("ALTER TABLE caddy ADD COLUMN redirect_path TEXT NOT NULL DEFAULT ''"); } catch { /* column already exists */ }
// Seed default settings — INSERT OR IGNORE writes a key only if it is absent.
const DEFAULT_SETTINGS: Record<string, string> = {
azure_enabled: 'false',
@ -117,7 +117,7 @@ const DEFAULT_SETTINGS: Record<string, string> = {
semaphore_api_token: '',
semaphore_project_id: '',
caddy_enabled: 'false',
caddy_admin_url: 'http://localhost:2019',
caddy_admin_url: 'http://127.0.0.1:2019',
};
const seedSetting = db.prepare('INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)');
@ -137,39 +137,68 @@ export function getAllSettings(): Record<string, string> {
return Object.fromEntries(rows.map(r => [r.key, r.value]));
}
const insertLog = db.prepare(
'INSERT INTO logs (id, timestamp, type, message, deviceId, userId) VALUES (?, ?, ?, ?, ?, ?)',
);
/**
* Append a logbook entry. `deviceId`/`userId` default to NULL; `timestamp`
* defaults to now (pass one to share a single timestamp across a batch).
* Returns the generated log id.
*/
export function addLog(
type: string,
message: string,
opts: { deviceId?: string | null; userId?: string | null; timestamp?: string } = {},
): string {
const id = uid('log');
insertLog.run(id, opts.timestamp ?? new Date().toISOString(), type, message, opts.deviceId ?? null, opts.userId ?? null);
return id;
}
/** A reverse-proxy route as stored (booleans are SQLite 0/1 integers). */
export interface CaddyRoute {
id: number;
hostname: string;
upstream: string;
tls: number;
compress: number;
redirect_path: string;
redirect: string;
created_at: string;
}
/** Fields a caller supplies to create or update a route (JS booleans). */
export interface CaddyRouteInput {
hostname: string;
upstream: string;
tls: boolean;
compress: boolean;
redirect?: string;
}
export function getCaddyRoutes(): CaddyRoute[] {
return db.prepare('SELECT * FROM caddy ORDER BY id ASC').all() as CaddyRoute[];
}
export function addCaddyRoute(hostname: string, upstream: string, tls: boolean, compress: boolean, redirectPath = ''): CaddyRoute {
const { lastInsertRowid } = db.prepare(
'INSERT INTO caddy (hostname, upstream, tls, compress, redirect_path) VALUES (?, ?, ?, ?, ?)'
).run(hostname, upstream, tls ? 1 : 0, compress ? 1 : 0, redirectPath);
return db.prepare('SELECT * FROM caddy WHERE id = ?').get(lastInsertRowid) as CaddyRoute;
export function getCaddyRouteById(id: number): CaddyRoute | undefined {
return db.prepare('SELECT * FROM caddy WHERE id = ?').get(id) as CaddyRoute | undefined;
}
export function updateCaddyRoute(id: number, hostname: string, upstream: string, tls: boolean, compress: boolean, redirectPath = ''): CaddyRoute {
db.prepare('UPDATE caddy SET hostname = ?, upstream = ?, tls = ?, compress = ?, redirect_path = ? WHERE id = ?')
.run(hostname, upstream, tls ? 1 : 0, compress ? 1 : 0, redirectPath, id);
return db.prepare('SELECT * FROM caddy WHERE id = ?').get(id) as CaddyRoute;
export function addCaddyRoute(route: CaddyRouteInput): CaddyRoute {
const { lastInsertRowid } = db.prepare(
'INSERT INTO caddy (hostname, upstream, tls, compress, redirect) VALUES (?, ?, ?, ?, ?)',
).run(route.hostname, route.upstream, route.tls ? 1 : 0, route.compress ? 1 : 0, route.redirect ?? '');
return getCaddyRouteById(Number(lastInsertRowid))!;
}
export function updateCaddyRoute(id: number, route: CaddyRouteInput): CaddyRoute {
db.prepare('UPDATE caddy SET hostname = ?, upstream = ?, tls = ?, compress = ?, redirect = ? WHERE id = ?')
.run(route.hostname, route.upstream, route.tls ? 1 : 0, route.compress ? 1 : 0, route.redirect ?? '', id);
return getCaddyRouteById(id)!;
}
export function deleteCaddyRoute(id: number): void {
db.prepare('DELETE FROM caddy WHERE id = ?').run(id);
}
export function getCaddyRouteById(id: number): CaddyRoute | undefined {
return db.prepare('SELECT * FROM caddy WHERE id = ?').get(id) as CaddyRoute | undefined;
}
export default db;
export default db;