ce76980fe5
- 新增 JWT httpOnly cookie 认证链路 (jose),登录/注册签发 token, 所有用户和盲盒 API 改为从 cookie 提取 userId,不再信任客户端传值 - 新增 /api/auth/logout 端点清除认证 cookie - GET /api/user 区分 owner/非 owner,非 owner 不暴露 email - atomicUpdateRoom 新增 per-room 应用层互斥锁,防止 SQLite 下并发 lost update - 修复 getRoomData 中 fire-and-forget delete 改为 await - 37 个静默 catch 块跨 17 个文件添加 console.error 日志 - 新增 REFACTOR_PLAN.md 全景分析文档
210 lines
7.9 KiB
Markdown
210 lines
7.9 KiB
Markdown
# 项目代码质量全景分析 & 重构计划
|
||
|
||
> 生成时间: 2026-03-02 | 分析工具: Claude Code 7-agent 并行审查
|
||
|
||
## 模块评分总览
|
||
|
||
| # | 模块 | 评分 | 重构优先级 | 核心问题 |
|
||
|---|------|------|-----------|----------|
|
||
| 1 | 认证 & 用户 API | 7.5 | 高 | 无真正鉴权机制,userId 可伪造 |
|
||
| 2 | 房间投票 API | 7.0 | 中 | atomicUpdateRoom 并发 lost update |
|
||
| 3 | 盲盒系统 API | 7.0 | 中 | AI 错误静默吞掉,plan/route.ts 臃肿 |
|
||
| 4 | 位置服务 API | 6.5 | 中 | 高德 API 调用代码 4 处重复,无超时/缓存 |
|
||
| 5 | 前端页面 | 5.5 | 高 | blindbox/[code] 1300行 37个useState |
|
||
| 6 | 组件 & Hooks | 6.5 | 高 | ShareCard 三兄弟 60% 重复,BlindboxPlan 742行 |
|
||
| 7 | 基础设施 & Lib | 6.5 | 高 | Room JSON blob 模型、前后端代码边界模糊 |
|
||
|
||
**全局平均: 6.6 / 10**
|
||
|
||
---
|
||
|
||
## 跨模块共性问题 TOP 5
|
||
|
||
### 1. 无真正的认证机制 (影响: 全局)
|
||
所有 API 的 userId 由客户端 localStorage 传入,任何人可伪造身份操作他人数据。登录接口签发了用户信息但没有 JWT/Cookie,形同虚设。
|
||
|
||
### 2. AI/外部 API 错误被静默吞掉 (影响: 盲盒、位置、Lib)
|
||
ai.ts 所有函数的 catch 都是 return null,amap 调用无超时,blindboxPlanGen.ts 多处空 catch。生产环境问题排查极其困难。
|
||
|
||
### 3. 巨型组件/页面 (影响: 前端)
|
||
- blindbox/[code]/page.tsx: 1300行, 37个useState, 12个useEffect
|
||
- BlindboxPlan.tsx: 742行
|
||
- blindbox/page.tsx: 658行, 18个useState
|
||
- MatchResult.tsx: 513行
|
||
|
||
### 4. 代码重复 (影响: 组件、位置、盲盒)
|
||
- ShareCard 三个文件 ~1024行,重复率 ~60%
|
||
- 高德 transit API 调用在 4处 复制粘贴
|
||
- 标签更新映射代码 3处 重复
|
||
- generateRoomCode 函数 2处 相同实现
|
||
|
||
### 5. Room 数据模型: JSON Blob 反模式 (影响: 房间、Lib)
|
||
Room.data 用一个 JSON 字符串存储全部状态,无法利用数据库约束、索引和关联查询。同项目的 BlindBoxRoom 系列已证明团队有能力做好关系化建模。
|
||
|
||
---
|
||
|
||
## 重构路线图
|
||
|
||
### P0 -- 立即修复 (安全/数据完整性)
|
||
|
||
- [ ] **实现 JWT/httpOnly Cookie 认证链路** (2-3天)
|
||
- 登录签发 JWT,设置 httpOnly cookie
|
||
- 新增 getAuthUserId(req) 从 cookie 中提取用户
|
||
- 所有 /api/user/*, /api/blindbox/*, /api/room/* 改用服务端鉴权
|
||
- 前端移除 userId 参数传递,改为 cookie 自动携带
|
||
|
||
- [ ] **修复 atomicUpdateRoom 并发安全** (0.5天)
|
||
- SQLite 下使用 IMMEDIATE 事务或应用层锁
|
||
- 如迁移到 PostgreSQL,使用 SELECT ... FOR UPDATE
|
||
|
||
- [ ] **所有 catch 块至少加 console.error** (0.5天)
|
||
- ai.ts: tagIdea, suggestIdeas, generateSchedule, refinePlan, suggestAlternativeItems
|
||
- blindboxPlanGen.ts: 多处空 catch
|
||
- 前端组件: BlindboxPlan, MatchResult, SwipeDeck, RestaurantCard 等
|
||
- API routes: applyTags 的 fire-and-forget
|
||
|
||
### P1 -- 短期重构 (代码质量)
|
||
|
||
- [ ] 拆分 blindbox/[code]/page.tsx 为 5-6 个子模块 + hooks (2-3天)
|
||
- [ ] 抽取 ShareCardShell 消除三兄弟重复 (1天)
|
||
- [ ] 拆分 BlindboxPlan.tsx (1天)
|
||
- [ ] 完善 amap.ts 为完整 API 客户端 (1天)
|
||
- [ ] 统一数据获取层 SWR 替代裸 fetch+useState (1-2天)
|
||
|
||
### P2 -- 中期优化 (架构改善)
|
||
|
||
- [ ] Room JSON blob 拆为关系化模型 (3-5天)
|
||
- [ ] 引入 zod 做 AI 返回值 + request body 校验 (1-2天)
|
||
- [ ] blindboxPlanGen.ts 拆为 4 个子模块 (1天)
|
||
- [ ] ApiError 独立 + validation 纯函数化 (0.5天)
|
||
- [ ] plan/route.ts PATCH/GET 内部拆分 (0.5天)
|
||
|
||
### P3 -- 长期改善
|
||
|
||
- [ ] 部分页面引入 Server Component 混合渲染
|
||
- [ ] 补全 a11y (aria-label、键盘导航)
|
||
- [ ] SSE 重连策略 (指数退避)
|
||
- [ ] 文件重命名 (store.ts → roomRepository.ts)
|
||
|
||
---
|
||
|
||
## 各模块详细分析
|
||
|
||
### 模块1: 认证 & 用户 API (7.5/10)
|
||
|
||
**亮点:**
|
||
- 已有 apiHandler 统一错误处理框架
|
||
- validation.ts 提供输入校验工具
|
||
- P2002 唯一约束冲突有分层防御
|
||
|
||
**问题:**
|
||
1. [Critical] userId 由客户端传入可伪造,无 JWT/session
|
||
2. [Critical] 登录成功后无状态维持(不签发 token)
|
||
3. [Warning] JSON.parse 部分未做防御处理
|
||
4. [Warning] GET /api/user 无需鉴权即可查任意用户 email
|
||
5. [Warning] login 接口缺少暴力破解防护
|
||
6. [Suggestion] 用户序列化逻辑重复
|
||
7. [Suggestion] achievements 业务逻辑偏重可抽 service
|
||
|
||
### 模块2: 房间投票 API (7.0/10)
|
||
|
||
**亮点:**
|
||
- atomicUpdateRoom 原子操作封装
|
||
- buildRoomStatus 视图层分离
|
||
- roomEvents 发布/订阅模式
|
||
- 各 handler 职责单一 (10-30行)
|
||
|
||
**问题:**
|
||
1. [Critical] atomicUpdateRoom 事务隔离级别不足,并发 lost update
|
||
2. [Critical] Room.data JSON blob 反模式
|
||
3. [Warning] SSE 连接中被踢用户无实时通知
|
||
4. [Warning] 房间过期清理机制不可靠 (进程内变量)
|
||
5. [Warning] getRoomData 中 fire-and-forget delete
|
||
6. [Warning] buildRoomStatus 每次查 DB 获取 UserProfile,缺缓存
|
||
7. [Suggestion] 房间 ID 使用 Math.random() 非密码学安全
|
||
|
||
### 模块3: 盲盒系统 API (7.0/10)
|
||
|
||
**亮点:**
|
||
- Agent + Legacy 双路径容错设计
|
||
- requireMembership 公共权限检查
|
||
- IdeaTags 多维标签系统设计合理
|
||
- 路由数量合理,职责清晰
|
||
|
||
**问题:**
|
||
1. [Critical] applyTags 静默吞掉所有错误
|
||
2. [Critical] retag 端点串行处理无并发控制
|
||
3. [Critical] plan/route.ts 227行承担过多职责
|
||
4. [Warning] 标签更新映射代码 3处 重复
|
||
5. [Warning] roomId 验证方式不一致
|
||
6. [Warning] plan/stream 未使用 apiHandler
|
||
7. [Warning] plan GET 的 pending/history 有 N+1 查询
|
||
8. [Suggestion] blindboxPlanGen.ts 808行应拆分
|
||
|
||
### 模块4: 位置服务 API (6.5/10)
|
||
|
||
**亮点:**
|
||
- 三个 location 端点都有测试覆盖
|
||
- apiHandler 统一包装
|
||
|
||
**问题:**
|
||
1. [Critical] 高德 transit API 调用在 4处 复制粘贴
|
||
2. [Critical] fetch 调用缺少超时控制
|
||
3. [Critical] debug 端点未用 apiHandler 且缺 try-catch
|
||
4. [Warning] amap.ts 封装过于薄弱 (仅 7行)
|
||
5. [Warning] 缺少缓存策略
|
||
6. [Warning] fetch 响应未检查 HTTP 状态码
|
||
7. [Warning] 输入验证不够严格 (经纬度未校验范围)
|
||
8. [Suggestion] POI 类型定义散落多文件
|
||
|
||
### 模块5: 前端页面 (5.5/10)
|
||
|
||
**亮点:**
|
||
- 路由设计清晰语义明确
|
||
- Skeleton 骨架屏使用
|
||
|
||
**问题:**
|
||
1. [Critical] blindbox/[code]/page.tsx 1300行 37个useState "上帝组件"
|
||
2. [Critical] blindbox/page.tsx 658行表单代码重复
|
||
3. [Critical] profile/page.tsx 521行 18个useState
|
||
4. [Warning] 数据获取方式不一致 (裸fetch vs SWR)
|
||
5. [Warning] userId 通过 URL 参数传递
|
||
6. [Warning] 错误静默吞掉
|
||
7. [Warning] panic/page.tsx 598行位置搜索逻辑应抽取
|
||
8. [Suggestion] 所有页面都是 "use client" 未利用 SSR
|
||
9. [Suggestion] 重复的页面布局模式 (ambient glow + 返回按钮)
|
||
|
||
### 模块6: 组件 & Hooks (6.5/10)
|
||
|
||
**亮点:**
|
||
- Hooks 设计整体合理
|
||
- Toast 系统简洁
|
||
- useShare 正确处理 AbortError
|
||
|
||
**问题:**
|
||
1. [Critical] ShareCard 三兄弟 ~60% 代码重复
|
||
2. [Critical] BlindboxPlan.tsx 742行职责过多
|
||
3. [Warning] 多处错误被静默吞掉
|
||
4. [Warning] useRoomPolling SSE 重连策略不足
|
||
5. [Warning] MatchResult.tsx 513行职责偏重
|
||
6. [Warning] useEffect 依赖项不完整
|
||
7. [Suggestion] 可访问性(a11y)严重不足
|
||
8. [Suggestion] ShareCard inline style 缺注释说明原因
|
||
|
||
### 模块7: 基础设施 & Lib (6.5/10)
|
||
|
||
**亮点:**
|
||
- 前后端目前无实际交叉引用错误
|
||
- sceneConfig/avatars 等纯函数设计良好
|
||
|
||
**问题:**
|
||
1. [Critical] Room JSON blob + WeekendPlan/Decision JSON 存储
|
||
2. [Warning] store.ts 命名严重误导 (服务端代码叫 store)
|
||
3. [Warning] api.ts 混合两类职责
|
||
4. [Warning] blindboxPlanGen.ts 808行过大
|
||
5. [Warning] 两套房间模型 (Room vs BlindBoxRoom) 设计差异大
|
||
6. [Warning] ai.ts AI 返回值校验不统一
|
||
7. [Warning] userId.ts 基于 localStorage UUID 无安全性
|
||
8. [Suggestion] runAgentLoop 硬编码 finalize_plan 工具名
|
||
9. [Suggestion] roomEvents 进程内存级发布订阅
|