petstore-docs/P0-研发落地清单.md
2026-08-01 21:56:07 +08:00

177 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 宠小它 — P0 研发落地清单
> **本体对齐**:任务条目引用 [`ontology/`](./ontology/) 中的实体/规则 ID如 `entity:report`、`rule:BR-RPT-002`)。冲突以本体为准。
>
> 用途:发给研发拆任务与验收;**仅含 P0**(本期质量与主线闭环必需,不含 P1/P2 增强)。
> 依据:《产品全方位优化说明 v1》《本期主线》《宠主端预约体验优化》《产品设计文档》及当前仓库实现粗对齐。
> 更新2026-07-05P0 稳定化轮次:冻结本期范围,重新标记状态并绑定 Owner 与验收命令)
**关联** [产品全方位优化说明-v1](./产品全方位优化说明-v1.md) · [本期主线-下一步产品优化点](./本期主线-下一步产品优化点.md) · [宠主端预约体验优化-产品说明](./宠主端预约体验优化-产品说明.md) · [架构与产品评估报告-2026-07-05](./架构与产品评估报告-2026-07-05.md) · [Cursor P0 Handoff](./superpowers/plans/2026-07-05-cursor-p0-handoff.md)
---
## 本期 P0 范围(冻结口径)
本期 P0 范围:
- 门店端:预约列表、开始服务、填写报告、发送报告、回访池。
- 宠主端:预约填单、公开报告页、下次服务提醒留资、报告打开基础埋点。
- 报告能力:服务前/服务后照片、服务过程素材、短片生成与下载、分享链接/二维码/话术。
不进入 P0
- 会员、储值、套餐、复杂 CRM。
- 宠主账号内历史报告汇总。
- 完整经营分析看板。
- 「到店不排队」等无容量模型承诺,统一文案为「在线选时段,到店更省心」。
---
## 状态标记说明
- ✅ 已实现:仓库已实现且通过本次构建/验收命令。
- 🟡 部分实现:主路径已落,但仍有 gap已列出需按验收命令闭环。
- ❌ 未实现:本期必须补齐。
- 🧪 待测试:实现可能已存在,但缺自动化测试或人工 smoke 证据。
---
## 优先级说明
- **P0**:本迭代必须交付;阻塞对外口碑、数据脏读、合规提示缺失、或主线(传播/成片/留资)不可用。
- 已部分实现的项:**仍保留**,以下方「验收标准」为准做 gap 关闭。
---
## A. 后端Spring Boot
| ID | 需求 | 验收标准 | Owner | 状态 | 验收命令 | 备注 |
|----|------|----------|-------|------|----------|------|
| **A1** | **预约状态机校验**`PUT /appointment/status`(及任意改状态入口)禁止非法迁移 | 仅允许:`new→doing`、`new→cancel`、`doing→done`、`doing→cancel`(与产品最终规则一致);非法迁移返回 **4xx + 明确业务码**(如 `INVALID_STATUS`、`CANCEL_NOT_ALLOWED` | Backend Core | 🟡 部分实现:`AppointmentService.updateStatus`/`startService` 已集中校验,但缺自动化测试 | `mvn -f backend/pom.xml test`(待补 `AppointmentServiceTest` | 与「谁点谁服务」一致Batch D 补测试 |
| **A2** | **开始服务**仅当 `status=new` | `startService``new` 时拒绝,勿静默改库 | Backend Core | 🟡 部分实现:服务层已校验,需补测试 | 同 A1 | 与 A1 同一套状态机 |
| **A3** | **取消预约**校验:仅允许目标状态为 `cancel` 且前置状态符合产品规则 | 与 A1 同一套状态机;前端取消按钮仅 `new` 时展示则后端仍要防篡改 | Backend Core | 🟡 部分实现:状态机已收口,需补测试 | 同 A1 | 防恶意请求 |
| **A4** | **留资去重**:同一 `report_token` + 同一手机号 | 二次提交返回成功态或「已提交」语义,不重复插库 | Report Media Backend | 🟡 部分实现:去重逻辑已存在,需补测试用例 | `mvn -f backend/pom.xml test`(待补 `ReportLeadControllerTest` | 口径见《本期主线》C |
| **A5** | **公开报告字段裁剪**`GET /api/report/get?token=` 不返回 top-level `userId/storeId/reportToken`;日志只记 token hash | 公开 token 请求只返回页面必要字段store 对象可返回 `id` 用于预约跳转 | System Architect / Report Media Backend | ✅ 已实现Batch B | 手工 curl + `mvn test` | 对应 P0-2 |
| **A6** | **报告一约一份**`Report.appointment_id` 唯一约束;服务层拒绝同预约重复提交 | 同一 `appointmentId` 第二次提交返回 409 / `REPORT_ALREADY_EXISTS`;非 `doing` 预约不能创建报告;无预约提交返回 `APPOINTMENT_REQUIRED` | System Architect / Data Model / Report Media Backend | ✅ 已实现Batch B/D`ReportServiceTest`/`ReportControllerTest` | `mvn -f backend/pom.xml test` | 对应 P0-3上线前需清理重复数据 |
| **A7** | **报告前后照片必填后端兜底** | 缺 before 返回 `BEFORE_PHOTO_REQUIRED`;缺 after 返回 `AFTER_PHOTO_REQUIRED` | Report Media Backend | ✅ 已实现Batch B`ReportControllerTest` | `mvn -f backend/pom.xml test` | 与前端 B5 同步落地 |
| **A8** | **统一鉴权上下文**HMAC session token + `CurrentUserContext`protected API 不再信任请求里的身份字段 | 未登录返回 401A 店用户访问 B 店预约/报告/线索返回 403customer 不能用任意 `userId` 创建他人宠物/预约 | System Architect / Backend Core | ✅ 已实现Batch C`SessionTokenServiceTest` | `mvn -f backend/pom.xml test` + 跨店/跨用户接口验证 | 对应 P0-1不引入完整 Spring Security |
| **A9** | **线索脱敏**`/report/leads` 默认不返回完整 `wechatOpenid/wechatUnionid` | 回包只有 `wechatBound`、`wechatOpenidMasked`、`wechatUnionidMasked` | Report Media Backend | ✅ 已实现Batch B | 手工 curl + `mvn test` | 对应 P0-2 |
| **A10** | **配置安全与启动迁移收口**`application.yml` 不保留真实敏感值;生产 profile 禁用 `ddl-auto:update`/`show-sql`;移除启动期 DDL/历史 UPDATE | 仓库不含真实 DB/微信密钥;生产启动只读环境变量 | Backend Ops / System Architect | ✅ 已实现Batch D | `rg` 扫描 + 启动验证 | 对应 P0-8已暴露凭据需轮换 |
| **A11** | **上传路径与类型保护**`FileController` 归一化路径 + 扩展名/MIME 校验 | `/api/upload/image/../...`、伪装扩展名、超大文件均被拒绝 | Backend Core / System Architect | ✅ 已实现Batch D | 手工 curl + `mvn test` | 对应 P0-9 |
| **A12** | **最小测试基线**:补 `SessionTokenServiceTest`、`ReportServiceTest`、`ReportControllerTest`、`AppointmentServiceTest` | `mvn test` 不再输出 `No tests to run`,新增用例全部通过 | Core Flow QA / System Architect | ✅ 已实现Batch D | `mvn -f backend/pom.xml test` | 对应 P0-10持续回归数量以 Surefire 当次统计为准 |
| **A13** | **预约/报告身份语义拆分**:客户、创建人、服务技师、报告作者不得复用同一语义字段 | customer 自约身份从 session 派生门店代约必须提供真实宠主宠主报告按预约客户归属查询legacy 字段只做兼容 | System Architect / Backend Core / Report Media Backend | ✅ 已实现Phase 0 RC1 后) | `mvn -f backend/pom.xml test` + H5/小程序构建 | 迁移见 `backend/db/migrations/20260801_split_service_identity.sql` |
| **A14** | **StoreCustomer 门店客户主档**:客户列表不再临时拼成无 ID 投影 | 预约/留资自动建档同店账号与手机号唯一API 返回 storeCustomerId 且手机脱敏;历史数据可回填 | Backend Core / Report Media Backend / Data Model | ✅ 已实现(待生产迁移) | `mvn -f backend/pom.xml test` + `npm --prefix admin run build` | 迁移见 `backend/db/migrations/20260801_create_store_customer.sql` |
---
## B. 小程序 — 门店端(老板/员工)
| ID | 需求 | 验收标准 | Owner | 状态 | 验收命令 | 备注 |
|----|------|----------|-------|------|----------|------|
| **B1** | **「已完成」Tab 列表默认不含已取消** | Tab「已完成」下默认仅展示 `status===done``cancel` 通过次级筛选或单独子 TAB 实现 | Store Miniapp FE | 🟡 部分实现(以现状为准做回归) | `npm --prefix frontend run build:h5` + 手工 smoke | 当前 `Home.vue` 需对照 |
| **B2** | **发送报告成功页**:同屏 报告链接 + 二维码 + 两条可复制话术 | 话术支持变量:`{宠物名}{服务类型}{门店名}{链接}`;一键复制单条话术 | Store Miniapp FE | ✅ 已实现(`ReportShareModal.vue` | `npm --prefix frontend run build:h5` + 手工 smoke | 对齐《本期主线》A |
| **B3** | **报告提交锁死提示** | 提交前弹窗固定文案:「提交后不可修改,请确认照片与备注无误」 | Store Miniapp FE | 🟡 部分实现:核对文案与位置 | 手工 smoke | 与产品 v1 锁死策略一致 |
| **B4** | **「我的」老板端分组标题** | 至少两组:`店铺与经营` / `团队与账号`;高频在上;使用 `.module-title` | Store Miniapp FE | ✅ 已实现 | `npm --prefix frontend run build:h5` + 手工 smoke | 见《产品全方位优化说明》§2.2 |
| **B5** | **报告前后照片必填前端校验** | 无 before 提示「请至少上传1张服务前照片」无 after 提示「请至少上传1张服务后照片」 | Store Miniapp FE / Customer Experience FE | ✅ 已实现Batch A | `npm --prefix frontend run build:h5` + `npm --prefix frontend run build:mp-weixin` | 对应 A7、P0-4 |
---
## C. 小程序 — 宠主端customer
| ID | 需求 | 验收标准 | Owner | 状态 | 验收命令 | 备注 |
|----|------|----------|-------|------|----------|------|
| **C1** | **单一主预约路径** | 首屏仅保留一个主级「预约服务」入口;不再同屏强并存「大按钮 + 空态大按钮 + FAB +」等效重复 | Customer Experience FE | 🟡 部分实现:需对照当前 `Home.vue` 复核 | 手工 smoke | 见《宠主端预约体验优化》§9 |
| **C2** | **扫码 / 分享落地 `storeId`**(含小程序码 `scene` 解码) | 普通 `storeId` query、小程序码 `scene=storeId%3D1`、分享 path/query 均预填门店且可「更换门店」 | Customer Experience FE | ✅ 已实现Batch A | `npm --prefix frontend run build:h5` + `npm --prefix frontend run build:mp-weixin` + 手工 smoke | 对应 P0-6、P1-1 |
| **C3** | **登录时机与草稿**(冻结策略:提交时登录 + guest 草稿恢复) | 未登录可填单,提交时跳登录,登录后草稿恢复;草稿 key 不依赖 `userInfo.id`;不会产生 `userId: undefined` | Customer Experience FE / Backend Core | ✅ 已实现Batch A | 手工 smoke未登录填写 → 提交跳登录 → 草稿恢复 | 与 `Login.vue` redirect 联动 |
| **C4** | **异常可理解** | 无可用时段、网络失败、未登录:均有 toast / 空态 / 重试,禁止静默失败 | Customer Experience FE | 🟡 部分实现:需逐场景回归 | 手工 smoke | 专文 §7 |
| **C5** | **报告页角色判断**`isStaff` 改为角色判断boss/staff | customer 登录态打开公开报告页仍显示留资/预约 CTAboss/staff 才显示内部分享/保存 | Customer Experience FE | ✅ 已实现Batch A | 手工 smoke | 对应 P0-7 |
---
## D. H5 报告页(`report-view` / 独立 H5
| ID | 需求 | 验收标准 | Owner | 状态 | 验收命令 | 备注 |
|----|------|----------|-------|------|----------|------|
| **D1** | **隐私提示(短期策略)** | 首屏或固定条:「本页含宠物服务影像,请勿公开转发或发群」 | Customer Experience FE / Product Design | 🟡 部分实现:核对文案与位置 | 手工 smoke | 对齐《本期主线》A token 风险 |
| **D2** | **短片三态与文案对齐小程序** | `processing / failed / success``ReportHighlightBlock` 一致;失败展示归类中文,不暴露堆栈 | Customer Experience FE | 🟡 部分实现:需对照三态文案 | 手工 smoke | H5 与小程序报告页行为一致 |
| **D3** | **弱网 / 失败重试** | 报告主接口失败:按钮「重新加载」;超时阈值 810s 后出失败态 | Customer Experience FE | 🟡 部分实现 | 手工 smoke | 与《产品全方位优化说明》§3.3 |
| **D4** | **公开报告 token 使用方式**:不依赖回包 `reportToken`,只用路由 token 做留资/分享 | 公开报告页 `reminderToken` = 路由 token不读 `reportData.reportToken` | Customer Experience FE | ✅ 已实现Batch A | 手工 smoke + 代码审查 | 与 A5 联动 |
---
## E. 传播与埋点P0 最小集)
| ID | 需求 | 验收标准 | Owner | 状态 | 验收命令 | 备注 |
|----|------|----------|-------|------|----------|------|
| **E1** | **分享卡片元信息规则** | 小程序 `onShareAppMessage`:标题「宠物名 + 服务 + 门店」;封面优先级 成片封面 > 服务后首图 > Logo | Customer Experience FE | ✅ 已实现(`reportShare.js` | 手工 smoke + 代码审查 | 见 `frontend/src/utils/reportShare.js` |
| **E2** | **埋点:报告打开** | 上报:`report_token` 匿名 hash、首次/再次、时间戳;落地页 H5 亦要能报 | Report Share QA / Backend Ops | 🟡 部分实现:日志已有,缺事件 schema 与统计落地 | 见《本期主线》埋点 schema 表 | 对应 P0-10、P1-4 |
| **E3** | **埋点事件 schema**(最小集) | 定义 `report_open`、`report_reopen`、`highlight_success`、`highlight_failed`、`video_play`、`video_save`、`lead_submit` 字段、来源、统计窗口 | Report Share QA / Product Design | ✅ 已冻结Batch A 文档) | 见《本期主线-下一步产品优化点》埋点 schema 表 | 对应 P1-4 |
---
## F. 视觉与规范(工程债)
| ID | 需求 | 验收标准 | Owner | 状态 | 验收命令 | 备注 |
|----|------|----------|-------|------|----------|------|
| **F1** | **禁止业务页硬编码主色** | 主色/品牌浅底统一 `var(--c-brand)` 等;`rg "#16a34a|#2db96d"` 业务 vue 内为 0`global.css`/极少量渐变定义) | Store Miniapp FE / Customer Experience FE | 🟡 部分实现 | `rg "#16a34a|#2db96d" frontend/src/pages` | 《前端 UI 规范》已对齐 `--c-*` |
| **F2** | **空态禁用 emoji 作主视觉** | 宠主空态等用 `AppIcon` 或插图占位,不用 📋 等作为主视觉 | Customer Experience FE | 🟡 部分实现 | 代码审查 | 见 `Home.vue` 空态 slot |
---
## G. 文案与对外承诺(配置级)
| ID | 需求 | 验收标准 | Owner | 状态 | 验收命令 | 备注 |
|----|------|----------|-------|------|----------|------|
| **G1** | **无容量模型不写「排队」** | 全局检索「排队」「不排队」;宠主副标题等改为「在线选时段,到店更省心」 | Product Design / Customer Experience FE | ✅ 已实现Batch A 文档冻结) | `rg "到店不排队|不排队" docs frontend/src` | 与《产品全方位优化说明》D2 一致 |
| **G2** | **对内录单表述(可选)** | 门店端新建预约入口文案是否改为「代客预约」由产品拍板;若改则全局统一 | Product Design | 🟡 待产品拍板 | — | 降低「预约」歧义 |
---
## H. 发布 RC 门禁Batch D 收口)
| ID | 需求 | 验收标准 | Owner | 状态 | 验收命令 | 备注 |
|----|------|----------|-------|------|----------|------|
| **H1** | **backend README RC 清单** | 含 `ffmpeg -version`、`ffprobe -version`、`curl -I $APP_BASE_URL/api/upload/image/<known-file>`、`mvn test`;写明 `APP_BASE_URL`、`HIGHLIGHT_*`、`PETSTORE_SESSION_SECRET`、上传目录权限、Nginx `client_max_body_size` | Backend Ops | ✅ 已实现Batch D | 代码审查 | 对应 P0-10 |
| **H2** | **frontend README RC 清单** | 含 `npm install`、`build:h5`、`build:mp-weixin`;写明 `VITE_API_ORIGIN`、`VITE_REPORT_PUBLIC_ORIGIN`、微信 request/download 合法域名、报告二维码链接检查 | Frontend Release Ops | ✅ 已实现Batch D | 代码审查 | 对应 P0-10 |
| **H3** | **P0 通过条件** | 见下方「P0 通过条件」块 | System Architect / Core Flow QA | 🟡 待人工 smoke 复核 | 见下方 | 对应 P0-10 |
---
## 建议排期顺序(供研发参考)
1. **A1A3**(后端状态机)— 防脏数据,优先合。
2. **B1**(已完成 Tab— 前端小改、用户感知强。
3. **B2、D1、D2、E1**(传播与报告体验)— 主线门面。
4. **C1C5**(宠主)— 与登录/路由并行可排。
5. **E2、E3、F1、F2、G1** — 可并行或插空。
6. **A5A12**(后端边界、隐私、配置、上传、测试)— Batch B/C/D。
7. **H1H3**(发布 RC 门禁)— Batch D 收口。
---
## P0 通过条件(最终门禁)
- 后端 `mvn -f backend/pom.xml test` 有实际测试用例并通过(不再 `No tests to run`)。
- 前端 `npm --prefix frontend run build:h5``npm --prefix frontend run build:mp-weixin` 均通过。
- 公开报告页 token 匿名可打开,且不返回 top-level `userId/storeId/reportToken`
- boss/staff 登录后可生成报告、发送报告、查看回访池。
- customer 登录态打开报告仍显示留资和预约 CTA。
- 同一 `appointmentId` 第二次提交报告返回 `REPORT_ALREADY_EXISTS`
- 报告前后照片缺失返回对应业务码。
- A 店 boss/staff 不能查 B 店 leads/list/reportcustomer 不能用任意 `userId` 创建他人宠物/预约。
- 生产配置扫描不含真实 DB/微信密钥,无 `ddl-auto:update`,无宽 CORS。
- 文档口径扫描:`rg "到店不排队|会员储值 \| 路线图 P0|宠主通过微信查看服务报告v2|无限制,随便选" docs` 无命中。
---
## 不在 P0勿与本清单混排
- 会员卡 / 储值 / 次卡 / 套餐P1/P2
- 宠主账号内历史报告汇总P2
- 报告 token 作废重发(中期,见 D3 决策)
- 多技师分成、排班深度联动
- 复杂数据看板、漏斗大屏
- 分包优化(可 P1
---
*评审后可将本页 ID 勾进看板;与专文冲突以迭代评审为准。*