"""ui_settings: single-row UI settings (phase 91) Revision ID: 0014 Revises: 0013 Create Date: 2026-09-09 Phase 91 (admin Theme tab: the owner sets the app name, input placeholder, footer text and the 8 identity colors with text fields and color pickers — one additive, fully reversible table, A13): * ``ui_settings`` — ONE row (PK ``id``, the row is always id 1): the phase-91 admin Theme tab persists its values here. The 3 strings (``app_name`` / ``input_placeholder`` / ``footer_text``, VARCHAR(300)) and the 8 identity colors (``bg`` / ``surface`` / ``ink`` / ``ink_soft`` / ``line`` / ``brand`` / ``brand_soft`` / ``brand_ink``, VARCHAR(7) ``#rrggbb``) are ALL nullable — NULL = default (the env value for the strings, the built-in palette for the colors, B1). The row is created only by the PUT upsert (no seed, no server default — a missing row means "defaults", the byte-identical contract). """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "0014" down_revision = "0013" branch_labels = None depends_on = None def upgrade() -> None: op.create_table( "ui_settings", sa.Column("id", sa.Integer(), nullable=False), sa.Column("app_name", sa.String(length=300), nullable=True), sa.Column("input_placeholder", sa.String(length=300), nullable=True), sa.Column("footer_text", sa.String(length=300), nullable=True), sa.Column("bg", sa.String(length=7), nullable=True), sa.Column("surface", sa.String(length=7), nullable=True), sa.Column("ink", sa.String(length=7), nullable=True), sa.Column("ink_soft", sa.String(length=7), nullable=True), sa.Column("line", sa.String(length=7), nullable=True), sa.Column("brand", sa.String(length=7), nullable=True), sa.Column("brand_soft", sa.String(length=7), nullable=True), sa.Column("brand_ink", sa.String(length=7), nullable=True), sa.PrimaryKeyConstraint("id"), ) def downgrade() -> None: # Safe order: the table is the only 0014 artefact — dropping it # leaves 0013's schema byte-identical (A13, fully reversible). op.drop_table("ui_settings")