rebuild(stage-3): establish accounts permissions and secure settings

This commit is contained in:
leefer
2026-07-30 01:33:19 +08:00
parent 2ff35eb6df
commit f69972c3c0
31 changed files with 2742 additions and 18 deletions
@@ -0,0 +1,95 @@
from __future__ import annotations
import sqlite3
from backend.database.migrations.runner import Migration
def upgrade(connection: sqlite3.Connection) -> None:
statements = (
"""
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
username_key TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
is_admin INTEGER NOT NULL DEFAULT 0 CHECK (is_admin IN (0, 1)),
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled')),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)
""",
"""
CREATE TABLE memberships (
user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
state TEXT NOT NULL DEFAULT 'inactive'
CHECK (state IN ('inactive', 'active', 'disabled')),
expires_at TEXT,
is_permanent INTEGER NOT NULL DEFAULT 0 CHECK (is_permanent IN (0, 1)),
daily_llm_limit INTEGER NOT NULL DEFAULT 50
CHECK (daily_llm_limit BETWEEN 1 AND 1000),
updated_at TEXT NOT NULL,
updated_by INTEGER REFERENCES users(id) ON DELETE SET NULL
)
""",
"""
CREATE TABLE sessions (
token_hash TEXT PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
csrf_hash TEXT NOT NULL,
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL,
last_seen_at TEXT NOT NULL
)
""",
"CREATE INDEX sessions_user_id_idx ON sessions(user_id)",
"CREATE INDEX sessions_expires_at_idx ON sessions(expires_at)",
"""
CREATE TABLE birth_profiles (
user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
encrypted_payload TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)
""",
"""
CREATE TABLE llm_usage_daily (
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
usage_date TEXT NOT NULL,
successful_calls INTEGER NOT NULL DEFAULT 0 CHECK (successful_calls >= 0),
updated_at TEXT NOT NULL,
PRIMARY KEY (user_id, usage_date)
)
""",
"""
CREATE TABLE system_credentials (
name TEXT PRIMARY KEY,
encrypted_value TEXT NOT NULL,
updated_at TEXT NOT NULL,
updated_by INTEGER NOT NULL REFERENCES users(id) ON DELETE RESTRICT
)
""",
)
for statement in statements:
connection.execute(statement)
def downgrade(connection: sqlite3.Connection) -> None:
for table in (
"system_credentials",
"llm_usage_daily",
"birth_profiles",
"sessions",
"memberships",
"users",
):
connection.execute(f"DROP TABLE {table}")
MIGRATION = Migration(
version=1,
name="create_accounts",
signature="accounts:v1:users-memberships-sessions-profiles-usage-credentials",
upgrade=upgrade,
downgrade=downgrade,
)
@@ -0,0 +1,54 @@
from __future__ import annotations
import sqlite3
from backend.database.migrations.runner import Migration
def upgrade(connection: sqlite3.Connection) -> None:
connection.execute(
"""
CREATE TABLE llm_models (
id INTEGER PRIMARY KEY AUTOINCREMENT,
display_name TEXT NOT NULL,
display_name_key TEXT NOT NULL UNIQUE,
base_url TEXT NOT NULL,
model_identifier TEXT NOT NULL,
encrypted_api_key TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
updated_by INTEGER NOT NULL REFERENCES users(id) ON DELETE RESTRICT
)
"""
)
connection.execute(
"""
CREATE TABLE llm_configuration (
id INTEGER PRIMARY KEY CHECK (id = 1),
primary_model_id INTEGER REFERENCES llm_models(id) ON DELETE RESTRICT,
fallback_model_id INTEGER REFERENCES llm_models(id) ON DELETE RESTRICT,
updated_at TEXT,
updated_by INTEGER REFERENCES users(id) ON DELETE RESTRICT,
CHECK (
fallback_model_id IS NULL
OR primary_model_id IS NULL
OR fallback_model_id <> primary_model_id
)
)
"""
)
connection.execute("INSERT INTO llm_configuration (id) VALUES (1)")
def downgrade(connection: sqlite3.Connection) -> None:
connection.execute("DROP TABLE llm_configuration")
connection.execute("DROP TABLE llm_models")
MIGRATION = Migration(
version=2,
name="create_model_pool",
signature="model-pool:v1:models-primary-fallback-encrypted-key",
upgrade=upgrade,
downgrade=downgrade,
)
+3 -1
View File
@@ -1,3 +1,5 @@
from backend.database.migrations.m0001_accounts import MIGRATION as ACCOUNTS
from backend.database.migrations.m0002_model_pool import MIGRATION as MODEL_POOL
from backend.database.migrations.runner import Migration
MIGRATIONS: tuple[Migration, ...] = ()
MIGRATIONS: tuple[Migration, ...] = (ACCOUNTS, MODEL_POOL)