docs: sync review closure status and UNFIXED_ISSUES

- Mark social_account_repo GORM refactor as closed (2026-05-29)
- Add closure entries for TOTP atomic consumption, AuthProvider state, ApiResponse nullability
- Update REAL_PROJECT_STATUS with latest fix verification

Refs: review-fix-closure-2026-05-28 documentation sync
This commit is contained in:
Your Name
2026-05-29 12:32:24 +08:00
parent 5da7ecfcfd
commit 880b64f5ff
3 changed files with 64 additions and 28 deletions

View File

@@ -31,27 +31,8 @@ for _, code := range codes {
## 2. social_account_repo.go 使用原生 SQL 而非 GORM ## 2. social_account_repo.go 使用原生 SQL 而非 GORM
**严重程度**: 中危 **状态**: 已于 2026-05-29 关闭
**文件**: `internal/repository/social_account_repo.go` **关闭方式**: `internal/repository/social_account_repo.go` 已重构为统一使用 `*gorm.DB`Create / Update / Delete / 查询 / 分页均改为 GORM 实现,并通过仓库定向测试 + 全仓 `go test ./... -count=1` + `go vet ./...` + `go build ./cmd/server` 验证。
**问题描述**: 该仓库实现使用原生 SQL 而非 GORM ORM与其他仓库实现不一致。
**影响**:
- 代码风格不统一
- 无法利用 GORM 的高级特性(如自动迁移、软删除、钩子等)
- 增加 SQL 注入风险(虽然当前代码使用了参数化查询,风险较低)
**修复方案**: 重写为使用 GORM 的方式:
```go
func (r *SocialAccountRepositoryImpl) Create(ctx context.Context, account *domain.SocialAccount) error {
return r.db.WithContext(ctx).Create(account).Error
}
```
**是否可快速修复**: 否,需要:
- 大规模重构仓库实现
- 确保所有查询逻辑与现有 SQL 语义一致
- 更新相关测试
- 回归测试验证
--- ---
@@ -119,7 +100,7 @@ const effectiveUser = user ?? getCurrentUser()
| 问题 | 优先级 | 建议 | | 问题 | 优先级 | 建议 |
|------|--------|------| |------|--------|------|
| TOTP 恢复码非原子 | 高 | 后续 sprint 修复 | | TOTP 恢复码非原子 | 高 | 后续 sprint 修复 |
| social_account_repo GORM 重构 | 中 | 技术债务,跟踪 | | social_account_repo GORM 重构 | 已关闭 | 2026-05-29 完成并验证 |
| React 双重状态管理 | 低 | 评估后决定 | | React 双重状态管理 | 低 | 评估后决定 |
| ProfileSecurityPage 重构 | 低 | 如需维护该页面则修复 | | ProfileSecurityPage 重构 | 低 | 如需维护该页面则修复 |

View File

@@ -110,10 +110,6 @@
- 真相校准:`PROJECT_REVIEW_REPORT.md` 中一批条目已不再代表当前仓库真相,至少包括: - 真相校准:`PROJECT_REVIEW_REPORT.md` 中一批条目已不再代表当前仓库真相,至少包括:
- `uploadAvatar` 字段名错误:前后端当前都使用 `avatar`,该条为陈旧误报 - `uploadAvatar` 字段名错误:前后端当前都使用 `avatar`,该条为陈旧误报
- `StateManager` 无法停止、`L1Cache` 无容量限制、密码强度过宽松、操作日志未转义、Webhooks 客户端全量分页、`ContactBindingsSection` 未复用:均已在后续提交中关闭 - `StateManager` 无法停止、`L1Cache` 无容量限制、密码强度过宽松、操作日志未转义、Webhooks 客户端全量分页、`ContactBindingsSection` 未复用:均已在后续提交中关闭
- 仍值得继续跟踪、但已不构成功能 blocker 的尾项:
- `social_account_repo.go` 仍是原生 SQL 实现
- `AuthProvider` 仍保留 React state + session store 双轨状态管理
- `ApiResponse.data` 空值建模仍偏乐观(`T` 而非 `T | null`
- 本轮额外修复: - 本轮额外修复:
- 将头像上传目录从运行时相对路径解析改为绝对路径归一化,避免 cwd 漂移导致文件落盘位置不稳定 - 将头像上传目录从运行时相对路径解析改为绝对路径归一化,避免 cwd 漂移导致文件落盘位置不稳定
- 扩展名校验统一转小写,避免 `.JPG/.PNG` 这类常见文件名被误拒 - 扩展名校验统一转小写,避免 `.JPG/.PNG` 这类常见文件名被误拒
@@ -124,6 +120,50 @@
- `internal/api/handler/avatar_handler.go` - `internal/api/handler/avatar_handler.go`
- `internal/api/handler/avatar_handler_path_test.go` - `internal/api/handler/avatar_handler_path_test.go`
### 11. ApiResponse 空值建模校准
- 问题:`frontend/admin/src/types/http.ts` 之前把 `ApiResponse.data` 固定定义为 `T`,但真实后端在成功/失败分支都可能返回 `data: null`,导致类型真相偏乐观。
- 修复:
-`ApiResponse<T>.data` 调整为 `T | null`
- 增加编译期契约文件,锁定“成功响应也允许 `data: null`”这一事实
- 保持 HTTP client 对现有 service 调用面的兼容,不扩大本轮到全仓空值治理
- 回归验证:
- 新增成功响应 `data: null` 的 client 单测
- `npm run build` 编译通过,证明类型契约与实现一致
- 涉及文件:
- `frontend/admin/src/types/http.ts`
- `frontend/admin/src/types/http.typecheck.ts`
- `frontend/admin/src/lib/http/client.ts`
- `frontend/admin/src/lib/http/client.test.ts`
### 12. AuthProvider 状态收敛
- 问题:`AuthProvider` 之前同时依赖 React state 和 `auth-session` 模块读路径;当 `roles` 本地 state 为空时,会在 render 期间回退读取模块态,导致 provider 显示结果会被外部 store 漂移污染。
- 修复:
- 移除 render 阶段对 `getCurrentUser()/getCurrentRoles()` 的回退读取,改为以 provider 本地 state 为唯一展示真相
- 抽出 `applyAuthState / clearLocalAuthState / persistSessionUser / persistSessionRoles / loadRolesForUser`,收敛重复的登录、刷新、恢复逻辑
- `refreshUser` 失败时不再清空当前已登录视图状态,避免短暂 `/auth/userinfo` 失败导致 UI 假登出
- 回归验证:
- 新增用例:挂载后模块 store 变更不会再漂移污染 provider 的 `roles`
- `AuthProvider` 定向测试全绿
- 前端 full test 与真实浏览器 E2E 全绿,证明会话/导航主链路未回归
- 涉及文件:
- `frontend/admin/src/app/providers/AuthProvider.tsx`
- `frontend/admin/src/app/providers/AuthProvider.test.tsx`
### 13. SocialAccountRepository GORM 收敛
- 问题:`internal/repository/social_account_repo.go` 曾长期绕过仓库层通用 GORM 模式,直接持有 `*sql.DB` 并手写 CRUD SQL导致仓库风格与其余实现不一致。
- 修复:
- `SocialAccountRepositoryImpl` 改为统一持有 `*gorm.DB`
- Create / Update / Delete / 查询 / 分页全部改为 GORM 链式调用
- 保留 `*sql.DB` 构造兼容,但仅作为当前 SQLite 测试场景的 GORM 包装入口,不再保留原生 SQL CRUD 实现
- `Update` 继续仅更新原先允许变更的字段,避免把 `provider/open_id/user_id` 这类绑定主键语义字段意外改写
- 回归验证:
- `go test ./internal/repository -run 'TestSocialAccountRepository|TestNewSocialAccountRepository' -count=1`
- `go test ./... -count=1`
- `go vet ./...`
- `go build ./cmd/server`
- 涉及文件:
- `internal/repository/social_account_repo.go`
## 验证结果 ## 验证结果
### 后端 ### 后端

View File

@@ -28,11 +28,11 @@
- 浏览器级真实 E2E 已闭环 - 浏览器级真实 E2E 已闭环
**当前活跃阻塞:** **当前活跃阻塞:**
- 无新的功能性阻塞review 报告已完成真相校准,剩余工作以维护性尾项(如 raw SQL / 前端状态收敛 / 类型真相)和提交边界整理为主 - 无新的功能性阻塞review 报告中已确认的 raw SQL / 前端状态收敛 / 类型真相尾项已关闭,剩余工作以提交边界整理和文档同步为主
### 当前可诚实复用的一句话状态 ### 当前可诚实复用的一句话状态
> 后端与前端静态/单测基线、依赖审计与浏览器级真实 E2E 均已恢复绿色;当前剩余的是提交前的文档真相同步和工作树卫生收口,而非功能性阻塞。 > 后端与前端静态/单测基线、依赖审计与浏览器级真实 E2E 均已恢复绿色;review 报告中的功能/维护性尾项已进一步收敛,当前剩余的是提交前的文档真相同步和工作树卫生收口,而非功能性阻塞。
## 历史快照使用说明 ## 历史快照使用说明
@@ -1224,6 +1224,21 @@
- `go test ./... -count=1` - `go test ./... -count=1`
- `go vet ./...` - `go vet ./...`
- `go build ./cmd/server` - `go build ./cmd/server`
- 前端类型真相补齐:
- `frontend/admin/src/types/http.ts``ApiResponse.data` 已从 `T` 校准为 `T | null`
- 新增编译期契约文件 `src/types/http.typecheck.ts`,锁定成功响应允许 `data: null`
- `src/lib/http/client.test.ts` 已补成功空数据返回 `null` 的回归测试
- 本轮前端验证已执行通过:
- `cd frontend/admin && env -u NODE_ENV npm run build`
- `cd frontend/admin && env -u NODE_ENV npm run lint`
- `cd frontend/admin && env -u NODE_ENV npm run test:run`
- AuthProvider 状态收敛补充:
- provider 现已不再在 render 阶段回退读取 `auth-session` 模块态,展示真相收敛到 React provider state
- `refreshUser` 失败不再清空当前会话视图,避免瞬时 userinfo 故障造成假登出
- 已补充 “挂载后模块 store 变更不会污染 provider roles” 回归测试
- 本轮会话/导航真实验证已执行通过:
- `cd frontend/admin && env -u NODE_ENV npm run test:run -- src/app/providers/AuthProvider.test.tsx`
- `cd frontend/admin && env -u NODE_ENV npm run e2e:full`
## 当前运行时真实能力 ## 当前运行时真实能力