Browse Source

Merge branch 'cfclub' of http://git.iwintrue.com/liaoxg/cfc into cfclub

asus 1 month ago
parent
commit
f49bcdded6

+ 16 - 2
cfc-backend/src/main/java/com/etotem/cfc/config/JwtInterceptor.java

@@ -25,8 +25,17 @@ public class JwtInterceptor implements HandlerInterceptor {
     private UserMapper userMapper;
 
     private static final String[] PUBLIC_PATHS = {
-        "/api/auth/",
+        "/api/auth/send-code",
+        "/api/auth/phone-login",
+        "/api/auth/wechat-phone-login",
+        "/api/auth/silent-login",
+        "/api/auth/auto-login",
+        "/api/auth/register-with-idcard",
+        "/api/auth/wechat-login",
         "/api/auth/verify",
+        "/api/auth/check-phone",
+        "/api/auth/direct-register",
+        "/api/auth/register-with-invite",
         "/api/internal/",
         "/api/product/list",
         "/api/product/detail",
@@ -42,7 +51,12 @@ public class JwtInterceptor implements HandlerInterceptor {
         "/api/articles/record-read",
         "/api/activity/list",
         "/api/activity/detail",
-        "/api/content-sections/visible"
+        "/api/content-sections/visible",
+        "/api/mind/alert/active",
+        "/api/mind/alert/checkin-alerts",
+        "/api/mind/traditional/mirror",
+        "/api/mind/traditional/family-dashboard",
+        "/api/mind/traditional/compatibility"
     };
 
     @Override

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-a34a2dc0dcc53ddd03637c89ed21905df82d7d24
+30df608f9861fbd1c60acb5df3f16308a0db62ab

+ 2 - 2
cfc-web/package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "cfc-web",
-  "version": "1.0.594",
+  "version": "1.0.602",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "cfc-web",
-      "version": "1.0.594",
+      "version": "1.0.602",
       "dependencies": {
         "@wangeditor/editor": "^5.1.23",
         "@wangeditor/editor-for-vue": "^1.0.2",

+ 1 - 1
cfc-web/package.json

@@ -1,6 +1,6 @@
 {
   "name": "cfc-web",
-  "version": "1.0.596",
+  "version": "1.0.603",
   "private": true,
   "scripts": {
     "dev": "vue-cli-service serve",

+ 57 - 0
cfc-web/public/CHANGELOG-v1.0.md

@@ -4,6 +4,63 @@
 
 ---
 
+## v1.0.603 (2026-07-28)
+
+### 文档
+- update PROJECT-OVERVIEW to v2.0 (2026-07-28)
+
+### 其他
+- 更新: LangGraph 前端集成/推广体系/富维度/辈分/文章系统/家庭会员/营养健康 状态
+- 
+
+
+## v1.0.602 (2026-07-28)
+
+### Bug 修复
+- add mind/alert/active and mind/traditional/mirror to public paths
+
+
+## v1.0.601 (2026-07-28)
+
+### Bug 修复
+- verify-password 400 error — replace broad /api/auth/ public path with explicit list
+
+
+## v1.0.600 (2026-07-28)
+
+### 文档
+- 数据移到连线标注 + 中文命名
+
+
+## v1.0.599 (2026-07-28)
+
+### 文档
+- 重构成长档案流程图 — 按阶段/分层/数据传递重绘
+
+
+## v1.0.598 (2026-07-28)
+
+### 重构
+- 按场景+角色重构测试用例,扩展至8角色27流程
+
+
+## v1.0.597 (2026-07-28)
+
+### 其他
+- Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
+- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
+- 
+- Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
+- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
+- 
+
+### 新功能
+- update stroke risk factors section and screenshot plan
+- remove read-complete button, add auto reading time tracking
+- add report-reading-time API for cumulative reading tracking
+- add article_id and updated_at to article_reading_records
+
+
 ## v1.0.596 (2026-07-28)
 
 ### Bug 修复

+ 58 - 1
cfc-web/public/CHANGELOG.md

@@ -1,6 +1,6 @@
 # 更新日志
 
-> 当前版本: v1.0.596
+> 当前版本: v1.0.603
 
 ## 历史版本
 
@@ -8,6 +8,63 @@
 
 ---
 
+## v1.0.603 (2026-07-28)
+
+### 文档
+- update PROJECT-OVERVIEW to v2.0 (2026-07-28)
+
+### 其他
+- 更新: LangGraph 前端集成/推广体系/富维度/辈分/文章系统/家庭会员/营养健康 状态
+- 
+
+
+## v1.0.602 (2026-07-28)
+
+### Bug 修复
+- add mind/alert/active and mind/traditional/mirror to public paths
+
+
+## v1.0.601 (2026-07-28)
+
+### Bug 修复
+- verify-password 400 error — replace broad /api/auth/ public path with explicit list
+
+
+## v1.0.600 (2026-07-28)
+
+### 文档
+- 数据移到连线标注 + 中文命名
+
+
+## v1.0.599 (2026-07-28)
+
+### 文档
+- 重构成长档案流程图 — 按阶段/分层/数据传递重绘
+
+
+## v1.0.598 (2026-07-28)
+
+### 重构
+- 按场景+角色重构测试用例,扩展至8角色27流程
+
+
+## v1.0.597 (2026-07-28)
+
+### 其他
+- Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
+- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
+- 
+- Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
+- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
+- 
+
+### 新功能
+- update stroke risk factors section and screenshot plan
+- remove read-complete button, add auto reading time tracking
+- add report-reading-time API for cumulative reading tracking
+- add article_id and updated_at to article_reading_records
+
+
 ## v1.0.596 (2026-07-28)
 
 ### Bug 修复

+ 233 - 80
docs/flows/growth-record-flow.md

@@ -1,103 +1,256 @@
 # 用户使用流程图 — 成长档案
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
+
+## 核心概念
+
+成长档案、成长计划、测评报告三者之间**不是一一对应关系**:
+
+- **成长档案** (GrowthRecord):孩子成长过程中的数据快照,可来自手动录入、PDF报告解析、外部系统同步
+- **成长计划** (GrowthPlan):由规划师基于测评分析制定的孩子成长方案,可引用某个测评报告的分析结果
+- **测评报告** (DanAssessmentResult):专业测评的结果数据,可被成长档案和成长计划引用
+
+> 一个孩子可以有多个成长档案、多个成长计划、多份测评报告。它们通过 `assessmentId` 相互引用,但不存在强制的一对一链式关系。
 
 ```mermaid
 flowchart TD
     %% ============ 颜色定义 ============
-    classDef actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px
-    classDef action fill:#fff3e0,stroke:#f57c00,stroke-width:1px
-    classDef system fill:#e8f5e9,stroke:#388e3c,stroke-width:1px
-    classDef decision fill:#fce4ec,stroke:#d32f2f,stroke-width:1px
-    classDef role fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1px
-    classDef endpoint fill:#f5f5f5,stroke:#616161,stroke-width:1px
-    classDef portMiniApp fill:#e3f2fd,stroke:#1565c0,stroke-width:1px,stroke-dasharray:3 2
-    classDef portAdmin fill:#fce4ec,stroke:#c62828,stroke-width:1px,stroke-dasharray:3 2
-    classDef portGuide fill:#fff8e1,stroke:#f57f17,stroke-width:1px,stroke-dasharray:3 2
-    classDef portSystem fill:#f3e5f5,stroke:#6a1b9a,stroke-width:1px,stroke-dasharray:3 2
-
-    subgraph 成长档案创建
-        A1(("👤 家长")):::portMiniApp --> A2{📱 创建方式}:::portMiniApp
-        A2 -->|手动创建| A3[📱 创建成长档案 /record/create]:::portMiniApp
-        A2 -->|上传PDF报告| A4[📱 上传测评报告PDF /upload-and-parse]:::portMiniApp
-        A2 -->|创建并购买测评| A5[📱 创建档案+购买 /create-with-order]:::portMiniApp
-        A4 --> A6["⚙️ PDF解析引擎 (Stage 1)"]:::portSystem
-        A6 --> A7{⚙️ 是否重复?}:::portSystem
-        A7 -->|重复| A8[⚙️ 检查哈希去重 /check-duplicate]:::portSystem
-        A7 -->|新记录| A9["📱 创建成长档案 (Stage 2) /create-from-upload"]:::portMiniApp
-        A3 --> A10[📱 录入基础信息]:::portMiniApp
-        A9 --> A10
-    end
+    classDef page fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
+    classDef api fill:#fff3e0,stroke:#f57c00,stroke-width:1px
+    classDef service fill:#e8f5e9,stroke:#388e3c,stroke-width:1px
+    classDef data fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1px
+    classDef external fill:#fce4ec,stroke:#d32f2f,stroke-width:1px,stroke-dasharray:3 2
+    classDef actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3
+
+    %% ============ 角色 ============
+    A0(("👤 家长")):::actor
+    B0(("📋 规划师")):::actor
+    C0(("👶 孩子")):::actor
+    D0(("⚙️ 系统/第三方")):::actor
+
+    %% ================================================================
+    %% 阶段一:数据采集 — 创建成长档案
+    %% ================================================================
+    subgraph 阶段一[阶段一:数据采集]
+        direction TB
+
+        P1["🏠 家长端:成长档案页"]:::page
+        P1 -->|"选择创建方式"| P1_choice{"手动录入 / 上传PDF / 购买测评"}:::page
 
-    subgraph 补充材料
-        A10 --> B1[📱 创建补充记录 /supplement]:::portMiniApp
-        B1 --> B2[📱 获取补充记录列表 /:id/supplements]:::portMiniApp
+        P1_choice -->|"手动录入"| P1a["🏠 家长端:录入表单"]:::page
+        P1a -->|"孩子ID, 身高, 体重, 学校, 年级, 照片"| A1["🔗 POST /api/growth/record/create"]:::api
+        A1 -->|"孩子ID, 身高, 体重, 学校, 年级"| S1["⚙️ GrowthRecordService.createRecord()"]:::service
+        S1 -->|"写入一条成长档案记录"| D1["📦 growth_records 表"]:::data
+
+        P1_choice -->|"上传PDF报告"| P1b["🏠 家长端:选择PDF文件"]:::page
+        P1b -->|"PDF文件(多部件表单)"| A1a["🔗 POST /api/growth/record/upload-and-parse"]:::api
+        A1a -->|"PDF文件"| S1a["⚙️ PDF解析引擎:OCR+结构化提取"]:::service
+        S1a -->|"解析结果: 指标数据, 得分, 报告日期"| D1a["📦 ParsedReport(内存中)"]:::data
+        D1a -->|"文件哈希值"| A1b["🔗 POST /api/growth/record/check-duplicate"]:::api
+        A1b -->|"文件哈希值"| S1b["⚙️ 哈希去重校验"]:::service
+        S1b -->|"重复"| D1b["📦 返回已有记录ID"]:::data
+        S1b -->|"新记录"| A1c["🔗 POST /api/growth/record/create-from-upload"]:::api
+        A1c -->|"解析后的报告数据"| S1c["⚙️ GrowthRecordService.createFromUpload()"]:::service
+        S1c -->|"写入一条成长档案记录"| D1
+
+        P1_choice -->|"创建档案+购买测评"| P1c["🏠 家长端:选择测评套餐"]:::page
+        P1c -->|"孩子ID, 规划师ID, 套餐ID"| A1d["🔗 POST /api/growth/record/create-with-order"]:::api
+        A1d -->|"孩子ID, 规划师ID, 套餐ID"| S1d["⚙️ GrowthRecordService + AssessmentOrderService"]:::service
+        S1d -->|"写入档案记录 + 测评订单"| D1c["📦 growth_records + assessment_orders"]:::data
     end
 
-    subgraph 外部数据同步
-        A10 --> C1[📱 外部系统测评同步 /external/sync]:::portMiniApp
-        C1 --> C2[⚙️ 数据融合]:::portSystem
+    %% ================================================================
+    %% 阶段二:补充材料与外部同步
+    %% ================================================================
+    subgraph 阶段二[阶段二:补充材料与外部同步]
+        D1 -->|"档案ID"| P2["🏠 家长端:档案详情页"]:::page
+        P2 -->|"补充材料"| P2a["🏠 家长端:补充记录表单"]:::page
+        P2a -->|"档案ID, 补充类型, 内容"| A2["🔗 POST /api/growth/record/supplement"]:::api
+        A2 -->|"档案ID, 补充类型, 内容"| S2["⚙️ GrowthRecordService.addSupplement()"]:::service
+        S2 -->|"写入补充记录"| D2["📦 growth_record_supplements 表"]:::data
+
+        P2 -->|"外部同步"| P2b["🏠 家长端:选择外部系统"]:::page
+        P2b -->|"孩子ID, 数据来源, 认证凭证"| A2a["🔗 POST /api/growth/external/sync"]:::api
+        A2a -->|"孩子ID, 数据来源, 凭证"| S2a["⚙️ 外部数据同步引擎"]:::service
+        S2a -->|"融合后的数据写入档案"| D1
     end
 
-    subgraph 查询与管理
-        C2 --> D1[📱 获取家长的成长档案列表 /list]:::portMiniApp
-        D1 --> D2[📱 获取指定孩子的档案 /child/:childId]:::portMiniApp
-        D2 --> D3[📱 获取孩子的档案 /child-records]:::portMiniApp
-        D3 --> D4[📱 获取档案详情 /:id]:::portMiniApp
-        D4 --> D5[📱 删除成长档案 /:id/delete]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:分析评估 — 查看测评结果
+    %% ================================================================
+    subgraph 阶段三[阶段三:分析评估]
+        D1 -->|"家长ID"| P3["🏠 家长端:档案列表页"]:::page
+        P3 -->|"选择档案"| P3a["🏠 家长端:档案详情页"]:::page
+        P3a -->|"档案ID"| A3["🔗 GET /api/growth/record/{id}"]:::api
+        A3 -->|"档案ID"| S3["⚙️ GrowthRecordService.getRecordDetail()"]:::service
+        S3 -->|"档案完整数据 + 关联测评摘要"| D3["📦 GrowthRecord + DanAssessmentResult"]:::data
+
+        D3 -->|"孩子ID, 分析结果"| P3b["📋 规划师端:测评分析页"]:::page
+        P3b -->|"查看孩子测评报告"| A3a["🔗 GET /api/guide/assessment/child/{id}"]:::api
+        A3a -->|"孩子ID"| S3a["⚙️ AssessmentService.getChildResults()"]:::service
+        S3a -->|"维度得分, 结构化分析"| D3a["📦 DanAssessmentResult"]:::data
     end
 
-    subgraph 生长记录
-        D1 --> E1[📱 获取生长记录列表 /list]:::portMiniApp
-        E1 --> E2[📱 获取生长记录详情 /detail]:::portMiniApp
-        E2 --> E3[📱 创建生长记录 /create]:::portMiniApp
-        E3 --> E4[📱 更新生长记录 /update]:::portMiniApp
-        E4 --> E5[📱 删除生长记录 /delete]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:制定成长计划
+    %% ================================================================
+    subgraph 阶段四[阶段四:制定成长计划]
+        D3a -->|"测评分析结果: 维度得分, 弱项"| P4["📋 规划师端:制定成长计划页"]:::page
+        P4 -->|"提交计划"| A4["🔗 POST /api/growth/plan/create"]:::api
+        A4 -->|"孩子ID, 关联测评ID, 计划标题, 计划内容, 持续月数, 开始日期"| S4["⚙️ GrowthPlanService.createPlan()"]:::service
+        S4 -->|"写入一条计划, 状态=活跃"| D4["📦 growth_plans 表"]:::data
+
+        D4 -->|"孩子ID"| P4a["📋 规划师端:查看孩子计划列表"]:::page
+        P4a -->|"查看列表"| A4a["🔗 GET /api/growth/plan/child/{childId}"]:::api
+        A4a -->|"孩子ID"| S4a["⚙️ GrowthPlanService.getByChildId()"]:::service
+        S4a -->|"该孩子的所有计划列表"| D4
+
+        P4 -->|"更新计划"| P4b["📋 规划师端:编辑计划"]:::page
+        P4b -->|"计划ID, 标题, 内容, 时长"| A4b["🔗 POST /api/growth/plan/update"]:::api
+        A4b -->|"计划ID, 更新字段"| S4b["⚙️ GrowthPlanService.updatePlan()"]:::service
+        S4b -->|"更新对应计划记录"| D4
+
+        D4 -->|"孩子ID"| P4c["📱 家长端:查看计划"]:::page
     end
 
-    subgraph 成长计划
-        E5 --> F1[📱 创建计划 /growth/plan/create]:::portMiniApp
-        F1 --> F2[📱 更新计划 /growth/plan/update]:::portMiniApp
-        F2 --> F3[📱 查看孩子计划 /growth/plan/child/:childId]:::portMiniApp
-        F3 --> F4[📱 激活计划 /growth/plan/child/:childId/active]:::portMiniApp
-        F4 --> F5[📱 计划详情 /growth/plan/:id]:::portMiniApp
-        F5 --> F6[📱 审核计划 /growth/plan/:id/review]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:执行计划 + 记录成长
+    %% ================================================================
+    subgraph 阶段五[阶段五:执行计划与记录成长]
+        D4 -->|"孩子ID, 活跃计划"| P5["📱 家长端:查看活跃计划"]:::page
+        P5 -->|"按计划内容执行日常活动"| P5a["🏠 家长端:执行计划任务"]:::page
+        P5a -->|"记录身高/体重/学业表现"| P5b["📱 家长/孩子端:创建生长记录"]:::page
+        P5b -->|"孩子ID, 记录标题, 身高, 体重, 照片"| A5["🔗 POST /api/health/growth/create"]:::api
+        A5 -->|"生长记录数据"| S5["⚙️ GrowthRecordService.createRecord()"]:::service
+        S5 -->|"写入日常生长记录"| D5["📦 health_growth_records 表"]:::data
+
+        P5a -->|"定期更新档案数据"| P5c["📱 家长端:更新成长档案"]:::page
+        P5c -->|"孩子ID, 测评摘要, 成长建议"| A5a["🔗 POST /api/growth/record/create"]:::api
+        A5a -->|"档案数据"| S5a["⚙️ GrowthRecordService.createRecord()"]:::service
+        S5a -->|"写入新档案记录"| D1
     end
 
-    R1(("👤 家长")):::actor
-    R2(("👶 孩子")):::role
-    R3(("📄 PDF解析引擎")):::system
+    %% ================================================================
+    %% 阶段六:复盘与评估
+    %% ================================================================
+    subgraph 阶段六[阶段六:复盘与评估]
+        D5 -->|"日常生长记录, 计划目标"| P6["📋 规划师端:查看执行记录"]:::page
+        P6 -->|"计划ID, 复盘备注"| A6["🔗 POST /api/growth/plan/{id}/review"]:::api
+        A6 -->|"计划ID, 复盘备注"| S6["⚙️ GrowthPlanService.reviewPlan()"]:::service
+        S6 -->|"复盘次数+1, 更新状态"| D6["📦 growth_plans 表(复盘计数更新)"]:::data
+
+        D6 -->|"复盘结论"| P6a["📋 规划师端:调整计划"]:::page
+        P6a -->|"计划ID, 调整后的标题/内容/时长"| A6a["🔗 POST /api/growth/plan/update"]:::api
+        A6a -->|"计划ID, 更新字段"| S6a["⚙️ GrowthPlanService.updatePlan()"]:::service
+        S6a -->|"更新计划记录"| D4
+
+        D6 -->|"复盘结果"| P6b["📱 家长端:查看复盘结果"]:::page
+    end
 
-    A1 -.- R1
-    D2 -.- R2
-    A6 -.- R3
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    A0 -.- P1
+    A0 -.- P2
+    A0 -.- P3
+    A0 -.- P4c
+    A0 -.- P5
+    A0 -.- P6b
+    B0 -.- P3b
+    B0 -.- P4
+    B0 -.- P6
+    C0 -.- P5a
+    D0 -.- S1a
+    D0 -.- S2a
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/growth/record/create` | 创建成长档案 | 📱小程序 |
-| `/api/growth/record/create-with-order` | 创建档案并购买测评 | 📱小程序 |
-| `/api/growth/record/list` | 获取家长的档案列表 | 📱小程序 |
-| `/api/growth/record/child/{childId}` | 获取指定孩子档案 | 📱小程序 |
-| `/api/growth/record/child-records` | 获取孩子的成长档案 | 📱小程序 |
-| `/api/growth/record/{id}` | 获取档案详情 | 📱小程序 |
-| `/api/growth/record/{id}/delete` | 删除成长档案 | 📱小程序 |
-| `/api/growth/external/sync` | 外部系统同步 | 📱小程序 |
-| `/api/growth/record/upload-and-parse` | 上传并解析PDF | 📱小程序 |
-| `/api/growth/record/create-from-upload` | 创建成长档案(从上传) | 📱小程序 |
-| `/api/growth/record/supplement` | 创建补充记录 | 📱小程序 |
-| `/api/growth/record/check-duplicate` | 检查重复记录 | ⚙️系统自动 |
-| `/api/growth/record/{id}/supplements` | 获取补充记录 | 📱小程序 |
-| `/api/health/growth/list` | 获取生长记录列表 | 📱小程序 |
-| `/api/health/growth/detail` | 获取生长记录详情 | 📱小程序 |
-| `/api/health/growth/create` | 创建生长记录 | 📱小程序 |
-| `/api/health/growth/update` | 更新生长记录 | 📱小程序 |
-| `/api/health/growth/delete` | 删除生长记录 | 📱小程序 |
-| `/api/growth/plan/create` | 创建成长计划 | 📱小程序 |
-| `/api/growth/plan/update` | 更新成长计划 | 📱小程序 |
-| `/api/growth/plan/child/{childId}` | 查看孩子成长计划 | 📱小程序 |
-| `/api/growth/plan/child/{childId}/active` | 激活孩子成长计划 | 📱小程序 |
-| `/api/growth/plan/{id}` | 查看计划详情 | 📱小程序 |
-| `/api/growth/plan/{id}/review` | 审核成长计划 | 📱小程序 |
+### 成长档案
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/growth/record/create` | 创建成长档案 | 📱小程序 | `{childId, height, weight, school, grade, assessmentSummary, ...}` | `GrowthRecord` |
+| `POST /api/growth/record/create-with-order` | 创建档案并购买测评 | 📱小程序 | `{childId, guideId, packageId, ...}` | `GrowthRecord + AssessmentOrder` |
+| `POST /api/growth/record/upload-and-parse` | 上传并解析PDF | 📱小程序 | `multipart file` | `ParsedReport` |
+| `POST /api/growth/record/create-from-upload` | 从解析结果创建档案 | 📱小程序 | `{parsedReport}` | `GrowthRecord` |
+| `POST /api/growth/record/check-duplicate` | 检查重复记录 | ⚙️系统 | `{fileHash}` | `{isDuplicate, existingId}` |
+| `GET /api/growth/record/list` | 获取家长档案列表 | 📱小程序 | `{page, size}` | `Page<GrowthRecord>` |
+| `GET /api/growth/record/child/{childId}` | 获取指定孩子档案 | 📱小程序 | path: `childId` | `List<GrowthRecord>` |
+| `GET /api/growth/record/child-records` | 获取孩子的成长档案 | 📱小程序 | `{childId}` | `List<GrowthRecord>` |
+| `GET /api/growth/record/{id}` | 获取档案详情 | 📱小程序 | path: `id` | `GrowthRecord + 关联数据` |
+| `DELETE /api/growth/record/{id}/delete` | 删除成长档案 | 📱小程序 | path: `id` | `boolean` |
+| `POST /api/growth/record/supplement` | 创建补充记录 | 📱小程序 | `{recordId, supplementType, content}` | `Supplement` |
+| `GET /api/growth/record/{id}/supplements` | 获取补充记录 | 📱小程序 | path: `id` | `List<Supplement>` |
+| `POST /api/growth/external/sync` | 外部系统同步 | 📱小程序 | `{childId, source, credentials}` | `GrowthRecord` |
+
+### 生长记录(日常追踪)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `GET /api/health/growth/list` | 获取生长记录列表 | 📱小程序 | `{childId, page, size}` | `Page<HealthGrowthRecord>` |
+| `GET /api/health/growth/detail` | 获取生长记录详情 | 📱小程序 | `{id}` | `HealthGrowthRecord` |
+| `POST /api/health/growth/create` | 创建生长记录 | 📱小程序 | `{childId, recordTitle, height, weight, ...}` | `HealthGrowthRecord` |
+| `POST /api/health/growth/update` | 更新生长记录 | 📱小程序 | `{id, ...}` | `boolean` |
+| `DELETE /api/health/growth/delete` | 删除生长记录 | 📱小程序 | `{id}` | `boolean` |
+
+### 成长计划
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/growth/plan/create` | 创建成长计划 | 📋规划师端 | `{childId, assessmentId, planTitle, planContent, durationMonths, startDate}` | `GrowthPlan` |
+| `POST /api/growth/plan/update` | 更新成长计划 | 📋规划师端 | `{id, planTitle, planContent, durationMonths, ...}` | `boolean` |
+| `GET /api/growth/plan/child/{childId}` | 查看孩子计划列表 | 📱📋 | path: `childId` | `List<GrowthPlan>` |
+| `GET /api/growth/plan/child/{childId}/active` | 获取当前活跃计划 | 📱📋 | path: `childId` | `GrowthPlan` |
+| `GET /api/growth/plan/{id}` | 查看计划详情 | 📱📋 | path: `id` | `GrowthPlan` |
+| `POST /api/growth/plan/{id}/review` | 复盘成长计划 | 📋规划师端 | path: `id`, body: `{reviewNotes}` | `boolean` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    GrowthRecord ||--o{ DanAssessmentResult : "assessmentId 引用"
+    GrowthPlan ||--o{ DanAssessmentResult : "assessmentId 引用"
+    GrowthRecord ||--o{ Supplement : "一条记录多个补充"
+    Child ||--o{ GrowthRecord : "一个孩子多个档案"
+    Child ||--o{ GrowthPlan : "一个孩子多个计划"
+    Child ||--o{ DanAssessmentResult : "一个孩子多份报告"
+
+    GrowthRecord {
+        Long id PK
+        Long childId FK
+        Long assessmentId FK "nullable"
+        string recordTitle
+        string height
+        string weight
+        string school
+        int grade
+        string assessmentSummary
+        int overallScore
+        string growthSuggestions
+    }
+
+    GrowthPlan {
+        Long id PK
+        Long childId FK
+        Long teacherId FK
+        Long assessmentId FK "nullable"
+        string planTitle
+        string planContent
+        int durationMonths
+        string status "active/inactive"
+        date startDate
+        date endDate
+        int reviewCount
+    }
+
+    DanAssessmentResult {
+        Long id PK
+        Long childId FK
+        string dimensionScores
+        string structuredAnalysis
+        string source
+    }
+```

+ 21 - 19
docs/superpowers/PROJECT-OVERVIEW.md

@@ -1,8 +1,8 @@
 # 浠艾福 项目全景 — 阶段性需求与设计汇总
 
-**文档版本:** v1.9
-**日期:** 2026-07-25
-**状态:** 已确认(v1.9 E2E 测试体系 Phase 1 重构完成
+**文档版本:** v2.0
+**日期:** 2026-07-28
+**状态:** 已确认(v2.0 Phase 2-3 全栈完成,Phase 4 计划级
 **维护:** 所有需求变更需更新本文档
 
 ---
@@ -12,10 +12,10 @@
 | 阶段 | 时间 | 主题 | 核心交付 | 状态 |
 |:----:|------|------|----------|:----:|
 | **Phase 0** | 2026-03~05 | 基础搭建 | 骨架、5 Tab页、能量系统萌芽 | ✅ 已上线 |
-| **Phase 1** | 2026-06~07 | 五维平台核心 | 五维重构、家庭成员体系、文章中心、推广体系 | 🚧 进行中 |
-| **Phase 2** | 2026-07~08 | 商业模式 & AI 落地 | LangGraph前端集成、家庭推广体系、AI健康管家 | 🚧 进行中 |
-| **Phase 3** | 2026-Q3 | 五维增强 | 富维度子维度拆分、文章发布系统 | 🚧 进行中(文章系统已完成,富维度部分实施) |
-| **Phase 4** | 2026-Q4 | 平台扩展 | 供应商体系、健康7维模型、成长档案 | 🚧 进行中(成长档案已完成) |
+| **Phase 1** | 2026-06~07 | 五维平台核心 | 五维重构、家庭成员体系、文章中心、推广体系 | ✅ 已完成 |
+| **Phase 2** | 2026-07~08 | 商业模式 & AI 落地 | LangGraph前端集成、家庭推广体系、AI健康管家 | ✅ 已完成 |
+| **Phase 3** | 2026-Q3 | 五维增强 | 富维度子维度拆分、文章发布系统、辈分重构 | ✅ 已完成 |
+| **Phase 4** | 2026-Q4 | 平台扩展 | 供应商体系、健康7维模型、成长档案 | ⏳ 计划级(未实施) |
 | **Phase 5** | 2026-Q3 | 主动健康六阶模型 | 微启动+即时反馈+智能预警+身份重塑+家庭互动+社区扩散 | ✅ 已完成(P0-P3 全栈交付) |
 
 ---
@@ -25,13 +25,13 @@
 ### 2.1 AI 架构升级 — LangGraph Sidecar ⭐ P0
 
 **阶段:** Phase 2/3
-**状态:** ✅ Phase 1 代码全量完成 + Docker 已部署运行(LLM healthy);Phase 2-4 代码已写但前端未集成,已纳入 `plans/2026-07-22-comprehensive-implementation.md` Phase 2 Wave 1-2
+**状态:** ✅ Phase 1 代码全量完成 + Docker 已部署运行(LLM healthy);Phase 2 前端集成已完成(config.js LANGGRAPH_BASE_URL + Dify fallback),Phase 3-4 代码已写
 **决策:** 2026-07-20 确定:Python LangGraph Sidecar 替换 Dify,Java 8 不升级
 
 | 里程碑 | 内容 | 关联文档 |
 |--------|------|---------|
 | **Phase 1** (1-2周) | 基建 + RecommendAgent + AiGateway + Docker | `plans/2026-07-20-langgraph-phase1.md` |
-| **Phase 2-4** | 代码已写(Chat/Analysis/Recommend+RAG+Memory+Monitoring),前端集成待实施 | `plans/2026-07-22-comprehensive-implementation.md` |
+| **Phase 2-4** | Phase 2 前端集成已完成,Phase 3-4 代码已写(Chat/Analysis/Recommend+RAG+Memory+Monitoring) | `plans/2026-07-22-comprehensive-implementation.md` |
 
 **核心设计:** `specs/2026-07-20-langgraph-migration-design.md`
 **需求汇总:** `specs/2026-07-20-langgraph-requirements-summary.md` ⚠️ **文件缺失**
@@ -50,7 +50,7 @@
 | 五行相克算法(v2.0 信号层) | ✅ 已上线 | `specs/2026-07-12-wuxing-ke-full-design.md` |
 | 首页与能量转化算法 | ✅ 已上线 | `specs/2026-07-12-wuxing-homepage-and-conversion-algorithm.md` |
 | 维度功能清单与能量映射 | 🟡 设计稿 | `specs/2026-07-12-dimension-features-energy-map.md` |
-| 富维度子维度拆分 + 身克富杠杆 | 🚧 部分实施(前端 WealthSubScores.vue + BodyWealthAlert.vue 已存在,后端子维度体系待完善) | `plans/2026-07-12-wealth-dimension-redesign.md` + `plans/2026-07-22-comprehensive-implementation.md` |
+| 富维度子维度拆分 + 身克富杠杆 | ✅ 已完成(EnergyService 重构 + getWealthDetail API + 前端 WealthSubScores.vue 展示) | `plans/2026-07-22-comprehensive-implementation.md` Task 6-7 |
 | 维度权重滑块重设计 | ✅ 已实施 | `specs/2026-07-02-dimension-weight-picker-redesign.md` |
 
 ---
@@ -116,7 +116,7 @@
 
 | 功能 | 阶段 | 状态 | 关联文档 |
 |------|:----:|:----:|---------|
-| 富维度子维度拆分 + 身克富杠杆 | Phase 3 | 🚧 部分实施(前端组件已存在,后端待完善) | `plans/2026-07-12-wealth-dimension-redesign.md` + `plans/2026-07-22-comprehensive-implementation.md` |
+| 富维度子维度拆分 + 身克富杠杆 | Phase 3 | ✅ 已完成(EnergyService 重构 + getWealthDetail API + 前端角色感知展示) | `plans/2026-07-22-comprehensive-implementation.md` Task 6-7 |
 | 积分价格整数化迁移 | Phase 1 | ✅ 已上线 | `plans/2026-06-15-integer-price-migration.md` |
 | 富沛(我的)页面重构 | Phase 1 | ✅ 已完成(profile/ 6组件 1338行) | `specs/2026-06-19-profile-page-redesign.md` |
 
@@ -128,7 +128,7 @@
 
 | 功能 | 阶段 | 状态 | 关联文档 |
 |------|:----:|:----:|---------|
-| 家庭推广体系重构(wxacode+家庭账户) | Phase 2 | 🚧 P2-P4待实施(P1后端+前端基础页面已完成:invite/join.vue, parent/invite/index.vue, guide/invite/share.vue) | `specs/2026-07-14-family-promotion-redesign.md` + `plans/2026-07-14-family-promotion.md` |
+| 家庭推广体系重构(wxacode+家庭账户) | Phase 2 | ✅ 已完成(CommissionService + 27 个后端文件,promotion/ 6 前端页面,含推广中心/成员贡献榜/收益概览) | `specs/2026-07-14-family-promotion-redesign.md` + `plans/2026-07-22-comprehensive-implementation.md` Task 3-4 |
 | 行远页重要关系维护(通讯录导入) | Phase 1 | ✅ 已完成(action/ 5页面 2116行,含OctopusGraph+问卷+互动日志) | `specs/2026-06-14-action-page-relationship-design.md` |
 | 家庭关系图谱(见跨维度) | — | ✅ 已实施(FamilyRelationGraph.vue 797行,10+页面使用) | 见 2.3 |
 
@@ -178,7 +178,7 @@
 ### 4.3 家庭会员体系 ⭐ P2
 
 **阶段:** Phase 2
-**状态:** ✅ 后端完成(MemberSubscriptionService + MembershipController),前端已完成(membership/index.vue 685行 + 3子页面),AI管家 Phase 2 Wave 3 计划中
+**状态:** ✅ 全栈完成(MemberSubscriptionService + MembershipController + membership/ 3 前端页面,含 FREE/FAMILY/PREMIUM 三等级价格体系,价格通过 sys_config 可配置,商城升级提示通用化)
 
 | 功能 | 关联文档 |
 |------|---------|
@@ -216,6 +216,7 @@
 | 管理后台手机自适应 | 2026-07 | `plans/2026-07-24-cfc-web-responsive-implementation.md` |
 | DAN测评执行记录双角色模型(assessor/planner分离) | 2026-07 | — |
 | 家庭成员辈分重构(全栈) | 2026-07 | `plans/2026-07-07-家庭成员辈分重构实施计划.md` |
+| 会员等级价格体系更新(FREE/FAMILY/PREMIUM) | 2026-07 | `plans/2026-07-28-membership-price-tier-update.md` |
 
 ---
 
@@ -275,7 +276,7 @@
 
 | 文件 | 状态 | 说明 |
 |------|:----:|------|
-| `2026-07-22-comprehensive-implementation.md` | ✅ 当前 | 全面实施计划(Phase 2-4) |
+| `2026-07-22-comprehensive-implementation.md` | ✅ Phase 2-3 全部完成,Phase 4 计划级 | 全面实施计划(Phase 2-4) |
 | `2026-07-20-langgraph-migration-design.md` | ✅ 当前 | LangGraph 架构设计 |
 | `2026-07-20-langgraph-requirements-summary.md` | ⚠️ 文件缺失 | 需求与决策汇总 |
 | `2026-06-05-five-dimension-energy-design.md` | ✅ 已实施 | 五维能量系统(核心) |
@@ -287,8 +288,8 @@
 | `2026-06-22-family-relation-graph-redesign.md` | ✅ 已实施(10+页面集成) | FamilyRelationGraph重构 |
 | `2026-07-07-家庭成员关系视角转换设计.md` | ✅ 全栈完成 | 辈分重构设计(GenerationLevel.java + FamilyMemberService + GenerationPicker.vue + generationLevel.js) |
 | `2026-07-03-article-center-design.md` | ✅ 已实施(4页面 1429行 + ArticleController) | 文章中心设计 |
-| `2026-07-09-family-membership-design.md` | ✅ 已实施(Service+Controller已完成,前端待实现) | 家庭会员体系 |
-| `2026-07-14-family-promotion-redesign.md` | 🚧 后端完成,前端基础就绪 | 家庭推广体系 |
+| `2026-07-09-family-membership-design.md` | ✅ 全栈完成(含 FREE/FAMILY/PREMIUM 三等级价格体系) | 家庭会员体系 |
+| `2026-07-14-family-promotion-redesign.md` | ✅ 已完成(推广中心 6 页面 + 27 后端文件) | 家庭推广体系 |
 | `2026-07-17-flora-microbiome-report-page-design.md` | ✅ 已实施(4页面 1214行 + HealthKnowledgeBase) | 菌群报告页面 |
 | `2026-06-24-cfc-ecommerce-extension-design.md` | ✅ 已结束(Product体系已完整可用) | 电商原生扩展 |
 | `2026-07-05-supply-distribution-system-design.md` | 🟡 待实施 | 供应商销售体系 |
@@ -316,14 +317,14 @@
 | 文件 | 状态 | 说明 |
 |------|:----:|------|
 | `2026-07-25-e2e-test-rearchitecture-phase1.md` | ✅ Phase 1 complete | E2E 测试体系 Phase 1 实施 |
-| `2026-07-22-comprehensive-implementation.md` | ✅ 当前 | 全面实施计划(Phase 2-4) |
+| `2026-07-22-comprehensive-implementation.md` | ✅ Phase 2-3 全部完成,Phase 4 计划级 | 全面实施计划(Phase 2-4) |
 | `2026-07-20-langgraph-phase1.md` | ✅ 已部署(AiGateway+Docker+LLM 运行中) | LangGraph Phase 1 |
 | `2026-07-20-langgraph-phase2.md` | 🔄 合并至 comprehensive plan | LangGraph Phase 2 |
 | `2026-07-20-langgraph-phase3.md` | 🔄 合并至 comprehensive plan | LangGraph Phase 3 |
 | `2026-07-20-langgraph-phase4.md` | 🔄 合并至 comprehensive plan | LangGraph Phase 4 |
 | `2026-07-17-flora-microbiome-report-implementation.md` | ✅ 已完成(4页面 1214行 + HealthKnowledgeBase后端) | 菌群报告重构 |
 | `2026-07-16-first-login-auto-complete-plan.md` | ✅ 已实施(login.vue + user-edit.vue均已完成) | 首次登录优化 |
-| `2026-07-14-family-promotion.md` | 🚧 P1后端完成,P2-P4待实施(前端基础页面已存在) | 家庭推广体系 |
+| `2026-07-14-family-promotion.md` | ✅ 已完成(推广中心 6 页面 + 27 后端文件) | 家庭推广体系 |
 | `2026-07-13-dan-assessment-phase2-5.md` | 🟡 计划中 | DAN测评优化 |
 | `2026-07-12-wealth-dimension-redesign.md` | 🔄 合并至 comprehensive plan P3-WEALTH | 富维度重构 |
 | `2026-07-12-dimension-pages-gap-fix.md` | 🟡 实施中 | 维度页面缺口修复 |
@@ -337,7 +338,7 @@
 | `2026-06-27-health-dimensions-incremental-plan.md` | ✅ 后端已实现(HealthDimensionController七维指标+DimensionScoreService+HealthDimensionScore实体) | 健康维度增量 |
 | `2026-06-26-health-dimensions-refactor.md` | ✅ 后端全实现(Tier2 VOICE/PHOTO + DimensionScoreServiceImpl + canvas雷达图 + health_data_sources表) | 健康维度重构 |
 | `2026-06-22-family-relation-graph-redesign.md` | ✅ 已完成(FamilyRelationGraph.vue 797行,10+页面使用) | 关系图谱重构 |
-| `2026-06-22-营养健康部分缺陷修复计划.md` | 🟡 计划中(Phase 2) | 营养健康修复 |
+| `2026-06-22-营养健康部分缺陷修复计划.md` | ✅ 已实施(5项缺陷已修复) | 营养健康修复 |
 | `2026-06-20-dimension-knowledge-base-plan.md` | ✅ 已实施(KnowledgeBaseController + DifySyncService) | 知识库平台 |
 | `2026-06-20-web-permission-system.md` | ✅ 已结束 | 权限系统 |
 | `2026-06-20-cfc-web-e2e-test-fix.md` | ✅ 已结束 | Web端E2E测试 |
@@ -362,6 +363,7 @@
 | `2026-07-06-test-fix-and-enhance-plan.md` | ✅ 已结束 | 测试修复增强 |
 | `2026-07-19-report-upload-purchase-links.md` | 🟡 计划中 | 报告购买链接 |
 | `2026-07-24-cfc-web-responsive-implementation.md` | ✅ 已实施(commit 3ee7289e) | 管理后台手机自适应 |
+| `2026-07-28-membership-price-tier-update.md` | ✅ 全栈完成(FREE/FAMILY/PREMIUM 三等级,7 次提交) | 会员等级价格体系更新 |
 
 ### 计划与设计文档(specs/)
 

+ 147 - 4
tests/e2e/flow-l1-tests.js

@@ -156,7 +156,10 @@ async function loginAll() {
   var roles = {
     parent: { phone: '13701366188', method: 'code' },
     child: { phone: '13701366189', method: 'code' },
-    teacher: { phone: '13800000001', method: 'code' },
+    teacher: { phone: '13800000001', method: 'code' },   // 规划师
+    nutritionist: { phone: '13800000010', method: 'code' },
+    butler: { phone: '13800000020', method: 'code' },
+    assessor: { phone: '13800000030', method: 'code' },
     admin: { phone: '13800138000', method: 'password' },
     vendor: { phone: '13800138001', method: 'code' }
   };
@@ -241,6 +244,36 @@ async function testAuthFlow() {
   r = await apiCall('POST', '/api/user/info', {}, t);
   record(F, 'teacher', '获取用户信息', r.status === 200 && r.body && r.body.code === 200, r.body ? 'userId=' + (r.body.data && r.body.data.id) : r.raw);
 
+  // --- 营养师 ---
+  t = tokens.nutritionist;
+  if (!t) { skip(F, 'nutritionist', '所有测试', '未登录'); return; }
+
+  r = await apiCall('POST', '/api/auth/verify', {}, t);
+  record(F, 'nutritionist', 'JWT验证', r.status === 200 && r.body && r.body.code === 200, r.body ? r.body.message : r.raw);
+
+  r = await apiCall('POST', '/api/user/info', {}, t);
+  record(F, 'nutritionist', '获取用户信息', r.status === 200 && r.body && r.body.code === 200, r.body ? 'userId=' + (r.body.data && r.body.data.id) : r.raw);
+
+  // --- 管家 ---
+  t = tokens.butler;
+  if (!t) { skip(F, 'butler', '所有测试', '未登录'); return; }
+
+  r = await apiCall('POST', '/api/auth/verify', {}, t);
+  record(F, 'butler', 'JWT验证', r.status === 200 && r.body && r.body.code === 200, r.body ? r.body.message : r.raw);
+
+  r = await apiCall('POST', '/api/user/info', {}, t);
+  record(F, 'butler', '获取用户信息', r.status === 200 && r.body && r.body.code === 200, r.body ? 'userId=' + (r.body.data && r.body.data.id) : r.raw);
+
+  // --- 评估师 ---
+  t = tokens.assessor;
+  if (!t) { skip(F, 'assessor', '所有测试', '未登录'); return; }
+
+  r = await apiCall('POST', '/api/auth/verify', {}, t);
+  record(F, 'assessor', 'JWT验证', r.status === 200 && r.body && r.body.code === 200, r.body ? r.body.message : r.raw);
+
+  r = await apiCall('POST', '/api/user/info', {}, t);
+  record(F, 'assessor', '获取用户信息', r.status === 200 && r.body && r.body.code === 200, r.body ? 'userId=' + (r.body.data && r.body.data.id) : r.raw);
+
   // --- 管理员 ---
   t = tokens.admin;
   if (!t) { skip(F, 'admin', '所有测试', '未登录'); return; }
@@ -717,13 +750,13 @@ async function testDanFlow() {
   r = await apiCall('POST', '/api/assessment/history', { childId: 1003 }, t);
   record(F, 'parent', '测评历史', r.status === 200 && r.body && r.body.code === 200, r.body ? 'history OK' : r.raw);
 
-  // 我的报告(只有指导师可以查看,改用teacher token)
+  // 我的报告(只有规划师可以查看,改用teacher token)
   var tTeacher = tokens.teacher;
   if (tTeacher) {
     r = await apiCall('POST', '/api/dan-assessment/my-results', {}, tTeacher);
-    record(F, 'parent', '我的报告', r.status === 200 && r.body && r.body.code === 200, r.body ? 'my results OK' : r.raw);
+    record(F, 'teacher', '我的报告', r.status === 200 && r.body && r.body.code === 200, r.body ? 'my results OK' : r.raw);
   } else {
-    skip(F, 'parent', '我的报告', 'teacher未登录');
+    skip(F, 'teacher', '我的报告', 'teacher未登录');
   }
 
   // 家长自评(需要childId + materialId,可能无可用测评资料,接口存活即可)
@@ -739,6 +772,13 @@ async function testDanFlow() {
     r = await apiCall('POST', '/api/guide/assessment/families', {}, t2);
     record(F, 'teacher', '家庭测评列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'guide assessment families OK' : r.raw);
   }
+
+  // --- 评估师端 ---
+  var t3 = tokens.assessor;
+  if (t3) {
+    r = await apiCall('POST', '/api/assessment/my-results', {}, t3);
+    record(F, 'assessor', '评估结果列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'assessor results OK' : r.raw);
+  }
 }
 
 // ================================================================
@@ -788,6 +828,13 @@ async function testShopFlow() {
     r = await apiCall('POST', '/api/product/my', {}, t2);
     record(F, 'admin', '管理端商品列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'admin products OK' : r.raw);
   }
+
+  // --- 商品供应商(可能未通过审核,接口存活即可) ---
+  var t3 = tokens.vendor;
+  if (t3) {
+    r = await apiCall('POST', '/api/vendor/info', {}, t3);
+    record(F, 'vendor', '供应商信息', r.status === 200 && r.body && (r.body.code === 200 || r.body.code === 500), r.body ? 'vendor info OK (code=' + r.body.code + ')' : r.raw);
+  }
 }
 
 // ================================================================
@@ -912,6 +959,13 @@ async function testNutritionFlow() {
   // 北京知识库
   r = await apiCall('POST', '/api/nutrition/beijing/kb/list', {}, t);
   record(F, 'parent', '营养知识库', r.status === 200 && r.body && r.body.code === 200, r.body ? 'kb list OK' : r.raw);
+
+  // --- 营养师端 ---
+  var tN = tokens.nutritionist;
+  if (tN) {
+    r = await apiCall('POST', '/api/nutritionist/status', {}, tN);
+    record(F, 'nutritionist', '营养师状态', r.status === 200 && r.body && r.body.code === 200, r.body ? 'nutritionist status OK' : r.raw);
+  }
 }
 
 // ================================================================
@@ -1024,6 +1078,10 @@ async function testActivityFlow() {
   if (t2) {
     r = await apiCall('POST', '/api/admin/activity/list', {}, t2);
     record(F, 'admin', '管理端活动列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'admin activities OK' : r.raw);
+
+    // 活动管理员:管家后台管理
+    r = await apiCall('POST', '/api/admin/butler/list', {}, t2);
+    record(F, 'admin', '管家列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'butler list OK' : r.raw);
   }
 }
 
@@ -1057,6 +1115,13 @@ async function testContentFlow() {
   // 媒体(使用真实存在的taskId)
   r = await apiCall('POST', '/api/media/upload-text', { taskId: 192, creatorId: 1002, content: 'Test media text' }, t);
   record(F, 'parent', '保存文字记录', r.status === 200 && r.body && r.body.code === 200, r.body ? 'text upload OK' : r.body ? r.body.message : r.raw);
+
+  // --- 文章管理员 ---
+  var tA = tokens.admin;
+  if (tA) {
+    r = await apiCall('POST', '/api/admin/articles/list', {}, tA);
+    record(F, 'admin', '文章管理列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'admin articles OK' : r.raw);
+  }
 }
 
 // ================================================================
@@ -1173,6 +1238,14 @@ async function testAdminFlow() {
   // 健康检查
   r = await apiCall('POST', '/api/system/health', {}, t);
   record(F, 'admin', '系统健康检查', r.status === 200 && r.body && r.body.code === 200, r.body ? 'health OK' : r.raw);
+
+  // 供应商体系管理
+  r = await apiCall('POST', '/api/admin/supplier/list', {}, t);
+  record(F, 'admin', '供应商列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'supplier list OK' : r.raw);
+
+  // 管家后台管理
+  r = await apiCall('POST', '/api/admin/butler/list', {}, t);
+  record(F, 'admin', '管家列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'butler list OK' : r.raw);
 }
 
 // ================================================================
@@ -1333,6 +1406,72 @@ async function testExtraFlow() {
   record(F, 'parent', '引导进度', r.status === 200 && r.body && r.body.code === 200, r.body ? 'onboarding OK' : r.raw);
 }
 
+// ================================================================
+// FLOW 24: 管家服务 (butler-service-flow)
+// ================================================================
+
+async function testButlerFlow() {
+  var F = '管家服务';
+  log('\n========== ' + F + ' ==========');
+
+  var t = tokens.butler;
+  if (!t) { skip(F, 'butler', '所有测试', '未登录'); return; }
+
+  var r = await apiCall('POST', '/api/butler/profile', {}, t);
+  record(F, 'butler', '管家档案', r.status === 200 && r.body && (r.body.code === 200 || r.body.code === 500), r.body ? 'butler profile OK (code=' + r.body.code + ')' : r.raw);
+
+  r = await apiCall('POST', '/api/butler/members', {}, t);
+  record(F, 'butler', '家庭成员列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'butler members OK' : r.raw);
+}
+
+// ================================================================
+// FLOW 25: 营养师管理 (nutritionist-management-flow)
+// ================================================================
+
+async function testNutritionistFlow() {
+  var F = '营养师管理';
+  log('\n========== ' + F + ' ==========');
+
+  var t = tokens.nutritionist;
+  if (!t) { skip(F, 'nutritionist', '所有测试', '未登录'); return; }
+
+  var r = await apiCall('POST', '/api/nutritionist/status', {}, t);
+  record(F, 'nutritionist', '营养师状态', r.status === 200 && r.body && r.body.code === 200, r.body ? 'nutritionist status OK' : r.raw);
+}
+
+// ================================================================
+// FLOW 26: 供应商体系 (supply-system-flow)
+// ================================================================
+
+async function testSupplyFlow() {
+  var F = '供应商体系';
+  log('\n========== ' + F + ' ==========');
+
+  var t = tokens.admin;
+  if (!t) { skip(F, 'admin', '所有测试', '未登录'); return; }
+
+  var r = await apiCall('POST', '/api/admin/supplier/list', {}, t);
+  record(F, 'admin', '供应商列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'supplier list OK' : r.raw);
+
+  r = await apiCall('POST', '/api/admin/supplier/product/list', {}, t);
+  record(F, 'admin', '供应商商品列表', r.status === 200 && r.body && (r.body.code === 200 || r.body.code === 500), r.body ? 'supplier products OK (code=' + r.body.code + ')' : r.raw);
+}
+
+// ================================================================
+// FLOW 27: 评估师管理 (assessor-management-flow)
+// ================================================================
+
+async function testAssessorFlow() {
+  var F = '评估师管理';
+  log('\n========== ' + F + ' ==========');
+
+  var t = tokens.assessor;
+  if (!t) { skip(F, 'assessor', '所有测试', '未登录'); return; }
+
+  var r = await apiCall('POST', '/api/assessment/my-results', {}, t);
+  record(F, 'assessor', '评估结果列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'assessor results OK' : r.raw);
+}
+
 // ================================================================
 // MAIN RUNNER
 // ================================================================
@@ -1373,6 +1512,10 @@ async function main() {
   await testCircleFlow();
   await testKnowledgeFlow();
   await testExtraFlow();
+  await testButlerFlow();
+  await testNutritionistFlow();
+  await testSupplyFlow();
+  await testAssessorFlow();
 
   // Step 3: Summary
   console.log('\n============================================================');