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 全景分析文档
7.9 KiB
7.9 KiB
项目代码质量全景分析 & 重构计划
生成时间: 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 唯一约束冲突有分层防御
问题:
- [Critical] userId 由客户端传入可伪造,无 JWT/session
- [Critical] 登录成功后无状态维持(不签发 token)
- [Warning] JSON.parse 部分未做防御处理
- [Warning] GET /api/user 无需鉴权即可查任意用户 email
- [Warning] login 接口缺少暴力破解防护
- [Suggestion] 用户序列化逻辑重复
- [Suggestion] achievements 业务逻辑偏重可抽 service
模块2: 房间投票 API (7.0/10)
亮点:
- atomicUpdateRoom 原子操作封装
- buildRoomStatus 视图层分离
- roomEvents 发布/订阅模式
- 各 handler 职责单一 (10-30行)
问题:
- [Critical] atomicUpdateRoom 事务隔离级别不足,并发 lost update
- [Critical] Room.data JSON blob 反模式
- [Warning] SSE 连接中被踢用户无实时通知
- [Warning] 房间过期清理机制不可靠 (进程内变量)
- [Warning] getRoomData 中 fire-and-forget delete
- [Warning] buildRoomStatus 每次查 DB 获取 UserProfile,缺缓存
- [Suggestion] 房间 ID 使用 Math.random() 非密码学安全
模块3: 盲盒系统 API (7.0/10)
亮点:
- Agent + Legacy 双路径容错设计
- requireMembership 公共权限检查
- IdeaTags 多维标签系统设计合理
- 路由数量合理,职责清晰
问题:
- [Critical] applyTags 静默吞掉所有错误
- [Critical] retag 端点串行处理无并发控制
- [Critical] plan/route.ts 227行承担过多职责
- [Warning] 标签更新映射代码 3处 重复
- [Warning] roomId 验证方式不一致
- [Warning] plan/stream 未使用 apiHandler
- [Warning] plan GET 的 pending/history 有 N+1 查询
- [Suggestion] blindboxPlanGen.ts 808行应拆分
模块4: 位置服务 API (6.5/10)
亮点:
- 三个 location 端点都有测试覆盖
- apiHandler 统一包装
问题:
- [Critical] 高德 transit API 调用在 4处 复制粘贴
- [Critical] fetch 调用缺少超时控制
- [Critical] debug 端点未用 apiHandler 且缺 try-catch
- [Warning] amap.ts 封装过于薄弱 (仅 7行)
- [Warning] 缺少缓存策略
- [Warning] fetch 响应未检查 HTTP 状态码
- [Warning] 输入验证不够严格 (经纬度未校验范围)
- [Suggestion] POI 类型定义散落多文件
模块5: 前端页面 (5.5/10)
亮点:
- 路由设计清晰语义明确
- Skeleton 骨架屏使用
问题:
- [Critical] blindbox/[code]/page.tsx 1300行 37个useState "上帝组件"
- [Critical] blindbox/page.tsx 658行表单代码重复
- [Critical] profile/page.tsx 521行 18个useState
- [Warning] 数据获取方式不一致 (裸fetch vs SWR)
- [Warning] userId 通过 URL 参数传递
- [Warning] 错误静默吞掉
- [Warning] panic/page.tsx 598行位置搜索逻辑应抽取
- [Suggestion] 所有页面都是 "use client" 未利用 SSR
- [Suggestion] 重复的页面布局模式 (ambient glow + 返回按钮)
模块6: 组件 & Hooks (6.5/10)
亮点:
- Hooks 设计整体合理
- Toast 系统简洁
- useShare 正确处理 AbortError
问题:
- [Critical] ShareCard 三兄弟 ~60% 代码重复
- [Critical] BlindboxPlan.tsx 742行职责过多
- [Warning] 多处错误被静默吞掉
- [Warning] useRoomPolling SSE 重连策略不足
- [Warning] MatchResult.tsx 513行职责偏重
- [Warning] useEffect 依赖项不完整
- [Suggestion] 可访问性(a11y)严重不足
- [Suggestion] ShareCard inline style 缺注释说明原因
模块7: 基础设施 & Lib (6.5/10)
亮点:
- 前后端目前无实际交叉引用错误
- sceneConfig/avatars 等纯函数设计良好
问题:
- [Critical] Room JSON blob + WeekendPlan/Decision JSON 存储
- [Warning] store.ts 命名严重误导 (服务端代码叫 store)
- [Warning] api.ts 混合两类职责
- [Warning] blindboxPlanGen.ts 808行过大
- [Warning] 两套房间模型 (Room vs BlindBoxRoom) 设计差异大
- [Warning] ai.ts AI 返回值校验不统一
- [Warning] userId.ts 基于 localStorage UUID 无安全性
- [Suggestion] runAgentLoop 硬编码 finalize_plan 工具名
- [Suggestion] roomEvents 进程内存级发布订阅