diff --git a/netx_api/app_startup.py b/netx_api/app_startup.py index 42bd032..7e2f82e 100644 --- a/netx_api/app_startup.py +++ b/netx_api/app_startup.py @@ -10,6 +10,7 @@ from .db import Base, SessionLocal, engine from .schema_patches import ( apply_all_legacy_startup_ddl, apply_auth_schema_patches, + apply_topology_schema_safety_net, run_alembic_upgrade_to_head, ) from .security_bootstrap import assert_secure_defaults_or_exit @@ -54,8 +55,11 @@ def run_api_startup() -> None: try: with engine.begin() as conn: apply_auth_schema_patches(conn) + # Critical topology columns even when full legacy DDL is skipped + # (e.g. alembic stamped head without applying domain patches). + apply_topology_schema_safety_net(conn) except Exception: - _log.exception("startup: auth schema patches failed") + _log.exception("startup: auth/topology schema safety patches failed") if skip_ddl and alembic_ok: _log.info("startup: schema via Alembic (legacy inline DDL skipped)") else: diff --git a/netx_api/schema_patches.py b/netx_api/schema_patches.py index 192e23e..d073e8e 100644 --- a/netx_api/schema_patches.py +++ b/netx_api/schema_patches.py @@ -123,6 +123,28 @@ def apply_auth_schema_patches(conn: Connection) -> None: ) +def apply_topology_schema_safety_net(conn: Connection) -> None: + """Always-on topology columns (Alembic stamp-without-upgrade must not skip these).""" + _run_sql( + conn, + "ALTER TABLE topo_folder ADD COLUMN IF NOT EXISTS external_ref VARCHAR(128) DEFAULT ''", + ) + _run_sql( + conn, + "CREATE INDEX IF NOT EXISTS ix_topo_folder_external_ref ON topo_folder (external_ref)", + ) + _run_sql(conn, "ALTER TABLE topo_fabric_node ADD COLUMN IF NOT EXISTS world_x DOUBLE PRECISION") + _run_sql(conn, "ALTER TABLE topo_fabric_node ADD COLUMN IF NOT EXISTS world_y DOUBLE PRECISION") + _run_sql( + conn, + "CREATE INDEX IF NOT EXISTS ix_topo_fabric_node_world_x ON topo_fabric_node (world_x)", + ) + _run_sql( + conn, + "CREATE INDEX IF NOT EXISTS ix_topo_fabric_node_world_y ON topo_fabric_node (world_y)", + ) + + def apply_key_alert_schema_patches( engine: Engine | None = None, *,