Files
cairnquire/apps/server/internal/database/migrations/000009_auth.up.sql
2026-05-28 08:35:50 -04:00

91 lines
3.0 KiB
SQL

CREATE TABLE IF NOT EXISTS sessions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
token_hash TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL,
last_seen_at TEXT,
revoked_at TEXT,
ip_address TEXT,
user_agent TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_sessions_token_hash ON sessions(token_hash);
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id);
CREATE TABLE IF NOT EXISTS webauthn_credentials (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
credential_id BLOB NOT NULL UNIQUE,
credential_json TEXT NOT NULL,
created_at TEXT NOT NULL,
last_used_at TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_webauthn_credentials_user ON webauthn_credentials(user_id);
CREATE TABLE IF NOT EXISTS auth_challenges (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
type TEXT NOT NULL CHECK(type IN ('webauthn_registration', 'webauthn_login')),
session_json TEXT NOT NULL,
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL,
used_at TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_auth_challenges_user_type ON auth_challenges(user_id, type);
CREATE TABLE IF NOT EXISTS device_codes (
id TEXT PRIMARY KEY,
user_id TEXT,
device_code_hash TEXT NOT NULL UNIQUE,
user_code_hash TEXT NOT NULL UNIQUE,
user_code_display TEXT NOT NULL,
name TEXT NOT NULL,
scopes TEXT NOT NULL,
status TEXT NOT NULL CHECK(status IN ('pending', 'approved', 'denied', 'expired')),
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL,
approved_at TEXT,
last_polled_at TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE SET NULL
);
CREATE INDEX IF NOT EXISTS idx_device_codes_user_code_hash ON device_codes(user_code_hash);
CREATE INDEX IF NOT EXISTS idx_device_codes_device_code_hash ON device_codes(device_code_hash);
CREATE TABLE IF NOT EXISTS permissions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
resource_type TEXT NOT NULL CHECK(resource_type IN ('global', 'collection', 'document')),
resource_id TEXT,
permission TEXT NOT NULL CHECK(permission IN ('read', 'write', 'admin')),
granted_by TEXT,
created_at TEXT NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY(granted_by) REFERENCES users(id) ON DELETE SET NULL
);
CREATE INDEX IF NOT EXISTS idx_permissions_user ON permissions(user_id);
CREATE TABLE IF NOT EXISTS audit_log (
id TEXT PRIMARY KEY,
actor_user_id TEXT,
event_type TEXT NOT NULL,
resource_type TEXT,
resource_id TEXT,
ip_address TEXT,
user_agent TEXT,
created_at TEXT NOT NULL,
metadata_json TEXT NOT NULL DEFAULT '{}',
FOREIGN KEY(actor_user_id) REFERENCES users(id) ON DELETE SET NULL
);
CREATE INDEX IF NOT EXISTS idx_audit_log_created_at ON audit_log(created_at);
ALTER TABLE api_keys ADD COLUMN revoked_at TEXT;