- SQLite database with full schema: users, roles, permissions, role_permissions, user_roles, services, audit_log - RBAC engine with wildcard permission resolution (*.*.*) - Automatic v2→v3 migration from JSON files - 5 default roles: super_admin, admin, editor, user, viewer - Feature registration for APP, GGL, FDX (119 permissions) - 8 services seeded - Full API: roles CRUD, permission check, user-role assignment, feature registration, audit log, stats - Backward compatible with existing auth flows
98 lines
3.2 KiB
JavaScript
98 lines
3.2 KiB
JavaScript
const Database = require('better-sqlite3');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
const DB_PATH = path.join(__dirname, '..', 'data', 'access-manager.db');
|
|
fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
|
|
|
|
const db = new Database(DB_PATH);
|
|
db.pragma('journal_mode = WAL');
|
|
db.pragma('foreign_keys = ON');
|
|
|
|
// ─── Schema ───
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
email TEXT UNIQUE NOT NULL COLLATE NOCASE,
|
|
name TEXT NOT NULL,
|
|
password_hash TEXT,
|
|
auth_methods TEXT NOT NULL DEFAULT '["google"]',
|
|
metadata TEXT DEFAULT '{}',
|
|
tags TEXT DEFAULT '[]',
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
created_by TEXT DEFAULT 'system',
|
|
last_login TEXT,
|
|
status TEXT NOT NULL DEFAULT 'active'
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS roles (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT UNIQUE NOT NULL,
|
|
display_name TEXT NOT NULL,
|
|
description TEXT,
|
|
is_system INTEGER NOT NULL DEFAULT 0,
|
|
priority INTEGER NOT NULL DEFAULT 100,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS permissions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
app TEXT NOT NULL,
|
|
feature TEXT NOT NULL,
|
|
action TEXT NOT NULL,
|
|
display_name TEXT,
|
|
description TEXT,
|
|
category TEXT DEFAULT 'general',
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
UNIQUE(app, feature, action)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS role_permissions (
|
|
role_id INTEGER NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
|
permission_id INTEGER NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
|
|
PRIMARY KEY (role_id, permission_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS user_roles (
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
role_id INTEGER NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
|
scope TEXT NOT NULL DEFAULT '*',
|
|
granted_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
granted_by TEXT,
|
|
PRIMARY KEY (user_id, role_id, scope)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS services (
|
|
id TEXT PRIMARY KEY,
|
|
display_name TEXT NOT NULL,
|
|
hostname TEXT,
|
|
hostnames TEXT DEFAULT '[]',
|
|
port INTEGER,
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
features_registered INTEGER DEFAULT 0,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS audit_log (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
timestamp TEXT NOT NULL DEFAULT (datetime('now')),
|
|
actor_email TEXT NOT NULL,
|
|
action TEXT NOT NULL,
|
|
target_type TEXT,
|
|
target_id TEXT,
|
|
detail TEXT,
|
|
ip TEXT,
|
|
service TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_user_roles_user ON user_roles(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_user_roles_role ON user_roles(role_id);
|
|
CREATE INDEX IF NOT EXISTS idx_role_perms_role ON role_permissions(role_id);
|
|
CREATE INDEX IF NOT EXISTS idx_permissions_app ON permissions(app);
|
|
CREATE INDEX IF NOT EXISTS idx_audit_actor ON audit_log(actor_email);
|
|
CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON audit_log(timestamp);
|
|
`);
|
|
|
|
module.exports = db;
|