db: add schema for API keys, audit log, and per-minute uptime; migrate links/clicks

New tables: api_keys (hashed bearer tokens with scopes), audit_log (admin
action trail), uptime_minutes (multi-worker-safe availability marks).
Idempotent column migrations: links.redirect_type (default 302),
links.password_hash, links.deleted_at, clicks.is_bot. Existing databases
upgrade in place on next startup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jason Stedwell
2026-07-03 01:36:56 -05:00
parent e928770105
commit c892588d31
+26
View File
@@ -134,6 +134,28 @@ def init_db():
checks_total INTEGER DEFAULT 0, checks_total INTEGER DEFAULT 0,
checks_up INTEGER DEFAULT 0 checks_up INTEGER DEFAULT 0
); );
CREATE TABLE IF NOT EXISTS uptime_minutes (
minute TEXT PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS api_keys (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id),
name TEXT NOT NULL,
key_hash TEXT UNIQUE NOT NULL,
prefix TEXT NOT NULL,
scope TEXT NOT NULL DEFAULT 'read',
created_at TEXT NOT NULL,
last_used_at TEXT,
revoked INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
actor TEXT,
action TEXT NOT NULL,
target TEXT,
details TEXT,
created_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_links_code ON links(code); CREATE INDEX IF NOT EXISTS idx_links_code ON links(code);
CREATE INDEX IF NOT EXISTS idx_clicks_link ON clicks(link_id); CREATE INDEX IF NOT EXISTS idx_clicks_link ON clicks(link_id);
CREATE INDEX IF NOT EXISTS idx_clicks_at ON clicks(clicked_at); CREATE INDEX IF NOT EXISTS idx_clicks_at ON clicks(clicked_at);
@@ -146,6 +168,10 @@ def init_db():
"ALTER TABLE clicks ADD COLUMN country TEXT", "ALTER TABLE clicks ADD COLUMN country TEXT",
"ALTER TABLE users ADD COLUMN plan TEXT NOT NULL DEFAULT 'free'", "ALTER TABLE users ADD COLUMN plan TEXT NOT NULL DEFAULT 'free'",
"ALTER TABLE users ADD COLUMN org_id INTEGER REFERENCES organizations(id)", "ALTER TABLE users ADD COLUMN org_id INTEGER REFERENCES organizations(id)",
"ALTER TABLE links ADD COLUMN redirect_type INTEGER DEFAULT 302",
"ALTER TABLE links ADD COLUMN password_hash TEXT",
"ALTER TABLE links ADD COLUMN deleted_at TEXT",
"ALTER TABLE clicks ADD COLUMN is_bot INTEGER DEFAULT 0",
]: ]:
try: try:
conn.execute(migration) conn.execute(migration)