fix(api): support configurable users username column mapping

This commit is contained in:
chengkml
2026-05-01 10:05:26 +08:00
parent fb1c3c8022
commit 4b8b6f7210
6 changed files with 40 additions and 1 deletions
+1
View File
@@ -10,6 +10,7 @@ DB_NAME=postgres
DB_SCHEMA=public
DB_USERNAME=fquiz
DB_PASSWORD=fquiz
USER_USERNAME_COLUMN=username
FILE_VFS_ROOT=./data/vfs
MINIO_ENABLED=true
MINIO_ENDPOINT=http://minio:9000
+1
View File
@@ -226,6 +226,7 @@
- `DB_SCHEMA` 通过 PostgreSQL `search_path` 注入,语义等价 JDBC 的 `currentSchema`
- API 启动初始化口径:`seed_defaults` 对本地目标执行;为兼容老表状态约束,初始管理员状态写入值统一为 `ENABLED`(不使用 `active`)。
- 用户表兼容口径:用户主键列对齐旧库 `users.user_id`,与用户关联的外键统一引用 `users.user_id`(不再引用 `users.id`)。
- 用户名列口径:历史环境存在 `users.username``users.user_name` 双形态;运行时通过 `USER_USERNAME_COLUMN``username`/`user_name`)与目标库对齐,避免启动阶段关系预加载触发 `UndefinedColumn`
## 发布验收口径(2026-04-26
+1
View File
@@ -23,6 +23,7 @@ class Settings(BaseSettings):
db_schema: str = "public"
db_username: str = "fquiz"
db_password: str = "fquiz"
user_username_column: Literal["username", "user_name"] = "username"
file_vfs_root: str = "./data/vfs"
minio_enabled: bool = False
minio_endpoint: str = "http://minio:9000"
+9 -1
View File
@@ -7,6 +7,7 @@ from uuid import uuid4
from sqlalchemy import DateTime, String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from ..core.config import get_settings
from ..core.database import Base
from .base import utcnow
@@ -15,6 +16,8 @@ if TYPE_CHECKING:
from .audit_log import AuditLog
from .rbac import Role
settings = get_settings()
class User(Base):
__tablename__ = "users"
@@ -26,7 +29,12 @@ class User(Base):
default=lambda: uuid4().hex,
)
email: Mapped[str] = mapped_column(String(255), unique=True, index=True)
username: Mapped[str] = mapped_column("user_name", String(64), unique=True, index=True)
username: Mapped[str] = mapped_column(
settings.user_username_column,
String(64),
unique=True,
index=True,
)
password_hash: Mapped[str] = mapped_column("password", String(255))
status: Mapped[str] = mapped_column("state", String(32), default="ENABLED", index=True)
created_at: Mapped[datetime] = mapped_column(
+3
View File
@@ -102,6 +102,7 @@ services:
DB_SCHEMA: ${DB_SCHEMA:-public}
DB_USERNAME: ${DB_USERNAME:-fquiz}
DB_PASSWORD: ${DB_PASSWORD:-fquiz}
USER_USERNAME_COLUMN: ${USER_USERNAME_COLUMN:-username}
FILE_VFS_ROOT: ${FILE_VFS_ROOT:-./data/vfs}
MINIO_ENABLED: ${MINIO_ENABLED:-true}
MINIO_ENDPOINT: ${MINIO_ENDPOINT:-http://minio:9000}
@@ -175,6 +176,7 @@ services:
DB_SCHEMA: ${DB_SCHEMA:-public}
DB_USERNAME: ${DB_USERNAME:-fquiz}
DB_PASSWORD: ${DB_PASSWORD:-fquiz}
USER_USERNAME_COLUMN: ${USER_USERNAME_COLUMN:-username}
CELERY_BROKER_URL: ${CELERY_BROKER_URL:-redis://redis:6379/0}
CELERY_RESULT_BACKEND: ${CELERY_RESULT_BACKEND:-redis://redis:6379/1}
CELERY_TIMEZONE: ${CELERY_TIMEZONE:-Asia/Shanghai}
@@ -211,6 +213,7 @@ services:
DB_SCHEMA: ${DB_SCHEMA:-public}
DB_USERNAME: ${DB_USERNAME:-fquiz}
DB_PASSWORD: ${DB_PASSWORD:-fquiz}
USER_USERNAME_COLUMN: ${USER_USERNAME_COLUMN:-username}
CELERY_BROKER_URL: ${CELERY_BROKER_URL:-redis://redis:6379/0}
CELERY_RESULT_BACKEND: ${CELERY_RESULT_BACKEND:-redis://redis:6379/1}
CELERY_TIMEZONE: ${CELERY_TIMEZONE:-Asia/Shanghai}
+25
View File
@@ -18,3 +18,28 @@
- 风险与影响:
- 影响范围:仅 PostgreSQL 且仅触发于“存在 `users.id` 且缺少 `users.user_id`”的历史库。
- 该变更属于启动期一次性 DDL 兼容动作;对已规范为 `users.user_id` 的库无行为变化。
## Work Log - 修复 API 启动时报 users.user_name / users.username 列不一致(2026-05-01
- 背景:
- API 启动阶段在 `seed_defaults -> _seed_permissions` 查询中触发 ORM 关系预加载,SQL 使用了 `users.user_name`,但当前 PostgreSQL `users` 表实际字段为 `username`,导致 `psycopg.errors.UndefinedColumn`,服务启动失败。
- 本次改动(最小闭环):
- 文件:`api/app/core/config.py`
- 新增配置 `user_username_column`(环境变量 `USER_USERNAME_COLUMN`),可选值 `username` / `user_name`,默认 `username`
- 文件:`api/app/models/user.py`
- `User.username` 列改为基于 `settings.user_username_column` 动态映射,兼容两类历史库结构。
- 文件:`docker-compose.yml`
-`api` / `celery-worker` / `celery-beat` 注入 `USER_USERNAME_COLUMN` 环境变量透传。
- 文件:`.env.example`
- 新增 `USER_USERNAME_COLUMN=username` 示例配置。
- 验证:
- `python3 -m py_compile api/app/core/config.py api/app/models/user.py api/app/services/seed_service.py` -> 通过。
- `USER_USERNAME_COLUMN=user_name POSTGRES_PORT=5434 docker compose up -d --no-deps api` -> 启动成功。
- `USER_USERNAME_COLUMN=user_name POSTGRES_PORT=5434 docker compose ps api` -> `Up (healthy)`
- `curl -fsS http://127.0.0.1:8000/health` -> `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`
- 风险与影响:
- 影响面集中在 `User` 模型用户名字段映射。
- 运行环境需明确 `USER_USERNAME_COLUMN` 与目标数据库实际字段一致;配置错误会在启动阶段继续抛 `UndefinedColumn`