From fb1c3c8022a13f094c895c705062acea1e42ab80 Mon Sep 17 00:00:00 2001 From: chengkai3 Date: Fri, 1 May 2026 08:54:24 +0800 Subject: [PATCH] fix(api): add users pk column compatibility at startup --- MEMORY.md | 7 +++++++ api/app/core/database.py | 32 +++++++++++++++++++++++++++++++- memory/2026-05-01.md | 20 ++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 memory/2026-05-01.md diff --git a/MEMORY.md b/MEMORY.md index 56bfa44..763c164 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -939,3 +939,10 @@ - 缓冲区分析联动: - `GET /api/v1/lightning-currents/stats/tower-buffer` 返回 `terrain_metrics`(若杆塔已有地形指标)。 - 风险分级引入地形暴露权重:`ng_for_risk = ng * (1 + 0.25 * exposure)`,但原始返回字段 `ng_per_km2_year` 保持未加权值。 + +## users 主键兼容口径(2026-05-01) + +- 用户主键列工程约定仍为 `users.user_id`。 +- 为兼容历史库(残留 `users.id`)并避免启动 seed 阶段出现 `UndefinedColumn: users.user_id`,`init_db()` 在 PostgreSQL 下新增启动期兼容逻辑: + - 若检测到 `users` 表存在且仅有 `id`、缺少 `user_id`,自动执行 `ALTER TABLE users RENAME COLUMN id TO user_id`,再继续 `create_all/seed`。 +- 对已对齐 `users.user_id` 的库,该逻辑不产生任何改动。 diff --git a/api/app/core/database.py b/api/app/core/database.py index 8b7955d..c89adf7 100644 --- a/api/app/core/database.py +++ b/api/app/core/database.py @@ -2,7 +2,7 @@ from collections.abc import Generator import logging from typing import Any -from sqlalchemy import create_engine +from sqlalchemy import create_engine, inspect, text from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker from .config import get_settings @@ -38,6 +38,35 @@ class Base(DeclarativeBase): pass +def _ensure_user_pk_column_compatibility() -> None: + """ + Keep legacy databases compatible with the current ORM mapping. + + Historical deployments may still use `users.id` as the primary key column. + Current models and foreign keys uniformly target `users.user_id`. + """ + if not database_url.startswith("postgresql"): + return + + schema = settings.resolved_db_schema + with engine.begin() as connection: + db_inspector = inspect(connection) + if not db_inspector.has_table("users", schema=schema): + return + + column_names = { + column["name"] + for column in db_inspector.get_columns("users", schema=schema) + } + if "user_id" in column_names or "id" not in column_names: + return + + connection.execute(text("ALTER TABLE users RENAME COLUMN id TO user_id")) + logger.warning( + "Detected legacy users.id primary key; renamed to users.user_id for schema compatibility.", + ) + + def get_db() -> Generator[Session, None, None]: db = SessionLocal() try: @@ -74,6 +103,7 @@ def init_db() -> None: ) # noqa: F401 from ..services.seed_service import seed_defaults + _ensure_user_pk_column_compatibility() Base.metadata.create_all(bind=engine) with SessionLocal() as db: local_hosts = {"db", "localhost", "127.0.0.1", "::1"} diff --git a/memory/2026-05-01.md b/memory/2026-05-01.md new file mode 100644 index 0000000..99e90dc --- /dev/null +++ b/memory/2026-05-01.md @@ -0,0 +1,20 @@ +## Work Log - 修复 API 启动阶段 users 主键列兼容问题(2026-05-01) + +- 背景: + - 启动报错 `psycopg.errors.UndefinedColumn: column users.user_id does not exist`,触发点在 `seed_defaults -> _seed_permissions` 的关系加载 SQL。 + - 当前 ORM 与外键约定统一使用 `users.user_id`,但历史库可能残留 `users.id` 主键列命名。 + +- 本次改动: + - `api/app/core/database.py` + - 新增 `_ensure_user_pk_column_compatibility()`。 + - 在 `init_db()` 执行 `Base.metadata.create_all()` 前,针对 PostgreSQL 做一次兼容检查: + - 若 `users` 表存在,且检测到仅有 `id` 而没有 `user_id`,自动执行:`ALTER TABLE users RENAME COLUMN id TO user_id`。 + - 其余情况不改动(已是 `user_id` 或两者都不存在时直接跳过)。 + +- 验证: + - 在 `fquiz-api` 容器内执行 `init_db()`:`init_db_ok`。 + - 在 `fquiz-api` 容器内执行查询,确认当前数据库 `users` 列包含 `user_id`。 + +- 风险与影响: + - 影响范围:仅 PostgreSQL 且仅触发于“存在 `users.id` 且缺少 `users.user_id`”的历史库。 + - 该变更属于启动期一次性 DDL 兼容动作;对已规范为 `users.user_id` 的库无行为变化。