diff --git a/.env.example b/.env.example index 11e7523..50b0d7e 100644 --- a/.env.example +++ b/.env.example @@ -11,6 +11,7 @@ DB_SCHEMA=public DB_USERNAME=fquiz DB_PASSWORD=fquiz USER_USERNAME_COLUMN=username +USER_PASSWORD_COLUMN=password_hash FILE_VFS_ROOT=./data/vfs MINIO_ENABLED=true MINIO_ENDPOINT=http://minio:9000 diff --git a/MEMORY.md b/MEMORY.md index d6d27fa..68804a7 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -227,6 +227,7 @@ - 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`。 +- 密码列口径:历史环境存在 `users.password` 与 `users.password_hash` 双形态;运行时通过 `USER_PASSWORD_COLUMN`(`password`/`password_hash`)与目标库对齐,避免启动阶段关系预加载触发 `UndefinedColumn`。 ## 发布验收口径(2026-04-26) diff --git a/api/app/core/config.py b/api/app/core/config.py index 573d9b4..efb05f8 100644 --- a/api/app/core/config.py +++ b/api/app/core/config.py @@ -24,6 +24,7 @@ class Settings(BaseSettings): db_username: str = "fquiz" db_password: str = "fquiz" user_username_column: Literal["username", "user_name"] = "username" + user_password_column: Literal["password", "password_hash"] = "password_hash" file_vfs_root: str = "./data/vfs" minio_enabled: bool = False minio_endpoint: str = "http://minio:9000" diff --git a/api/app/models/user.py b/api/app/models/user.py index 7ca0b17..3421c14 100644 --- a/api/app/models/user.py +++ b/api/app/models/user.py @@ -35,7 +35,10 @@ class User(Base): unique=True, index=True, ) - password_hash: Mapped[str] = mapped_column("password", String(255)) + password_hash: Mapped[str] = mapped_column( + settings.user_password_column, + String(255), + ) status: Mapped[str] = mapped_column("state", String(32), default="ENABLED", index=True) created_at: Mapped[datetime] = mapped_column( "create_date", diff --git a/docker-compose.yml b/docker-compose.yml index 402de9f..64f44f4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -103,6 +103,7 @@ services: DB_USERNAME: ${DB_USERNAME:-fquiz} DB_PASSWORD: ${DB_PASSWORD:-fquiz} USER_USERNAME_COLUMN: ${USER_USERNAME_COLUMN:-username} + USER_PASSWORD_COLUMN: ${USER_PASSWORD_COLUMN:-password_hash} FILE_VFS_ROOT: ${FILE_VFS_ROOT:-./data/vfs} MINIO_ENABLED: ${MINIO_ENABLED:-true} MINIO_ENDPOINT: ${MINIO_ENDPOINT:-http://minio:9000} @@ -177,6 +178,7 @@ services: DB_USERNAME: ${DB_USERNAME:-fquiz} DB_PASSWORD: ${DB_PASSWORD:-fquiz} USER_USERNAME_COLUMN: ${USER_USERNAME_COLUMN:-username} + USER_PASSWORD_COLUMN: ${USER_PASSWORD_COLUMN:-password_hash} 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} @@ -214,6 +216,7 @@ services: DB_USERNAME: ${DB_USERNAME:-fquiz} DB_PASSWORD: ${DB_PASSWORD:-fquiz} USER_USERNAME_COLUMN: ${USER_USERNAME_COLUMN:-username} + USER_PASSWORD_COLUMN: ${USER_PASSWORD_COLUMN:-password_hash} 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} diff --git a/memory/2026-05-01.md b/memory/2026-05-01.md index 35340e8..c15f9d3 100644 --- a/memory/2026-05-01.md +++ b/memory/2026-05-01.md @@ -106,3 +106,27 @@ - 风险与影响: - 影响范围:仅 GitHub 发布脚本默认值,不影响已存在且手工维护的服务器 `.env`。 - 若线上环境明确依赖 `5433`,需在服务器 `.env` 显式保留 `POSTGRES_PORT=5433`。 + +## Work Log - 修复 API 启动时报 users.password 列不存在(2026-05-01) + +- 背景: + - 启动报错 `psycopg.errors.UndefinedColumn: column users.password does not exist`。 + - 触发点在 `seed_defaults -> _seed_permissions` 的查询过程中,SQLAlchemy 关系预加载 `Role.users` 时会查询 `users` 全字段;当前 ORM 将 `password_hash` 绑定到 `users.password`,但目标库字段为 `password_hash`。 + +- 本次改动(最小闭环): + - 文件:`api/app/core/config.py` + - 新增配置 `user_password_column`(环境变量 `USER_PASSWORD_COLUMN`),可选值 `password` / `password_hash`,默认 `password_hash`。 + - 文件:`api/app/models/user.py` + - `User.password_hash` 改为基于 `settings.user_password_column` 动态映射,兼容两类历史库结构。 + - 文件:`docker-compose.yml` + - 为 `api` / `celery-worker` / `celery-beat` 注入 `USER_PASSWORD_COLUMN` 环境变量透传。 + - 文件:`.env.example` + - 新增 `USER_PASSWORD_COLUMN=password_hash` 示例配置。 + +- 验证: + - `python3 -m py_compile api/app/core/config.py api/app/models/user.py api/app/services/seed_service.py` -> 通过。 + - `rg -n "USER_PASSWORD_COLUMN|user_password_column" ...` 命中配置、模型、compose、env 示例,映射链路完整。 + +- 风险与影响: + - 影响面集中在 `User` 模型密码字段映射。 + - 运行环境需确保 `USER_PASSWORD_COLUMN` 与目标数据库实际字段一致;若配置错误,启动阶段仍可能抛 `UndefinedColumn`。