Quellcode durchsuchen

docs(cfclub): 小程序改版设计+分阶段实施计划(需求驱动·逐步解锁,C类问题域闭环优先)

E2E Test Bot vor 1 Monat
Ursprung
Commit
b05b420adf
1 geänderte Dateien mit 252 neuen und 0 gelöschten Zeilen
  1. 252 0
      docs/cfc-redesign-progressive-unlock.md

+ 252 - 0
docs/cfc-redesign-progressive-unlock.md

@@ -0,0 +1,252 @@
+# 浠艾福小程序改版:需求驱动 · 逐步解锁
+
+> 阶段:实施计划 v1.0 | 分支:cfclub | 产品决策已确认(2026-08-13)
+
+## 一、背景与目标
+
+现状:小程序首页对所有用户一视同仁地堆内容(商品/活动/文章/任务),未区分用户需求深度,转化链路不清晰。
+
+改版核心:**从用户需求出发,先识别用户类型,按需求深度逐步解锁内容与功能,无关内容不展示。**
+
+三类用户:
+- **A类 目标明确型**:已接受平台理念,直接买 DAN测评 / 菌群检测 → 上传报告 → 出方案 → 生成任务 → 执行(方案任务需会员)
+- **B类 观望型**:登录看看 → 轻问卷 → 按答案开放相关科普内容
+- **C类 问题导向型**:带具体问题来(减肥/睡眠/便秘)→ 服务流程介绍 → 专项调研 → 匹配推荐套餐 → 购买 → 试剂盒寄送/样本寄回 → 报告完成系统通知 → 方案确认 → 任务分解执行 → 全部完成奖励 CF 值
+
+已确认决策:
+1. 入口呈现:**首次登录强制选择**;已登录但从未选过的用户,下次进入也要弹出选择
+2. 问题域首版:**减肥 / 睡眠 / 便秘** 三个
+3. 会员任务边界:**仅"方案生成"的任务需会员**;未缴费用户可以自己创建任务自己完成(免费)
+4. 完成回馈奖励:**主要奖励 CF 值**(复用 PlatformPointsService)
+5. 实施优先级:**C类优先 → A类会员任务解锁 → B类问卷引流**
+
+## 二、现状摸底结论(已核实)
+
+| 模块 | 现状 | 结论 |
+|------|------|------|
+| 首页分流 | `pages/index-home/index.vue` 内嵌登录/游客两态,游客看商品+活动+文章,登录看沙盘+动态+会员入口+快捷功能+任务+挑战+推荐 | 需重构为"旅程状态驱动" |
+| 测评链路 | `DanAssessmentController`: order/create→pay→appointment→record→result→report 全链路已有 | ★★★ 直接复用 |
+| 报告解析 | `DanReportController`: upload→edit→confirm→complete-analysis | ★★★ 直接复用 |
+| 菌群检测 | `BeijingNutritionController`: bacteria/save + analysis + recommend;送会员走 `TrialMembership` | ★★★ 直接复用 |
+| 会员 | `FamilyMembership`(FREE/BASIC/PROFESSIONAL/ENTERPRISE) + `MembershipController`(upgrade/trial/my/can-use/benefits) | ★★★ 直接复用 |
+| 问卷 | `SurveyTemplate`(questionsJson 题目JSON) + `SurveyRecord`(answersJson) + `ReportSurveyController`(create/submit/status);前端 `pages/health/survey-questionnaire.vue` 通用渲染页已有 | ★★ 扩展(题目JSON 加 resultMapping) |
+| 套餐 | `GuidePackage`(price/validityDays) + `TaskTemplatePackage`(cycleDays/category/price) + `AssessmentProduct`(single/bundle) | ★★ 需补"套餐→检测→任务模板"关联 |
+| 任务 | `Task` 有 sourceType/sourceId/dimensionCode,**无会员字段** | ★ 需加 `member_only` |
+| CF值 | `PlatformPointsService.earn/spend/freeze/unfreeze` + 家庭池 `FamilyPlatformPointsService`;`UnlockGateService` 已实现关卡奖励发 CF 值(幂等) | ★★★ 复用 earn() 发奖励 |
+| 优惠券 | `Coupon`/`UserCoupon`/`CouponController`(exchange/claim) | ★★★ 备用 |
+| 通知 | `NoticeController` 仅 `/list`(GET,且不合规),无主动通知 | ★ 需新建通知表+写入+列表接口 |
+
+## 三、数据模型设计
+
+### 3.1 新增 `problem_domains`(问题域表)
+
+```sql
+CREATE TABLE IF NOT EXISTS problem_domains (
+  id BIGINT AUTO_INCREMENT PRIMARY KEY,
+  code VARCHAR(50) NOT NULL COMMENT '唯一编码: weight_loss/sleep/constipation',
+  name VARCHAR(50) NOT NULL COMMENT '名称: 减肥/睡眠/便秘',
+  icon VARCHAR(255) DEFAULT '' COMMENT '图标',
+  description VARCHAR(500) DEFAULT '' COMMENT '一句话描述',
+  flow_intro_json TEXT COMMENT '服务流程介绍(7步) JSON',
+  survey_template_id BIGINT DEFAULT NULL COMMENT '专项调研问卷模板ID(SurveyTemplate.id)',
+  content_tags VARCHAR(500) DEFAULT '' COMMENT '内容标签,逗号分隔(过滤文章/知识库)',
+  recommended_product_ids VARCHAR(500) DEFAULT '' COMMENT '推荐产品ID,逗号分隔(Product.id)',
+  task_template_package_ids VARCHAR(500) DEFAULT '' COMMENT '套餐绑定的任务模板包ID(TaskTemplatePackage.id)',
+  reward_cf_value INT DEFAULT 0 COMMENT '全部完成奖励CF值',
+  status TINYINT DEFAULT 1 COMMENT '1启用 0停用',
+  sort_order INT DEFAULT 0,
+  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  UNIQUE KEY uk_code (code)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='问题域定义(改版v1)';
+```
+
+### 3.2 新增 `user_intents`(用户意图/旅程表)
+
+```sql
+CREATE TABLE IF NOT EXISTS user_intents (
+  id BIGINT AUTO_INCREMENT PRIMARY KEY,
+  user_id BIGINT NOT NULL COMMENT '用户ID',
+  intent_type VARCHAR(20) DEFAULT '' COMMENT 'A/B/C 用户类型',
+  problem_domain_code VARCHAR(50) DEFAULT '' COMMENT '问题域编码(仅C类)',
+  journey_stage INT DEFAULT 0 COMMENT '旅程阶段 0-7,语义见下方状态机',
+  stage_updated_at DATETIME DEFAULT NULL COMMENT '最近阶段变化时间',
+  survey_template_id BIGINT DEFAULT NULL COMMENT '最近作答问卷模板ID',
+  survey_submitted_at DATETIME DEFAULT NULL COMMENT '最近问卷提交时间',
+  survey_result_json TEXT COMMENT '问卷答案→推荐结果快照',
+  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  UNIQUE KEY uk_user (user_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户意图与服务旅程(改版v1)';
+```
+
+**journey_stage 状态机(C类,0-7)**:
+| stage | 语义 | 进入条件 | 推进动作 |
+|-------|------|----------|----------|
+| 0 | 已选择问题域,未看流程 | 用户选择 C 类+问题域 | 打开流程介绍页 |
+| 1 | 已看流程介绍 | 流程介绍页曝光完成 | 提交调研 |
+| 2 | 调研已提交 | 调研提交成功 | 购买套餐 |
+| 3 | 已购买 | 支付回调成功 | 管理员发货 |
+| 4 | 试剂盒已发/样本已收 | 物流状态更新 | 报告生成 |
+| 5 | 报告已出 | completeAnalysis 完成 | 用户确认方案 |
+| 6 | 方案已确认,任务已生成 | 方案确认接口 | 任务全部完成 |
+| 7 | 任务完成,CF奖励已发 | 奖励发放成功 | —(终态,展示回馈) |
+
+A类简化:0=已选A类,1=已购测评/检测,2=报告已出,3=方案确认,4=任务完成。B类简化:0=已选B类,1=问卷已答(此后首页按结果定向展示内容)。
+
+### 3.2b 通知表与既有 `notices` 的边界
+
+- `notices`(`Notice.java`, @TableName("notices")):**平台级公告**,管理员发布(platform/activity/promotion),全员可见,`NoticeController` 仅 GET /list(遗留不合规,不动)。
+- `user_notifications`(新增):**用户级主动通知**,按 user_id 定向(报告完成/奖励到账/物流变化),带 ref_type/ref_id 可跳转。二者并存不冲突。
+
+### 3.3 Task 表加会员字段
+
+```sql
+ALTER TABLE task ADD COLUMN member_only TINYINT DEFAULT 0 COMMENT '1=会员任务(方案生成),执行需会员';
+```
+
+### 3.4 新增 `user_notifications`(站内通知表)
+
+```sql
+CREATE TABLE IF NOT EXISTS user_notifications (
+  id BIGINT AUTO_INCREMENT PRIMARY KEY,
+  user_id BIGINT NOT NULL COMMENT '接收用户ID',
+  type VARCHAR(30) DEFAULT 'report_ready' COMMENT 'report_ready/reward_granted/system',
+  title VARCHAR(200) NOT NULL,
+  content VARCHAR(1000) DEFAULT '',
+  ref_type VARCHAR(30) DEFAULT '' COMMENT '关联对象类型: report/package/task',
+  ref_id BIGINT DEFAULT NULL COMMENT '关联对象ID',
+  is_read TINYINT DEFAULT 0,
+  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+  INDEX idx_user_read (user_id, is_read)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='站内通知(改版v1)';
+```
+
+### 3.5 套餐/物流状态扩展(复用 PackageOrder / ProductOrder)
+
+- `package_orders` 表(`entity/PackageOrder.java` 已存在,含 userId/familyId/packageId/contactName/contactPhone/contactAddress)加:
+  - `logistics_status VARCHAR(20) DEFAULT 'none'`(none/kit_shipped/kit_received/sample_shipped/sample_received)
+  - `tracking_no VARCHAR(100) DEFAULT ''`
+
+### 3.6 调研问卷 → 推荐结果映射
+
+`SurveyTemplate.questionsJson` 题目结构扩展:每题的 option 支持 `resultTags`:
+
+```json
+[
+  {"text": "您的睡眠问题持续多久了?", "options": [
+    {"text": "1-3个月", "resultTags": "短期,轻中度"},
+    {"text": "半年以上", "resultTags": "长期,重度"}
+  ]}
+]
+```
+
+后端提交问卷时汇总所有选中 option 的 resultTags + 问题域 code,返回推荐产品列表快照,存入 `user_intents.survey_result_json`。
+
+## 四、后端改动清单(cfc-backend)
+
+### 阶段1:C类问题导向型闭环(优先交付)
+
+| # | 文件 | 改动 | 验证 |
+|---|------|------|------|
+| B1 | `entity/ProblemDomain.java` | 新实体(§3.1) | compile |
+| B2 | `mapper/ProblemDomainMapper.java` | 新 Mapper | compile |
+| B3 | `entity/UserIntent.java` | 新实体(§3.2) | compile |
+| B4 | `mapper/UserIntentMapper.java` | 新 Mapper | compile |
+| B5 | `entity/UserNotification.java` | 新实体(§3.4) | compile |
+| B6 | `mapper/UserNotificationMapper.java` | 新 Mapper | compile |
+| B7 | `entity/Task.java` | 加 `memberOnly` 字段 | compile |
+| B8 | `config/DatabaseInitializer.java` | 迁移:3 张新表 + task.member_only + package_order 物流字段 | compile |
+| B9 | `resources/schema.sql` | 同步建表语句 | — |
+| B10 | `controller/ProblemDomainController.java` | 接口:`POST /api/problem-domain/list`(启用中,含问卷模板+推荐产品+任务模板) | compile |
+| B11 | `controller/UserIntentController.java` | 接口:`POST /api/user-intent/get`(当前意图) / `POST /api/user-intent/choose`(首次选择A/B/C) / `POST /api/user-intent/update-stage`(旅程推进) | compile |
+| B12 | `controller/UserNotificationController.java` | 接口:`POST /api/notification/list` / `POST /api/notification/read` | compile |
+| B13 | `controller/ProblemSurveyController.java` | 接口:`POST /api/problem-survey/submit`(提交调研→汇总resultTags→查推荐产品→存快照→返回推荐列表) | compile |
+| B14 | `controller/ProblemPackageController.java` | 接口:`POST /api/problem-package/detail`(套餐详情:介绍/使用方式/包含检测/任务模板/奖励说明) | compile |
+| B15 | `controller/TaskController.java` | 补会员校验:`/{id}/complete`、`/accept` 时若 `task.memberOnly==1` 且非会员 → 拒绝(提示开通会员) | compile |
+| B16 | `service/DanReportService.completeAnalysis`(报告确认处) | 报告完成解析后:写 `user_notifications`(report_ready) + 更新 `user_intents.journey_stage`=5 | compile |
+| B17 | `service/ProblemCompletionService.java` | 新 Service:任务全部完成后发放 CF 值。**奖励对象:家庭池(FamilyPlatformPointsService.earn,familyId 维度)**,金额=问题域配置 reward_cf_value;幂等:按 (familyId, problemDomainCode, 'completion') 查唯一发放记录;写通知(reward_granted) + 更新旅程 stage=7 | compile |
+| B18 | `entity/PackageOrder.java` | 加 `logisticsStatus` / `trackingNo`(表 package_orders) | compile |
+| B19 | `controller/LogisticsController.java` | 接口:`POST /api/logistics/update`(管理端发货/收样) / `POST /api/logistics/my`(用户查状态) | compile |
+
+### 阶段2:A类会员任务解锁
+
+| # | 文件 | 改动 |
+|---|------|------|
+| B20 | `service/TaskPlanService`(任务实例生成处)+ `TaskService.createSingleTask` | 方案/套餐确认生成任务实例时标记 `memberOnly=1`;`createSingleTask` 从 DTO 透传 memberOnly |
+| B21 | `service/RepeatTaskGenerator` | 重复任务复制模板时**透传 memberOnly 字段**(否则方案任务实例的会员标记丢失) |
+| B22 | `TaskController.create` | 未缴费用户自建任务:`memberOnly=0`,不校验会员(确认现有 create 已放行) |
+
+### 阶段3:B类问卷引流
+
+| # | 文件 | 改动 |
+|---|------|------|
+| B23 | `SurveyTemplate` 扩展 | questionsJson 支持 resultTags;`getActiveTemplates` 支持按问题域过滤 |
+| B24 | `controller/ContentFilterController.java` | 接口:`POST /api/content/by-tags`(按 resultTags + 问题域 code 过滤文章/知识库/饮食推荐) |
+
+## 五、前端改动清单(cfc-frontend)
+
+### 阶段1:C类闭环
+
+| # | 文件 | 改动 |
+|---|------|------|
+| F1 | `pages/index-home/index.vue` | **首页重构**:登录后顶部"旅程状态卡"(进度+下一步);未选择过意图的用户弹"首次选择"层(A直达/B问卷/C问题域) |
+| F2 | `components/intent-picker.vue`(新) | 首次选择弹层:三个入口卡片 |
+| F3 | `components/journey-card.vue`(新) | 旅程进度条 + 下一步动作按钮(按 user_intents 渲染) |
+| F4 | `pages/problem/domain-list.vue`(新) | 问题域列表页(3个卡片) |
+| F5 | `pages/problem/flow-intro.vue`(新) | 服务流程介绍页(7步,来自 flow_intro_json) |
+| F6 | `pages/problem/survey.vue`(新) | 专项调研页(复用 survey-questionnaire 模式,提交走 problem-survey/submit) |
+| F7 | `pages/problem/package-match.vue`(新) | 调研结果→推荐套餐列表(只显示相关) |
+| F8 | `pages/problem/package-detail.vue`(新) | 套餐详情(介绍/使用方式/包含检测/任务模板/奖励)→ 购买按钮 |
+| F9 | `pages/problem/logistics.vue`(新) | 试剂盒寄送/样本寄回状态 |
+| F10 | `pages/problem/plan-confirm.vue`(新) | 报告出来后查看方案 → 确认 → 生成任务 |
+| F11 | `pages/notification/index.vue`(新) | 站内通知列表(报告完成/奖励到账) |
+| F12 | `pages/tasks/tasks.vue` | 会员任务角标(memberOnly 显示🔒,点击提示开通会员) |
+| F13 | `utils/api.js` | 新接口封装(problem-domain/user-intent/notification/problem-survey/problem-package/logistics) |
+
+### 阶段2:A类
+
+| # | 文件 | 改动 |
+|---|------|------|
+| F14 | `pages/index-home/index.vue` | 入口A直达"测评/检测选购页" |
+| F15 | 方案确认页复用 F10 | A类报告出方案→确认→生成任务(带 memberOnly) |
+
+### 阶段3:B类
+
+| # | 文件 | 改动 |
+|---|------|------|
+| F16 | `pages/problem/quick-survey.vue`(新) | 5-8题轻问卷 |
+| F17 | `pages/index-home/index.vue` | 按调研结果定向展示科普内容模块 |
+
+## 六、管理端改动清单(cfc-web)
+
+| # | 文件 | 改动 |
+|---|------|------|
+| W1 | `views/admin/ProblemDomainManage.vue`(新) | 问题域 CRUD:编码/名称/图标/描述/流程介绍(7步编辑)/绑定问卷模板/内容标签/推荐产品/任务模板包/奖励CF值 |
+| W2 | 套餐管理增强 | 绑定检测项目、任务模板包、完成奖励CF值 |
+| W3 | 通知模板管理 | report_ready / reward_granted 文案配置(可选) |
+| W4 | 物流管理 | 试剂盒发货/样本签收状态更新(可选,后端接口已备) |
+
+## 七、实施顺序(里程碑)
+
+| 里程碑 | 内容 | 验收标准 |
+|--------|------|----------|
+| M1 数据层 | B1-B9 | mvn clean compile 通过;3 张新表 + task.member_only 迁移幂等 |
+| M2 C类后端接口 | B10-B19 | compile 通过;关键接口(survey submit→推荐、报告完成→通知+旅程推进、任务完成→CF奖励)逻辑可测 |
+| M3 C类前端闭环 | F1-F13 + W1 | 用户在开发者工具可走通:选减肥→流程介绍→调研→套餐→购买→物流→通知→方案确认→任务→完成得CF值 |
+| M4 A类会员任务 | B20-B21 + F14-F15 | 方案任务带锁,非会员执行被拦截;自建任务免费可用 |
+| M5 B类问卷引流 | B22-B23 + F16-F17 | 观望用户填问卷后首页只显示相关内容 |
+
+## 八、风险与注意事项
+
+1. **首次选择弹层**:必须在登录后数据加载前弹出一次,且"跳过"不得导致下次不再弹出(storage 标记 `intent_skipped`,弹层关闭时写标记但 user_intents 未创建 → 下次仍弹)。决策1要求"未选过就要弹"。**teacher(规划师)角色不弹**(服务商不是 C 类客户,仅 parent/child 视角弹)。
+2. **memberOnly 校验**:校验点在 TaskController complete/accept,需同时覆盖规划师批量审核路径(GuideFamilyTaskController)与家长代完成路径(complete-parent)。
+3. **CF 奖励幂等 + 归属**:按 (familyId, problemDomainCode, 'completion') 唯一记录防重复发放(参照 UnlockGateService 已实现模式);**奖励进家庭池**(FamilyPlatformPointsService),不落个人池,避免"执行者是孩子、购买者是家长"的归属争议。
+4. **问卷 resultTags**:老模板无 resultTags 时兼容(option 是纯字符串),解析器需双态处理。
+5. **小程序规范**:新页面全部 Options API、禁止可选链、禁止 :key 表达式、日期用 parseDate、路由用 POST。
+6. **通知合规**:`NoticeController` 现有 `/list` 是 GET(不合规遗留),新建的 `UserNotificationController` 一律 POST;不动旧接口。
+7. **问卷模板 JSON 迁移**:现有调研模板数据结构不含 resultTags,提交接口需对"无 resultTags"模板返回空推荐(不报错)。
+8. **物流状态**:已确认 `package_orders` 表存在(`PackageOrder.java`),物流字段加其上;kit_shipped 即"试剂盒已寄出"。
+9. **会员判断复用**:调 `MembershipController.can-use` 或直接查 `FamilyMembership` levelCode != FREE 且未过期。
+10. **C类流程承载物**:流程描述页/套餐详情页写死"菌群检测试剂盒"是错误的——**套餐(TaskTemplatePackage/GuidePackage)是承载物**,flow_intro_json 每步文案可配置,检测项目通过套餐绑定的 assessmentProduct 决定。减肥/睡眠/便秘各自的套餐与检测项在管理端配置,代码不写死。
+11. **新增 Controller 前置检查**:新增 ProblemDomainController/UserIntentController 等前,先跑路由重复检查(AGENTS.md 工作流)与 Bean 名冲突检查。