Commit Graph

25 Commits

Author SHA1 Message Date
kurihada 482307f2f4 清理 lint 剩余告警并更新审计文档状态 2026-03-03 13:53:19 +08:00
kurihada 67fdf7427a 修复 SSE 成员校验未生效的问题 2026-03-03 12:14:38 +08:00
kurihada 8b4ab415fd fix: validate swipe restaurant ids against room candidates 2026-03-03 12:06:03 +08:00
kurihada f3d8a58603 fix: unify panic room code format and validate room join id 2026-03-03 12:04:00 +08:00
kurihada 4f4220652e refactor(P2/P3): 完成全部7批重构 — 模块化、SSE退避、无障碍、Zod校验、Server组件、Room关系化
批次A:重命名 + 路由拆分
- store.ts → roomRepository.ts,更新全部 import
- blindbox/plan/route.ts 精简为薄路由,业务逻辑抽取到 planActions.ts / planQueries.ts

批次B:blindboxPlanGen.ts 拆分(710行 → src/lib/plan/)
- agentPlan.ts:Agent 工具调用与系统提示
- legacyPlan.ts:非 Agent 备用生成逻辑
- ideaSelection.ts:Idea 筛选与 Slot 映射
- transitEnrichment.ts:交通信息查询与填充
- index.ts:runPlanGeneration 主入口

批次C:SSE 连接稳定性
- useRoomPolling.ts 加入指数退避重连(上限60s,含Jitter)
- plan/stream/route.ts 添加30s心跳 + abort信号清理

批次D:无障碍修复
- Modal:role=dialog、aria-modal、aria-labelledby
- AuthModal:aria-label关闭按钮、tablist/tab/aria-selected
- PlanItemEditModal、QrInviteModal:补全aria-label
- BlindboxPlan:图标按钮aria-label

批次E:Zod 引入
- src/lib/schemas/ai.ts:AI返回值 Schema(IdeaTagsSchema等5个)
- src/lib/schemas/requests.ts:请求体 Schema
- ai.ts 手工验证替换为 Zod safeParse

批次F:Server Components
- achievements/page.tsx → Server Component + AchievementsClient.tsx
- profile/page.tsx → Server Component + ProfileClient.tsx

批次G:Room 关系化模型
- prisma/schema.prisma:新增 RoomMember、RoomRestaurant、RoomLike、RoomSwipe 4张表
- migration:20260302010000_room_relational_model
- roomRepository.ts 完整重写(关系查询+应用锁)
- buildRoomStatus.ts 适配关系查询

测试:全部329个用例通过,修复68个因auth mock缺失导致的测试失败
2026-03-02 20:27:06 +08:00
kurihada ce76980fe5 refactor(P0): JWT 认证、并发安全、错误日志三项安全加固
- 新增 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 全景分析文档
2026-03-02 17:24:26 +08:00
kurihada 3ccd1262f9 test: 添加完整测试套件(52 个文件,326 个用例)
基于 Vitest 搭建测试基础设施,覆盖后端纯函数、API 路由、
前端 hooks、UI 组件和页面级集成测试。
2026-02-28 20:19:14 +08:00
kurihada dfb3cfa136 fix: 服务端验证强化 — 房间ID/坐标/swipe/盲盒竞态/空格
- #15: 房间 ID 扩展为 6 位字母数字,createRoom 用 P2002 重试替代 find-then-create
- #16: 盲盒编辑/删除改用 updateMany/deleteMany 原子操作,防止 TOCTOU
- #17: lat/lng 用 Number.isFinite + 范围校验 (-90~90, -180~180)
- #18: swipe action 必须为 'like' 或 'pass'
- #19: user PUT 的 JSON.parse(preferences) 加 try/catch
- #26: requireString 拒绝纯空格字符串
2026-02-26 20:19:56 +08:00
kurihada 508903b67d fix: SSE 认证 + 收藏去重 + 数据库索引和级联删除
- #7: SSE events 接口校验 userId 房间成员身份,start() 加 try/catch
- #9: Favorite 新增 restaurantId 字段做精确去重,不再用 JSON contains
- #10: 补齐 Decision/Favorite/Room/BlindBoxIdea 缺失索引
- #11: Decision/Favorite/BlindBoxMember/BlindBoxIdea 加 onDelete Cascade
2026-02-26 20:15:45 +08:00
kurihada 90d3b35069 fix: 房间 swipe/undo/reset 接口添加成员身份校验
- swipe/undo:校验 userId 在 data.users 中,非成员返回 403
- reset:要求传 userId,校验为房间成员或创建者
- 客户端 handleReset/handleNarrow 传入 userId
2026-02-26 20:09:40 +08:00
kurihada 9641acbcbd refactor: 提取 buildNavUrl 工具函数,统一 room API 错误处理
- 将 MatchResult.tsx 和 profile/page.tsx 中重复的导航 URL 构建逻辑提取到 src/lib/navigation.ts
- 7 个 room API 路由从 return NextResponse.json({ error }, { status }) 统一改为 throw ApiError,由 apiHandler 统一捕获
2026-02-26 19:31:00 +08:00
kurihada 19edcaeeb5 refactor: 提取 requireUserId/requireUser/requireMembership 校验工具
- 新增 requireUserId:统一 14 处 userId 非空校验,返回 401
- 新增 requireUser:统一 4 处用户存在性检查,返回 404
- validateMembership 升级为 requireMembership,直接抛 403
- 混合校验拆分为 auth(401) + 字段(400),状态码更准确
2026-02-26 18:17:17 +08:00
kurihada 0595887480 refactor: 引入 apiHandler + ApiError,消除 20 个路由的 try/catch 样板
- 新增 src/lib/api.ts:ApiError 错误类 + apiHandler 统一包装器
- 20 个 API 路由统一使用 apiHandler,删除重复的 try/catch 块
- 验证错误改用 throw new ApiError(),减少嵌套层级
- join/manage 路由的错误码映射改为直接抛出 ApiError
- 删除已无引用的 errorResponse 辅助函数
- 净减 273 行代码
2026-02-26 18:08:47 +08:00
kurihada 07ffe42176 feat: 房间创建者管理权限——锁定房间、踢人、结束投票 2026-02-24 21:01:24 +08:00
kurihada 8c0d89af6d feat: 用 SSE 替代 SWR 轮询,实现房间状态实时推送
SSE 断连时自动降级为 2s 轮询,重连后切回 SSE。
2026-02-24 19:51:30 +08:00
kurihada cb9f4a3d0f feat: 拆分"再来一轮"为 Top N 决赛和换一批餐厅两个选项 2026-02-24 19:34:35 +08:00
kurihada 5d297684fc feat: best 匹配结果页展示 Top 3 候选排行,支持折叠查看备选餐厅 2026-02-24 19:30:10 +08:00
kurihada 30329df136 fix: 0 票最佳匹配时展示"都不太满意"引导页,替代尴尬的 Trophy 展示 2026-02-24 19:26:54 +08:00
kurihada 998d0a4e15 fix: 刷新页面后恢复滑动进度,防止重复 swipe
服务端 GET room 返回 swipeCounts,前端据此恢复 currentIndex、
swipeHistory 和引导状态;swipe API 增加幂等性检查,跳过已滑过的卡片。
2026-02-24 18:40:42 +08:00
kurihada 48e74c03e6 feat: 撤回滑动功能,按钮移至进度条旁
- 新增 POST /api/room/[id]/undo 端点,撤回 like 和 swipeCount
- 进度条右侧显示"↩ 撤回"按钮,可一直撤回到第一张
- ActionButtons 恢复干净的两按钮布局,避免误触
2026-02-24 17:48:47 +08:00
kurihada fb49e21eb2 feat: 增加滑动参与感 - 进度条、实时气泡、热度标签
- 卡片上方显示滑动进度条和计数 (3/15)
- 轮询检测到当前卡片新增 like 时弹出"有人也想去这家!"气泡
- 卡片图片角落显示"🔥N 人想去"热度标签
- 后端 GET /api/room/[id] 新增 likeCounts 字段
2026-02-24 17:36:04 +08:00
kurihada a72f7ed884 fix: 修复滑完后卡在等待状态的问题
- findBestMatch 不再返回 null,无人 like 时按评分兜底推荐
- 移除即时匹配的 users.length > 1 限制,支持单人房间
2026-02-24 17:30:59 +08:00
kurihada e2c3b869eb feat: 两级匹配机制 - 全票通过即时匹配 + 滑完自动推荐得票最高
- 后端 GET /api/room/[id] 新增 findBestMatch,滑完后选出得票最高餐厅
- 平票时取高德评分更高的一家,永远不会出现"无结果"死局
- 返回 matchType (unanimous/best) 和 matchLikes 区分匹配类型
- 全票通过:绿色庆祝 + "大家一拍即合!"
- 得票最高:橙色推荐 + "N/M 人想去这家"
- 移除 noMatch 死局页面,简化 SwipeDeck 状态管理
2026-02-24 17:26:16 +08:00
kurihada 77d15f29e3 fix: 修复竞态条件、重置逻辑、无匹配终态等关键问题
- 用 Prisma $transaction 实现 atomicUpdateRoom,防止并发写入覆盖
- 新增 POST /api/room/[id]/reset 端点,修复"再来一轮"按钮死循环
- 新增 swipeCounts 字段追踪滑动进度,检测"无人匹配"终态
- 着陆页 handleCreate 增加 res.ok 检查,防止跳转到无效房间
- 匹配或无匹配后停止轮询,减少无效请求
2026-02-24 17:04:16 +08:00
kurihada d87d30ccc0 feat: 实现 NoWhatever 别说随便餐厅决策 Web App
- Framer Motion 卡片滑动 UI,带物理阻尼动画
- 多人房间系统,4位房间号 + SWR 实时轮询
- 高德地图 POI v5 API 搜索附近餐厅
- Web Share API 一键邀请,剪贴板降级方案
- SQLite/Prisma 持久化存储
- 移动端优先响应式设计 (Tailwind CSS)
2026-02-24 16:49:43 +08:00