diff --git a/db/index.js b/db/index.js new file mode 100644 index 0000000..4d2907e --- /dev/null +++ b/db/index.js @@ -0,0 +1,74 @@ +import Database from 'better-sqlite3'; +import { mkdirSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const DB_PATH = join(__dirname, 'newbury.sqlite'); + +mkdirSync(__dirname, { recursive: true }); + +const db = new Database(DB_PATH); +db.pragma('journal_mode = WAL'); +db.pragma('foreign_keys = ON'); + +db.exec(` +CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + role TEXT NOT NULL DEFAULT 'admin', + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE TABLE IF NOT EXISTS abilities ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT UNIQUE NOT NULL, + kind TEXT NOT NULL DEFAULT 'common', -- common | boss + charges INTEGER, + cooldown TEXT, + effect TEXT +); + +CREATE TABLE IF NOT EXISTS ghosts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + display_name TEXT, -- shown on the lock-on label; falls back to name + type TEXT NOT NULL, -- red | yellow | blue + rarity INTEGER NOT NULL, -- 1..4 (stars) + speed INTEGER NOT NULL DEFAULT 0, + range INTEGER NOT NULL DEFAULT 0, + charge_shot INTEGER NOT NULL DEFAULT 0, + health INTEGER NOT NULL, + damage INTEGER NOT NULL, + ability TEXT, + is_boss INTEGER NOT NULL DEFAULT 0, + set_number TEXT, + set_name TEXT, + image_path TEXT, -- uploaded GIF/PNG billboard (nullable) + enabled INTEGER NOT NULL DEFAULT 1, + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); +CREATE INDEX IF NOT EXISTS idx_ghosts_type ON ghosts(type); +CREATE INDEX IF NOT EXISTS idx_ghosts_rarity ON ghosts(rarity); +CREATE INDEX IF NOT EXISTS idx_ghosts_boss ON ghosts(is_boss); + +CREATE TABLE IF NOT EXISTS sets ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + code TEXT UNIQUE NOT NULL, -- QR payload / scan code + set_number TEXT, -- e.g. 70419 (reference only) + set_name TEXT NOT NULL, + boss_ghost_id INTEGER REFERENCES ghosts(id) ON DELETE SET NULL, + enabled INTEGER NOT NULL DEFAULT 1, + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE TABLE IF NOT EXISTS set_ghosts ( + set_id INTEGER NOT NULL REFERENCES sets(id) ON DELETE CASCADE, + ghost_id INTEGER NOT NULL REFERENCES ghosts(id) ON DELETE CASCADE, + PRIMARY KEY (set_id, ghost_id) +); +`); + +export default db; +export { DB_PATH };