19 KiB
19 KiB
架构与产品评估报告
本体对齐:本报告的 P0 必补项与
ontology/的规则条目对齐(如 P0-1→rule:BR-AUTH-001、P0-2→rule:BR-RPT-006/rule:BR-LEAD-002、P0-3→rule:BR-RPT-002、P0-4→rule:BR-RPT-003)。冲突以本体为准。
日期:2026-07-05
评估范围:
- 文档:
docs/产品设计文档.md、docs/P0-研发落地清单.md、docs/本期主线-下一步产品优化点.md、报告成片、宠主预约、公众号协同、品牌与 UI 规范等。 - 后端:
backend/src/main/java/com/petstore下的预约、报告、成片、留资、宠物、用户、文件上传、配置与启动逻辑。 - 前端:
frontend/src下的首页、预约创建、报告填写、公开报告页、报告分享弹层、留资卡片、线索页、我的页、API 与工具函数。
方法:
- 架构师 agent 从边界、状态机、API 契约、数据模型、隐私安全、发布运维、测试可观测性做只读评估。
- 产品 agent 从定位、角色、主链路、报告分享、宠主预约、留资转化、文案品牌、验收标准做只读评估。
- 主线程补充核对关键代码路径,并执行基础验证命令。
总结
当前系统已经有一条可运行的主线:门店预约、开始服务、报告填写、报告发送、公开报告页、成片生成、宠主留资、回访池这些关键环节都已出现实现。真正阻碍进入稳定验收的,不是主流程缺失,而是四类风险仍未收口:
- 身份与数据边界仍主要依赖前端传参,后端缺统一鉴权上下文。
- 产品文档与代码状态不同步,部分 P0 已实现但文档仍写待改,部分文档承诺代码还未闭环。
- 报告、线索、公开 token、上传与配置存在隐私和发布风险。
- 自动化测试、迁移脚本、发布门禁和埋点统计基线不足,导致回归和上线依赖人工经验。
建议先按 P0 修“边界、隐私、报告不变量、产品口径、验证基线”,再做 P1 的增长与可观测性增强。
健康度评估
| 维度 | 结论 | 主要依据 |
|---|---|---|
| 产品定位 | 基本健康但文档滞后 | B 端门店 SaaS + C 端报告/预约/留资闭环已形成;但 产品设计文档.md 仍把宠主查看报告写作 v2,与 P0 清单和现有代码冲突。 |
| 主流程 | 中等偏好 | 预约、状态 Tab、开始服务、报告提交、发送弹层、报告页、短片三态都有实现。 |
| 状态机 | 较好但缺测试 | AppointmentService 已集中处理 new -> doing -> done、取消规则和非法迁移,但文档还保留旧口径,自动化测试缺失。 |
| API 边界 | 中等偏弱 | 前端 API 已集中,但后端多处仍从请求参数读取 userId/storeId/role 控制范围。 |
| 数据模型 | 中等偏弱 | Report、ReportLead 字段逐步补齐,但“一约一报告”、报告 token 生命周期、成片任务队列和迁移脚本仍不完整。 |
| 隐私安全 | 弱 | 公开报告回包和线索接口暴露面偏大;登录、CORS、配置密钥、上传路径需要生产化。 |
| 发布运维 | 弱 | FFmpeg、上传大小、H5 public origin、微信合法域名、生产 profile、迁移步骤缺一份 RC 门禁清单。 |
| 测试与可观测 | 弱 | 后端 mvn test 可执行但无测试用例;前端缺依赖和可执行测试;报告打开埋点仍偏日志化。 |
当前可以保留的基础
- 前端角色分流和主流程页面已经成型,
Home.vue、Report.vue、ReportShareModal.vue、reportView.vue能串起核心体验。 - 预约状态机已经从“直接赋值”收口到服务层校验,文档应更新为“待补测试和验收证据”,不是“待重写”。
- 报告成片字段契约和前后端字段名基本一致,
highlightStatus、highlightVideoUrl、highlightFailReason等字段具备继续扩展的基础。 - 留资链路已有 token、手机号、同报告同手机号去重、同意状态等基础,不需要推倒重做。
- P0 清单本身结构可用,适合继续作为验收总入口;问题是状态需要重新冻结。
P0 必补项
| 编号 | 问题 | Owner | 涉及路径 | 建议 | 验收口径 |
|---|---|---|---|---|---|
| P0-1 | 后端身份与店铺边界未收口 | System Architect、Backend Core、Report Media Backend | AppointmentController、ReportController、ReportLeadController、PetController、StoreController、UserController |
建立统一登录态和角色上下文;所有 boss/staff/customer 接口从上下文派生 userId/storeId/role,不再信任请求参数;公开报告 token 接口单独白名单。 |
A 店用户访问 B 店预约、报告列表、线索接口返回 403;宠主不能用任意 userId 创建/查询他人宠物和预约。 |
| P0-2 | 公开报告与线索隐私暴露面偏大 | System Architect、Product Design、Report Media Backend、Customer Experience FE | ReportController.get、ReportLeadController.leads、Leads.vue、reportView.vue |
公开报告回包只返回页面必要字段;线索列表默认不返回完整 openid/unionid,手机号按角色决定展示/脱敏;日志只记录不可逆 token hash。 | GET /api/report/get?token= 不含内部 userId/storeId/reportToken;员工态不显示完整 openid/unionid;日志不可反推出 token。 |
| P0-3 | 报告“一约一份”和提交不变量缺数据库与服务层兜底 | System Architect、Report Media Backend、Data Model | ReportService.create、Report.java、ReportController.create、Report.vue |
增加 appointment_id 唯一约束;服务层拒绝同预约重复提交;明确是否允许无预约报告,若不允许则前后端同时拦截。 |
同一 appointmentId 第二次提交返回 409 或业务码;非 doing 预约不能创建报告;无预约提交符合产品确认后的唯一规则。 |
| P0-4 | 报告前后照片必填口径未落实 | Product Design、Store Miniapp FE、Report Media Backend | 产品设计文档.md、Report.vue、报告创建接口 |
文档、前端、后端统一:服务前、服务后至少各 1 张,过程图可选。 | 0 张 before 或 0 张 after 时提交失败,提示“请至少上传 1 张服务前/服务后照片”。 |
| P0-5 | 产品文档与代码状态冲突 | Product Design、PM Assistant、Docs | 产品设计文档.md、P0-研发落地清单.md、宠主端预约体验优化-产品说明.md、产品全方位优化说明-v1.md |
冻结本期范围:宠主预约/公开报告/留资/基础埋点属于本期;历史报告汇总、复杂会员储值、完整 CRM 放到 P1/P2;删除“到店不排队”等无容量模型承诺。 | `rg "到店不排队 |
| P0-6 | 宠主预约登录与草稿策略未闭环 | Product Design、Customer Experience FE、Backend Core | P0-研发落地清单.md、CustAppointmentCreate.vue、frontend/README.md |
二选一冻结策略:进入预约先登录,或提交时登录并恢复 guest 草稿。若选择提交时登录,草稿 key 不能依赖 userInfo.id。 |
未登录填写后提交不会产生 userId: undefined;登录返回后门店、宠物、服务、时段、备注恢复。 |
| P0-7 | 报告页角色判断会把已登录 customer 当员工态 | Product Design、Customer Experience FE | reportView.vue、auth/session 工具 |
把 isStaff 从“是否登录”改为“角色是 boss/staff”;customer 登录态仍看到留资/预约 CTA。 |
customer 登录态打开报告页显示 ReminderCard 和“我也要预约”;boss/staff 才显示内部操作。 |
| P0-8 | 配置、密钥与生产 profile 风险 | System Architect、Backend Ops、Frontend Release Ops | backend/src/main/resources/application.yml、application-example.yml、.env.* |
移除真实环境配置和明文敏感项,改为环境变量;已暴露凭据按安全流程轮换;生产 profile 禁用 ddl-auto:update、show-sql、万能验证码和宽 CORS。 |
仓库不含真实 DB/微信密钥;生产启动只读环境变量;安全扫描不再命中敏感配置。 |
| P0-9 | 上传接口缺路径与类型保护 | System Architect、Backend Core | FileController、上传反代配置 |
对上传文件做扩展名、MIME、大小、路径归一化校验;下载/访问路径拒绝 ..、绝对路径和非媒体类型。 |
构造 /api/upload/image/../...、伪装扩展名、超大文件均被拒绝;正常图片/视频仍可上传访问。 |
| P0-10 | 验证基线不足 | Core Flow QA、Report Share QA、System Architect | backend/src/test、前端 smoke、CI |
补最小自动化:预约状态机、报告创建、留资去重、公开报告字段、跨店访问拒绝、前端报告打开/分享/预约深链 smoke。 | mvn test 至少跑上述服务/控制器测试;前端构建和 smoke 能在本地或 CI 复现。 |
P1 补强项
| 编号 | 问题 | Owner | 建议 | 验收口径 |
|---|---|---|---|---|
| P1-1 | storeId 全入口不完整 |
Customer Experience FE、Product Design | 支持普通 query、小程序码 scene、报告页“我也要预约”、公众号菜单、分享 path/query;写清参数协议。 |
三种入口均可预填门店,并允许用户更换门店。 |
| P1-2 | 留资主档规则待定 | Product Design、Report Media Backend | 明确手机号、openid、unionid 的主键、合并、冲突、解绑、展示和权限策略。 | 同手机号重复提交合并;不同微信同手机号有明确处理;Leads 页面展示符合权限。 |
| P1-3 | 成片任务缺成本与队列治理 | Report Media Backend、Backend Ops | 增加重试次数、频控、任务表或可观测队列、失败分类聚合、FFmpeg 健康检查。 | 同一报告短时间重复生成被限制;失败原因可统计;RC 可检测 FFmpeg/ffprobe。 |
| P1-4 | 埋点从日志升级为可统计事件 | Report Share QA、Progress Digest、Backend Ops | 定义 report_open、report_reopen、highlight_success、highlight_failed、video_play、video_save、lead_submit。 |
老板端或日报能看到打开率、成片成功率、留资转化。 |
| P1-5 | 启动期 DDL/修复逻辑不可审计 | System Architect、Data Model、Backend Ops | 把 PetstoreApplication 中的临时 DDL/历史 UPDATE 移入迁移脚本,建立版本化迁移。 |
新环境和老环境都通过迁移脚本升级;应用启动不再改表结构。 |
| P1-6 | 共享空态和品牌细节不统一 | Product Design、Customer Experience FE、Store Miniapp FE | AppPageState 默认改用 AppIcon 或显式 icon prop;清理主视觉 emoji;统一品牌词和按钮文案。 |
主流程空态不出现 emoji 主视觉;品牌名、Slogan、主色使用规范一致。 |
| P1-7 | 公众号配置不是代码能证明的 P0 | PM Assistant、Frontend Release Ops、Product Design | 将公众号菜单、欢迎语、自动回复列为运营配置验收项,和代码页面存在性分开。 | 公众号后台截图/配置单可证明菜单可跳小程序,自动回复路径有效。 |
P2 方向库
| 编号 | 方向 | 说明 |
|---|---|---|
| P2-1 | 报告 token 作废、重发、有效期 | 支持老板重新生成分享链接、旧链接失效、异常频次提醒。 |
| P2-2 | 宠主历史报告汇总 | 在本期公开报告页稳定后,再做宠主账号内历史记录。 |
| P2-3 | 会员、储值、套餐 | 不进入当前 P0;应等待预约/报告/留资闭环和数据口径稳定后再设计。 |
| P2-4 | 公众号模板消息和小程序订阅去重 | 避免报告通知、成片通知、小程序订阅消息重复触达。 |
| P2-5 | 经营分析看板 | 基于 P1 埋点和订单数据,做报告打开、预约转化、回访转化、服务复购。 |
文档修订清单
| 文档 | 当前问题 | 建议改法 |
|---|---|---|
产品设计文档.md |
写“宠主查看服务报告 v2”;预约时间写“无限制,随便选”;取消单展示和状态矩阵与代码/P0 不一致;数据模型缺新字段。 | 改为本期包含宠主预约、公开报告、留资;更新预约时间为可预约窗口和占用校验;状态矩阵对齐代码;补 ReportLead、成片字段、预约窗口等模型。 |
P0-研发落地清单.md |
部分“当前需改”已过时,如状态机、报告分享弹层、我的页分组;部分缺口还未标清 owner。 | 重新标记 已实现 / 部分实现 / 未实现 / 待测试,并把每项绑定 owner 和验收命令。 |
宠主端预约体验优化-产品说明.md |
仍有“到店不排队”示例;旧入口描述和当前主 CTA 不一致;登录策略未冻结。 | 删除容量承诺,统一为“在线选时段,到店更省心”;写清登录策略和深链协议。 |
产品全方位优化说明-v1.md |
会员储值被写进 P0 路线图,与 common context 和 P0 清单冲突。 | 降级到 P1/P2 方向库,当前只保留预约/报告/留资闭环。 |
本期主线-下一步产品优化点.md |
指标建议好,但缺事件 schema 和数据来源。 | 增加埋点事件、字段、统计窗口、owner、看板或日报落地方式。 |
洗美报告短视频成片方案.md |
成片方案大体吻合代码,但重试频控、队列状态、成本指标没有落到验收。 | 增加成片任务状态机、失败重试次数、频控和 RC 检查。 |
公众号协同与全链路触达-产品说明.md |
P0 中包含运营后台配置,代码无法自动证明。 | 拆成“代码可验收”和“运营配置可验收”两栏。 |
backend/README.md、frontend/README.md |
发布依赖、环境变量、微信合法域名、FFmpeg、上传大小、H5 origin 不完整。 | 增加本地开发、RC、生产上线三段式运行手册。 |
代码修订清单
后端
-
建立统一鉴权中间层或拦截器,生成
CurrentUserContext:userIdrolestoreIdisCustomerisStaffisBoss
-
控制器改造原则:
- 管理接口不接受客户端传入的身份字段作为权限依据。
- 查询列表时由上下文派生作用域。
- 公开报告接口只允许 token 和必要参数。
- 线索、宠物、报告、预约接口都做跨店/跨用户校验。
-
数据约束:
report.appointment_id加唯一约束。report_lead(report_id, phone)已有方向,但需迁移脚本确认。- 报告 token 增加状态、作废时间或过期策略的预留字段。
- 成片任务若继续异步化,建议从 report 字段扩展到任务表或任务日志。
-
配置与发布:
- 移除仓库内真实环境敏感配置,使用环境变量和 profile。
- 关闭生产
ddl-auto:update和 SQL 明文输出。 - 收敛 CORS 白名单。
- 上传路径做归一化和类型校验。
前端
-
reportView.vue:isStaff使用角色判断,不使用isLoggedIn()。- customer 登录态仍显示留资/预约入口。
- 公开报告页不要依赖后端回包里的内部 token 字段。
-
CustAppointmentCreate.vue:- 支持
scene解码。 - 冻结登录策略并实现 guest 草稿或进入页登录。
- 提交前确保
userInfo.id一定存在或后端可识别匿名转登录上下文。
- 支持
-
Report.vue:- 前后照片必填。
- 与后端一致处理重复报告、非
doing预约和无预约报告。
-
Leads.vue:- 默认隐藏或脱敏 openid/unionid。
- 手机号展示按角色和操作场景收敛。
-
ReportShareModal.vue、reportPublicUrl.js:- 把
VITE_REPORT_PUBLIC_ORIGIN写入发布手册和 RC 检查。 - 链接、二维码、话术、封面规则做 smoke。
- 把
-
共享 UI:
AppPageState用品牌 icon 作为默认主视觉。- 清理主流程空态中的 emoji 主视觉。
建议实施顺序
- 第 1 批:修文档口径、报告页角色判断、照片必填、
storeId深链协议、公开报告字段裁剪。 - 第 2 批:统一鉴权上下文、跨店/跨用户校验、线索脱敏、报告唯一约束。
- 第 3 批:迁移脚本、生产配置、上传安全、FFmpeg/上传/微信域名 RC 门禁。
- 第 4 批:后端最小测试、前端构建与 smoke、埋点事件入库或可统计日志。
- 第 5 批:token 作废、历史报告、会员储值、经营看板等 P2 方向。
最小验收集
后端
| 场景 | 期望 |
|---|---|
new -> doing |
成功 |
doing -> done |
成功 |
done -> doing |
失败并返回明确业务码 |
done -> cancel |
失败并返回明确业务码 |
重复 startService |
第二次失败 |
| 非本店用户查预约/线索/报告列表 | 403 |
| 公开 token 查报告 | 只返回公开页必要字段 |
| 同一预约重复创建报告 | 第二次失败 |
| 报告前图或后图为空 | 创建失败 |
| 同报告同手机号重复留资 | 幂等更新,不产生重复记录 |
上传路径带 .. |
拒绝 |
前端
| 场景 | 期望 |
|---|---|
| customer 首页 | 只有一个主预约入口,空态不出现第二个主按钮 |
预约页普通 storeId query |
预填门店 |
预约页小程序码 scene |
预填门店 |
| 未登录填写预约 | 按冻结策略登录并恢复草稿,或进入前即登录 |
| customer 登录态打开报告页 | 仍显示留资/预约 CTA |
| boss/staff 打开报告页 | 显示内部分享/保存操作 |
| 报告提交无前图或后图 | 阻止提交并提示 |
| 报告提交成功 | 链接、二维码、两条话术同屏 |
| 成片处理中/失败/完成 | 三态文案和按钮正确 |
| 线索页 | openid/unionid 不默认明文展示 |
发布 RC
| 检查 | 期望 |
|---|---|
APP_BASE_URL |
后端可生成可访问媒体 URL |
VITE_REPORT_PUBLIC_ORIGIN |
报告链接和二维码非空且可访问 |
ffmpeg -version、ffprobe -version |
服务端可执行 |
| 上传 50MB 视频 | 不被 Nginx 或后端误拦截 |
| 微信 request/download 合法域名 | 小程序可请求 API 并下载短片 |
| 生产配置扫描 | 无真实 DB/微信密钥、无 ddl-auto:update、无宽 CORS |
本次验证结果
| 命令 | 结果 | 说明 |
|---|---|---|
mvn test(backend) |
成功 | Maven 构建通过,但输出 No tests to run,不能证明业务逻辑有自动化覆盖。 |
npm --prefix frontend run build:h5 |
失败 | frontend/node_modules 不存在,uni: command not found;这是依赖/工具链缺失,不是源码编译通过或失败的业务结论。 |
git -C docs diff --check |
成功 | 文档变更无空白检查错误。 |
结论
这套文档和代码的方向是对的:先做门店服务闭环,再把报告页作为宠主触达与复购入口。但现在不适合继续叠会员、储值或更复杂增长功能。下一轮应把 P0 的身份边界、报告不变量、隐私脱敏、文档口径和测试基线补齐;补齐后再推进埋点、公众号、经营看板和会员能力,风险会低很多。