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, )