53 lines
3.1 KiB
Markdown
53 lines
3.1 KiB
Markdown
## Context
|
||
|
||
参见 `proposal.md` 的 Why。当前运营弹窗配置读取链路由 Query 直接读取配置模型并映射为统一响应 DTO;配置表只保存 `creator`、`updater` 账号 ID,账号名称位于 `tb_account.username`。列表与详情共用响应 DTO,但当前映射函数没有账号名称输入。
|
||
|
||
项目要求读取使用 Query/GORM,关联通过 ID 显式查询,不新增 GORM 关联或数据库外键。账号采用软删除,历史配置需要能解析已删除账号。
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:**
|
||
|
||
- 列表和详情使用同一账号名称语义与响应字段。
|
||
- 列表名称补充保持常数次查询,不产生 N+1。
|
||
- 名称查询错误沿既有稳定错误链返回。
|
||
|
||
**Non-Goals:**
|
||
|
||
- 不保存创建人或更新人的名称快照。
|
||
- 不修改配置写入、版本、启停、排序或权限语义。
|
||
- 不修改账号删除策略或数据库 Schema。
|
||
|
||
## Decisions
|
||
|
||
### 1. 在响应 DTO 增加 `creator_name` 与 `updater_name`
|
||
|
||
保留 `creator`、`updater`,新增同语义名称字段。这样现有调用方保持兼容,后台可直接展示名称。未采用替换 ID 或嵌套账号对象,因为都会扩大契约变更并增加前端迁移成本。
|
||
|
||
### 2. Query 批量读取当前账号名称
|
||
|
||
列表先读取当页配置,再收集非零且去重后的创建人、更新人 ID,通过一次 `Unscoped` GORM 查询读取 `id, username`,生成名称映射后投影响应。详情复用同一批量加载函数,以单元素 ID 集合获得相同语义。
|
||
|
||
未采用 SQL JOIN:当前 Query 已先执行总数与分页读取,独立批量查询更容易保持 Count、排序和配置模型扫描不变,也符合项目显式关联约束。未采用逐条账号查询,避免 N+1。
|
||
|
||
### 3. 已删除账号可见,缺失账号返回空名称
|
||
|
||
账号查询使用 `Unscoped`,因此软删除账号仍能提供历史用户名。映射中没有对应记录时保留字符串零值,表示账号事实已不存在。该行为不制造占位文案,避免把展示策略固化到 API。
|
||
|
||
### 4. 查询失败不得静默降级
|
||
|
||
账号名称查询失败包装为稳定数据库错误并终止列表或详情响应。静默返回空名称会把数据库故障与“账号记录不存在”混为同一可观察结果,违反契约。
|
||
|
||
## Risks / Trade-offs
|
||
|
||
- [账号用户名后续可修改,历史配置展示的是当前用户名而非操作时快照] → 本次明确只补充当前账号名称;若业务要求历史身份不可变,应另建名称快照变更。
|
||
- [列表增加一次账号查询] → 对当页 ID 去重并只选择 `id, username`,查询数量固定为一次。
|
||
- [历史脏数据引用不存在账号] → 保留账号 ID,名称返回空字符串,使调用方仍能识别原始关联值。
|
||
|
||
## Migration Plan
|
||
|
||
1. 更新响应 DTO 与 Query 投影。
|
||
2. 重新生成 OpenAPI 文档并构建 API、Worker。
|
||
3. 在维护者指定的隔离环境请求列表和详情,核对正常账号、软删除账号及不存在账号三种结果。
|
||
4. 回滚只需恢复应用代码与生成文档;无数据库迁移或数据回滚。
|