Commit Graph

136 Commits

Author SHA1 Message Date
kurihada 482307f2f4 清理 lint 剩余告警并更新审计文档状态 2026-03-03 13:53:19 +08:00
kurihada d91ea8c1e8 补充核心回归测试并完成补测清单 T1-T4 2026-03-03 13:33:42 +08:00
kurihada 22610f0b59 统一盲盒前端 API 调用层并收敛错误处理 2026-03-03 13:17:42 +08:00
kurihada 532d8ff7ad 统一盲盒请求契约并移除冗余 userId 参数 2026-03-03 13:11:33 +08:00
kurihada 4a5ed3b25a 优化房间点赞同步为增量更新策略 2026-03-03 13:07:22 +08:00
kurihada 325b7b5742 优化计划查询避免 N+1 数据库访问 2026-03-03 13:05:29 +08:00
kurihada 41ac21ea12 完善 CI 质量门禁并启用覆盖率阈值 2026-03-03 13:02:31 +08:00
kurihada 4cd593bc30 修复定时器与动画回调清理不完整问题 2026-03-03 12:27:34 +08:00
kurihada 45dbac1935 修复 lint 阻塞错误并恢复门禁 2026-03-03 12:25:03 +08:00
kurihada 52b87abee3 修复 TypeScript 基线并补齐测试类型 2026-03-03 12:21:02 +08:00
kurihada 673dc1177e 修复计划接受流程的前后端状态不一致 2026-03-03 12:16:04 +08:00
kurihada 67fdf7427a 修复 SSE 成员校验未生效的问题 2026-03-03 12:14:38 +08:00
kurihada 5a6d457a87 修复 API 500 响应泄露内部错误细节 2026-03-03 12:11:02 +08:00
kurihada 486193c823 修复 suggest-item 接口缺失鉴权并补充测试 2026-03-03 12:08:35 +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 6bb0e65d4c refactor(P1): 5 项代码质量改进 — 消除重复、拆分巨型组件、统一基础设施
Task 4: 统一 amap.ts 为完整 API 客户端
- 扩展 amap.ts 为统一客户端(amapFetch 8s 超时 + 错误处理)
- 导出 searchPlaceText/searchPlaceAround/getInputTips/reverseGeocode/getTransitDirection
- 精简 4 个 location route 为单行调用,blindboxPlanGen 删除 ~80 行内联 API 代码

Task 2: 抽取 ShareCardShell 消除三兄弟重复
- 新建 ShareCardShell.tsx 共享外框/背景/品牌头/QR 底部
- RestaurantShareCard 406→268 行,BlindboxShareCard 341→173 行,BlindboxPlanShareCard 277→159 行

Task 3: 拆分 BlindboxPlan.tsx (742→371 行)
- 提取 planUtils.ts (guessCategory + formatDuration)
- 提取 PoiSearchField / SortablePlanItem / PlanItemEditModal 三个独立组件

Task 1: 拆分 blindbox/[code]/page.tsx 上帝组件 (1300→509 行)
- 提取 useBlindboxRoom / useBlindboxIdeas / useBlindboxPlan / useBlindboxDraw 四个 hooks
- 提取 BlindboxPoolPhase / BlindboxRevealPhase 两个子组件
- 主页面仅保留 phase 协调 + hook 组装 + 子组件渲染

Task 5: 统一 SWR 数据获取层
- 新建 fetcher.ts (FetchError 携带 status,401 不重试)
- 新建 useBlindboxRooms / useAchievements / useFavorites SWR hooks
- useRoomPolling 改用共享 fetcher
- blindbox 大厅/成就/个人中心页面删除手写 fetch 样板代码
- JWT 过期时自动弹出登录框而非反复重试
2026-03-02 18:05: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 99120a7042 feat: 交通信息与 AI 解耦,完善出发/回程路线显示
- 从 finalize_plan schema 和 agent 提示词中移除 transit 字段,AI 只负责活动/POI/坐标
- 新增 enrichTransitInfo:计划生成后查询高德 V3 公交 API,计算出发地→首活动、活动间、末活动→出发地三段交通
- parseTransitSegments 增加起终点站显示(去除线路名中的全程终点括号)
- WeekendPlanData 新增 transitFromStart/transitToEnd 字段
- BlindboxPlan 新增出发地和返回出发地交通连接器,传入 startLocationLabel 显示具体地址
- BlindBoxRoom schema 新增 address 字段存完整逆地理地址,city 保留供 API 使用
- 新增 /api/debug/transit 调试端点(仅开发环境)
- agent userPrompt 要求将出发/回程时间计入全天时间预算
2026-03-02 16:35:38 +08:00
kurihada e5a255a49e feat: 行程卡片间显示交通路线描述和时间
- get_travel_time 解析 Amap segments 提取线路名和站数
- PlanItem 新增 transitToNext / transitDescription 字段
- finalize_plan schema 加入 transit_to_next_description
- 修复 Turbopack 中文引号解析报错
- UI 连接器改为两行布局,路线描述与时长分行显示
2026-03-02 14:20:53 +08:00
kurihada 7b6ce22f63 fix: 修复行程卡片间距被 last:mb-0 清零的问题
每个 SortablePlanItem 被 motion.div 包裹,last:mb-0 会对
所有 item 生效导致 mb-5 失效,移除 last:mb-0 即可。
同步优化卡片内部间距、padding、reason 加分隔线。
2026-03-02 13:03:53 +08:00
kurihada 04a45c4894 feat: AI 辅助修改行程(自然语言调整 + 单活动替代推荐)
- 新增 refinePlan / suggestAlternativeItems 到 ai.ts
- 新增 POST /api/blindbox/plan/refine(整体行程调整)
- 新增 POST /api/blindbox/plan/suggest-item(单活动 AI 替代 + POI 搜索)
- BlindboxPlan 底部新增自然语言输入框(方案 A)
- 编辑 modal 内新增 AI 推荐替代方案卡片(方案 B)
- export searchPois 供 suggest-item 路由复用
2026-03-02 12:29:21 +08:00
kurihada 4e6a3e007c feat: 行程活动拖拽排序 + 编辑表单(含高德 POI 搜索)
- 安装 @dnd-kit/core/sortable/utilities/modifiers
- BlindboxPlan: 同天内拖拽排序(PointerSensor + TouchSensor,限垂直轴)
- BlindboxPlan: 点击编辑弹出 sheet modal,支持改时间(type=time)、时长、活动名
- BlindboxPlan: POI 字段改为高德 inputtips 搜索下拉,选中自动填入名称/地址/坐标
- BlindboxPlan: 搜索传入房间坐标 location 参数,结果按距离排序
- BlindboxPlan: 跨天移动通过 select 立即生效
- plan route: 新增 update_plan action,支持 PATCH 保存修改后的 days
- page.tsx: 新增 handlePlanDaysChange,乐观更新本地 state + 失败时回滚
2026-03-02 12:06:50 +08:00
kurihada df2e373beb feat: 改进计划生成体验与 AI 提示词
- 生成中状态改为滚动日志列表,底部新增消息自动滚动
- 返回想法池不再清空计划,pool 页面保留"待确认计划"横幅
- 换方案时才清空旧计划
- 提示词补充午餐/晚餐时间窗口约束(午餐11:30-13:00,晚餐17:30-19:30)
- get_travel_time 从驾车改为公共交通,阈值从30分钟调整为45分钟
2026-03-02 11:26:20 +08:00
kurihada b78063739b fix: 盲盒想法打标改为后台异步,新增 retag 补打接口
- applyTags 改为 fire-and-forget,用户投入想法立即返回(<200ms)
- 打标超时设为 60s,失败静默,由 /api/blindbox/retag 兜底
- 新增 POST /api/blindbox/retag:补打房间内所有无标签想法
2026-03-02 10:55:27 +08:00
kurihada 9d891fb702 feat: 为行程规划 agent 添加 get_travel_time 工具,调用高德驾车 API 验证交通时间
agent 之前完全靠 LLM 猜测地理距离,现在可以查询真实驾车时间,超过 30 分钟会换更近地点。
同时修复 dev 端口未生效的问题(next dev 加 --port 3721)。
2026-03-02 10:21:00 +08:00
kurihada ea49ce6081 chore: 端口从 3000 改为 3721 避免冲突 2026-03-02 01:07:45 +08:00
kurihada 7fd1005e03 feat: 行程规划改用 tool-calling agent,旧逻辑保留为降级方案
ai.ts 新增通用 runAgentLoop(),blindboxPlanGen.ts 拆分为
agent 主路径(list_ideas/search_poi/finalize_plan 三个工具)
和 legacy 降级路径,agent 失败时自动回退。
AI 思考和工具调用实时推送给前端。
2026-03-02 01:07:25 +08:00
kurihada 93499867d5 feat: 改进标签系统 — 新增品类/费用/强度/预约标签,timeSlot 参与选活动
- IdeaCategory 扩展 7→9,新增 experience(体验)和 nature(自然)
- 替换 outdoor boolean 为 costLevel/intensity/needsBooking 三个高价值字段
- AI 标注 prompt 同步更新,行程规划新增强度交替、费用平衡、预约提醒原则
- selectIdeasForSlots 重写为四优先级:timeSlot+category > category > timeSlot > 任意
- 前端想法卡片展示费用/强度/预约标签
2026-03-02 00:03:35 +08:00
kurihada fe9a52e2e4 fix: API 500 错误返回具体原因,便于线上排查 2026-03-01 21:59:23 +08:00
kurihada 3ccd1262f9 test: 添加完整测试套件(52 个文件,326 个用例)
基于 Vitest 搭建测试基础设施,覆盖后端纯函数、API 路由、
前端 hooks、UI 组件和页面级集成测试。
2026-02-28 20:19:14 +08:00
kurihada 3e7bb51618 fix: 房间加载失败时显示具体错误原因,便于线上排查 2026-02-28 17:30:09 +08:00
kurihada 1e39c72a63 fix(blindbox): 修复房间创建后返回大厅不可见 + 大厅房间列表管理
- 修复房主退出房间时误删整间房的问题,改为返回大厅(房间保留)
- 修复大厅页 fetchRooms 时序依赖导致导航回来不刷新的问题
- fetch 添加 cache:no-store + router.refresh() 确保数据始终最新
- 房间列表增加 max-h 滚动 + 底部渐变遮罩防溢出
- 大厅房间卡片支持内联删除/退出(··· 按钮 → 确认栏)
- rooms API 返回 creatorId 以区分房主/成员操作
2026-02-27 18:38:05 +08:00
kurihada 2d49744dd0 feat(blindbox): AI 计划生成流式进度与渐进式文案
- 新增 runPlanGeneration 与 onProgress 回调 (blindboxPlanGen.ts)
- 新增 POST /api/blindbox/plan/stream 推送 SSE 进度事件
- 前端优先走流式接口,实时展示「分析想法→搜索地点→规划路线→快好了」
- 流式失败时回退普通 POST,客户端轮播进度文案作为后备
- 规划阶段 UI 显示 planStatusMessage 替代静态文案
2026-02-27 17:37:40 +08:00
kurihada 9aee4f0e9b fix(blindbox): 周末契约页输入框无法输入 — 非受控输入 + 全局 input 样式
- 创建/加入房间输入改为 ref + defaultValue,提交时从 DOM 取值,避免受控 state 导致无法打字
- globals: input/textarea 增加 user-select: text !important、touch-action: manipulation
- Input 组件: cursor-text、touch-manipulation、min-w-0、autoComplete=off
2026-02-27 17:27:51 +08:00
kurihada 61ef54b2bd feat: 盲盒想法输入增加 AI 灵感推荐
输入框下方展示灵感建议标签,点击即填入,降低创作门槛:
- 房间有 ≥2 条想法时调用 DeepSeek 生成贴合调性的推荐
- 想法不足或 AI 失败时 fallback 到 18 条静态灵感随机选 4 条
- 提交新想法后自动刷新推荐,支持手动换一批
2026-02-27 16:52:59 +08:00
kurihada 76349f0dcf feat: 接入全站图片资源 + 修复卡片滑动与房间轮询问题
图片资源接入:
- OG/Twitter 社交分享元数据 (og-image.png)
- 错误页插画替换图标 (error-robot.png)
- EmptyState 组件支持 image prop,空状态页面接入插画
- 餐厅图片 fallback 改用 restaurant-fallback.png
- 极速救场/周末契约页面添加 hero 装饰图
- 分享卡片添加背景图层 (share-bg-*.png),通过 base64 预加载
- 更新 App 图标 (apple-touch-icon, icon-192/512)

Bug 修复:
- SwipeDeck: swipe action 从 "nope" 改为 "pass",匹配 API 预期
- SwipeDeck: 用 ref 读取 currentIndex 避免竞态重置(本地滑动后
  被服务端旧 swipeCounts 立即清零)
- SwipeDeck: 卡片 key 加入 isTop 标识,强制 remount 解决
  framer-motion drag 手势在 isTop 切换时不重新初始化的问题
- SwipeableCard: initial 统一为背景位置,确保晋升为顶部卡片时
  有一致的放大动画
- useRoomPolling: roomId 为空时跳过 SWR 和 EventSource
- room page: joinRoom 前 guard roomId,消除退房时 404
- layout: 添加 metadataBase 消除 Next.js OG 图片警告
2026-02-27 16:08:38 +08:00
kurihada 4073be9066 fix: invite 页面补充 Utensils 图标导入,修复编译失败 2026-02-27 11:43:40 +08:00
kurihada 3335f7f872 refactor: 移除 Service Worker 离线缓存 + 统一注册引导文案
- 删除 sw.js、ServiceWorkerRegistrar、offline 页面
- 保留 manifest 和 PWA 图标(添加到主屏幕仍可用)
- 注册引导文案统一为"10 秒注册,无需手机号"
2026-02-27 10:38:33 +08:00
kurihada 4cc9d66403 fix: SW 缓存导致页面不更新 — fetch 绕过 HTTP 缓存 + hydration 闪屏修复
- sw.js: HTML fetch 加 cache:"no-cache",避免从浏览器缓存拿旧页面
- ServiceWorkerRegistrar: 注册时 updateViaCache:"none",确保 SW 自身及时更新
- blindbox/page: 增加 hydrated 状态,防止 SSR/CSR 内容不一致导致闪屏
2026-02-27 10:28:23 +08:00
kurihada beb2c632bb refactor: 移除个人页面决策记录,统一由成就墙展示
决策记录已完整迁移至 /achievements 成就墙页面,
个人中心不再重复展示,减少冗余数据请求。
2026-02-27 10:05:22 +08:00
kurihada c17b13b6a8 feat: 契约生命周期 + 到期通知 + 成就墙
- 扩展 WeekendPlan schema: 新增 endTime 字段与 userId 索引
- PATCH /api/blindbox/plan 支持 accept/complete/expire 操作,
  接受时自动计算契约结束时间
- GET /api/blindbox/plan 支持 mode 参数 (latest/pending/history)
- 房间页接受契约后自动返回想法池,顶部显示"契约进行中"指示器
- 契约到期时触发浏览器通知 + 页面加载时弹出完成确认弹窗
- 新增 /achievements 成就墙页面:统计数据 + 决策记录/契约记录双标签
- 首页和个人中心新增成就墙入口
2026-02-27 02:12:18 +08:00
kurihada d8e42b860f feat: 已接受契约持久化 — 保存/加载/自动展示
- PATCH /api/blindbox/plan: 接受契约时更新状态为 accepted
- GET /api/blindbox/plan: 查询房间内最近一次已接受的计划
- 进入房间时自动加载已接受计划并展示行程视图
- 修复整个周末想法不足时重复活动的问题(不足则只生成一天)
2026-02-27 01:57:42 +08:00
kurihada 9c680ec11e feat: AI 周末行程规划 — DeepSeek 智能排期 + 高德 POI + 多日翻页
- 接入 DeepSeek API,提交想法时自动 AI 打标(品类/时段/时长/搜索策略)
- 新增行程规划 API:智能选取想法 → 高德 POI 搜索 → AI 生成最优行程
- 支持多日计划("整个周末"拆分周六/周日,并行 AI 调用)
- 行程展示逐日翻页,时间线可滚动,操作按钮固定底部
- 分享卡适配多日格式,支持图片保存与原生分享
- Prisma schema 新增 WeekendPlan 模型及 BlindBoxIdea AI 标签字段
- Jenkinsfile 集成 DEEPSEEK_API_KEY 环境变量
2026-02-27 01:51:47 +08:00
kurihada 8c6da410ca style: 周末契约顶部对齐极速救场 + 首页卡片样式统一
- blindbox/page: 加 justify-center 让标题垂直位置与 panic 页保持一致,移除 flex-1 子容器
- page: 周末契约卡片色值统一用 white/* 透明度,去掉紫色 drop-shadow,简化 hover 光晕
2026-02-27 00:12:58 +08:00
kurihada fbb2c22964 feat: 场景细分为餐厅/咖啡奶茶/甜品 + 附近搜索优先 + 美食多选标签 2026-02-26 23:04:25 +08:00
kurihada c0662de3dd feat: 美食多选 + 自定义输入标签 2026-02-26 21:40:14 +08:00
kurihada ab55f0981e feat: 地点搜索附近优先 — 透传用户坐标给高德 inputtips 2026-02-26 21:00:48 +08:00
kurihada deba7ab2bb fix: AudioContext 复用 + 盲盒加载错误提示 + icon 按钮 aria-label
- #27: panic/blindbox/ShareCardModal/AuthModal 中 icon-only 按钮补 aria-label
- #28: playChime 缓存复用单个 AudioContext,避免超出浏览器 ~6 个上限
- #29: 已完成(上一批次 ApiError.name = "ApiError")
- #30: blindbox lobby fetchRooms 失败时显示"加载失败/点击重试"
- #31: 已完成(theme.ts VALID_THEMES 校验)
2026-02-26 20:25:56 +08:00