"""bootstrap administrator + registration gate The first account created on a fresh install becomes the administrator and registration closes behind it, so an exposed port cannot be claimed by a stranger. Existing installs keep their oldest account as administrator and start closed; an admin reopens registration from the admin panel. Revision ID: 0016 Revises: 0015 Create Date: 2026-09-15 """ from __future__ import annotations from collections.abc import Sequence from alembic import op revision: str = "0016" down_revision: str | None = "0015" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: op.execute("ALTER TABLE users ADD COLUMN is_admin boolean NOT NULL DEFAULT false") op.execute( """ CREATE TABLE app_settings ( id integer PRIMARY KEY DEFAULT 1, registration_open boolean NOT NULL DEFAULT false, updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT ck_app_settings_singleton CHECK (id = 1) ) """ ) # Existing deployment: the oldest account is the one that set the instance up, # so it becomes the administrator. Ties on created_at break by id. op.execute( """ UPDATE users SET is_admin = true WHERE id = (SELECT id FROM users ORDER BY created_at, id LIMIT 1) """ ) # Fresh install (no users yet) starts open so the first signup can happen; # anything else starts closed. op.execute( "INSERT INTO app_settings (id, registration_open) " "VALUES (1, NOT EXISTS (SELECT 1 FROM users))" ) def downgrade() -> None: op.execute("DROP TABLE IF EXISTS app_settings") op.execute("ALTER TABLE users DROP COLUMN IF EXISTS is_admin")