Files
fquiz/memory/2026-05-01.md
T
2026-05-01 13:54:01 +08:00

209 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 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` 的库无行为变化。
## 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`
## Work Log - GitHub Actions 部署分支切换为 dev2026-05-01
- 背景:
- 当前 workflow 仅监听 `main` push,且 deploy job 条件写死为 `refs/heads/main`,导致 `dev` 推送不触发自动部署。
- 本次改动(最小改动):
- 文件:`.github/workflows/main.yml`
- `on.push.branches``main` 改为 `dev`
- `deploy.if``github.ref == 'refs/heads/main'` 改为 `github.ref == 'refs/heads/dev'`
- 预期行为:
- `git push origin dev`:自动触发构建,并在构建成功后执行 deploy。
- `main` 分支 push:不再触发该 workflow 自动部署链路。
- 风险与影响:
- 生产发布入口从 `main` 切换到 `dev`,需确认团队分支策略已同步。
- `workflow_dispatch` 若在非 `dev` 分支触发,deploy job 会被 `if` 条件跳过。
## Work Log - 修复 docker db 端口 5433 冲突并改为 54342026-05-01
- 背景:
- `docker compose` 启动 `db` 报错:`Bind for 0.0.0.0:5433 failed: port is already allocated`
- 现有默认口径为宿主机映射 `5433->5432`,与本机已占用端口冲突。
- 本次改动(最小闭环):
- 文件:`docker-compose.yml`
- `db.ports` 默认映射从 `${POSTGRES_PORT:-5433}:5432` 改为 `${POSTGRES_PORT:-5434}:5432`
- 文件:`.env.example`
- `POSTGRES_PORT` 默认值从 `5433` 改为 `5434`
- 本机直连 `DB_PORT` 默认值从 `5433` 改为 `5434`
- 文件:`api/app/core/config.py`
- `db_port` 默认值从 `5433` 改为 `5434`,与环境模板和 compose 默认保持一致。
- 文件:`README.md`
- 本地 PostgreSQL 示例端口从 `localhost:5433` 更新为 `localhost:5434`
- 文件:`MEMORY.md`
- 宿主机默认 `POSTGRES_PORT` 与本机直连 `DB_PORT` 长期口径同步更新为 `5434`
- 验证:
- `POSTGRES_PORT=5434 docker compose up -d db` -> `fquiz-db` 启动成功。
- `docker compose ps -a` -> `fquiz-db` 状态 `Up ... (healthy)`
- `docker inspect fquiz-db --format '{{json .HostConfig.PortBindings}}'` -> `5432/tcp` 映射 `HostPort=5434`
- 风险与影响:
- 影响范围:本地/部署侧依赖默认 `5433` 的连接配置需同步为 `5434`,否则会出现连接失败。
- 容器内服务间连接不受影响,仍通过 `db:5432` 通信。
## Work Log - 统一 GitHub 发布默认 PostgreSQL 端口为 54342026-05-01
- 背景:
- 仓库本地 `docker-compose.yml` 默认端口已是 `5434`,但 GitHub Actions 发布脚本内联的 `docker-compose.prod.yml` 与首次生成 `.env` 仍使用 `5433`,存在口径不一致。
- 本次改动(最小改动):
- 文件:`.github/workflows/main.yml`
- 将发布脚本中 `db.ports` 默认映射从 `${POSTGRES_PORT:-5433}:5432` 改为 `${POSTGRES_PORT:-5434}:5432`
- 将首次初始化 `.env` 模板中的 `POSTGRES_PORT=5433` 改为 `POSTGRES_PORT=5434`
- 验证:
- `rg -n "POSTGRES_PORT:-5434|POSTGRES_PORT=5434" .github/workflows/main.yml` 命中两处,未发现 workflow 内 `5433` 残留。
- 风险与影响:
- 影响范围:仅 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`
## Work Log - 修复 API 启动时报 users.state 列不存在(2026-05-01
- 背景:
- 启动报错 `psycopg.errors.UndefinedColumn: column users.state does not exist`
- 触发点同样在 `seed_defaults -> _seed_permissions` 的关系预加载过程中,ORM 查询 `users` 全字段时固定引用了 `state`,但目标库实际字段为 `status`
- 本次改动(最小闭环):
- 文件:`api/app/core/config.py`
- 新增配置 `user_status_column`(环境变量 `USER_STATUS_COLUMN`),可选值 `status` / `state`,默认 `status`
- 文件:`api/app/models/user.py`
- `User.status` 列改为基于 `settings.user_status_column` 动态映射,兼容两类历史库结构。
- 文件:`docker-compose.yml`
-`api` / `celery-worker` / `celery-beat` 注入 `USER_STATUS_COLUMN` 环境变量透传。
- 文件:`.env.example`
- 新增 `USER_STATUS_COLUMN=status` 示例配置。
- 验证:
- `rg -n "USER_STATUS_COLUMN|user_status_column"` 命中配置、模型、compose、env 示例,映射链路完整。
- `git diff` 检查仅包含本次预期的 4 个文件改动。
- 风险与影响:
- 影响面集中在 `User` 模型状态字段映射。
- 运行环境需确保 `USER_STATUS_COLUMN` 与目标数据库实际字段一致;若配置错误,启动阶段仍可能抛 `UndefinedColumn`
## Work Log - 修复 API 启动时报 users.create_user / users.update_user 列不存在(2026-05-01
- 背景:
- 发布部署日志报错 `psycopg.errors.UndefinedColumn: column users.create_user does not exist`,容器持续重启。
- 触发点在 `init_db -> seed_defaults``Role.users` 关系预加载会查询 `users` 全字段;当历史库缺失 `create_user/update_user` 时,启动阶段直接失败。
- 本次改动(最小闭环):
- 文件:`api/app/core/database.py`
- 新增 `_ensure_user_audit_column_compatibility()` 并在 `init_db()` 中接入(位于 `Base.metadata.create_all()` 前执行)。
- 兼容策略:
- 若存在历史列 `create_by/created_by`,自动重命名为 `create_user`
- 若存在历史列 `update_by/updated_by`,自动重命名为 `update_user`
- 若目标列仍缺失,自动补齐 nullable 列:
- `ALTER TABLE users ADD COLUMN IF NOT EXISTS create_user VARCHAR(64)`
- `ALTER TABLE users ADD COLUMN IF NOT EXISTS update_user VARCHAR(64)`
- 验证:
- `git diff` 检查改动仅落在 `api/app/core/database.py` 与记忆文档。
- 启动期兼容逻辑为 PostgreSQL 定向执行;仅在 `users` 表存在且列不一致时触发 DDL,已对齐环境不会产生变更。
- 风险与影响:
- 影响面限定在 PostgreSQL 的 `users` 表审计字段兼容处理。
- 该兼容动作为启动期一次性 DDL,可能短暂持有 `users` 表 DDL 锁;对已有规范列名的库无行为变化。
## Work Log - 修复 /api/v1/admin/roles 在缺失 user_role 表时返回 5002026-05-01
- 背景:
- 复现路径:登录后调用 `GET /api/v1/admin/roles`,接口返回 `500`
- 根因:`legacy_admin_rbac_service.list_roles` 固定查询 legacy 表 `user_role`,当库仅存在 modern RBAC 表(`roles/user_roles/role_menus`)时触发 `psycopg.errors.UndefinedTable`
- 本次改动(最小闭环):
- 文件:`api/app/services/legacy_admin_rbac_service.py`
- 新增 `user_role` 存在性探测:`_legacy_role_table_exists()`
- `list_roles` 增加双链路读取:
- legacy 存在时保持原有 `user_role + role_menu_rela + menu` 查询;
- legacy 缺失时自动回退 `roles + role_menus + menus + role_permissions + permissions`
- `get_role_by_id``list_role_menu_ids` 同步支持 modern 回退(兼容按 `id``code` 查角色)。
- 新增辅助函数:
- `_load_role_rows(..., role_source=...)`
- `_load_role_permission_codes_map(..., role_source=...)`
- 扩展辅助函数以支持 modern 回退:
- `_load_role_menu_ids_map(..., role_source=...)`
- `_load_menus_map(..., role_source=...)`
- 验证:
- `python3 -m py_compile api/app/services/legacy_admin_rbac_service.py` -> 通过。
- `git push origin HEAD:dev` -> 成功(提交 `2c3ad31`)。
- 风险与影响:
- 影响范围限定在后台角色读取接口(`/api/v1/admin/roles*`)查询链路。
- 对 legacy 表完整的数据库行为保持不变;仅在 `user_role` 缺失时触发 modern 回退逻辑。