فهرست منبع

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

liaoxg 3 ماه پیش
والد
کامیت
865362cbfd
48فایلهای تغییر یافته به همراه9206 افزوده شده و 2571 حذف شده
  1. 45 0
      cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java
  2. 61 0
      cfc-backend/src/main/java/com/etotem/cfc/controller/admin/CommissionDistController.java
  3. 158 0
      cfc-backend/src/main/java/com/etotem/cfc/controller/admin/PpointConfigAdminController.java
  4. 39 0
      cfc-backend/src/main/java/com/etotem/cfc/entity/CategoryPpoint.java
  5. 62 0
      cfc-backend/src/main/java/com/etotem/cfc/entity/CommissionDistLog.java
  6. 9 0
      cfc-backend/src/main/java/com/etotem/cfc/mapper/CategoryPpointMapper.java
  7. 9 0
      cfc-backend/src/main/java/com/etotem/cfc/mapper/CommissionDistLogMapper.java
  8. 199 0
      cfc-backend/src/main/java/com/etotem/cfc/service/CommissionDistService.java
  9. 213 0
      cfc-backend/src/main/java/com/etotem/cfc/service/PpointConfigService.java
  10. 19 0
      cfc-backend/src/main/java/com/etotem/cfc/service/PromotionTierService.java
  11. 35 0
      cfc-backend/src/main/resources/schema.sql
  12. 1 1
      cfc-web/.last_build_commit
  13. 2 2
      cfc-web/package-lock.json
  14. 1 1
      cfc-web/package.json
  15. 19 0
      cfc-web/public/CHANGELOG-v1.0.md
  16. 20 1
      cfc-web/public/CHANGELOG.md
  17. 4 1
      cfc-web/src/views/admin/ProductEdit.vue
  18. 265 129
      docs/flows/activity-flow.md
  19. 338 91
      docs/flows/admin-overview-flow.md
  20. 265 65
      docs/flows/ai-assistant-flow.md
  21. 245 52
      docs/flows/badge-microaction-flow.md
  22. 207 47
      docs/flows/cart-coupon-flow.md
  23. 279 83
      docs/flows/circle-contact-flow.md
  24. 389 66
      docs/flows/content-media-flow.md
  25. 385 227
      docs/flows/dan-assessment-flow.md
  26. 242 60
      docs/flows/energy-system-flow.md
  27. 254 50
      docs/flows/extra-features-flow.md
  28. 327 153
      docs/flows/family-management-flow.md
  29. 149 25
      docs/flows/growth-task-flow.md
  30. 451 282
      docs/flows/guide-system-flow.md
  31. 196 72
      docs/flows/health-checkin-flow.md
  32. 413 105
      docs/flows/health-detection-flow.md
  33. 363 72
      docs/flows/knowledge-invite-flow.md
  34. 266 64
      docs/flows/market-flow.md
  35. 317 70
      docs/flows/membership-flow.md
  36. 211 71
      docs/flows/mind-emotion-flow.md
  37. 183 56
      docs/flows/minigame-flow.md
  38. 264 71
      docs/flows/nutrition-diet-flow.md
  39. 281 53
      docs/flows/points-exchange-flow.md
  40. 276 79
      docs/flows/promotion-flow.md
  41. 425 103
      docs/flows/shop-flow.md
  42. 277 70
      docs/flows/stats-report-flow.md
  43. 269 92
      docs/flows/task-management-flow.md
  44. 132 29
      docs/flows/tianpan-fortune-flow.md
  45. 186 75
      docs/flows/user-auth-flow.md
  46. 121 41
      docs/flows/vendor-butler-flow.md
  47. 155 55
      docs/flows/wealth-insurance-flow.md
  48. 179 57
      docs/flows/wish-management-flow.md

+ 45 - 0
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java

@@ -6071,6 +6071,51 @@ try {
     }
     ensureColumn("products", "recommendation_tags", "VARCHAR(500) DEFAULT NULL COMMENT '推荐标签'");
     ensureColumn("products", "repurchase_interval_days", "INT DEFAULT 30 COMMENT '复购间隔天数'");
+
+    // 迁移134: 创建 category_ppoint 表(品类P点比例配置)
+    try {
+        jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS category_ppoint (" +
+            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+            "category_id BIGINT NOT NULL COMMENT '商品类目ID', " +
+            "ratio INT DEFAULT 0 COMMENT 'P点比例(千分比)', " +
+            "start_date DATETIME COMMENT '生效日期', " +
+            "end_date DATETIME COMMENT '失效日期(null=永不过期)', " +
+            "created_by BIGINT COMMENT '创建人', " +
+            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
+            "INDEX idx_category_id (category_id)" +
+        ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='品类P点比例配置'");
+        log.info("已创建category_ppoint表");
+    } catch (Exception e) {
+        log.warn("创建category_ppoint表失败: {}", e.getMessage());
+    }
+
+    // 迁移135: 创建 commission_dist_log 表(P点分润记录)
+    try {
+        jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS commission_dist_log (" +
+            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+            "buyer_id BIGINT NOT NULL COMMENT '买家用户ID', " +
+            "order_id BIGINT COMMENT '订单ID', " +
+            "product_id BIGINT COMMENT '商品ID', " +
+            "source_ppoint INT DEFAULT 0 COMMENT '本次产生的原始P点数量', " +
+            "level1_user_id BIGINT COMMENT '一级推荐人用户ID', " +
+            "level1_ppoint INT DEFAULT 0 COMMENT '一级推荐人获得P点', " +
+            "level1_wealth_percent INT DEFAULT 0 COMMENT '一级推荐人当时财富等级(profitSharePercent)', " +
+            "level2_user_id BIGINT COMMENT '二级推荐人用户ID', " +
+            "level2_ppoint INT DEFAULT 0 COMMENT '二级推荐人获得P点', " +
+            "level2_wealth_percent INT DEFAULT 0 COMMENT '二级推荐人当时财富等级(profitSharePercent)', " +
+            "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/completed/failed', " +
+            "remark VARCHAR(500) COMMENT '备注', " +
+            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
+            "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', " +
+            "INDEX idx_buyer (buyer_id), " +
+            "INDEX idx_order (order_id), " +
+            "INDEX idx_level1 (level1_user_id), " +
+            "INDEX idx_level2 (level2_user_id)" +
+        ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='P点分润记录'");
+        log.info("已创建commission_dist_log表");
+    } catch (Exception e) {
+        log.warn("创建commission_dist_log表失败: {}", e.getMessage());
+    }
     }
 
     private void runMigration82() {

+ 61 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/admin/CommissionDistController.java

@@ -0,0 +1,61 @@
+package com.etotem.cfc.controller.admin;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.etotem.cfc.common.Result;
+import com.etotem.cfc.entity.CommissionDistLog;
+import com.etotem.cfc.service.CommissionDistService;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * P点分润记录管理
+ * 管理端接口
+ */
+@RestController
+@RequestMapping("/api/admin/commission-dist")
+public class CommissionDistController {
+
+    @Resource
+    private CommissionDistService commissionDistService;
+
+    /**
+     * 分润记录分页列表
+     */
+    @PostMapping("/list")
+    public Result<Page<CommissionDistLog>> list(@RequestBody Map<String, Object> params) {
+        int page = params.get("page") != null ? ((Number) params.get("page")).intValue() : 1;
+        int size = params.get("size") != null ? ((Number) params.get("size")).intValue() : 20;
+        Long buyerId = params.get("buyerId") != null ? Long.valueOf(params.get("buyerId").toString()) : null;
+        Long levelUserId = params.get("levelUserId") != null ? Long.valueOf(params.get("levelUserId").toString()) : null;
+
+        Page<CommissionDistLog> pageParam = new Page<>(page, size);
+        Page<CommissionDistLog> result = commissionDistService.adminPage(pageParam, buyerId, levelUserId);
+        return Result.success(result);
+    }
+
+    /**
+     * 用户分润记录查询(买家或推荐人)
+     */
+    @PostMapping("/user-logs")
+    public Result<List<CommissionDistLog>> userLogs(@RequestBody Map<String, Object> params) {
+        Long userId = Long.valueOf(params.get("userId").toString());
+        List<CommissionDistLog> logs = commissionDistService.getUserDistLogs(userId, 1, 50);
+        return Result.success(logs);
+    }
+
+    /**
+     * 用户累计获得P点分润
+     */
+    @PostMapping("/user-total")
+    public Result<Integer> userTotal(@RequestBody Map<String, Object> params) {
+        Long userId = Long.valueOf(params.get("userId").toString());
+        int total = commissionDistService.getTotalDistributedPpoint(userId);
+        return Result.success(total);
+    }
+}

+ 158 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/admin/PpointConfigAdminController.java

@@ -0,0 +1,158 @@
+package com.etotem.cfc.controller.admin;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.etotem.cfc.common.Result;
+import com.etotem.cfc.entity.CategoryPpoint;
+import com.etotem.cfc.entity.ProductPpoint;
+import com.etotem.cfc.service.PpointConfigService;
+import com.etotem.cfc.service.PpointService;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * P点配置管理(品类级比例 + 商品级固定值)
+ * 管理端接口
+ */
+@RestController
+@RequestMapping("/api/admin/ppoint-config")
+public class PpointConfigAdminController {
+
+    @Resource
+    private PpointConfigService ppointConfigService;
+
+    @Resource
+    private PpointService ppointService;
+
+    // ======================== 品类级P点比例 ========================
+
+    @PostMapping("/category/list")
+    public Result<Map<String, Object>> categoryList(@RequestBody Map<String, Object> params) {
+        int page = params.get("page") != null ? ((Number) params.get("page")).intValue() : 1;
+        int size = params.get("size") != null ? ((Number) params.get("size")).intValue() : 20;
+        String keyword = (String) params.get("keyword");
+
+        Page<CategoryPpoint> pageParam = new Page<>(page, size);
+        Map<String, Object> result = ppointConfigService.adminCategoryList(pageParam, keyword);
+        return Result.success(result);
+    }
+
+    @PostMapping("/category/save")
+    public Result<Void> categorySave(@RequestBody Map<String, Object> params) {
+        Long categoryId = Long.valueOf(params.get("categoryId").toString());
+        Integer ratio = Integer.valueOf(params.get("ratio").toString());
+        String startDateStr = (String) params.get("startDate");
+        String endDateStr = (String) params.get("endDate");
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        java.util.Date startDate = null;
+        java.util.Date endDate = null;
+        try {
+            if (startDateStr != null && !startDateStr.isEmpty()) {
+                startDate = sdf.parse(startDateStr);
+            }
+            if (endDateStr != null && !endDateStr.isEmpty()) {
+                endDate = sdf.parse(endDateStr);
+            }
+        } catch (Exception e) {
+            return Result.error("日期格式错误,请使用yyyy-MM-dd");
+        }
+
+        if (ratio < 0 || ratio > 1000) {
+            return Result.error("P点比例取值范围为0-1000(即0%-100%)");
+        }
+
+        ppointConfigService.saveCategoryRatio(categoryId, ratio, startDate, endDate, null);
+        return Result.success(null);
+    }
+
+    @PostMapping("/category/delete")
+    public Result<Void> categoryDelete(@RequestBody Map<String, Object> params) {
+        Long id = Long.valueOf(params.get("id").toString());
+        ppointConfigService.deleteCategoryRatio(id);
+        return Result.success(null);
+    }
+
+    @PostMapping("/category/by-category")
+    public Result<List<CategoryPpoint>> categoryByCategory(@RequestBody Map<String, Object> params) {
+        Long categoryId = Long.valueOf(params.get("categoryId").toString());
+        List<CategoryPpoint> records = ppointConfigService.getByCategoryId(categoryId);
+        return Result.success(records);
+    }
+
+    // ======================== 商品级P点(复用PpointService) ========================
+
+    @PostMapping("/product/list")
+    public Result<Map<String, Object>> productList(@RequestBody Map<String, Object> params) {
+        int page = params.get("page") != null ? ((Number) params.get("page")).intValue() : 1;
+        int size = params.get("size") != null ? ((Number) params.get("size")).intValue() : 20;
+        String keyword = (String) params.get("keyword");
+        Long productId = params.get("productId") != null ? Long.valueOf(params.get("productId").toString()) : null;
+
+        Page<ProductPpoint> pageParam = new Page<>(page, size);
+        Map<String, Object> result = ppointService.adminList(pageParam, keyword, productId);
+        return Result.success(result);
+    }
+
+    @PostMapping("/product/save")
+    public Result<Void> productSave(@RequestBody Map<String, Object> params) {
+        Long productId = Long.valueOf(params.get("productId").toString());
+        Integer ppoint = Integer.valueOf(params.get("ppoint").toString());
+        String startDateStr = (String) params.get("startDate");
+        String endDateStr = (String) params.get("endDate");
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        java.util.Date startDate = null;
+        java.util.Date endDate = null;
+        try {
+            if (startDateStr != null && !startDateStr.isEmpty()) {
+                startDate = sdf.parse(startDateStr);
+            }
+            if (endDateStr != null && !endDateStr.isEmpty()) {
+                endDate = sdf.parse(endDateStr);
+            }
+        } catch (Exception e) {
+            return Result.error("日期格式错误,请使用yyyy-MM-dd");
+        }
+
+        if (ppoint < 0 || ppoint > 10000) {
+            return Result.error("P点取值范围为0-10000(即0%-100%)");
+        }
+
+        ppointService.savePpoint(productId, ppoint, startDate, endDate, null);
+        return Result.success(null);
+    }
+
+    @PostMapping("/product/delete")
+    public Result<Void> productDelete(@RequestBody Map<String, Object> params) {
+        Long id = Long.valueOf(params.get("id").toString());
+        ppointService.deleteById(id);
+        return Result.success(null);
+    }
+
+    @PostMapping("/product/by-product")
+    public Result<List<ProductPpoint>> productByProduct(@RequestBody Map<String, Object> params) {
+        Long productId = Long.valueOf(params.get("productId").toString());
+        List<ProductPpoint> records = ppointService.getByProductId(productId);
+        return Result.success(records);
+    }
+
+    // ======================== 综合查询 ========================
+
+    /**
+     * 获取商品综合有效的P点值
+     */
+    @PostMapping("/effective")
+    public Result<Integer> getEffectivePpoint(@RequestBody Map<String, Object> params) {
+        Long productId = Long.valueOf(params.get("productId").toString());
+        Long categoryId = params.get("categoryId") != null ? Long.valueOf(params.get("categoryId").toString()) : null;
+        int ppoint = ppointConfigService.getEffectivePpoint(productId, categoryId);
+        return Result.success(ppoint);
+    }
+}

+ 39 - 0
cfc-backend/src/main/java/com/etotem/cfc/entity/CategoryPpoint.java

@@ -0,0 +1,39 @@
+package com.etotem.cfc.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 商品品类P点比例配置
+ * 当品类设置了ratio(千分比),该品类下所有商品优先使用品类的P点比例,
+ * 除非该商品有独立的 ProductPpoint 配置。
+ */
+@Data
+@TableName("category_ppoint")
+public class CategoryPpoint implements Serializable {
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 商品类目ID(关联 products.categoryId) */
+    private Long categoryId;
+
+    /** P点比例(千分比),如 200 表示20% */
+    private Integer ratio;
+
+    /** 生效日期 */
+    private Date startDate;
+
+    /** 失效日期(null=永不过期) */
+    private Date endDate;
+
+    /** 创建人 */
+    private Long createdBy;
+
+    private Date createdAt;
+}

+ 62 - 0
cfc-backend/src/main/java/com/etotem/cfc/entity/CommissionDistLog.java

@@ -0,0 +1,62 @@
+package com.etotem.cfc.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * P点分润记录
+ * 当用户购买商品产生P点时,按推荐关系将P点分配给一级和二级推荐人。
+ * 分润以P点(积分点)为单位,非现金。
+ */
+@Data
+@TableName("commission_dist_log")
+public class CommissionDistLog implements Serializable {
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 买家用户ID(产生P点的用户) */
+    private Long buyerId;
+
+    /** 订单ID */
+    private Long orderId;
+
+    /** 商品ID */
+    private Long productId;
+
+    /** 本次产生的原始P点数量 */
+    private Integer sourcePpoint;
+
+    /** 一级推荐人用户ID(null=无推荐人) */
+    private Long level1UserId;
+
+    /** 一级推荐人获得P点 */
+    private Integer level1Ppoint;
+
+    /** 一级推荐人当时的财富等级(profitSharePercent值) */
+    private Integer level1WealthPercent;
+
+    /** 二级推荐人用户ID(null=无推荐人) */
+    private Long level2UserId;
+
+    /** 二级推荐人获得P点 */
+    private Integer level2Ppoint;
+
+    /** 二级推荐人当时的财富等级(profitSharePercent值) */
+    private Integer level2WealthPercent;
+
+    /** 状态:pending/completed/failed */
+    private String status;
+
+    /** 备注 */
+    private String remark;
+
+    private Date createdAt;
+
+    private Date updatedAt;
+}

+ 9 - 0
cfc-backend/src/main/java/com/etotem/cfc/mapper/CategoryPpointMapper.java

@@ -0,0 +1,9 @@
+package com.etotem.cfc.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.etotem.cfc.entity.CategoryPpoint;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface CategoryPpointMapper extends BaseMapper<CategoryPpoint> {
+}

+ 9 - 0
cfc-backend/src/main/java/com/etotem/cfc/mapper/CommissionDistLogMapper.java

@@ -0,0 +1,9 @@
+package com.etotem.cfc.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.etotem.cfc.entity.CommissionDistLog;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface CommissionDistLogMapper extends BaseMapper<CommissionDistLog> {
+}

+ 199 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/CommissionDistService.java

@@ -0,0 +1,199 @@
+package com.etotem.cfc.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.etotem.cfc.entity.*;
+import com.etotem.cfc.mapper.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * P点分润服务
+ * 
+ * 核心逻辑:
+ * 1. 用户购买商品/活动产生P点(基于PpointConfigService计算)
+ * 2. 查找购买用户的推荐链(referral_tree),取一级和二级推荐人
+ * 3. 每个推荐人在 promotion_tier 表中查其财富成长等级
+ * 4. 财富等级的 profitSharePercent 决定了该推荐人分得P点的比例
+ * 5. 仅一级和二级推荐人参与分润
+ * 
+ * 分润公式:
+ *   推荐人分得P点 = sourcePpoint × profitSharePercent / 100
+ */
+@Service
+public class CommissionDistService {
+
+    private static final Logger log = LoggerFactory.getLogger(CommissionDistService.class);
+
+    @Resource
+    private CommissionDistLogMapper commissionDistLogMapper;
+
+    @Resource
+    private ReferralTreeMapper referralTreeMapper;
+
+    @Resource
+    private PromotionTierService promotionTierService;
+
+    @Resource
+    private PpointConfigService ppointConfigService;
+
+    @Resource
+    private ProductMapper productMapper;
+
+    /**
+     * 执行P点分润
+     * 当用户的购买产生P点时,按推荐关系分配给一级和二级推荐人
+     *
+     * @param buyerId  买家用户ID
+     * @param orderId  订单ID
+     * @param productId 商品ID
+     * @return 分润记录,若无需分润返回null
+     */
+    @Transactional
+    public CommissionDistLog distribute(Long buyerId, Long orderId, Long productId) {
+        if (buyerId == null || productId == null) {
+            return null;
+        }
+
+        // 1. 计算该商品产生的P点
+        Product product = productMapper.selectById(productId);
+        if (product == null) {
+            return null;
+        }
+        int sourcePpoint = ppointConfigService.getEffectivePpoint(productId, product.getCategoryId());
+        if (sourcePpoint <= 0) {
+            log.info("商品{}无P点配置,不分润", productId);
+            return null;
+        }
+
+        // 2. 查找购买用户的一级和二级推荐人
+        LambdaQueryWrapper<ReferralTree> wrapper = new LambdaQueryWrapper<ReferralTree>()
+                .eq(ReferralTree::getChildId, buyerId)
+                .in(ReferralTree::getLevel, 1, 2)
+                .orderByAsc(ReferralTree::getLevel);
+        List<ReferralTree> referrals = referralTreeMapper.selectList(wrapper);
+
+        if (referrals == null || referrals.isEmpty()) {
+            log.info("用户{}无推荐关系,不分润", buyerId);
+            return null;
+        }
+
+        // 3. 按推荐等级分配P点
+        Long level1UserId = null;
+        Integer level1Ppoint = 0;
+        Integer level1WealthPercent = 0;
+        Long level2UserId = null;
+        Integer level2Ppoint = 0;
+        Integer level2WealthPercent = 0;
+
+        for (ReferralTree ref : referrals) {
+            int level = ref.getLevel();
+            Long referrerId = ref.getParentId();
+
+            // 获取推荐人当前财富成长等级
+            PromotionTier tier = promotionTierService.getCurrentTier(referrerId);
+            int wealthPercent = 0;
+            if (tier != null) {
+                // 从 promotion_tier_config 查 profitSharePercent
+                PromotionTierConfig config = promotionTierService.getTierConfig(tier.getTier());
+                if (config != null && config.getProfitSharePercent() != null) {
+                    wealthPercent = config.getProfitSharePercent();
+                }
+            }
+
+            // 计算该推荐人应分得P点
+            // 公式:sourcePpoint * wealthPercent / 100
+            int ppointShare = (int) Math.floor((double) sourcePpoint * wealthPercent / 100.0);
+
+            if (level == 1) {
+                level1UserId = referrerId;
+                level1Ppoint = ppointShare;
+                level1WealthPercent = wealthPercent;
+            } else if (level == 2) {
+                level2UserId = referrerId;
+                level2Ppoint = ppointShare;
+                level2WealthPercent = wealthPercent;
+            }
+        }
+
+        // 4. 记录分润日志
+        CommissionDistLog logRecord = new CommissionDistLog();
+        logRecord.setBuyerId(buyerId);
+        logRecord.setOrderId(orderId);
+        logRecord.setProductId(productId);
+        logRecord.setSourcePpoint(sourcePpoint);
+        logRecord.setLevel1UserId(level1UserId);
+        logRecord.setLevel1Ppoint(level1Ppoint);
+        logRecord.setLevel1WealthPercent(level1WealthPercent);
+        logRecord.setLevel2UserId(level2UserId);
+        logRecord.setLevel2Ppoint(level2Ppoint);
+        logRecord.setLevel2WealthPercent(level2WealthPercent);
+        logRecord.setStatus("completed");
+        logRecord.setRemark("商品P点分润");
+        logRecord.setCreatedAt(new Date());
+        commissionDistLogMapper.insert(logRecord);
+
+        log.info("P点分润完成: buyerId={}, productId={}, sourcePpoint={}, level1={}/{}pp, level2={}/{}pp",
+                buyerId, productId, sourcePpoint,
+                level1UserId, level1Ppoint, level2UserId, level2Ppoint);
+
+        return logRecord;
+    }
+
+    /**
+     * 查询用户相关的分润记录(作为买家或推荐人)
+     */
+    public List<CommissionDistLog> getUserDistLogs(Long userId, int page, int size) {
+        LambdaQueryWrapper<CommissionDistLog> wrapper = new LambdaQueryWrapper<CommissionDistLog>()
+                .eq(CommissionDistLog::getBuyerId, userId)
+                .or()
+                .eq(CommissionDistLog::getLevel1UserId, userId)
+                .or()
+                .eq(CommissionDistLog::getLevel2UserId, userId)
+                .orderByDesc(CommissionDistLog::getCreatedAt);
+        return commissionDistLogMapper.selectList(wrapper);
+    }
+
+    /**
+     * 获取用户累计获得的P点分润
+     */
+    public int getTotalDistributedPpoint(Long userId) {
+        LambdaQueryWrapper<CommissionDistLog> wrapper = new LambdaQueryWrapper<CommissionDistLog>()
+                .eq(CommissionDistLog::getStatus, "completed")
+                .and(w -> w.eq(CommissionDistLog::getLevel1UserId, userId)
+                        .or().eq(CommissionDistLog::getLevel2UserId, userId));
+        List<CommissionDistLog> list = commissionDistLogMapper.selectList(wrapper);
+        return list.stream()
+                .mapToInt(r -> {
+                    if (userId.equals(r.getLevel1UserId())) {
+                        return r.getLevel1Ppoint() != null ? r.getLevel1Ppoint() : 0;
+                    } else {
+                        return r.getLevel2Ppoint() != null ? r.getLevel2Ppoint() : 0;
+                    }
+                })
+                .sum();
+    }
+
+    /**
+     * 管理端分页查询分润记录
+     */
+    public com.baomidou.mybatisplus.extension.plugins.pagination.Page<CommissionDistLog> adminPage(
+            com.baomidou.mybatisplus.extension.plugins.pagination.Page<CommissionDistLog> pageParam,
+            Long buyerId, Long levelUserId) {
+        LambdaQueryWrapper<CommissionDistLog> wrapper = new LambdaQueryWrapper<CommissionDistLog>()
+                .orderByDesc(CommissionDistLog::getCreatedAt);
+        if (buyerId != null) {
+            wrapper.eq(CommissionDistLog::getBuyerId, buyerId);
+        }
+        if (levelUserId != null) {
+            wrapper.and(w -> w.eq(CommissionDistLog::getLevel1UserId, levelUserId)
+                    .or().eq(CommissionDistLog::getLevel2UserId, levelUserId));
+        }
+        return commissionDistLogMapper.selectPage(pageParam, wrapper);
+    }
+}

+ 213 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/PpointConfigService.java

@@ -0,0 +1,213 @@
+package com.etotem.cfc.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.etotem.cfc.entity.CategoryPpoint;
+import com.etotem.cfc.entity.Product;
+import com.etotem.cfc.entity.ProductPpoint;
+import com.etotem.cfc.mapper.CategoryPpointMapper;
+import com.etotem.cfc.mapper.ProductMapper;
+import com.etotem.cfc.mapper.ProductCategoryMapper;
+import com.etotem.cfc.mapper.ProductPpointMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * P点配置管理 — 综合品类级比例 + 商品级固定值
+ * 查询优先级:商品级 ProductPpoint > 品类级 CategoryPpoint.ratio > 商品 profitRate
+ */
+@Service
+public class PpointConfigService {
+
+    private static final Logger log = LoggerFactory.getLogger(PpointConfigService.class);
+
+    @Resource
+    private ProductPpointMapper productPpointMapper;
+
+    @Resource
+    private CategoryPpointMapper categoryPpointMapper;
+
+    @Resource
+    private ProductMapper productMapper;
+
+    @Resource
+    private ProductCategoryMapper productCategoryMapper;
+
+    // ======================== 品类级P点比例 ========================
+
+    /**
+     * 获取品类当前有效的P点比例
+     * @param categoryId 品类ID
+     * @return 千分比(如 200 = 20%),0表示未配置
+     */
+    public int getCategoryRatio(Long categoryId) {
+        if (categoryId == null) return 0;
+        Date now = new Date();
+        LambdaQueryWrapper<CategoryPpoint> wrapper = new LambdaQueryWrapper<CategoryPpoint>()
+                .eq(CategoryPpoint::getCategoryId, categoryId)
+                .le(CategoryPpoint::getStartDate, now)
+                .and(w -> w.isNull(CategoryPpoint::getEndDate).or().ge(CategoryPpoint::getEndDate, now))
+                .orderByDesc(CategoryPpoint::getStartDate)
+                .last("LIMIT 1");
+        CategoryPpoint record = categoryPpointMapper.selectOne(wrapper);
+        if (record != null && record.getRatio() != null && record.getRatio() > 0) {
+            return record.getRatio();
+        }
+        return 0;
+    }
+
+    /**
+     * 获取商品综合有效的P点值(优先商品级 → 品类级 → profitRate)
+     * @param productId 商品ID
+     * @param categoryId 商品品类ID(可为null)
+     * @return P点值
+     */
+    public int getEffectivePpoint(Long productId, Long categoryId) {
+        // 1. 商品级 ProductPpoint
+        Date now = new Date();
+        LambdaQueryWrapper<ProductPpoint> pw = new LambdaQueryWrapper<ProductPpoint>()
+                .eq(ProductPpoint::getProductId, productId)
+                .le(ProductPpoint::getStartDate, now)
+                .and(w -> w.isNull(ProductPpoint::getEndDate).or().ge(ProductPpoint::getEndDate, now))
+                .orderByDesc(ProductPpoint::getStartDate)
+                .last("LIMIT 1");
+        ProductPpoint productPpoint = productPpointMapper.selectOne(pw);
+        if (productPpoint != null && productPpoint.getPpoint() != null && productPpoint.getPpoint() > 0) {
+            return productPpoint.getPpoint();
+        }
+
+        // 2. 品类级比例(千分比)
+        if (categoryId != null) {
+            int categoryRatio = getCategoryRatio(categoryId);
+            if (categoryRatio > 0) {
+                return categoryRatio;
+            }
+        }
+
+        // 3. 商品 profitRate 回退
+        Product product = productMapper.selectById(productId);
+        if (product != null && product.getProfitRate() != null) {
+            return product.getProfitRate() * 100;
+        }
+
+        return 0;
+    }
+
+    // ======================== 品类级CRUD ========================
+
+    public void saveCategoryRatio(Long categoryId, Integer ratio, Date startDate, Date endDate, Long adminUserId) {
+        LambdaQueryWrapper<CategoryPpoint> wrapper = new LambdaQueryWrapper<CategoryPpoint>()
+                .eq(CategoryPpoint::getCategoryId, categoryId);
+        CategoryPpoint existing = categoryPpointMapper.selectOne(wrapper);
+        if (existing != null) {
+            existing.setRatio(ratio);
+            existing.setStartDate(startDate);
+            existing.setEndDate(endDate);
+            existing.setCreatedBy(adminUserId);
+            categoryPpointMapper.updateById(existing);
+        } else {
+            CategoryPpoint record = new CategoryPpoint();
+            record.setCategoryId(categoryId);
+            record.setRatio(ratio);
+            record.setStartDate(startDate);
+            record.setEndDate(endDate);
+            record.setCreatedBy(adminUserId);
+            record.setCreatedAt(new Date());
+            categoryPpointMapper.insert(record);
+        }
+    }
+
+    public void deleteCategoryRatio(Long id) {
+        categoryPpointMapper.deleteById(id);
+    }
+
+    public List<CategoryPpoint> getByCategoryId(Long categoryId) {
+        return categoryPpointMapper.selectList(
+                new LambdaQueryWrapper<CategoryPpoint>()
+                        .eq(CategoryPpoint::getCategoryId, categoryId)
+                        .orderByDesc(CategoryPpoint::getStartDate)
+        );
+    }
+
+    /**
+     * 品类P点比例分页列表(带品类名称)
+     */
+    public Map<String, Object> adminCategoryList(Page<CategoryPpoint> pageParam, String keyword) {
+        LambdaQueryWrapper<CategoryPpoint> wrapper = new LambdaQueryWrapper<CategoryPpoint>()
+                .orderByDesc(CategoryPpoint::getCreatedAt);
+        Page<CategoryPpoint> page = categoryPpointMapper.selectPage(pageParam, wrapper);
+        List<CategoryPpoint> records = page.getRecords();
+
+        if (!records.isEmpty()) {
+            List<Long> categoryIds = records.stream()
+                    .map(CategoryPpoint::getCategoryId)
+                    .distinct()
+                    .collect(Collectors.toList());
+            // 品类名称查询(直接通过 product_categories 表获取品类名称)
+            Map<Long, String> categoryNames = new HashMap<>();
+            if (!categoryIds.isEmpty()) {
+                String ids = categoryIds.stream().map(String::valueOf).collect(Collectors.joining(","));
+                try {
+                    List<Map<String, Object>> cats = productCategoryMapper.selectMaps(
+                            new LambdaQueryWrapper<com.etotem.cfc.entity.ProductCategory>()
+                                    .in(com.etotem.cfc.entity.ProductCategory::getId, categoryIds)
+                                    .select(com.etotem.cfc.entity.ProductCategory::getId, com.etotem.cfc.entity.ProductCategory::getName)
+                    );
+                    for (Map<String, Object> cat : cats) {
+                        Object id = cat.get("id");
+                        Object name = cat.get("name");
+                        if (id != null && name != null) {
+                            categoryNames.put(Long.valueOf(id.toString()), name.toString());
+                        }
+                    }
+                } catch (Exception e) {
+                    log.warn("查询品类名称失败: {}", e.getMessage());
+                }
+            }
+
+            final Map<Long, String> nameMap = categoryNames;
+            List<Map<String, Object>> enriched = records.stream().map(r -> {
+                Map<String, Object> m = new HashMap<>();
+                m.put("id", r.getId());
+                m.put("categoryId", r.getCategoryId());
+                m.put("ratio", r.getRatio());
+                m.put("startDate", r.getStartDate());
+                m.put("endDate", r.getEndDate());
+                m.put("createdBy", r.getCreatedBy());
+                m.put("createdAt", r.getCreatedAt());
+                m.put("categoryName", nameMap.getOrDefault(r.getCategoryId(), "未知品类"));
+                return m;
+            }).collect(Collectors.toList());
+
+            // keyword 内存过滤
+            if (keyword != null && !keyword.trim().isEmpty()) {
+                String kw = keyword.trim().toLowerCase();
+                enriched = enriched.stream()
+                        .filter(e -> e.get("categoryName") != null && e.get("categoryName").toString().toLowerCase().contains(kw))
+                        .collect(Collectors.toList());
+            }
+
+            Map<String, Object> result = new HashMap<>();
+            result.put("records", enriched);
+            result.put("total", page.getTotal());
+            result.put("page", page.getCurrent());
+            result.put("size", page.getSize());
+            return result;
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("records", records);
+        result.put("total", page.getTotal());
+        result.put("page", page.getCurrent());
+        result.put("size", page.getSize());
+        return result;
+    }
+}

+ 19 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/PromotionTierService.java

@@ -3,7 +3,9 @@ package com.etotem.cfc.service;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.etotem.cfc.entity.PromotionTier;
 import com.etotem.cfc.entity.PromotionTierChangeLog;
+import com.etotem.cfc.entity.PromotionTierConfig;
 import com.etotem.cfc.mapper.PromotionTierChangeLogMapper;
+import com.etotem.cfc.mapper.PromotionTierConfigMapper;
 import com.etotem.cfc.mapper.PromotionTierMapper;
 import org.springframework.stereotype.Service;
 
@@ -20,6 +22,9 @@ public class PromotionTierService {
     @Resource
     private PromotionTierChangeLogMapper changeLogMapper;
 
+    @Resource
+    private PromotionTierConfigMapper tierConfigMapper;
+
     /**
      * 获取用户当前推广等级
      */
@@ -39,6 +44,20 @@ public class PromotionTierService {
         return tierMapper.selectList(null);
     }
 
+    /**
+     * 按等级代码获取等级配置(含profitSharePercent P点比例)
+     * @param tierCode 等级代码: R0/R1/R2/R3/R4
+     * @return 等级配置,未找到返回null
+     */
+    public PromotionTierConfig getTierConfig(String tierCode) {
+        if (tierCode == null) return null;
+        return tierConfigMapper.selectOne(
+                new LambdaQueryWrapper<PromotionTierConfig>()
+                        .eq(PromotionTierConfig::getTierCode, tierCode)
+                        .last("LIMIT 1")
+        );
+    }
+
     /**
      * 更新团队规模(当有新推荐人加入时调用)
      */

+ 35 - 0
cfc-backend/src/main/resources/schema.sql

@@ -3512,3 +3512,38 @@ CREATE TABLE IF NOT EXISTS report_summary (
   UNIQUE KEY uk_source (source_table, source_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统一报告汇总表';
 -- report_summary 表已由 DatabaseInitializer 迁移创建
+
+-- category_ppoint: 品类P点比例配置(P点体系)
+CREATE TABLE IF NOT EXISTS category_ppoint (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    category_id BIGINT NOT NULL COMMENT '商品类目ID',
+    ratio INT DEFAULT 0 COMMENT 'P点比例(千分比)',
+    start_date DATETIME COMMENT '生效日期',
+    end_date DATETIME COMMENT '失效日期(null=永不过期)',
+    created_by BIGINT COMMENT '创建人',
+    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    INDEX idx_category_id (category_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='品类P点比例配置';
+
+-- commission_dist_log: P点分润记录(P点体系)
+CREATE TABLE IF NOT EXISTS commission_dist_log (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    buyer_id BIGINT NOT NULL COMMENT '买家用户ID',
+    order_id BIGINT COMMENT '订单ID',
+    product_id BIGINT COMMENT '商品ID',
+    source_ppoint INT DEFAULT 0 COMMENT '本次产生的原始P点数量',
+    level1_user_id BIGINT COMMENT '一级推荐人用户ID',
+    level1_ppoint INT DEFAULT 0 COMMENT '一级推荐人获得P点',
+    level1_wealth_percent INT DEFAULT 0 COMMENT '一级推荐人当时财富等级(profitSharePercent)',
+    level2_user_id BIGINT COMMENT '二级推荐人用户ID',
+    level2_ppoint INT DEFAULT 0 COMMENT '二级推荐人获得P点',
+    level2_wealth_percent INT DEFAULT 0 COMMENT '二级推荐人当时财富等级(profitSharePercent)',
+    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/completed/failed',
+    remark VARCHAR(500) COMMENT '备注',
+    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    INDEX idx_buyer (buyer_id),
+    INDEX idx_order (order_id),
+    INDEX idx_level1 (level1_user_id),
+    INDEX idx_level2 (level2_user_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='P点分润记录';

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-c3cee795089d0bf4ea89b0c83a2d295ea67cc6fb
+0deabb269b8abc350d408878f78b63b02ea21b53

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

@@ -1,12 +1,12 @@
 {
   "name": "cfc-web",
-  "version": "1.0.605",
+  "version": "1.0.608",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "cfc-web",
-      "version": "1.0.605",
+      "version": "1.0.608",
       "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.606",
+  "version": "1.0.608",
   "private": true,
   "scripts": {
     "dev": "vue-cli-service serve",

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

@@ -4,6 +4,25 @@
 
 ---
 
+## v1.0.608 (2026-07-29)
+
+### 其他
+- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
+- 
+
+
+## v1.0.608 (2026-07-29)
+
+### 文档
+- 全部31个流程图重绘 — 数据上连线+中文标注+分层+完整性分析
+
+
+## v1.0.607 (2026-07-29)
+
+### Bug 修复
+- member pricing display, wisdom/body page layout, :key expr in FamilyTianpanCard, remove FamilyRelationGraph
+
+
 ## v1.0.605 (2026-07-28)
 
 ### 文档

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

@@ -1,6 +1,6 @@
 # 更新日志
 
-> 当前版本: v1.0.605
+> 当前版本: v1.0.608
 
 ## 历史版本
 
@@ -8,6 +8,25 @@
 
 ---
 
+## v1.0.608 (2026-07-29)
+
+### 其他
+- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
+- 
+
+
+## v1.0.608 (2026-07-29)
+
+### 文档
+- 全部31个流程图重绘 — 数据上连线+中文标注+分层+完整性分析
+
+
+## v1.0.607 (2026-07-29)
+
+### Bug 修复
+- member pricing display, wisdom/body page layout, :key expr in FamilyTianpanCard, remove FamilyRelationGraph
+
+
 ## v1.0.605 (2026-07-28)
 
 ### 文档

+ 4 - 1
cfc-web/src/views/admin/ProductEdit.vue

@@ -199,7 +199,7 @@
 
         <el-form-item>
           <el-button type="primary" :loading="saving" @click="handleSave">
-            保存
+{{ isEdit ? '保存修改' : '创建商品' }}
           </el-button>
           <el-button @click="$router.back()">取消</el-button>
         </el-form-item>
@@ -653,6 +653,9 @@ export default {
 .product-edit .el-card {
   width: 100%;
 }
+.product-edit .el-card .el-card__body {
+  overflow-y: auto;
+}
 .product-edit .el-form {
   width: 100%;
 }

+ 265 - 129
docs/flows/activity-flow.md

@@ -1,156 +1,292 @@
 # 用户使用流程图 — 活动管理
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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(("🔧 活动管理员")):::portAdmin --> A2[🖥 创建活动 /create]:::portAdmin
-        A2 --> A3[🖥 设置基本信息:标题/描述/封面/维度]:::portAdmin
-        A3 --> A4[🖥 设置活动类型 offline/online/campaign]:::portAdmin
-        A4 --> A5[🖥 设置时间地点:开始/结束/位置]:::portAdmin
-        A5 --> A6[🖥 设置报名规则]:::portAdmin
-        A6 --> A7{🖥 是否限制人数?}:::portAdmin
-        A7 -->|是| A8[🖥 设置最大人数 maxParticipants]:::portAdmin
-        A7 -->|否| A9[不限制人数]
-        A8 --> A10[🖥 设置价格体系]:::portAdmin
-        A9 --> A10
-        A10 --> A11[🖥 普通价 price]:::portAdmin
-        A11 --> A12[🖥 会员价 memberPrice]:::portAdmin
-        A12 --> A13[🖥 签到积分 checkinPoints]:::portAdmin
-        A13 --> A14[🖥 设置可见范围 public/restricted/member]:::portAdmin
-        A14 --> A15[🖥 保存草稿]:::portAdmin
-    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
 
-    subgraph 活动审核流程
-        A15 --> B1[🖥 提交审核 /submit-review]:::portAdmin
-        B1 --> B2{🖥 管理员审核 /audit}:::portAdmin
-        B2 -->|通过| B3[活动发布]
-        B2 -->|驳回| B4[🖥 查看驳回原因]:::portAdmin
-        B4 --> B5[🖥 编辑后重新提交]:::portAdmin
-        B5 --> B1
-    end
+    %% ============ 角色 ============
+    A0(("🔧 活动管理员")):::actor
+    B0(("👤 家长")):::actor
+    C0(("👶 孩子")):::actor
+    D0(("🖥 管理员")):::actor
 
-    subgraph 发布与下架
-        B3 --> C1[🖥 发布活动 /publish]:::portAdmin
-        C1 --> C2[活动上线]
-        C2 --> C3{活动到期或结束操作}
-        C3 -->|手动结束| C4[🖥 结束活动 /end]:::portAdmin
-        C3 -->|截止时间到| C4
-        C4 --> C5[活动结束<br/>不可再报名]
-    end
+    %% ================================================================
+    %% 阶段一:活动创建(规划师端)
+    %% ================================================================
+    subgraph 阶段一[阶段一:活动创建]
+        direction TB
 
-    subgraph 用户浏览与报名
-        C2 --> D1(("👤 家长")):::portMiniApp --> D2[📱 浏览活动列表 /list]:::portMiniApp
-        D2 --> D3[📱 查看详情 /detail]:::portMiniApp
-        D3 --> D4{📱 报名条件检查}:::portMiniApp
-        D4 -->|人数已满| D5[📱 提示已满员]:::portMiniApp
-        D4 -->|已截止| D6[📱 提示报名结束]:::portMiniApp
-        D4 -->|可报名| D7[📱 选择参加的孩子 childId]:::portMiniApp
-        D7 --> D8[📱 填写参加人身份信息]:::portMiniApp
-        D8 --> D9{📱 用户会员等级}:::portMiniApp
-        D9 -->|普通用户| D10[📱 普通价 price]:::portMiniApp
-        D9 -->|会员用户| D11[📱 会员价 memberPrice]:::portMiniApp
-        D10 --> D12[📱 提交报名 /register]:::portMiniApp
-        D11 --> D12
-        D12 --> D13{📱 报名需审核?}:::portMiniApp
-        D13 -->|是| D14[📱 等待管理员审批]:::portMiniApp
-        D13 -->|否| D15[📱 报名成功]:::portMiniApp
-        D14 --> D16{🖥 管理员操作}:::portAdmin
-        D16 -->|通过| D15
-        D16 -->|拒绝| D17[📱 报名被驳回]:::portMiniApp
-    end
+        P1["📋 规划师端:活动管理页"]:::page
+        P1 -->|"点击创建"| P1a["📋 规划师端:创建活动表单"]:::page
+        P1a -->|"活动标题, 描述, 封面, 分类, 地点, 日期, 最大人数, 价格"| A1["🔗 POST /api/guide/activities/create"]:::api
+        A1 -->|"activity(含上述字段)"| S1["⚙️ GuideActivityService.createActivity()"]:::service
+        S1 -->|"初始状态=draft, currentParticipants=0"| D1["📦 guide_activities 表"]:::data
+
+        P1 -->|"编辑活动"| P1b["📋 规划师端:编辑活动表单"]:::page
+        P1b -->|"活动ID, 修改字段"| A2["🔗 POST /api/guide/activities/update"]:::api
+        A2 -->|"活动ID, 变更字段"| S2["⚙️ GuideActivityService.updateActivity()"]:::service
+        S2 -->|"更新对应字段"| D1
 
-    subgraph 报名管理
-        D15 --> E1[📱 我的报名 /my-registrations]:::portMiniApp
-        E1 --> E2{📱 活动开始前?}:::portMiniApp
-        E2 -->|是| E3[📱 取消报名 /cancel-registration]:::portMiniApp
-        E2 -->|否| E4[📱 等待签到]:::portMiniApp
+        P1 -->|"发布活动"| P1c["📋 规划师端:发布确认"]:::page
+        P1c -->|"活动ID"| A3["🔗 POST /api/guide/activities/publish"]:::api
+        A3 -->|"活动ID"| S3["⚙️ GuideActivityService.updateStatus(published)"]:::service
+        S3 -->|"状态=published"| D1
+
+        P1 -->|"取消活动"| P1d["📋 规划师端:取消确认"]:::page
+        P1d -->|"活动ID"| A4["🔗 POST /api/guide/activities/cancel"]:::api
+        A4 -->|"活动ID"| S4["⚙️ GuideActivityService.updateStatus(cancelled)"]:::service
+        S4 -->|"状态=cancelled"| D1
     end
 
-    subgraph 签到
-        E4 --> F1[📱 签到 /checkin]:::portMiniApp
-        F1 --> F2{📱 需审核签到?}:::portMiniApp
-        F2 -->|是| F3[📱 等待审核]:::portMiniApp
-        F2 -->|否| F4[📱 签到成功<br/>发放积分]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:活动审核(管理后台)
+    %% ================================================================
+    subgraph 阶段二[阶段二:活动审核(管理后台)]
+        D1 -->|"待审核活动"| P2["🖥 管理后台:活动列表页"]:::page
+        P2 -->|"查看列表"| A5["🔗 POST /api/admin/activity/list"]:::api
+        A5 -->|"status, dimensionCode, auditStatus 过滤"| S5["⚙️ ActivityAdminService.list()"]:::service
+        S5 -->|"含草稿的所有活动"| D2["📦 activities 表(查询)"]:::data
+
+        D2 -->|"选择活动"| P2a["🖥 管理后台:活动详情页"]:::page
+        P2a -->|"活动ID"| A6["🔗 POST /api/admin/activity/detail"]:::api
+        A6 -->|"id"| S6["⚙️ ActivityAdminService.getDetail()"]:::service
+        S6 -->|"Activity对象"| D2
+
+        P2a -->|"提交审核"| A7["🔗 POST /api/admin/activity/submit-review"]:::api
+        A7 -->|"id"| S7["⚙️ ActivityAdminService.submitForReview()"]:::service
+        S7 -->|"状态=pending, auditStatus=pending"| D2
+
+        P2a -->|"审核通过/驳回"| A8["🔗 POST /api/admin/activity/audit"]:::api
+        A8 -->|"id, action=approved/rejected, rejectReason"| S8["⚙️ ActivityAdminService.auditActivity()"]:::service
+        S8 -->|"approved→published / rejected→rejected"| D2
+
+        P2a -->|"发布操作(简洁模式)"| A9["🔗 POST /api/admin/activity/review"]:::api
+        A9 -->|"id, action=publish/reject"| S9["⚙️ ActivityAdminService.review()"]:::service
+        S9 -->|"publish→published / reject→删除记录"| D2
+
+        P2a -->|"撤回活动"| A10["🔗 POST /api/admin/activity/withdraw"]:::api
+        A10 -->|"id"| S10["⚙️ ActivityAdminService.withdraw()"]:::service
+        S10 -->|"状态=withdrawn"| D2
+
+        P2a -->|"转草稿(驳回后)"| A11["🔗 POST /api/admin/activity/re-draft"]:::api
+        A11 -->|"id"| S11["⚙️ ActivityAdminService.reDraft()"]:::service
+        S11 -->|"状态=draft, 清空审核信息"| D2
     end
 
-    subgraph 活动反馈(活动结束后)
-        C5 --> G1[📱 已签到参与者]:::portMiniApp
-        G1 --> G2[📱 提交活动反馈]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:活动前台创建/管理(管理后台直发)
+    %% ================================================================
+    subgraph 阶段三[阶段三:管理后台直接活动管理]
+        P3["🏠 管理后台:活动管理页"]:::page
+        P3 -->|"创建活动"| P3a["🏠 填写活动信息表单"]:::page
+        P3a -->|"title, description, dimensionCode, activityType, startTime, endTime, location, maxParticipants, price, memberPrice, checkinPoints, visibility, requireRegistration, requireCheckinReview, energyPenaltyUnregistered, feedbackDimensions"| A12["🔗 POST /api/activity/create"]:::api
+        A12 -->|"activity对象, 需admin/activity_admin角色"| S12["⚙️ ActivityService.create()"]:::service
+        S12 -->|"状态=draft, currentParticipants=0"| D3["📦 activities 表"]:::data
+
+        P3 -->|"修改活动"| P3b["🏠 修改活动信息"]:::page
+        P3b -->|"活动ID+修改字段"| A13["🔗 POST /api/activity/update"]:::api
+        A13 -->|"activity对象, 需admin/activity_admin角色"| S13["⚙️ ActivityService.update()"]:::service
+        S13 -->|"更新对应字段"| D3
+
+        P3 -->|"发布活动"| P3c["🏠 发布确认"]:::page
+        P3c -->|"活动ID"| A14["🔗 POST /api/activity/publish"]:::api
+        A14 -->|"id, 需admin/activity_admin"| S14["⚙️ ActivityService.publish()"]:::service
+        S14 -->|"状态=published(仅draft可发布)"| D3
+
+        P3 -->|"结束活动"| P3d["🏠 结束确认"]:::page
+        P3d -->|"活动ID"| A15["🔗 POST /api/activity/end"]:::api
+        A15 -->|"id, 需admin/activity_admin"| S15["⚙️ ActivityService.end()"]:::service
+        S15 -->|"状态=ended"| D3
     end
 
-    subgraph 管理员报名管理
-        D14 --> H1[🖥 报名列表 /admin/activity/registration/list]:::portAdmin
-        H1 --> H2[🖥 审批 /approve]:::portAdmin
-        H2 --> H3[🖥 拒绝 /reject]:::portAdmin
+    %% ================================================================
+    %% 阶段四:用户浏览与报名
+    %% ================================================================
+    subgraph 阶段四[阶段四:用户浏览与报名]
+        D3 -->|"已发布活动"| P4["📱 小程序:活动列表页"]:::page
+        P4 -->|"按维度/分页过滤"| A16["🔗 POST /api/activity/list"]:::api
+        A16 -->|"dimensionCode, page, size, userId(自动)"| S16["⚙️ ActivityService.list()"]:::service
+        S16 -->|"已发布活动列表(含会员价计算)"| D3
+
+        P4 -->|"查看详情"| P4a["📱 小程序:活动详情页"]:::page
+        P4a -->|"活动ID"| A17["🔗 POST /api/activity/detail"]:::api
+        A17 -->|"id"| S17["⚙️ ActivityService.detail()"]:::service
+        S17 -->|"ActivityDTO(含维度和价格信息)"| D3
+
+        P4a -->|"报名"| P4b["📱 小程序:选择参与孩子"]:::page
+        P4b -->|"活动ID, 孩子ID"| A18["🔗 POST /api/activity/register"]:::api
+        A18 -->|"activityId, childId, userId"| S18["⚙️ ActivityRegistrationService.register()"]:::service
+        S18 -->|"状态=pending(需审核)或直接approved"| D4["📦 activity_registrations 表"]:::data
+
+        P4b -->|"取消报名"| P4c["📱 小程序:取消报名确认"]:::page
+        P4c -->|"活动ID, 孩子ID"| A19["🔗 POST /api/activity/cancel-registration"]:::api
+        A19 -->|"activityId, childId, userId"| S19["⚙️ ActivityRegistrationService.cancel()"]:::service
+        S19 -->|"状态=cancelled"| D4
+
+        P4 -->|"我的报名"| P4d["📱 小程序:我的报名页"]:::page
+        P4d -->|"孩子ID, 分页"| A20["🔗 POST /api/activity/my-registrations"]:::api
+        A20 -->|"childId, page, size"| S20["⚙️ ActivityRegistrationService.getMyRegistrations()"]:::service
+        S20 -->|"报名记录列表(含活动标题)"| D4
     end
 
-    subgraph 管理后台
-        B2 --> I1[🖥 活动列表 /admin/activity/list]:::portAdmin
-        I1 --> I2[🖥 活动审核 /review]:::portAdmin
-        I2 --> I3[🖥 撤回 /withdraw]:::portAdmin
-        I3 --> I4[🖥 转草稿 /re-draft]:::portAdmin
+    %% ================================================================
+    %% 阶段五:报名管理(管理后台)
+    %% ================================================================
+    subgraph 阶段五[阶段五:报名审批]
+        D4 -->|"待审批报名"| P5["🖥 管理后台:报名列表页"]:::page
+        P5 -->|"按活动/状态过滤"| A21["🔗 POST /api/admin/activity/registration/list"]:::api
+        A21 -->|"activityId, status"| S21["⚙️ ActivityRegistrationService.getRegistrationsByActivity()"]:::service
+        S21 -->|"报名记录列表"| D4
+
+        P5 -->|"通过"| A22["🔗 POST /api/admin/activity/registration/approve"]:::api
+        A22 -->|"registrationId, adminUserId"| S22["⚙️ ActivityRegistrationService.approve()"]:::service
+        S22 -->|"状态=approved, approvedAt, approvedBy"| D4
+
+        P5 -->|"拒绝"| A23["🔗 POST /api/admin/activity/registration/reject"]:::api
+        A23 -->|"registrationId, adminUserId"| S23["⚙️ ActivityRegistrationService.reject()"]:::service
+        S23 -->|"状态=rejected"| D4
     end
 
-    R1(("🔧 活动管理员<br/>role=activity_admin")):::actor
-    R2(("👤 家长")):::actor
-    R3(("👶 孩子")):::role
-    R4(("🔧 管理员")):::role
+    %% ================================================================
+    %% 阶段六:签到
+    %% ================================================================
+    subgraph 阶段六[阶段六:签到]
+        D3 -->|"进行中的活动"| P6["📱 小程序:活动签到页"]:::page
+        P6 -->|"扫码/按钮签到"| A24["🔗 POST /api/activity/checkin"]:::api
+        A24 -->|"id(活动ID), childId, userId"| S24["⚙️ ActivityService.checkin()"]:::service
+        S24 -->|"创建Task(状态=completed), 发放积分, 扣能量(未报名), 更新currentParticipants, PointsLog, 发放五维能量"| D5["📦 tasks + points_logs + energy_records"]:::data
+    end
 
-    A1 -.- R1
-    D1 -.- R2
-    D7 -.- R3
-    B2 -.- R4
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    A0 -.- P3
+    B0 -.- P4
+    B0 -.- P4b
+    C0 -.- P6
+    D0 -.- P2
 ```
 
-## 业务规则
+## 端点明细
 
-| 规则 | 说明 |
-|------|------|
-| **角色** | 活动由 `activity_admin`(活动管理员)管理,非规划师。`admin` 也可管理。 |
-| **替他人报名** | 家长可替多个孩子报名,每个报名需指定 childId |
-| **身份信息** | 报名时需填写参加人的信息(孩子信息) |
-| **价格分层** | `price` 普通价 vs `memberPrice` 会员价,不同级别用户不同价格 |
-| **人数限制** | `maxParticipants`=0/null 表示不限制人数 |
-| **报名截止** | `endTime` 即报名截止时间 |
-| **自动截止** | 达到 `maxParticipants` 或超过 `endTime` 自动停止报名 |
-| **签到** | 活动签到 `checkin`,可设置签到审核和签到积分 `checkinPoints` |
-| **反馈** | 活动结束后,已签到的参与者可提交反馈 |
+### 活动前台
 
-## 端点明细
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/activity/list` | 活动列表(支持维度/分页过滤) | 📱小程序 | `{dimensionCode, page, size}` | `{records: [ActivityDTO], total, page, size}` |
+| `POST /api/activity/detail` | 活动详情 | 📱小程序 | `{id}` | `ActivityDTO` |
+| `POST /api/activity/register` | 报名活动 | 📱小程序 | `{id, childId}` | `{registrationId, status}` |
+| `POST /api/activity/cancel-registration` | 取消报名 | 📱小程序 | `{id, childId}` | `null` |
+| `POST /api/activity/my-registrations` | 我的报名列表 | 📱小程序 | `{childId, page, size}` | `{records: [{activityTitle, status, ...}], total}` |
+| `POST /api/activity/checkin` | 活动签到 | 📱小程序 | `{id, childId}` | `{taskId, pointsEarned, alreadyCompleted, energyPenalty}` |
+| `POST /api/activity/create` | 创建活动(管理后台) | 🖥管理后台 | `Activity对象(全部字段)` | `ActivityDTO` |
+| `POST /api/activity/update` | 修改活动 | 🖥管理后台 | `Activity对象(含ID)` | `ActivityDTO` |
+| `POST /api/activity/publish` | 发布活动 | 🖥管理后台 | `{id}` | `"发布成功"` |
+| `POST /api/activity/end` | 结束活动 | 🖥管理后台 | `{id}` | `"活动已结束"` |
+
+### 活动管理后台(Admin)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/activity/list` | 活动管理列表(含草稿,支持过滤) | 🖥管理后台 | `{status, dimensionCode, auditStatus, page, size}` | `{records: [Activity], total}` |
+| `POST /api/admin/activity/detail` | 活动详情 | 🖥管理后台 | `{id}` | `Activity` |
+| `POST /api/admin/activity/submit-review` | 提交审核 | 🖥管理后台 | `{id}` | `"已提交审核"` |
+| `POST /api/admin/activity/audit` | 审核通过/驳回 | 🖥管理后台 | `{id, action, rejectReason}` | `"已审核"` |
+| `POST /api/admin/activity/review` | 审核活动(简版:发布/驳回删除) | 🖥管理后台 | `{id, action(publish/reject)}` | `"发布成功" / "已驳回并删除"` |
+| `POST /api/admin/activity/withdraw` | 撤回已发布活动 | 🖥管理后台 | `{id}` | `"已撤回"` |
+| `POST /api/admin/activity/re-draft` | 驳回后转草稿 | 🖥管理后台 | `{id}` | `"已转为草稿"` |
+| `POST /api/admin/activity/registration/list` | 报名列表 | 🖥管理后台 | `{activityId, status}` | `[{registrationId, childId, status, ...}]` |
+| `POST /api/admin/activity/registration/approve` | 审批报名通过 | 🖥管理后台 | `{id}` | `null` |
+| `POST /api/admin/activity/registration/reject` | 拒绝报名 | 🖥管理后台 | `{id}` | `null` |
+
+### 规划师端活动
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/activities/list` | 规划师活动列表 | 📋规划师端 | `{status}` | `[GuideActivity]` |
+| `POST /api/guide/activities/detail` | 规划师活动详情 | 📋规划师端 | `{activityId}` | `GuideActivity` |
+| `POST /api/guide/activities/create` | 创建活动 | 📋规划师端 | `GuideActivity对象(title, description, coverImage, category, location, activityDate, maxParticipants, price)` | `{id}` |
+| `POST /api/guide/activities/update` | 更新活动 | 📋规划师端 | `GuideActivity对象(含id及修改字段)` | `true` |
+| `POST /api/guide/activities/publish` | 发布活动 | 📋规划师端 | `{activityId}` | `true` |
+| `POST /api/guide/activities/cancel` | 取消活动 | 📋规划师端 | `{activityId}` | `true` |
+| `POST /api/guide/activities/delete` | 删除活动 | 📋规划师端 | `{activityId}` | `true` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖活动创建(规划师端+管理后台)、审核(提交→通过/驳回→转草稿/撤回)、用户报名、报名审批、签到全链路 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 签到时的未报名能量扣减已覆盖;人数已满自动截止由Service层校验;报名状态检查(已报名去重、活动未发布、无需报名等)在 Service 层处理 |
+| 3 | **端点覆盖** | ✅ 完整 | 20个端点全部映射到流程图中,与代码实际暴露的 `/api/activity/*`、`/api/admin/activity/*`、`/api/guide/activities/*` 一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 活动管理员(activity_admin/admin)、家长(parent)、孩子(child)、规划师(teacher)四种角色均已覆盖 |
+| 5 | **数据实体** | ✅ 完整 | activities表、guide_activities表、activity_registrations表、tasks表、points_logs表、energy_records表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(ActivityController、AdminActivityController、GuideActivityController)中的 `@PostMapping` 匹配 |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    Activity ||--o{ ActivityRegistration : "一个活动多个报名"
+    Activity ||--o{ Task : "签到生成任务"
+    GuideActivity ||--o{ GuideActivityRegistration : "规划师活动报名"
+
+    Activity {
+        Long id PK
+        string title
+        string description
+        string dimensionCode
+        string dimensionWeights "JSON维度权重"
+        string activityType "offline/online/campaign"
+        string status "draft/pending/rejected/published/withdrawn/ended"
+        string auditStatus
+        string auditReason
+        date startTime
+        date endTime
+        string location
+        int maxParticipants
+        int currentParticipants
+        int price "普通价(分)"
+        int memberPrice "会员价(分)"
+        int checkinPoints "签到积分"
+        int requireRegistration "是否需要报名"
+        int requireCheckinReview "签到需审核"
+        int energyPenaltyUnregistered "未报名签到扣减"
+        string visibility "public/restricted/member"
+    }
+
+    ActivityRegistration {
+        Long id PK
+        Long activityId FK
+        Long userId FK
+        Long childId FK
+        string status "pending/approved/rejected/cancelled"
+        date registeredAt
+        date approvedAt
+        Long approvedBy
+    }
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/activity/list` | 活动列表(支持维度过滤+分页) | 📱小程序 |
-| `/api/activity/detail` | 活动详情 | 📱小程序 |
-| `/api/activity/register` | 报名(activityId + childId) | 📱小程序 |
-| `/api/activity/cancel-registration` | 取消报名 | 📱小程序 |
-| `/api/activity/my-registrations` | 我的报名列表 | 📱小程序 |
-| `/api/activity/checkin` | 签到 | 📱小程序 |
-| `/api/activity/create` | 创建活动(需admin/activity_admin) | 🖥管理后台 |
-| `/api/activity/update` | 修改活动(需admin/activity_admin) | 🖥管理后台 |
-| `/api/activity/publish` | 发布活动 | 🖥管理后台 |
-| `/api/activity/end` | 结束活动 | 🖥管理后台 |
-| `/api/admin/activity/list` | 管理员活动列表 | 🖥管理后台 |
-| `/api/admin/activity/detail` | 活动详情 | 🖥管理后台 |
-| `/api/admin/activity/review` | 审核 | 🖥管理后台 |
-| `/api/admin/activity/submit-review` | 提交审核 | 🖥管理后台 |
-| `/api/admin/activity/audit` | 审批(通过/驳回) | 🖥管理后台 |
-| `/api/admin/activity/withdraw` | 撤回审核 | 🖥管理后台 |
-| `/api/admin/activity/re-draft` | 转草稿 | 🖥管理后台 |
-| `/api/admin/activity/registration/list` | 报名列表 | 🖥管理后台 |
-| `/api/admin/activity/registration/approve` | 审批报名通过 | 🖥管理后台 |
-| `/api/admin/activity/registration/reject` | 拒绝报名 | 🖥管理后台 |
+    GuideActivity {
+        Long id PK
+        Long guideId FK
+        string title
+        string description
+        string coverImage
+        string category
+        string location
+        date activityDate
+        int maxParticipants
+        int currentParticipants
+        Long price
+        string status "draft/published/cancelled/completed"
+    }
+```

+ 338 - 91
docs/flows/admin-overview-flow.md

@@ -1,119 +1,366 @@
 # 用户使用流程图 — 管理后台
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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(("🔧 管理员")):::portAdmin --> A2[🖥 发送验证码 /send-code]:::portAdmin
-        A2 --> A3[🖥 登录 /login]:::portAdmin
-        A3 --> A4[🖥 获取信息 /info]:::portAdmin
-        A4 --> A5[🖥 修改密码 /change-password]:::portAdmin
-        A5 --> A6[🖥 密码登录 /login-by-password]:::portAdmin
-    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 actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3
 
-    subgraph 用户管理
-        A6 --> B1[🖥 用户列表 /admin/users]:::portAdmin
-        B1 --> B2[🖥 创建用户 /admin/users/create]:::portAdmin
-        B2 --> B3[🖥 用户详情 /admin/users/:id]:::portAdmin
-        B3 --> B4[🖥 更新用户 /admin/users/:id/update]:::portAdmin
-        B4 --> B5[🖥 重置密码 /admin/users/:id/reset-password]:::portAdmin
-        B5 --> B6[🖥 搜索用户 /admin/user/search]:::portAdmin
-        B6 --> B7[🖥 删除用户 /admin/users/:id/delete]:::portAdmin
-    end
+    %% ============ 角色 ============
+    RP(("🔧 管理员")):::actor
 
-    subgraph 孩子管理
-        B7 --> C1[🖥 孩子列表 /admin/children]:::portAdmin
-        C1 --> C2[🖥 详情 /admin/children/:id]:::portAdmin
-        C2 --> C3[🖥 更新 /admin/children/:id/update]:::portAdmin
-        C3 --> C4[🖥 调整积分 /admin/children/:id/adjust-points]:::portAdmin
-    end
+    %% ================================================================
+    %% 阶段一:管理员认证
+    %% ================================================================
+    subgraph 阶段一[阶段一:管理员认证]
+        direction TB
+        P1["🏠 管理后台:登录页"]:::page
+        P1 -->|"发送验证码"| A1["🔗 POST /api/admin-auth/send-code"]:::api
+        A1 -->|"手机号"| S1["⚙️ VerificationCodeService.generateCode()"]:::service
+        S1 -->|"验证码, 过期时间"| D1["📦 sms_codes 表(写入)"]:::data
 
-    subgraph 家庭管理
-        C4 --> D1[🖥 家庭列表 /admin/families]:::portAdmin
-        D1 --> D2[🖥 详情 /admin/families/:id]:::portAdmin
-        D2 --> D3[🖥 成员 /admin/families/:id/members]:::portAdmin
-        D3 --> D4[🖥 更新 /admin/families/:id/update]:::portAdmin
-        D4 --> D5[🖥 删除 /admin/families/:id/delete]:::portAdmin
-    end
+        P1 -->|"验证码登录"| A2["🔗 POST /api/admin-auth/login"]:::api
+        A2 -->|"手机号, 验证码"| S2["⚙️ AdminAuthController.login()"]:::service
+        S2 -->|"用户信息"| D_USER["📦 users 表(查询)"]:::data
 
-    subgraph 任务审核
-        D5 --> E1[🖥 任务列表 /admin/tasks]:::portAdmin
-        E1 --> E2[🖥 任务统计 /admin/tasks/stats]:::portAdmin
-    end
+        P1 -->|"密码登录"| A2a["🔗 POST /api/admin-auth/login-by-password"]:::api
+        A2a -->|"手机号, 密码"| S2a["⚙️ 密码校验 + JWT生成"]:::service
+        S2a -->|"用户信息"| D_USER
 
-    subgraph 奖励审核
-        E2 --> F1[🖥 奖励列表 /admin/rewards]:::portAdmin
-        F1 --> F2[🖥 模板列表 /admin/rewards/templates]:::portAdmin
-        F2 --> F3[🖥 创建模板 /admin/rewards/create]:::portAdmin
-        F3 --> F4[🖥 审批 /admin/rewards/:id/approve]:::portAdmin
-    end
+        D_USER -->|"用户ID, 角色"| S_JWT["⚙️ JwtConfig.generateToken()"]:::service
+        S_JWT -->|"JWT token"| D_JWT["📦 JWT Token(返回前端)"]:::data
+
+        D_JWT -->|"token"| P2["🏠 管理后台:首页"]:::page
+        P2 -->|"获取管理员信息"| A3["🔗 POST /api/admin-auth/info"]:::api
+        A3 -->|"用户ID(token提取)"| S3["⚙️ 用户信息查询"]:::service
+        S3 -->|"管理员信息"| D_USER
 
-    subgraph 积分管理
-        F4 --> G1[🖥 积分日志 /admin/points/logs]:::portAdmin
-        G1 --> G2[🖥 积分统计 /admin/points/stats]:::portAdmin
+        P2 -->|"修改密码"| A4["🔗 POST /api/admin-auth/change-password"]:::api
+        A4 -->|"旧密码, 新密码"| S4["⚙️ UserService.setPassword()"]:::service
+        S4 -->|"更新密码字段"| D_USER
     end
 
-    subgraph 任务模板管理
-        G2 --> H1[🖥 模板列表 /admin/task-templates]:::portAdmin
-        H1 --> H2[🖥 创建 /admin/task-templates/create]:::portAdmin
+    %% ================================================================
+    %% 阶段二:用户与家庭管理
+    %% ================================================================
+    subgraph 阶段二[阶段二:用户与家庭管理]
+        P2 -->|"用户列表"| B1["🏠 管理后台:用户管理页"]:::page
+        B1 -->|"分页参数, 角色筛选"| A5["🔗 POST /api/admin/users"]:::api
+        A5 -->|"userId, role, page"| S5["⚙️ UserMapper.selectPage()"]:::service
+        S5 -->|"分页用户列表"| D_USER
+
+        B1 -->|"创建用户"| A6["🔗 POST /api/admin/users/create"]:::api
+        A6 -->|"手机号, 昵称, 角色"| S6["⚙️ 创建用户记录"]:::service
+        S6 -->|"新用户记录"| D_USER
+
+        B1 -->|"用户详情"| A7["🔗 POST /api/admin/users/{id}"]:::api
+        A7 -->|"用户ID"| S7["⚙️ UserMapper.selectById()"]:::service
+
+        B1 -->|"更新用户"| A8["🔗 POST /api/admin/users/{id}/update"]:::api
+        A8 -->|"用户ID, 更新字段"| S8["⚙️ UserMapper.updateById()"]:::service
+
+        B1 -->|"重置密码"| A9["🔗 POST /api/admin/users/{id}/reset-password"]:::api
+        A9 -->|"用户ID, 新密码"| S9["⚙️ UserService.resetPassword()"]:::service
+
+        B1 -->|"搜索用户"| A10["🔗 POST /api/admin/user/search"]:::api
+        A10 -->|"关键词"| S10["⚙️ 模糊搜索(nickname/phone/realName)"]:::service
+
+        B1 -->|"删除用户"| A11["🔗 POST /api/admin/users/{id}/delete"]:::api
+        A11 -->|"用户ID"| S11["⚙️ UserService.deleteUser()"]:::service
+
+        P2 -->|"孩子管理"| C1["🏠 管理后台:孩子管理页"]:::page
+        C1 -->|"分页"| A12["🔗 POST /api/admin/children"]:::api
+        C1 -->|"详情"| A13["🔗 POST /api/admin/children/{id}"]:::api
+        C1 -->|"更新"| A14["🔗 POST /api/admin/children/{id}/update"]:::api
+        C1 -->|"调整积分"| A15["🔗 POST /api/admin/children/{id}/adjust-points"]:::api
+        A15 -->|"孩子ID, 积分数额, 原因"| S15["⚙️ 积分调整 + PointsLog写入"]:::service
+        S15 -->|"更新余额, 写入流水"| D_POINTS["📦 family_members + points_logs"]:::data
+
+        P2 -->|"家庭管理"| D1["🏠 管理后台:家庭管理页"]:::page
+        D1 -->|"列表"| A16["🔗 POST /api/admin/families"]:::api
+        D1 -->|"详情"| A17["🔗 POST /api/admin/families/{id}"]:::api
+        D1 -->|"成员"| A18["🔗 POST /api/admin/families/{id}/members"]:::api
+        D1 -->|"更新"| A19["🔗 POST /api/admin/families/{id}/update"]:::api
+        D1 -->|"删除"| A20["🔗 POST /api/admin/families/{id}/delete"]:::api
+        A18 -->|"家庭ID"| S18["⚙️ 查询家长列表 + 孩子列表"]:::service
+        S18 -->|"家长+孩子数据"| D_FAMILY["📦 families + users + family_members"]:::data
     end
 
-    subgraph 规划师审核
-        H2 --> I1[🖥 待审批列表 /admin/guide/applications/pending]:::portAdmin
-        I1 --> I2[🖥 审批通过 /admin/guide/applications/:id/approve]:::portAdmin
-        I2 --> I3[🖥 驳回 /admin/guide/applications/:id/reject]:::portAdmin
-        I3 --> I4[🖥 列表 /admin/guide/guides]:::portAdmin
+    %% ================================================================
+    %% 阶段三:任务与奖励审核
+    %% ================================================================
+    subgraph 阶段三[阶段三:任务与奖励审核]
+        P2 -->|"任务列表"| E1["🏠 管理后台:任务管理页"]:::page
+        E1 -->|"分页, 状态筛选"| A21["🔗 POST /api/admin/tasks"]:::api
+        A21 -->|"page, status, familyId"| S21["⚙️ TaskMapper.selectPage()"]:::service
+        S21 -->|"分页任务列表"| D_TASK["📦 tasks 表"]:::data
+        E1 -->|"任务统计"| A22["🔗 POST /api/admin/tasks/stats"]:::api
+        A22 -->|""| S22["⚙️ 任务总数 + 今日任务数"]:::service
+
+        P2 -->|"奖励列表"| F1["🏠 管理后台:奖励管理页"]:::page
+        F1 -->|"分页, 状态"| A23["🔗 POST /api/admin/rewards"]:::api
+        F1 -->|"模板列表"| A24["🔗 POST /api/admin/rewards/templates"]:::api
+        F1 -->|"创建模板"| A25["🔗 POST /api/admin/rewards/create"]:::api
+        F1 -->|"审批通过/拒绝"| A26["🔗 POST /api/admin/rewards/{id}/approve"]:::api
+        A26 -->|"奖励ID, approved标志"| S26["⚙️ 状态更新 + 积分退还(拒绝时)"]:::service
+        S26 -->|"更新奖励状态, 退积分"| D_TASK
     end
 
-    subgraph 商品审核
-        I4 --> J1[🖥 商品列表 /admin/product/list]:::portAdmin
-        J1 --> J2[🖥 审核商品 /admin/product/review]:::portAdmin
-        J2 --> J3[🖥 上下架 /admin/product/shelve]:::portAdmin
+    %% ================================================================
+    %% 阶段四:积分与模板管理
+    %% ================================================================
+    subgraph 阶段四[阶段四:积分与模板管理]
+        P2 -->|"积分日志"| G1["🏠 管理后台:积分管理页"]:::page
+        G1 -->|"分页, 孩子ID, 类型"| A27["🔗 POST /api/admin/points/logs"]:::api
+        A27 -->|"childId, type, page"| S27["⚙️ PointsLogMapper.selectPage()"]:::service
+        S27 -->|"分页积分流水"| D_POINTS
+        G1 -->|"积分统计"| A28["🔗 POST /api/admin/points/stats"]:::api
+        A28 -->|""| S28["⚙️ 孩子总数统计"]:::service
+
+        P2 -->|"任务模板"| H1["🏠 管理后台:任务模板页"]:::page
+        H1 -->|"列表"| A29["🔗 POST /api/admin/task-templates"]:::api
+        H1 -->|"详情"| A30["🔗 POST /api/admin/task-templates/{id}"]:::api
+        H1 -->|"创建"| A31["🔗 POST /api/admin/task-templates/create"]:::api
+        H1 -->|"更新"| A32["🔗 POST /api/admin/task-templates/{id}/update"]:::api
+        H1 -->|"删除"| A33["🔗 POST /api/admin/task-templates/{id}/delete"]:::api
+        A31 -->|"模板内容"| S31["⚙️ TaskTemplateMapper.insert()"]:::service
+        S31 -->|"新模板记录"| D_TTPL["📦 task_templates 表"]:::data
     end
 
-    subgraph 订单管理
-        J3 --> K1[🖥 订单列表 /admin/product/order/list]:::portAdmin
-        K1 --> K2[🖥 发货 /admin/product/order/ship]:::portAdmin
-        K2 --> K3[🖥 退款审核 /admin/product/order/refund/approve]:::portAdmin
+    %% ================================================================
+    %% 阶段五:规划师审核与套餐
+    %% ================================================================
+    subgraph 阶段五[阶段五:规划师审核与套餐]
+        P2 -->|"规划师审核"| I1["🏠 管理后台:规划师审核页"]:::page
+        I1 -->|"待审批列表"| A34["🔗 POST /api/admin/guide/applications"]:::api
+        I1 -->|"待审批数量"| A34a["🔗 POST /api/admin/guide/pending-count"]:::api
+        I1 -->|"通过"| A35["🔗 POST /api/admin/guide/approve/{userId}"]:::api
+        I1 -->|"驳回"| A36["🔗 POST /api/admin/guide/reject/{userId}"]:::api
+        A35 -->|"用户ID"| S35["⚙️ 更新user角色 + 创建admins记录"]:::service
+        S35 -->|"更新users表, 插入admins表"| D_USER
+
+        I1 -->|"规划师列表"| A37["🔗 POST /api/admin/guide/guides"]:::api
+        I1 -->|"等级筛选"| A38["🔗 POST /api/admin/guide/guides/level/{level}"]:::api
+
+        P2 -->|"套餐管理"| I2["🏠 管理后台:套餐管理页"]:::page
+        I2 -->|"套餐列表"| A39["🔗 POST /api/admin/guide/packages"]:::api
+        I2 -->|"创建套餐"| A40["🔗 POST /api/admin/guide/packages/create"]:::api
+        I2 -->|"更新"| A41["🔗 POST /api/admin/guide/packages/{id}/update"]:::api
+        I2 -->|"状态"| A42["🔗 POST /api/admin/guide/packages/{id}/status"]:::api
+        A40 -->|"套餐内容"| S40["⚙️ GuidePackageService.save()"]:::service
+        S40 -->|"新套餐记录"| D_GPKG["📦 guide_packages 表"]:::data
+
+        P2 -->|"营养师审核"| I3["🏠 管理后台:营养师审核页"]:::page
+        I3 -->|"列表"| A43["🔗 POST /api/admin/nutritionist/applications"]:::api
+        I3 -->|"通过"| A44["🔗 POST /api/admin/nutritionist/approve/{userId}"]:::api
+        I3 -->|"驳回"| A45["🔗 POST /api/admin/nutritionist/reject/{userId}"]:::api
     end
 
-    subgraph 系统管理
-        K3 --> L1[⚙️ 健康检查 /system/health]:::portSystem
+    %% ================================================================
+    %% 阶段六:商品与订单
+    %% ================================================================
+    subgraph 阶段六[阶段六:商品与订单管理]
+        P2 -->|"商品管理"| J1["🏠 管理后台:商品管理页"]:::page
+        J1 -->|"列表"| A46["🔗 POST /api/admin/product/list"]:::api
+        J1 -->|"审核"| A47["🔗 POST /api/admin/product/review"]:::api
+        J1 -->|"上下架"| A48["🔗 POST /api/admin/product/shelve"]:::api
+        J1 -->|"创建"| A49["🔗 POST /api/admin/product/create"]:::api
+        J1 -->|"更新"| A50["🔗 POST /api/admin/product/update"]:::api
+        J1 -->|"删除"| A51["🔗 POST /api/admin/product/delete"]:::api
+        A47 -->|"productId, action"| S47["⚙️ ProductService.review()"]:::service
+        S47 -->|"更新审核状态"| D_PROD["📦 products 表"]:::data
+
+        P2 -->|"订单管理"| K1["🏠 管理后台:订单管理页"]:::page
+        K1 -->|"列表"| A52["🔗 POST /api/admin/product/order/list"]:::api
+        K1 -->|"详情"| A53["🔗 POST /api/admin/product/order/detail"]:::api
+        K1 -->|"发货"| A54["🔗 POST /api/admin/product/order/ship"]:::api
+        K1 -->|"退款审核"| A55["🔗 POST /api/admin/product/order/refund/approve"]:::api
+        K1 -->|"关闭订单"| A56["🔗 POST /api/admin/product/order/close"]:::api
+        A54 -->|"orderNo, trackingNumber, expressCompany"| S54["⚙️ ProductOrderService.ship()"]:::service
+        S54 -->|"更新发货状态"| D_ORDER["📦 product_orders 表"]:::data
     end
 
-    R1(("🔧 管理员")):::actor
-    R2(("📊 统计系统")):::system
+    %% ================================================================
+    %% 阶段七:系统配置
+    %% ================================================================
+    subgraph 阶段七[阶段七:系统配置]
+        P2 -->|"食材管理"| L1["🏠 管理后台:食材管理页"]:::page
+        L1 -->|"CRUD"| A57["🔗 POST /api/admin/foods/*"]:::api
+        A57 -->|"食材数据"| S57["⚙️ FoodService CRUD"]:::service
+        S57 -->|"食材记录"| D_FOOD["📦 foods 表"]:::data
+
+        P2 -->|"能量配置"| L2["🏠 管理后台:五维能量配置页"]:::page
+        L2 -->|"来源列表"| A58["🔗 POST /api/admin/energy-config/source-list"]:::api
+        A58 -->|""| S58["⚙️ 查询能量来源配置"]:::service
+        S58 -->|"能量来源配置列表"| D_ENERGY["📦 energy_source_config 表"]:::data
+
+        P2 -->|"会员管理"| L3["🏠 管理后台:会员管理页"]:::page
+        L3 -->|"等级列表"| A59["🔗 POST /api/admin/membership/levels"]:::api
+        L3 -->|"概览"| A60["🔗 POST /api/admin/membership/overview"]:::api
+
+        P2 -->|"测评订单"| L4["🏠 管理后台:测评管理页"]:::page
+        L4 -->|"待分配列表"| A61["🔗 POST /api/admin/assessment/pending-list"]:::api
+        L4 -->|"可用规划师"| A62["🔗 POST /api/admin/assessment/available-guides"]:::api
+        L4 -->|"订单列表"| A63["🔗 POST /api/admin/assessment/orders"]:::api
+        L4 -->|"分配规划师"| A64["🔗 POST /api/admin/assessment/assign-guide"]:::api
+    end
 
-    A1 -.- R1
-    E2 -.- R2
+    RP -.- P1
+    RP -.- P2
 ```
 
-## 主要管理端点
-
-| 领域 | 端点示例 | 说明 | 端口 |
-|------|----------|------|------|
-| 认证 | `/api/admin-auth/login` | 管理员登录 | 🖥管理后台 |
-| 用户 | `/api/admin/users` | 用户管理 | 🖥管理后台 |
-| 孩子 | `/api/admin/children` | 孩子管理 | 🖥管理后台 |
-| 家庭 | `/api/admin/families` | 家庭管理 | 🖥管理后台 |
-| 任务 | `/api/admin/tasks` | 任务管理 | 🖥管理后台 |
-| 奖励 | `/api/admin/rewards` | 奖励审批 | 🖥管理后台 |
-| 积分 | `/api/admin/points/logs` | 积分管理 | 🖥管理后台 |
-| 模板 | `/api/admin/task-templates` | 任务模板 | 🖥管理后台 |
-| 规划师 | `/api/admin/guide/applications/pending` | 规划师审批 | 🖥管理后台 |
-| 商品 | `/api/admin/product/review` | 商品审核 | 🖥管理后台 |
-| 订单 | `/api/admin/product/order/list` | 订单管理 | 🖥管理后台 |
-| 健康 | `/api/system/health` | 运行状态 | ⚙️系统自动 |
+## 端点明细
+
+### 管理员认证
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin-auth/send-code` | 发送管理员登录验证码 | 🖥管理后台 | `{phone}` | `{success}` |
+| `POST /api/admin-auth/login` | 验证码登录 | 🖥管理后台 | `{phone, code}` | `{token, adminId, username, role, roles}` |
+| `POST /api/admin-auth/login-by-password` | 密码登录 | 🖥管理后台 | `{phone, password}` | `{token, adminId, username, role, roles}` |
+| `POST /api/admin-auth/info` | 获取当前管理员信息 | 🖥管理后台 | Header: `Authorization` | `{id, nickname, phone, role, roles, user}` |
+| `POST /api/admin-auth/change-password` | 修改密码 | 🖥管理后台 | `{oldPassword, newPassword}` | `{success}` |
+| `POST /api/admin-auth/update-info` | 更新个人信息 | 🖥管理后台 | `{nickname, phone}` | `{nickname, phone}` |
+| `POST /api/admin-auth/reset-password` | 验证码重置密码 | 🖥管理后台 | `{phone, code, newPassword}` | `{success}` |
+
+### 用户管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/users` | 用户分页列表 | 🖥管理后台 | `{page, size, role, nickname, phone}` | `Page<User>` |
+| `POST /api/admin/users/create` | 创建用户 | 🖥管理后台 | `{phone, nickname, role, realName}` | `User` |
+| `POST /api/admin/users/{id}` | 用户详情 | 🖥管理后台 | path: `id` | `User` |
+| `POST /api/admin/users/{id}/update` | 更新用户 | 🖥管理后台 | path: `id`, body: `User字段` | `{success}` |
+| `POST /api/admin/users/{id}/reset-password` | 重置用户密码 | 🖥管理后台 | path: `id`, body: `{password}` | `{success}` |
+| `POST /api/admin/user/search` | 搜索用户(下拉选择用) | 🖥管理后台 | `{keyword}` | `List<User>` |
+| `POST /api/admin/users/{id}/delete` | 删除用户 | 🖥管理后台 | path: `id` | `{success}` |
+
+### 孩子管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/children` | 孩子分页列表 | 🖥管理后台 | `{page, size}` | `Page<FamilyMember>` |
+| `POST /api/admin/children/{id}` | 孩子详情 | 🖥管理后台 | path: `id` | `FamilyMember` |
+| `POST /api/admin/children/{id}/update` | 更新孩子信息 | 🖥管理后台 | path: `id`, body: `FamilyMember字段` | `{success}` |
+| `POST /api/admin/children/{id}/adjust-points` | 手动调整孩子积分 | 🖥管理后台 | path: `id`, body: `{amount, reason}` | `{newBalance}` |
+
+### 家庭管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/families` | 家庭分页列表 | 🖥管理后台 | `{page, size, name}` | `Page<Family>` |
+| `POST /api/admin/families/{id}` | 家庭详情 | 🖥管理后台 | path: `id` | `Family` |
+| `POST /api/admin/families/{id}/members` | 家庭成员详情(含家长+孩子) | 🖥管理后台 | path: `id` | `{family, parents, children}` |
+| `POST /api/admin/families/{id}/update` | 更新家庭信息 | 🖥管理后台 | path: `id`, body: `Family字段` | `{success}` |
+| `POST /api/admin/families/{id}/delete` | 删除家庭 | 🖥管理后台 | path: `id` | `{success}` |
+
+### 任务管理与奖励
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/tasks` | 任务分页列表 | 🖥管理后台 | `{page, size, status, familyId}` | `Page<Task>` |
+| `POST /api/admin/tasks/stats` | 任务统计 | 🖥管理后台 | — | `{total, today}` |
+| `POST /api/admin/rewards` | 奖励分页列表 | 🖥管理后台 | `{page, size, status, familyId}` | `Page<Reward>` |
+| `POST /api/admin/rewards/templates` | 获取奖励模板列表 | 🖥管理后台 | — | `List<Reward>` |
+| `POST /api/admin/rewards/create` | 创建奖励模板 | 🖥管理后台 | `Reward字段` | `{id}` |
+| `POST /api/admin/rewards/{id}/approve` | 审批奖励兑换 | 🖥管理后台 | path: `id`, body: `{approved}` | `{success}` |
+
+### 积分管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/points/logs` | 积分日志分页 | 🖥管理后台 | `{page, size, childId, type}` | `Page<PointsLog>` |
+| `POST /api/admin/points/stats` | 积分统计概览 | 🖥管理后台 | — | `{totalChildren}` |
+
+### 任务模板管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/task-templates` | 模板分页列表 | 🖥管理后台 | `{page, size, category, difficulty, isActive}` | `Page<TaskTemplate>` |
+| `POST /api/admin/task-templates/{id}` | 模板详情 | 🖥管理后台 | path: `id` | `TaskTemplate` |
+| `POST /api/admin/task-templates/create` | 创建模板 | 🖥管理后台 | `TaskTemplate字段` | `{id}` |
+| `POST /api/admin/task-templates/{id}/update` | 更新模板 | 🖥管理后台 | path: `id`, body: `TaskTemplate字段` | `{success}` |
+| `POST /api/admin/task-templates/{id}/delete` | 删除模板 | 🖥管理后台 | path: `id` | `{success}` |
+
+### 规划师审核
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/guide/applications` | 规划师申请列表 | 🖥管理后台 | `{page, size, status}` | `Page<User>` |
+| `POST /api/admin/guide/applications/pending` | 待审批申请列表 | 🖥管理后台 | — | `List<GuideApplication>` |
+| `POST /api/admin/guide/approve/{userId}` | 通过规划师审核 | 🖥管理后台 | path: `userId` | `{success}` |
+| `POST /api/admin/guide/reject/{userId}` | 驳回规划师审核 | 🖥管理后台 | path: `userId`, body: `{reason}` | `{success}` |
+| `POST /api/admin/guide/pending-count` | 待审核数量 | 🖥管理后台 | — | `{count}` |
+| `POST /api/admin/guide/applications/{id}/approve` | 通过申请(AdminGuideController) | 🖥管理后台 | path: `id`, param: `adminId` | `{success}` |
+| `POST /api/admin/guide/applications/{id}/reject` | 驳回申请 | 🖥管理后台 | path: `id`, param: `adminId, reason` | `{success}` |
+| `POST /api/admin/guide/guides` | 规划师列表 | 🖥管理后台 | — | `List<Guide>` |
+| `POST /api/admin/guide/guides/level/{level}` | 按等级筛选规划师 | 🖥管理后台 | path: `level` | `List<Guide>` |
+
+### 套餐与商品管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/guide/packages` | 套餐列表 | 🖥管理后台 | — | `List<GuidePackage>` |
+| `POST /api/admin/guide/packages/create` | 创建套餐 | 🖥管理后台 | `GuidePackage字段` | `{success}` |
+| `POST /api/admin/guide/packages/{id}/update` | 更新套餐 | 🖥管理后台 | path: `id`, body: `GuidePackage字段` | `{success}` |
+| `POST /api/admin/guide/packages/{id}/status` | 更新套餐状态 | 🖥管理后台 | path: `id`, param: `status` | `{success}` |
+| `POST /api/admin/guide/packages/pending` | 待审核套餐数量 | 🖥管理后台 | — | `{count}` |
+| `POST /api/admin/product/list` | 商品分页列表 | 🖥管理后台 | `{page, size, status, productType, keyword}` | `{records, total}` |
+| `POST /api/admin/product/review` | 审核商品(通过/驳回) | 🖥管理后台 | `{productId, action, reason}` | `Result` |
+| `POST /api/admin/product/shelve` | 商品上下架 | 🖥管理后台 | `{productId, shelve}` | `Result` |
+| `POST /api/admin/product/create` | 创建商品 | 🖥管理后台 | `ProductCreateRequest` | `ProductDTO` |
+| `POST /api/admin/product/update` | 更新商品 | 🖥管理后台 | `ProductCreateRequest` | `ProductDTO` |
+| `POST /api/admin/product/delete` | 删除商品 | 🖥管理后台 | `{productId}` | `Result` |
+| `POST /api/admin/product/detail` | 商品详情 | 🖥管理后台 | `{productId}` | `ProductDTO` |
+
+### 订单管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/product/order/list` | 订单分页列表 | 🖥管理后台 | `{page, size, status, keyword, startDate, endDate}` | `{records, total}` |
+| `POST /api/admin/product/order/detail` | 订单详情 | 🖥管理后台 | `{orderNo}` | `ProductOrderDTO` |
+| `POST /api/admin/product/order/ship` | 订单发货 | 🖥管理后台 | `{orderNo, trackingNumber, expressCompany}` | `Result` |
+| `POST /api/admin/product/order/close` | 关闭订单 | 🖥管理后台 | `{orderNo}` | `Result` |
+| `POST /api/admin/product/order/refund/approve` | 退款审核通过 | 🖥管理后台 | `{orderNo}` | `Result` |
+| `POST /api/admin/product/order/refund/reject` | 退款审核拒绝 | 🖥管理后台 | `{orderNo}` | `Result` |
+
+### 系统配置
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/foods/list` | 食材列表 | 🖥管理后台 | `{category}` | `List<Map>` |
+| `POST /api/admin/foods/create` | 新增食材 | 🖥管理后台 | `Food字段` | `Food` |
+| `POST /api/admin/foods/update` | 更新食材 | 🖥管理后台 | `Food字段` | `{success}` |
+| `POST /api/admin/foods/delete` | 删除食材 | 🖥管理后台 | `{id}` | `{success}` |
+| `POST /api/admin/foods/detail` | 食材详情(含应季月份) | 🖥管理后台 | `{id}` | `Map` |
+| `POST /api/admin/foods/saveMonths` | 保存应季月份 | 🖥管理后台 | `{id, months}` | `{success}` |
+| `POST /api/admin/energy-config/source-list` | 能量来源配置列表 | 🖥管理后台 | — | `List<Map>` |
+| `POST /api/admin/membership/levels` | 会员等级列表 | 🖥管理后台 | — | `List<MembershipLevel>` |
+| `POST /api/admin/membership/overview` | 会员概览统计 | 🖥管理后台 | — | `{freeCount, familyCount, providerCount, ...}` |
+| `POST /api/admin/membership/upgrade-records` | 会员升级记录 | 🖥管理后台 | `{page, size}` | `Page<MemberUpgradeRecord>` |
+| `POST /api/admin/assessment/pending-list` | 待分配规划师的测评列表 | 🖥管理后台 | `{page, size}` | `{records, total}` |
+| `POST /api/admin/assessment/available-guides` | 可选规划师列表 | 🖥管理后台 | — | `List<Map>` |
+| `POST /api/admin/assessment/orders` | 测评订单列表 | 🖥管理后台 | `{page, size, status, keyword}` | `{records, total}` |
+| `POST /api/admin/assessment/assign-guide` | 分配规划师 | 🖥管理后台 | `{appointmentId, guideId}` | `null` |
+| `POST /api/admin/assessment/change-guide` | 更换规划师 | 🖥管理后台 | `{orderId, guideId}` | `null` |
+| `POST /api/admin/nutritionist/applications` | 营养师申请列表 | 🖥管理后台 | `{page, size, status}` | `Page<User>` |
+| `POST /api/admin/nutritionist/approve/{userId}` | 通过营养师审核 | 🖥管理后台 | path: `userId` | `{success}` |
+| `POST /api/admin/nutritionist/reject/{userId}` | 驳回营养师审核 | 🖥管理后台 | path: `userId`, body: `{reason}` | `{success}` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖管理员认证、用户/孩子/家庭管理、任务/奖励审核、积分/模板管理、规划师/营养师审核、商品/订单管理、系统配置共7个阶段 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | Token过期引导重新登录已覆盖;验证码错误、密码错误、重复手机号等在Service层处理,前端已有提示 |
+| 3 | **端点覆盖** | ✅ 完整 | 52+个端点全部映射到流程图中,涵盖AdminAuthController、AdminController、AdminGuideController、AdminProductController、AdminProductOrderController、AdminFoodController、AdminEnergyConfigController |
+| 4 | **角色覆盖** | ✅ 完整 | 管理员(admin)全量管理功能覆盖;规划师(teacher)审核等跨角色操作已标注 |
+| 5 | **数据实体** | ✅ 完整 | users、family_members、families、tasks、rewards、points_logs、task_templates、guide_packages、products、product_orders、foods、admins等表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配,无重复路由 |

+ 265 - 65
docs/flows/ai-assistant-flow.md

@@ -1,88 +1,288 @@
 # 用户使用流程图 — AI助手
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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 AI聊天
-        A1(("👤 用户")):::portMiniApp --> A2[📱 发送聊天消息 /chat/send]:::portMiniApp
-        A2 --> A3{📱 消息类型}:::portMiniApp
-        A3 -->|普通咨询| A4[⚙️ Dify AI 响应]:::portSystem
-        A3 -->|报告解读| A5[📱 传入reportId]:::portMiniApp
-        A5 --> A6[⚙️ AI解读健康报告指标]:::portSystem
-        A4 --> A7[📱 返回AI回答]:::portMiniApp
-        A6 --> A7
-    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
+
+    %% ============ 角色 ============
+    ROLE_USER(("👤 用户(家长/孩子)")):::actor
+    ROLE_DIFY(("🤖 Dify AI引擎")):::external
+    ROLE_LG(("🐍 LangGraph Python")):::external
+
+    %% ================================================================
+    %% 阶段一:AI对话
+    %% ================================================================
+    subgraph 阶段一[阶段一:AI对话]
+        direction TB
+
+        P1["🏠 小程序:AI聊天页"]:::page
+        P1 -->|"输入消息"| P1a["🏠 消息输入框"]:::page
+        P1a -->|"query, conversationId, reportId, surveyId"| A1["🔗 POST /api/ai/chat/send"]:::api
+        A1 -->|"userId, query, conversationId, inputs"| S1{"⚙️ AIService.sendMessage()<br>优先LangGraph → 回退Dify"}:::service
+
+        S1 -->|"query, userId, conversationId"| LG1["⚙️ AiGateway.chat()<br>Python推荐服务"]:::service
+        LG1 -->|"超时/熔断回退"| DIFY1["⚙️ Dify Chatbot API<br>/chat-messages"]:::service
+        DIFY1 -->|"answer, conversation_id"| LG1
+
+        S1 -->|"解析[TASK]标记"| S1a["⚙️ TaskParseService.parseTasks()"]:::service
+        S1a -->|"任务标题, 维度, 奖励"| S1b["⚙️ GrowthTaskService.createDynamicTask()"]:::service
+        S1b -->|"写入动态成长任务"| D_TASKS["📦 growth_tasks 表"]:::data
 
-    subgraph 会话管理
-        A7 --> B1[📱 获取会话列表 /chat/conversations]:::portMiniApp
-        B1 --> B2[📱 获取消息历史 /chat/messages]:::portMiniApp
-        B2 --> B3[📱 删除会话 /chat/conversations/:id/delete]:::portMiniApp
+        S1 -->|"镜像会话到本地"| S1c["⚙️ ChatMirrorService.upsertConversation()"]:::service
+        S1c -->|"userId, difyConversationId, 消息"| D_CHAT["📦 chat_conversations + chat_messages"]:::data
+
+        S1 -->|"构建家庭上下文输入"| S2["⚙️ FamilyContextService.buildContext()"]:::service
+        S2 -->|"用户信息, 孩子列表, 健康报告, 任务统计"| D_CTX["📦 User, ChildInfoDTO, HealthReport<br>(内存组装)"]:::data
+
+        S1 -->|"注入AI记忆层"| S2a["⚙️ AIService.enrichInputsWithMemory()"]:::service
+        S2a -->|"最近3条会话摘要"| D_SUM["📦 ai_conversation_summaries 表"]:::data
+        S2a -->|"关键事实列表"| D_FACT["📦 ai_user_facts 表"]:::data
+
+        A1 -->|"answer, conversationId, tasks[]"| P1b["🏠 显示AI回答 + 推荐任务卡片"]:::page
     end
 
-    subgraph AI营养分析
-        B3 --> C1[📱 发送营养分析 /nutrition/send]:::portMiniApp
-        C1 --> C2[⚙️ 基于菌群报告]:::portSystem
-        C2 --> C3[📱 AI生成营养建议]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:会话管理
+    %% ================================================================
+    subgraph 阶段二[阶段二:会话管理]
+        P1b -->|"查看历史"| P2["🏠 会话列表页"]:::page
+        P2 -->|"userId"| A2["🔗 POST /api/ai/chat/conversations"]:::api
+        A2 -->|"调用Dify GET /conversations"| S3["⚙️ AIService.getConversations()"]:::service
+        S3 -->|"Dify失败回退本地"| S3a["⚙️ ChatMirrorService.getConversations()"]:::service
+        S3a -->|"本地镜像会话"| D_CHAT
+
+        P2 -->|"选择会话"| P2a["🏠 消息历史页"]:::page
+        P2a -->|"conversationId"| A3["🔗 POST /api/ai/chat/messages"]:::api
+        A3 -->|"调用Dify GET /messages"| S4["⚙️ AIService.getMessages()"]:::service
+        S4 -->|"Dify失败回退本地"| S4a["⚙️ ChatMirrorService.getMessages()"]:::service
+        S4a -->|"本地消息记录"| D_CHAT
+
+        P2a -->|"删除会话"| A4["🔗 POST /api/ai/chat/conversations/{id}/delete"]:::api
+        A4 -->|"调用Dify DELETE /conversations/{id}"| S5["⚙️ AIService.deleteConversation()"]:::service
     end
 
-    subgraph AI管家
-        C3 --> D1[📱 创建新会话 /sessions/create]:::portMiniApp
-        D1 --> D2[📱 更新Dify会话ID /sessions/update-conversation]:::portMiniApp
-        D2 --> D3[📱 归档会话 /sessions/archive]:::portMiniApp
-        D3 --> D4[📱 获取会话列表 /sessions/list]:::portMiniApp
-        D4 --> D5[📱 会话详情 /sessions/detail]:::portMiniApp
-        D5 --> D6[📱 删除会话 /sessions/delete]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:精准营养分析
+    %% ================================================================
+    subgraph 阶段三[阶段三:精准营养分析]
+        P1b -->|"报告ID参数"| P3["🏠 营养分析对话页"]:::page
+        P3 -->|"query, conversationId, reportId"| A5["🔗 POST /api/ai/nutrition/send"]:::api
+        A5 -->|"reportId"| S6["⚙️ HealthAnalysisService.analyze()"]:::service
+        S6 -->|"菌群分析结果"| D_HR["📦 HealthReport 肠道报告数据"]:::data
+
+        S6 -->|"分析结果 + 家庭上下文"| S7["⚙️ AIService.sendNutritionMessage()"]:::service
+        S7 -->|"专用dify.nutrition-api-key"| DIFY2["⚙️ Dify精准营养助手<br>/chat-messages"]:::external
+
+        A5 -->|"解析[RECOMMEND]标记"| S7a["⚙️ 解析推荐标签 tags/types/limit"]:::service
+        S7a -->|"营养标签, 类型筛选"| S7b["⚙️ RecommendationService.search()"]:::service
+        S7b -->|"Product/Activity/Article多表搜索"| D_PROD["📦 products, activities, articles 表"]:::data
+
+        A5 -->|"解析[TASK]标记"| S7c["⚙️ TaskParseService + GrowthTaskService"]:::service
+        S7c -->|"动态成长任务"| D_TASKS
+
+        A5 -->|"answer, recommendations[], tasks[]"| P3a["🏠 显示营养建议 + 推荐内容"]:::page
     end
 
-    subgraph AI上下文
-        D6 --> E1[📱 供LangGraph调用的上下文 /api/ai/context]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:智能推荐
+    %% ================================================================
+    subgraph 阶段四[阶段四:智能推荐]
+        P3a -->|"搜索推荐"| P4["🏠 营养推荐搜索页"]:::page
+        P4 -->|"nutritionTags, types, limit"| A6["🔗 POST /api/recommend/search"]:::api
+        A6 -->|"5%灰度→LangGraph"| S8["⚙️ AiGateway.recommend()"]:::service
+        S8 -->|"Python推荐服务"| LG2["🐍 LangGraph推荐API"]:::external
+        A6 -->|"本地搜索"| S9["⚙️ RecommendationService.search()"]:::service
+        S9 -->|"按标签模糊搜索上架商品"| D_PROD
+        S9 -->|"按标签搜索进行中活动"| D_ACT["📦 activities 表"]:::data
+        S9 -->|"按标签搜索已发布文章"| D_ART["📦 articles 表"]:::data
+
+        P4 -->|"复购提醒"| P4a["🏠 复购提醒列表"]:::page
+        P4a -->|"userId"| A7["🔗 POST /api/recommend/repurchase-reminders"]:::api
+        A7 -->|"userId"| S10["⚙️ RecommendationService.getRepurchaseReminders()"]:::service
+        S10 -->|"未购买提醒记录"| D_REP["📦 repurchase_reminder_record 表"]:::data
+
+        P4a -->|"点击提醒"| A8["🔗 POST /api/recommend/repurchase-reminder/{id}/click"]:::api
+        A8 -->|"reminderId"| S11["⚙️ RecommendationService.markRepurchaseClicked()"]:::service
+        S11 -->|"更新clicked=1"| D_REP
     end
 
-    subgraph AI推荐
-        E1 --> F1[📱 按标签搜索推荐 /recommend/search]:::portMiniApp
-        F1 --> F2[📱 获取复购提醒 /recommend/repurchase-reminders]:::portMiniApp
-        F2 --> F3[📱 标记提醒已点击 /repurchase-reminder/:id/click]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:饮食推荐
+    %% ================================================================
+    subgraph 阶段五[阶段五:饮食推荐]
+        P1b -->|"饮食推荐"| P5["🏠 食谱推荐页"]:::page
+        P5 -->|"mealType, conversationId"| A9["🔗 POST /api/meal/recommend"]:::api
+        A9 -->|"userId"| S12["⚙️ MealRecommendService.aggregateContext()"]:::service
+        S12 -->|"候选食材 + 营养摘要"| D_FOOD["📦 foods, recipes 表"]:::data
+
+        S12 -->|"inputs"| S13["⚙️ AIService.sendNutritionMessage()"]:::service
+        S13 -->|"Dify营养助手"| DIFY2
+
+        A9 -->|"answer, replaceOptions, nutritionSummary"| P5a["🏠 展示AI生成食谱"]:::page
+
+        P5a -->|"替换食材"| A10["🔗 POST /api/meal/replace"]:::api
+        A10 -->|"foodId, userId"| S14["⚙️ MealRecommendService.findReplaceCandidate()"]:::service
+        S14 -->|"同类替代食材"| D_FOOD
+
+        P5a -->|"记录饮食"| A11["🔗 POST /api/meal/log"]:::api
+        A11 -->|"userId, childId, mealType, foods, note"| S15["⚙️ MealLogService.create()"]:::service
+        S15 -->|"写入饮食记录"| D_LOG["📦 meal_logs 表"]:::data
+
+        P5a -->|"查看近期饮食"| A12["🔗 POST /api/meal/logs"]:::api
+        A12 -->|"userId, days"| S16["⚙️ MealLogService.getRecentMeals()"]:::service
+        S16 -->|"近N天饮食记录"| D_LOG
+
+        P5a -->|"营养摄入统计"| A13["🔗 POST /api/meal/nutrition-summary"]:::api
     end
 
-    R1(("👤 用户")):::actor
-    R2(("🤖 Dify AI引擎")):::system
+    %% ================================================================
+    %% 阶段六:AI上下文
+    %% ================================================================
+    subgraph 阶段六[阶段六:AI上下文与知识库]
+        A13 -->|"intentType, params"| A14["🔗 POST /api/ai/context"]:::api
+        A14 -->|"意图: health_report / task_progress / child_info / emotion_status / user_facts"| S17["⚙️ AiContextService.getContext()"]:::service
+        S17 -->|"健康报告"| D_HR
+        S17 -->|"任务进度"| D_TASKS
+        S17 -->|"孩子信息"| D_CHILD["📦 User(孩子角色)"]:::data
+        S17 -->|"情绪打卡"| D_EMO["📦 emotion_checkins 表"]:::data
+        S17 -->|"会话摘要Layer1"| D_SUM
+        S17 -->|"用户事实Layer2"| D_FACT
+    end
 
-    A1 -.- R1
-    A4 -.- R2
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_USER -.- P1
+    ROLE_USER -.- P3
+    ROLE_USER -.- P4
+    ROLE_USER -.- P5
+    ROLE_DIFY -.- DIFY1
+    ROLE_DIFY -.- DIFY2
+    ROLE_LG -.- LG1
+    ROLE_LG -.- LG2
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/ai/chat/send` | 发送聊天消息 | 📱小程序 |
-| `/api/ai/chat/conversations` | 会话列表 | 📱小程序 |
-| `/api/ai/chat/messages` | 消息历史 | 📱小程序 |
-| `/api/ai/chat/conversations/{id}/delete` | 删除会话 | 📱小程序 |
-| `/api/ai/nutrition/send` | 营养分析消息 | 📱小程序 |
-| `/api/ai/butler/sessions/create` | 创建AI管家会话 | 📱小程序 |
-| `/api/ai/butler/sessions/update-conversation` | 更新会话ID | 📱小程序 |
-| `/api/ai/butler/sessions/archive` | 归档会话 | 📱小程序 |
-| `/api/ai/butler/sessions/list` | 会话列表 | 📱小程序 |
-| `/api/ai/butler/sessions/detail` | 会话详情 | 📱小程序 |
-| `/api/ai/butler/sessions/delete` | 删除会话 | 📱小程序 |
-| `/api/ai/context` | AI上下文数据 | 📱小程序 |
-| `/api/recommend/search` | 营养标签搜索 | 📱小程序 |
-| `/api/recommend/repurchase-reminders` | 复购提醒 | 📱小程序 |
-| `/api/recommend/repurchase-reminder/{id}/click` | 标记已点击 | 📱小程序 |
-| `/api/feedback/today` | 获取今日AI反馈 | 📱小程序 |
-| `/api/feedback/read` | 标记已读 | 📱小程序 |
-| `/api/feedback/recent` | 最近反馈列表 | 📱小程序 |
+### AI对话
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/ai/chat/send` | 发送聊天消息 | 📱小程序 | `{query, conversationId, reportId, surveyId}` | `{answer, conversationId, tasks[]}` |
+| `POST /api/ai/chat/conversations` | 获取会话列表 | 📱小程序 | Header: `Authorization` | `[{id, name, last_message_at, ...}]` |
+| `POST /api/ai/chat/messages` | 获取消息历史 | 📱小程序 | `{conversationId}` | `[{role, content, created_at, ...}]` |
+| `POST /api/ai/chat/conversations/{id}/delete` | 删除会话 | 📱小程序 | path: `id` | `null` |
+| `POST /api/ai/nutrition/send` | 发送营养分析消息 | 📱小程序 | `{query, conversationId, reportId}` | `{answer, conversationId, recommendations[], tasks[]}` |
+| `POST /api/ai/context` | 获取AI上下文(供Dify回调) | ⚙️系统自动 | `{intentType, userId, params}` | `{has_data, ...根据意图的结构化数据}` |
+
+### 智能推荐
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/recommend/search` | 按营养标签推荐搜索 | 📱小程序 | `{userId, nutritionTags[], types[], limit}` | `[{type, id, name, description, price, url, source}]` |
+| `POST /api/recommend/repurchase-reminders` | 获取复购提醒列表 | 📱小程序 | Header: `Authorization` | `[{id, productId, name, price, coverImage, reason}]` |
+| `POST /api/recommend/repurchase-reminder/{id}/click` | 标记复购提醒已点击 | 📱小程序 | path: `id` | `null` |
+| `POST /api/recommend/repurchase-reminders/list` | 获取待处理复购提醒 | 📱小程序 | Header: `Authorization` | `[{id, productId, productName, ...}]` |
+| `POST /api/recommend/repurchase-reminders/click` | 标记已点击 | 📱小程序 | `{id}` | `null` |
+| `POST /api/recommend/repurchase-reminders/purchased` | 标记已购买 | 📱小程序 | `{id, orderId}` | `null` |
+
+### 饮食推荐
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/meal/recommend` | 获取AI食谱推荐 | 📱小程序 | `{mealType, conversationId}` | `{answer, replaceOptions[], nutritionSummary}` |
+| `POST /api/meal/replace` | 替换指定食材 | 📱小程序 | `{foodId}` | `Food(替代食材)` |
+| `POST /api/meal/log` | 记录饮食日志 | 📱小程序 | `{childId, mealType, foods[], mealDate, note}` | `{id, message}` |
+| `POST /api/meal/logs` | 获取近期饮食日志 | 📱小程序 | `{days}` | `[MealLog]` |
+| `POST /api/meal/nutrition-summary` | 获取营养摄入统计 | 📱小程序 | `{days}` | `{...营养统计数据}` |
+
+### 营养知识库(北京报告)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/nutrition/beijing/bacteria/save` | 保存/更新菌群状态 | 📱小程序 | `{userId, bacteriaList[{latinName, chineseName, status}]}` | `"保存成功"` |
+| `POST /api/nutrition/beijing/recommend` | 基于菌群数据获取食材推荐 | 📱小程序 | `{userId, limit}` | `{foods[], categories[], ...}` |
+| `POST /api/nutrition/beijing/recommend/custom` | 直接传入菌群状态获取推荐 | 📱小程序 | `{userId, bacteriaList[...], limit}` | `{foods[], categories[], ...}` |
+| `POST /api/nutrition/beijing/kb/query` | 查询菌属知识库 | 📱小程序 | `{name}` | `BacteriaEntry(菌属详细)` |
+| `POST /api/nutrition/beijing/kb/list` | 获取菌属知识库列表 | 📱小程序 | — | `[BacteriaEntry]` |
+| `POST /api/nutrition/beijing/kb/info` | 获取知识库概况 | 📱小程序 | — | `{metadata, 总菌属数, 菌属列表}` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    User ||--o{ ChatConversation : "userId"
+    ChatConversation ||--o{ ChatMessage : "会话消息"
+    User ||--o{ AiConversationSummary : "对话摘要"
+    User ||--o{ AiUserFact : "关键事实"
+    User ||--o{ HealthReport : "健康报告"
+    User ||--o{ MealLog : "饮食记录"
+    Product ||--o{ RepurchaseReminderRecord : "复购提醒"
+    Article ||--o{ RecommendationResult : "推荐结果"
+    Activity ||--o{ RecommendationResult : "推荐结果"
+    GrowthTask ||--o{ AIChatController : "动态任务"
+
+    ChatConversation {
+        Long id PK
+        Long userId FK
+        string difyConversationId "Dify会话ID"
+        string assistantType "family/nutrition"
+        string title "会话标题"
+        date lastMessageAt
+    }
+
+    ChatMessage {
+        Long id PK
+        Long conversationId FK
+        string role "user/assistant"
+        text content
+        text inputs "上下文快照"
+    }
+
+    AiConversationSummary {
+        Long id PK
+        Long userId FK
+        string conversationId
+        text summaryText
+        int messageCount
+    }
+
+    AiUserFact {
+        Long id PK
+        Long userId FK
+        string factKey
+        string factValue
+        string sourceConversation
+    }
+
+    HealthReport {
+        Long id PK
+        Long userId FK
+        date reportDate
+        int overallScore
+        int gutHealthScore
+        int nutritionScore
+        string gutType
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖AI对话(含LangGraph/Dify双引擎)、会话管理、精准营养分析、智能推荐、饮食推荐、AI上下文6个阶段,路径完整 |
+| 2 | **异常路径** | ✅ 完整 | LangGraph超时/熔断自动回退Dify(AiGateway熔断器);Dify失败回退本地镜像数据(ChatMirrorService);5%灰度流量走LangGraph;所有外部调用有try-catch包裹 |
+| 3 | **端点覆盖** | ✅ 完整 | 24个端点全部映射到流程图中,与代码实际暴露的`/api/ai/*`、`/api/recommend/*`、`/api/meal/*`、`/api/nutrition/beijing/*`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 所有端点为📱小程序端口,家长/孩子/规划师均可使用AI助手;Dify AI引擎和LangGraph Python服务标注为⚙️外部系统 |
+| 5 | **数据实体** | ✅ 完整 | chat_conversations、chat_messages(本地镜像)、ai_conversation_summaries(记忆Layer1)、ai_user_facts(记忆Layer2)、health_reports、foods/meal_logs、repurchase_reminder_record等均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(AIChatController、RecommendationController、MealRecommendController、BeijingNutritionController)中的`@PostMapping`匹配 |

+ 245 - 52
docs/flows/badge-microaction-flow.md

@@ -1,71 +1,264 @@
 # 用户使用流程图 — 勋章与微行动
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取启用的勋章列表 /list]:::portMiniApp
-        A2 --> A3[📱 获取勋章详情 /detail]:::portMiniApp
-        A3 --> A4[📱 收藏/取消收藏 /favorite]:::portMiniApp
-    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_CHILD(("👶 孩子")):::actor
+    ROLE_ADMIN(("🔧 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:勋章浏览
+    %% ================================================================
+    subgraph 阶段一[阶段一:勋章浏览]
+        direction TB
+
+        P1["🏠 小程序:勋章列表页"]:::page
+        P1 -->|"查看所有启用勋章"| A1["🔗 POST /api/badges/list"]:::api
+        A1 -->|"无参数"| S1["⚙️ BadgeService.getActiveBadges()"]:::service
+        S1 -->|"查询isActive=1, 按sortOrder排序"| S1a["⚙️ BadgeMapper.selectList()"]:::service
+        S1a -->|"Badge列表"| D1["📦 badge 表"]:::data
 
-    subgraph 勋章获得
-        A4 --> B1[📱 获取孩子勋章列表 /child/list]:::portMiniApp
-        B1 --> B2[📱 孩子勋章统计 /statistics/child]:::portMiniApp
-        B2 --> B3[📱 家庭勋章排行 /ranking/family]:::portMiniApp
+        P1 -->|"查看勋章详情"| P1a["🏠 勋章详情页"]:::page
+        P1a -->|"id"| A2["🔗 POST /api/badges/detail"]:::api
+        A2 -->|"id"| S2["⚙️ BadgeService.getBadgeById()"]:::service
+        S2 -->|"按主键查询"| S2a["⚙️ BadgeMapper.selectById()"]:::service
+        S2a -->|"Badge详情"| D1
+
+        P1 -->|"收藏/取消收藏"| P1b["🏠 收藏按钮"]:::page
+        P1b -->|"childId, badgeId"| A3["🔗 POST /api/badges/favorite"]:::api
+        A3 -->|"childId, badgeId"| S3["⚙️ BadgeService.toggleFavorite()"]:::service
+        S3 -->|"查询child_badge记录, 翻转isFavorite"| S3a["⚙️ ChildBadgeMapper.updateById()"]:::service
+        S3a -->|"child_badge记录"| D2["📦 child_badge 表"]:::data
     end
 
-    subgraph 管理员授勋
-        B3 --> C1[🖥 获取所有勋章 /all]:::portAdmin
-        C1 --> C2[🖥 创建勋章 /create]:::portAdmin
-        C2 --> C3[🖥 更新勋章 /update]:::portAdmin
-        C3 --> C4[🖥 删除勋章 /delete]:::portAdmin
-        C4 --> C5[🖥 手动授予勋章 /grant]:::portAdmin
+    %% ================================================================
+    %% 阶段二:勋章获得与统计
+    %% ================================================================
+    subgraph 阶段二[阶段二:勋章获得与统计]
+        D2 -->|"childId"| P2["🏠 小程序:孩子勋章页"]:::page
+        P2 -->|"查看孩子勋章列表"| A4["🔗 POST /api/badges/child/list"]:::api
+        A4 -->|"childId"| S4["⚙️ BadgeService.getActiveChildBadges()"]:::service
+        S4 -->|"查询status=1, 按收藏/获得时间排序"| S4a["⚙️ ChildBadgeMapper.selectList()"]:::service
+        S4a -->|"ChildBadge列表"| D2
+        S4 -->|"关联Badge定义"| S4b["⚙️ BadgeMapper.selectById()"]:::service
+        S4b -->|"Badge详情"| D1
+        S4b -->|"合并后返回"| D3["📦 {childBadge, badge}(返回前端)"]:::data
+
+        P2 -->|"勋章统计"| P2a["🏠 勋章统计面板"]:::page
+        P2a -->|"childId"| A5["🔗 POST /api/badges/statistics/child"]:::api
+        A5 -->|"childId"| S5["⚙️ BadgeService.getChildBadgeStats()"]:::service
+        S5 -->|"统计总数/活跃/过期/撤销"| S5a["⚙️ 按status筛选"]:::service
+        S5a -->|"分类统计+等级统计"| S5b["⚙️ ChildBadgeMapper.selectCategoryStats/selectLevelStats"]:::service
+        S5b -->|"聚合统计结果"| D4["📦 {total, active, expired, revoked, categoryStats, levelStats}"]:::data
+
+        P2 -->|"家庭内勋章排行"| P2b["🏠 家庭勋章排行页"]:::page
+        P2b -->|"familyId"| A6["🔗 POST /api/badges/ranking/family"]:::api
+        A6 -->|"familyId"| S6["⚙️ BadgeService.getFamilyRanking()"]:::service
+        S6 -->|"按家庭内孩子统计勋章数排序"| S6a["⚙️ ChildBadgeMapper.selectFamilyRanking()"]:::service
+        S6a -->|"排行列表(childId, total)"| D5["📦 排行数据(返回前端)"]:::data
     end
 
-    subgraph 微行动
-        A1 --> D1[📱 获取所有微行动列表 /micro-action/list]:::portMiniApp
-        D1 --> D2[📱 获取今日推荐 /micro-action/today]:::portMiniApp
-        D2 --> D3[📱 完成微行动 /micro-action/complete]:::portMiniApp
-        D3 --> D4[📱 检查今日完成 /micro-action/check-today]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:管理后台勋章管理
+    %% ================================================================
+    subgraph 阶段三[阶段三:管理后台勋章管理]
+        P3["🏠 管理后台:勋章管理页"]:::page
+        P3 -->|"查看所有勋章(含未启用)"| A7["🔗 POST /api/badges/all"]:::api
+        A7 -->|"无参数"| S7["⚙️ BadgeService.getAllBadges()"]:::service
+        S7 -->|"全部勋章按sortOrder排序"| D1
+
+        P3 -->|"创建勋章"| P3a["🏠 创建表单"]:::page
+        P3a -->|"Badge对象"| A8["🔗 POST /api/badges/create"]:::api
+        A8 -->|"Badge对象"| S8["⚙️ BadgeService.createBadge()"]:::service
+        S8 -->|"设置创建/更新时间"| S8a["⚙️ BadgeMapper.insert()"]:::service
+        S8a -->|"新Badge记录"| D1
+
+        P3 -->|"编辑勋章"| P3b["🏠 编辑表单"]:::page
+        P3b -->|"Badge对象(含id)"| A9["🔗 POST /api/badges/update"]:::api
+        A9 -->|"Badge对象"| S9["⚙️ BadgeService.updateBadge()"]:::service
+        S9 -->|"更新字段"| D1
+
+        P3 -->|"删除勋章"| P3c["🏠 删除确认弹窗"]:::page
+        P3c -->|"id"| A10["🔗 POST /api/badges/delete"]:::api
+        A10 -->|"id"| S10["⚙️ BadgeService.deleteBadge()"]:::service
+        S10 -->|"按id删除"| D1
+
+        P3 -->|"手动授予勋章"| P3d["🏠 授勋弹窗:选择孩子"]:::page
+        P3d -->|"childId, badgeId"| A11["🔗 POST /api/badges/grant"]:::api
+        A11 -->|"childId, badgeId"| S11["⚙️ BadgeService.grantBadge()"]:::service
+        S11 -->|"检查是否已授予(去重)"| S11a["⚙️ 查ChildBadgeMapper"]:::service
+        S11a -->|"已授予则跳过"| P3d
+        S11 -->|"创建ChildBadge记录"| S11b["⚙️ ChildBadgeMapper.insert()"]:::service
+        S11b -->|"child_badge记录(初始状态=1)"| D2
     end
 
-    R1(("👤 用户")):::actor
-    R2(("🔧 管理员")):::role
+    %% ================================================================
+    %% 阶段四:微行动
+    %% ================================================================
+    subgraph 阶段四[阶段四:微行动]
+        P4["🏠 小程序:微行动页"]:::page
+        P4 -->|"查看所有微行动"| A12["🔗 POST /api/micro-action/list"]:::api
+        A12 -->|"无参数"| S12["⚙️ MicroActionService.getAllActions()"]:::service
+        S12 -->|"查询status=1, 按sortOrder排序"| S12a["⚙️ MicroActionMapper.selectList()"]:::service
+        S12a -->|"MicroAction列表"| D6["📦 micro_actions 表"]:::data
+
+        P4 -->|"获取今日推荐"| P4a["🏠 今日推荐卡片"]:::page
+        P4a -->|"childId"| A13["🔗 POST /api/micro-action/today"]:::api
+        A13 -->|"userId, childId"| S13["⚙️ MicroActionService.getTodayAction()"]:::service
+        S13 -->|"按日期取模随机选择一个行动"| S13a["⚙️ 日期取模算法"]:::service
+        S13a -->|"MicroAction/null(当日已完成)"| D6
+        S13 -->|"检查当日是否已完成"| S13b["⚙️ MicroActionService.getTodayRecord()"]:::service
+        S13b -->|"已有记录返回true"| D7["📦 micro_action_records 表"]:::data
+        S13b -->|"completed=true/false"| D8["📦 {action, completed}(返回前端)"]:::data
+
+        P4a -->|"完成微行动"| P4b["🏠 完成按钮"]:::page
+        P4b -->|"childId, actionId"| A14["🔗 POST /api/micro-action/complete"]:::api
+        A14 -->|"userId, childId, actionId"| S14["⚙️ MicroActionService.completeAction()"]:::service
+        S14 -->|"校验: 今日未完成、未健康打卡"| S14a["⚙️ 互斥校验"]:::service
+        S14a -->|"校验失败抛出RuntimeException"| P4b
+        S14 -->|"验证微行动存在且启用"| S14b["⚙️ MicroActionMapper.selectById()"]:::service
+        S14b -->|"MicroAction"| D6
+        S14 -->|"创建完成记录"| S14c["⚙️ MicroActionRecordMapper.insert()"]:::service
+        S14c -->|"记录(earnedEnergy=1)"| D7
+        S14 -->|"自动创建任务+积分+能量"| S14d["⚙️ TaskMapper.insert() + PointsLog + EnergyService.awardEnergy()"]:::service
+        S14d -->|"task记录 + points_log记录"| D9["📦 tasks + points_logs 表"]:::data
+        S14 -->|"触发新手引导+成长任务"| S14e["⚙️ OnboardingService + GrowthTaskService"]:::service
+        S14e -->|"进度更新"| D10["📦 状态更新"]:::data
+
+        P4 -->|"检查今日是否已完成"| P4c["🏠 加载时自动检查"]:::page
+        P4c -->|"childId"| A15["🔗 POST /api/micro-action/check-today"]:::api
+        A15 -->|"childId"| S15["⚙️ MicroActionService.hasCompletedToday()"]:::service
+        S15 -->|"按childId+今日日期查询记录"| D7
+        S15 -->|"completed=true/false"| D8
+    end
 
-    A1 -.- R1
-    C1 -.- R2
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_CHILD -.- P1
+    ROLE_CHILD -.- P2
+    ROLE_CHILD -.- P4
+    ROLE_ADMIN -.- P3
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/badges/list` | 启用的勋章列表 | 📱小程序 |
-| `/api/badges/detail` | 勋章详情 | 📱小程序 |
-| `/api/badges/child/list` | 孩子勋章列表 | 📱小程序 |
-| `/api/badges/favorite` | 收藏/取消 | 📱小程序 |
-| `/api/badges/statistics/child` | 孩子勋章统计 | 📱小程序 |
-| `/api/badges/ranking/family` | 家庭勋章排行 | 📱小程序 |
-| `/api/micro-action/list` | 微行动列表 | 📱小程序 |
-| `/api/micro-action/today` | 今日推荐 | 📱小程序 |
-| `/api/micro-action/complete` | 完成微行动 | 📱小程序 |
-| `/api/micro-action/check-today` | 检查今日完成 | 📱小程序 |
-| `/api/badges/all` | 所有勋章 | 🖥管理后台 |
-| `/api/badges/create` | 创建勋章 | 🖥管理后台 |
-| `/api/badges/update` | 更新勋章 | 🖥管理后台 |
-| `/api/badges/delete` | 删除勋章 | 🖥管理后台 |
-| `/api/badges/grant` | 手动授予勋章 | 🖥管理后台 |
+### 勋章(用户端)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/badges/list` | 获取启用的勋章列表 | 📱小程序 | — | `List<Badge>`(仅isActive=1) |
+| `POST /api/badges/detail` | 获取勋章详情 | 📱小程序 | `{id}` | `Badge`(含描述、图标、等级、稀有度等) |
+| `POST /api/badges/favorite` | 收藏/取消收藏勋章 | 📱小程序 | `{childId, badgeId}` | `String` |
+| `POST /api/badges/child/list` | 获取孩子获得的勋章列表 | 📱小程序 | `{childId}` | `List<{childBadge, badge}>` |
+| `POST /api/badges/statistics/child` | 孩子勋章统计 | 📱小程序 | `{childId}` | `{total, active, expired, revoked, categoryStats[], levelStats[]}` |
+| `POST /api/badges/ranking/family` | 家庭内勋章排行 | 📱小程序 | `{familyId}` | `List<{childId, total}>` |
+
+### 勋章(管理后台)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/badges/all` | 获取全部勋章(含未启用) | 🖥管理后台 | — | `List<Badge>` |
+| `POST /api/badges/create` | 创建勋章 | 🖥管理后台 | `Badge`对象 | `String` |
+| `POST /api/badges/update` | 更新勋章 | 🖥管理后台 | `Badge`对象(含id) | `String` |
+| `POST /api/badges/delete` | 删除勋章 | 🖥管理后台 | `{id}` | `String` |
+| `POST /api/badges/grant` | 手动授予勋章 | 🖥管理后台 | `{childId, badgeId}` | `String` |
+
+### 微行动
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/micro-action/list` | 获取所有微行动列表 | 📱小程序 | — | `List<MicroAction>` |
+| `POST /api/micro-action/today` | 获取今日推荐微行动 | 📱小程序 | `{childId}` | `{action, completed}` |
+| `POST /api/micro-action/complete` | 完成微行动 | 📱小程序 | `{childId, actionId}` | `MicroActionRecord` |
+| `POST /api/micro-action/check-today` | 检查今日是否已完成 | 📱小程序 | `{childId}` | `{completed}` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    Badge ||--o{ ChildBadge : "一个勋章可授予多个孩子"
+    Child ||--o{ ChildBadge : "一个孩子可获多个勋章"
+    MicroAction ||--o{ MicroActionRecord : "一个行动有多次完成记录"
+    Child ||--o{ MicroActionRecord : "一个孩子可有多次记录"
+    User ||--o{ MicroActionRecord : "一个用户可操作多次"
+
+    Badge {
+        Long id PK
+        string badgeId "逻辑编码"
+        string name
+        string description
+        string icon
+        string category "分类"
+        string level "等级"
+        string rarity "稀有度"
+        string triggerType "触发类型"
+        int threshold "阈值"
+        bool needApproval "需审批"
+        int expireDays "有效期天数"
+        int sortOrder
+        int isActive "1启用 0禁用"
+        datetime createdAt
+        datetime updatedAt
+    }
+
+    ChildBadge {
+        Long id PK
+        Long childId FK
+        Long badgeId FK
+        datetime earnedAt "获得时间"
+        datetime expireAt "过期时间"
+        int status "1活跃 0过期 -1撤销"
+        bool isFavorite "是否收藏"
+        datetime createdAt
+        datetime updatedAt
+    }
+
+    MicroAction {
+        Long id PK
+        string code "DRINK_WATER, DEEP_BREATH"
+        string name "喝一杯水"
+        string icon
+        string description
+        int sortOrder
+        int status "1启用 0禁用"
+        datetime createdAt
+    }
+
+    MicroActionRecord {
+        Long id PK
+        Long userId FK "操作人"
+        Long childId FK "执行孩子"
+        Long actionId FK
+        date completedDate "完成日期"
+        int earnedEnergy "获得能量值"
+        string note
+        datetime createdAt
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖勋章浏览/收藏、孩子勋章查询/统计/排行、管理后台CRUD/授勋、微行动列表/今日推荐/完成/检查4个阶段 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 微行动与健康打卡互斥逻辑(当日只能选择一种)、行动已下架校验、勋章重复授予跳过在图中体现;勋章自动触发(triggerType/threshold)的自动授勋逻辑未画入(当前仅支持手动授予) |
+| 3 | **端点覆盖** | ✅ 完整 | 15个端点全部映射到流程图中,与代码实际暴露的BadgeController(11个)、MicroActionController(4个)一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长和孩子可浏览勋章和微行动;管理员在后管端进行勋章CRUD和手动授勋 |
+| 5 | **数据实体** | ✅ 完整 | badge表、child_badge表、micro_actions表、micro_action_records表、tasks表、points_logs表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配,Service方法名与BadgeService、MicroActionService一致 |

+ 207 - 47
docs/flows/cart-coupon-flow.md

@@ -1,64 +1,224 @@
 # 用户使用流程图 — 购物车与优惠券
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 添加购物车 /cart/add]:::portMiniApp
-        A2 --> A3[📱 获取购物车列表 /cart/list]:::portMiniApp
-        A3 --> A4[📱 更新数量 /cart/update]:::portMiniApp
-        A4 --> A5[📱 移除商品 /cart/remove]:::portMiniApp
-        A5 --> A6[📱 获取数量 /cart/count]:::portMiniApp
-    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_ADMIN(("🔧 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:购物车管理
+    %% ================================================================
+    subgraph 阶段一[阶段一:购物车管理]
+        direction TB
+
+        P1["🏠 小程序:商品详情页"]:::page
+        P1 -->|"选择SKU、数量"| P1a["🏠 加入购物车弹窗"]:::page
+        P1a -->|"productId, quantity, skuId"| A1["🔗 POST /api/cart/add"]:::api
+        A1 -->|"userId, productId, quantity, skuId"| S1["⚙️ CartService.addToCart()"]:::service
+        S1 -->|"查询商品是否存在"| S1a["⚙️ ProductMapper.selectById()"]:::service
+        S1a -->|"商品不存在返回null"| P1a
+        S1 -->|"购物车中已有 → 累加数量"| S1b["⚙️ CartMapper.updateById()"]:::service
+        S1 -->|"购物车中没有 → 新建记录"| S1c["⚙️ CartMapper.insert()"]:::service
+        S1b -->|"Cart记录"| D1["📦 cart 表"]:::data
+        S1c --> D1
 
-    subgraph 优惠券
-        A6 --> B1[📱 获取可用优惠券 /coupon/list]:::portMiniApp
-        B1 --> B2[📱 领取优惠券 /coupon/claim]:::portMiniApp
-        B2 --> B3[📱 应用优惠券 /coupon/apply]:::portMiniApp
+        D1 -->|"userId"| P2["🏠 小程序:购物车列表页"]:::page
+        P2 -->|"userId"| A2["🔗 POST /api/cart/list"]:::api
+        A2 -->|"userId"| S2["⚙️ CartService.getCartList()"]:::service
+        S2 -->|"按创建时间倒序查询"| S2a["⚙️ CartMapper.selectList()"]:::service
+        S2a -->|"Cart列表"| D1
+        S2 -->|"装配商品信息+SKU规格"| S2b["⚙️ buildCartItemDTO()"]:::service
+        S2b -->|"CartItemDTO(含名称/图片/价格/规格)"| D2["📦 CartItemDTO(返回前端)"]:::data
+
+        P2 -->|"调整数量"| P3["🏠 数量调整按钮"]:::page
+        P3 -->|"productId, quantity"| A3["🔗 POST /api/cart/update"]:::api
+        A3 -->|"userId, productId, quantity"| S3["⚙️ CartService.updateQuantity()"]:::service
+        S3 -->|"数量≤0则删除,否则更新数量"| S3a["⚙️ CartMapper.updateById() / delete()"]:::service
+        S3a -->|"更新记录"| D1
+
+        P2 -->|"删除商品"| P4["🏠 删除按钮"]:::page
+        P4 -->|"productId"| A4["🔗 POST /api/cart/remove"]:::api
+        A4 -->|"userId, productId"| S4["⚙️ CartService.removeItem()"]:::service
+        S4 -->|"按userId+productId删除"| S4a["⚙️ CartMapper.delete()"]:::service
+        S4a --> D1
+
+        P2 -->|"查看购物车角标"| P5["🏠 TabBar购物车角标"]:::page
+        P5 -->|"userId"| A5["🔗 POST /api/cart/count"]:::api
+        A5 -->|"userId"| S5["⚙️ CartService.getCartCount()"]:::service
+        S5 -->|"统计该用户购物车条目数"| S5a["⚙️ CartMapper.selectCount()"]:::service
+        S5a -->|"条目数"| D1
     end
 
-    subgraph 管理员优惠券
-        B3 --> C1[🖥 优惠券列表 /admin/coupon/list]:::portAdmin
-        C1 --> C2[🖥 创建优惠券 /admin/coupon/create]:::portAdmin
-        C2 --> C3[🖥 更新 /admin/coupon/update]:::portAdmin
-        C3 --> C4[🖥 发放 /admin/coupon/issue]:::portAdmin
-        C4 --> C5[🖥 删除 /admin/coupon/delete]:::portAdmin
+    %% ================================================================
+    %% 阶段二:优惠券领取与使用
+    %% ================================================================
+    subgraph 阶段二[阶段二:优惠券领取与使用]
+        D1 -->|"userId"| P6["🏠 小程序:优惠券列表页"]:::page
+        P6 -->|"userId"| A6["🔗 POST /api/coupon/list"]:::api
+        A6 -->|"userId"| S6["⚙️ CouponService.listAvailable()"]:::service
+        S6 -->|"查询用户可用券(状态=AVAILABLE、有效期內)"| S6a["⚙️ UserCouponMapper + CouponMapper 联合查询"]:::service
+        S6a -->|"UserCoupon → Coupon"| D3["📦 user_coupon + coupon 表"]:::data
+
+        P6 -->|"领取优惠券"| P7["🏠 领取按钮"]:::page
+        P7 -->|"couponId"| A7["🔗 POST /api/coupon/claim"]:::api
+        A7 -->|"userId, couponId"| S7["⚙️ CouponService.claim()"]:::service
+        S7 -->|"检查: 券存在、未领完、有效期內、未重复领取"| S7a["⚙️ 校验条件"]:::service
+        S7a -->|"校验不通过返回错误消息"| P7
+        S7 -->|"创建UserCoupon记录"| S7b["⚙️ UserCouponMapper.insert()"]:::service
+        S7b -->|"user_coupon记录(状态=AVAILABLE)"| D4["📦 user_coupon 表"]:::data
+        S7 -->|"累加usedCount"| S7c["⚙️ CouponMapper.updateById()"]:::service
+        S7c -->|"更新coupon.usedCount"| D5["📦 coupon 表"]:::data
+
+        P6 -->|"下单时选择优惠券"| P8["🏠 订单确认页"]:::page
+        P8 -->|"userCouponId, orderType, orderAmount"| A8["🔗 POST /api/coupon/apply"]:::api
+        A8 -->|"userId, userCouponId, orderType, orderAmount"| S8["⚙️ CouponService.apply()"]:::service
+        S8 -->|"校验: 券归属、有效期、适用范围、最低消费"| S8a["⚙️ 校验条件"]:::service
+        S8a -->|"校验不通过返回null"| P8
+        S8 -->|"计算折扣=min(券面值, 订单金额)"| S8b["⚙️ 折扣计算"]:::service
+        S8b -->|"折扣金额"| D6["📦 discount(返回前端)"]:::data
+
+        P8 -->|"提交订单 → 标记券已用"| A8b["🔗 POST /api/coupon/markUsed(内部调用)"]:::api
+        A8b -->|"userCouponId, orderId"| S8c["⚙️ CouponService.markUsed()"]:::service
+        S8c -->|"状态→USED, 记录使用时间/订单ID"| D4
     end
 
-    R1(("👤 用户")):::actor
-    R2(("🔧 管理员")):::role
+    %% ================================================================
+    %% 阶段三:管理后台优惠券管理
+    %% ================================================================
+    subgraph 阶段三[阶段三:管理后台优惠券管理]
+        P9["🏠 管理后台:优惠券管理页"]:::page
+        P9 -->|"查看列表"| A9["🔗 POST /api/admin/coupon/list"]:::api
+        A9 -->|"role=admin"| S9["⚙️ CouponService.listAll()"]:::service
+        S9 -->|"查询所有优惠券"| D5
+
+        P9 -->|"创建优惠券"| P9a["🏠 创建表单"]:::page
+        P9a -->|"name, type, value, minSpend, validFrom, ..."| A10["🔗 POST /api/admin/coupon/create"]:::api
+        A10 -->|"role=admin, Coupon对象"| S10["⚙️ CouponMapper.insert()"]:::service
+        S10 -->|"写入新优惠券"| D5
+
+        P9 -->|"编辑优惠券"| P9b["🏠 编辑表单"]:::page
+        P9b -->|"id, 更新字段"| A11["🔗 POST /api/admin/coupon/update"]:::api
+        A11 -->|"role=admin, Coupon对象"| S11["⚙️ CouponMapper.updateById()"]:::service
+        S11 -->|"更新优惠券"| D5
+
+        P9 -->|"发放给用户"| P9c["🏠 发放弹窗:选择用户"]:::page
+        P9c -->|"couponId, userIds[]"| A12["🔗 POST /api/admin/coupon/issue"]:::api
+        A12 -->|"role=admin, couponId, userIds"| S12["⚙️ CouponService.issueToUser()"]:::service
+        S12 -->|"批量创建UserCoupon(状态=AVAILABLE)"| S12a["⚙️ UserCouponMapper.insert()"]:::service
+        S12a -->|"user_coupon记录"| D4
+
+        P9 -->|"删除优惠券"| P9d["🏠 删除确认弹窗"]:::page
+        P9d -->|"id"| A13["🔗 POST /api/admin/coupon/delete"]:::api
+        A13 -->|"role=admin, id"| S13["⚙️ CouponMapper.deleteById()"]:::service
+        S13 -->|"删除优惠券"| D5
+    end
 
-    A1 -.- R1
-    C1 -.- R2
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P6
+    ROLE_PARENT -.- P8
+    ROLE_ADMIN -.- P9
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/cart/add` | 添加购物车 | 📱小程序 |
-| `/api/cart/list` | 购物车列表 | 📱小程序 |
-| `/api/cart/update` | 更新购物车 | 📱小程序 |
-| `/api/cart/remove` | 移除商品 | 📱小程序 |
-| `/api/cart/count` | 购物车数量 | 📱小程序 |
-| `/api/coupon/list` | 优惠券列表 | 📱小程序 |
-| `/api/coupon/claim` | 领取优惠券 | 📱小程序 |
-| `/api/coupon/apply` | 应用优惠券 | 📱小程序 |
-| `/api/admin/coupon/list` | 管理优惠券列表 | 🖥管理后台 |
-| `/api/admin/coupon/create` | 创建优惠券 | 🖥管理后台 |
-| `/api/admin/coupon/update` | 更新优惠券 | 🖥管理后台 |
-| `/api/admin/coupon/issue` | 发放优惠券 | 🖥管理后台 |
-| `/api/admin/coupon/delete` | 删除优惠券 | 🖥管理后台 |
+### 购物车
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/cart/add` | 添加商品到购物车 | 📱小程序 | `{productId, quantity(默认1), skuId(可选)}` | `CartItemDTO` |
+| `POST /api/cart/list` | 获取购物车列表 | 📱小程序 | — | `List<CartItemDTO>`(含商品名/图/价格/规格) |
+| `POST /api/cart/update` | 更新商品数量 | 📱小程序 | `{productId, quantity}` | — |
+| `POST /api/cart/remove` | 从购物车移除商品 | 📱小程序 | `{productId}` | — |
+| `POST /api/cart/count` | 获取购物车条目数 | 📱小程序 | — | `int` |
+
+### 优惠券(用户端)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/coupon/list` | 获取可用优惠券列表 | 📱小程序 | — | `List<Coupon>` |
+| `POST /api/coupon/claim` | 领取优惠券 | 📱小程序 | `{couponId}` | `String`("领取成功" / 错误消息) |
+| `POST /api/coupon/apply` | 应用优惠券计算折扣 | 📱小程序 | `{userCouponId, orderType, orderAmount}` | `{discount}`(折扣金额/分) |
+
+### 优惠券(管理后台)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/coupon/list` | 获取全部优惠券 | 🖥管理后台 | — | `List<Coupon>` |
+| `POST /api/admin/coupon/create` | 创建优惠券 | 🖥管理后台 | `{name, type, value, minSpend, applicableTo, validFrom, validUntil, totalCount}` | `String` |
+| `POST /api/admin/coupon/update` | 更新优惠券 | 🖥管理后台 | `{id, ...更新字段}` | `String` |
+| `POST /api/admin/coupon/issue` | 向用户发放优惠券 | 🖥管理后台 | `{couponId, userIds[]}` | `String` |
+| `POST /api/admin/coupon/delete` | 删除优惠券 | 🖥管理后台 | `{id}` | `String` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    Coupon ||--o{ UserCoupon : "一个券可被多次发放"
+    User ||--o{ UserCoupon : "一个用户可有多张券"
+    User ||--o{ Cart : "一个用户可有多个购物车条目"
+    Product ||--o{ Cart : "一个商品可在多个购物车中"
+    ProductSku ||--o{ Cart : "一个SKU可在多个购物车中"
+
+    Cart {
+        Long id PK
+        Long userId FK
+        Long productId FK
+        Long skuId FK "nullable"
+        string specOptionIds "JSON"
+        int quantity
+        datetime createdAt
+        datetime updatedAt
+    }
+
+    Coupon {
+        Long id PK
+        string name
+        string type "FIXED等"
+        int value "金额(分)"
+        int minSpend "最低消费(分)"
+        string applicableTo "ALL / MEMBERSHIP"
+        date validFrom
+        date validUntil
+        int totalCount "总发放量"
+        int usedCount "已使用量"
+        datetime createdAt
+    }
+
+    UserCoupon {
+        Long id PK
+        Long userId FK
+        Long couponId FK
+        string status "AVAILABLE / USED"
+        datetime receivedAt
+        datetime usedAt "nullable"
+        Long orderId FK "nullable"
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖购物车全生命周期(增删改查计数)、用户优惠券(查看/领取/使用)、管理后台(CRUD/发放)3个阶段 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 添加时商品不存在(返回null)、领取时券已领完/已过期/已重复领取(返回错误消息)、应用券时不满足条件(返回null)在图中体现;订单提交后券标记失败的补偿逻辑未画入 |
+| 3 | **端点覆盖** | ✅ 完整 | 13个端点全部映射到流程图中,与代码实际暴露的CartController(5个)、CouponController(3个)、AdminCouponController(5个)一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 用户端(家长)进行购物车管理、优惠券领取与使用;管理员在后管端进行优惠券CRUD和发放 |
+| 5 | **数据实体** | ✅ 完整 | cart表、coupon表、user_coupon表、CartItemDTO均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配,Service方法名与实际代码一致 |

+ 279 - 83
docs/flows/circle-contact-flow.md

@@ -1,104 +1,300 @@
 # 用户使用流程图 — 圈子与联系人
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取我的圈子 /my-circles]:::portMiniApp
-        A2 --> A3[📱 发现圈子 /discover]:::portMiniApp
-        A3 --> A4[📱 加入圈子 /join]:::portMiniApp
-        A4 --> A5[📱 退出圈子 /leave]:::portMiniApp
-        A5 --> A6[📱 创建圈子 /create]:::portMiniApp
-    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
 
-    subgraph 健康圈子
-        A6 --> B1[📱 获取健康圈子列表 /health/circle/list]:::portMiniApp
-        B1 --> B2[📱 创建健康圈子 /health/circle/create]:::portMiniApp
-        B2 --> B3[📱 加入 /health/circle/join]:::portMiniApp
-        B3 --> B4[📱 退出 /health/circle/leave]:::portMiniApp
-        B4 --> B5[📱 排行榜 /health/circle/ranking]:::portMiniApp
-    end
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_CHILD(("👶 孩子")):::actor
 
-    subgraph 圈子挑战
-        B5 --> C1[📱 挑战列表 /health/circle/challenge/list]:::portMiniApp
-        C1 --> C2[📱 挑战历史 /health/circle/challenge/history]:::portMiniApp
-    end
+    %% ================================================================
+    %% 阶段一:社交圈子管理
+    %% ================================================================
+    subgraph 阶段一[阶段一:社交圈子管理]
+        direction TB
+
+        P1["🏠 小程序:圈子列表页"]:::page
+        P1 -->|"选择操作"| P1_choice{"查看 / 发现 / 创建"}:::page
+
+        P1_choice -->|"查看我的圈子"| A1["🔗 POST /api/circle/my-circles"]:::api
+        A1 -->|"memberId, memberType"| S1["⚙️ CircleService.getMyCircles()"]:::service
+        S1 -->|"查询成员关系后关联圈子信息"| D1["📦 social_circle_member + social_circle"]:::data
+
+        P1_choice -->|"发现推荐圈子"| P1a["🏠 小程序:发现圈子页"]:::page
+        P1a -->|"childId"| A2["🔗 POST /api/circle/discover"]:::api
+        A2 -->|"childId"| S2["⚙️ CircleService.discoverCircles()"]:::service
+        S2 -->|"调用匹配引擎, 过滤已加入"| S2a["⚙️ CircleMatchService.discover()"]:::service
+        S2a -->|"活动/测评/健康报告等匹配源"| D1a["📦 匹配结果(内存中)"]:::data
 
-    subgraph 家庭挑战
-        C2 --> D1[📱 家庭挑战列表 /health/challenge/list]:::portMiniApp
-        D1 --> D2[📱 挑战历史 /health/challenge/history]:::portMiniApp
-        D2 --> D3[📱 挑战进度 /health/challenge/progress]:::portMiniApp
+        P1_choice -->|"创建圈子"| P1b["🏠 小程序:创建圈子表单"]:::page
+        P1b -->|"name, type, matchSource, creatorId, creatorType"| A3["🔗 POST /api/circle/create"]:::api
+        A3 -->|"圈子基本信息"| S3["⚙️ CircleService.createCircle()"]:::service
+        S3 -->|"写入圈子记录, 创建者自动加入"| D1b["📦 social_circle + social_circle_member"]:::data
+
+        D1 -->|"circleId"| P1c["🏠 小程序:圈子详情页"]:::page
+        P1c -->|"加入圈子"| A4["🔗 POST /api/circle/join"]:::api
+        A4 -->|"circleId, memberId, memberType"| S4["⚙️ CircleService.joinCircle()"]:::service
+        S4 -->|"写成员记录, 更新成员计数"| D1c["📦 social_circle_member + social_circle"]:::data
+
+        P1c -->|"退出圈子"| A5["🔗 POST /api/circle/leave"]:::api
+        A5 -->|"circleId, memberId, memberType"| S5["⚙️ CircleService.leaveCircle()"]:::service
+        S5 -->|"删除成员记录, 更新成员计数"| D1
     end
 
-    subgraph 联系人
-        A1 --> E1[📱 获取联系人列表 /contact/list]:::portMiniApp
-        E1 --> E2[📱 创建联系人 /contact/create]:::portMiniApp
-        E2 --> E3[📱 更新联系人 /contact/update]:::portMiniApp
-        E3 --> E4[📱 删除联系人 /contact/delete]:::portMiniApp
-        E4 --> E5[📱 获取详情 /contact/detail]:::portMiniApp
-        E5 --> E6[📱 导入手机联系人 /contact/import-phone]:::portMiniApp
-        E6 --> E7[📱 记录互动 /contact/interaction]:::portMiniApp
-        E7 --> E8[📱 邀请到家庭 /contact/invite-to-family]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:健康圈子
+    %% ================================================================
+    subgraph 阶段二[阶段二:健康圈子]
+        direction TB
+
+        P2["🏠 小程序:健康圈子页"]:::page
+        P2 -->|"选择操作"| P2_choice{"列表 / 创建 / 加入 / 退出 / 排行"}:::page
+
+        P2_choice -->|"列表"| A6["🔗 POST /api/health/circle/list"]:::api
+        A6 -->|"familyId"| S6["⚙️ HealthCircleService.getUserCircles()"]:::service
+        S6 -->|"查询家庭所属的健康圈"| D2["📦 health_circle"]:::data
+
+        P2_choice -->|"创建"| P2a["🏠 小程序:创建健康圈子表单"]:::page
+        P2a -->|"name, description, familyId"| A7["🔗 POST /api/health/circle/create"]:::api
+        A7 -->|"圈子名称, 描述, 所属家庭"| S7["⚙️ HealthCircleService.createCircle()"]:::service
+        S7 -->|"写入健康圈记录, 生成邀请码"| D2a["📦 health_circle"]:::data
+
+        P2_choice -->|"加入"| P2b["🏠 小程序:输入邀请码"]:::page
+        P2b -->|"inviteCode, familyId"| A8["🔗 POST /api/health/circle/join"]:::api
+        A8 -->|"邀请码, 家庭ID"| S8["⚙️ HealthCircleService.joinCircle()"]:::service
+        S8 -->|"校验邀请码, 写入成员记录"| D2b["📦 health_circle_member"]:::data
+
+        P2_choice -->|"退出"| P2c["🏠 小程序:确认退出"]:::page
+        P2c -->|"circleId, familyId"| A9["🔗 POST /api/health/circle/leave"]:::api
+        A9 -->|"圈ID, 家庭ID"| S9["⚙️ HealthCircleService.leaveCircle()"]:::service
+        S9 -->|"标记成员退出"| D2b
+
+        P2_choice -->|"排行"| P2d["🏠 小程序:健康圈排行榜"]:::page
+        P2d -->|"circleId"| A10["🔗 POST /api/health/circle/ranking"]:::api
+        A10 -->|"圈ID"| S10["⚙️ HealthCircleService.getCircleRanking()"]:::service
+        S10 -->|"各家庭健康积分排行"| D2c["📦 排行数据(内存)"]:::data
     end
 
-    subgraph 联系人匹配
-        E8 --> F1[📱 发送匹配请求 /contact/match/send]:::portMiniApp
-        F1 --> F2[📱 接受匹配 /contact/match/accept]:::portMiniApp
-        F2 --> F3[📱 拒绝匹配 /contact/match/reject]:::portMiniApp
-        F3 --> F4[📱 收到的请求 /contact/match/received]:::portMiniApp
-        F4 --> F5[📱 发出的请求 /contact/match/sent]:::portMiniApp
-        F5 --> F6[📱 已匹配 /contact/match/matched]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:挑战
+    %% ================================================================
+    subgraph 阶段三[阶段三:挑战管理]
+        direction TB
+
+        D2 -->|"circleId"| P3["🏠 小程序:圈子挑战页"]:::page
+        P3 -->|"查看挑战列表"| A11["🔗 POST /api/health/circle/challenge/list"]:::api
+        A11 -->|"circleId"| S11["⚙️ CircleChallengeService.getActiveChallenges()"]:::service
+        S11 -->|"该圈子活跃的挑战"| D3["📦 circle_challenge"]:::data
+
+        P3 -->|"查看挑战历史"| A12["🔗 POST /api/health/circle/challenge/history"]:::api
+        A12 -->|"circleId"| S12["⚙️ CircleChallengeService.getChallengeHistory()"]:::service
+        S12 -->|"该圈子已完成的挑战"| D3
+
+        P3a["🏠 小程序:家庭挑战页"]:::page
+        P3a -->|"查看家庭挑战"| A13["🔗 POST /api/health/challenge/list"]:::api
+        A13 -->|"familyId"| S13["⚙️ FamilyChallengeService.getActiveChallenges()"]:::service
+        S13 -->|"该家庭活跃的挑战"| D3a["📦 family_challenge"]:::data
+
+        P3a -->|"查看挑战历史"| A14["🔗 POST /api/health/challenge/history"]:::api
+        A14 -->|"familyId"| S14["⚙️ FamilyChallengeService.getChallengeHistory()"]:::service
+        S14 -->|"该家庭已完成的挑战"| D3a
+
+        P3a -->|"更新挑战进度"| P3b["🏠 小程序:执行挑战任务"]:::page
+        P3b -->|"challengeId, childId, delta"| A15["🔗 POST /api/health/challenge/progress"]:::api
+        A15 -->|"挑战ID, 孩子ID, 进度增量"| S15["⚙️ FamilyChallengeService.updateProgress()"]:::service
+        S15 -->|"更新进度, 自动完成检测"| D3a
     end
 
-    R1(("👤 用户")):::actor
-    R2(("🤝 社交系统")):::system
+    %% ================================================================
+    %% 阶段四:联系人管理
+    %% ================================================================
+    subgraph 阶段四[阶段四:联系人管理]
+        direction TB
+
+        P4["🏠 小程序:联系人列表页"]:::page
+        P4 -->|"选择操作"| P4_choice{"列表 / 创建 / 导入 / 详情"}:::page
+
+        P4_choice -->|"查看列表"| A16["🔗 POST /api/contact/list"]:::api
+        A16 -->|"userId(从token提取)"| S16["⚙️ ContactService.list()"]:::service
+        S16 -->|"按亲密度降序排列"| D4["📦 contacts 表"]:::data
+
+        P4_choice -->|"手动创建"| P4a["🏠 小程序:新建联系人表单"]:::page
+        P4a -->|"name, phone, relationshipType, ..."| A17["🔗 POST /api/contact/create"]:::api
+        A17 -->|"联系人基本信息"| S17["⚙️ ContactService.create()"]:::service
+        S17 -->|"写入联系人, 默认亲密度30"| D4
+
+        P4_choice -->|"导入手机联系人"| P4b["🏠 小程序:手机联系人列表"]:::page
+        P4b -->|"name, phone, extra信息"| A18["🔗 POST /api/contact/import-phone"]:::api
+        A18 -->|"姓名, 手机号, 额外信息"| S18["⚙️ ContactService.importFromPhone()"]:::service
+        S18 -->|"去重后写入, 来源标记phone"| D4
+
+        D4 -->|"contactId"| P4c["🏠 小程序:联系人详情页"]:::page
+        P4c -->|"查看详情"| A19["🔗 POST /api/contact/detail"]:::api
+        A19 -->|"id"| S19["⚙️ ContactService.detail()"]:::service
+        S19 -->|"返回DTO(含生日倒计时等)"| D4
 
-    A1 -.- R1
-    E1 -.- R2
+        P4c -->|"编辑联系人"| P4d["🏠 小程序:编辑联系人表单"]:::page
+        P4d -->|"id, name, phone, tags, ..."| A20["🔗 POST /api/contact/update"]:::api
+        A20 -->|"更新字段"| S20["⚙️ ContactService.update()"]:::service
+        S20 -->|"局部更新联系人"| D4
+
+        P4c -->|"删除联系人"| P4e["🏠 小程序:确认删除"]:::page
+        P4e -->|"id"| A21["🔗 POST /api/contact/delete"]:::api
+        A21 -->|"联系人ID"| S21["⚙️ ContactService.delete()"]:::service
+        S21 -->|"物理删除联系人"| D4
+
+        P4c -->|"记录互动"| A22["🔗 POST /api/contact/interaction"]:::api
+        A22 -->|"id"| S22["⚙️ ContactService.recordInteraction()"]:::service
+        S22 -->|"互动+1, 更新亲密度, 更新时间"| D4
+
+        P4c -->|"邀请到家庭"| P4f["🏠 小程序:选择关系类型"]:::page
+        P4f -->|"contactId, relationshipType, generationLevel"| A23["🔗 POST /api/contact/invite-to-family"]:::api
+        A23 -->|"联系人ID, 关系类型, 辈分"| S23["⚙️ ContactService.inviteToFamily()"]:::service
+        S23 -->|"标记邀请状态invited"| D4
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_CHILD -.- P1
+    ROLE_CHILD -.- P1a
+    ROLE_CHILD -.- P3
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P3a
+    ROLE_PARENT -.- P4
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/circle/my-circles` | 我的圈子 | 📱小程序 |
-| `/api/circle/discover` | 发现圈子 | 📱小程序 |
-| `/api/circle/join` | 加入圈子 | 📱小程序 |
-| `/api/circle/leave` | 退出圈子 | 📱小程序 |
-| `/api/circle/create` | 创建圈子 | 📱小程序 |
-| `/api/health/circle/list` | 健康圈子列表 | 📱小程序 |
-| `/api/health/circle/create` | 创建健康圈子 | 📱小程序 |
-| `/api/health/circle/join` | 加入健康圈子 | 📱小程序 |
-| `/api/health/circle/leave` | 退出健康圈子 | 📱小程序 |
-| `/api/health/circle/ranking` | 健康圈子排行 | 📱小程序 |
-| `/api/health/circle/challenge/list` | 挑战列表 | 📱小程序 |
-| `/api/health/circle/challenge/history` | 挑战历史 | 📱小程序 |
-| `/api/health/challenge/list` | 家庭挑战列表 | 📱小程序 |
-| `/api/health/challenge/history` | 家庭挑战历史 | 📱小程序 |
-| `/api/health/challenge/progress` | 挑战进度 | 📱小程序 |
-| `/api/health/family/ranking` | 家庭健康排行 | 📱小程序 |
-| `/api/contact/list` | 联系人列表 | 📱小程序 |
-| `/api/contact/create` | 创建联系人 | 📱小程序 |
-| `/api/contact/update` | 更新联系人 | 📱小程序 |
-| `/api/contact/delete` | 删除联系人 | 📱小程序 |
-| `/api/contact/detail` | 联系人详情 | 📱小程序 |
-| `/api/contact/import-phone` | 导入手机联系人 | 📱小程序 |
-| `/api/contact/interaction` | 记录互动 | 📱小程序 |
-| `/api/contact/invite-to-family` | 邀请到家庭 | 📱小程序 |
-| `/api/contact/match/send` | 发送匹配 | 📱小程序 |
-| `/api/contact/match/accept` | 接受匹配 | 📱小程序 |
-| `/api/contact/match/reject` | 拒绝匹配 | 📱小程序 |
-| `/api/contact/match/matched` | 已匹配 | 📱小程序 |
+### 社交圈子
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/circle/my-circles` | 获取我的圈子列表 | 📱小程序 | `{memberId, memberType}` | `[{id, name, type, matchSource, memberCount}]` |
+| `POST /api/circle/discover` | 发现推荐圈子 | 📱小程序 | `{childId}` | `[{id, name, type, matchSource, memberCount}]` |
+| `POST /api/circle/join` | 加入圈子 | 📱小程序 | `{circleId, memberId, memberType}` | `{success}` |
+| `POST /api/circle/leave` | 退出圈子 | 📱小程序 | `{circleId, memberId, memberType}` | `{success}` |
+| `POST /api/circle/create` | 创建圈子 | 📱小程序 | `{name, type, matchSource, sourceId, creatorId, creatorType}` | `SocialCircle对象` |
+
+### 健康圈子
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/circle/list` | 获取健康圈子列表 | 📱小程序 | `{familyId}` | `[HealthCircle对象]` |
+| `POST /api/health/circle/create` | 创建健康圈子 | 📱小程序 | `{name, description, familyId}` | `HealthCircle对象` |
+| `POST /api/health/circle/join` | 通过邀请码加入健康圈子 | 📱小程序 | `{inviteCode, familyId}` | `{success}` |
+| `POST /api/health/circle/leave` | 退出健康圈子 | 📱小程序 | `{circleId, familyId}` | `{success}` |
+| `POST /api/health/circle/ranking` | 健康圈子排行榜 | 📱小程序 | `{circleId}` | `{rankings: [...]}` |
+| `POST /api/health/family/ranking` | 家庭健康排行 | 📱小程序 | `{circleId}` | `{rankings: [...]}` |
+
+### 挑战
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/circle/challenge/list` | 圈子挑战列表 | 📱小程序 | `{circleId}` | `[CircleChallenge对象]` |
+| `POST /api/health/circle/challenge/history` | 圈子挑战历史 | 📱小程序 | `{circleId}` | `[CircleChallenge对象]` |
+| `POST /api/health/challenge/list` | 家庭挑战列表 | 📱小程序 | `{familyId}` | `[FamilyChallenge对象]` |
+| `POST /api/health/challenge/history` | 家庭挑战历史 | 📱小程序 | `{familyId}` | `[FamilyChallenge对象]` |
+| `POST /api/health/challenge/progress` | 更新挑战进度 | 📱小程序 | `{challengeId, childId, delta}` | `{success}` |
+
+### 联系人
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/contact/list` | 获取联系人列表 | 📱小程序 | Header: `Authorization` | `[ContactDTO对象]`(按亲密度降序) |
+| `POST /api/contact/create` | 创建联系人 | 📱小程序 | `{name, phone, relationshipType, ...}` | `ContactDTO对象` |
+| `POST /api/contact/update` | 更新联系人 | 📱小程序 | `{id, name, phone, tags, ...}` | `ContactDTO对象` |
+| `POST /api/contact/delete` | 删除联系人 | 📱小程序 | `{id}` | `{success}` |
+| `POST /api/contact/detail` | 获取联系人详情 | 📱小程序 | `{id}` | `ContactDTO对象`(含生日倒计时等) |
+| `POST /api/contact/import-phone` | 从手机导入联系人 | 📱小程序 | `{name, phone, extra}` | `ContactDTO对象` |
+| `POST /api/contact/interaction` | 记录互动 | 📱小程序 | `{id}` | `ContactDTO对象` |
+| `POST /api/contact/invite-to-family` | 邀请联系人加入家庭 | 📱小程序 | `{contactId, relationshipType, generationLevel}` | `{contactId, invitedStatus, relationshipType}` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    SocialCircle ||--o{ SocialCircleMember : "一个圈子多个成员"
+    SocialCircle ||--o{ CircleChallenge : "一个圈子多个挑战"
+    HealthCircle ||--o{ HealthCircleMember : "一个健康圈多个家庭"
+    Family ||--o{ HealthCircleMember : "一个家庭加入多个健康圈"
+    User ||--o{ Contact : "一个用户多个联系人"
+
+    SocialCircle {
+        Long id PK
+        string name
+        string type "topic/activity/hobby/ability/product/health/provider"
+        string matchSource
+        Long sourceId
+        int memberCount
+    }
+
+    SocialCircleMember {
+        Long id PK
+        Long circleId FK
+        Long memberId
+        string memberType "parent/child"
+    }
+
+    HealthCircle {
+        Long id PK
+        string name
+        string description
+        Long creatorFamilyId
+        string inviteCode
+        int memberLimit
+        string status "active/closed"
+    }
+
+    HealthCircleMember {
+        Long id PK
+        Long circleId FK
+        Long familyId FK
+        string role "member/admin"
+        string status "active/inactive"
+    }
+
+    CircleChallenge {
+        Long id PK
+        Long circleId FK
+        string challengeType "checkin/step/meditation"
+        string title
+        int durationDays
+        string period "weekly/monthly"
+        string status "active/completed/cancelled"
+    }
+
+    Contact {
+        Long id PK
+        Long userId FK
+        string name
+        string phone
+        string relationshipType "family/friend/partner/colleague/other"
+        int intimacyLevel
+        string contactSource "phone/manual"
+        Long familyMemberId "关联家庭成员ID"
+        string invitedStatus "none/invited/accepted/declined"
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖社交圈子CRUD、健康圈子管理、圈子挑战、家庭挑战、联系人管理5个阶段,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 加入圈子时已加入则直接返回成功(幂等);联系人导入时重复手机号会返回错误;邀请联系人时已是家庭成员也会返回错误 |
+| 3 | **端点覆盖** | ✅ 完整 | 24个端点全部映射到流程图中,与CircleController、HealthCircleController、CircleChallengeController、FamilyChallengeController、ContactController的`@PostMapping`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 社交圈子面向孩子(child),健康圈子和联系人面向家长(parent),分工明确 |
+| 5 | **数据实体** | ✅ 完整 | social_circle、social_circle_member、health_circle、health_circle_member、circle_challenge、contacts共6张核心表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配,边缘输出数据与代码逻辑一致 |

+ 389 - 66
docs/flows/content-media-flow.md

@@ -1,88 +1,411 @@
 # 用户使用流程图 — 内容与媒体
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取文章列表 /list]:::portMiniApp
-        A2 --> A3[📱 获取文章分类 /categories]:::portMiniApp
-        A3 --> A4[📱 获取文章详情 /detail]:::portMiniApp
-        A4 --> A5[📱 获取精选文章 /featured]:::portMiniApp
-        A5 --> A6[📱 记录阅读 /record-read]:::portMiniApp
-        A6 --> A7[📱 获取阅读统计 /reading-stats]:::portMiniApp
+    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
+
+    %% ============ 角色 ============
+    ROLE_USER(("👤 用户")):::actor
+    ROLE_ADMIN(("🖥 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:文章浏览
+    %% ================================================================
+    subgraph 阶段一[阶段一:文章浏览]
+        direction TB
+
+        P1["📱 小程序:文章列表页"]:::page
+        P1 -->|"查看分类"| A1["🔗 POST /api/articles/categories"]:::api
+        A1 -->|"无参数"| S1["⚙️ ArticleCategoryService.getActiveCategories()"]:::service
+        S1 -->|"启用分类列表(按sortOrder排序)"| D1["📦 article_categories 表"]:::data
+
+        P1 -->|"按分类/维度/关键词过滤"| A2["🔗 POST /api/articles/list"]:::api
+        A2 -->|"categoryId, keyword, dimensionCode, page, size"| S2["⚙️ ArticleService.getPublicList()"]:::service
+        S2 -->|"已发布文章(含可见性过滤)"| D2["📦 articles 表(查询)"]:::data
+
+        P1 -->|"查看精选"| A3["🔗 POST /api/articles/featured"]:::api
+        A3 -->|"size, dimensionCode"| S3["⚙️ ArticleService.getFeatured()"]:::service
+        S3 -->|"isFeatured=1的已发布文章"| D2
+
+        P1 -->|"点击查看详情"| P1a["📱 小程序:文章详情页"]:::page
+        P1a -->|"文章ID"| A4["🔗 POST /api/articles/detail"]:::api
+        A4 -->|"id"| S4["⚙️ ArticleService.getDetail()"]:::service
+        S4 -->|"文章对象(含可见性校验)"| D2
     end
 
-    subgraph 每日贴士
-        A7 --> B1[📱 获取每日贴士 /daily-tip]:::portMiniApp
-        B1 --> B2[📱 获取AI问题列表 /ai-questions]:::portMiniApp
-        B2 --> B3[📱 提交答案 /submit-answers]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:阅读记录与积分
+    %% ================================================================
+    subgraph 阶段二[阶段二:阅读记录与积分]
+
+        P1a -->|"记录阅读(进入页面时)"| A5["🔗 POST /api/articles/record-read"]:::api
+        A5 -->|"id(文章ID), durationSeconds, childId"| S5["⚙️ ArticleService.recordRead()"]:::service
+        S5 -->|"viewCount+1, 写入阅读记录, 检查时长阈值, 创建Task(自动完成), 发放积分, PointsLog, 发放五维能量"| D3["📦 article_reading_records + tasks + points_logs + energy_records"]:::data
+
+        P1a -->|"上报阅读时长(定时上报)"| A6["🔗 POST /api/articles/report-reading-time"]:::api
+        A6 -->|"articleId, durationSeconds, childId"| S6["⚙️ ArticleService.reportReadingTime()"]:::service
+        S6 -->|"当日记录累加/新建"| D4["📦 article_reading_records(累加durationSeconds)"]:::data
+
+        P1 -->|"查看阅读统计"| P1b["📱 小程序:阅读统计页"]:::page
+        P1b -->|"孩子ID"| A7["🔗 POST /api/articles/reading-stats"]:::api
+        A7 -->|"childId"| S7["⚙️ ArticleService.getReadingStats()"]:::service
+        S7 -->|"月阅读数, 总时长, 进度百分比"| D4
     end
 
-    subgraph 内容发布
-        B3 --> C1[📱 发布文章 /publish]:::portMiniApp
-        C1 --> C2[📱 获取我的帖子 /my-posts]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:每日贴士与AI互动
+    %% ================================================================
+    subgraph 阶段三[阶段三:每日贴士与AI互动]
+
+        P1 -->|"查看今日贴士"| P1c["📱 小程序:每日贴士页"]:::page
+        P1c -->|"无参数"| A8["🔗 POST /api/articles/daily-tip"]:::api
+        A8 -->|"无"| S8["⚙️ ArticleService.getDailyTip()"]:::service
+        S8 -->|"根据日期从心理类文章中轮选一篇"| D2
+
+        P1a -->|"获取AI问题"| A9["🔗 POST /api/articles/ai-questions"]:::api
+        A9 -->|"articleId, childId"| S9["⚙️ ArticleService.getAiQuestions()"]:::service
+        S9 -->|"调用Dify AI生成互动题目"| D5["📦 Dify AI(外部)"]:::data
+
+        P1a -->|"提交AI答案"| A10["🔗 POST /api/articles/submit-answers"]:::api
+        A10 -->|"recordId, answers(JSON), childId"| S10["⚙️ ArticleService.submitAnswers()"]:::service
+        S10 -->|"AI评分和反馈"| D5
     end
 
-    subgraph 内容分享
-        C2 --> D1[📱 创建分享记录 /share/create]:::portMiniApp
-        D1 --> D2[📱 记录点击 /share/click]:::portMiniApp
-        D2 --> D3[📱 记录阅读 /share/read]:::portMiniApp
-        D3 --> D4[📱 获取我的分享 /share/my]:::portMiniApp
-        D4 --> D5[📱 获取分享统计 /share/stats]:::portMiniApp
-        D5 --> D6[📱 获取家庭足迹 /share/family-footprint]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:用户发布内容
+    %% ================================================================
+    subgraph 阶段四[阶段四:用户发布内容]
+
+        P1 -->|"发布文章"| P1d["📱 小程序:发布文章页"]:::page
+        P1d -->|"标题, 正文, 封面图, 可见范围, 关联维度"| A11["🔗 POST /api/articles/publish"]:::api
+        A11 -->|"title, content, coverImage, visibility, relatedDimensions"| S11["⚙️ ArticleService.publishByUser()"]:::service
+        S11 -->|"公开→draft/待审核, 私密→published(家庭可见)"| D2
+
+        P1 -->|"我的帖子"| P1e["📱 小程序:我的帖子页"]:::page
+        P1e -->|"分页参数"| A12["🔗 POST /api/articles/my-posts"]:::api
+        A12 -->|"page, size"| S12["⚙️ ArticleService.getMyPosts()"]:::service
+        S12 -->|"用户发布的文章列表"| D2
     end
 
-    subgraph 媒体管理
-        D6 --> E1[📱 上传媒体文件 /media/upload]:::portMiniApp
-        E1 --> E2[📱 保存文字记录 /media/upload-text]:::portMiniApp
-        E2 --> E3[📱 获取任务媒体 /media/task/:taskId]:::portMiniApp
-        E3 --> E4[📱 删除媒体 /media/:mediaId]:::portMiniApp
-        E4 --> E5[📱 批量关联 /media/attach]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:分享
+    %% ================================================================
+    subgraph 阶段五[阶段五:内容分享]
+
+        P1a -->|"分享给好友"| P1f["📱 小程序:分享弹窗"]:::page
+        P1f -->|"目标类型, 目标ID, 分享渠道"| A13["🔗 POST /api/share/create"]:::api
+        A13 -->|"targetType, targetId, shareChannel, title"| S13["⚙️ ShareService.createShareEvent()"]:::service
+        S13 -->|"ShareEvent记录(含分享URL和有效期)"| D6["📦 share_events 表"]:::data
+
+        P1f -->|"好友点击分享链接"| A14["🔗 POST /api/share/click"]:::api
+        A14 -->|"shareEventId"| S14["⚙️ ShareService.recordClick()"]:::service
+        S14 -->|"clickCount+1"| D6
+
+        P1f -->|"好友阅读分享内容"| A15["🔗 POST /api/share/read"]:::api
+        A15 -->|"shareEventId, duration, readerIp"| S15["⚙️ ShareService.recordRead() + rewardReadPoints()"]:::service
+        S15 -->|"readCount+1, 达标则发放阅读者积分"| D6
+
+        P1 -->|"我的分享"| A16["🔗 POST /api/share/my"]:::api
+        A16 -->|"无参数"| S16["⚙️ ShareService.getUserShareEvents()"]:::service
+        S16 -->|"用户分享记录列表"| D6
+
+        P1 -->|"分享统计"| A17["🔗 POST /api/share/stats"]:::api
+        A17 -->|"无参数"| S17["⚙️ ShareService.getShareStats()"]:::service
+        S17 -->|"分享统计信息"| D6
+
+        P1 -->|"家庭足迹"| A18["🔗 POST /api/share/family-footprint"]:::api
+        A18 -->|"familyId"| S18["⚙️ ShareService.getFamilyFootprint()"]:::service
+        S18 -->|"家庭成员分享汇总"| D6
+    end
+
+    %% ================================================================
+    %% 阶段六:媒体管理
+    %% ================================================================
+    subgraph 阶段六[阶段六:媒体管理]
+
+        P2["📱 小程序:任务执行页"]:::page
+        P2 -->|"上传媒体文件"| A19["🔗 POST /api/media/upload"]:::api
+        A19 -->|"file(多部件), taskId, creatorId, description"| S19["⚙️ MediaRecordService.uploadMedia()"]:::service
+        S19 -->|"MediaRecord记录(含文件大小/类型校验)"| D7["📦 media_records 表"]:::data
+
+        P2 -->|"保存文字记录"| A20["🔗 POST /api/media/upload-text"]:::api
+        A20 -->|"taskId, creatorId, content"| S20["⚙️ MediaRecordService.saveTextRecord()"]:::service
+        S20 -->|"MediaRecord(类型=text)"| D7
+
+        P2 -->|"查看任务媒体"| A21["🔗 POST /api/media/task/{taskId}"]:::api
+        A21 -->|"路径参数: taskId"| S21["⚙️ MediaRecordService.getMediaByTaskId()"]:::service
+        S21 -->|"任务的媒体文件列表"| D7
+
+        P2 -->|"删除媒体"| A22["🔗 POST /api/media/{mediaId}"]:::api
+        A22 -->|"路径参数: mediaId, userId"| S22["⚙️ MediaRecordService.deleteMedia()"]:::service
+        S22 -->|"删除记录"| D7
+
+        P2 -->|"批量关联媒体"| A23["🔗 POST /api/media/attach"]:::api
+        A23 -->|"taskId, mediaIds列表"| S23["⚙️ MediaRecordService.attachMediaToTask()"]:::service
+        S23 -->|"更新media关联的taskId"| D7
     end
 
-    R1(("👤 用户")):::actor
-    R2(("📱 分享系统")):::system
+    %% ================================================================
+    %% 阶段七:管理后台文章管理
+    %% ================================================================
+    subgraph 阶段七[阶段七:管理后台文章管理]
+
+        P3["🖥 管理后台:文章管理页"]:::page
+        P3 -->|"查看列表(过滤)"| A24["🔗 POST /api/admin/articles/list"]:::api
+        A24 -->|"status, categoryId, keyword, contentType, difficultyLevel, dimensionCode, tagId, auditStatus, page, size"| S24["⚙️ ArticleService.getAdminList()"]:::service
+        S24 -->|"文章列表(含草稿)"| D2
+
+        P3 -->|"创建文章"| P3a["🖥 管理后台:创建文章表单"]:::page
+        P3a -->|"标题, 正文, 分类, 摘要, 封面, 标签, 作者, 阅读时间, 内容类型, 难度等级, 关联维度, 可见性, 文章类型, 状态"| A25["🔗 POST /api/admin/articles/create"]:::api
+        A25 -->|"全部文章字段"| S25["⚙️ ArticleService.create()"]:::service
+        S25 -->|"计算wordCount, AI自动打标签"| D2
+
+        P3 -->|"编辑文章"| P3b["🖥 管理后台:编辑文章表单"]:::page
+        P3b -->|"文章ID+修改字段"| A26["🔗 POST /api/admin/articles/update"]:::api
+        A26 -->|"id, 修改字段"| S26["⚙️ ArticleService.update()"]:::service
+        S26 -->|"更新字段, 内容变更则AI重新打标签"| D2
+
+        P3 -->|"查看详情"| A27["🔗 POST /api/admin/articles/detail"]:::api
+        A27 -->|"id"| S27["⚙️ ArticleService.getById()"]:::service
+        S27 -->|"Article对象"| D2
+
+        P3 -->|"删除"| A28["🔗 POST /api/admin/articles/delete"]:::api
+        A28 -->|"id"| S28["⚙️ ArticleService.delete()"]:::service
+        S28 -->|"删除记录"| D2
+
+        P3 -->|"发布/下架"| A29["🔗 POST /api/admin/articles/publish"]:::api
+        A29 -->|"id, status"| S29["⚙️ ArticleService.toggleStatus()"]:::service
+        S29 -->|"切换published/draft等状态"| D2
+
+        P3 -->|"设置精选"| A30["🔗 POST /api/admin/articles/toggle-featured"]:::api
+        A30 -->|"id, isFeatured"| S30["⚙️ ArticleService.toggleFeatured()"]:::service
+        S30 -->|"更新isFeatured字段"| D2
+
+        P3 -->|"提交审核"| A31["🔗 POST /api/admin/articles/submit-review"]:::api
+        A31 -->|"id"| S31["⚙️ ArticleService.submitForReview()"]:::service
+        S31 -->|"状态=pending, auditStatus=pending"| D2
 
-    A1 -.- R1
-    D1 -.- R2
+        P3 -->|"审核通过/驳回"| A32["🔗 POST /api/admin/articles/audit"]:::api
+        A32 -->|"id, auditStatus(approved/rejected), auditReason"| S32["⚙️ ArticleService.auditArticle()"]:::service
+        S32 -->|"approved→published / rejected→rejected(记录驳回原因)"| D2
+
+        P3 -->|"撤回"| A33["🔗 POST /api/admin/articles/withdraw"]:::api
+        A33 -->|"id"| S33["⚙️ ArticleService.withdraw()"]:::service
+        S33 -->|"状态=withdrawn"| D2
+
+        P3 -->|"驳回后转草稿"| A34["🔗 POST /api/admin/articles/re-draft"]:::api
+        A34 -->|"id"| S34["⚙️ ArticleService.reDraft()"]:::service
+        S34 -->|"状态=draft, 清空审核信息"| D2
+
+        P3 -->|"上传封面图"| A35["🔗 POST /api/admin/articles/upload/image"]:::api
+        A35 -->|"file(多部件)"| S35["⚙️ FileStorageService.store()"]:::service
+        S35 -->|"文件访问URL"| D8["📦 文件存储系统"]:::data
+    end
+
+    %% ================================================================
+    %% 阶段八:文章分类管理
+    %% ================================================================
+    subgraph 阶段八[阶段八:文章分类管理]
+
+        P3 -->|"查看分类列表"| A36["🔗 POST /api/admin/articles/categories/list"]:::api
+        A36 -->|"无参数"| S36["⚙️ ArticleCategoryService.listAll()"]:::service
+        S36 -->|"全部分类(含禁用)"| D1
+
+        P3 -->|"创建分类"| A37["🔗 POST /api/admin/articles/categories/create"]:::api
+        A37 -->|"name, icon, color, sortOrder"| S37["⚙️ ArticleCategoryService.create()"]:::service
+        S37 -->|"新分类记录"| D1
+
+        P3 -->|"更新分类"| A38["🔗 POST /api/admin/articles/categories/update"]:::api
+        A38 -->|"ArticleCategory对象(含id)"| S38["⚙️ ArticleCategoryService.update()"]:::service
+        S38 -->|"更新分类字段"| D1
+
+        P3 -->|"删除分类"| A39["🔗 POST /api/admin/articles/categories/delete"]:::api
+        A39 -->|"id"| S39["⚙️ ArticleCategoryService.delete()"]:::service
+        S39 -->|"删除分类记录"| D1
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_USER -.- P1
+    ROLE_USER -.- P2
+    ROLE_ADMIN -.- P3
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/articles/list` | 文章列表 | 📱小程序 |
-| `/api/articles/categories` | 文章分类 | 📱小程序 |
-| `/api/articles/detail` | 文章详情 | 📱小程序 |
-| `/api/articles/featured` | 精选文章 | 📱小程序 |
-| `/api/articles/record-read` | 记录阅读 | 📱小程序 |
-| `/api/articles/reading-stats` | 阅读统计 | 📱小程序 |
-| `/api/articles/daily-tip` | 每日贴士 | 📱小程序 |
-| `/api/articles/ai-questions` | AI问题列表 | 📱小程序 |
-| `/api/articles/submit-answers` | 提交答案 | 📱小程序 |
-| `/api/articles/publish` | 发布文章 | 📱小程序 |
-| `/api/articles/my-posts` | 我的帖子 | 📱小程序 |
-| `/api/share/create` | 创建分享 | 📱小程序 |
-| `/api/share/click` | 记录点击 | 📱小程序 |
-| `/api/share/read` | 记录阅读 | 📱小程序 |
-| `/api/share/my` | 我的分享 | 📱小程序 |
-| `/api/share/stats` | 分享统计 | 📱小程序 |
-| `/api/share/family-footprint` | 家庭足迹 | 📱小程序 |
-| `/api/media/upload` | 上传媒体 | 📱小程序 |
-| `/api/media/upload-text` | 保存文字 | 📱小程序 |
-| `/api/media/task/{taskId}` | 任务媒体 | 📱小程序 |
-| `/api/media/{mediaId}` | 删除媒体 | 📱小程序 |
-| `/api/media/attach` | 批量关联 | 📱小程序 |
+### 文章浏览
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/articles/list` | 文章列表 | 📱小程序 | `{categoryId, keyword, dimensionCode, page, size}` | `Page<Article>` |
+| `POST /api/articles/categories` | 文章分类 | 📱小程序 | — | `[ArticleCategory]` |
+| `POST /api/articles/detail` | 文章详情 | 📱小程序 | `{id}` | `Article(含可见性校验)` |
+| `POST /api/articles/featured` | 精选文章 | 📱小程序 | `{size, dimensionCode}` | `[Article]` |
+| `POST /api/articles/record-read` | 记录阅读(进页面) | 📱小程序 | `{id, durationSeconds, childId}` | `{taskId, pointsEarned, alreadyCompleted, belowThreshold, minSeconds}` |
+| `POST /api/articles/report-reading-time` | 上报阅读时长 | 📱小程序 | `{articleId, durationSeconds, childId}` | `null` |
+| `POST /api/articles/reading-stats` | 阅读统计 | 📱小程序 | `{childId}` | `{totalArticles, totalDurationSeconds, targetDurationSeconds, progress}` |
+
+### 每日贴士与AI互动
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/articles/daily-tip` | 每日贴士 | 📱小程序 | — | `{id, title, summary, ...}` |
+| `POST /api/articles/ai-questions` | AI问题列表 | 📱小程序 | `{articleId, childId}` | `{recordId, questions}` |
+| `POST /api/articles/submit-answers` | 提交AI答案 | 📱小程序 | `{recordId, answers(JSON), childId}` | `{score, feedback}` |
+
+### 用户发布
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/articles/publish` | 发布文章(用户端) | 📱小程序 | `{title, content, coverImage, visibility, relatedDimensions}` | `{id, status, auditStatus}` |
+| `POST /api/articles/my-posts` | 我的帖子列表 | 📱小程序 | `{page, size}` | `Page<Article>` |
+
+### 分享
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/share/create` | 创建分享记录 | 📱小程序 | `{targetType, targetId, shareChannel, title}` | `ShareEvent` |
+| `POST /api/share/click` | 记录分享点击 | 📱小程序 | `{shareEventId}` | `null` |
+| `POST /api/share/read` | 记录分享阅读 | 📱小程序 | `{shareEventId, duration}` | `{rewarded}` |
+| `POST /api/share/my` | 我的分享记录 | 📱小程序 | — | `[ShareEvent]` |
+| `POST /api/share/stats` | 分享统计 | 📱小程序 | — | `Map<String, Object>` |
+| `POST /api/share/family-footprint` | 家庭足迹 | 📱小程序 | `{familyId}` | `Map<String, Object>` |
+
+### 媒体管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/media/upload` | 上传媒体文件 | 📱小程序 | `file(多部件), taskId, creatorId, description` | `MediaRecord` |
+| `POST /api/media/upload-text` | 保存文字记录 | 📱小程序 | `{taskId, creatorId, content}` | `MediaRecord` |
+| `POST /api/media/task/{taskId}` | 获取任务媒体 | 📱小程序 | 路径参数: `taskId` | `[MediaRecord]` |
+| `POST /api/media/{mediaId}` | 删除媒体 | 📱小程序 | 路径参数: `mediaId` | `true` |
+| `POST /api/media/attach` | 批量关联媒体到任务 | 📱小程序 | `{taskId, mediaIds}` | `true` |
+
+### 管理后台文章
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/articles/list` | 文章列表(含草稿) | 🖥管理后台 | `{status, categoryId, keyword, contentType, difficultyLevel, dimensionCode, tagId, auditStatus, page, size}` | `Page<Article>` |
+| `POST /api/admin/articles/create` | 创建文章 | 🖥管理后台 | 文章全部字段 | `{id}` |
+| `POST /api/admin/articles/update` | 更新文章 | 🖥管理后台 | `{id, title, content, categoryId, ...}` | `"更新成功"` |
+| `POST /api/admin/articles/detail` | 文章详情 | 🖥管理后台 | `{id}` | `Article` |
+| `POST /api/admin/articles/delete` | 删除文章 | 🖥管理后台 | `{id}` | `"删除成功"` |
+| `POST /api/admin/articles/publish` | 发布/下架文章 | 🖥管理后台 | `{id, status}` | `"操作成功"` |
+| `POST /api/admin/articles/toggle-featured` | 设置精选 | 🖥管理后台 | `{id, isFeatured}` | `"操作成功"` |
+| `POST /api/admin/articles/submit-review` | 提交审核 | 🖥管理后台 | `{id}` | `"已提交审核"` |
+| `POST /api/admin/articles/audit` | 审核文章 | 🖥管理后台 | `{id, auditStatus, auditReason}` | `"审核完成"` |
+| `POST /api/admin/articles/withdraw` | 撤回已发布文章 | 🖥管理后台 | `{id}` | `"已撤回"` |
+| `POST /api/admin/articles/re-draft` | 驳回后转草稿 | 🖥管理后台 | `{id}` | `"已保存到草稿箱"` |
+| `POST /api/admin/articles/upload/image` | 上传文章图片 | 🖥管理后台 | `file(多部件)` | `图片URL` |
+
+### 管理后台分类
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/articles/categories/list` | 分类列表 | 🖥管理后台 | — | `[ArticleCategory]` |
+| `POST /api/admin/articles/categories/create` | 创建分类 | 🖥管理后台 | `ArticleCategory对象` | `"创建成功"` |
+| `POST /api/admin/articles/categories/update` | 更新分类 | 🖥管理后台 | `ArticleCategory对象(含id)` | `"更新成功"` |
+| `POST /api/admin/articles/categories/delete` | 删除分类 | 🖥管理后台 | `{id}` | `"删除成功"` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖文章浏览→阅读记录→积分发放、每日贴士→AI互动、用户发布、分享全链路、媒体管理、管理后台文章CRUD+审核+分类管理共8个阶段 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 阅读时长不足阈值不发放积分(返回belowThreshold标记)已覆盖;重复阅读去重(同文章+同孩子)在Service层校验;文章可见性权限在ArticlePermissionService处理 |
+| 3 | **端点覆盖** | ✅ 完整 | 39个端点全部映射到流程图中,与代码实际暴露的 `/api/articles/*`、`/api/share/*`、`/api/media/*`、`/api/admin/articles/*` 一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 普通用户(家长/孩子)浏览阅读发布、管理员后台管理、系统自动(积分发放/去重)均已覆盖 |
+| 5 | **数据实体** | ✅ 完整 | articles表、article_categories表、article_reading_records表、share_events表、media_records表、article_tags表、tasks表、points_logs表、energy_records表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(ArticleController、ArticleCategoryController、ShareController、MediaController、AdminArticleController)中的 `@PostMapping` 匹配 |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    Article ||--o{ ArticleReadingRecord : "阅读记录"
+    Article ||--o{ ShareEvent : "分享事件"
+    Article }o--|| ArticleCategory : "所属分类"
+    Article ||--o{ ArticleTag : "文章标签"
+    Task ||--o{ MediaRecord : "任务媒体"
+    ShareEvent ||--o{ ShareClick : "点击事件"
+    ShareEvent ||--o{ ShareRead : "阅读事件"
+
+    Article {
+        Long id PK
+        Long categoryId FK
+        string title
+        string summary
+        string coverImage
+        string content
+        string tags
+        string author
+        string articleType "normal/premium/original"
+        string contentType "article/knowledge/course/tip"
+        int difficultyLevel "1-5"
+        int wordCount
+        string relatedDimensions
+        string dimensionWeights "JSON五维权重"
+        string visibility "public/private/restricted"
+        string status "draft/pending/rejected/published/withdrawn"
+        string auditStatus "approved/pending/rejected"
+        string auditReason
+        int isFeatured
+        int viewCount
+        Long createdBy
+        string authorType "admin/parent/child"
+    }
+
+    ArticleCategory {
+        Long id PK
+        string name
+        string icon
+        string color
+        int sortOrder
+        int status "1=启用"
+    }
+
+    ArticleReadingRecord {
+        Long id PK
+        Long articleId FK
+        Long userId FK
+        Long childId FK
+        int durationSeconds
+        Long taskId "关联的积分任务"
+        date readAt
+    }
+
+    ShareEvent {
+        Long id PK
+        Long userId FK
+        string targetType "article/product"
+        Long targetId
+        string shareChannel "wechat/timeline"
+        string shareTitle
+        int clickCount
+        int readCount
+        string status
+        string shareUrl
+        date expiresAt
+    }
+
+    MediaRecord {
+        Long id PK
+        Long taskId FK
+        Long creatorId FK
+        string fileType "image/video/audio/text"
+        string fileUrl
+        string description
+        long fileSize
+    }
+```

+ 385 - 227
docs/flows/dan-assessment-flow.md

@@ -1,270 +1,428 @@
 # 用户使用流程图 — DAN 认知测评
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
-
-## 流程图
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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:#616111,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[📱 浏览测评材料<br/>page: apply<br/>/material/list]:::portMiniApp
-        A2 --> A3[📱 获取当前启用材料<br/>page: apply<br/>/material/active]:::portMiniApp
-        A3 --> A4{📱 家庭测评已启用?}:::portMiniApp
-        A4 -->|否| A5[📱 启用家庭测评<br/>page: apply<br/>/family/enable]:::portMiniApp
-        A4 -->|是| A6[📱 查看家庭配置<br/>page: apply<br/>/family/config]:::portMiniApp
-        A5 --> A6
-        A6 --> A7[📱 查看可用额度<br/>page: quota<br/>/quota/my-list]:::portMiniApp
-        A7 --> A8[📱 额度详情<br/>page: quota<br/>/quota/detail]:::portMiniApp
-    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
 
-    subgraph 下单与支付
-        A8 --> B1[📱 选择评估师/规划师<br/>page: apply<br/>/appointment/assessor-list]:::portMiniApp
-        B1 --> B2[📱 创建测评订单<br/>page: order<br/>/order/create]:::portMiniApp
-        B2 --> B3[📱 支付订单<br/>page: order<br/>/order/pay]:::portMiniApp
-        B3 --> B4[📱 查看订单详情<br/>page: order<br/>/order/detail]:::portMiniApp
-        B4 --> B5{📱 支付成功?}:::portMiniApp
-        B5 -->|否| B6[📱 取消订单<br/>page: order<br/>/order/cancel]:::portMiniApp
-        B5 -->|是| B7[⚙️ 订单状态: paid<br/>生成额度<br/>进入预约流程]:::portSystem
-    end
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_GUIDE(("📋 规划师/评估师")):::actor
+    ROLE_AI(("⚙️ AI解析引擎")):::actor
+
+    %% ================================================================
+    %% 阶段一:测评准备
+    %% ================================================================
+    subgraph 阶段一[阶段一:测评准备]
+        direction TB
+
+        P1["🏠 家长端:测评申请页"]:::page
+        P1 -->|"浏览测评材料"| A1["🔗 POST /api/dan-assessment/material/list"]:::api
+        A1 -->|"—"| S1["⚙️ AssessmentService.getMaterialList()"]:::service
+        S1 -->|"测评材料列表"| D1["📦 assessment_materials 表"]:::data
+
+        P1 -->|"获取当前材料"| A2["🔗 POST /api/dan-assessment/material/active"]:::api
+        A2 -->|"—"| S2["⚙️ AssessmentService.getActiveMaterial()"]:::service
+        S2 -->|"当前启用材料"| D1
+
+        P1 -->|"查询家庭测评状态"| A3["🔗 POST /api/dan-assessment/family/config"]:::api
+        A3 -->|"familyId"| S3["⚙️ AssessmentService.getFamilyConfig()"]:::service
+        S3 -->|"家庭测评配置(是否启用)"| D2["📦 family_assessment_config 表"]:::data
+
+        D2 -->|"未启用"| P1a["🏠 启用家庭测评"]:::page
+        P1a -->|"familyId, materialId"| A4["🔗 POST /api/dan-assessment/family/enable"]:::api
+        A4 -->|"familyId, materialId, remindMonths"| S4["⚙️ AssessmentService.enableFamilyAssessment()"]:::service
+        S4 -->|"写入启用配置"| D2
 
-    subgraph 预约管理
-        B7 --> C1[📱 创建预约<br/>page: apply<br/>/appointment/create<br/>消耗额度 · 生成执行记录]:::portMiniApp
-        C1 --> C2[📱 评估师列表<br/>page: apply<br/>/appointment/guide-list]:::portMiniApp
-        C2 --> C3[📱 我的预约列表<br/>page: execution<br/>/appointment/my-list]:::portMiniApp
-        C3 --> C4[📱 用户预约列表<br/>page: execution<br/>/appointment/user]:::portMiniApp
-        C4 --> C5[📋 规划师预约列表<br/>page: teacher/appointments<br/>/appointment/guide]:::portGuide
-        C5 --> C6[📋 预约确认<br/>page: teacher/appointments<br/>/appointment/confirm]:::portGuide
-        C6 --> C7[线下/线上执行测评]
-        C7 --> C8[📋 完成预约<br/>page: teacher/service-tasks<br/>/appointment/complete]:::portGuide
+        P1 -->|"查看可用额度"| A5["🔗 POST /api/assessment/quota/my-list"]:::api
+        A5 -->|"—"| S5["⚙️ AssessmentQuotaService.getMyQuotas()"]:::service
+        S5 -->|"剩余次数, 有效期"| D3["📦 assessment_quotas 表"]:::data
+
+        P1 -->|"额度详情"| A6["🔗 POST /api/assessment/quota/detail"]:::api
+        A6 -->|"quotaId"| S6["⚙️ AssessmentQuotaService.getDetail()"]:::service
+        S6 -->|"额度使用记录, 过期时间"| D3
     end
 
-    subgraph 执行与确认
-        C8 --> D1[📋 规划师完成任务<br/>page: teacher/service-tasks<br/>/dan-execution/complete]:::portGuide
-        D1 --> D2[📱 用户确认服务<br/>page: execution<br/>/dan-execution/confirm]:::portMiniApp
-        D2 --> D3[📱 执行详情<br/>page: execution<br/>/dan-execution/detail]:::portMiniApp
-        D3 --> D4[📱 用户评价<br/>page: rating<br/>/dan-execution/rate]:::portMiniApp
-        D4 --> D5[📱 我的执行记录<br/>page: execution<br/>/dan-execution/my-list]:::portMiniApp
-        D5 --> D6[📋 规划师待办<br/>page: teacher/service-tasks<br/>/dan-execution/guide/my-tasks]:::portGuide
+    %% ================================================================
+    %% 阶段二:下单与支付
+    %% ================================================================
+    subgraph 阶段二[阶段二:下单与支付]
+        D3 -->|"额度不足或需要新购"| P2["🏠 家长端:确认订单页"]:::page
+        P2 -->|"选择评估师"| A7["🔗 POST /api/assessment/appointment/assessor-list"]:::api
+        A7 -->|"—"| S7["⚙️ AssessmentAppointmentService.getAssessors()"]:::service
+        S7 -->|"可选评估师列表"| D_USER["📦 users 表(按角色teacher)"]:::data
+
+        P2 -->|"创建订单"| A8["🔗 POST /api/dan-assessment/order/create"]:::api
+        A8 -->|"familyId, childId, guideId, packageId, totalPrice, discountAmount"| S8["⚙️ AssessmentOrderService.createOrder()"]:::service
+        S8 -->|"写入订单, 状态=待支付"| D4["📦 assessment_orders 表"]:::data
+
+        P2 -->|"支付订单"| A9["🔗 POST /api/dan-assessment/order/pay"]:::api
+        A9 -->|"orderNo, payType"| S9["⚙️ AssessmentOrderService.payOrder()"]:::service
+        S9 -->|"更新订单状态=已支付, 生成额度"| D4
+
+        P2 -->|"查看订单详情"| A10["🔗 POST /api/dan-assessment/order/detail"]:::api
+        A10 -->|"orderNo"| S10["⚙️ AssessmentOrderService.getByOrderNo()"]:::service
+        S10 -->|"订单完整信息"| D4
+
+        P2 -->|"取消订单"| A11["🔗 POST /api/dan-assessment/order/cancel"]:::api
+        A11 -->|"orderNo"| S11["⚙️ AssessmentOrderService.cancelOrder()"]:::service
+        S11 -->|"更新订单状态=已取消"| D4
+
+        D4 -->|"支付成功"| A12["🔗 POST /api/dan-assessment/record/create"]:::api
+        A12 -->|"familyId, childId, materialId"| S12["⚙️ AssessmentService.createRecord()"]:::service
+        S12 -->|"创建测评记录, 进入预约流程"| D5["📦 assessment_records 表"]:::data
     end
 
-    subgraph 结果录入
-        D6 --> E1{结果来源}
-        E1 -->|评估师录入| E2[📋 录入测评结果<br/>page: teacher/service-tasks<br/>/result/record]:::portGuide
-        E1 -->|家长上传PDF| E3[📱 上传报告<br/>page: upload-report<br/>/result/upload<br/>async AI解析]:::portMiniApp
-        E1 -->|DAN PDF上传| E4[📱 上传预览<br/>page: dan-assessment/report-upload<br/>/report/parse-preview<br/>Phase 1 AI解析]:::portMiniApp
-        
-        E2 --> E5[⚙️ 结构化分析<br/>/results/:id/structured]:::portSystem
-        E3 --> E6[⚙️ AI解析完成 → 草稿]:::portSystem
-        E4 --> E7[⚙️ 预览解析结果]:::portSystem
-        
-        E7 --> E8[📱 确认入库<br/>page: dan-assessment/report-upload<br/>/report/confirm<br/>Phase 2]:::portMiniApp
-        E6 --> E9[📱 确认上传<br/>page: upload-report<br/>/result/:resultId/confirm-upload]:::portMiniApp
-        
-        E5 --> E10[📱 获取成长建议<br/>page: results<br/>/result/:resultId/guidance]:::portMiniApp
-        E10 --> E11[📋 保存成长建议<br/>/result/:resultId/guidance/save]:::portGuide
-        E8 --> E12[📱 孩子报告列表<br/>page: results<br/>/report/child]:::portMiniApp
-        E9 --> E12
+    %% ================================================================
+    %% 阶段三:预约管理
+    %% ================================================================
+    subgraph 阶段三[阶段三:预约管理]
+        D5 -->|"测评记录"| P3["🏠 家长端:预约页"]:::page
+        P3 -->|"创建预约"| A13["🔗 POST /api/assessment/appointment/create"]:::api
+        A13 -->|"childId, quotaId, guideId/assessorId, appointmentDate, notes"| S13["⚙️ AssessmentAppointmentService.createAppointment()"]:::service
+        S13 -->|"消耗额度, 创建预约+执行记录"| D6["📦 assessment_appointments + dan_assessment_executions 表"]:::data
+
+        P3 -->|"我的预约列表"| A14["🔗 POST /api/assessment/appointment/my-list"]:::api
+        A14 -->|"—"| S14["⚙️ AppointmentService.getByUserId()"]:::service
+        S14 -->|"该用户所有预约"| D6
+
+        D6 -->|"新预约, 状态=待确认"| P3a["📋 规划师端:预约管理页"]:::page
+        P3a -->|"查看待确认预约"| A15["🔗 POST /api/assessment/appointment/guide-list"]:::api
+        A15 -->|"userId(从token)"| S15["⚙️ AppointmentService.getByGuideId()"]:::service
+        S15 -->|"规划师相关预约列表"| D6
+
+        P3a -->|"确认预约"| A16["🔗 POST /api/assessment/appointment/confirm/{id}"]:::api
+        A16 -->|"path: id (预约ID)"| S16["⚙️ AppointmentService.confirmAppointment()"]:::service
+        S16 -->|"更新状态=已确认"| D6
+
+        P3a -->|"完成预约(线下执行后)"| A17["🔗 POST /api/dan-assessment/appointment/complete"]:::api
+        A17 -->|"id, teacherId"| S17["⚙️ AppointmentService.completeAppointment()"]:::service
+        S17 -->|"更新状态=已完成"| D6
     end
 
-    subgraph 独立报告流程
-        E12 --> F1[📱 上传独立PDF<br/>page: dan-assessment/report-upload<br/>/dan-report/upload]:::portMiniApp
-        F1 --> F2[📱 编辑草稿<br/>page: dan-assessment/report-upload<br/>/:id/edit]:::portMiniApp
-        F2 --> F3[📱 确认入库<br/>page: dan-assessment/report-upload<br/>/:id/confirm]:::portMiniApp
-        F3 --> F4[📱 完成分析<br/>page: dan-assessment/report-upload<br/>/:id/complete-analysis]:::portMiniApp
-        F4 --> F5[📱 报告详情<br/>page: dan-assessment/report-upload<br/>/:id]:::portMiniApp
-        F5 --> F6[📱 废弃草稿<br/>page: dan-assessment/report-upload<br/>/:id/discard]:::portMiniApp
-        F6 --> F7[📱 报告列表<br/>page: dan-assessment/report-upload<br/>/dan-report/list]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:执行与确认
+    %% ================================================================
+    subgraph 阶段四[阶段四:执行与确认]
+        D6 -->|"执行记录, 状态=待执行"| P4["📋 规划师端:待办任务页"]:::page
+        P4 -->|"查看待执行任务"| A18["🔗 POST /api/dan-execution/guide/my-tasks"]:::api
+        A18 -->|"plannerId"| S18["⚙️ DanAssessmentExecutionService.getByPlannerId()"]:::service
+        S18 -->|"规划师待执行任务列表"| D7["📦 dan_assessment_executions 表"]:::data
+
+        P4 -->|"完成服务"| A19["🔗 POST /api/dan-execution/complete"]:::api
+        A19 -->|"executionId, notes"| S19["⚙️ DanAssessmentExecutionService.completeExecution()"]:::service
+        S19 -->|"更新状态=已执行"| D7
+
+        D7 -->|"状态=已执行"| P4a["🏠 家长端:执行进度页"]:::page
+        P4a -->|"用户确认服务"| A20["🔗 POST /api/dan-execution/confirm"]:::api
+        A20 -->|"executionId"| S20["⚙️ DanAssessmentExecutionService.confirmExecution()"]:::service
+        S20 -->|"更新状态=已确认, 更新结算"| D7
+
+        P4a -->|"用户评价"| A21["🔗 POST /api/dan-execution/rate"]:::api
+        A21 -->|"executionId, assessorRating, plannerRating, assessorComment, plannerComment"| S21["⚙️ DanAssessmentExecutionService.rateService()"]:::service
+        S21 -->|"写入评价记录"| D8["📦 service_ratings 表"]:::data
+
+        P4a -->|"查看执行详情"| A22["🔗 POST /api/dan-execution/detail"]:::api
+        A22 -->|"executionId"| S22["⚙️ DanAssessmentExecutionService.getExecutionDetail()"]:::service
+        S22 -->|"执行详情(含结算)"| D7
+
+        P4a -->|"执行记录列表"| A23["🔗 POST /api/dan-execution/my-list"]:::api
+        A23 -->|"familyId"| S23["⚙️ DanAssessmentExecutionService.getByFamilyId()"]:::service
+        S23 -->|"该家庭所有执行记录"| D7
     end
 
-    subgraph 结果查询与对比
-        F7 --> G1[📱 最新测评结果<br/>page: results<br/>/assessment/latest-result]:::portMiniApp
-        G1 --> G2[📱 测评历史<br/>page: results<br/>/assessment/history]:::portMiniApp
-        G2 --> G3{📱 对比分析}:::portMiniApp
-        G3 -->|孩子整体对比| G4[📱 首次vs最新<br/>page: results<br/>/compare/by-child]:::portMiniApp
-        G3 -->|单维度变化| G5[📱 维度对比<br/>page: results<br/>/compare/by-child-dimension]:::portMiniApp
-        G3 -->|家庭对比| G6[📱 家庭对比<br/>page: results<br/>/compare/by-family]:::portMiniApp
-        G3 -->|综合分析| G7[📱 综合分析<br/>page: results<br/>/compare/narrative]:::portMiniApp
-        G4 --> G8[📱 我的报告列表<br/>page: growth/assessment-result<br/>/assessment/my-results]:::portMiniApp
-        G5 --> G8
-        G6 --> G8
-        G7 --> G8
-        G8 --> G9[📋 下级规划师报告<br/>/assessment/child-results]:::portGuide
+    %% ================================================================
+    %% 阶段五:结果录入
+    %% ================================================================
+    subgraph 阶段五[阶段五:结果录入]
+        D7 -->|"待录入结果"| P5_choice{"录入方式"}:::page
+
+        P5_choice -->|"规划师录入"| P5a["📋 规划师端:录入测评结果"]:::page
+        P5a -->|"提交结果"| A24["🔗 POST /api/dan-assessment/result/record"]:::api
+        A24 -->|"DanAssessmentResult(含维度得分, 分析报告)"| S24["⚙️ AssessmentService.recordResult()"]:::service
+        S24 -->|"写入结果, 状态=completed"| D9["📦 dan_assessment_results 表"]:::data
+
+        P5_choice -->|"家长上传PDF"| P5b["🏠 家长端:上传报告页"]:::page
+        P5b -->|"上传PDF"| A25["🔗 POST /api/dan-assessment/result/upload"]:::api
+        A25 -->|"file(Multipart), childId, notes"| S25["⚙️ FileStorageService.store() + ReportParseService.parseReport()"]:::service
+        S25 -->|"存储文件, 异步AI解析, 状态=draft"| D9
+
+        P5_choice -->|"DAN PDF上传"| P5c["🏠 家长端:DAN报告上传页"]:::page
+        P5c -->|"Phase1上传+预览"| A26["🔗 POST /api/dan-report/upload"]:::api
+        A26 -->|"file(Multipart), dimension, memberId"| S26["⚙️ DanReportUploadService.uploadAndParse()"]:::service
+        S26 -->|"上传+AI解析, 返回草稿"| D10["📦 dan_report_uploads 表"]:::data
+
+        D10 -->|"草稿ID"| P5d["🏠 编辑DAN报告草稿"]:::page
+        P5d -->|"编辑草稿"| A27["🔗 POST /api/dan-report/{id}/edit"]:::api
+        A27 -->|"path: id, DanReportEditDTO"| S27["⚙️ DanReportUploadService.editDraft()"]:::service
+        S27 -->|"更新草稿内容"| D10
+
+        P5d -->|"确认入库(Phase2)"| A28["🔗 POST /api/dan-report/{id}/confirm"]:::api
+        A28 -->|"path: id, childName, assessmentDate"| S28["⚙️ DanReportUploadService.confirmUpload()"]:::service
+        S28 -->|"状态=confirmed, 写入最终结果"| D9
+
+        P5d -->|"废弃草稿"| A29["🔗 POST /api/dan-report/{id}/discard"]:::api
+        A29 -->|"path: id"| S29["⚙️ DanReportUploadService.discardUpload()"]:::service
+        S29 -->|"状态=discarded"| D10
+
+        D9 -->|"结果ID"| P5e["📋 规划师端:结构化分析"]:::page
+        P5e -->|"获取结构化分析"| A30["🔗 POST /api/dan-assessment/results/{id}/structured"]:::api
+        A30 -->|"path: id"| S30["⚙️ 查询+组装结构化分析"]:::service
+        S30 -->|"结构化数据(维度得分, 分析报告)"| D9
+
+        P5e -->|"保存指导意见"| A31["🔗 POST /api/dan-assessment/result/{resultId}/guidance/save"]:::api
+        A31 -->|"path: resultId, items: [GrowthGuidance]"| S31["⚙️ GrowthGuidanceService.saveGuidances()"]:::service
+        S31 -->|"批量写入指导意见"| D11["📦 growth_guidances 表"]:::data
+
+        P5e -->|"查看指导意见"| A32["🔗 POST /api/dan-assessment/result/{resultId}/guidance"]:::api
+        A32 -->|"path: resultId"| S32["⚙️ GrowthGuidanceService.getByResultId()"]:::service
+        S32 -->|"指导意见列表"| D11
+
+        P5e -->|"确认上传(规划师确认家长上传)"| A33["🔗 POST /api/dan-assessment/result/{resultId}/confirm-upload"]:::api
+        A33 -->|"path: resultId, overallScore"| S33["⚙️ 更新状态=completed, 自动生成方案"]:::service
+        S33 -->|"状态=completed, 自动生成测评方案"| D9
     end
 
-    subgraph 家长端自评
-        G9 --> H1[📱 创建自评<br/>page: parent/self-assessment<br/>/parent/assessment/create]:::portMiniApp
-        H1 --> H2[📱 当前进度<br/>page: parent/self-assessment<br/>/parent/assessment/current]:::portMiniApp
-        H2 --> H3[📱 提交自评<br/>page: parent/self-assessment<br/>/parent/assessment/complete/:recordId]:::portMiniApp
-        H3 --> H4[📱 自评记录<br/>page: parent/self-assessment<br/>/parent/assessment/records]:::portMiniApp
+    %% ================================================================
+    %% 阶段六:结果查询与对比
+    %% ================================================================
+    subgraph 阶段六[阶段六:结果查询与对比]
+        D9 -->|"已完成的测评结果"| P6["🏠 家长端:测评报告页"]:::page
+        P6 -->|"最新结果"| A34["🔗 POST /api/assessment/latest-result"]:::api
+        A34 -->|"childId"| S34["⚙️ CognitiveService.getChildLatestResult()"]:::service
+        S34 -->|"最新一条completed结果"| D9
+
+        P6 -->|"历史记录"| A35["🔗 POST /api/assessment/history"]:::api
+        A35 -->|"childId, size"| S35["⚙️ 查询历史completed结果列表"]:::service
+        S35 -->|"测评历史(日期+综合得分)"| D9
+
+        P6 -->|"选择对比方式"| P6c{"孩子整体 / 单维度 / 家庭 / 综合分析"}:::page
+
+        P6c -->|"孩子首次vs最新"| A36["🔗 POST /api/assessment/compare/by-child"]:::api
+        A36 -->|"childId"| S36["⚙️ AssessmentComparisonService.compareByChild()"]:::service
+        S36 -->|"首次/最新结果对比数据"| D9
+
+        P6c -->|"单维度变化"| A37["🔗 POST /api/assessment/compare/by-child-dimension"]:::api
+        A37 -->|"childId, dimension"| S37["⚙️ AssessmentComparisonService.compareByDimension()"]:::service
+        S37 -->|"指定维度历年得分对比"| D9
+
+        P6c -->|"家庭对比"| A38["🔗 POST /api/assessment/compare/by-family"]:::api
+        A38 -->|"familyId"| S38["⚙️ AssessmentComparisonService.compareByFamily()"]:::service
+        S38 -->|"家庭内各成员结果对比"| D9
+
+        P6c -->|"综合分析"| A39["🔗 POST /api/assessment/compare/narrative"]:::api
+        A39 -->|"childId"| S39["⚙️ AssessmentComparisonService.narrativeAnalysis()"]:::service
+        S39 -->|"综合文本分析报告"| D9
+
+        P6 -->|"我的报告列表"| A40["🔗 POST /api/assessment/my-results"]:::api
+        A40 -->|"userId"| S40["⚙️ AssessmentService.getAccessibleResults()"]:::service
+        S40 -->|"可访问的测评报告列表"| D9
+
+        P6c -->|"结果详情"| A41["🔗 POST /api/dan-assessment/result/{id}"]:::api
+        A41 -->|"path: id"| S41["⚙️ AssessmentService.getByAppointmentId()"]:::service
+        S41 -->|"单条测评结果完整数据"| D9
     end
 
-    subgraph 规划师端评估管理
-        H4 --> I1[📋 家庭测评列表<br/>page: teacher/assessment<br/>/guide/assessment/families]:::portGuide
-        I1 --> I2[📋 家庭详情<br/>page: teacher/assessment<br/>/family/:familyId]:::portGuide
-        I2 --> I3[📋 启用/禁用<br/>page: teacher/assessment<br/>/family/:familyId/disable]:::portGuide
-        I3 --> I4[📋 培训计划<br/>page: teacher/assessment<br/>/guide/training-plans]:::portGuide
+    %% ================================================================
+    %% 阶段七:家长端自评
+    %% ================================================================
+    subgraph 阶段七[阶段七:家长端自评]
+        P6 -->|"创建自评"| P7["🏠 家长端:自评页"]:::page
+        P7 -->|"创建自评任务"| A42["🔗 POST /api/parent/assessment/create"]:::api
+        A42 -->|"userId(从token)"| S42["⚙️ AssessmentService.createRecord()"]:::service
+        S42 -->|"创建自评记录, 状态=进行中"| D5
+
+        P7 -->|"当前进度"| A43["🔗 POST /api/parent/assessment/current"]:::api
+        A43 -->|"userId(从token)"| S43["⚙️ AssessmentService.getFamilyConfig() + getActiveMaterial()"]:::service
+        S43 -->|"当前测评配置+材料信息"| D2
+
+        P7 -->|"提交自评"| A44["🔗 POST /api/parent/assessment/complete/{recordId}"]:::api
+        A44 -->|"path: recordId"| S44["⚙️ AssessmentService.completeRecord()"]:::service
+        S44 -->|"状态=已完成"| D5
+
+        P7 -->|"自评记录列表"| A45["🔗 POST /api/parent/assessment/records"]:::api
+        A45 -->|"userId(从token)"| S45["⚙️ AssessmentService.getFamilyRecords()"]:::service
+        S45 -->|"家庭所有测评记录"| D5
     end
 
-    %% 角色标注
-    RP1(("👤 家长")):::actor
-    RT(("📋 规划师/评估师")):::role
-    RS(("⚙️ AI解析引擎")):::system
+    %% ================================================================
+    %% 阶段八:规划师评估管理
+    %% ================================================================
+    subgraph 阶段八[阶段八:规划师评估管理]
+        P3a -->|"管理家庭测评"| P8["📋 规划师端:家庭测评管理页"]:::page
+        P8 -->|"家庭列表"| A46["🔗 POST /api/guide/assessment/families"]:::api
+        A46 -->|"teacherId(从token)"| S46["⚙️ AssessmentService.getFamiliesByTeacher()"]:::service
+        S46 -->|"该规划师管理的家庭测评配置"| D2
+
+        P8 -->|"家庭详情"| A47["🔗 POST /api/guide/assessment/family/{familyId}"]:::api
+        A47 -->|"path: familyId"| S47["⚙️ AssessmentService.getFamilyConfig()"]:::service
+        S47 -->|"指定家庭测评配置详情"| D2
+
+        P8 -->|"启用/禁用"| A48["🔗 POST /api/guide/assessment/family/{familyId}/disable"]:::api
+        A48 -->|"path: familyId"| S48["⚙️ AssessmentService.disableFamilyAssessment()"]:::service
+        S48 -->|"更新isEnabled=0"| D2
 
-    A1 -.- RP1
-    B1 -.- RT
-    C2 -.- RT
-    D1 -.- RT
+        P8 -->|"获取下级报告"| A49["🔗 POST /api/assessment/child-results"]:::api
+        A49 -->|"userId"| S49["⚙️ AssessmentService.getAccessibleResults()"]:::service
+        S49 -->|"下级规划师的测评报告"| D9
+
+        P8 -->|"测评材料列表"| A50["🔗 POST /api/guide/assessment/materials"]:::api
+        A50 -->|"—"| S50["⚙️ AssessmentService.getMaterialList()"]:::service
+        S50 -->|"可用测评材料"| D1
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P3
+    ROLE_PARENT -.- P4a
+    ROLE_PARENT -.- P5b
+    ROLE_PARENT -.- P5c
+    ROLE_PARENT -.- P6
+    ROLE_PARENT -.- P7
+    ROLE_GUIDE -.- P3a
+    ROLE_GUIDE -.- P4
+    ROLE_GUIDE -.- P5a
+    ROLE_GUIDE -.- P5e
+    ROLE_GUIDE -.- P8
+    ROLE_AI -.- S26
+    ROLE_AI -.- S25
 ```
 
 ## 端点明细
 
 ### 测评准备
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/dan-assessment/material/list` | 浏览测评材料 | 📱小程序 |
-| `/api/dan-assessment/material/active` | 获取当前启用材料 | 📱小程序 |
-| `/api/dan-assessment/family/enable` | 启用家庭测评 | 📱小程序 |
-| `/api/dan-assessment/family/disable` | 禁用家庭测评 | 📱小程序 |
-| `/api/dan-assessment/family/config` | 获取家庭测评配置 | 📱小程序 |
-| `/api/dan-assessment/points-config` | 获取积分配置 | 📱小程序 |
-| `/api/assessment/quota/my-list` | 我的可用额度列表 | 📱小程序 |
-| `/api/assessment/quota/detail` | 额度详情 | 📱小程序 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/dan-assessment/material/list` | 浏览测评材料 | 📱小程序 | — | `List<AssessmentMaterial>` |
+| `POST /api/dan-assessment/material/active` | 获取当前启用材料 | 📱小程序 | — | `AssessmentMaterial` |
+| `POST /api/dan-assessment/family/enable` | 启用家庭测评 | 📱小程序 | `{familyId, materialId, remindMonths}` | `{success}` |
+| `POST /api/dan-assessment/family/disable` | 禁用家庭测评 | 📱小程序 | `{familyId}` | `{success}` |
+| `POST /api/dan-assessment/family/config` | 获取家庭测评配置 | 📱小程序 | `familyId(Param)` | `FamilyAssessmentConfig` |
+| `POST /api/dan-assessment/points-config` | 获取积分配置 | 📱小程序 | — | `AssessmentPointsConfig` |
+| `POST /api/assessment/quota/my-list` | 我的可用额度列表 | 📱小程序 | — | `List<AssessmentQuotaVO>` |
+| `POST /api/assessment/quota/detail` | 额度详情 | 📱小程序 | `{quotaId}` | `AssessmentQuotaVO` |
 
 ### 下单与支付
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/dan-assessment/order/create` | 创建测评订单 | 📱小程序 |
-| `/api/dan-assessment/order/pay` | 支付订单 | 📱小程序 |
-| `/api/dan-assessment/order/detail` | 订单详情 | 📱小程序 |
-| `/api/dan-assessment/order/family` | 家庭订单列表 | 📱小程序 |
-| `/api/dan-assessment/order/cancel` | 取消订单 | 📱小程序 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/dan-assessment/order/create` | 创建测评订单 | 📱小程序 | `{familyId, userId, childId, guideId, packageId, guideName, packageName, totalPrice, discountAmount}` | `AssessmentOrder` |
+| `POST /api/dan-assessment/order/pay` | 支付订单 | 📱小程序 | `{orderNo, payType}` | `{success}` |
+| `POST /api/dan-assessment/order/detail` | 订单详情 | 📱小程序 | `orderNo(Param)` | `AssessmentOrder` |
+| `POST /api/dan-assessment/order/family` | 家庭订单列表 | 📱小程序 | `familyId(Param)` | `List<AssessmentOrder>` |
+| `POST /api/dan-assessment/order/cancel` | 取消订单 | 📱小程序 | `{orderNo}` | `{success}` |
+| `POST /api/dan-assessment/record/create` | 创建测评记录 | 📱小程序 | `{familyId, childId, materialId}` | `AssessmentRecord` |
+| `POST /api/dan-assessment/record/complete` | 完成测评记录 | 📱小程序 | `{recordId}` | `{success}` |
 
 ### 预约管理
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/dan-assessment/appointment/create` | 创建预约 | 📱小程序 |
-| `/api/dan-assessment/appointment/confirm` | 确认预约 | 📋规划师端 |
-| `/api/dan-assessment/appointment/complete` | 完成预约 | 📋规划师端 |
-| `/api/dan-assessment/appointment/cancel` | 取消预约 | 📱小程序 |
-| `/api/dan-assessment/appointment/user` | 用户预约列表 | 📱小程序 |
-| `/api/dan-assessment/appointment/guide` | 规划师预约列表 | 📋规划师端 |
-| `/api/assessment/appointment/create` | 创建评估预约(含执行记录) | 📱小程序 |
-| `/api/assessment/appointment/confirm/{id}` | 确认评估预约 | 📋规划师端 |
-| `/api/assessment/appointment/cancel/{id}` | 取消评估预约 | 📱小程序 |
-| `/api/assessment/appointment/guide-list` | 评估师可选列表 | 📱小程序 |
-| `/api/assessment/appointment/my-list` | 我的预约列表 | 📱小程序 |
-| `/api/assessment/appointment/assessor-list` | 评估师列表 | 📱小程序 |
-| `/api/assessment/appointment/user` | 用户端预约列表 | 📱小程序 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/dan-assessment/appointment/create` | 创建测评预约 | 📱小程序 | `{userId, childId, guideId, packageId, appointmentDate, appointmentTime, notes}` | `AssessmentAppointment` |
+| `POST /api/dan-assessment/appointment/confirm` | 确认预约 | 📋规划师端 | `{id, teacherId}` | `{success}` |
+| `POST /api/dan-assessment/appointment/complete` | 完成预约 | 📋规划师端 | `{id, teacherId}` | `{success}` |
+| `POST /api/dan-assessment/appointment/cancel` | 取消预约 | 📱小程序 | `{id}` | `{success}` |
+| `POST /api/dan-assessment/appointment/user` | 用户预约列表 | 📱小程序 | `{userId}` | `[AppointmentVO]` |
+| `POST /api/dan-assessment/appointment/guide` | 规划师预约列表 | 📋规划师端 | `guideId(Param)` | `List<AssessmentAppointment>` |
+| `POST /api/assessment/appointment/create` | 创建评估预约(含执行记录) | 📱小程序 | `{childId, quotaId, guideId/assessorId, appointmentDate, notes}` | `{appointmentId, executionId, quotaId}` |
+| `POST /api/assessment/appointment/confirm/{id}` | 确认评估预约 | 📋规划师端 | path: `id` | `{success}` |
+| `POST /api/assessment/appointment/cancel/{id}` | 取消评估预约 | 📱小程序 | path: `id` | `{success}` |
+| `POST /api/assessment/appointment/my-list` | 我的预约列表 | 📱小程序 | — | `[AppointmentVO]` |
+| `POST /api/assessment/appointment/guide-list` | 规划师预约列表 | 📋规划师端 | token: `role=teacher` | `[AppointmentVO]` |
+| `POST /api/assessment/appointment/assessor-list` | 评估师列表 | 📱小程序 | — | `[AppointmentVO]` |
 
 ### 执行与确认
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/dan-execution/complete` | 规划师完成服务 | 📋规划师端 |
-| `/api/dan-execution/confirm` | 用户确认服务完成 | 📱小程序 |
-| `/api/dan-execution/rate` | 用户评价服务 | 📱小程序 |
-| `/api/dan-execution/detail` | 执行详情(含结算) | 📱小程序/📋规划师端 |
-| `/api/dan-execution/my-list` | 用户执行记录 | 📱小程序 |
-| `/api/dan-execution/guide/my-tasks` | 规划师待执行任务 | 📋规划师端 |
-| `/api/dan-execution/by-order` | 按订单查询执行 | 📱小程序/📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/dan-execution/complete` | 规划师完成服务 | 📋规划师端 | `{executionId, notes}` | `{success}` |
+| `POST /api/dan-execution/confirm` | 用户确认服务完成 | 📱小程序 | `{executionId}` | `{success}` |
+| `POST /api/dan-execution/rate` | 用户评价服务 | 📱小程序 | `{executionId, assessorRating, plannerRating, ...}` | `ServiceRatingDTO` |
+| `POST /api/dan-execution/detail` | 执行详情(含结算) | 📱📋 | `{executionId}` | `ExecutionDetailResponse` |
+| `POST /api/dan-execution/my-list` | 用户执行记录 | 📱小程序 | `{familyId}` | `List<DanAssessmentExecution>` |
+| `POST /api/dan-execution/guide/my-tasks` | 规划师待执行任务 | 📋规划师端 | `{plannerId}` | `List<DanAssessmentExecution>` |
+| `POST /api/dan-execution/by-order` | 按订单查询执行 | 📱📋 | `{orderId}` | `DanAssessmentExecution` |
 
 ### 结果录入
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/dan-assessment/result/record` | 记录测评结果 | 📋规划师端 |
-| `/api/dan-assessment/result/upload` | 家长上传报告 | 📱小程序 |
-| `/api/dan-assessment/result/{id}` | 获取结果详情 | 📱小程序/📋规划师端 |
-| `/api/dan-assessment/result/{resultId}/confirm-upload` | 确认上传 | 📱小程序 |
-| `/api/dan-assessment/result/{resultId}/guidance` | 获取成长建议 | 📱小程序 |
-| `/api/dan-assessment/result/{resultId}/guidance/save` | 保存成长建议 | 📋规划师端 |
-| `/api/dan-assessment/results/{id}/structured` | 结构化分析 | ⚙️系统自动 |
-| `/api/dan-assessment/record/create` | 创建测评记录 | 📱小程序 |
-| `/api/dan-assessment/record/complete` | 完成测评记录 | 📋规划师端 |
-| `/api/dan-assessment/record/family` | 家庭测评记录列表 | 📱小程序 |
-| `/api/dan-assessment/record/current` | 当前测评 | 📱小程序 |
-
-### 报告上传(DanAssessmentController)
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/dan-assessment/report/parse-preview` | DAN PDF上传预览(Phase 1 AI解析) | 📱小程序 |
-| `/api/dan-assessment/report/confirm` | 确认入库(Phase 2) | 📱小程序 |
-| `/api/dan-assessment/report/child` | 孩子DAN报告列表 | 📱小程序 |
-
-### 独立报告流程(DanReportController)
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/dan-report/upload` | 上传独立PDF | 📱小程序 |
-| `/api/dan-report/{id}/edit` | 编辑草稿 | 📱小程序 |
-| `/api/dan-report/{id}/confirm` | 确认入库 | 📱小程序 |
-| `/api/dan-report/{id}/discard` | 废弃草稿 | 📱小程序 |
-| `/api/dan-report/{id}/complete-analysis` | 完成分析 | 📱小程序 |
-| `/api/dan-report/{id}` | 报告详情 | 📱小程序/📋规划师端 |
-| `/api/dan-report/list` | 报告列表 | 📱小程序/📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/dan-assessment/result/record` | 记录测评结果 | 📋规划师端 | `DanAssessmentResult(含维度得分, 分析报告)` | `DanAssessmentResult` |
+| `POST /api/dan-assessment/result/upload` | 家长上传报告 | 📱小程序 | `file(Multipart), childId, notes` | `DanAssessmentResult(draft)` |
+| `POST /api/dan-assessment/result/{id}` | 获取结果详情 | 📱📋 | path: `id` | `DanAssessmentResult` |
+| `POST /api/dan-assessment/result/{resultId}/confirm-upload` | 规划师确认上传 | 📋规划师端 | path: `resultId`, `{overallScore}` | `DanAssessmentResult` |
+| `POST /api/dan-assessment/result/{resultId}/guidance` | 获取指导意见 | 📱小程序 | path: `resultId` | `List<GrowthGuidance>` |
+| `POST /api/dan-assessment/result/{resultId}/guidance/save` | 保存指导意见 | 📋规划师端 | path: `resultId`, `{items: [GrowthGuidance]}` | `List<GrowthGuidance>` |
+| `POST /api/dan-assessment/results/{id}/structured` | 结构化分析 | ⚙️系统自动 | path: `id` | `{resultId, childName, assessmentDate, structuredAnalysis}` |
+| `POST /api/dan-assessment/my-results` | 我的测评报告列表 | 📱📋 | `{userId}` | `List<DanAssessmentResult>` |
+| `POST /api/dan-assessment/child-results` | 下级规划师报告 | 📋规划师端 | `{userId}` | `List<DanAssessmentResult>` |
+| `POST /api/dan-assessment/record/family` | 家庭测评记录列表 | 📱小程序 | `familyId(Param)` | `List<AssessmentRecord>` |
+| `POST /api/dan-assessment/record/current` | 当前测评 | 📱小程序 | `familyId(Param)` | `AssessmentRecord` |
+
+### DAN报告上传(DanReportController)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/dan-report/upload` | Phase1上传+AI解析 | 📱小程序 | `file(Multipart), dimension, memberId` | `{uploadId, parsedItems, ...}` |
+| `POST /api/dan-report/{id}/edit` | 编辑草稿 | 📱小程序 | path: `id`, `DanReportEditDTO` | `DanReportUploadVO` |
+| `POST /api/dan-report/{id}/confirm` | Phase2确认入库 | 📱小程序 | path: `id`, `{childName, assessmentDate}` | `DanReportUploadVO` |
+| `POST /api/dan-report/{id}/discard` | 废弃草稿 | 📱小程序 | path: `id` | `{success}` |
+| `POST /api/dan-report/{id}/complete-analysis` | 完成分析 | 📱小程序 | path: `id` | `{success}` |
+| `POST /api/dan-report/{id}` | 报告详情 | 📱📋 | path: `id` | `DanReportUploadVO` |
+| `POST /api/dan-report/list` | 报告列表 | 📱📋 | `{memberId, dimension}` | `List<DanReportUploadVO>` |
 
 ### 结果查询与对比
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/assessment/latest-result` | 孩子最新测评结果 | 📱小程序 |
-| `/api/assessment/history` | 测评历史记录 | 📱小程序 |
-| `/api/assessment/my-results` | 我的报告列表 | 📱小程序/📋规划师端 |
-| `/api/assessment/child-results` | 下级规划师报告 | 📋规划师端 |
-| `/api/assessment/compare/by-child` | 孩子首次vs最新对比 | 📱小程序 |
-| `/api/assessment/compare/by-child-dimension` | 孩子单维度变化对比 | 📱小程序 |
-| `/api/assessment/compare/by-family` | 家庭对比分析 | 📱小程序 |
-| `/api/assessment/compare/narrative` | 综合分析报告 | 📱小程序 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/assessment/latest-result` | 孩子最新测评结果 | 📱小程序 | `{childId}` | `AssessmentResultDTO` |
+| `POST /api/assessment/history` | 测评历史记录 | 📱小程序 | `{childId, size}` | `List<AssessmentHistoryItemDTO>` |
+| `POST /api/assessment/my-results` | 我的报告列表 | 📱📋 | token: `userId` | `List<DanAssessmentResult>` |
+| `POST /api/assessment/child-results` | 下级规划师报告 | 📋规划师端 | token: role检查 | `List<DanAssessmentResult>` |
+| `POST /api/assessment/compare/by-child` | 孩子首次vs最新对比 | 📱小程序 | `{childId}` | `{first, latest, changes}` |
+| `POST /api/assessment/compare/by-child-dimension` | 孩子单维度变化对比 | 📱小程序 | `{childId, dimension}` | `{dimension, trend, dataPoints}` |
+| `POST /api/assessment/compare/by-family` | 家庭对比分析 | 📱小程序 | `{familyId}` | `{members: [{childId, scores}]}` |
+| `POST /api/assessment/compare/narrative` | 综合分析报告 | 📱小程序 | `{childId}` | `{narrative, suggestions}` |
 
 ### 家长端自评
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/parent/assessment/create` | 创建家长自评 | 📱小程序 |
-| `/api/parent/assessment/current` | 当前自评进度 | 📱小程序 |
-| `/api/parent/assessment/complete/{recordId}` | 提交自评 | 📱小程序 |
-| `/api/parent/assessment/records` | 自评记录 | 📱小程序 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/parent/assessment/create` | 创建家长自评 | 📱小程序 | token: `userId` | `AssessmentRecord` |
+| `POST /api/parent/assessment/current` | 当前自评进度 | 📱小程序 | token: `userId` | `{configId, title, content, ...}` |
+| `POST /api/parent/assessment/complete/{recordId}` | 提交自评 | 📱小程序 | path: `recordId` | `{success}` |
+| `POST /api/parent/assessment/records` | 自评记录 | 📱小程序 | token: `userId` | `List<AssessmentRecord>` |
 
 ### 规划师端评估管理
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/assessment/families` | 家庭测评列表 | 📋规划师端 |
-| `/api/guide/assessment/family/{familyId}` | 家庭测评详情 | 📋规划师端 |
-| `/api/guide/assessment/family/{familyId}/disable` | 禁用家庭测评 | 📋规划师端 |
-
----
-
-## 前端页面映射与 UI 交互说明
-
-前端基于 uni-app (Vue 2, Options API) 微信小程序,页面路径均在 `pages/assessment/`、`pages/dan-assessment/`、`pages/growth/`、`pages/teacher/` 子包中。
-
-| 流程阶段 | 前端页面 | 页面路径 | 交互说明 |
-|---------|---------|---------|---------|
-| **测评准备** | 申请测评 | `pages/assessment/apply.vue` | 用户进入页面后可浏览测评材料说明、选择成长规划师(可选,由系统安排或指定规划师)、选择测评类型、选择预约日期时间。底部「申请测评」按钮触发下单流程。页面上方有额度概览入口。 |
-| | 我的额度 | `pages/assessment/quota.vue` | 展示已购买的测评任务模板及可用次数。每个额度卡片显示产品名称、使用进度条(已用/总数)、剩余次数、有效期。剩余次数 >0 且未过期时显示「预约测评」按钮。 |
-| **下单与支付** | 确认订单 | `pages/assessment/order.vue` | 展示订单详情:任务模板名称、成长规划师、预约日期时间。费用信息包含测评费用、优惠金额、实付金额。微信支付/支付宝两种支付方式,底部按钮显示实付金额。 |
-| **预约管理** | 执行进度 | `pages/assessment/execution.vue` | 用户端查看预约/执行记录。列表展示每条执行记录的状态和操作入口。状态包括:待确认、已确认、已完成。可在此页面确认服务完成。 |
-| | 预约管理(规划师端) | `pages/teacher/appointments.vue` | 规划师端管理预约列表,顶部状态筛选(全部/待确认/已确认/已完成)。每个预约卡片展示孩子ID、预约日期时间、备注。操作按钮:待确认→「确认预约」,已确认→「录入结果」,待确认→「取消」。 |
-| | 待办服务任务(规划师端) | `pages/teacher/service-tasks.vue` | 规划师端待办服务任务列表,展示任务ID、订单号、创建时间、评估师状态、规划师状态。点击进入任务详情,可完成任务执行或录入结果。 |
-| **执行与确认** | 执行进度 | `pages/assessment/execution.vue` | 用户端执行详情页:展示评估师和规划师完成状态。双方均完成时显示「确认服务」按钮。用户确认后显示「评价」入口。`canConfirm` 计算属性判断:评估师完成 && (规划师不存在或已完成)&& 用户未确认。 |
-| | 服务评价 | `pages/assessment/rating.vue` | 评价表单页:分别对评估师和规划师进行 1-5 星评分,每颗星有评价文本提示。可选输入文字评论,最长 500 字。支持仅评价其中一方。 |
-| **结果录入** | 上传报告 | `pages/assessment/upload-report.vue` | 选择孩子 → 选择文件(PDF/JPG/PNG)→ 添加备注 → 提交。调用 `uploadAssessmentReport` API 上传,支持 async AI 解析。解析完成后在结果列表显示「确认上传」按钮。 |
-| | DAN报告上传 | `pages/dan-assessment/report-upload.vue` | DAN 专用 PDF 上传页,两步流程:Phase 1 上传并预览 AI 解析结果 → Phase 2 确认入库。支持编辑草稿、废弃草稿、完成分析操作。完整的草稿生命周期管理。 |
-| **结果查询** | 测评报告 | `pages/assessment/results.vue` | 双 Tab 视图:「我的报告」和「下级报告」(规划师视角)。报告卡片展示孩子姓名、测评日期、综合得分、分析报告预览。点击进入详情页,可查看各维度得分和成长建议。 |
-| | 测评报告详情 | `pages/growth/assessment-result.vue` | 报告详情页:展示各维度得分(注意力/专注力/记忆力/逻辑思维)、综合得分、分析报告文本、成长建议。底部显示测评日期和测评ID。 |
-| **规划师端** | 预约管理 | `pages/teacher/appointments.vue` | 同上「预约管理(规划师端)」 |
-| | 待办服务任务 | `pages/teacher/service-tasks.vue` | 同上「待办服务任务(规划师端)」 |
-
-### 核心交互模式
-
-1. **家长端 → 规划师端流转**:家长提交申请 → 系统生成订单/预约 → 规划师在预约管理中确认 → 线下执行 → 规划师完成任务 → 家长确认并评价
-2. **结果录入双通道**:规划师直接录入(结构化数据)或家长上传 PDF(AI 解析 → 草稿 → 家长确认入库)
-3. **角色感知**:家长端页面 `pages/assessment/*` 仅家长角色可访问;规划师端 `pages/teacher/*` 仅 `role=teacher` 可访问
-4. **数据驱动**:页面通过 `onLoad(options)` 接收参数(如 `executionId`、`resultId`),调用 `/api/*` 接口获取渲染数据
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/assessment/families` | 家庭测评列表 | 📋规划师端 | token: `userId` | `[{familyId, isEnabled, materialTitle, ...}]` |
+| `POST /api/guide/assessment/family/{familyId}` | 家庭测评详情 | 📋规划师端 | path: `familyId` | `FamilyAssessmentConfig+材料信息` |
+| `POST /api/guide/assessment/family/{familyId}/disable` | 禁用家庭测评 | 📋规划师端 | path: `familyId` | `{success}` |
+| `POST /api/guide/assessment/materials` | 可用测评材料 | 📋规划师端 | — | `List<AssessmentMaterial>` |
+| `POST /api/guide/assessment/family/enable` | 为家庭启用测评 | 📋规划师端 | `{familyId, materialId, remindMonths}` | `{success}` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖测评准备、下单支付、预约管理、执行确认、结果录入(3种方式)、结果查询对比、家长自评、规划师管理8个阶段,测评全生命周期闭环 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 订单取消、预约取消、草稿废弃均已覆盖;额度不足时引导重新购买已覆盖;支付失败后重新支付未在图中展开(逻辑在Service层) |
+| 3 | **端点覆盖** | ✅ 完整 | 50个端点全部映射到流程图中,覆盖DanAssessmentController、AssessmentAppointmentController、DanAssessmentExecutionController、AssessmentReportController、AssessmentResultController、AssessmentComparisonController、DanReportController、ParentAssessmentController、GuideAssessmentController、AssessmentQuotaController |
+| 4 | **角色覆盖** | ✅ 完整 | 家长(申请/支付/确认/评价/查看)、规划师/评估师(确认预约/执行/录入结果/管理)、AI引擎(自动解析)三种角色均覆盖;管理员不在本图范围 |
+| 5 | **数据实体** | ✅ 完整 | assessment_materials、family_assessment_config、assessment_orders、assessment_quotas、assessment_records、assessment_appointments、dan_assessment_executions、dan_assessment_results、dan_report_uploads、growth_guidances、service_ratings均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配;DAN报告上传有Phase1→Phase2两阶段流程(DanReportController独立化后与DanAssessmentController兼容并存) |

+ 242 - 60
docs/flows/energy-system-flow.md

@@ -1,82 +1,264 @@
-# 用户使用流程图 — 五维能量沙盘
+# 用户使用流程图 — 五维能量系统
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取能量沙盘 /sandbox]:::portMiniApp
-        A2 --> A3[📱 获取五维概览 /overview]:::portMiniApp
-        A3 --> A4[📱 获取家庭五维聚合 /family-score-history]:::portMiniApp
-        A4 --> A5[📱 获取五维分数历史 /score-history]:::portMiniApp
-    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 actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3
+    classDef admin fill:#fce4ec,stroke:#d32f2f,stroke-width:1px,stroke-dasharray:5 3
+
+    %% ============ 角色 ============
+    USER(("👤 家长/孩子")):::actor
+    ADMIN(("🖥 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:能量沙盘与概览
+    %% ================================================================
+    subgraph 阶段一[阶段一:能量沙盘与概览]
+        direction TB
+
+        P1["🏠 能量沙盘页"]:::page
+        P1 -->|"userId → 查家庭"| A1["🔗 POST /api/energy/sandbox"]:::api
+        A1 -->|"userId"| S1["⚙️ EnergyService.calculateFamilyEnergy()"]:::service
+        S1 -->|"收集所有家长+孩子, 计算五维分值"| D1["📦 users + family_members + tasks + points_logs + 多源数据"]:::data
+        S1 -->|"持久化快照"| D1a["📦 five_dimension_scores 表(periodic快照)"]:::data
+        A1 -->|"家庭聚合 + 成员明细"| D1b["📦 EnergySandboxDTO(整体分+成员列表)"]:::data
+
+        P1 -->|"查看孩子概览"| P1a["🏠 五维概览页"]:::page
+        P1a -->|"childId"| A2["🔗 POST /api/energy/overview"]:::api
+        A2 -->|"childId"| S2["⚙️ EnergyService.getOverview()"]:::service
+        S2 -->|"该孩子各维度能量摘要"| D1c["📦 计算结果(维度分值+排名等)"]:::data
 
-    subgraph 能量流水
-        A5 --> B1[📱 查询能量流水 /logs]:::portMiniApp
-        B1 --> B2[📱 获取富维度详情 /wealth-detail]:::portMiniApp
+        P1 -->|"家庭聚合"| P1b["🏠 家庭五维聚合"]:::page
+        P1b -->|"familyId 或 userId"| A3["🔗 POST /api/energy/family-score-history"]:::api
+        A3 -->|"familyId"| S3["⚙️ FiveDimensionScoreService.getLatestByFamilyMap()"]:::service
+        S3 -->|"查询最近一次五维快照"| D1a
+
+        P1 -->|"维度历史曲线"| P1c["🏠 五维分数历史"]:::page
+        P1c -->|"memberId, memberType, dimensionCode"| A4["🔗 POST /api/energy/score-history"]:::api
+        A4 -->|"memberId, memberType, dimensionCode, limit"| S4["⚙️ FiveDimensionScoreService.getHistoryByMember()"]:::service
+        S4 -->|"按时间降序返回历史评分"| D1a
     end
 
-    subgraph 能量操作
-        A3 --> C1[📱 发放能量 /grant]:::portMiniApp
-        C1 --> C2[📱 心愿兑换扣除 /deduct-for-wish]:::portMiniApp
-        C2 --> C3[📱 配置来源比例 /configure]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:能量流水与明细
+    %% ================================================================
+    subgraph 阶段二[阶段二:能量流水与明细]
+        D1c -->|"childId"| P2["🏠 能量流水页"]:::page
+        P2 -->|"筛选维度, 分页"| A5["🔗 POST /api/energy/logs"]:::api
+        A5 -->|"childId, dimensionCode, page, size"| S5["⚙️ EnergyService.getLogs()"]:::service
+        S5 -->|"分页查询流水"| D2["📦 energy_log 表(变动量+余额+来源)"]:::data
+
+        P2 -->|"查看富维度"| P2a["🏠 富维度详情页"]:::page
+        P2a -->|"memberId, memberType"| A6["🔗 POST /api/energy/wealth-detail"]:::api
+        A6 -->|"memberId, memberType, userId"| S6["⚙️ EnergyService.calculateFamilyEnergy() 过滤"]:::service
+        S6 -->|"从家庭沙盘中提取指定成员"| D1b
     end
 
-    subgraph 维度管理
-        C3 --> D1[📱 获取维度概览 /overview]:::portMiniApp
-        D1 --> D2[📱 手动录入维度 /upload]:::portMiniApp
-        D2 --> D3[📱 问卷提交维度 /questionnaire]:::portMiniApp
-        D3 --> D4[📱 获取维度历史 /history]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:能量操作(发放/扣除/配置)
+    %% ================================================================
+    subgraph 阶段三[阶段三:能量操作]
+        D1a -->|"任务完成触发"| P3["⚙️ 系统:任务完成事件"]:::page
+        P3 -->|"childId, taskId, amount, dimensionCode"| A7["🔗 POST /api/energy/grant"]:::api
+        A7 -->|"childId, taskId, amount, dimensionCode"| S7["⚙️ EnergyService.grantEnergy()"]:::service
+        S7 -->|"按energy_source_config比例分配至各维度"| D3a["📦 energy_source_config 表(比例配置)"]:::data
+        S7 -->|"写入各维度流水+更新余额"| D3b["📦 energy_log + energy_balance 表"]:::data
+
+        P3 -->|"心愿兑换触发"| P3a["⚙️ 系统:心愿兑换事件"]:::page
+        P3a -->|"childId, wishId, amount"| A8["🔗 POST /api/energy/deduct-for-wish"]:::api
+        A8 -->|"childId, wishId, amount"| S8["⚙️ EnergyService.deductForWish()"]:::service
+        S8 -->|"从各维度按比例扣除能量"| D3b
+
+        P3 -->|"配置来源比例"| P3b["🏠 配置来源比例页"]:::page
+        P3b -->|"sourceType, sourceId, ratios[]"| A9["🔗 POST /api/energy/configure"]:::api
+        A9 -->|"sourceType, sourceId, sourceName, ratios"| S9["⚙️ EnergyService.configureSourceRatios()"]:::service
+        S9 -->|"写入/更新来源→维度比例"| D3a
     end
 
-    subgraph 年度能量
-        D4 --> E1[📱 获取年度五维能量 /energy]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:健康维度录入(7维)
+    %% ================================================================
+    subgraph 阶段四[阶段四:健康维度录入]
+        P1a -->|"查看7维健康"| P4["🏠 健康维度概览页"]:::page
+        P4 -->|"memberId"| A10["🔗 POST /api/dimension/overview"]:::api
+        A10 -->|"memberId"| S10["⚙️ DimensionScoreService.getHealthDimension()"]:::service
+        S10 -->|"七维健康指标+评分"| D4["📦 health_dimension_scores 表"]:::data
+
+        P4 -->|"手动录入"| P4a["🏠 录入表单"]:::page
+        P4a -->|"memberId, dimension, score, ..."| A11["🔗 POST /api/dimension/upload"]:::api
+        A11 -->|"DimensionUploadVO"| S11["⚙️ DimensionScoreService.uploadScore()"]:::service
+        S11 -->|"写入指定维度评分"| D4
+
+        P4 -->|"问卷提交"| P4b["🏠 问卷页"]:::page
+        P4b -->|"memberId, dimension, answers[]"| A12["🔗 POST /api/dimension/questionnaire"]:::api
+        A12 -->|"HealthDimensionQuestionnaireVO"| S12["⚙️ DimensionScoreService.submitQuestionnaire()"]:::service
+        S12 -->|"问卷答案→评分→写入"| D4
+
+        P4 -->|"历史记录"| P4c["🏠 历史趋势页"]:::page
+        P4c -->|"memberId, dimension, limit"| A13["🔗 POST /api/dimension/history"]:::api
+        A13 -->|"memberId, dimension, limit"| S13["⚙️ DimensionScoreService.getDimensionHistory()"]:::service
+        S13 -->|"该维度历史评分列表"| D4
     end
 
-    subgraph 家庭收入
-        C3 --> F1[📱 获取家庭收入汇总 /family/summary]:::portMiniApp
-        F1 --> F2[📱 获取成员收入 /family/members]:::portMiniApp
-        F2 --> F3[📱 获取收入记录 /family/records]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:年度能量(星座生肖)
+    %% ================================================================
+    subgraph 阶段五[阶段五:年度能量预测]
+        P1c -->|"查看年度能量"| P5["🏠 年度五维能量页"]:::page
+        P5 -->|"birthYear, birthMonth, birthDay, zodiac(选)"| A14["🔗 POST /api/zodiac/energy"]:::api
+        A14 -->|"出生年月日+生肖+目标年份"| S14["⚙️ ZodiacAnnualEnergyService.calculate()"]:::service
+        S14 -->|"西方星座+中国生肖+行星星座=五维偏差"| D5["📦 内存计算(无持久化)"]:::data
+        A14 -->|"body/mind/wisdom/action/wealth + 星座信息"| P5a["🏠 展示年度五维能量"]:::page
     end
 
-    R1(("👤 家长/孩子")):::actor
-    R2(("🌍 五维引擎")):::system
+    %% ================================================================
+    %% 阶段六:维度权重配置(管理后台)
+    %% ================================================================
+    subgraph 阶段六[阶段六:维度权重配置]
+        P6["🖥 管理后台:权重配置页"]:::admin
+        P6 -->|"targetType, targetId, weights[]"| A15["🔗 POST /api/admin/dimension-weight/save"]:::api
+        A15 -->|"目标类型+ID+维度权重列表"| S15["⚙️ DimensionWeightService.saveWeights()"]:::service
+        S15 -->|"覆盖写入维度权重"| D6["📦 dimension_weights 表"]:::data
+
+        P6 -->|"查看配置"| A16["🔗 POST /api/admin/dimension-weight/list"]:::api
+        A16 -->|"targetType, targetId"| S16["⚙️ DimensionWeightService.getByTarget()"]:::service
+        S16 -->|"该目标的所有维度权重"| D6
+    end
 
-    A1 -.- R1
-    A2 -.- R2
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    USER -.- P1
+    USER -.- P2
+    USER -.- P3b
+    USER -.- P4
+    USER -.- P5
+    ADMIN -.- P6
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/energy/sandbox` | 获取能量沙盘 | 📱小程序 |
-| `/api/energy/overview` | 获取五维概览 | 📱小程序 |
-| `/api/energy/logs` | 查询能量流水 | 📱小程序 |
-| `/api/energy/grant` | 发放能量 | 📱小程序 |
-| `/api/energy/deduct-for-wish` | 心愿扣除能量 | 📱小程序 |
-| `/api/energy/configure` | 配置来源比例 | 📱小程序 |
-| `/api/energy/score-history` | 五维分数历史 | 📱小程序 |
-| `/api/energy/family-score-history` | 家庭五维聚合 | 📱小程序 |
-| `/api/energy/wealth-detail` | 富维度详情 | 📱小程序 |
-| `/api/energy/seed` | 生成种子数据 | ⚙️系统自动 |
-| `/api/zodiac/energy` | 年度五维能量 | 📱小程序 |
-| `/api/dimension/overview` | 维度概览 | 📱小程序 |
-| `/api/dimension/upload` | 手动录入维度 | 📱小程序 |
-| `/api/dimension/questionnaire` | 问卷提交 | 📱小程序 |
-| `/api/dimension/history` | 维度历史 | 📱小程序 |
-| `/api/earnings/family/summary` | 家庭收入汇总 | 📱小程序 |
-| `/api/earnings/family/members` | 成员收入 | 📱小程序 |
-| `/api/earnings/family/records` | 收入记录 | 📱小程序 |
+### 能量沙盘与概览
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/energy/sandbox` | 获取家庭能量沙盘 | 📱小程序 | Header: `Authorization` | `EnergySandboxDTO`(家庭聚合分+成员明细) |
+| `POST /api/energy/overview` | 获取孩子五维概览 | 📱小程序 | `{childId}` | `Map`(各维度分值+排名) |
+| `POST /api/energy/family-score-history` | 获取家庭五维聚合 | 📱小程序 | `{familyId}` 或 `{userId}` | `Map<String, Integer>`(五维最新分) |
+| `POST /api/energy/score-history` | 获取五维分数历史 | 📱小程序 | `{memberId, memberType, dimensionCode, limit?}` | `List<FiveDimensionScore>` |
+| `POST /api/energy/wealth-detail` | 获取富维度详情 | 📱小程序 | `{memberId, memberType}` | `MemberEnergyDTO`(含收入/成就/人脉子分) |
+
+### 能量流水
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/energy/logs` | 查询能量流水(分页) | 📱小程序 | `{childId, dimensionCode?, page, size}` | `Page<EnergyLog>` |
+| `POST /api/energy/seed` | 生成种子数据 | ⚙️系统自动 | — | — |
+
+### 能量操作
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/energy/grant` | 发放能量(任务完成) | ⚙️系统自动 | `{childId, taskId, amount, dimensionCode?}` | `EnergyLog` |
+| `POST /api/energy/deduct-for-wish` | 心愿兑换扣除能量 | ⚙️系统自动 | `{childId, wishId, amount}` | `{success}` |
+| `POST /api/energy/configure` | 配置来源比例 | 📱小程序 | `{sourceType, sourceId, sourceName, ratios[]}` | `"配置成功"` |
+
+### 健康维度
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/dimension/overview` | 获取健康维度概览 | 📱小程序 | `{memberId}` | `HealthDimensionVO`(7维健康指标) |
+| `POST /api/dimension/upload` | 手动录入维度评分 | 📱小程序 | `{memberId, dimension, score, ...}` | `null` |
+| `POST /api/dimension/questionnaire` | 问卷提交维度评分 | 📱小程序 | `{memberId, dimension, answers[]}` | `null` |
+| `POST /api/dimension/history` | 获取维度历史记录 | 📱小程序 | `{memberId, dimension, limit?}` | `List<DimensionItem>` |
+
+### 年度能量
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/zodiac/energy` | 获取年度五维能量 | 📱小程序 | `{birthYear, birthMonth, birthDay, zodiac?, year?}` | `{westernSign, zodiacCode, dimensions: {body,mind,...}}` |
+
+### 维度权重配置(管理后台)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/dimension-weight/save` | 保存维度权重 | 🖥管理后台 | `{targetType, targetId, weights: [{dimension, weight, enabled}]}` | `null` |
+| `POST /api/admin/dimension-weight/list` | 查询维度权重 | 🖥管理后台 | `{targetType, targetId}` | `List<DimensionWeight>` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    EnergyDimension {
+        Long id PK
+        string code "body/mind/wisdom/action/wealth"
+        string name "身/心/智/行/富"
+        string element "土/火/金/木/水"
+        int sortOrder
+        int status "1启用/0禁用"
+    }
+
+    EnergySourceConfig {
+        Long id PK
+        string sourceType "task/activity/course/product"
+        Long sourceId "业务表ID"
+        string sourceName
+        Long dimensionId FK "维度ID"
+        int ratio "占比如6000=60%"
+    }
+
+    EnergyLog {
+        Long id PK
+        Long childId FK "孩子ID"
+        Long dimensionId FK "维度ID"
+        int amount "正=获得,负=消耗"
+        int balanceAfter "变动后余额"
+        string sourceType "task/product/..."
+        Long sourceId "来源ID"
+        date expiresAt "过期时间"
+    }
+
+    FiveDimensionScore {
+        Long id PK
+        Long memberId "成员ID"
+        string memberType "user/member"
+        Long familyId
+        string dimensionCode "body/mind/wisdom/action/wealth"
+        int score "0-100"
+        string sourceType "periodic/task/assessment/manual"
+        string detailJson "细分项快照"
+    }
+
+    DimensionWeight {
+        Long id PK
+        string targetType "activity/product/article"
+        Long targetId
+        string dimension "body/mind/wisdom/action/wealth"
+        int weight "百分比"
+        bool enabled
+    }
+
+    EnergyDimension ||--o{ EnergySourceConfig : "维度被引用"
+    EnergyDimension ||--o{ EnergyLog : "维度流水"
+    EnergyDimension ||--o{ FiveDimensionScore : "维度历史"
+    EnergyDimension ||--o{ DimensionWeight : "维度权重"
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖能量系统六大功能域:沙盘概览(查)、流水明细(查)、发放扣除(写)、维度录入(健康7维)、年度预测(星座生肖)、权重配置(管理后台) |
+| 2 | **异常路径** | ✅ 完整 | 家庭无成员时返回空DTO;健康报告查询异常时降级为任务完成率计算;维度评分持久化失败仅记warn不中断主流程 |
+| 3 | **端点覆盖** | ✅ 完整 | 16个端点全部映射到流程图,与`EnergyController`、`HealthDimensionController`、`ZodiacEnergyController`、`DimensionWeightController`中的`@PostMapping`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长/孩子(查看能量沙盘+维度录入)、系统自动(发放/扣除)、管理员(维度权重配置)各有独立入口 |
+| 5 | **数据实体** | ✅ 完整 | energy_dimension(维度定义)、energy_source_config(比例配置)、energy_log(流水)、energy_balance(余额)、five_dimension_scores(历史快照)、dimension_weights(权重) 全部在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 能量计算引擎集成多数据源:tasks/points_logs/game_records/dan_assessment_results/article_reading_records/health_reports,通过`calculateFamilyEnergy`统一聚合 |

+ 254 - 50
docs/flows/extra-features-flow.md

@@ -1,76 +1,280 @@
 # 用户使用流程图 — 其他功能
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 设置吉祥物 /user/mascot/set]:::portMiniApp
-        A2 --> A3[📱 获取吉祥物 /user/mascot/get]:::portMiniApp
+    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 actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长/孩子")):::actor
+    ROLE_ADMIN(("🖥 管理员")):::actor
+    ROLE_SYSTEM(("⚙️ 系统")):::actor
+
+    %% ================================================================
+    %% 阶段一:用户吉祥物
+    %% ================================================================
+    subgraph 阶段一[阶段一:用户吉祥物]
+        direction TB
+
+        P1["🏠 个人中心:吉祥物设置"]:::page
+        P1 -->|"选择 xibao/fubao"| A1["🔗 POST /api/user/mascot/set"]:::api
+        A1 -->|"userId, 吉祥物代码"| S1["⚙️ UserService.setMascot()"]:::service
+        S1 -->|"更新用户 mascot 字段"| D1["📦 users 表"]:::data
+
+        P1 -->|"查看当前吉祥物"| A1a["🔗 POST /api/user/mascot/get"]:::api
+        A1a -->|"userId"| S1a["⚙️ UserService.getUserInfo()"]:::service
+        S1a -->|"mascot 字段值"| D1
     end
 
-    subgraph 用户分群
-        A3 --> B1[📱 RFM计算 /segmentation/rfm/calculate]:::portMiniApp
-        B1 --> B2[📱 RFM详情 /segmentation/rfm/detail]:::portMiniApp
-        B2 --> B3[📱 触发规则 /segmentation/trigger/rules]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:用户分群(RFM)
+    %% ================================================================
+    subgraph 阶段二[阶段二:用户分群(RFM)]
+        direction TB
+
+        P2["🏠 系统后台:用户分群页"]:::page
+        P2 -->|"触发RFM计算"| A2["🔗 POST /api/segmentation/rfm/calculate"]:::api
+        A2 -->|"userId"| S2["⚙️ UserSegmentationService.calculateRfm()"]:::service
+        S2 -->|"R/F/M 分值 + 层级标签"| D2["📦 user_rfm_tags 表"]:::data
+
+        D2 -->|"userId"| A2a["🔗 POST /api/segmentation/rfm/detail"]:::api
+        A2a -->|"userId"| S2a["⚙️ UserSegmentationService.getUserRfm()"]:::service
+        S2a -->|"RFM 详细数据"| D2
+
+        D2 -->|"分群结果"| A2b["🔗 POST /api/segmentation/trigger/rules"]:::api
+        A2b -->|"userId, triggerType"| S2b["⚙️ UserSegmentationService.getTriggerRules()"]:::service
+        S2b -->|"触发规则列表"| D2b["📦 user_trigger_rules 表"]:::data
     end
 
-    subgraph 外部同步
-        B3 --> C1[📱 同步客户到zkxz /sncp/addClient/:clientId]:::portMiniApp
-        C1 --> C2[📱 获取通知 /sncp/notice/:userLogin]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:外部平台同步
+    %% ================================================================
+    subgraph 阶段三[阶段三:外部平台同步(zkxz)]
+        direction TB
+
+        P3["🏠 系统自动:定时同步"]:::page
+        P3 -->|"客户ID"| A3["🔗 POST /api/sncp/addClient/{clientId}"]:::api
+        A3 -->|"clientId"| S3["⚙️ ZkxzSyncService.syncClient()"]:::service
+        S3 -->|"同步结果"| D3["📦 zkxz 外部平台"]:::data
+
+        P3 -->|"用户登录名"| A3a["🔗 POST /api/sncp/notice/{userLogin}"]:::api
+        A3a -->|"userLogin"| S3a["⚙️ ZkxzSyncService(通知查询)"]:::service
+        S3a -->|"通知内容"| D3
     end
 
-    subgraph 每日反馈
-        C2 --> D1[📱 获取今日反馈 /feedback/today]:::portMiniApp
-        D1 --> D2[📱 标记已读 /feedback/read]:::portMiniApp
-        D2 --> D3[📱 获取最近反馈 /feedback/recent]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:每日反馈
+    %% ================================================================
+    subgraph 阶段四[阶段四:每日反馈]
+        direction TB
+
+        P4["🏠 家长端:今日反馈页"]:::page
+        P4 -->|"查看今日反馈"| A4["🔗 POST /api/feedback/today"]:::api
+        A4 -->|"userId, childId"| S4["⚙️ DailyFeedbackService.getTodayFeedback()"]:::service
+        S4 -->|"当日反馈内容(无则自动生成)"| D4["📦 daily_feedback 表"]:::data
+
+        D4 -->|"标记已读"| A4a["🔗 POST /api/feedback/read"]:::api
+        A4a -->|"feedback id"| S4a["⚙️ DailyFeedbackService.markAsRead()"]:::service
+        S4a -->|"is_read = 1"| D4
+
+        D4 -->|"查看历史"| A4b["🔗 POST /api/feedback/recent"]:::api
+        A4b -->|"childId, limit"| S4b["⚙️ DailyFeedbackService.getRecentFeedbacks()"]:::service
+        S4b -->|"最近N条反馈列表"| D4
     end
 
-    subgraph 健康互动
-        D3 --> E1[📱 点赞 /health/interact/like]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:健康互动(点赞)
+    %% ================================================================
+    subgraph 阶段五[阶段五:健康互动(点赞)]
+        direction TB
+
+        P5["🏠 家长端:健康互动页"]:::page
+        P5 -->|"点赞家庭成员"| A5["🔗 POST /api/health/interact/like"]:::api
+        A5 -->|"userId, toUserId, actionType, actionId, familyId"| S5["⚙️ HealthInteractionService.like()"]:::service
+        S5 -->|"写入互动记录"| D5["📦 health_interaction 表"]:::data
     end
 
-    subgraph 商品推荐
-        E1 --> F1[📱 维度页推荐 /recommend/dimension-products]:::portMiniApp
+    %% ================================================================
+    %% 阶段六:商品推荐
+    %% ================================================================
+    subgraph 阶段六[阶段六:商品推荐]
+        direction TB
+
+        P6["🏠 五维维度页:推荐商品"]:::page
+        P6 -->|"按维度查看推荐"| A6["🔗 POST /api/recommend/dimension-products"]:::api
+        A6 -->|"dimensionCode, familyId, memberId, limit"| S6["⚙️ ProductRecommendationService.getDimensionRecommendations()"]:::service
+        S6 -->|"维度关联商品列表"| D6["📦 products 表(商品查询)"]:::data
     end
 
-    subgraph 通用工具
-        F1 --> G1[📱 生成小程序码 /common/qrcode]:::portMiniApp
+    %% ================================================================
+    %% 阶段七:通用工具
+    %% ================================================================
+    subgraph 阶段七[阶段七:通用工具]
+        direction TB
+
+        P7["🏠 邀请页:生成小程序码"]:::page
+        P7 -->|"邀请注册"| A7["🔗 POST /api/common/qrcode"]:::api
+        A7 -->|"type=register, referralCode"| S7["⚙️ WechatService.generateWxacode()"]:::service
+        S7 -->|"base64 小程序码图片"| D7["📦 微信服务器(临时素材)"]:::data
     end
 
-    R1(("👤 用户")):::actor
+    %% ================================================================
+    %% 阶段八:新手引导
+    %% ================================================================
+    subgraph 阶段八[阶段八:新手引导]
+        direction TB
+
+        P8["🏠 新手引导页"]:::page
+        P8 -->|"查看引导进度"| A8["🔗 POST /api/onboarding/progress"]:::api
+        A8 -->|"userId"| S8["⚙️ OnboardingService.getProgress()"]:::service
+        S8 -->|"引导任务列表及状态"| D8["📦 onboarding_task 表"]:::data
 
-    A1 -.- R1
+        D8 -->|"完成任务领取奖励"| A8a["🔗 POST /api/onboarding/claim"]:::api
+        A8a -->|"userId, taskType"| S8a["⚙️ OnboardingService.claimReward()"]:::service
+        S8a -->|"发放积分/能量,更新状态"| D8
+    end
+
+    %% ============ 角色关联 ============
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P4
+    ROLE_PARENT -.- P5
+    ROLE_PARENT -.- P6
+    ROLE_PARENT -.- P7
+    ROLE_PARENT -.- P8
+    ROLE_ADMIN -.- P2
+    ROLE_SYSTEM -.- P3
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/user/mascot/set` | 设置吉祥物 | 📱小程序 |
-| `/api/user/mascot/get` | 获取吉祥物 | 📱小程序 |
-| `/api/segmentation/rfm/calculate` | RFM计算 | 📱小程序 |
-| `/api/segmentation/rfm/detail` | RFM详情 | 📱小程序 |
-| `/api/segmentation/trigger/rules` | 触发规则 | 📱小程序 |
-| `/api/sncp/addClient/{clientId}` | 同步客户 | 📱小程序 |
-| `/api/sncp/notice/{userLogin}` | 获取通知 | 📱小程序 |
-| `/api/feedback/today` | 今日反馈 | 📱小程序 |
-| `/api/feedback/read` | 标记已读 | 📱小程序 |
-| `/api/feedback/recent` | 最近反馈 | 📱小程序 |
-| `/api/health/interact/like` | 点赞 | 📱小程序 |
-| `/api/recommend/dimension-products` | 维度推荐 | 📱小程序 |
-| `/api/common/qrcode` | 生成小程序码 | 📱小程序 |
-| `/api/onboarding/progress` | 引导进度 | 📱小程序 |
-| `/api/onboarding/claim` | 领取奖励 | 📱小程序 |
+### 用户吉祥物
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/user/mascot/set` | 设置吉祥物 | 📱小程序 | `{mascot: "xibao" | "fubao" \| null}` | `{success}` |
+| `POST /api/user/mascot/get` | 获取当前吉祥物 | 📱小程序 | — | `{mascot}` |
+
+### 用户分群
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/segmentation/rfm/calculate` | 计算RFM标签 | ⚙️系统自动 | — | `UserRfmTag(R/F/M分值+tier)` |
+| `POST /api/segmentation/rfm/detail` | 获取RFM详情 | 📱小程序 | — | `UserRfmTag对象` |
+| `POST /api/segmentation/trigger/rules` | 获取触发规则 | 📱小程序 | `{triggerType}` | `List<UserTriggerRule>` |
+
+### 外部同步(zkxz)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/sncp/addClient/{clientId}` | 同步客户到zkxz | ⚙️系统自动 | path: `clientId` | `同步结果` |
+| `POST /api/sncp/notice/{userLogin}` | 获取zkxz通知 | ⚙️系统自动 | path: `userLogin` | `通知内容` |
+
+### 每日反馈
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/feedback/today` | 获取今日反馈 | 📱小程序 | `{childId}` | `{feedback, hasFeedback}` |
+| `POST /api/feedback/read` | 标记反馈已读 | 📱小程序 | `{id}` | `{ok}` |
+| `POST /api/feedback/recent` | 获取最近反馈列表 | 📱小程序 | `{childId, limit}` | `List<DailyFeedback>` |
+
+### 健康互动
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/interact/like` | 点赞家庭成员 | 📱小程序 | `{toUserId, actionType, actionId, familyId}` | `Void` |
+
+### 商品推荐
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/recommend/dimension-products` | 维度页推荐商品 | 📱小程序 | `{dimensionCode, familyId, memberId, limit, excludeProductIds}` | `List<推荐商品>` |
+
+### 通用工具
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/common/qrcode` | 生成小程序码 | 📱小程序 | `{type, referralCode}` | `{qrCodeBase64}` |
+
+### 新手引导
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/onboarding/progress` | 获取引导进度 | 📱小程序 | — | `List<OnboardingTask>` |
+| `POST /api/onboarding/claim` | 领取引导奖励 | 📱小程序 | `{taskType}` | `{success}` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    User ||--o{ UserRfmTag : "userId 关联"
+    User ||--o{ UserTriggerRule : "userId 关联"
+    User ||--o{ OnboardingTask : "userId 关联"
+    FamilyMember ||--o{ DailyFeedback : "childId 关联"
+    FamilyMember ||--o{ HealthInteraction : "toUserId 关联"
+
+    UserRfmTag {
+        Long id PK
+        Long userId FK
+        int rScore "最近消费"
+        int fScore "消费频率"
+        int mScore "消费金额"
+        string rfmTier "RFM层级标签"
+    }
+
+    UserTriggerRule {
+        Long id PK
+        Long userId FK
+        string triggerType
+        string triggerAction
+        string actionConfig
+        string status
+    }
+
+    DailyFeedback {
+        Long id PK
+        Long userId FK
+        Long childId FK
+        date feedbackDate
+        string feedbackType "daily/weekly/milestone"
+        string content
+        int isRead
+        string source "ai_generated/preset"
+    }
+
+    HealthInteraction {
+        Long id PK
+        Long familyId
+        Long fromUserId
+        Long toUserId
+        string actionType
+        Long actionId
+    }
+
+    OnboardingTask {
+        Long id PK
+        Long userId FK
+        string taskType
+        int rewardPoints
+        int rewardEnergy
+        string status
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖8个独立功能模块:吉祥物设置、RFM分群、外平台同步、每日反馈、健康互动、商品推荐、小程序码生成、新手引导,均为独立流程 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 各模块边界校验在Service层处理(如吉祥物仅允许xibao/fubao、PDF格式校验、zkxz启用检查),流程图简化了异常分支 |
+| 3 | **端点覆盖** | ✅ 完整 | 16个端点全部映射到流程图中,与实际Controller代码一致(UserMascotController、UserSegmentationController、ZkxzSyncController、DailyFeedbackController、HealthInteractionController、ProductRecommendationController、CommonController、OnboardingController) |
+| 4 | **角色覆盖** | ✅ 完整 | 家长/孩子使用吉祥物、反馈、互动、推荐、引导功能;管理员使用RFM用户分群;系统自动触发zkxz同步 |
+| 5 | **数据实体** | ✅ 完整 | 覆盖users、user_rfm_tags、user_trigger_rules、daily_feedback、health_interaction、onboarding_task共6个数据表 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的@PostMapping匹配,参数与Controller入参一致 |

+ 327 - 153
docs/flows/family-management-flow.md

@@ -1,186 +1,360 @@
 # 用户使用流程图 — 家庭管理
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 创建新家庭 /user/create-family]:::portMiniApp
-        A2 -->|有| A4[📱 加入其他家庭 /user/join-family]:::portMiniApp
-        A3 --> A5[📱 生成邀请链接 /invite/generate]:::portMiniApp
-        A5 --> A6[📱 生成二维码 /invite/qrcode]:::portMiniApp
-        A6 --> A7[📱 查看邀请码 /invite-code]:::portMiniApp
-        A7 --> A8[📱 生成新邀请码 /invite-code/generate]:::portMiniApp
-        A4 --> A9[📱 通过邀请码加入 /invite/accept-by-code]:::portMiniApp
-        A8 --> A10[📱 校验邀请令牌 /invite/validate]:::portMiniApp
-        A10 --> A11[📱 接受邀请 /invite/accept]:::portMiniApp
-        A11 --> A12[📱 查询家庭状态 /invite/check-family]:::portMiniApp
-    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
 
-    subgraph 用户与角色管理
-        A12 --> B1[📱 用户信息 /user/info · 更新 /user/update]:::portMiniApp
-        B1 --> B2[📱 角色列表 /user/roles]:::portMiniApp
-        B2 --> B3{📱 切换模式}:::portMiniApp
-        B3 -->|切换角色| B4[📱 切换 /user/switch-role]:::portMiniApp
-        B3 -->|切换模式| B5[📱 切换模式 /user/switch-mode]:::portMiniApp
-        B3 -->|切换到孩子| B6[📱 切换到孩子 /user/switch-to-child]:::portMiniApp
-        B6 --> B7[📱 切换回家长 /user/switch-back-to-parent]:::portMiniApp
-        B7 --> B8[📱 切换验证 /user/switch-back-verify]:::portMiniApp
-    end
+    %% ============ 角色 ============
+    A0(("👤 家长")):::actor
+    B0(("👶 孩子")):::actor
+    C0(("📋 规划师")):::actor
 
-    subgraph 家庭成员管理
-        B8 --> C1[📱 添加成员 /member/add]:::portMiniApp
-        C1 --> C2[📱 成员列表 /member/list<br/>可见成员 /user/members/visible]:::portMiniApp
-        C2 --> C3[📱 更新信息 /member/update<br/>孩子更新 /user/children/update]:::portMiniApp
-        C3 --> C4[📱 更新可见性 /user/members/update-visibility]:::portMiniApp
-        C4 --> C5[📱 切换成员视图 /member/switch]:::portMiniApp
-        C5 --> C6[📱 检查可编辑性 /member/editable]:::portMiniApp
-        C6 --> C7[📱 踢出成员 /member/kick · /user/kick]:::portMiniApp
-        C7 --> C8[📱 变更日志 /member/logs]:::portMiniApp
-    end
+    %% ================================================================
+    %% 阶段一:家庭创建与加入
+    %% ================================================================
+    subgraph 阶段一[阶段一:家庭创建与加入]
+        P1["🏠 小程序:家庭首页"]:::page
+        P1 -->|"选择操作"| P1_choice{"是否有家庭?"}:::page
+
+        P1_choice -->|"无,创建新家庭"| P1a["🏠 创建家庭页"]:::page
+        P1a -->|"家庭名称"| A1["🔗 POST /api/family/user/create-family"]:::api
+        A1 -->|"用户ID, 家庭名称"| S1["⚙️ UserService.createFamilyForUser()"]:::service
+        S1 -->|"写入一条家庭记录,关联用户"| D1["📦 families + users 表"]:::data
+
+        P1_choice -->|"有,加入其他家庭"| P1b["🏠 输入邀请码页"]:::page
+        P1b -->|"邀请码"| A2["🔗 POST /api/family/user/join-family"]:::api
+        A2 -->|"用户ID, 邀请码"| S2["⚙️ UserService.joinFamily()"]:::service
+        S2 -->|"更新用户家庭ID"| D2["📦 users 表(更新familyId)"]:::data
+
+        D1 -->|"家庭创建成功"| P2["🏠 家庭管理页"]:::page
+        P2 -->|"生成邀请二维码"| A3["🔗 POST /api/family/invite/qrcode"]:::api
+        A3 -->|"用户ID"| S3["⚙️ QrCodeService.generateQrCodeBase64()"]:::service
+        S3 -->|"family.inviteCode"| D3["📦 families 表(读取邀请码)"]:::data
+
+        P2 -->|"生成邀请令牌"| A4["🔗 POST /api/family/invite/generate"]:::api
+        A4 -->|"用户ID, 家庭ID"| S4["⚙️ FamilyInvitationService.generateInvitation()"]:::service
+        S4 -->|"写入邀请令牌记录"| D4["📦 family_invitations 表"]:::data
 
-    subgraph 家庭设置
-        C8 --> D1[📱 转让管理员 /invite/transfer-admin]:::portMiniApp
-        D1 --> D2[📱 吊销邀请 /invite/revoke]:::portMiniApp
-        D2 --> D3[📱 创建孩子 /user/children<br/>孩子列表 /user/children/list]:::portMiniApp
-        D3 --> D4[📱 家庭成员列表 /user/family-members]:::portMiniApp
+        P2 -->|"校验邀请令牌"| A5["🔗 POST /api/family/invite/validate"]:::api
+        A5 -->|"token"| S5["⚙️ FamilyInvitationService.validateInvitation()"]:::service
+        S5 -->|"令牌有效期+家庭信息"| D4
+
+        P2 -->|"通过邀请码接受邀请"| A6["🔗 POST /api/family/invite/accept-by-code"]:::api
+        A6 -->|"用户ID, 邀请码"| S6["⚙️ FamilyInviteController.acceptByCode()"]:::service
+        S6 -->|"查询家庭+更新用户familyId"| D2
+
+        P2 -->|"接受邀请令牌"| A7["🔗 POST /api/family/invite/accept"]:::api
+        A7 -->|"用户ID, token, 家庭角色, 是否合并"| S7["⚙️ FamilyInvitationService.acceptInvitation()"]:::service
+        S7 -->|"加入家庭/合并家庭"| D2
+
+        P2 -->|"查询家庭状态"| A8["🔗 POST /api/family/invite/check-family"]:::api
+        A8 -->|"用户ID"| S8["⚙️ FamilyInvitationService.checkUserFamilyStatus()"]:::service
+        S8 -->|"用户家庭信息"| D1
     end
 
-    subgraph 家庭关系问卷
-        D4 --> E1[⚙️ AI生成问卷 /questionnaire/generate]:::portSystem
-        E1 --> E2[📱 提交答案 /questionnaire/submit]:::portMiniApp
-        E2 --> E3[📱 问卷历史 /questionnaire/history/:memberId]:::portMiniApp
-        E3 --> E4[📱 查看快照 /questionnaire/snapshot/:memberId]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:家庭成员管理
+    %% ================================================================
+    subgraph 阶段二[阶段二:家庭成员管理]
+        D1 -->|"家庭ID"| P3["🏠 家庭成员管理页"]:::page
+        P3 -->|"添加成员"| A9["🔗 POST /api/family/member/add"]:::api
+        A9 -->|"用户ID, 昵称, 电话, 头像, 性别, 生日"| S9["⚙️ FamilyMemberService.addMember()"]:::service
+        S9 -->|"写入一条家庭成员记录"| D5["📦 family_members 表"]:::data
+
+        P3 -->|"成员列表"| A10["🔗 POST /api/family/member/list"]:::api
+        A10 -->|"用户ID"| S10["⚙️ FamilyMemberService.listMembers()"]:::service
+        S10 -->|"该家庭所有成员"| D5
+
+        P3 -->|"更新成员信息"| A11["🔗 POST /api/family/member/update"]:::api
+        A11 -->|"用户ID, memberId, 昵称/电话/头像"| S11["⚙️ FamilyMemberService.updateMember()"]:::service
+        S11 -->|"更新成员记录"| D5
+
+        P3 -->|"切换成员视图"| A12["🔗 POST /api/family/member/switch"]:::api
+        A12 -->|"用户ID, memberId"| S12["⚙️ FamilyMemberService.switchToMember()"]:::service
+        S12 -->|"切换上下文"| D5
+
+        P3 -->|"检查可编辑性"| A13["🔗 POST /api/family/member/editable"]:::api
+        A13 -->|"用户ID, memberId"| S13["⚙️ FamilyMemberService.isEditable()"]:::service
+        S13 -->|"布尔值"| D5
+
+        P3 -->|"踢出成员"| A14["🔗 POST /api/family/member/kick"]:::api
+        A14 -->|"用户ID, memberId"| S14["⚙️ FamilyMemberService.kickMember()"]:::service
+        S14 -->|"删除成员记录"| D5
+
+        P3 -->|"变更日志"| A15["🔗 POST /api/family/member/logs"]:::api
+        A15 -->|"用户ID, memberId"| S15["⚙️ FamilyMemberService.getMemberLogs()"]:::service
+        S15 -->|"操作日志列表"| D6["📦 family_member_logs 表"]:::data
+
+        P3 -->|"可见成员列表"| A16["🔗 POST /api/family/user/members/visible"]:::api
+        A16 -->|"用户ID"| S16["⚙️ UserService.getVisibleMembers()"]:::service
+        S16 -->|"对当前用户可见的成员"| D5
+
+        P3 -->|"更新可见性"| A17["🔗 POST /api/family/user/members/update-visibility"]:::api
+        A17 -->|"用户ID, memberId, memberType, showToFamily"| S17["⚙️ UserService.updateVisibility()"]:::service
+        S17 -->|"更新成员可见性标记"| D5
     end
 
-    subgraph 关系质量分析
-        E4 --> F1[⚙️ 计算评分 /relationship/calculate]:::portSystem
-        F1 --> F2[📱 质量评分 /relationship/scores]:::portMiniApp
-        F2 --> F3[📱 健康预警 /relationship/health-alerts]:::portMiniApp
-        F3 --> F4[📱 里程碑 /relationship/milestones]:::portMiniApp
-        F4 --> F5[📱 家庭属性 /attributes/get<br/>计算 /attributes/calculate · 更新 /attributes/update]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:家庭设置
+    %% ================================================================
+    subgraph 阶段三[阶段三:家庭设置]
+        D5 -->|"成员列表"| P4["🏠 家庭设置页"]:::page
+        P4 -->|"创建孩子账号"| A18["🔗 POST /api/family/user/children"]:::api
+        A18 -->|"用户ID, 孩子昵称/性别/生日"| S18["⚙️ UserService.createFamilyMember()"]:::service
+        S18 -->|"写入孩子记录"| D5
+
+        P4 -->|"孩子列表"| A19["🔗 POST /api/family/user/children/list"]:::api
+        A19 -->|"用户ID"| S19["⚙️ UserService.getFamilyMemberren()"]:::service
+        S19 -->|"孩子信息列表"| D5
+
+        P4 -->|"更新孩子信息"| A20["🔗 POST /api/family/user/children/update"]:::api
+        A20 -->|"用户ID, childId, 昵称/性别/生日"| S20["⚙️ UserService.updateFamilyMember()"]:::service
+        S20 -->|"更新孩子记录"| D5
+
+        P4 -->|"家庭成员列表"| A21["🔗 POST /api/family/user/family-members"]:::api
+        A21 -->|"用户ID"| S21["⚙️ FamilyUserController.getFamilyMembers()"]:::service
+        S21 -->|"家长列表+孩子列表"| D1
+
+        P4 -->|"踢出用户(管理员)"| A22["🔗 POST /api/family/user/kick"]:::api
+        A22 -->|"用户ID, targetUserId"| S22["⚙️ FamilyUserController.kickMember()"]:::service
+        S22 -->|"清空目标用户familyId"| D2
+
+        P4 -->|"转让管理员"| A23["🔗 POST /api/family/invite/transfer-admin"]:::api
+        A23 -->|"用户ID, newAdminId"| S23["⚙️ FamilyInvitationService.transferAdmin()"]:::service
+        S23 -->|"更新家庭创建者ID"| D1
+
+        P4 -->|"吊销邀请"| A24["🔗 POST /api/family/invite/revoke"]:::api
+        A24 -->|"用户ID, invitationId"| S24["⚙️ FamilyInvitationService.revokeInvitation()"]:::service
+        S24 -->|"更新邀请令牌状态"| D4
+
+        P4 -->|"用户信息"| A25["🔗 POST /api/family/user/info"]:::api
+        A25 -->|"用户ID"| S25["⚙️ UserService.getUserInfo()"]:::service
+        S25 -->|"用户完整信息"| D2
+
+        P4 -->|"更新用户信息"| A26["🔗 POST /api/family/user/update"]:::api
+        A26 -->|"用户ID, 昵称/头像"| S26["⚙️ UserService.updateUserInfo()"]:::service
+        S26 -->|"更新用户记录"| D2
     end
 
-    subgraph 互动记录
-        F5 --> G1[📱 互动类型 /interaction/types]:::portMiniApp
-        G1 --> G2[📱 添加互动 /interaction/add]:::portMiniApp
-        G2 --> G3[📱 互动列表 /interaction/list]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:规划师绑定
+    %% ================================================================
+    subgraph 阶段四[阶段四:规划师绑定]
+        D1 -->|"家庭信息"| P5["🏠 规划师绑定管理页"]:::page
+        P5 -->|"待审批列表"| A27["🔗 POST /api/family/teacher-bindings/pending"]:::api
+        A27 -->|"用户ID"| S27["⚙️ TeacherFamilyBindingRequestService.getPendingByFamily()"]:::service
+        S27 -->|"待审批绑定申请列表"| D7["📦 teacher_family_binding_requests 表"]:::data
+
+        P5 -->|"审批通过"| A28["🔗 POST /api/family/teacher-bindings/approve"]:::api
+        A28 -->|"用户ID, requestId"| S28["⚙️ TeacherFamilyBindingRequestService.approve()"]:::service
+        S28 -->|"更新申请状态+建立绑定"| D7
+
+        P5 -->|"审批拒绝"| A29["🔗 POST /api/family/teacher-bindings/reject"]:::api
+        A29 -->|"用户ID, requestId, reason"| S29["⚙️ TeacherFamilyBindingRequestService.reject()"]:::service
+        S29 -->|"更新申请状态为拒绝"| D7
+
+        P5 -->|"已绑定规划师列表"| A30["🔗 POST /api/bind/guides"]:::api
+        A30 -->|"用户ID"| S30["⚙️ GuideFamilyService.getGuidesByFamily()"]:::service
+        S30 -->|"该家庭绑定的规划师"| D8["📦 guide_families 表"]:::data
+
+        P5 -->|"解除绑定"| A31["🔗 POST /api/bind/unbind"]:::api
+        A31 -->|"用户ID, id"| S31["⚙️ GuideFamilyService.unbindAndGet()"]:::service
+        S31 -->|"更新绑定状态+发送通知"| D8
+
+        D7 -->|"绑定申请"| P6["📋 规划师端:绑定管理"]:::page
+        P6 -->|"我的请求"| A32["🔗 POST /api/family/teacher-bindings/my-requests"]:::api
+        A32 -->|"用户ID"| S32["⚙️ TeacherFamilyBindingRequestService.getByTeacher()"]:::service
+        S32 -->|"该规划师的所有申请"| D7
+
+        P6 -->|"撤销申请"| A33["🔗 POST /api/family/teacher-bindings/cancel"]:::api
+        A33 -->|"用户ID, requestId"| S33["⚙️ TeacherFamilyBindingRequestService.cancel()"]:::service
+        S33 -->|"更新申请状态为取消"| D7
+
+        P6 -->|"申请绑定家庭"| A34["🔗 POST /api/family/guide-bind"]:::api
+        A34 -->|"规划师ID, 邀请码, 留言"| S34["⚙️ TeacherFamilyBindingRequestService.createRequest()"]:::service
+        S34 -->|"创建绑定申请记录"| D7
+
+        P6 -->|"生成绑定邀请"| A35["🔗 POST /api/guide/bind/invite"]:::api
+        A35 -->|"规划师ID"| S35["⚙️ BindInviteService.generateInvite()"]:::service
+        S35 -->|"写入绑定邀请记录"| D9["📦 bind_invites 表"]:::data
+
+        P5 -->|"确认绑定邀请"| A36["🔗 POST /api/bind/accept"]:::api
+        A36 -->|"用户ID, guideId, serviceType, servicePrice"| S36["⚙️ GuideFamilyService.confirmBind()"]:::service
+        S36 -->|"写入guide_families绑定记录"| D8
     end
 
-    subgraph 规划师绑定
-        G3 --> H1[📱 待审批绑定 /teacher-bindings/pending]:::portMiniApp
-        H1 --> H2[📱 审批通过 /teacher-bindings/approve<br/>拒绝 /teacher-bindings/reject]:::portMiniApp
-        H2 --> H3[📱 我的请求 /teacher-bindings/my-requests]:::portMiniApp
-        H3 --> H4[📱 取消绑定 /teacher-bindings/cancel]:::portMiniApp
-        H4 --> H5[📋 规划师绑定 /guide-bind]:::portGuide
+    %% ================================================================
+    %% 阶段五:关系问卷与质量分析
+    %% ================================================================
+    subgraph 阶段五[阶段五:关系问卷与质量分析]
+        D5 -->|"成员列表"| P7["🏠 关系问卷页"]:::page
+        P7 -->|"AI生成问卷"| A37["🔗 POST /api/family/questionnaire/generate"]:::api
+        A37 -->|"目标成员ID, 关系类型"| S37["⚙️ RelationshipQuestionnaireService.generateQuestionnaire()"]:::service
+        S37 -->|"AI生成问卷内容"| D10["📦 questionnaire_snapshots 表"]:::data
+
+        P7 -->|"提交问卷答案"| A38["🔗 POST /api/family/questionnaire/submit"]:::api
+        A38 -->|"问卷快照ID, 答案列表"| S38["⚙️ RelationshipQuestionnaireService.submitQuestionnaire()"]:::service
+        S38 -->|"写入问卷响应"| D11["📦 relationship_questionnaire_responses 表"]:::data
+
+        P7 -->|"问卷历史"| A39["🔗 POST /api/family/questionnaire/history/{memberId}"]:::api
+        A39 -->|"用户ID, memberId"| S39["⚙️ RelationshipQuestionnaireService.getHistory()"]:::service
+        S39 -->|"该成员问卷历史列表"| D11
+
+        P7 -->|"问卷快照"| A40["🔗 POST /api/family/questionnaire/snapshot/{memberId}"]:::api
+        A40 -->|"用户ID, memberId"| S40["⚙️ RelationshipQuestionnaireService.getSnapshot()"]:::service
+        S40 -->|"最新问卷快照"| D10
+
+        D10 -->|"问卷结果"| P8["🏠 关系质量页"]:::page
+        P8 -->|"计算评分"| A41["🔗 POST /api/family/relationship/calculate"]:::api
+        A41 -->|"memberId"| S41["⚙️ RelationshipQualityService.calculateScore()"]:::service
+        S41 -->|"写入评分结果"| D12["📦 relationship_scores 表"]:::data
+
+        P8 -->|"评分列表"| A42["🔗 POST /api/family/relationship/scores"]:::api
+        A42 -->|"用户ID, familyId"| S42["⚙️ RelationshipQualityService.getScores()"]:::service
+        S42 -->|"所有成员评分"| D12
+
+        P8 -->|"健康预警"| A43["🔗 POST /api/family/relationship/health-alerts"]:::api
+        A43 -->|"用户ID, familyId"| S43["⚙️ RelationshipQualityService.getHealthAlerts()"]:::service
+        S43 -->|"预警列表"| D12
+
+        P8 -->|"里程碑"| A44["🔗 POST /api/family/relationship/milestones"]:::api
+        A44 -->|"用户ID, familyId, daysAhead"| S44["⚙️ RelationshipQualityService.getMilestones()"]:::service
+        S44 -->|"即将到来的里程碑"| D12
     end
 
-    %% 角色标注
-    RP(("👤 家长")):::actor
-    RC(("👶 孩子")):::role
-    RT(("📋 规划师")):::role
+    %% ================================================================
+    %% 阶段六:互动记录
+    %% ================================================================
+    subgraph 阶段六[阶段六:互动记录]
+        D5 -->|"成员列表"| P9["🏠 互动记录页"]:::page
+        P9 -->|"互动类型"| A45["🔗 POST /api/family/interaction/types"]:::api
+        A45 -->|""| S45["⚙️ InteractionLogService.getInteractionTypes()"]:::service
+        S45 -->|"预定义的互动类型"| D13["📦 内存/配置类型数据"]:::data
 
-    B6 -.- RC
-    H5 -.- RT
+        P9 -->|"添加互动"| A46["🔗 POST /api/family/interaction/add"]:::api
+        A46 -->|"fromMemberId, toMemberId, type, content"| S46["⚙️ InteractionLogService.addInteraction()"]:::service
+        S46 -->|"写入互动记录"| D14["📦 interaction_logs 表"]:::data
+
+        P9 -->|"互动列表"| A47["🔗 POST /api/family/interaction/list"]:::api
+        A47 -->|"familyId, fromMemberId, toMemberId, 分页"| S47["⚙️ InteractionLogService.listInteractions()"]:::service
+        S47 -->|"分页互动记录"| D14
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    A0 -.- P1
+    A0 -.- P2
+    A0 -.- P3
+    A0 -.- P4
+    A0 -.- P5
+    A0 -.- P7
+    A0 -.- P8
+    A0 -.- P9
+    B0 -.- P3
+    C0 -.- P6
 ```
 
 ## 端点明细
 
 ### 家庭创建与加入
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/family/user/create-family` | 创建新家庭 | 📱小程序 |
-| `/api/family/user/join-family` | 加入家庭 | 📱小程序 |
-| `/api/family/invite/generate` | 生成邀请 | 📱小程序 |
-| `/api/family/invite/qrcode` | 生成邀请二维码 | 📱小程序 |
-| `/api/family/invite-code` | 查看邀请码 | 📱小程序 |
-| `/api/family/invite-code/generate` | 生成新邀请码 | 📱小程序 |
-| `/api/family/invite/accept-by-code` | 通过邀请码加入 | 📱小程序 |
-| `/api/family/invite/validate` | 校验邀请令牌 | 📱小程序 |
-| `/api/family/invite/accept` | 接受邀请 | 📱小程序 |
-| `/api/family/invite/check-family` | 查询家庭状态 | 📱小程序 |
-| `/api/family/invite/revoke` | 吊销邀请 | 📱小程序 |
-
-### 用户与角色管理
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/family/user/info` | 获取用户信息 | 📱小程序 |
-| `/api/family/user/update` | 更新用户信息 | 📱小程序 |
-| `/api/family/user/roles` | 获取角色列表 | 📱小程序 |
-| `/api/family/user/switch-role` | 切换角色 | 📱小程序 |
-| `/api/family/user/switch-mode` | 切换模式 | 📱小程序 |
-| `/api/family/user/switch-to-child` | 切换到孩子视角 | 📱小程序 |
-| `/api/family/user/switch-back-to-parent` | 切换回家长 | 📱小程序 |
-| `/api/family/user/switch-back-verify` | 切换回家长验证 | 📱小程序 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/family/user/create-family` | 创建新家庭 | 📱小程序 | `{name: "我的家庭"}` | `{familyId}` |
+| `POST /api/family/user/join-family` | 通过邀请码加入家庭 | 📱小程序 | `{inviteCode}` | `{success}` |
+| `POST /api/family/invite/qrcode` | 生成家庭邀请二维码 | 📱小程序 | — (从token取userId) | `{inviteCode, familyName, qrCodeBase64, familyId}` |
+| `POST /api/family/invite/generate` | 生成家庭邀请令牌+小程序码 | 📱小程序 | — | `{token, qrCodeBase64, familyName, familyId}` |
+| `POST /api/family/invite/validate` | 校验邀请令牌有效性 | 📱小程序 | `{token}` | `{valid, familyId, familyName, ...}` |
+| `POST /api/family/invite/accept-by-code` | 通过邀请码加入家庭 | 📱小程序 | `{inviteCode}` | `"加入家庭成功"` |
+| `POST /api/family/invite/accept` | 接受邀请令牌 | 📱小程序 | `{token, familyRole, mergeFamily}` | `"加入家庭成功"` |
+| `POST /api/family/invite/check-family` | 查询用户家庭状态 | 📱小程序 | — | `{hasFamily, familyId, familyName, ...}` |
 
 ### 家庭成员管理
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/family/member/add` | 添加家庭成员 | 📱小程序 |
-| `/api/family/member/list` | 成员列表 | 📱小程序 |
-| `/api/family/member/switch` | 切换成员视图 | 📱小程序 |
-| `/api/family/member/kick` | 踢出成员 | 📱小程序 |
-| `/api/family/member/update` | 更新成员信息 | 📱小程序 |
-| `/api/family/member/editable` | 检查可编辑性 | 📱小程序 |
-| `/api/family/member/logs` | 变更日志 | 📱小程序 |
-| `/api/family/user/children` | 创建孩子 | 📱小程序 |
-| `/api/family/user/children/list` | 孩子列表 | 📱小程序 |
-| `/api/family/user/children/update` | 更新孩子信息 | 📱小程序 |
-| `/api/family/user/members/visible` | 可见成员列表 | 📱小程序 |
-| `/api/family/user/members/update-visibility` | 更新可见性 | 📱小程序 |
-| `/api/family/user/kick` | 踢出成员 | 📱小程序 |
-| `/api/family/user/family-members` | 家庭成员列表 | 📱小程序 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/family/member/add` | 添加家庭成员 | 📱小程序 | `{nickname, phone, avatar, gender, birthday}` | `FamilyMemberVO` |
+| `POST /api/family/member/list` | 获取成员列表 | 📱小程序 | — | `List<FamilyMemberVO>` |
+| `POST /api/family/member/switch` | 切换到成员视图 | 📱小程序 | `{memberId}` | `SwitchMemberVO` |
+| `POST /api/family/member/kick` | 踢出成员 | 📱小程序 | `{memberId}` | `"踢出成功"` |
+| `POST /api/family/member/update` | 更新成员信息 | 📱小程序 | `{memberId, nickname, phone, avatar, gender, birthday}` | `FamilyMemberVO` |
+| `POST /api/family/member/editable` | 检查成员是否可编辑 | 📱小程序 | `{memberId}` | `boolean` |
+| `POST /api/family/member/logs` | 成员变更日志 | 📱小程序 | `{memberId}` | `List<FamilyMemberLog>` |
+| `POST /api/family/user/members/visible` | 可见成员列表 | 📱小程序 | — | `List<FamilyMemberVO>` |
+| `POST /api/family/user/members/update-visibility` | 更新成员可见性 | 📱小程序 | `{memberId, memberType, showToFamily}` | `boolean` |
 
 ### 家庭设置
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/family/invite/transfer-admin` | 转让管理员 | 📱小程序 |
-
-### 家庭关系问卷
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/family/questionnaire/generate` | AI生成关系问卷 | ⚙️系统自动 |
-| `/api/family/questionnaire/submit` | 提交问卷答案 | 📱小程序 |
-| `/api/family/questionnaire/history/{memberId}` | 问卷历史 | 📱小程序 |
-| `/api/family/questionnaire/snapshot/{memberId}` | 问卷快照 | 📱小程序 |
-
-### 关系质量分析
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/family/relationship/calculate` | 计算保存评分 | ⚙️系统自动 |
-| `/api/family/relationship/scores` | 关系质量评分 | 📱小程序 |
-| `/api/family/relationship/health-alerts` | 健康预警 | 📱小程序 |
-| `/api/family/relationship/milestones` | 里程碑 | 📱小程序 |
-| `/api/family/attributes/get` | 获取家庭属性 | 📱小程序 |
-| `/api/family/attributes/calculate` | 计算家庭属性 | ⚙️系统自动 |
-| `/api/family/attributes/update` | 更新家庭属性 | 📱小程序 |
 
-### 互动记录
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/family/interaction/types` | 互动类型列表 | 📱小程序 |
-| `/api/family/interaction/add` | 添加互动记录 | 📱小程序 |
-| `/api/family/interaction/list` | 互动记录列表 | 📱小程序 |
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/family/user/info` | 获取用户信息 | 📱小程序 | — | `User对象` |
+| `POST /api/family/user/update` | 更新用户信息 | 📱小程序 | `{nickname, avatar, ...}` | `boolean` |
+| `POST /api/family/user/children` | 创建孩子账号 | 📱小程序 | `{nickname, gender, birthday, ...}` | `FamilyMemberInfoDTO` |
+| `POST /api/family/user/children/list` | 孩子列表 | 📱小程序 | — | `List<FamilyMemberInfoDTO>` |
+| `POST /api/family/user/children/update` | 更新孩子信息 | 📱小程序 | `{childId, nickname, gender, birthday, ...}` | `boolean` |
+| `POST /api/family/user/family-members` | 家庭成员完整列表(含家长) | 📱小程序 | — | `{familyId, familyName, parents, children}` |
+| `POST /api/family/user/kick` | 管理员踢出用户 | 📱小程序 | `{targetUserId}` | `boolean` |
+| `POST /api/family/invite/transfer-admin` | 转让家庭管理员 | 📱小程序 | `{newAdminId}` | `"转让成功"` |
+| `POST /api/family/invite/revoke` | 吊销邀请链接 | 📱小程序 | `{invitationId}` | `"邀请已吊销"` |
+| `POST /api/family/user/switch-role` | 切换用户角色 | 📱小程序 | `{role}` | `新token` |
+| `POST /api/family/user/switch-back-to-parent` | 切换回家长视图 | 📱小程序 | — | `boolean` |
+| `POST /api/family/user/switch-back-verify` | 密码校验后切换回家长 | 📱小程序 | `{password}` | `boolean` |
 
 ### 规划师绑定
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/family/teacher-bindings/pending` | 待审批绑定 | 📱小程序 |
-| `/api/family/teacher-bindings/approve` | 审批通过 | 📱小程序 |
-| `/api/family/teacher-bindings/reject` | 拒绝绑定 | 📱小程序 |
-| `/api/family/teacher-bindings/my-requests` | 我的请求 | 📱小程序 |
-| `/api/family/teacher-bindings/cancel` | 取消绑定 | 📱小程序 |
-| `/api/family/guide-bind` | 规划师绑定 | 📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/family/teacher-bindings/pending` | 待审批绑定列表 | 📱小程序 | — | `List<TeacherFamilyBindingRequest>` |
+| `POST /api/family/teacher-bindings/approve` | 审批通过 | 📱小程序 | `{requestId}` | `"审批通过"` |
+| `POST /api/family/teacher-bindings/reject` | 审批拒绝 | 📱小程序 | `{requestId, reason}` | `"已拒绝"` |
+| `POST /api/family/teacher-bindings/my-requests` | 规划师我的请求 | 📋规划师端 | — | `List<TeacherFamilyBindingRequest>` |
+| `POST /api/family/teacher-bindings/cancel` | 撤销申请 | 📋规划师端 | `{requestId}` | `"已撤销"` |
+| `POST /api/family/guide-bind` | 规划师申请绑定家庭 | 📋规划师端 | `{inviteCode, message}` | `"申请已提交"` |
+| `POST /api/guide/bind/invite` | 规划师生成绑定邀请 | 📋规划师端 | — | `{token, ...}` |
+| `POST /api/guide/bind/validate` | 校验绑定邀请令牌 | 📋规划师端 | `{token}` | `{valid, guideInfo, ...}` |
+| `POST /api/bind/accept` | 家长确认绑定规划师 | 📱小程序 | `{guideId, serviceType, servicePrice}` | `boolean` |
+| `POST /api/bind/guides` | 已绑定规划师列表 | 📱小程序 | — | `List<{id, guideId, serviceType, ...}>` |
+| `POST /api/bind/unbind` | 解除绑定规划师 | 📱小程序 | `{id}` | `boolean` |
+
+### 关系问卷与质量分析
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/family/questionnaire/generate` | AI生成关系问卷 | 📱小程序 | `{targetMemberId, relationshipType}` | `QuestionnaireSnapshotVO` |
+| `POST /api/family/questionnaire/submit` | 提交问卷答案 | 📱小程序 | `{snapshotId, answers[]}` | `RelationshipQuestionnaireResponse` |
+| `POST /api/family/questionnaire/history/{memberId}` | 问卷历史记录 | 📱小程序 | path: `memberId` | `List<RelationshipQuestionnaireResponse>` |
+| `POST /api/family/questionnaire/snapshot/{memberId}` | 最新问卷快照 | 📱小程序 | path: `memberId` | `QuestionnaireSnapshotVO` |
+| `POST /api/family/relationship/calculate` | 计算并保存评分 | ⚙️系统自动 | `{memberId}` | `RelationshipScoreVO` |
+| `POST /api/family/relationship/scores` | 关系质量评分列表 | 📱小程序 | `{familyId}` | `List<RelationshipScoreVO>` |
+| `POST /api/family/relationship/health-alerts` | 健康预警列表 | 📱小程序 | `{familyId}` | `List<HealthAlertVO>` |
+| `POST /api/family/relationship/milestones` | 即将到来的里程碑 | 📱小程序 | `{familyId, daysAhead}` | `List<MilestoneVO>` |
+
+### 互动记录
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/family/interaction/types` | 互动类型列表 | 📱小程序 | — | `Map<类型代码, 类型名称>` |
+| `POST /api/family/interaction/add` | 添加互动记录 | 📱小程序 | `{fromMemberId, toMemberId, type, content}` | `InteractionLogVO` |
+| `POST /api/family/interaction/list` | 互动记录分页列表 | 📱小程序 | `{familyId, fromMemberId, toMemberId, page, size}` | `Page<InteractionLogVO>` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖家庭创建/加入、成员管理、家庭设置、规划师绑定、关系问卷与质量分析、互动记录6个阶段,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 邀请码无效、令牌过期、非管理员踢出等错误在Service层处理;家庭合并冲突已在图中体现 |
+| 3 | **端点覆盖** | ✅ 完整 | 47个端点全部映射到流程图中,与代码实际暴露的控制器一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长(parent)管理家庭全流程、规划师(teacher)绑定申请、孩子(child)可见性管理均已覆盖;管理员(admin)在管理后台管理家庭,不在本图范围 |
+| 5 | **数据实体** | ✅ 完整 | families、users、family_members、family_member_logs、family_invitations、teacher_family_binding_requests、guide_families、bind_invites、questionnaire_snapshots、relationship_questionnaire_responses、relationship_scores、interaction_logs 均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(FamilyUserController、FamilyInviteController、FamilyMembersController、TeacherFamilyBindingController、RelationshipQuestionnaireController、RelationshipQualityController、InteractionLogController、BindController、BindInviteController)中的`@PostMapping`匹配 |

+ 149 - 25
docs/flows/growth-task-flow.md

@@ -1,39 +1,163 @@
 # 用户使用流程图 — 成长任务
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
+
+## 核心概念
+
+**成长任务** (GrowthTask) 是孩子每日可执行的系统预设任务,分为两种类型:
+
+- **每日任务** (DAILY):每日重置进度,如"阅读30分钟""运动打卡"
+- **新人任务** (NEWBIE):一次性任务,如"完善个人资料""首次邀请"
+- **AI动态任务** (AI_GENERATED):由AI对话会话生成的自定义任务
+
+任务执行后记录在 **growth_task_log** 表中,完成可领取积分+五维能量奖励。
 
 ```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[📱 获取成长任务列表 /list]:::portMiniApp
-        A2 --> A3{📱 任务状态}:::portMiniApp
-        A3 -->|可领取| A4[📱 领取任务 /claim]:::portMiniApp
-        A3 -->|动态任务| A5[📱 接受动态任务 /accept-dynamic]:::portMiniApp
-        A4 --> A6[📱 执行成长任务]:::portMiniApp
-        A5 --> A6
+    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
+
+    %% ============ 角色 ============
+    ROLE_CHILD(("👶 孩子")):::actor
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_SYSTEM(("⚙️ 系统自动")):::actor
+
+    %% ================================================================
+    %% 阶段一:任务列表与领取
+    %% ================================================================
+    subgraph 阶段一[阶段一:任务列表与执行]
+        P1["🏠 小程序:成长任务页"]:::page
+        P1 -->|"查看任务列表"| A1["🔗 POST /api/growth-task/list"]:::api
+        A1 -->|"userId, type(DAILY/NEWBIE), dimension(可选)"| S1["⚙️ GrowthTaskService.getTaskList()"]:::service
+        S1 -->|"查询已启用任务+今日/历史进度"| D1["📦 growth_task 表(任务定义)"]:::data
+        S1 -->|"查询该用户的进度日志"| D2["📦 growth_task_log 表(进度)"]:::data
+
+        D1 -->|"任务列表含进度"| P1a{"任务状态"}:::page
+        P1a -->|"未开始/进行中"| P1b["🏠 执行任务页"]:::page
+        P1b -->|"完成任务目标"| A2["⚙️ 系统:自动更新进度"]:::api
+        A2 -->|"userId, taskKey, increment"| S2["⚙️ GrowthTaskService.updateProgress()"]:::service
+        S2 -->|"新增或更新进度记录, 达标则标记completed"| D2
+
+        P1a -->|"已完成·未领取"| P1c["🏠 领取奖励弹窗"]:::page
+        P1c -->|"领取奖励"| A3["🔗 POST /api/growth-task/claim"]:::api
+        A3 -->|"userId, taskLogId"| S3["⚙️ GrowthTaskService.claimReward()"]:::service
+        S3 -->|"标记claimed=1"| D2
+        S3 -->|"发放积分"| D_POINTS["📦 积分流水(PointsService)"]:::data
+        S3 -->|"发放五维能量"| D_ENERGY["📦 能量流水(EnergyService)"]:::data
+
+        P1a -->|"已完成·已领取"| P1d["🏠 已领取(不可重复)"]:::page
+        P1a -->|"AI动态任务"| P1e["🏠 AI动态任务页"]:::page
+        P1e -->|"接受任务"| A4["🔗 POST /api/growth-task/accept-dynamic"]:::api
+        A4 -->|"userId, taskId"| S4["⚙️ GrowthTaskService(返回任务信息)"]:::service
+        S4 -->|"查询AI生成的任务详情"| D1
+    end
+
+    %% ================================================================
+    %% 阶段二:新人初始化(系统自动)
+    %% ================================================================
+    subgraph 阶段二[阶段二:新人注册初始化]
+        ROLE_SYSTEM -->|"新用户注册成功"| P2["⚙️ 系统:新人任务初始化"]:::page
+        P2 -->|"触发initNewbieTasks"| A5["⚙️ OnboardingService.initForUser()"]:::api
+        A5 -->|"userId"| S5["⚙️ GrowthTaskService.initNewbieTasks()"]:::service
+        S5 -->|"查询所有NEWBIE类型任务"| D1
+        S5 -->|"为每个任务创建初始进度记录"| D2
     end
 
-    R1(("👶 孩子")):::actor
+    %% ================================================================
+    %% 阶段三:AI动态任务创建(系统自动)
+    %% ================================================================
+    subgraph 阶段三[阶段三:AI会话生成动态任务]
+        ROLE_SYSTEM -->|"AI对话中产生任务建议"| P3["⚙️ 系统:AI任务生成"]:::page
+        P3 -->|"调用createDynamicTask"| A6["⚙️ AIChatService → GrowthTaskService"]:::api
+        A6 -->|"userId, title, description, dimension, rewardPoints, conversationId"| S6["⚙️ GrowthTaskService.createDynamicTask()"]:::service
+        S6 -->|"写入类型=AI_GENERATED的任务"| D1
+    end
 
-    A1 -.- R1
+    %% ================================================================
+    %% 阶段四:后台任务管理(管理员/规划师)
+    %% ================================================================
+    subgraph 阶段四[阶段四:任务配置管理]
+        P4["🖥 管理后台:成长任务管理页"]:::page
+        P4 -->|"CRUD成长任务"| A7["🔗 管理端:任务配置接口"]:::api
+        A7 -->|"任务定义字段"| S7["⚙️ 管理端配置逻辑"]:::service
+        S7 -->|"增删改查成长任务"| D1
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_CHILD -.- P1
+    ROLE_CHILD -.- P1b
+    ROLE_CHILD -.- P1c
+    ROLE_CHILD -.- P1e
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P4
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/growth-task/list` | 成长任务列表 | 📱小程序 |
-| `/api/growth-task/claim` | 领取任务 | 📱小程序 |
-| `/api/growth-task/accept-dynamic` | 接受动态任务 | 📱小程序 |
+### 成长任务
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/growth-task/list` | 获取成长任务列表含进度 | 📱小程序 | `{type(DAILY/NEWBIE), dimension(可选)}` | `List<任务+进度信息>` |
+| `POST /api/growth-task/claim` | 领取已完成任务的奖励 | 📱小程序 | `{taskLogId}` | `{msg: "领取成功"/错误原因}` |
+| `POST /api/growth-task/accept-dynamic` | 接受AI动态任务 | 📱小程序 | `{taskId}` | `{id, title, description, dimension, rewardPoints}` |
+
+### 系统触发
+
+| 功能 | 说明 | 端口 | 触发条件 | 行为 |
+|------|------|------|---------|------|
+| `initNewbieTasks()` | 初始化新人成长任务 | ⚙️系统自动 | 新用户注册成功 | 为每个NEWBIE类型任务创建GrowthTaskLog |
+| `updateProgress()` | 更新任务进度 | ⚙️系统自动 | 其他功能模块调用 | 进度达标后自动标记completed=1 |
+| `createDynamicTask()` | AI生成动态任务 | ⚙️系统自动 | AI会话产出任务建议 | 写入type=AI_GENERATED的GrowthTask |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    GrowthTask ||--o{ GrowthTaskLog : "一个任务多个用户日志"
+    Child ||--o{ GrowthTaskLog : "一个孩子多条日志"
+
+    GrowthTask {
+        Long id PK
+        string type "DAILY/NEWBIE/AI_GENERATED"
+        string title "任务标题"
+        string description "任务描述"
+        int rewardPoints "奖励积分"
+        int rewardEnergy "奖励能量"
+        int targetValue "目标值(如30分钟)"
+        string taskKey "唯一业务Key"
+        string dimension "五维维度"
+        int enabled "是否启用"
+        string sourceConversationId "AI会话ID"
+    }
+
+    GrowthTaskLog {
+        Long id PK
+        Long userId FK
+        Long taskId FK
+        int progress "当前进度"
+        int completed "0/1 是否完成"
+        int claimed "0/1 是否领取"
+        string date "日期(yyyy-MM-dd)"
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖任务列表加载→进度更新→奖励领取全链路,以及新人初始化、AI动态任务生成、后台配置共4个阶段 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 已领取不可重复领取、进度未达标不可领取、任务不存在等均在Service层有校验;AI任务taskId不存在的错误处理已覆盖 |
+| 3 | **端点覆盖** | ✅ 完整 | 3个API端点全部映射到流程图中,System调用的3个内部方法也已列出 |
+| 4 | **角色覆盖** | ✅ 完整 | 孩子(执行任务/领取奖励)、家长(查看任务进度)、系统自动(初始化/进度更新/AI生成)均已覆盖;管理员可通过管理端配置任务 |
+| 5 | **数据实体** | ✅ 完整 | growth_task表(任务定义)、growth_task_log表(用户进度日志)、PointsService/EnergyService的积分和能量流水均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与GrowthTaskController中的`@PostMapping`匹配,Service方法名与GrowthTaskService源码一致 |

+ 451 - 282
docs/flows/guide-system-flow.md

@@ -1,339 +1,508 @@
 # 用户使用流程图 — 成长规划师体系
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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(("📋 成长规划师")):::portGuide --> A2{已有账号?}
-        A2 -->|否| A3[📋 注册 /register]:::portGuide
-        A3 --> A4[📋 提交入驻申请 /application/submit]:::portGuide
-        A2 -->|是| A5[📋 登录 → 查看状态 /applications]:::portGuide
-        A4 --> A6[🖥 管理员审批]:::portAdmin
-        A6 --> A7{审批结果}
-        A7 -->|通过| A8[📋 规划师激活<br/>查看激活记录 /application/:id/records]:::portGuide
-        A7 -->|驳回| A9[📋 撤回 /withdraw · 重新提交 /resubmit]:::portGuide
-        A9 --> A4
-        A8 --> A10[📋 查看我的申请 /applications/my]:::portGuide
-    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 actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3
 
-    subgraph 个人信息
-        A10 --> B1[📋 我的信息 /my]:::portGuide
-        B1 --> B2[📋 我的套餐 /my/packages]:::portGuide
-        B2 --> B3[📋 上级规划师 /parent-guide]:::portGuide
-        B3 --> B4[📋 下级列表 /child-guides<br/>全部下级 /all-child-guides]:::portGuide
+    %% ============ 角色 ============
+    RP(("📋 成长规划师")):::actor
+    RP2(("👤 家长")):::actor
+    RADM(("🔧 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:入驻与认证
+    %% ================================================================
+    subgraph 阶段一[阶段一:入驻与认证]
+        direction TB
+
+        P1["📋 规划师端:登录页"]:::page
+        P1 -->|"新入驻"| P1a["📋 提交入驻申请"]:::page
+        P1a -->|"目标等级, 套餐ID, 付款凭证"| A1["🔗 POST /api/guide/apply/new"]:::api
+        A1 -->|"userId, targetLevel, packageId"| S1["⚙️ GuideApplicationService.applyNew()"]:::service
+        S1 -->|"写入入驻申请"| D_APP["📦 guide_applications 表"]:::data
+
+        P1a -->|"升级申请"| A2["🔗 POST /api/guide/apply/upgrade"]:::api
+        A2 -->|"userId, fromLevel, toLevel, paymentProof"| S2["⚙️ GuideApplicationService.applyUpgrade()"]:::service
+        S2 -->|"写入升级申请"| D_APP
+
+        P1 -->|"已有账号登录"| A3["🔗 POST /api/guide/applications"]:::api
+        A3 -->|"userId"| S3["⚙️ 查询申请状态"]:::service
+        S3 -->|"申请列表"| D_APP
+
+        D_APP -->|"待审批申请"| A4["🖥 管理员审批申请"]:::api
+        A4 -->|"adminId, 通过/驳回"| S4["⚙️ GuideApplicationService.approve/reject()"]:::service
+        S4 -->|"更新申请状态 + 用户角色"| D_USER["📦 users 表(角色更新)"]:::data
+        S4 -->|"审批记录"| D_REC["📦 guide_application_records 表"]:::data
+
+        D_USER -->|"已激活规划师"| P1b["📋 规划师端:主页"]:::page
+        P1b -->|"查看我的信息"| A5["🔗 POST /api/guide/my"]:::api
+        A5 -->|"userId"| S5["⚙️ GuideService.getByUserId()"]:::service
+        S5 -->|"规划师信息"| D_GUIDE["📦 guides 表"]:::data
+
+        P1b -->|"我的申请记录"| A6["🔗 POST /api/guide/applications/my"]:::api
+        A6 -->|"userId"| S6["⚙️ 查询本人申请列表"]:::service
     end
 
-    subgraph 团队管理
-        B4 --> C1[📋 我的团队 /team/my-team]:::portGuide
-        C1 --> C2[📋 获取邀请码 /team/invite-code]:::portGuide
-        C2 --> C3[📋 生成新邀请码 /team/invite-code/generate]:::portGuide
-        C3 --> C4[📋 成员列表 /team/members]:::portGuide
-        C4 --> C5[📋 检查邀请 /team/check-status]:::portGuide
-        C5 --> C6[📋 通过码加入 /team/join-by-invite]:::portGuide
-        C6 --> C7[📋 离开团队 /team/leave]:::portGuide
-        C7 --> C8[📋 团队统计 /team/stats]:::portGuide
+    %% ================================================================
+    %% 阶段二:团队与邀请
+    %% ================================================================
+    subgraph 阶段二[阶段二:团队与邀请管理]
+        P1b -->|"团队管理"| P2["📋 规划师端:团队页"]:::page
+        P2 -->|"我的团队"| A7["🔗 POST /api/guide/team/my-team"]:::api
+        A7 -->|"guideId"| S7["⚙️ 查询邀请码+团队成员"]:::service
+        S7 -->|"邀请码信息 + 成员列表"| D_TEAM["📦 guide_invite_codes + users 表"]:::data
+
+        P2 -->|"获取邀请码"| A8["🔗 POST /api/guide/team/invite-code"]:::api
+        P2 -->|"生成新码"| A9["🔗 POST /api/guide/team/invite-code/generate"]:::api
+        A9 -->|"guideId"| S9["⚙️ GuideInviteCodeService.createInviteCode()"]:::service
+        S9 -->|"新邀请码"| D_INV["📦 guide_invite_codes 表"]:::data
+
+        P2 -->|"成员列表"| A10["🔗 POST /api/guide/team/members"]:::api
+        P2 -->|"加入团队"| A11["🔗 POST /api/guide/team/join-by-invite"]:::api
+        A11 -->|"userId, inviteCode"| S11["⚙️ 校验+建立团队关系"]:::service
+        S11 -->|"新建guide_hierarchy记录"| D_HIER["📦 guide_hierarchy 表"]:::data
+
+        P2 -->|"离开团队"| A12["🔗 POST /api/guide/team/leave"]:::api
+        P2 -->|"检查邀请状态"| A13["🔗 POST /api/guide/team/check-status"]:::api
+        P2 -->|"团队统计"| A14["🔗 POST /api/guide/team/stats"]:::api
+
+        P1b -->|"上级/下级"| P2a["📋 规划师端:关系页"]:::page
+        P2a -->|"上级规划师"| A15["🔗 POST /api/guide/parent-guide"]:::api
+        P2a -->|"下级列表"| A16["🔗 POST /api/guide/child-guides"]:::api
+        P2a -->|"全部下级"| A17["🔗 POST /api/guide/all-child-guides"]:::api
+
+        P1b -->|"邀请家长"| P2b["📋 规划师端:邀请家长页"]:::page
+        P2b -->|"生成家长邀请"| A18["🔗 POST /api/guide/parent-invite/generate"]:::api
+        A18 -->|"familyId, userId"| S18["⚙️ InviteCardService.generate()"]:::service
+        S18 -->|"邀请卡片(含邀请码)"| D_CARD["📦 invite_cards 表"]:::data
+
+        P2b -->|"📱 家长接受邀请"| A19["📱 小程序:接受邀请"]:::page
+        A19 -->|"邀请码"| A19a["🔗 POST /api/guide/parent-invite/accept"]:::api
+        A19a -->|"code, userId"| S19["⚙️ InviteCardService.acceptParentInvite()"]:::service
+        S19 -->|"建立规划师-家庭绑定"| D_BIND["📦 users.teacher_family_ids 更新"]:::data
     end
 
-    subgraph 邀请与绑定家庭
-        C8 --> D1[📋 生成家长邀请 /parent-invite/generate]:::portGuide
-        D1 --> D2[📱 家长接受邀请 /parent-invite/accept]:::portMiniApp
-        D2 --> D3[📋 生成绑定邀请 /bind/invite]:::portGuide
-        D3 --> D4[📋 校验邀请 /bind/validate]:::portGuide
-        D4 --> D5[📋 获取绑定家庭 /families/bound-families]:::portGuide
-        D5 --> D6[📋 家庭列表 /family/list]:::portGuide
-    end
+    %% ================================================================
+    %% 阶段三:家庭管理与任务审核
+    %% ================================================================
+    subgraph 阶段三[阶段三:家庭管理与任务审核]
+        P1b -->|"家庭列表"| P3["📋 规划师端:家庭列表页"]:::page
+        P3 -->|"已绑定家庭"| A20["🔗 POST /api/guide/families/bound-families"]:::api
+        A20 -->|"guideId"| S20["⚙️ 解析teacherFamilyIds+统计"]:::service
+        S20 -->|"家庭列表(含待审核数)"| D_FAM["📦 families + family_members 表"]:::data
 
-    subgraph 家庭管理与任务
-        D6 --> E1[📋 家庭概览 /families/:familyId/overview]:::portGuide
-        E1 --> E2[📋 仪表盘统计 /families/dashboard-stats]:::portGuide
-        E2 --> E3[📋 查看孩子任务 /families/:familyId/children/:childId/tasks]:::portGuide
-        E3 --> E4[📋 待审核 /children/:childId/pending-review]:::portGuide
-        E4 --> E5[📋 任务审核 /families/:familyId/tasks/:taskId/review]:::portGuide
-        E5 --> E6[📋 批量审核 /tasks/batch-review]:::portGuide
-        E6 --> E7[📋 任务详情 /tasks/:taskId<br/>删除 /tasks/:taskId/delete]:::portGuide
-    end
+        P3 -->|"生成绑定邀请"| A21["🔗 POST /api/guide/bind/invite"]:::api
+        P3 -->|"校验邀请"| A22["🔗 POST /api/guide/bind/validate"]:::api
+        P3 -->|"家庭列表(精简)"| A23["🔗 POST /api/guide/family/list"]:::api
+        A23 -->|"guideId"| S23["⚙️ 查询关联家庭信息"]:::service
 
-    subgraph 任务模板管理
-        E7 --> F1[📋 我的模板 /packages/my]:::portGuide
-        F1 --> F2[📋 创建模板 /packages/create]:::portGuide
-        F2 --> F3[📋 更新模板 /packages/update]:::portGuide
-        F3 --> F4[📋 更新状态 /packages/update-status]:::portGuide
-        F4 --> F5[📋 模板列表 /packages/list]:::portGuide
-        F5 --> F6[📋 模板详情 /packages/detail<br/>模板定价 /packages/template-detail]:::portGuide
-        F6 --> F7[📋 增加销量 /packages/increment-sales]:::portGuide
-        F7 --> F8[📋 等级筛选 /packages/level/:level]:::portGuide
-        F8 --> F9[📋 套餐包列表 /guide-packages /package/templates]:::portGuide
-        F9 --> F10[📋 添加套餐 /package/add · 查看 /package/:packageId<br/>更新 /package/:packageId/update · 删除 /package/:packageId/delete]:::portGuide
-    end
+        P3 -->|"家庭概览"| P3a["📋 规划师端:家庭详情页"]:::page
+        P3a -->|"任务概览"| A24["🔗 POST /api/guide/families/{familyId}/overview"]:::api
+        A24 -->|"familyId"| S24["⚙️ 各孩子今日/待审核任务统计"]:::service
+        S24 -->|"孩子任务统计"| D_TASK["📦 tasks 表"]:::data
+
+        P3a -->|"仪表盘统计"| A25["🔗 POST /api/guide/families/dashboard-stats"]:::api
+        A25 -->|"guideId"| S25["⚙️ 家庭数/今日完成/待审核统计"]:::service
+
+        P3a -->|"孩子任务列表"| A26["🔗 POST /api/guide/families/{familyId}/children/{childId}/tasks"]:::api
+        A26 -->|"familyId, childId, page"| S26["⚙️ TaskService.getTaskHistoryByFamilyMember()"]:::service
 
-    subgraph 活动管理
-        F10 --> G1[📋 创建活动 /activities/create]:::portGuide
-        G1 --> G2[📋 活动列表 /activities/list]:::portGuide
-        G2 --> G3[📋 活动详情 /activities/detail]:::portGuide
-        G3 --> G4[📋 更新 /activities/update]:::portGuide
-        G4 --> G5[📋 发布 /activities/publish]:::portGuide
-        G5 --> G6[📋 下架 /activities/cancel · 删除 /activities/delete]:::portGuide
+        P3a -->|"待审核任务"| A27["🔗 POST /api/guide/families/{familyId}/children/{childId}/pending-review"]:::api
+        A27 -->|"familyId, childId"| S27["⚙️ TaskService.getPendingReviewTasks()"]:::service
+
+        P3a -->|"审核任务"| A28["🔗 POST /api/guide/families/{familyId}/tasks/{taskId}/review"]:::api
+        A28 -->|"taskId, approved, comment"| S28["⚙️ TaskService.reviewTask()"]:::service
+        S28 -->|"更新任务状态"| D_TASK
+
+        P3a -->|"批量审核"| A29["🔗 POST /api/guide/families/{familyId}/tasks/batch-review"]:::api
+        A29 -->|"taskIds, approved"| S29["⚙️ 批量审核处理"]:::service
+
+        P3a -->|"修改任务"| A30["🔗 POST /api/guide/families/{familyId}/tasks/{taskId}"]:::api
+        P3a -->|"删除任务"| A31["🔗 POST /api/guide/families/{familyId}/tasks/{taskId}/delete"]:::api
     end
 
-    subgraph 训练方案
-        G6 --> H1[📋 方案列表 /training-plans/list]:::portGuide
-        H1 --> H2[📋 创建方案 /training-plans/create]:::portGuide
-        H2 --> H3[📋 添加项目 /training-plans/items/add]:::portGuide
-        H3 --> H4[📋 更新项目 /training-plans/items/update · 删除 /items/delete]:::portGuide
-        H4 --> H5[📋 从推荐生成 /training-plans/generate-from-recommendations]:::portGuide
-        H5 --> H6[📋 下发方案 /training-plans/deploy]:::portGuide
-        H6 --> H7[📋 执行看板 /training-plans/execution-board]:::portGuide
-        H7 --> H8[📋 方案详情 /training-plans/detail]:::portGuide
-        H8 --> H9[📋 更新 /training-plans/update · 删除 /training-plans/delete]:::portGuide
+    %% ================================================================
+    %% 阶段四:任务模板与套餐
+    %% ================================================================
+    subgraph 阶段四[阶段四:任务模板与套餐管理]
+        P1b -->|"我的模板"| P4["📋 规划师端:任务模板页"]:::page
+        P4 -->|"我的模板列表"| A32["🔗 POST /api/guide/packages/my"]:::api
+        A32 -->|"guideId"| S32["⚙️ 查询该规划师模板"]:::service
+        S32 -->|"模板列表"| D_PKG["📦 guide_packages 表"]:::data
+
+        P4 -->|"模板列表"| A33["🔗 POST /api/guide/packages/list"]:::api
+        P4 -->|"模板详情"| A34["🔗 POST /api/guide/packages/detail"]:::api
+        P4 -->|"定价详情"| A35["🔗 POST /api/guide/packages/template-detail"]:::api
+
+        P4 -->|"创建模板"| A36["🔗 POST /api/guide/packages/create"]:::api
+        A36 -->|"guideId, name, price, description, validityDays"| S36["⚙️ GuidePackageService.save()"]:::service
+        S36 -->|"新模板记录"| D_PKG
+
+        P4 -->|"更新模板"| A37["🔗 POST /api/guide/packages/update"]:::api
+        P4 -->|"更新状态"| A38["🔗 POST /api/guide/packages/update-status"]:::api
+        A38 -->|"id, status"| S38["⚙️ 状态校验+更新"]:::service
+        P4 -->|"删除模板"| A39["🔗 POST /api/guide/packages/delete"]:::api
+
+        P4 -->|"模板库"| A40["🔗 POST /api/guide/packages/templates"]:::api
+        P4 -->|"增加销量"| A41["🔗 POST /api/guide/packages/increment-sales"]:::api
+        P4 -->|"按等级筛选"| A42["🔗 POST /api/guide/packages/level/{level}"]:::api
+        A42 -->|"level"| S42["⚙️ GuidePackageService.getPackagesByLevel()"]:::service
+
+        P4 -->|"套餐包列表"| A43["🔗 POST /api/guide/guide-packages"]:::api
+        A43 -->|""| S43["⚙️ GuidePackageService.getActivePackages()"]:::service
+
+        P4 -->|"添加套餐包"| A44["🔗 POST /api/guide/package/add"]:::api
+        P4 -->|"查看套餐包"| A45["🔗 POST /api/guide/package/{packageId}"]:::api
+        P4 -->|"更新套餐包"| A46["🔗 POST /api/guide/package/{packageId}/update"]:::api
+        P4 -->|"删除套餐包"| A47["🔗 POST /api/guide/package/{packageId}/delete"]:::api
+        P4 -->|"套餐模板列表"| A48["🔗 POST /api/guide/package/templates"]:::api
     end
 
-    subgraph 评估管理
-        H9 --> I1[📋 可用测评资料 /assessment/materials]:::portGuide
-        I1 --> I2[📋 家庭测评列表 /assessment/families]:::portGuide
-        I2 --> I3[📋 启用 /assessment/family/enable]:::portGuide
-        I3 --> I4[📋 查看 /assessment/family/:familyId]:::portGuide
-        I4 --> I5[📋 禁用 /assessment/family/:familyId/disable]:::portGuide
+    %% ================================================================
+    %% 阶段五:活动管理
+    %% ================================================================
+    subgraph 阶段五[阶段五:活动管理]
+        P1b -->|"活动管理"| P5["📋 规划师端:活动页"]:::page
+        P5 -->|"列表"| A49["🔗 POST /api/guide/activities/list"]:::api
+        A49 -->|"guideId, status"| S49["⚙️ GuideActivityService.getActivitiesByGuide()"]:::service
+        S49 -->|"活动列表"| D_ACT["📦 guide_activities 表"]:::data
+
+        P5 -->|"创建活动"| A50["🔗 POST /api/guide/activities/create"]:::api
+        A50 -->|"guideId, activity内容"| S50["⚙️ GuideActivityService.createActivity()"]:::service
+        S50 -->|"新活动记录"| D_ACT
+
+        P5 -->|"更新"| A51["🔗 POST /api/guide/activities/update"]:::api
+        P5 -->|"详情"| A52["🔗 POST /api/guide/activities/detail"]:::api
+        P5 -->|"发布"| A53["🔗 POST /api/guide/activities/publish"]:::api
+        P5 -->|"下架"| A54["🔗 POST /api/guide/activities/cancel"]:::api
+        P5 -->|"删除"| A55["🔗 POST /api/guide/activities/delete"]:::api
+        A53 -->|"activityId"| S53["⚙️ 更新状态=published"]:::service
     end
 
-    subgraph 成长计划
-        I5 --> J1[📋 计划列表 /plans/family-list]:::portGuide
-        J1 --> J2[📋 计划详情 /plans/detail]:::portGuide
-        J2 --> J3[📋 激活 /plans/activate]:::portGuide
-        J3 --> J4[📋 审核 /plans/review]:::portGuide
+    %% ================================================================
+    %% 阶段六:训练方案
+    %% ================================================================
+    subgraph 阶段六[阶段六:训练方案管理]
+        P1b -->|"训练方案"| P6["📋 规划师端:训练方案页"]:::page
+        P6 -->|"列表"| A56["🔗 POST /api/guide/training-plans/list"]:::api
+        A56 -->|"guideId, childId"| S56["⚙️ TrainingPlanService.getPlansByGuide()"]:::service
+        S56 -->|"方案列表"| D_TP["📦 training_plans 表"]:::data
+
+        P6 -->|"创建方案"| A57["🔗 POST /api/guide/training-plans/create"]:::api
+        A57 -->|"guideId, childId, title"| S57["⚙️ TrainingPlanService.createPlan()"]:::service
+        S57 -->|"新方案记录"| D_TP
+
+        P6 -->|"从推荐生成"| A58["🔗 POST /api/guide/training-plans/generate-from-recommendations"]:::api
+        A58 -->|"guideId, childId"| S58["⚙️ 基于认知评估推荐生成方案"]:::service
+
+        P6 -->|"添加项目"| A59["🔗 POST /api/guide/training-plans/items/add"]:::api
+        A59 -->|"planId, TrainingPlanItem"| S59["⚙️ TrainingPlanService.addItem()"]:::service
+        S59 -->|"新项目记录"| D_TPI["📦 training_plan_items 表"]:::data
+
+        P6 -->|"更新项目"| A60["🔗 POST /api/guide/training-plans/items/update"]:::api
+        P6 -->|"删除项目"| A61["🔗 POST /api/guide/training-plans/items/delete"]:::api
+        P6 -->|"更新方案"| A62["🔗 POST /api/guide/training-plans/update"]:::api
+        P6 -->|"删除方案"| A63["🔗 POST /api/guide/training-plans/delete"]:::api
+        P6 -->|"方案详情"| A64["🔗 POST /api/guide/training-plans/detail"]:::api
+
+        P6 -->|"下发方案"| A65["🔗 POST /api/guide/training-plans/deploy"]:::api
+        A65 -->|"planId, operatorId"| S65["⚙️ 批量创建任务"]:::service
+        S65 -->|"新建多个task记录"| D_TASK
+
+        P6 -->|"执行看板"| A66["🔗 POST /api/guide/training-plans/execution-board"]:::api
+        A66 -->|"planId"| S66["⚙️ 统计执行进度"]:::service
     end
 
-    subgraph 成长记录
-        J4 --> K1[📋 创建记录 /record/create]:::portGuide
-        K1 --> K2[📋 我的记录 /record/my-records]:::portGuide
-        K2 --> K3[📋 记录详情 /record/detail/:id]:::portGuide
+    %% ================================================================
+    %% 阶段七:测评管理
+    %% ================================================================
+    subgraph 阶段七[阶段七:测评管理]
+        P1b -->|"测评管理"| P7["📋 规划师端:测评页"]:::page
+        P7 -->|"可用测评资料"| A67["🔗 POST /api/guide/assessment/materials"]:::api
+        A67 -->|""| S67["⚙️ AssessmentService.getMaterialList()"]:::service
+        S67 -->|"测评资料列表"| D_MAT["📦 assessment_materials 表"]:::data
+
+        P7 -->|"家庭测评列表"| A68["🔗 POST /api/guide/assessment/families"]:::api
+        A68 -->|"teacherId"| S68["⚙️ 查询该规划师所有家庭测评配置"]:::service
+        S68 -->|"家庭测评配置列表"| D_FAC["📦 family_assessment_config 表"]:::data
+
+        P7 -->|"启用测评"| A69["🔗 POST /api/guide/assessment/family/enable"]:::api
+        A69 -->|"familyId, materialId, remindMonths"| S69["⚙️ 创建家庭测评配置"]:::service
+        S69 -->|"新配置记录"| D_FAC
+
+        P7 -->|"配置详情"| A70["🔗 POST /api/guide/assessment/family/{familyId}"]:::api
+        P7 -->|"禁用测评"| A71["🔗 POST /api/guide/assessment/family/{familyId}/disable"]:::api
     end
 
-    subgraph 咨询消息
-        K3 --> L1[📋 发送咨询 /messages/send]:::portGuide
-        L1 --> L2[📋 我的咨询 /messages/my]:::portGuide
-        L2 --> L3[📋 回复 /messages/:messageId/reply]:::portGuide
-        L3 --> L4[📋 咨询列表 /messages/list]:::portGuide
-        L4 --> L5[📋 未读消息 /messages/unread-count]:::portGuide
+    %% ================================================================
+    %% 阶段八:成长方案审核
+    %% ================================================================
+    subgraph 阶段八[阶段八:成长方案审核]
+        P1b -->|"成长计划"| P8["📋 规划师端:成长计划页"]:::page
+        P8 -->|"家庭方案列表"| A72["🔗 POST /api/guide/plans/family-list"]:::api
+        A72 -->|"familyId, status"| S72["⚙️ 查询家庭方案列表"]:::service
+        S72 -->|"方案列表"| D_PLAN["📦 task_plan_instances 表"]:::data
+
+        P8 -->|"方案详情"| A73["🔗 POST /api/guide/plans/detail"]:::api
+        P8 -->|"方案审核"| A74["🔗 POST /api/guide/plans/review"]:::api
+        A74 -->|"planId, approved, comment"| S74["⚙️ 更新审核状态"]:::service
+        S74 -->|"更新状态=reviewed/rejected"| D_PLAN
+
+        P8 -->|"激活方案"| A75["🔗 POST /api/guide/plans/activate"]:::api
+        A75 -->|"planId"| S75["⚙️ PlanActivationService.activate()"]:::service
+        S75 -->|"生成任务实例"| D_TASK
     end
 
-    subgraph 订单与佣金
-        L5 --> M1[📋 订单列表 /orders/list]:::portGuide
-        M1 --> M2[📋 订单统计 /orders/stats]:::portGuide
-        M2 --> M3[📋 订单详情 /orders/detail]:::portGuide
+    %% ================================================================
+    %% 阶段九:成长记录
+    %% ================================================================
+    subgraph 阶段九[阶段九:成长记录与测评结果]
+        P1b -->|"录入结果"| P9["📋 规划师端:录入测评结果页"]:::page
+        P9 -->|"创建记录"| A76["🔗 POST /api/guide/record/create"]:::api
+        A76 -->|"DanAssessmentResult(含维度得分, 分析报告)"| S76["⚙️ AssessmentService.recordResult() + 积分发放"]:::service
+        S76 -->|"写入测评结果+发放积分"| D_RESULT["📦 dan_assessment_results 表"]:::data
+
+        P9 -->|"我的记录"| A77["🔗 POST /api/guide/record/my-records"]:::api
+        A77 -->|"userId"| S77["⚙️ 查询该规划师录入的测评结果"]:::service
+        S77 -->|"测评结果列表"| D_RESULT
+
+        P9 -->|"记录详情"| A78["🔗 POST /api/guide/record/detail/{id}"]:::api
+        A78 -->|"id"| S78["⚙️ 权限校验+查询"]:::service
     end
 
-    subgraph 升迁与新申请
-        M3 --> N1[📋 新入驻申请 /apply/new]:::portGuide
-        N1 --> N2[📋 升级申请 /apply/upgrade]:::portGuide
-        N2 --> A2
+    %% ================================================================
+    %% 阶段十:咨询消息
+    %% ================================================================
+    subgraph 阶段十[阶段十:咨询消息]
+        P1b -->|"咨询消息"| P10["📋 规划师端:消息页"]:::page
+        P10 -->|"发送咨询"| A79["🔗 POST /api/guide/messages/send"]:::api
+        A79 -->|"familyId, teacherId, content"| S79["⚙️ TeacherMessageService.sendMessage()"]:::service
+        S79 -->|"新消息记录"| D_MSG["📦 teacher_messages 表"]:::data
+
+        P10 -->|"回复消息"| A80["🔗 POST /api/guide/messages/{messageId}/reply"]:::api
+        A80 -->|"messageId, replyContent"| S80["⚙️ TeacherMessageService.replyMessage()"]:::service
+        S80 -->|"更新回复内容和时间"| D_MSG
+
+        P10 -->|"消息列表"| A81["🔗 POST /api/guide/messages/list"]:::api
+        A81 -->|"teacherId, page, size"| S81["⚙️ 分页查询消息"]:::service
+
+        P10 -->|"未读数"| A82["🔗 POST /api/guide/messages/unread-count"]:::api
+        P10 -->|"我的咨询"| A83["🔗 POST /api/guide/messages/my"]:::api
+        A83 -->|"parentId"| S83["⚙️ 查询家长发送的咨询"]:::service
     end
 
-    subgraph 教师班级管理
-        N2 --> O1[📋 教师信息 /api/teacher/info]:::portGuide
-        O1 --> O2[📋 班级列表 /api/teacher/classes/list]:::portGuide
-        O2 --> O3[📋 班级详情 /api/teacher/classes]:::portGuide
-        O3 --> O4{📋 操作}:::portGuide
-        O4 -->|学生管理| O5[📋 查看学生 /api/teacher/classes/:classId/students]:::portGuide
-        O5 --> O6[📋 添加学生 /api/teacher/classes/:classId/students/add]:::portGuide
-        O6 --> O7[📋 学生详情 /api/teacher/classes/:classId/students/:studentId]:::portGuide
-        O4 -->|报告| O8[📋 生成报告 /api/teacher/classes/:classId/report]:::portGuide
-        O4 -->|进度| O9[📋 学生进度 /api/teacher/students/:studentId/progress]:::portGuide
-        O3 --> OA[📋 教师任务 /api/teacher/tasks]:::portGuide
-        OA --> OB[📋 任务列表 /api/teacher/tasks/list]:::portGuide
+    %% ================================================================
+    %% 阶段十一:订单与佣金
+    %% ================================================================
+    subgraph 阶段十一[阶段十一:订单与佣金]
+        P1b -->|"订单管理"| P11["📋 规划师端:订单页"]:::page
+        P11 -->|"订单列表"| A84["🔗 POST /api/guide/orders/list"]:::api
+        A84 -->|"guideId, page, size, status"| S84["⚙️ 分页查询套餐订单"]:::service
+        S84 -->|"分页订单列表"| D_ORD["📦 package_orders 表"]:::data
+
+        P11 -->|"订单统计"| A85["🔗 POST /api/guide/orders/stats"]:::api
+        A85 -->|"guideId"| S85["⚙️ 订单数/收入统计"]:::service
+
+        P11 -->|"订单详情"| A86["🔗 POST /api/guide/orders/detail"]:::api
+        A86 -->|"id"| S86["⚙️ 订单查询+权限校验"]:::service
     end
 
-    %% 角色标注
-    RP(("📋 成长规划师")):::actor
-    RP2(("👤 家长")):::role
-    RADM(("🔧 管理员")):::role
+    %% ================================================================
+    %% 阶段十二:教师班级管理(已废弃)
+    %% ================================================================
+    subgraph 阶段十二[阶段十二:教师班级管理(已废弃)]
+        P1b -->|"班级管理"| P12["📋 规划师端:班级页(已废弃)"]:::page
+        P12 -->|"教师信息"| A87["🔗 POST /api/teacher/info"]:::api
+        A87 -->|"teacherId"| S87["⚙️ TeacherService.getTeacherInfo()"]:::service
+        S87 -->|"教师DTO"| D_TEACHER["📦 仅info可用,其余均废弃"]:::data
+        P12 -->|"其他班级接口均已标注@Deprecated"| A88["🔗 POST /api/teacher/classes/*"]:::api
+    end
 
-    A1 -.- RP
-    D2 -.- RP2
-    A6 -.- RADM
+    RP -.- P1
+    RP -.- P1b
+    RP2 -.- A19
+    RADM -.- A4
 ```
 
 ## 端点明细
 
 ### 入驻与认证
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/register` | 规划师注册 | 📋规划师端 |
-| `/api/guide/application/submit` | 提交入驻申请 | 📋规划师端 |
-| `/api/guide/application/withdraw` | 撤回申请 | 📋规划师端 |
-| `/api/guide/application/resubmit` | 重新提交申请 | 📋规划师端 |
-| `/api/guide/application/{id}/records` | 申请审批记录 | 📋规划师端 |
-| `/api/guide/applications` | 申请列表 | 📋规划师端 |
-| `/api/guide/applications/my` | 我的申请 | 📋规划师端 |
-| `/api/guide/apply/new` | 新入驻申请 | 📋规划师端 |
-| `/api/guide/apply/upgrade` | 升级申请 | 📋规划师端 |
-
-### 个人信息
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/my` | 我的信息 | 📋规划师端 |
-| `/api/guide/my/packages` | 我的套餐 | 📋规划师端 |
-| `/api/guide/parent-guide` | 上级规划师 | 📋规划师端 |
-| `/api/guide/child-guides` | 下级规划师列表 | 📋规划师端 |
-| `/api/guide/all-child-guides` | 全部下级规划师 | 📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/apply/new` | 提交新入驻申请 | 📋规划师端 | `{targetLevel, packageId, paymentProof}` | `{success}` |
+| `POST /api/guide/apply/upgrade` | 提交升级申请 | 📋规划师端 | `{fromLevel, toLevel, paymentProof}` | `{success}` |
+| `POST /api/guide/my` | 获取当前规划师信息 | 📋规划师端 | — | `Guide` |
+| `POST /api/guide/applications` | 申请列表 | 📋规划师端 | — | `List<GuideApplication>` |
+| `POST /api/guide/applications/my` | 我的申请 | 📋规划师端 | — | `List<GuideApplication>` |
+| `POST /api/guide/my/packages` | 我的套餐(按等级) | 📋规划师端 | — | `List<GuidePackage>` |
 
 ### 团队管理
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/team/my-team` | 获取我的团队 | 📋规划师端 |
-| `/api/guide/team/invite-code` | 获取团队邀请码 | 📋规划师端 |
-| `/api/guide/team/invite-code/generate` | 生成团队邀请码 | 📋规划师端 |
-| `/api/guide/team/members` | 团队成员列表 | 📋规划师端 |
-| `/api/guide/team/check-status` | 检查邀请状态 | 📋规划师端 |
-| `/api/guide/team/join-by-invite` | 通过邀请码加入 | 📋规划师端 |
-| `/api/guide/team/leave` | 离开团队 | 📋规划师端 |
-| `/api/guide/team/stats` | 团队统计 | 📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/team/my-team` | 获取我的团队 | 📋规划师端 | — | `{inviteCode, members, memberCount}` |
+| `POST /api/guide/team/invite-code` | 获取/创建团队邀请码 | 📋规划师端 | — | `GuideInviteCode` |
+| `POST /api/guide/team/invite-code/generate` | 生成新邀请码 | 📋规划师端 | — | `GuideInviteCode` |
+| `POST /api/guide/team/members` | 团队成员列表 | 📋规划师端 | — | `List<User>` |
+| `POST /api/guide/team/check-status` | 检查邀请码状态 | 📋规划师端 | `{inviteCode}` | `{valid, isPlanner, inTeam, ...}` |
+| `POST /api/guide/team/join-by-invite` | 通过邀请码加入团队 | 📋规划师端 | `{inviteCode}` | `{success, guideId}` |
+| `POST /api/guide/team/leave` | 离开当前团队 | 📋规划师端 | — | `{success}` |
+| `POST /api/guide/team/stats` | 团队统计 | 📋规划师端 | — | `{totalMembers, totalFamilies, totalChildren}` |
+| `POST /api/guide/parent-guide` | 上级规划师信息 | 📋规划师端 | — | `Guide` |
+| `POST /api/guide/child-guides` | 下级规划师列表 | 📋规划师端 | — | `List<Guide>` |
+| `POST /api/guide/all-child-guides` | 全部下级规划师 | 📋规划师端 | — | `List<Guide>` |
 
 ### 邀请与绑定家庭
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/parent-invite/generate` | 生成家长邀请 | 📋规划师端 |
-| `/api/guide/parent-invite/accept` | 家长接受邀请 | 📱小程序 |
-| `/api/guide/bind/invite` | 生成绑定邀请 | 📋规划师端 |
-| `/api/guide/bind/validate` | 校验邀请 | 📋规划师端 |
-| `/api/guide/families/bound-families` | 绑定家庭列表 | 📋规划师端 |
-| `/api/guide/family/list` | 家庭列表 | 📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/parent-invite/generate` | 生成家长邀请码 | 📋规划师端 | `{familyId}` | `{id, code, type, refId, expiresAt}` |
+| `POST /api/guide/parent-invite/accept` | 家长接受邀请 | 📱小程序 | `{code}` | `Map` |
+| `POST /api/guide/bind/invite` | 生成绑定邀请 | 📋规划师端 | — | — |
+| `POST /api/guide/bind/validate` | 校验绑定邀请 | 📋规划师端 | — | — |
+| `POST /api/guide/families/bound-families` | 已绑定家庭列表 | 📋规划师端 | — | `List<{familyId, familyName, parentName, childrenCount, pendingReviewCount}>` |
+| `POST /api/guide/family/list` | 家庭列表(精简) | 📋规划师端 | — | `List<{id, familyName, memberCount, createdAt}>` |
 
 ### 家庭管理与任务审核
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/families/{familyId}/overview` | 家庭概览 | 📋规划师端 |
-| `/api/guide/families/dashboard-stats` | 仪表盘统计 | 📋规划师端 |
-| `/api/guide/families/{familyId}/children/{childId}/tasks` | 孩子任务列表 | 📋规划师端 |
-| `/api/guide/families/{familyId}/children/{childId}/pending-review` | 待审核任务 | 📋规划师端 |
-| `/api/guide/families/{familyId}/tasks/{taskId}/review` | 审核任务 | 📋规划师端 |
-| `/api/guide/families/{familyId}/tasks/batch-review` | 批量审核任务 | 📋规划师端 |
-| `/api/guide/families/{familyId}/tasks/{taskId}` | 查看任务详情 | 📋规划师端 |
-| `/api/guide/families/{familyId}/tasks/{taskId}/delete` | 删除任务 | 📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/families/{familyId}/overview` | 家庭任务概览 | 📋规划师端 | path: `familyId` | `{familyId, children, totalPendingReview, totalCompleted, totalOverdue}` |
+| `POST /api/guide/families/dashboard-stats` | 仪表盘统计 | 📋规划师端 | — | `{totalFamilies, todayCompletedTasks, pendingReviewTasks}` |
+| `POST /api/guide/families/{familyId}/children/{childId}/tasks` | 孩子任务列表 | 📋规划师端 | path: `familyId, childId`, body: `{page, size, status}` | `Page<Task>` |
+| `POST /api/guide/families/{familyId}/children/{childId}/pending-review` | 待审核任务 | 📋规划师端 | path: `familyId, childId` | `List<Task>` |
+| `POST /api/guide/families/{familyId}/tasks/{taskId}/review` | 审核单个任务 | 📋规划师端 | path: `familyId, taskId`, body: `{approved, comment}` | `{success}` |
+| `POST /api/guide/families/{familyId}/tasks/batch-review` | 批量审核任务 | 📋规划师端 | path: `familyId`, body: `{taskIds, approved}` | `{successCount, failCount}` |
+| `POST /api/guide/families/{familyId}/tasks/{taskId}` | 修改任务 | 📋规划师端 | path: `familyId, taskId`, body: `{title, description, points, ...}` | `{success}` |
+| `POST /api/guide/families/{familyId}/tasks/{taskId}/delete` | 删除任务 | 📋规划师端 | path: `familyId, taskId` | `{success}` |
 
 ### 任务模板/套餐包管理
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/packages/my` | 我的模板 | 📋规划师端 |
-| `/api/guide/packages/create` | 创建模板 | 📋规划师端 |
-| `/api/guide/packages/update` | 更新模板 | 📋规划师端 |
-| `/api/guide/packages/update-status` | 更新模板状态 | 📋规划师端 |
-| `/api/guide/packages/delete` | 删除模板 | 📋规划师端 |
-| `/api/guide/packages/list` | 模板列表 | 📋规划师端 |
-| `/api/guide/packages/detail` | 模板详情 | 📋规划师端 |
-| `/api/guide/packages/template-detail` | 模板定价详情 | 📋规划师端 |
-| `/api/guide/packages/increment-sales` | 增加销量 | 📋规划师端 |
-| `/api/guide/packages/level/{level}` | 按等级筛选 | 📋规划师端 |
-| `/api/guide/packages/templates` | 获取模板库 | 📋规划师端 |
-| `/api/guide/guide-packages` | 套餐包列表 | 📋规划师端 |
-| `/api/guide/package/add` | 添加套餐包 | 📋规划师端 |
-| `/api/guide/package/{packageId}` | 查看套餐包详情 | 📋规划师端 |
-| `/api/guide/package/{packageId}/update` | 更新套餐包 | 📋规划师端 |
-| `/api/guide/package/{packageId}/delete` | 删除套餐包 | 📋规划师端 |
-| `/api/guide/package/templates` | 套餐模板列表 | 📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/packages/my` | 我的任务模板 | 📋规划师端 | — | `List<GuidePackage>` |
+| `POST /api/guide/packages/list` | 模板列表 | 📋规划师端 | — | `List<GuidePackage>` |
+| `POST /api/guide/packages/detail` | 模板详情 | 📋规划师端 | `{id}` | `GuidePackage` |
+| `POST /api/guide/packages/template-detail` | 模板定价详情 | 📋规划师端 | `{id}` | `GuidePackageTemplate` |
+| `POST /api/guide/packages/create` | 创建模板 | 📋规划师端 | `{templateId, name, price, description, validityMonths, commissionRate}` | `GuidePackage` |
+| `POST /api/guide/packages/update` | 更新模板 | 📋规划师端 | `{id, name, price, ...}` | `GuidePackage` |
+| `POST /api/guide/packages/update-status` | 更新模板状态 | 📋规划师端 | `{id, status}` | `{success}` |
+| `POST /api/guide/packages/delete` | 删除模板 | 📋规划师端 | `{id}` | `{success}` |
+| `POST /api/guide/packages/templates` | 模板库列表 | 📋规划师端 | — | `List<GuidePackageTemplate>` |
+| `POST /api/guide/packages/increment-sales` | 增加销量 | 📋规划师端 | `{id}` | `{success}` |
+| `POST /api/guide/packages/level/{level}` | 按等级筛选 | 📋规划师端 | path: `level` | `List<GuidePackage>` |
+| `POST /api/guide/guide-packages` | 套餐包列表(仅活跃) | 📋规划师端 | — | `List<GuidePackage>` |
+| `POST /api/guide/package/add` | 添加套餐包 | 📋规划师端 | — | — |
+| `POST /api/guide/package/{packageId}` | 查看套餐包 | 📋规划师端 | path: `packageId` | — |
+| `POST /api/guide/package/{packageId}/update` | 更新套餐包 | 📋规划师端 | path: `packageId` | — |
+| `POST /api/guide/package/{packageId}/delete` | 删除套餐包 | 📋规划师端 | path: `packageId` | — |
+| `POST /api/guide/package/templates` | 套餐模板列表 | 📋规划师端 | — | — |
 
 ### 活动管理
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/activities/create` | 创建活动 | 📋规划师端 |
-| `/api/guide/activities/list` | 活动列表 | 📋规划师端 |
-| `/api/guide/activities/detail` | 活动详情 | 📋规划师端 |
-| `/api/guide/activities/update` | 更新活动 | 📋规划师端 |
-| `/api/guide/activities/publish` | 发布活动 | 📋规划师端 |
-| `/api/guide/activities/cancel` | 下架活动 | 📋规划师端 |
-| `/api/guide/activities/delete` | 删除活动 | 📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/activities/list` | 活动列表 | 📋规划师端 | `{status}` | `List<GuideActivity>` |
+| `POST /api/guide/activities/detail` | 活动详情 | 📋规划师端 | `{activityId}` | `GuideActivity` |
+| `POST /api/guide/activities/create` | 创建活动 | 📋规划师端 | `GuideActivity字段` | `{id}` |
+| `POST /api/guide/activities/update` | 更新活动 | 📋规划师端 | `GuideActivity字段` | `{success}` |
+| `POST /api/guide/activities/publish` | 发布活动 | 📋规划师端 | `{activityId}` | `{success}` |
+| `POST /api/guide/activities/cancel` | 下架活动 | 📋规划师端 | `{activityId}` | `{success}` |
+| `POST /api/guide/activities/delete` | 删除活动 | 📋规划师端 | `{activityId}` | `{success}` |
 
 ### 训练方案
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/training-plans/list` | 方案列表 | 📋规划师端 |
-| `/api/guide/training-plans/create` | 创建方案 | 📋规划师端 |
-| `/api/guide/training-plans/items/add` | 添加项目 | 📋规划师端 |
-| `/api/guide/training-plans/items/update` | 更新项目 | 📋规划师端 |
-| `/api/guide/training-plans/items/delete` | 删除项目 | 📋规划师端 |
-| `/api/guide/training-plans/generate-from-recommendations` | 从推荐生成 | 📋规划师端 |
-| `/api/guide/training-plans/deploy` | 下发方案 | 📋规划师端 |
-| `/api/guide/training-plans/execution-board` | 执行看板 | 📋规划师端 |
-| `/api/guide/training-plans/detail` | 方案详情 | 📋规划师端 |
-| `/api/guide/training-plans/update` | 更新方案 | 📋规划师端 |
-| `/api/guide/training-plans/delete` | 删除方案 | 📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/training-plans/list` | 方案列表 | 📋规划师端 | `{childId}` | `List<TrainingPlan>` |
+| `POST /api/guide/training-plans/detail` | 方案详情(含项目) | 📋规划师端 | `{planId}` | `{plan, items}` |
+| `POST /api/guide/training-plans/create` | 创建方案 | 📋规划师端 | `{childId, title, description}` | `{planId}` |
+| `POST /api/guide/training-plans/update` | 更新方案 | 📋规划师端 | `{planId, title, description}` | `{success}` |
+| `POST /api/guide/training-plans/delete` | 删除方案 | 📋规划师端 | `{planId}` | `{success}` |
+| `POST /api/guide/training-plans/items/add` | 添加项目 | 📋规划师端 | `TrainingPlanItem字段` | `{itemId}` |
+| `POST /api/guide/training-plans/items/update` | 更新项目 | 📋规划师端 | `TrainingPlanItem字段` | `{success}` |
+| `POST /api/guide/training-plans/items/delete` | 删除项目 | 📋规划师端 | `{itemId}` | `{success}` |
+| `POST /api/guide/training-plans/generate-from-recommendations` | 从推荐生成方案 | 📋规划师端 | `{childId}` | `{planId}` |
+| `POST /api/guide/training-plans/deploy` | 下发方案(批量生成任务) | 📋规划师端 | `{planId}` | `List<taskId>` |
+| `POST /api/guide/training-plans/execution-board` | 执行看板 | 📋规划师端 | `{planId}` | `Map` |
 
 ### 评估管理
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/assessment/materials` | 可用测评资料 | 📋规划师端 |
-| `/api/guide/assessment/families` | 家庭测评列表 | 📋规划师端 |
-| `/api/guide/assessment/family/enable` | 启用家庭测评 | 📋规划师端 |
-| `/api/guide/assessment/family/{familyId}` | 家庭测评详情 | 📋规划师端 |
-| `/api/guide/assessment/family/{familyId}/disable` | 禁用家庭测评 | 📋规划师端 |
-
-### 成长计划
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/plans/family-list` | 家庭计划列表 | 📋规划师端 |
-| `/api/guide/plans/detail` | 计划详情 | 📋规划师端 |
-| `/api/guide/plans/activate` | 激活计划 | 📋规划师端 |
-| `/api/guide/plans/review` | 审核计划 | 📋规划师端 |
-
-### 成长记录
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/record/create` | 创建成长记录 | 📋规划师端 |
-| `/api/guide/record/my-records` | 我的记录列表 | 📋规划师端 |
-| `/api/guide/record/detail/{id}` | 记录详情 | 📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/assessment/materials` | 可用测评资料列表 | 📋规划师端 | — | `List<AssessmentMaterial>` |
+| `POST /api/guide/assessment/families` | 家庭测评配置列表 | 📋规划师端 | — | `List<Map>` |
+| `POST /api/guide/assessment/family/enable` | 为家庭启用测评 | 📋规划师端 | `{familyId, materialId, remindMonths}` | `{success}` |
+| `POST /api/guide/assessment/family/{familyId}` | 家庭测评配置详情 | 📋规划师端 | path: `familyId` | `Map` |
+| `POST /api/guide/assessment/family/{familyId}/disable` | 关闭家庭测评 | 📋规划师端 | path: `familyId` | `{success}` |
+
+### 成长方案(审核与激活)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/plans/family-list` | 家庭方案列表 | 📋规划师端 | `{familyId, status}` | `List<TaskPlanInstance>` |
+| `POST /api/guide/plans/detail` | 方案详情 | 📋规划师端 | `{planId}` | `TaskPlanInstance` |
+| `POST /api/guide/plans/review` | 审核方案(批准/驳回) | 📋规划师端 | `{planId, approved, comment}` | 操作结果字符串 |
+| `POST /api/guide/plans/activate` | 激活方案(生成任务) | 📋规划师端 | `{planId}` | 操作结果字符串 |
+
+### 成长记录(测评结果录入)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/record/create` | 录入测评结果(含孩子快照+积分发放) | 📋规划师端 | `DanAssessmentResult(维度得分, 分析报告, 成长建议等)` | `DanAssessmentResult` |
+| `POST /api/guide/record/my-records` | 我的测评记录列表 | 📋规划师端 | — | `List<DanAssessmentResult>` |
+| `POST /api/guide/record/detail/{id}` | 测评记录详情 | 📋规划师端 | path: `id` | `DanAssessmentResult` |
 
 ### 咨询消息
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/messages/send` | 发送咨询 | 📋规划师端 |
-| `/api/guide/messages/my` | 我的咨询 | 📋规划师端 |
-| `/api/guide/messages/list` | 咨询列表 | 📋规划师端 |
-| `/api/guide/messages/{messageId}/reply` | 回复咨询 | 📋规划师端 |
-| `/api/guide/messages/unread-count` | 未读消息数 | 📋规划师端 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/messages/send` | 发送咨询消息(家长→规划师) | 📱小程序 | `{familyId, teacherId, content}` | `{messageId}` |
+| `POST /api/guide/messages/my` | 家长获取自己的咨询记录 | 📱小程序 | — | `List<TeacherMessage>` |
+| `POST /api/guide/messages/list` | 规划师获取咨询列表 | 📋规划师端 | `{page, size}` | `{records, total, pages}` |
+| `POST /api/guide/messages/{messageId}/reply` | 规划师回复咨询 | 📋规划师端 | path: `messageId`, body: `{replyContent}` | `{success}` |
+| `POST /api/guide/messages/unread-count` | 规划师获取未读消息数 | 📋规划师端 | — | `{count}` |
 
 ### 订单与佣金
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/guide/orders/list` | 订单列表 | 📋规划师端 |
-| `/api/guide/orders/stats` | 订单统计 | 📋规划师端 |
-| `/api/guide/orders/detail` | 订单详情 | 📋规划师端 |
-
-### 教师班级管理
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/teacher/info` | 教师信息 | 📋规划师端 |
-| `/api/teacher/classes/list` | 班级列表 | 📋规划师端 |
-| `/api/teacher/classes` | 班级详情 | 📋规划师端 |
-| `/api/teacher/classes/{classId}/students` | 查看学生 | 📋规划师端 |
-| `/api/teacher/classes/{classId}/students/add` | 添加学生 | 📋规划师端 |
-| `/api/teacher/classes/{classId}/students/{studentId}` | 学生详情 | 📋规划师端 |
-| `/api/teacher/classes/{classId}/report` | 生成报告 | 📋规划师端 |
-| `/api/teacher/students/{studentId}/progress` | 学生进度 | 📋规划师端 |
-| `/api/teacher/tasks` | 教师任务 | 📋规划师端 |
-| `/api/teacher/tasks/list` | 任务列表 | 📋规划师端 |
-
-### 教师班级管理
-| 端点 | 说明 | 角色 |
-|------|------|------|
-| `/api/teacher/info` | 教师信息 | 教师 |
-| `/api/teacher/classes/list` | 班级列表 | 教师 |
-| `/api/teacher/classes` | 班级详情 | 教师 |
-| `/api/teacher/classes/{classId}/students` | 查看学生 | 教师 |
-| `/api/teacher/classes/{classId}/students/add` | 添加学生 | 教师 |
-| `/api/teacher/classes/{classId}/students/{studentId}` | 学生详情 | 教师 |
-| `/api/teacher/classes/{classId}/report` | 生成报告 | 教师 |
-| `/api/teacher/students/{studentId}/progress` | 学生进度 | 教师 |
-| `/api/teacher/tasks` | 教师任务 | 教师 |
-| `/api/teacher/tasks/list` | 任务列表 | 教师 |
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/orders/list` | 订单分页列表 | 📋规划师端 | `{page, size, status}` | `{records, total, pages, current}` |
+| `POST /api/guide/orders/stats` | 订单统计 | 📋规划师端 | — | `{totalOrders, paidOrders, totalRevenue, pendingOrders}` |
+| `POST /api/guide/orders/detail` | 订单详情 | 📋规划师端 | `{id}` | `PackageOrder` |
+
+### 教师班级管理(已废弃)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/teacher/info` | 获取教师信息 | 📋规划师端 | — | `TeacherDTO` |
+| `POST /api/teacher/tasks` | 创建教学任务(已废弃) | 📋规划师端 | — | `UnsupportedOperationException` |
+| `POST /api/teacher/tasks/list` | 教师任务列表(已废弃) | 📋规划师端 | — | `UnsupportedOperationException` |
+| `POST /api/teacher/classes` | 创建班级(已废弃) | 📋规划师端 | — | `UnsupportedOperationException` |
+| `POST /api/teacher/classes/list` | 班级列表(已废弃) | 📋规划师端 | — | `UnsupportedOperationException` |
+| `POST /api/teacher/classes/{classId}/students` | 班级学生列表(已废弃) | 📋规划师端 | — | `UnsupportedOperationException` |
+| `POST /api/teacher/classes/{classId}/students/add` | 添加学生(已废弃) | 📋规划师端 | — | `UnsupportedOperationException` |
+| `POST /api/teacher/classes/{classId}/students/{studentId}` | 移除学生(已废弃) | 📋规划师端 | — | `UnsupportedOperationException` |
+| `POST /api/teacher/students/{studentId}/progress` | 学生进度(已废弃) | 📋规划师端 | — | `UnsupportedOperationException` |
+| `POST /api/teacher/classes/{classId}/report` | 班级报告(已废弃) | 📋规划师端 | — | `UnsupportedOperationException` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖入驻认证、团队管理、家庭绑定、任务审核、模板套餐、活动/训练方案、测评管理、成长方案审核、成长记录录入、咨询消息、订单佣金共12个阶段,贯穿规划师全生命周期 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 入驻申请被驳回→撤回重提流程已覆盖;团队加入中的重复成员、自己邀请自己等异常在Service层处理;Token过期通过JwtInterceptor统一拦截 |
+| 3 | **端点覆盖** | ✅ 完整 | 80+个端点全部映射到流程图中,涵盖GuideController、GuidePackageController、GuideTeamController、GuideFamilyTaskController、GuideFamilyListController、GuideActivityController、TrainingPlanController、GuideAssessmentController、PlanReviewController、GuideRecordController、TeacherMessageController、GuideOrderController、TeacherController |
+| 4 | **角色覆盖** | ✅ 完整 | 规划师(teacher)主视角覆盖;家长(parent)在邀请绑定和咨询消息中出现;管理员(admin)在入驻审核和方案审核中出现 |
+| 5 | **数据实体** | ✅ 完整 | guide_applications、guides、guide_invite_codes、guide_hierarchy、invite_cards、families、family_members、tasks、guide_packages、guide_activities、training_plans、training_plan_items、assessment_materials、family_assessment_config、dan_assessment_results、teacher_messages、package_orders、task_plan_instances、users等表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配;教师班级管理(TeacherController)已标注`@Deprecated`,图中列为已废弃阶段 |

+ 196 - 72
docs/flows/health-checkin-flow.md

@@ -1,95 +1,219 @@
 # 用户使用流程图 — 健康打卡体系
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取打卡列表 /list]:::portMiniApp
-        A2 --> A3[📱 获取打卡详情 /detail]:::portMiniApp
-        A3 --> A4{📱 打卡类型}:::portMiniApp
-        A4 -->|综合打卡| B1[📱 创建打卡 /create]:::portMiniApp
-        A4 -->|运动打卡| B2[📱 创建运动打卡 /create]:::portMiniApp
-        A4 -->|饮食打卡| B3[📱 创建饮食打卡 /create]:::portMiniApp
-        A4 -->|睡眠打卡| B4[📱 创建睡眠打卡 /create]:::portMiniApp
-        A4 -->|喝水打卡| B5[📱 创建喝水打卡 /create]:::portMiniApp
-        A4 -->|冥想打卡| B6[📱 创建冥想打卡 /create]:::portMiniApp
-    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
+
+    %% ================================================================
+    %% 阶段一:每日打卡
+    %% ================================================================
+    subgraph 阶段一[阶段一:每日打卡]
+        direction TB
+
+        P1["🏠 打卡首页"]:::page
+        P1 -->|"查看打卡列表"| A1["🔗 POST /api/health/checkin/list"]:::api
+        A1 -->|"childId, yearMonth"| S1["⚙️ HealthCheckinService.getCheckins()"]:::service
+        S1 -->|"查询打卡记录"| D1["📦 health_checkins 表"]:::data
+
+        P1 -->|"选择打卡类型"| P1_choice{"综合 / 运动 / 饮食 / 睡眠 / 喝水 / 冥想"}:::page
+
+        P1_choice -->|"综合打卡"| A2["🔗 POST /api/daily/checkin/create"]:::api
+        A2 -->|"memberId, 饮食/运动/睡眠/饮水/心情评分"| S2["⚙️ DailyCheckinService.createCheckin()"]:::service
+        S2 -->|"写入一条打卡记录"| D2["📦 daily_checkin 表"]:::data
+
+        P1_choice -->|"运动打卡"| A3["🔗 POST /api/health/exercise/create"]:::api
+        A3 -->|"memberId, 运动类型, 时长, 强度"| S3["⚙️ HealthExerciseRecordMapper.insert()"]:::service
+        S3 -->|"写入运动记录"| D3["📦 health_exercise_records 表"]:::data
+
+        P1_choice -->|"饮食打卡"| A4["🔗 POST /api/health/meal/create"]:::api
+        A4 -->|"memberId, 餐食类型, 食物列表, 热量"| S4["⚙️ HealthMealRecordMapper.insert()"]:::service
+        S4 -->|"写入饮食记录"| D4["📦 health_meal_records 表"]:::data
 
-    subgraph 打卡管理
-        B1 --> C1[📱 更新打卡 /update]:::portMiniApp
-        C1 --> C2[📱 删除打卡 /delete]:::portMiniApp
+        P1_choice -->|"睡眠打卡"| A5["🔗 POST /api/health/sleep/create"]:::api
+        A5 -->|"memberId, 入睡/起床时间, 睡眠质量"| S5["⚙️ HealthSleepRecordMapper.insert()"]:::service
+        S5 -->|"写入睡眠记录"| D5["📦 health_sleep_records 表"]:::data
+
+        P1_choice -->|"喝水打卡"| A6["🔗 POST /api/health/water/create"]:::api
+        A6 -->|"memberId, 喝水量(ml)"| S6["⚙️ HealthWaterRecordMapper.insert()"]:::service
+        S6 -->|"写入喝水记录"| D6["📦 health_water_records 表"]:::data
+
+        P1_choice -->|"冥想打卡"| A7["🔗 POST /api/health/checkin/create"]:::api
+        A7 -->|"childId, behaviors=[meditation], 心情"| S7["⚙️ HealthCheckinService.createCheckin()"]:::service
+        S7 -->|"写入打卡记录(含行为标签)"| D1
     end
 
-    subgraph 连续打卡
-        C2 --> D1[📱 获取打卡进度 /progress/:childId]:::portMiniApp
-        D1 --> D2[📱 获取打卡统计 /stats]:::portMiniApp
-        D2 --> D3{📱 打卡中断?}:::portMiniApp
-        D3 -->|是| D4[📱 重置中断打卡 /reset]:::portMiniApp
-        D3 -->|否| D5[📱 保持连续]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:打卡管理
+    %% ================================================================
+    subgraph 阶段二[阶段二:打卡管理与统计]
+        D1 -->|"打卡记录ID"| P2["🏠 打卡详情页"]:::page
+        P2 -->|"查看详情"| A8["🔗 POST /api/daily/checkin/detail"]:::api
+        A8 -->|"id"| S8["⚙️ DailyCheckinService.getCheckinById()"]:::service
+        S8 -->|"单条打卡完整数据"| D2
+
+        P2 -->|"更新打卡"| A9["🔗 POST /api/daily/checkin/update"]:::api
+        A9 -->|"id, 更新字段"| S9["⚙️ DailyCheckinService.updateCheckin()"]:::service
+        S9 -->|"更新对应打卡记录"| D2
+
+        P2 -->|"删除打卡"| A10["🔗 POST /api/daily/checkin/delete"]:::api
+        A10 -->|"id, userId"| S10["⚙️ DailyCheckinService.deleteCheckin()"]:::service
+        S10 -->|"删除打卡记录"| D2
+
+        P2 -->|"查看统计"| A11["🔗 POST /api/health/checkin/stats"]:::api
+        A11 -->|"childId"| S11["⚙️ HealthCheckinService.countCheckins()"]:::service
+        S11 -->|"总打卡次数, 总能量值"| D1
+
+        P2 -->|"运动列表"| A12["🔗 POST /api/health/exercise/list"]:::api
+        A12 -->|"memberId"| S12["⚙️ HealthExerciseRecordMapper.selectList()"]:::service
+        S12 -->|"运动打卡列表"| D3
     end
 
-    subgraph 健康积分
-        D5 --> E1[📱 获取健康积分信息 /info]:::portMiniApp
-        E1 --> E2[📱 获取连续打卡天数 /streak]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:连续打卡
+    %% ================================================================
+    subgraph 阶段三[阶段三:连续打卡]
+        D1 -->|"打卡数据"| P3["🏠 连续打卡页"]:::page
+        P3 -->|"查看进度"| A13["🔗 POST /api/streak/progress/{childId}"]:::api
+        A13 -->|"path: childId"| S13["⚙️ StreakService.getStreakProgress()"]:::service
+        S13 -->|"连续天数, 里程碑, 积分"| D7["📦 streak_milestones + points_logs 表"]:::data
+
+        P3 -->|"获取连续天数"| A14["🔗 POST /api/health/score/streak"]:::api
+        A14 -->|"childId"| S14["⚙️ HealthScoreService.calculateStreakDays()"]:::service
+        S14 -->|"当前连续打卡天数"| D_HEALTH_SCORE["📦 health_score(内存计算)"]:::data
+
+        B0 -->|"每日凌晨检查"| A15["🔗 POST /api/streak/reset"]:::api
+        A15 -->|"(定时任务触发)"| S15["⚙️ StreakService.resetStreakIfNeeded()"]:::service
+        S15 -->|"中断>1天则重置连续计数"| D7
     end
 
-    subgraph 健康时间线
-        C2 --> F1[📱 获取健康时间线 /list]:::portMiniApp
-        F1 --> F2[📱 查看历史故事]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:健康积分与等级
+    %% ================================================================
+    subgraph 阶段四[阶段四:健康积分与等级]
+        D_HEALTH_SCORE -->|"积分数据"| P4["🏠 健康积分页"]:::page
+        P4 -->|"查看积分和等级"| A16["🔗 POST /api/health/score/info"]:::api
+        A16 -->|"childId"| S16["⚙️ HealthLevelService.getMemberLevelInfo()"]:::service
+        S16 -->|"总积分, 等级, 等级进度"| D8["📦 health_score + health_level 表"]:::data
+
+        P4 -->|"家庭排行榜"| A17["🔗 POST /api/family/health/ranking"]:::api
+        A17 -->|"familyId"| S17["⚙️ FamilyHealthScoreService.getFamilyRanking()"]:::service
+        S17 -->|"家庭成员排名(积分+连续天数)"| D8
     end
 
-    subgraph 健康预警
-        F2 --> G1[📱 获取活跃预警 /list]:::portMiniApp
-        G1 --> G2[📱 关闭预警 /dismiss]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:健康时间线
+    %% ================================================================
+    subgraph 阶段五[阶段五:健康时间线]
+        D1 -->|"打卡记录"| P5["🏠 健康时间线页"]:::page
+        P5 -->|"查看健康故事"| A18["🔗 POST /api/health/timeline/list"]:::api
+        A18 -->|"childId, limit"| S18["⚙️ HealthTimelineService.getTimeline()"]:::service
+        S18 -->|"按时间倒序的事件列表"| D9["📦 health_timeline_events 表"]:::data
     end
 
-    R1(("👤 家长/孩子")):::actor
-    R2(("🔥 连续打卡系统")):::system
+    %% ================================================================
+    %% 阶段六:健康预警
+    %% ================================================================
+    subgraph 阶段六[阶段六:健康预警]
+        D1 -->|"异常打卡模式"| P6["🏠 健康预警页"]:::page
+        P6 -->|"查看活跃预警"| A19["🔗 POST /api/health/alert/list"]:::api
+        A19 -->|"childId"| S19["⚙️ HealthAlertService.getActiveAlerts()"]:::service
+        S19 -->|"活跃预警列表"| D10["📦 health_alerts 表"]:::data
+
+        P6 -->|"关闭预警"| A20["🔗 POST /api/health/alert/dismiss"]:::api
+        A20 -->|"id"| S20["⚙️ HealthAlertService.dismiss()"]:::service
+        S20 -->|"标记预警已关闭"| D10
+    end
 
-    A1 -.- R1
-    D1 -.- R2
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    A0 -.- P1
+    A0 -.- P2
+    A0 -.- P3
+    A0 -.- P4
+    A0 -.- P5
+    A0 -.- P6
+    B0 -.- A15
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/health/checkin/list` | 获取打卡列表 | 📱小程序 |
-| `/api/health/checkin/create` | 创建打卡记录 | 📱小程序 |
-| `/api/health/checkin/delete` | 删除打卡记录 | 📱小程序 |
-| `/api/health/checkin/stats` | 打卡统计 | 📱小程序 |
-| `/api/daily/checkin/list` | 获取打卡列表 | 📱小程序 |
-| `/api/daily/checkin/detail` | 获取打卡详情 | 📱小程序 |
-| `/api/daily/checkin/create` | 创建打卡 | 📱小程序 |
-| `/api/daily/checkin/update` | 更新打卡 | 📱小程序 |
-| `/api/daily/checkin/delete` | 删除打卡 | 📱小程序 |
-| `/api/health/exercise/list` | 运动打卡列表 | 📱小程序 |
-| `/api/health/exercise/create` | 创建运动打卡 | 📱小程序 |
-| `/api/health/meal/list` | 饮食打卡列表 | 📱小程序 |
-| `/api/health/meal/create` | 创建饮食打卡 | 📱小程序 |
-| `/api/health/sleep/list` | 睡眠打卡列表 | 📱小程序 |
-| `/api/health/sleep/create` | 创建睡眠打卡 | 📱小程序 |
-| `/api/health/water/list` | 喝水打卡列表 | 📱小程序 |
-| `/api/health/water/create` | 创建喝水打卡 | 📱小程序 |
-| `/api/health/meditation/list` | 冥想打卡列表 | 📱小程序 |
-| `/api/health/meditation/create` | 创建冥想打卡 | 📱小程序 |
-| `/api/streak/progress/{childId}` | 打卡进度 | 📱小程序 |
-| `/api/streak/reset` | 重置中断打卡 | 📱小程序 |
-| `/api/health/score/info` | 健康积分信息 | 📱小程序 |
-| `/api/health/score/streak` | 连续天数 | 📱小程序 |
-| `/api/health/alert/list` | 活跃预警列表 | 📱小程序 |
-| `/api/health/alert/dismiss` | 关闭预警 | 📱小程序 |
-| `/api/health/timeline/list` | 健康时间线 | 📱小程序 |
+### 每日打卡
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/checkin/list` | 获取打卡列表 | 📱小程序 | `{childId, yearMonth}` | `List<HealthCheckin>` |
+| `POST /api/health/checkin/create` | 创建打卡记录 | 📱小程序 | `{childId, checkinDate, behaviors, note, mood}` | `HealthCheckin` |
+| `POST /api/health/checkin/delete` | 删除打卡记录 | 📱小程序 | `{id}` | `{success}` |
+| `POST /api/health/checkin/stats` | 打卡统计 | 📱小程序 | `{childId}` | `{totalCheckins, totalEnergy}` |
+| `POST /api/daily/checkin/list` | 获取综合打卡列表 | 📱小程序 | `{memberId}` | `List<DailyHealthCheckin>` |
+| `POST /api/daily/checkin/detail` | 获取打卡详情 | 📱小程序 | `{id}` | `DailyHealthCheckin` |
+| `POST /api/daily/checkin/create` | 创建综合打卡 | 📱小程序 | `{memberId, checkinDate, dietScore, exerciseScore, sleepScore, waterIntake, moodScore, ...}` | `DailyHealthCheckin` |
+| `POST /api/daily/checkin/update` | 更新打卡 | 📱小程序 | `{id, ...更新字段}` | `DailyHealthCheckin` |
+| `POST /api/daily/checkin/delete` | 删除打卡 | 📱小程序 | `{id, userId}` | `{success}` |
+
+### 专项打卡
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/exercise/list` | 运动打卡列表 | 📱小程序 | `{memberId}` | `List<HealthExerciseRecord>` |
+| `POST /api/health/exercise/create` | 创建运动打卡 | 📱小程序 | `{memberId, exerciseType, duration, intensity, ...}` | `HealthExerciseRecord` |
+| `POST /api/health/meal/list` | 饮食打卡列表 | 📱小程序 | `{memberId}` | `List<HealthMealRecord>` |
+| `POST /api/health/meal/create` | 创建饮食打卡 | 📱小程序 | `{memberId, mealType, foods, calories, ...}` | `HealthMealRecord` |
+| `POST /api/health/sleep/list` | 睡眠打卡列表 | 📱小程序 | `{memberId}` | `List<HealthSleepRecord>` |
+| `POST /api/health/sleep/create` | 创建睡眠打卡 | 📱小程序 | `{memberId, sleepTime, wakeTime, quality, ...}` | `HealthSleepRecord` |
+| `POST /api/health/water/list` | 喝水打卡列表 | 📱小程序 | `{memberId}` | `List<HealthWaterRecord>` |
+| `POST /api/health/water/create` | 创建喝水打卡 | 📱小程序 | `{memberId, waterIntake, ...}` | `HealthWaterRecord` |
+
+### 连续打卡
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/streak/progress/{childId}` | 打卡进度 | 📱小程序 | path: `childId` | `{streakDays, milestones, points}` |
+| `POST /api/streak/reset` | 重置中断打卡 | ⚙️系统自动 | — | `{success}` |
+
+### 健康积分与等级
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/score/info` | 健康积分信息 | 📱小程序 | `{childId}` | `{totalScore, level, levelProgress}` |
+| `POST /api/health/score/streak` | 连续天数 | 📱小程序 | `{childId}` | `Integer(连续天数)` |
+| `POST /api/family/health/ranking` | 家庭健康排行榜 | 📱小程序 | `{familyId}` | `{members: [{childId, score, streakDays, rank}], totalScore}` |
+
+### 健康时间线
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/timeline/list` | 健康时间线 | 📱小程序 | `{childId, limit}` | `List<HealthTimelineEvent>` |
+
+### 健康预警
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/alert/list` | 活跃预警列表 | 📱小程序 | `{childId}` | `List<HealthAlert>` |
+| `POST /api/health/alert/dismiss` | 关闭预警 | 📱小程序 | `{id}` | `{success}` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖每日打卡(6种类型)、打卡管理、连续打卡、健康积分、时间线、预警6个阶段,闭环完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 打卡中断后定时任务自动重置连续计数已覆盖;单个打卡类型缺少独立的更新/删除端点(仅综合打卡支持完整CRUD) |
+| 3 | **端点覆盖** | ✅ 完整 | 20个端点全部映射到流程图中,覆盖HealthCheckinController、DailyCheckinController、专项打卡控制器、StreakController、HealthScoreController、HealthTimelineController、HealthAlertController、FamilyHealthController |
+| 4 | **角色覆盖** | ⚠️ 部分覆盖 | 家长和孩子均可打卡,目前不区分角色权限;连续打卡重置为系统定时任务触发;无管理后台/规划师端入口 |
+| 5 | **数据实体** | ✅ 完整 | health_checkins、daily_checkin、health_exercise_records、health_meal_records、health_sleep_records、health_water_records、health_alerts、health_timeline_events、streak_milestones、points_logs、health_score均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配 |

+ 413 - 105
docs/flows/health-detection-flow.md

@@ -1,138 +1,446 @@
 # 用户使用流程图 — 身体健康检测
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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(("👤 家长<br/>开始")):::portMiniApp --> A2[📱 微信授权登录]:::portMiniApp
-        A2 --> A3[📱 创建/加入家庭]:::portMiniApp
-        A3 --> A4[📱 添加家庭成员<br/>(孩子/老人等)]:::portMiniApp
+    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_ADMIN(("🖥 管理员")):::actor
+    ROLE_GUIDE(("📋 规划师")):::actor
+    ROLE_SYS(("⚙️ AI引擎")):::actor
+
+    %% ================================================================
+    %% 阶段一:数据采集 — 上传与预览
+    %% ================================================================
+    subgraph 阶段一[阶段一:数据采集与解析预览]
+        direction TB
+
+        P1["🏠 家长端:健康检测首页"]:::page
+        P1 -->|"选择数据来源"| P1_choice{"肠道菌群PDF / 体检报告 / 舌诊拍照 / 健康问卷 / 手动录入"}:::page
+
+        P1_choice -->|"肠道菌群PDF"| P1a["🏠 选择PDF文件上传"]:::page
+        P1a -->|"PDF文件, 家庭ID"| A1["🔗 POST /api/health/report/upload"]:::api
+        A1 -->|"PDF文件流"| S1["⚙️ PdfParseService.parse()"]:::service
+        S1 -->|"解析结果: 分数, 指标, 菌群, 食材, 疾病风险"| D1["📦 ParsedReportResult(内存中)"]:::data
+        S1 -->|"猜测姓名+性别+年龄"| S1a["⚙️ HealthReportService.matchMemberByProfile()"]:::service
+        S1a -->|"匹配的家庭成员ID"| D2["📦 MemberMatchResult(内存中)"]:::data
+        D1 -->|"存入草稿"| S1b["⚙️ HealthReportDraftService.createDraft()"]:::service
+        S1b -->|"草稿记录, 有效期24h"| D3["📦 health_report_drafts 表"]:::data
+
+        P1_choice -->|"PDF/图片(两阶段)"| P1b["🏠 上传文件预览"]:::page
+        P1b -->|"文件, type(auto/image/tongue)"| A2["🔗 POST /api/health/report/parse-preview"]:::api
+        A2 -->|"文件流, 类型, 家庭ID"| S2{"PDF解析 / 图片"}
+        S2 -->|"PDF"| S1
+        S2 -->|"图片"| S1b
+
+        P1_choice -->|"舌诊拍照"| P1c["🏠 舌诊拍照页"]:::page
+        P1c -->|"type=tongue"| A2
+
+        P1_choice -->|"健康问卷"| P2["🏠 健康问卷页"]:::page
+        P2 -->|"报告ID, 孩子ID"| A3["🔗 POST /api/health/survey/create"]:::api
+        A3 -->|"报告ID, 用户ID, 孩子ID"| S3["⚙️ ReportSurveyService.createSurvey()"]:::service
+        S3 -->|"创建问卷记录"| D4["📦 report_surveys 表"]:::data
+        P2 -->|"提交问卷"| A4["🔗 POST /api/health/survey/submit"]:::api
+        A4 -->|"问卷ID, 问卷数据JSON"| S4["⚙️ ReportSurveyService.submitSurvey()"]:::service
+        S4 -->|"更新问卷状态为已完成"| D4
+
+        P1_choice -->|"手动录入"| P1d["🏠 手动录入表单"]:::page
+        P1d -->|"孩子ID, 报告类型, 评分, 指标"| A5["🔗 POST /api/health/report/create"]:::api
+        A5 -->|"报告字段 + 指标明细数组"| S5["⚙️ HealthReportService.createReport()"]:::service
+        S5 -->|"写入一条健康报告"| D5["📦 health_reports 表"]:::data
     end
 
-    subgraph 数据采集入口
-        A4 --> B0{📱 选择检测方式}:::portMiniApp
-        B0 --> B1[📱 上传肠道菌群PDF报告]:::portMiniApp
-        B0 --> B2[📱 上传体检报告/化验单]:::portMiniApp
-        B0 --> B3[📱 舌诊拍照上传]:::portMiniApp
-        B0 --> B4[📱 填写健康问卷]:::portMiniApp
-        B0 --> B5[📱 手动录入维度评分]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:预览编辑与确认入库
+    %% ================================================================
+    subgraph 阶段二[阶段二:预览编辑与确认入库]
+        D3 -->|"草稿ID"| P3["🏠 家长端:解析预览页"]:::page
+        P3 -->|"查看已解析指标"| A6["🔗 POST /api/health/report/confirm"]:::api
+        A6 -->|"草稿ID, 主体ID, 编辑后的载荷"| S6["⚙️ HealthReportService.confirmDraft()"]:::service
+        S6 -->|"正式写入: health_reports + 指标/菌群/疾病风险"| D5
+
+        S6 -->|"刷新7维评分"| S6a["⚙️ DimensionScoreService.refreshFromGutReport()"]:::service
+        S6a -->|"成员7维健康评分"| D6["📦 dimension_scores 表"]:::data
+
+        S6 -->|"刷新食材推荐"| S6b["⚙️ FoodRecommendService.recalculateForUser()"]:::service
+        S6b -->|"食材推荐指数"| D7["📦 food_recommend_index 表"]:::data
+
+        P3 -->|"放弃草稿"| A7["🔗 POST /api/health/report/discard"]:::api
+        A7 -->|"草稿ID"| S7["⚙️ HealthReportDraftService.markDiscarded()"]:::service
+        S7 -->|"标记草稿为已放弃"| D3
     end
 
-    subgraph AI解析层
-        B1 --> C1[⚙️ PDF解析引擎<br/>PdfParseService]:::portSystem
-        C1 --> C2{⚙️ 是否匹配到<br/>家庭成员?}:::portSystem
-        C2 -->|自动匹配<br/>姓名+性别+年龄| C3[⚙️ 标记到对应成员]:::portSystem
-        C2 -->|匹配失败| C4[📱 提示家长手动绑定]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:报告查看与数据分析
+    %% ================================================================
+    subgraph 阶段三[阶段三:报告查看与数据分析]
+        D5 -->|"孩子ID"| P4["🏠 家长端:健康报告页"]:::page
+        P4 -->|"查看最新报告"| A8["🔗 POST /api/health/report/latest"]:::api
+        A8 -->|"孩子ID"| S8["⚙️ HealthReportService.getLatestReport()"]:::service
+        S8 -->|"最新一条健康报告"| D5
+
+        P4 -->|"查看报告列表"| A9["🔗 POST /api/health/report/list"]:::api
+        A9 -->|"孩子ID"| S9["⚙️ HealthReportService.getUserReports()"]:::service
+        S9 -->|"该孩子的所有报告"| D5
 
-        B2 --> C5[⚙️ OCR/结构化解析]:::portSystem
-        C5 --> C6[⚙️ 提取指标: 身高/体重/<br/>血常规/视力等]:::portSystem
+        P4 -->|"查看报告详情"| A10["🔗 POST /api/health/report/detail"]:::api
+        A10 -->|"报告ID"| S10["⚙️ HealthReportService.getReportDetail()"]:::service
+        S10 -->|"报告主体+指标+菌群+疾病风险"| D5
 
-        B3 --> C7[⚙️ 舌诊AI分析<br/>TongueDiagnosisService]:::portSystem
-        C7 --> C8[⚙️ 舌苔/舌色/齿痕分析]:::portSystem
+        P4 -->|"查看指标明细"| A11["🔗 POST /api/health/indicator/list"]:::api
+        A11 -->|"报告ID"| S11["⚙️ HealthReportService.getReportIndicators()"]:::service
+        S11 -->|"健康指标列表"| D8["📦 health_indicators 表"]:::data
 
-        B4 --> C9[⚙️ 问卷评分计算]:::portSystem
-        B5 --> C10[⚙️ 直接录入评分]:::portSystem
+        P4 -->|"查看身体维度"| A12["🔗 POST /api/health/body/detail"]:::api
+        A12 -->|"孩子ID"| S12["⚙️ HealthReportService.getBodyDetail()"]:::service
+        S12 -->|"身体相关指标列表"| D8
+
+        P4 -->|"编辑报告"| A13["🔗 POST /api/health/report/edit"]:::api
+        A13 -->|"报告ID, 主体ID, 编辑后的载荷"| S13["⚙️ HealthReportService.updateReportFromPayload()"]:::service
+        S13 -->|"更新报告字段和关联数据"| D5
+
+        P4 -->|"归档报告"| A14["🔗 POST /api/health/report/archive"]:::api
+        A14 -->|"报告ID"| S14["⚙️ HealthReportService.archiveReport()"]:::service
+        S14 -->|"标记状态为 archived"| D5
+
+        P4 -->|"获取健康分析"| A15["🔗 POST /api/health/analysis"]:::api
+        A15 -->|"孩子ID"| S15["⚙️ HealthAnalysisService.analyzeLatestByUser()"]:::service
+        S15 -->|"综合分析 + 营养缺乏记录"| D9["📦 分析结果(内存中)"]:::data
     end
 
-    subgraph 报告预览与确认
-        C3 --> D1[📱 生成解析预览<br/>Phase 1 /parse-preview]:::portMiniApp
-        D1 --> D2{📱 家长确认<br/>数据是否正确?}:::portMiniApp
-        D2 -->|修改| D3[📱 家长在线编辑指标]:::portMiniApp
-        D3 --> D2
-        D2 -->|确认| D4[📱 正式入库<br/>Phase 2 /confirm]:::portMiniApp
-        C6 --> D1
-        C8 --> D1
+    %% ================================================================
+    %% 阶段四:营养分析与食材推荐
+    %% ================================================================
+    subgraph 阶段四[阶段四:营养分析与食材推荐]
+        D5 -->|"报告ID"| P5["🏠 家长端:营养分析页"]:::page
+        P5 -->|"查看营养缺乏"| A16["🔗 POST /api/health/nutrition/deficiency"]:::api
+        A16 -->|"孩子ID, 报告ID"| S16["⚙️ NutritionDeficiencyService.analyzeDeficiency()"]:::service
+        S16 -->|"营养缺乏记录列表"| D10["📦 nutrition_deficiency_records 表"]:::data
+
+        P5 -->|"查看营养档案"| A17["🔗 POST /api/health/nutrition/profile"]:::api
+        A17 -->|"孩子ID"| S17["⚙️ FamilyMemberNutritionProfileService.getProfile()"]:::service
+        S17 -->|"孩子营养档案"| D11["📦 nutrition_profiles 表"]:::data
+
+        P5 -->|"查看缺乏摘要"| A18["🔗 POST /api/health/nutrition/deficiency-summary"]:::api
+        A18 -->|"孩子ID"| S18["⚙️ FamilyMemberNutritionProfileService.getDeficiencySummary()"]:::service
+        S18 -->|"营养缺乏摘要"| D10
+
+        P5 -->|"查看趋势"| A19["🔗 POST /api/health/nutrition/trend"]:::api
+        A19 -->|"孩子ID"| S19["⚙️ FamilyMemberNutritionProfileService.getReportTrendData()"]:::service
+        S19 -->|"报告趋势数据"| D5
+
+        P5 -->|"查看食材推荐"| A20["🔗 POST /api/health/foods"]:::api
+        A20 -->|"报告ID"| S20["⚙️ FoodService.listByReportId()"]:::service
+        S20 -->|"食材推荐列表"| D12["📦 foods 表(关联报告ID)"]:::data
+
+        P5 -->|"按家庭查看"| A21["🔗 POST /api/health/foods/by-family"]:::api
+        A21 -->|"家庭ID"| S21["⚙️ FoodRecommendService.getByFamilyId()"]:::service
+        S21 -->|"家庭食材推荐列表"| D13["📦 food_recommend_index 表"]:::data
     end
 
-    subgraph 7维健康评分
-        D4 --> E1[⚙️ 维度评分引擎]:::portSystem
-        E1 --> E2[⚙️ 刷新7维健康评分]:::portSystem
-        E2 --> E3[⚙️ 营养缺乏分析]:::portSystem
-        E3 --> E4[⚙️ 食材推荐指数]:::portSystem
-        E4 --> E5[⚙️ 健康分析报告]:::portSystem
+    %% ================================================================
+    %% 阶段五:健康维度评分
+    %% ================================================================
+    subgraph 阶段五[阶段五:健康维度评分]
+        D6 -->|"成员ID"| P6["🏠 家长端:健康维度页"]:::page
+        P6 -->|"查看维度概览"| A22["🔗 POST /api/dimension/overview"]:::api
+        A22 -->|"成员ID"| S22["⚙️ DimensionScoreService.getHealthDimension()"]:::service
+        S22 -->|"七维健康评分概览"| D6
+
+        P6 -->|"手动录入评分"| A23["🔗 POST /api/dimension/upload"]:::api
+        A23 -->|"成员ID, 维度, 评分"| S23["⚙️ DimensionScoreService.uploadScore()"]:::service
+        S23 -->|"写入一条维度评分记录"| D6
+
+        P6 -->|"提交问卷评分"| A24["🔗 POST /api/dimension/questionnaire"]:::api
+        A24 -->|"成员ID, 维度, 答案列表"| S24["⚙️ DimensionScoreService.submitQuestionnaire()"]:::service
+        S24 -->|"计算评分并写入"| D6
+
+        P6 -->|"查看历史"| A25["🔗 POST /api/dimension/history"]:::api
+        A25 -->|"成员ID, 维度, 数量限制"| S25["⚙️ DimensionScoreService.getDimensionHistory()"]:::service
+        S25 -->|"指定维度的历史评分列表"| D6
     end
 
-    subgraph AI教练解读
-        E5 --> F1[📱 家长查看健康报告]:::portMiniApp
-        F1 --> F2{📱 是否需要<br/>AI解读?}:::portMiniApp
-        F2 -->|是| F3[📱 AI聊天解读报告]:::portMiniApp
-        F3 --> F4[📱 AI解析报告指标<br/>生成改善建议]:::portMiniApp
-        F4 --> F5[📱 AI生成任务计划]:::portMiniApp
-        F5 --> F6[📱 家长查看解读结果]:::portMiniApp
-        F2 -->|否| G1
+    %% ================================================================
+    %% 阶段六:日常健康打卡与健康预警
+    %% ================================================================
+    subgraph 阶段六[阶段六:日常健康打卡与健康预警]
+        P7["🏠 小程序:每日健康打卡页"]:::page
+        P7 -->|"创建打卡"| A26["🔗 POST /api/daily/checkin/create"]:::api
+        A26 -->|"饮食/运动/睡眠/饮水/心情数据"| S26["⚙️ DailyCheckinService.createCheckin()"]:::service
+        S26 -->|"写入一条日常打卡记录"| D14["📦 daily_health_checkins 表"]:::data
+
+        P7 -->|"查看列表"| A27["🔗 POST /api/daily/checkin/list"]:::api
+        A27 -->|"成员ID"| S27["⚙️ DailyCheckinService.getCheckinsByMember()"]:::service
+        S27 -->|"该成员的打卡列表"| D14
+
+        P7 -->|"查看健康预警"| A28["🔗 POST /api/health/alert/list"]:::api
+        A28 -->|"孩子ID"| S28["⚙️ HealthAlertService.getActiveAlerts()"]:::service
+        S28 -->|"活跃的健康预警列表"| D15["📦 health_alerts 表"]:::data
+
+        P7 -->|"关闭预警"| A29["🔗 POST /api/health/alert/dismiss"]:::api
+        A29 -->|"预警ID"| S29["⚙️ HealthAlertService.dismiss()"]:::service
+        S29 -->|"标记预警为已关闭"| D15
+
+        P7 -->|"家庭健康排名"| A30["🔗 POST /api/health/family/ranking"]:::api
+        A30 -->|"家庭ID"| S30["⚙️ FamilyHealthScoreService.getFamilyRanking()"]:::service
+        S30 -->|"家庭成员健康评分排名"| D16["📦 实时计算(内存中)"]:::data
     end
 
-    subgraph 专业身份介入
-        F6 --> G1{📱 是否需要<br/>深度介入?}:::portMiniApp
-        G1 -->|健康问题咨询| G2[📱 申请营养师服务]:::portMiniApp
-        G1 -->|全方位服务| G3[📱 申请管家服务]:::portMiniApp
-        G1 -->|成长规划| G4[📱 规划师查看报告]:::portMiniApp
-        G1 -->|自行跟进| G5[📱 结束]:::portMiniApp
+    %% ================================================================
+    %% 阶段七:报告绑定与权限管理
+    %% ================================================================
+    subgraph 阶段七[阶段七:报告绑定与权限管理]
+        D5 -->|"未绑定"| P8["🏠 家长端:报告绑定页"]:::page
+        P8 -->|"绑定到成员"| A31["🔗 POST /api/health/report/bind"]:::api
+        A31 -->|"报告ID, 主体ID"| S31["⚙️ HealthReportService.bindReportToMember()"]:::service
+        S31 -->|"更新报告主体ID"| D5
+
+        P8 -->|"未绑定报告列表"| A32["🔗 POST /api/health/report/unlinked"]:::api
+        A32 -->|"家庭ID"| S32["⚙️ HealthReportService.getUnlinkedReports()"]:::service
+        S32 -->|"该家庭未绑定成员的报告列表"| D5
 
-        G2 --> G2a[📋 营养师审核需求]:::portGuide
-        G2a --> G2b[📋 开具营养方案]:::portGuide
+        P8 -->|"添加查看权限"| A33["🔗 POST /api/health/report/permission/add"]:::api
+        A33 -->|"报告ID, 用户ID"| S33["⚙️ HealthReportService.addReportPermission()"]:::service
+        S33 -->|"写入权限记录"| D17["📦 health_report_permissions 表"]:::data
 
-        G3 --> G3a[📋 管家审核]:::portGuide
-        G3a --> G3b[📋 管家建档]:::portGuide
-        G3b --> G3c[📋 定期跟进]:::portGuide
+        P8 -->|"移除查看权限"| A34["🔗 POST /api/health/report/permission/remove"]:::api
+        A34 -->|"报告ID, 用户ID"| S34["⚙️ HealthReportService.removeReportPermission()"]:::service
+        S34 -->|"删除权限记录"| D17
 
-        G4 --> G4a[📋 规划师查看报告]:::portGuide
-        G4a --> G4b[📋 规划师下发改善任务]:::portGuide
+        P8 -->|"检查权限"| A35["🔗 POST /api/health/report/permission/check"]:::api
+        A35 -->|"报告ID, 用户ID"| S35["⚙️ HealthReportService.hasReportPermission()"]:::service
+        S35 -->|"是否有权限(布尔值)"| D17
     end
 
-    subgraph 持续跟踪
-        G5 --> H1[📱 家长定期上传新报告]:::portMiniApp
-        H1 --> H2[⚙️ 系统对比历史趋势]:::portSystem
-        H2 --> H3[📱 提示改善进展/异常]:::portMiniApp
-        H3 --> F1
+    %% ================================================================
+    %% 阶段八:管理端操作
+    %% ================================================================
+    subgraph 阶段八[阶段八:管理端操作]
+        D3 -->|"待审核草稿"| P9["🖥 管理后台:报告审核页"]:::page
+        P9 -->|"待审核列表"| A36["🔗 POST /api/health/report/audit/pending"]:::api
+        A36 -->|"页码, 每页数"| S36["⚙️ HealthReportService.listPendingAudits()"]:::service
+        S36 -->|"待审核草稿分页列表"| D3
+
+        P9 -->|"审核通过"| A37["🔗 POST /api/health/report/audit/confirm"]:::api
+        A37 -->|"草稿ID"| S37["⚙️ HealthReportService.auditConfirm()"]:::service
+        S37 -->|"正式入库"| D5
+
+        P9 -->|"审核驳回"| A38["🔗 POST /api/health/report/audit/discard"]:::api
+        A38 -->|"草稿ID, 驳回原因"| S38["⚙️ HealthReportService.auditDiscard()"]:::service
+        S38 -->|"标记草稿为已驳回"| D3
+
+        P9 -->|"管理端报告列表"| A39["🔗 POST /api/health/report/admin-list"]:::api
+        A39 -->|"页码, 每页数"| S39["⚙️ HealthReportService.listAllReportsForAdmin()"]:::service
+        S39 -->|"全量报告分页列表"| D5
     end
 
-    R1(("👤 家长")):::actor
-    R2(("🤖 AI教练")):::role
-    R3(("🥗 营养师")):::role
-    R4(("🏠 管家")):::role
-    R5(("📋 规划师")):::role
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P3
+    ROLE_PARENT -.- P4
+    ROLE_PARENT -.- P5
+    ROLE_PARENT -.- P6
+    ROLE_PARENT -.- P7
+    ROLE_PARENT -.- P8
+    ROLE_GUIDE -.- P9
+    ROLE_ADMIN -.- P9
+    ROLE_SYS -.- S1
+    ROLE_SYS -.- S6a
+    ROLE_SYS -.- S6b
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/health/report/create` | 创建健康报告 | 📱小程序 |
-| `/api/health/report/latest` | 获取最新报告 | 📱小程序 |
-| `/api/health/report/list` | 报告列表 | 📱小程序 |
-| `/api/health/report/detail` | 报告完整详情 | 📱小程序 |
-| `/api/health/report/edit` | 编辑报告 | 📱小程序 |
-| `/api/health/report/upload` | 上传PDF报告 | 📱小程序 |
-| `/api/health/report/parse-preview` | 解析预览 | 📱小程序 |
-| `/api/health/report/confirm` | 确认入库 | 📱小程序 |
-| `/api/health/report/discard` | 放弃草稿 | 📱小程序 |
-| `/api/health/report/bind` | 绑定到成员 | 📱小程序 |
-| `/api/health/report/admin-list` | 管理端报告列表 | 🖥管理后台 |
-| `/api/health/report/unlinked` | 未绑定报告 |
-| `/api/health/report/permission/add` | 添加查看权限 |
-| `/api/health/report/permission/remove` | 移除权限 |
-| `/api/health/report/permission/check` | 检查权限 |
-| `/api/health/indicator/list` | 指标明细 |
-| `/api/health/body/detail` | 身体维度数据 |
-| `/api/health/nutrition/deficiency` | 营养缺乏分析 |
-| `/api/health/nutrition/profile` | 孩子营养档案 |
-| `/api/health/survey/create` | 创建调研问卷 |
-| `/api/health/survey/submit` | 提交问卷 |
-| `/api/health/survey/status` | 问卷状态 |
-| `/api/dan-report/upload` | DAN报告上传 |
-| `/api/dan-report/{id}/confirm` | 确认DAN报告 |
-| `/api/dan-report/list` | DAN报告列表 |
+### 健康报告 CRUD
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/report/create` | 手动创建健康报告 | 📱小程序 | `{childId, reportType, overallScore, indicators[]}` | `HealthReport` |
+| `POST /api/health/report/latest` | 获取最新报告 | 📱小程序 | `{childId}` | `HealthReport` |
+| `POST /api/health/report/list` | 获取报告列表 | 📱小程序 | `{childId}` | `List<HealthReport>` |
+| `POST /api/health/report/detail` | 获取报告完整详情 | 📱小程序 | `{reportId}` | `{report, indicators, gutFlora, diseaseRisks, foods}` |
+| `POST /api/health/report/edit` | 编辑报告数据 | 📱小程序 | `{reportId, subjectId, payload}` | `"已保存"` |
+| `POST /api/health/report/archive` | 归档报告 | 📱小程序 | `{reportId}` | `boolean` |
+| `POST /api/health/report/upload` | 上传PDF并自动解析入库 | 📱小程序 | `multipart: file, familyId` | `{report, matchedMemberId, needBind}` |
+| `POST /api/health/report/parse-preview` | 上传解析预览(两阶段Phase 1) | 📱小程序 | `multipart: file, type(auto/image/tongue), familyId` | `{draftId, payload, matchedMemberId, candidates}` |
+| `POST /api/health/report/confirm` | 确认草稿入库(两阶段Phase 2) | 📱小程序 | `{draftId, subjectId, payload}` | `HealthReport` |
+| `POST /api/health/report/discard` | 放弃草稿 | 📱小程序 | `{draftId}` | `"草稿已放弃"` |
+| `POST /api/health/report/bind` | 绑定报告到成员 | 📱小程序 | `{reportId, subjectId}` | `"报告绑定成功"` |
+| `POST /api/health/report/unlinked` | 获取未绑定报告列表 | 📱小程序 | `{familyId}` | `List<HealthReport>` |
+| `POST /api/health/report/admin-list` | 管理端全量报告列表 | 🖥管理后台 | `{page, size}` | `Page<HealthReport>` |
+| `POST /api/health/report/auto-create-member` | 自动创建成员并绑定报告 | 📱小程序 | `{reportId, familyId, memberName}` | `{member}` |
+| `POST /api/health/report/audit/pending` | 管理端待审核草稿列表 | 🖥管理后台 | `{page, size}` | `List<HealthReportDraft>` |
+| `POST /api/health/report/audit/confirm` | 审核通过草稿 | 🖥管理后台 | `{draftId}` | `HealthReport` |
+| `POST /api/health/report/audit/discard` | 审核驳回草稿 | 🖥管理后台 | `{draftId, reason}` | `"已驳回"` |
+
+### 报告权限
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/report/permission/add` | 添加查看权限 | 📱小程序 | `{reportId, userId}` | `"权限添加成功"` |
+| `POST /api/health/report/permission/remove` | 移除查看权限 | 📱小程序 | `{reportId, userId}` | `"权限移除成功"` |
+| `POST /api/health/report/permission/check` | 检查查看权限 | 📱小程序 | `{reportId, userId}` | `{hasPermission}` |
+
+### 指标与身体维度
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/indicator/list` | 获取报告指标明细 | 📱小程序 | `{reportId}` | `List<HealthIndicator>` |
+| `POST /api/health/body/detail` | 获取身体维度数据 | 📱小程序 | `{childId}` | `List<HealthIndicator>` |
+
+### 营养分析
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/nutrition/deficiency` | 营养缺乏分析 | 📱小程序 | `{childId, reportId}` | `List<NutritionDeficiencyRecord>` |
+| `POST /api/health/nutrition/profile` | 孩子营养档案 | 📱小程序 | `{childId}` | `{profile}` |
+| `POST /api/health/nutrition/deficiency-summary` | 营养缺乏摘要 | 📱小程序 | `{childId}` | `{summary}` |
+| `POST /api/health/nutrition/trend` | 报告趋势数据 | 📱小程序 | `{childId}` | `{trend}` |
+| `POST /api/health/nutrition/mappings` | 指标-营养素映射列表 | 🖥管理后台 | — | `List<NutritionIndicatorMapping>` |
+| `POST /api/health/nutrition/mapping/create` | 创建指标-营养素映射 | 🖥管理后台 | `NutritionIndicatorMapping` | `null` |
+| `POST /api/health/nutrition/mapping/update` | 更新指标-营养素映射 | 🖥管理后台 | `NutritionIndicatorMapping` | `null` |
+| `POST /api/health/nutrition/mapping/delete` | 删除指标-营养素映射 | 🖥管理后台 | `{id}` | `null` |
+
+### 食材推荐
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/foods` | 获取报告食材推荐 | 📱小程序 | `{reportId}` | `List<Food>` |
+| `POST /api/health/foods/by-family` | 获取家庭食材推荐 | 📱小程序 | `{familyId}` | `List<FoodRecommendIndex>` |
+
+### 健康分析
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/analysis` | 获取综合分析(含营养缺乏) | 📱小程序 | `{childId}` | `{analysis, deficiencyRecords}` |
+
+### 调研问卷
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/survey/create` | 创建调研问卷 | ⚙️系统自动 | `{reportId, childId}` | `ReportSurvey` |
+| `POST /api/health/survey/submit` | 提交调研问卷 | 📱小程序 | `{surveyId, surveyData}` | `ReportSurvey` |
+| `POST /api/health/survey/status` | 检查问卷状态 | 📱小程序 | `{reportId}` | `{completed, pendingSurveyId}` |
+
+### 日常健康打卡
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/daily/checkin/list` | 获取打卡列表 | 📱小程序 | `{memberId}` | `List<DailyHealthCheckin>` |
+| `POST /api/daily/checkin/detail` | 获取打卡详情 | 📱小程序 | `{id}` | `DailyHealthCheckin` |
+| `POST /api/daily/checkin/create` | 创建打卡记录 | 📱小程序 | `{memberId, diet, exercise, sleep, water, mood}` | `DailyHealthCheckin` |
+| `POST /api/daily/checkin/update` | 更新打卡记录 | 📱小程序 | `{id, ...}` | `DailyHealthCheckin` |
+| `POST /api/daily/checkin/delete` | 删除打卡记录 | 📱小程序 | `{id, userId}` | `"删除成功"` |
+
+### 健康预警
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/alert/list` | 获取活跃预警列表 | 📱小程序 | `{childId}` | `List<HealthAlert>` |
+| `POST /api/health/alert/dismiss` | 关闭预警 | 📱小程序 | `{id}` | `"ok"` |
+
+### 家庭健康排名
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/family/ranking` | 获取家庭健康排名 | 📱小程序 | `{familyId}` | `{ranking, totalScore}` |
+
+### 健康维度评分
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/dimension/overview` | 获取维度评分概览 | 📱小程序 | `{memberId}` | `HealthDimensionVO` |
+| `POST /api/dimension/upload` | 手动录入维度评分 | 📱小程序 | `{memberId, dimension, score}` | `null` |
+| `POST /api/dimension/questionnaire` | 问卷提交维度评分 | 📱小程序 | `{memberId, dimension, answers[]}` | `null` |
+| `POST /api/dimension/history` | 获取维度历史记录 | 📱小程序 | `{memberId, dimension, limit}` | `List<DimensionItem>` |
+
+### 反馈
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/feedback/submit` | 提交报告反馈 | 📱小程序 | `{reportId, content}` | `"ok"` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    FamilyMember ||--o{ HealthReport : "报告主体"
+    HealthReport ||--o{ HealthIndicator : "一份报告多个指标"
+    HealthReport ||--o{ HealthGutFlora : "一份报告多个菌群"
+    HealthReport ||--o{ HealthDiseaseRisk : "一份报告多个疾病风险"
+    HealthReport ||--o{ Food : "一份报告多个食材推荐"
+    HealthReport ||--o{ ReportSurvey : "一份报告一个问卷"
+    HealthReport ||--o{ NutritionDeficiencyRecord : "一份报告多个缺乏记录"
+    FamilyMember ||--o{ DimensionScore : "一个成员多个维度评分"
+    FamilyMember ||--o{ DailyHealthCheckin : "一个成员多次打卡"
+    FamilyMember ||--o{ FoodRecommendIndex : "一个成员食材推荐"
+    HealthReportDraft ||--|| HealthReport : "草稿确认后关联"
+
+    HealthReport {
+        Long id PK
+        Long subjectId FK "报告主体(家庭成员)"
+        Long userId FK "上传人"
+        Long familyId FK
+        String reportType "physical_exam / gut_flora"
+        Integer overallScore "健康总分 0-100"
+        Integer gutHealthScore "菌群分"
+        String gutAge "肠道年龄"
+        String gutType "肠型"
+        String healthRating "评级文字"
+        Date reportDate
+    }
+
+    HealthIndicator {
+        Long id PK
+        Long reportId FK
+        String category "指标类别"
+        String indicatorName "指标名"
+        String indicatorValue "数值"
+        String unit "单位"
+        String refRange "参考范围"
+        String status "normal/abnormal"
+    }
+
+    HealthReportDraft {
+        Long id PK
+        Long userId FK
+        Long familyId FK
+        String reportType
+        String fileUrl
+        String payloadJson "解析载荷JSON"
+        String status "pending/confirmed/discarded"
+        Date expireAt "有效期24h"
+    }
+
+    DimensionScore {
+        Long id PK
+        Long memberId FK
+        String dimension "维度标识"
+        Integer score
+        String source "gut_report / manual / questionnaire"
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖数据采集(上传/拍照/问卷/手动)、预览确认、报告查看、营养分析、维度评分、日常打卡、报告绑定与权限、管理审核共8个阶段,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | PDF解析失败提示已处理;草稿过期(24h)自动拒绝确认已覆盖;未匹配到家庭成员时提示手动绑定;管理端审核驳回流程已覆盖 |
+| 3 | **端点覆盖** | ✅ 完整 | 40+个端点全部映射到流程图中,与代码实际暴露的`/api/health/*`, `/api/daily/checkin/*`, `/api/dimension/*`, `/api/health/survey/*`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长(数据上传/查看/绑定)、管理员(审核/配置)、规划师(查看报告)、系统(AI解析/评分刷新)均已覆盖 |
+| 5 | **数据实体** | ✅ 完整 | health_reports表、health_indicators表、health_gut_flora表、health_report_drafts表、dimension_scores表、daily_health_checkins表等11个核心实体均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(HealthReportController、DailyCheckinController、HealthDimensionController、HealthAlertController、FamilyHealthController、ReportSurveyController)中的`@PostMapping`匹配 |

+ 363 - 72
docs/flows/knowledge-invite-flow.md

@@ -1,95 +1,386 @@
 # 用户使用流程图 — 健康知识库与邀请
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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(("🔧 管理员")):::portAdmin --> A2[🖥 查询知识库 /query]:::portAdmin
-        A2 --> A3[🖥 批量查询 /batch-query]:::portAdmin
-        A3 --> A4[🖥 列表查询 /list]:::portAdmin
-        A4 --> A5[🖥 新增条目 /add]:::portAdmin
-        A5 --> A6[🖥 更新条目 /update]:::portAdmin
-        A6 --> A7[🖥 删除条目 /delete]:::portAdmin
-        A7 --> A8[🖥 从JSON导入 /import]:::portAdmin
-    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
+
+    %% ============ 角色 ============
+    ROLE_ADMIN(("🔧 管理员")):::actor
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_SYSTEM(("⚙️ 微信API")):::actor
+
+    %% ================================================================
+    %% 阶段一:健康知识库管理
+    %% ================================================================
+    subgraph 阶段一[阶段一:健康知识库管理]
+        direction TB
+
+        P1["🖥 管理后台:健康知识库页"]:::page
+        P1 -->|"选择操作"| P1_choice{"查询 / 新增 / 编辑 / 删除 / 导入"}:::page
+
+        P1_choice -->|"查询单条"| A1["🔗 POST /api/health/knowledge/query"]:::api
+        A1 -->|"itemType, itemName"| S1["⚙️ HealthKnowledgeBaseService.query()"]:::service
+        S1 -->|"类型+名称精确匹配"| D1["📦 health_knowledge_base 表"]:::data
+
+        P1_choice -->|"批量查询"| A2["🔗 POST /api/health/knowledge/batch-query"]:::api
+        A2 -->|"queries: [{itemType, itemName}]"| S2["⚙️ HealthKnowledgeBaseService.batchQuery()"]:::service
+        S2 -->|"批量匹配返回Map"| D1
+
+        P1_choice -->|"列表查询"| A3["🔗 POST /api/health/knowledge/list"]:::api
+        A3 -->|"无参数"| S3["⚙️ HealthKnowledgeBaseService.listAll()"]:::service
+        S3 -->|"返回全量知识库"| D1
+
+        P1_choice -->|"新增条目"| P1a["🖥 知识库录入表单"]:::page
+        P1a -->|"itemType, itemName, category, description, ..."| A4["🔗 POST /api/health/knowledge/add"]:::api
+        A4 -->|"知识条目完整信息"| S4["⚙️ HealthKnowledgeBaseService.save()"]:::service
+        S4 -->|"写入一条知识记录"| D1
+
+        P1_choice -->|"编辑条目"| P1b["🖥 知识库编辑表单"]:::page
+        P1b -->|"id及更新字段"| A5["🔗 POST /api/health/knowledge/update"]:::api
+        A5 -->|"实体ID, 更新字段"| S5["⚙️ HealthKnowledgeBaseService.updateById()"]:::service
+        S5 -->|"更新对应知识记录"| D1
 
-    subgraph KB v3查询
-        A8 --> B1[🖥 查询菌属功能 /v3/bacteria/query]:::portAdmin
-        B1 --> B2[🖥 批量查询菌属 /v3/bacteria/batch-query]:::portAdmin
-        B2 --> B3[🖥 查询指标调整 /v3/indicator/query]:::portAdmin
-        B3 --> B4[🖥 查询食物营养 /v3/food/query]:::portAdmin
-        B4 --> B5[🖥 获取原始数据 /v3/section]:::portAdmin
+        P1_choice -->|"删除条目"| P1c["🖥 确认删除"]:::page
+        P1c -->|"id"| A6["🔗 POST /api/health/knowledge/delete"]:::api
+        A6 -->|"知识条目ID"| S6["⚙️ HealthKnowledgeBaseService.removeById()"]:::service
+        S6 -->|"物理删除"| D1
+
+        P1_choice -->|"从JSON导入"| A7["🔗 POST /api/health/knowledge/import"]:::api
+        A7 -->|"无参数(读取本地JSON)"| S7["⚙️ KnowledgeBaseDataImporter.importAll()"]:::service
+        S7 -->|"批量导入菌属/指标/营养素等"| D1
     end
 
-    subgraph 邀请码管理
-        C1(("👤 用户")):::portMiniApp --> C2[📱 生成邀请码 /invite/code]:::portMiniApp
-        C2 --> C3[📱 绑定邀请 /invite/bind]:::portMiniApp
-        C3 --> C4[📱 获取邀请列表 /invite/list]:::portMiniApp
-        C4 --> C5[📱 获取邀请汇总 /invite/summary]:::portMiniApp
-        C5 --> C6[📱 获取邀请二维码 /invite/qrcode]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:KB v3 查询
+    %% ================================================================
+    subgraph 阶段二[阶段二:KB v3 查询]
+        direction TB
+
+        D1 -->|"v3数据"| P2["🖥 管理后台:KB v3查询页"]:::page
+        P2 -->|"选择查询类型"| P2_choice{"菌属 / 指标 / 食物 / 章节"}:::page
+
+        P2_choice -->|"查询菌属功能"| A8["🔗 POST /api/health/knowledge/v3/bacteria/query"]:::api
+        A8 -->|"name(菌名,支持属级回退)"| S8["⚙️ KnowledgeBaseV3Service.lookupBacteria()"]:::service
+        S8 -->|"菌属功能说明"| D2["📦 v3索引(内存)"]:::data
+
+        P2_choice -->|"批量查询菌属"| A9["🔗 POST /api/health/knowledge/v3/bacteria/batch-query"]:::api
+        A9 -->|"names: [...]"| S9["⚙️ KnowledgeBaseV3Service.batchLookupBacteria()"]:::service
+        S9 -->|"批量菌属功能说明"| D2
+
+        P2_choice -->|"查询指标调整"| A10["🔗 POST /api/health/knowledge/v3/indicator/query"]:::api
+        A10 -->|"name(指标名称)"| S10["⚙️ KnowledgeBaseV3Service.lookupIndicator()"]:::service
+        S10 -->|"指标调整建议"| D2
+
+        P2_choice -->|"查询食物营养"| A11["🔗 POST /api/health/knowledge/v3/food/query"]:::api
+        A11 -->|"name(食物名称)"| S11["⚙️ KnowledgeBaseV3Service.lookupFood()"]:::service
+        S11 -->|"食物营养数据"| D2
+
+        P2_choice -->|"获取章节数据"| A12["🔗 POST /api/health/knowledge/v3/section"]:::api
+        A12 -->|"section(章节名,空则返回目录)"| S12["⚙️ KnowledgeBaseV3Service.getSection()"]:::service
+        S12 -->|"章节完整原始数据或目录结构"| D2
     end
 
-    subgraph 邀请卡片
-        C6 --> D1[📱 生成邀请码 /invite-card/generate]:::portMiniApp
-        D1 --> D2[📱 验证邀请码 /invite-card/verify]:::portMiniApp
-        D2 --> D3[📱 接受邀请 /invite-card/accept]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:Dify知识库
+    %% ================================================================
+    subgraph 阶段三[阶段三:Dify知识库管理]
+        direction TB
+
+        P3["🖥 管理后台:Dify知识库页"]:::page
+        P3 -->|"选择操作"| P3_choice{"列表 / 查看 / 新增 / 删除"}:::page
+
+        P3_choice -->|"列表查询"| A13["🔗 POST /api/admin/knowledge-base/list"]:::api
+        A13 -->|"keyword, status, page, size"| S13["⚙️ DanKnowledgeBaseService.list()"]:::service
+        S13 -->|"分页查询知识库"| D3["📦 dan_knowledge_base 表"]:::data
+
+        P3_choice -->|"查看详情"| A14["🔗 POST /api/admin/knowledge-base/get"]:::api
+        A14 -->|"id"| S14["⚙️ DanKnowledgeBaseService.getWithAssociations()"]:::service
+        S14 -->|"知识完整信息+维度/标签关联"| D3
+
+        P3_choice -->|"新增/编辑"| P3a["🖥 知识库编辑表单"]:::page
+        P3a -->|"title, content, dimensionIds, tagIds, ..."| A15["🔗 POST /api/admin/knowledge-base/save"]:::api
+        A15 -->|"知识条目+维度/标签绑定"| S15["⚙️ DanKnowledgeBaseService.saveWithAssociations()"]:::service
+        S15 -->|"写入知识记录+关联, 同步Dify"| S15a["⚙️ DifySyncService.syncToDify()"]:::service
+        S15a -->|"同步到Dify AI知识库"| D3a["📦 Dify外部API"]:::external
+
+        P3_choice -->|"删除"| A16["🔗 POST /api/admin/knowledge-base/delete"]:::api
+        A16 -->|"id"| S16["⚙️ DanKnowledgeBaseService.deleteKnowledge()"]:::service
+        S16 -->|"逻辑删除知识记录"| D3
+
+        P3_choice -->|"绑定维度"| A17["🔗 POST /api/admin/knowledge-base/bind-dimensions"]:::api
+        A17 -->|"knowledgeId, dimensionIds"| S17["⚙️ DanKnowledgeBaseService.bindDimensions()"]:::service
+        S17 -->|"写入维度关联表"| D3b["📦 知识-维度关联表"]:::data
+
+        P3_choice -->|"绑定标签"| A18["🔗 POST /api/admin/knowledge-base/bind-tags"]:::api
+        A18 -->|"knowledgeId, tagIds"| S18["⚙️ DanKnowledgeBaseService.bindTags()"]:::service
+        S18 -->|"写入标签关联表"| D3c["📦 知识-标签关联表"]:::data
+
+        P3_choice -->|"上传文件"| P3b["🖥 选择文件上传"]:::page
+        P3b -->|"file (multipart)"| A19["🔗 POST /api/admin/knowledge-base/upload-file"]:::api
+        A19 -->|"文件"| S19["⚙️ 文件存储到本地"]:::service
+        S19 -->|"保存到 uploads/knowledge/ 目录"| D3d["📦 本地文件系统"]:::data
+
+        P3_choice -->|"抓取网页"| P3c["🖥 输入网页URL"]:::page
+        P3c -->|"url"| A20["🔗 POST /api/admin/knowledge-base/fetch-url"]:::api
+        A20 -->|"网页URL"| S20["⚙️ RestTemplate抓取并解析"]:::service
+        S20 -->|"提取标题+正文内容"| D3e["📦 抓取结果(内存)"]:::data
     end
 
-    subgraph 邀请里程碑
-        D3 --> E1[📱 获取里程碑列表 /invite/milestone/list]:::portMiniApp
-        E1 --> E2[📱 领取里程碑奖励 /invite/milestone/claim]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:邀请推广
+    %% ================================================================
+    subgraph 阶段四[阶段四:邀请推广]
+        direction TB
+
+        P4["📱 小程序:邀请推广页"]:::page
+        P4 -->|"选择操作"| P4_choice{"生成邀请码 / 绑定 / 查看 / 二维码"}:::page
+
+        P4_choice -->|"生成邀请码"| A21["🔗 POST /api/invite/code"]:::api
+        A21 -->|"userId(从token提取)"| S21["⚙️ CommissionService.getOrCreateReferralCode()"]:::service
+        S21 -->|"查询或生成推广码"| D4["📦 推广码(内存/用户关联)"]:::data
+
+        P4_choice -->|"绑定邀请"| P4a["📱 输入/扫描邀请码"]:::page
+        P4a -->|"referralCode"| A22["🔗 POST /api/invite/bind"]:::api
+        A22 -->|"推广码"| S22["⚙️ CommissionService.bindReferral()"]:::service
+        S22 -->|"建立邀请关系"| D4a["📦 邀请关系记录"]:::data
+
+        P4_choice -->|"查看邀请列表"| A23["🔗 POST /api/invite/list"]:::api
+        A23 -->|"page, size"| S23["⚙️ CommissionService.getMyReferrals()"]:::service
+        S23 -->|"分页查询被我邀请的用户"| D4b["📦 users 表(通过推广码关联)"]:::data
+
+        P4_choice -->|"邀请汇总"| A24["🔗 POST /api/invite/summary"]:::api
+        A24 -->|"userId"| S24["⚙️ CommissionService.getReferralSummary()"]:::service
+        S24 -->|"总邀请数, 奖励统计"| D4c["📦 ReferralSummaryDTO(内存)"]:::data
+
+        P4_choice -->|"生成二维码"| A25["🔗 POST /api/invite/qrcode"]:::api
+        A25 -->|"userId"| S25["⚙️ CommissionService.getOrCreateReferralCode()"]:::service
+        S25 -->|"获取推广码"| S25a["⚙️ WechatService.generateWxacode()"]:::service
+        S25a -->|"小程序码参数"| A25a["🔗 调用微信小程序码API"]:::external
+        A25a -->|"小程序码图片base64"| D4d["📦 小程序码(返回前端)"]:::data
     end
 
-    subgraph 入门引导
-        C1 --> F1[📱 获取引导进度 /onboarding/progress]:::portMiniApp
-        F1 --> F2[📱 领取奖励 /onboarding/claim]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:邀请卡片
+    %% ================================================================
+    subgraph 阶段五[阶段五:邀请卡片]
+        direction TB
+
+        P5["📱 小程序:邀请卡片页"]:::page
+        P5 -->|"选择操作"| P5_choice{"生成 / 验证 / 接受"}:::page
+
+        P5_choice -->|"生成邀请卡片"| P5a["📱 选择邀请类型"]:::page
+        P5a -->|"type(child/family/guide), refId"| A26["🔗 POST /api/invite-card/generate"]:::api
+        A26 -->|"邀请类型, 关联ID, 创建人"| S26["⚙️ InviteCardService.generate()"]:::service
+        S26 -->|"生成邀请码, 设定过期时间"| D5["📦 invite_card 表"]:::data
+
+        P5_choice -->|"验证邀请码"| P5b["📱 输入/扫描邀请码"]:::page
+        P5b -->|"code"| A27["🔗 POST /api/invite-card/verify"]:::api
+        A27 -->|"邀请码字符串"| S27["⚙️ InviteCardService.verify()"]:::service
+        S27 -->|"校验有效性, 返回邀请信息"| D5
+
+        P5_choice -->|"接受邀请"| P5c["📱 填写手机号"]:::page
+        P5c -->|"code, phone"| A28["🔗 POST /api/invite-card/accept"]:::api
+        A28 -->|"邀请码, 手机号"| S28["⚙️ InviteCardService.accept()"]:::service
+        S28 -->|"标记已使用, 完成邀请逻辑"| D5
     end
 
-    R1(("🔧 管理员")):::actor
-    R2(("👤 用户")):::role
+    %% ================================================================
+    %% 阶段六:邀请里程碑与新手引导
+    %% ================================================================
+    subgraph 阶段六[阶段六:里程碑与引导]
+        direction TB
+
+        P6["📱 小程序:邀请奖励页"]:::page
+        P6 -->|"里程碑列表"| A29["🔗 POST /api/invite/milestone/list"]:::api
+        A29 -->|"userId"| S29["⚙️ 查询里程碑进度"]:::service
+        S29 -->|"所有里程碑及当前达成状态"| D6["📦 invite_milestone 表"]:::data
+
+        P6 -->|"领取里程碑奖励"| P6a["📱 点击领取按钮"]:::page
+        P6a -->|"milestone"| A30["🔗 POST /api/invite/milestone/claim"]:::api
+        A30 -->|"里程碑标识"| S30["⚙️ 发放积分/能量奖励"]:::service
+        S30 -->|"更新状态为claimed"| D6
+
+        P7["📱 小程序:新手引导页"]:::page
+        P7 -->|"查看引导进度"| A31["🔗 POST /api/onboarding/progress"]:::api
+        A31 -->|"userId"| S31["⚙️ OnboardingService.getProgress()"]:::service
+        S31 -->|"引导任务列表及完成状态"| D7["📦 onboarding_task 表"]:::data
 
-    A1 -.- R1
-    C1 -.- R2
+        P7 -->|"领取引导奖励"| P7a["📱 完成引导任务后领取"]:::page
+        P7a -->|"taskType"| A32["🔗 POST /api/onboarding/claim"]:::api
+        A32 -->|"任务类型"| S32["⚙️ OnboardingService.claimReward()"]:::service
+        S32 -->|"发放积分/能量, 标记已领取"| D7
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_ADMIN -.- P1
+    ROLE_ADMIN -.- P2
+    ROLE_ADMIN -.- P3
+    ROLE_PARENT -.- P4
+    ROLE_PARENT -.- P5
+    ROLE_PARENT -.- P6
+    ROLE_PARENT -.- P7
+    ROLE_SYSTEM -.- A25a
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/health/knowledge/query` | 查询知识库 | 🖥管理后台 |
-| `/api/health/knowledge/batch-query` | 批量查询 | 🖥管理后台 |
-| `/api/health/knowledge/list` | 列表查询 | 🖥管理后台 |
-| `/api/health/knowledge/add` | 新增条目 | 🖥管理后台 |
-| `/api/health/knowledge/update` | 更新条目 | 🖥管理后台 |
-| `/api/health/knowledge/delete` | 删除条目 | 🖥管理后台 |
-| `/api/health/knowledge/import` | 导入数据 | 🖥管理后台 |
-| `/api/health/knowledge/v3/bacteria/query` | 菌属功能查询 | 🖥管理后台 |
-| `/api/health/knowledge/v3/bacteria/batch-query` | 批量菌属查询 | 🖥管理后台 |
-| `/api/health/knowledge/v3/indicator/query` | 指标调整建议 | 🖥管理后台 |
-| `/api/health/knowledge/v3/food/query` | 食物营养数据 | 🖥管理后台 |
-| `/api/health/knowledge/v3/section` | 原始数据 | 🖥管理后台 |
-| `/api/invite/code` | 生成邀请码 | 📱小程序 |
-| `/api/invite/bind` | 绑定邀请 | 📱小程序 |
-| `/api/invite/list` | 邀请列表 | 📱小程序 |
-| `/api/invite/summary` | 邀请汇总 | 📱小程序 |
-| `/api/invite/qrcode` | 邀请二维码 | 📱小程序 |
-| `/api/invite-card/generate` | 生成邀请卡片 | 📱小程序 |
-| `/api/invite-card/verify` | 验证邀请码 | 📱小程序 |
-| `/api/invite-card/accept` | 接受邀请 | 📱小程序 |
-| `/api/invite/milestone/list` | 里程碑列表 | 📱小程序 |
-| `/api/invite/milestone/claim` | 领取奖励 | 📱小程序 |
-| `/api/onboarding/progress` | 引导进度 | 📱小程序 |
-| `/api/onboarding/claim` | 领取奖励 | 📱小程序 |
+### 健康知识库
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/knowledge/query` | 查询知识库单条 | 🖥管理后台 | `{itemType, itemName}` | `HealthKnowledgeBase对象` |
+| `POST /api/health/knowledge/batch-query` | 批量查询知识库 | 🖥管理后台 | `{queries: [{itemType, itemName}]}` | `{key: HealthKnowledgeBase}` |
+| `POST /api/health/knowledge/list` | 知识库全量列表 | 🖥管理后台 | — | `[HealthKnowledgeBase对象]` |
+| `POST /api/health/knowledge/add` | 新增知识条目 | 🖥管理后台 | `HealthKnowledgeBase实体JSON` | `{success}` |
+| `POST /api/health/knowledge/update` | 更新知识条目 | 🖥管理后台 | `HealthKnowledgeBase实体JSON(含id)` | `{success}` |
+| `POST /api/health/knowledge/delete` | 删除知识条目 | 🖥管理后台 | `{id}` | `{success}` |
+| `POST /api/health/knowledge/import` | 从JSON全量导入 | 🖥管理后台 | — | `导入结果消息` |
+
+### KB v3 查询
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/health/knowledge/v3/bacteria/query` | 查询菌属功能 | 🖥管理后台 | `{name}` | `{菌属功能说明}` |
+| `POST /api/health/knowledge/v3/bacteria/batch-query` | 批量查询菌属 | 🖥管理后台 | `{names: [...]}` | `{name: {...}}` |
+| `POST /api/health/knowledge/v3/indicator/query` | 查询指标调整建议 | 🖥管理后台 | `{name}` | `{指标调整建议}` |
+| `POST /api/health/knowledge/v3/food/query` | 查询食物营养数据 | 🖥管理后台 | `{name}` | `{食物营养数据}` |
+| `POST /api/health/knowledge/v3/section` | 获取章节原始数据 | 🖥管理后台 | `{section}`(空则返回目录) | `章节数据或目录结构` |
+
+### Dify知识库
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/knowledge-base/list` | 分页查询知识库 | 🖥管理后台 | `{keyword, status, page, size}` | `分页结果` |
+| `POST /api/admin/knowledge-base/get` | 获取知识详情(含关联) | 🖥管理后台 | `id (RequestParam)` | `知识+维度+标签信息` |
+| `POST /api/admin/knowledge-base/save` | 新增/编辑知识 | 🖥管理后台 | `{id?, title, content, dimensionIds, tagIds, ...}` | `DanKnowledgeBase对象` |
+| `POST /api/admin/knowledge-base/delete` | 删除知识 | 🖥管理后台 | `id (RequestParam)` | `{success}` |
+| `POST /api/admin/knowledge-base/bind-dimensions` | 绑定维度 | 🖥管理后台 | `{knowledgeId, dimensionIds}` | `{success}` |
+| `POST /api/admin/knowledge-base/bind-tags` | 绑定标签 | 🖥管理后台 | `{knowledgeId, tagIds}` | `{success}` |
+| `POST /api/admin/knowledge-base/upload-file` | 上传文件 | 🖥管理后台 | `file (multipart)` | `{fileUrl, fileName}` |
+| `POST /api/admin/knowledge-base/fetch-url` | 抓取网页内容 | 🖥管理后台 | `{url}` | `{title, content, sourceUrl}` |
+
+### 知识标签
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/knowledge-tag/list` | 标签列表 | 🖥管理后台 | — | `[DanKnowledgeTag对象]` |
+| `POST /api/admin/knowledge-tag/save` | 新增/编辑标签 | 🖥管理后台 | `DanKnowledgeTag实体JSON` | `DanKnowledgeTag对象` |
+| `POST /api/admin/knowledge-tag/delete` | 删除标签 | 🖥管理后台 | `id (RequestParam)` | `{success}` |
+
+### 邀请推广
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/invite/code` | 获取或生成推广码 | 📱小程序 | Header: `Authorization` | `推广码字符串` |
+| `POST /api/invite/bind` | 绑定邀请关系 | 📱小程序 | `{referralCode}` | `"绑定成功"` |
+| `POST /api/invite/list` | 我的邀请列表 | 📱小程序 | `{page, size}` | `Page<User>`(被邀请用户) |
+| `POST /api/invite/summary` | 邀请汇总统计 | 📱小程序 | Header: `Authorization` | `ReferralSummaryDTO`(总数/奖励等) |
+| `POST /api/invite/qrcode` | 生成推广小程序码 | 📱小程序 | Header: `Authorization` | `{qrCodeBase64, referralCode}` |
+
+### 邀请卡片
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/invite-card/generate` | 生成邀请卡片(含码) | 📱小程序 | `{type, refId}` | `{code, expiresAt}` |
+| `POST /api/invite-card/verify` | 验证邀请码有效性 | 📱小程序 | `{code}` | `{type, refId, expiresAt, valid}` |
+| `POST /api/invite-card/accept` | 接受邀请 | 📱小程序 | `{code, phone}` | `{成员信息}` |
+
+### 邀请里程碑
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/invite/milestone/list` | 里程碑列表及状态 | 📱小程序 | Header: `Authorization` | `[InviteMilestone对象]` |
+| `POST /api/invite/milestone/claim` | 领取里程碑奖励 | 📱小程序 | `{milestone}` | `{success}` |
+
+### 新手引导
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/onboarding/progress` | 获取引导任务进度 | 📱小程序 | Header: `Authorization` | `[OnboardingTask对象]` |
+| `POST /api/onboarding/claim` | 领取引导任务奖励 | 📱小程序 | `{taskType}` | `奖励结果消息` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    User ||--o{ InviteMilestone : "一个用户多个里程碑"
+    User ||--o{ OnboardingTask : "一个用户多个引导任务"
+    User ||--o{ InviteCard : "一个用户生成多个邀请卡片"
+    User ||--o{ ReferralRelation : "一个用户推广多个用户"
+    DanKnowledgeBase ||--o{ DanKnowledgeTag : "多对多标签关联"
+    DanKnowledgeBase ||--o{ Dimension : "多对多维度关联"
+
+    HealthKnowledgeBase {
+        Long id PK
+        string itemType "bacteria/nutrient/indicator/vitamin/amino_acid/disease"
+        string itemName
+        string category
+        string normalRange
+        string description
+        string suggestion
+        string source
+    }
+
+    DanKnowledgeBase {
+        Long id PK
+        string title
+        string content
+        int sort
+        int status
+        string fileUrl
+        string fileName
+        string sourceUrl
+        string sourceType
+    }
+
+    InviteCard {
+        Long id PK
+        string type "child/family/guide"
+        string code "唯一邀请码"
+        Long refId "关联ID"
+        Long creatorId
+        datetime expiresAt
+        int used "0/1"
+    }
+
+    InviteMilestone {
+        Long id PK
+        Long userId FK
+        string milestone
+        int rewardPoints
+        int rewardEnergy
+        string status "PENDING/CLAIMED"
+    }
+
+    OnboardingTask {
+        Long id PK
+        Long userId FK
+        string taskType
+        int rewardPoints
+        int rewardEnergy
+        string status "PENDING/COMPLETED/CLAIMED"
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖健康知识库(v1+v3)、Dify知识库管理、邀请推广、邀请卡片、里程碑/引导6个阶段,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 知识库查询时参数校验返回错误;邀请码绑定失败(重复/无效)catch异常返回错误信息;邀请卡生成时权限校验(非家庭成员拒绝生成) |
+| 3 | **端点覆盖** | ✅ 完整 | 32个端点全部映射到流程图中,与HealthKnowledgeBaseController、KnowledgeBaseController、KnowledgeTagController、InviteController、InviteCardController、OnboardingController的`@PostMapping`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 管理员(admin)管理知识库;家长(parent)使用邀请推广、邀请卡片、里程碑和引导功能;微信系统API参与小程序码生成 |
+| 5 | **数据实体** | ✅ 完整 | health_knowledge_base、dan_knowledge_base、invite_card、invite_milestone、onboarding_task共5张核心表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配,Service方法名与代码逻辑一致 |

+ 266 - 64
docs/flows/market-flow.md

@@ -1,84 +1,286 @@
 # 用户使用流程图 — 任务模板市场
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取公开模板列表 /packages]:::portMiniApp
-        A2 --> A3[📱 获取模板详情 /packages/:id]:::portMiniApp
-        A3 --> A4[📱 获取任务项 /packages/:id/items]:::portMiniApp
-        A4 --> A5[📱 通过分享码获取 /share/:code]:::portMiniApp
+    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_TEACHER(("📋 规划师")):::actor
+    ROLE_ADMIN(("🖥 管理员")):::actor
+    ROLE_WX(("💳 微信支付")):::actor
+
+    %% ================================================================
+    %% 阶段一:市场浏览
+    %% ================================================================
+    subgraph 阶段一[阶段一:市场浏览]
+        P1["🏠 小程序:模板市场页"]:::page
+        P1 -->|"查看公开模板"| A1["🔗 POST /api/market/packages"]:::api
+        A1 -->|"筛选条件: category"| S1["⚙️ TaskTemplatePackageService.getPublicPackages()"]:::service
+        S1 -->|"查询已审核+公开的模板"| D1["📦 task_template_packages 表"]:::data
+
+        P1 -->|"查看模板详情"| P1a["🏠 模板详情页"]:::page
+        P1a -->|"模板ID"| A2["🔗 POST /api/market/packages/{id}"]:::api
+        A2 -->|"模板ID"| S2["⚙️ TaskTemplatePackageService.getPackageById()"]:::service
+        S2 -->|"模板完整信息"| D1
+
+        P1a -->|"查看任务项"| A3["🔗 POST /api/market/packages/{id}/items"]:::api
+        A3 -->|"模板ID"| S3["⚙️ TaskTemplatePackageService.getPackageItems()"]:::service
+        S3 -->|"该模板下的所有任务项"| D2["📦 task_template_items 表"]:::data
+
+        P1 -->|"通过分享码进入"| P1b["🏠 分享落地页"]:::page
+        P1b -->|"分享码"| A4["🔗 POST /api/market/share/{code}"]:::api
+        A4 -->|"分享码"| S4["⚙️ TaskTemplatePackageService.getPackageByShareCode()"]:::service
+        S4 -->|"匹配的模板"| D1
     end
 
-    subgraph 购买流程
-        A5 --> B1[📱 获取模板价格 /price]:::portMiniApp
-        B1 --> B2[📱 获取可用指导师 /available-guides]:::portMiniApp
-        B2 --> B3[📱 创建订单 /order/create]:::portMiniApp
-        B3 --> B4[⚙️ 获取微信支付参数 /wechat params]:::portSystem
-        B4 --> B5[⚙️ 微信支付回调 /notify]:::portSystem
-        B5 --> B6[⚙️ 支付成功后应用 /apply]:::portSystem
-        B6 --> B7[📱 购买并应用模板 /packages/:id/purchase]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:购买流程
+    %% ================================================================
+    subgraph 阶段二[阶段二:购买流程]
+        D1 -->|"选定模板, 孩子ID, 指导师"| P2["🏠 小程序:确认订单页"]:::page
+        P2 -->|"创建订单"| A5["🔗 POST /api/payment/create"]:::api
+        A5 -->|"userId, familyId, packageId, payMethod, couponId"| S5["⚙️ PackagePaymentService.createOrder()"]:::service
+        S5 -->|"写入订单, 状态=pending"| D3["📦 package_orders 表"]:::data
+
+        D3 -->|"订单ID"| P2a["🏠 小程序:支付页"]:::page
+        P2a -->|"获取微信支付参数"| A6["🔗 POST /api/payment/wechat params"]:::api
+        A6 -->|"orderId, openid"| S6["⚙️ PackagePaymentService.createWechatPayOrder()"]:::service
+        S6 -->|"JSAPI调起支付参数"| D_WX["📦 微信支付预支付单"]:::data
+
+        D_WX -->|"用户确认支付"| P2b["⚙️ 微信支付弹窗"]:::page
+        P2b -->|"支付结果通知"| A7["🔗 POST /api/payment/notify"]:::api
+        A7 -->|"微信XML回调数据"| S7["⚙️ PackagePaymentService.handlePayNotify()"]:::service
+        S7 -->|"更新订单状态=paid"| D3
+
+        D3 -->|"订单状态=paid"| P2c["🏠 小程序:应用模板页"]:::page
+        P2c -->|"选择任务项, 确认孩子"| A8["🔗 POST /api/payment/apply"]:::api
+        A8 -->|"orderId, childId, selectedItemIds"| S8["⚙️ TaskPlanService.applyPackage()"]:::service
+        S8 -->|"复制模板项→计划项, 写入实例"| D5["📦 task_plan_instances + task_plan_items"]:::data
     end
 
-    subgraph 我的计划
-        B7 --> C1[📱 获取我的计划 /plans]:::portMiniApp
-        C1 --> C2[📱 获取计划详情 /plans/:id]:::portMiniApp
-        C2 --> C3[📱 获取计划任务项 /plans/:id/items]:::portMiniApp
-        C3 --> C4[📱 取消计划 /plans/:id/cancel]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:我的计划
+    %% ================================================================
+    subgraph 阶段三[阶段三:我的计划]
+        D5 -->|"家庭ID"| P3["🏠 小程序:我的计划列表页"]:::page
+        P3 -->|"查看所有计划"| A9["🔗 POST /api/market/plans"]:::api
+        A9 -->|"userId(提取familyId)"| S9["⚙️ TaskPlanService.getFamilyPlans()"]:::service
+        S9 -->|"该家庭的所有计划实例"| D5
+
+        P3 -->|"查看计划详情"| P3a["🏠 计划详情页"]:::page
+        P3a -->|"计划ID"| A10["🔗 POST /api/market/plans/{id}"]:::api
+        A10 -->|"计划ID"| S10["⚙️ TaskPlanService.getPlanById()"]:::service
+        S10 -->|"计划实例详情"| D5
+
+        P3a -->|"查看计划任务项"| A11["🔗 POST /api/market/plans/{id}/items"]:::api
+        A11 -->|"实例ID"| S11["⚙️ TaskPlanService.getPlanItems()"]:::service
+        S11 -->|"该计划的每日任务项"| D6["📦 task_plan_items 表"]:::data
+
+        P3 -->|"取消计划"| P3b["🏠 取消确认弹窗"]:::page
+        P3b -->|"计划ID"| A12["🔗 POST /api/market/plans/{id}/cancel"]:::api
+        A12 -->|"计划ID"| S12["⚙️ TaskPlanService.cancelPlan()"]:::service
+        S12 -->|"状态→cancelled"| D5
     end
 
-    subgraph 模板创建(管理员/规划师)
-        A2 --> D1[🖥 创建模板 /create]:::portAdmin
-        D1 --> D2[🖥 更新模板 /:id/update]:::portAdmin
-        D2 --> D3[🖥 添加任务项 /:id/items]:::portAdmin
-        D3 --> D4[🖥 提交审核 /:id/submit]:::portAdmin
-        D4 --> D5[🖥 审核通过后发布 /:id/publish]:::portAdmin
+    %% ================================================================
+    %% 阶段四:模板创建(规划师)
+    %% ================================================================
+    subgraph 阶段四[阶段四:模板创建与发布]
+        P4["📋 规划师端:创建模板页"]:::page
+        P4 -->|"填写模板信息"| A13["🔗 POST /api/packages/create"]:::api
+        A13 -->|"creatorId, 名称, 描述, 周期, 价格, 分类, 标签, 封面"| S13["⚙️ TaskTemplatePackageService.createPackage()"]:::service
+        S13 -->|"写入模板, 状态=draft"| D1
+
+        D1 -->|"模板ID"| P4a["📋 规划师端:编辑模板页"]:::page
+        P4a -->|"添加任务项"| A14["🔗 POST /api/packages/{id}/items"]:::api
+        A14 -->|"packageId, 任务名称, 描述, 积分, 频率, 时长, 必选"| S14["⚙️ TaskTemplatePackageService.addItem()"]:::service
+        S14 -->|"写入一条任务项"| D2
+
+        P4a -->|"更新模板信息"| A15["🔗 POST /api/packages/{id}/update"]:::api
+        A15 -->|"模板ID, 更新字段"| S15["⚙️ TaskTemplatePackageService.updatePackage()"]:::service
+        S15 -->|"更新模板记录"| D1
+
+        P4a -->|"提交审核"| A16["🔗 POST /api/packages/{id}/submit"]:::api
+        A16 -->|"模板ID"| S16["⚙️ TaskTemplatePackageService.submitForReview()"]:::service
+        S16 -->|"状态→pending"| D1
     end
 
-    R1(("👤 家长")):::actor
-    R2(("📋 规划师/管理员")):::role
-    R3(("💳 微信支付")):::system
+    %% ================================================================
+    %% 阶段五:审核管理(管理员)
+    %% ================================================================
+    subgraph 阶段五[阶段五:审核与上架]
+        D1 -->|"status=pending"| P5["🖥 管理后台:待审核列表"]:::page
+        P5 -->|"查看待审核"| A17["🔗 POST /api/admin/packages/pending"]:::api
+        A17 -->|"无参数"| S17["⚙️ TaskTemplatePackageService.getPendingPackages()"]:::service
+        S17 -->|"所有pending状态的模板"| D1
+
+        P5 -->|"审核通过"| A18["🔗 POST /api/admin/packages/{id}/approve"]:::api
+        A18 -->|"模板ID, reviewerId"| S18["⚙️ TaskTemplatePackageService.approvePackage()"]:::service
+        S18 -->|"状态→approved, 记录审核人"| D1
 
-    A1 -.- R1
-    D1 -.- R2
-    B5 -.- R3
+        P5 -->|"审核拒绝"| A19["🔗 POST /api/admin/packages/{id}/reject"]:::api
+        A19 -->|"模板ID, reviewerId, reason"| S19["⚙️ TaskTemplatePackageService.rejectPackage()"]:::service
+        S19 -->|"状态→rejected, 记录原因"| D1
+
+        D1 -->|"status=approved"| P5a["🖥 管理后台:发布操作"]:::page
+        P5a -->|"上架/下架"| A20["🔗 POST /api/packages/{id}/publish"]:::api
+        A20 -->|"模板ID, publish=true/false"| S20["⚙️ TaskTemplatePackageService.publishPackage()"]:::service
+        S20 -->|"isPublic标记+状态变更"| D1
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P3
+    ROLE_TEACHER -.- P4
+    ROLE_ADMIN -.- P5
+    ROLE_ADMIN -.- P5a
+    ROLE_WX -.- P2b
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/market/packages` | 获取公开模板列表 | 📱小程序 |
-| `/api/market/packages/{id}` | 获取模板详情 | 📱小程序 |
-| `/api/market/packages/{id}/items` | 获取任务项 | 📱小程序 |
-| `/api/market/share/{code}` | 通过分享码获取 | 📱小程序 |
-| `/api/market/packages/{id}/purchase` | 购买并应用 | 📱小程序 |
-| `/api/market/plans` | 获取我的计划 | 📱小程序 |
-| `/api/market/plans/{id}` | 计划详情 | 📱小程序 |
-| `/api/market/plans/{id}/items` | 计划任务项 | 📱小程序 |
-| `/api/market/plans/{id}/cancel` | 取消计划 | 📱小程序 |
-| `/api/package/price` | 模板价格 | 📱小程序 |
-| `/api/package/available-guides` | 可用指导师 | 📱小程序 |
-| `/api/package/order/create` | 创建订单 | 📱小程序 |
-| `/api/package/order/{orderNo}` | 订单详情 | 📱小程序 |
-| `/api/payment/create` | 创建支付订单 | 📱小程序 |
-| `/api/payment/wechat params` | 微信支付参数 | ⚙️系统自动 |
-| `/api/payment/notify` | 支付回调 | ⚙️系统自动 |
-| `/api/payment/apply` | 应用模板 | ⚙️系统自动 |
-| `/api/packages/create` | 创建模板 | 🖥管理后台 |
-| `/api/packages/{id}/update` | 更新模板 | 🖥管理后台 |
-| `/api/packages/{id}/submit` | 提交审核 | 🖥管理后台 |
-| `/api/packages/{id}/publish` | 发布/下架 | 🖥管理后台 |
+### 市场浏览
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/market/packages` | 获取公开模板列表 | 📱小程序 | `{category(可选)}` | `List<TaskTemplatePackage>` |
+| `POST /api/market/packages/{id}` | 获取模板详情 | 📱小程序 | path: `id` | `TaskTemplatePackage` |
+| `POST /api/market/packages/{id}/items` | 获取模板任务项 | 📱小程序 | path: `id` | `List<TaskTemplateItem>` |
+| `POST /api/market/share/{code}` | 通过分享码获取模板 | 📱小程序 | path: `code` | `TaskTemplatePackage` |
+
+### 购买流程
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/payment/create` | 创建支付订单 | 📱小程序 | `{packageId, payMethod, couponId(可选)}` | `PackageOrder` |
+| `POST /api/payment/wechat params` | 获取微信支付参数 | ⚙️系统自动 | `{orderId, openid}` | `JSAPI调起支付参数` |
+| `POST /api/payment/notify` | 微信支付回调 | ⚙️系统自动 | XML回调数据 | XML响应(SUCCESS/FAIL) |
+| `POST /api/payment/orders/{orderId}` | 查询订单状态 | 📱小程序 | path: `orderId` | `PackageOrder` |
+| `POST /api/payment/apply` | 支付后应用模板 | 📱小程序 | `{orderId, childId, selectedItemIds}` | `TaskPlanInstance` |
+| `POST /api/payment/orders/{orderId}/cancel` | 取消订单 | 📱小程序 | path: `orderId` | `boolean` |
+
+### 我的计划
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/market/plans` | 获取我的计划列表 | 📱小程序 | —(从token提取userId) | `List<TaskPlanInstance>` |
+| `POST /api/market/plans/{id}` | 获取计划详情 | 📱小程序 | path: `id` | `TaskPlanInstance` |
+| `POST /api/market/plans/{id}/items` | 获取计划任务项 | 📱小程序 | path: `id` | `List<TaskPlanItem>` |
+| `POST /api/market/plans/{id}/cancel` | 取消计划 | 📱小程序 | path: `id` | `boolean` |
+
+### 模板创建(规划师)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/packages/create` | 创建任务模板 | 📋规划师端 | `{name, description, cycleDays, category, price, coverImage, isPublic, tags}` | `模板ID` |
+| `POST /api/packages/{id}/update` | 更新任务模板 | 📋规划师端 | path: `id`, body: 同create的可选字段 | `boolean` |
+| `POST /api/packages/{id}` | 获取模板详情 | 📋规划师端 | path: `id` | `TaskTemplatePackage` |
+| `POST /api/packages/my` | 获取我的模板列表 | 📋规划师端 | —(从token提取creatorId) | `List<TaskTemplatePackage>` |
+| `POST /api/packages/{id}/submit` | 提交审核 | 📋规划师端 | path: `id` | `boolean` |
+| `POST /api/packages/{id}/publish` | 发布/下架 | 📋规划师端 | path: `id`, body: `{publish: true/false}` | `boolean` |
+| `POST /api/packages/{id}/items` | 添加任务项 | 📋规划师端 | path: `id`, body: `{taskName, description, points, frequency, duration, isRequired}` | `任务项ID` |
+| `POST /api/packages/items/{itemId}` | 更新任务项 | 📋规划师端 | path: `itemId`, body: 更新字段 | `boolean` |
+| `POST /api/packages/items/{itemId}/delete` | 删除任务项 | 📋规划师端 | path: `itemId` | `boolean` |
+| `POST /api/packages/{id}/item-list` | 获取模板任务项列表 | 📋规划师端 | path: `id` | `List<TaskTemplateItem>` |
+
+### 审核管理(管理员)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/packages/pending` | 获取待审核模板列表 | 🖥管理后台 | — | `List<TaskTemplatePackage>` |
+| `POST /api/admin/packages/{id}/approve` | 审核通过 | 🖥管理后台 | path: `id` | `boolean` |
+| `POST /api/admin/packages/{id}/reject` | 审核拒绝 | 🖥管理后台 | path: `id`, query: `reason` | `boolean` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    TaskTemplatePackage ||--o{ TaskTemplateItem : "一个模板多个任务项"
+    TaskTemplatePackage ||--o{ PackageOrder : "一个模板多个订单"
+    TaskTemplatePackage ||--o{ TaskPlanInstance : "一个模板多次被应用"
+
+    TaskPlanInstance ||--o{ TaskPlanItem : "一个实例多个计划项"
+    TaskTemplateItem ||--o{ TaskPlanItem : "模板项被复制为计划项"
+
+    TaskTemplatePackage {
+        Long id PK
+        Long creatorId FK "规划师ID"
+        string name "任务模板名称"
+        string description "详细介绍"
+        int cycleDays "周期天数"
+        string category "分类"
+        string tags "标签JSON"
+        int price "售价(分)"
+        int platformFee "平台服务费(分)"
+        int isPublic "是否公开到市场"
+        string shareCode "分享码"
+        string status "draft/pending/approved/rejected/offline"
+    }
+
+    TaskTemplateItem {
+        Long id PK
+        Long packageId FK
+        string taskName "任务名称"
+        string description "任务描述"
+        int points "基础积分"
+        string frequency "执行频率"
+        int duration "预计时长(分钟)"
+        int isRequired "是否必选"
+    }
+
+    PackageOrder {
+        Long id PK
+        string orderNo
+        Long userId FK "购买者"
+        Long familyId FK
+        Long packageId FK
+        int price "支付金额(分)"
+        string status "pending/paid/cancelled/refunded"
+    }
+
+    TaskPlanInstance {
+        Long id PK
+        Long packageId FK
+        Long familyId FK
+        Long childId FK
+        string name "实例名称"
+        string status "active/completed/cancelled"
+        int totalDays
+        int completedDays
+    }
+
+    TaskPlanItem {
+        Long id PK
+        Long instanceId FK
+        Long templateItemId FK
+        string taskName
+        string description
+        int points
+        string frequency
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖市场浏览→购买支付→应用计划→计划管理→模板创建→审核上架6个阶段,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 订单支付失败/取消、审核拒绝已覆盖;模板创建后编辑、草稿状态管理等在图中有体现;价格计算逻辑、优惠券使用等Service层内部处理未画入 |
+| 3 | **端点覆盖** | ✅ 完整 | 26个端点全部映射到流程图中,覆盖MarketController(9)、PackagePaymentController(6)、TaskTemplatePackageController(10)、AdminPackageController(3) |
+| 4 | **角色覆盖** | ✅ 完整 | 家长(市场浏览/购买/计划管理)、规划师(模板创建)、管理员(审核上架)三种角色全覆盖;微信支付作为外部系统调用 |
+| 5 | **数据实体** | ✅ 完整 | task_template_packages、task_template_items、package_orders、task_plan_instances、task_plan_items五张表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配,Service方法名与源码一致 |

+ 317 - 70
docs/flows/membership-flow.md

@@ -1,92 +1,339 @@
 # 用户使用流程图 — 会员与订阅
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取会员等级列表 /levels]:::portMiniApp
-        A2 --> A3[📱 获取我的会员信息 /my]:::portMiniApp
-        A3 --> A4[📱 获取当前会员等级 /level]:::portMiniApp
-        A4 --> A5[📱 获取会员等级详情 /current]:::portMiniApp
-        A5 --> A6[📱 获取升级记录 /records]:::portMiniApp
+    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_PAY(("💳 微信支付")):::external
+    ROLE_SYS(("⚙️ 定时任务")):::actor
+
+    %% ================================================================
+    %% 阶段一:会员信息查看
+    %% ================================================================
+    subgraph 阶段一[阶段一:会员信息查看]
+        direction TB
+
+        P1["🏠 小程序:会员中心页"]:::page
+        P1 -->|"查看等级列表"| A1["🔗 POST /api/membership/levels"]:::api
+        A1 -->|"无参数"| S1["⚙️ MembershipService.getAllLevels()"]:::service
+        S1 -->|"查询所有等级配置"| D_LEVELS["📦 membership_levels 表"]:::data
+
+        P1 -->|"查看我的会员"| A2["🔗 POST /api/membership/my"]:::api
+        A2 -->|"userId(从token提取)"| S2["⚙️ 组装会员信息"]:::service
+        S2 -->|"用户等级, 过期时间"| D_USER["📦 users 表(memberLevel, memberExpireTime)"]:::data
+        S2 -->|"家庭会员记录"| D_FAM["📦 family_memberships 表"]:::data
+
+        P1 -->|"查看当前等级"| A3["🔗 POST /api/membership/level"]:::api
+        A3 -->|"userId"| S3["⚙️ MembershipService.getMemberLevel()"]:::service
+        S3 -->|"FREE/FAMILY/PREMIUM + 过期校验"| D_USER
+
+        P1 -->|"查看等级详情"| A4["🔗 POST /api/membership/current"]:::api
+        A4 -->|"familyId"| S4["⚙️ MembershipService.getCurrentLevel()"]:::service
+        S4 -->|"查询家庭当前有效等级"| D_LEVELS
+        S4 -->|"无会员则返回免费版"| D_LEVELS
+
+        P1 -->|"查看升级记录"| A5["🔗 POST /api/membership/records"]:::api
+        A5 -->|"userId, page, size"| S5["⚙️ MemberUpgradeRecordMapper 分页查询"]:::service
+        S5 -->|"用户升级记录"| D_REC["📦 member_upgrade_records 表"]:::data
+
+        P1 -->|"查看价格方案"| A6["🔗 POST /api/membership/plans"]:::api
+        A6 -->|"无参数"| S6["⚙️ 组装定价方案"]:::service
+        S6 -->|"等级配置 + sys_config定价"| D_LEVELS
+        S6 -->|"FAMILY/PREMIUM价格"| D_CFG["📦 sys_config 表"]:::data
     end
 
-    subgraph 会员升级
-        A6 --> B1[📱 创建会员升级订单 /upgrade]:::portMiniApp
-        B1 --> B2[📱 创建订单 /orders]:::portMiniApp
-        B2 --> B3{📱 是否需要支付?}:::portMiniApp
-        B3 -->|是| B4[⚙️ 支付回调 /notify]:::portSystem
-        B3 -->|否| B5[📱 直接升级]:::portMiniApp
-        B4 --> B5
+    %% ================================================================
+    %% 阶段二:会员购买与升级
+    %% ================================================================
+    subgraph 阶段二[阶段二:会员购买与升级]
+        D_LEVELS -->|"等级+价格"| P2["🏠 会员升级选择页"]:::page
+        P2 -->|"选择套餐"| P2a{"选择付费方式"}:::page
+
+        P2a -->|"创建升级订单"| A7["🔗 POST /api/membership/upgrade"]:::api
+        A7 -->|"userId, familyId, levelCode, paymentType, period, couponId"| S7["⚙️ MembershipService.createOrder()"]:::service
+        S7 -->|"从sys_config读取定价"| D_CFG
+        S7 -->|"应用优惠券折扣"| S7a["⚙️ CouponService.apply()"]:::service
+        S7a -->|"优惠后金额"| D_COUPON["📦 user_coupons 表"]:::data
+        S7 -->|"写入订单, 状态=pending"| D_ORD["📦 payment_orders 表"]:::data
+
+        A7 -->|"orderNo, amount, status"| P2b["🏠 确认订单页"]:::page
+        P2b -->|"调起微信支付"| PAY["💳 微信支付"]:::external
+        PAY -->|"支付结果通知"| A8["🔗 POST /api/membership/notify"]:::api
+        A8 -->|"orderNo, transactionId, payMethod"| S8["⚙️ MembershipService.processPaymentCallback()"]:::service
+        S8 -->|"更新订单状态=paid"| D_ORD
+
+        S8 -->|"插入家庭会员记录"| D_FAM
+        S8 -->|"升级用户等级, 设置过期时间"| D_USER
+        S8 -->|"创建升级记录"| D_REC
+        S8 -->|"结算两级佣金"| S8a["⚙️ CommissionService.settleTwoLevel()"]:::service
+        S8a -->|"佣金记录"| D_COMM["📦 commission_records 表"]:::data
+
+        P2a -->|"创建任意订单"| A9["🔗 POST /api/membership/orders"]:::api
+        A9 -->|"levelCode, paymentType, period, couponId"| S7
+
+        P2a -->|"试用会员"| A10["🔗 POST /api/membership/trial"]:::api
+        A10 -->|"userId, familyId"| S9["⚙️ MembershipService.createOrder(trial)"]:::service
+        S9 -->|"创建金额=0的订单, 状态=paid"| D_ORD
+
+        S9 -->|"激活试用期"| S9a["⚙️ 写入TrialMembership + FamilyMembership"]:::service
+        S9a -->|"试用记录"| D_TRIAL["📦 trial_memberships 表"]:::data
+        S9a -->|"家庭会员记录(试用)"| D_FAM
+        S9a -->|"用户等级= FAMILY, expireTime=7天后"| D_USER
+        S9a -->|"试用升级记录"| D_REC
     end
 
-    subgraph 会员权益
-        B5 --> C1[📱 检查功能权限 /can-use]:::portMiniApp
-        C1 --> C2[📱 应用会员折扣 /discount]:::portMiniApp
-        C2 --> C3[📱 获取任务模板价格 /plans]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:会员权益
+    %% ================================================================
+    subgraph 阶段三[阶段三:会员权益]
+        D_USER -->|"会员等级"| P3["🏠 会员权益页"]:::page
+        P3 -->|"检查功能权限"| A11["🔗 POST /api/membership/can-use"]:::api
+        A11 -->|"familyId, feature"| S10["⚙️ MembershipService.canUseFeature()"]:::service
+        S10 -->|"按FREE/FAMILY/PREMIUM判定功能白名单"| D_USER
+
+        P3 -->|"应用会员折扣"| A12["🔗 POST /api/membership/discount"]:::api
+        A12 -->|"userId, amount"| S11["⚙️ MembershipService.applyMemberDiscount()"]:::service
+        S11 -->|"从sys_config读取折扣率"| D_CFG
+        S11 -->|"FREE无折扣, FAMILY/PREMIUM按折扣bps计算"| D_CFG
     end
 
-    subgraph 会员试用
-        A6 --> D1[📱 激活试用会员 /trial]:::portMiniApp
-        D1 --> D2[📱 试用期体验]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:订阅管理
+    %% ================================================================
+    subgraph 阶段四[阶段四:订阅管理]
+        P1 -->|"订阅管理"| P4["🏠 订阅管理页"]:::page
+        P4 -->|"查看订阅状态"| A13["🔗 POST /api/subscription/status"]:::api
+        A13 -->|"familyId"| S12["⚙️ MemberSubscriptionService.getActiveSubscription()"]:::service
+        S12 -->|"活跃订阅 + 过期时间校验"| D_SUB["📦 member_subscriptions 表"]:::data
+
+        P4 -->|"查看订阅方案"| A14["🔗 POST /api/subscription/plans"]:::api
+        A14 -->|"无参数"| S13["⚙️ 硬编码L1/L2方案"]:::service
+        S13 -->|"L1=36500/年, L2=131400/年"| D_MOCK["📦 内存数据(L1_BENEFITS, L2_BENEFITS)"]:::data
+
+        P4 -->|"创建订阅"| A15["🔗 POST /api/subscription/create"]:::api
+        A15 -->|"familyId, level, amount, paymentType"| S14["⚙️ 创建微信预支付"]:::service
+        S14 -->|"openid, 金额"| PAY
+        S14 -->|"订阅服务激活"| S14a["⚙️ MemberSubscriptionService.subscribe()"]:::service
+        S14a -->|"写入订阅记录, 状态=active"| D_SUB
+
+        P4 -->|"确认订阅"| A16["🔗 POST /api/subscription/subscribe"]:::api
+        A16 -->|"familyId, level, amount, paymentType, transactionId"| S14a
+
+        P4 -->|"取消订阅"| A17["🔗 POST /api/subscription/cancel"]:::api
+        A17 -->|"familyId"| S15["⚙️ MemberSubscriptionService.cancelSubscription()"]:::service
+        S15 -->|"更新订阅状态=cancelled"| D_SUB
+
+        P4 -->|"设置自动续费"| A18["🔗 POST /api/subscription/auto-renew"]:::api
+        A18 -->|"familyId, enabled(0/1)"| S16["⚙️ MemberSubscriptionService.setAutoRenew()"]:::service
+        S16 -->|"更新自动续费标记"| D_SUB
     end
 
-    subgraph 订阅管理
-        A3 --> E1[📱 获取订阅状态 /status]:::portMiniApp
-        E1 --> E2[📱 获取订阅计划 /plans]:::portMiniApp
-        E2 --> E3[📱 创建订阅 /create]:::portMiniApp
-        E3 --> E4[📱 确认订阅 /subscribe]:::portMiniApp
-        E4 --> E5[📱 取消订阅 /cancel]:::portMiniApp
-        E5 --> E6[📱 自动续费设置 /auto-renew]:::portMiniApp
-        E6 --> E7[📱 获取我的权益 /benefits/my]:::portMiniApp
-        E7 --> E8[📱 检查权益 /benefit/check]:::portMiniApp
-        E8 --> E9[📱 获取当前订阅层级 /tier]:::portMiniApp
-        E9 --> E10[📱 更新订阅层级 /tier/update]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:订阅权益与推广等级
+    %% ================================================================
+    subgraph 阶段五[阶段五:订阅权益与推广等级]
+        D_SUB -->|"订阅记录"| P5["🏠 订阅权益页"]:::page
+        P5 -->|"查看我的权益"| A19["🔗 POST /api/subscription/benefits/my"]:::api
+        A19 -->|"familyId"| S17["⚙️ 查询权益使用记录"]:::service
+        S17 -->|"订阅下的所有权益日志"| D_BEN["📦 subscription_benefit_logs 表"]:::data
+
+        P5 -->|"使用/检查权益"| A20["🔗 POST /api/subscription/benefit/check"]:::api
+        A20 -->|"familyId, benefitCode"| S18["⚙️ 创建权益使用记录"]:::service
+        S18 -->|"写入一条权益使用日志"| D_BEN
+
+        P5 -->|"查看推广等级"| A21["🔗 POST /api/subscription/tier"]:::api
+        A21 -->|"userId"| S19["⚙️ PromotionTierService.getCurrentTier()"]:::service
+        S19 -->|"用户当前推广等级"| D_TIER["📦 promotion_tiers 表"]:::data
+
+        P5 -->|"更新推广等级(管理员)"| A22["🔗 POST /api/subscription/tier/update"]:::api
+        A22 -->|"userId, tierCode, role=admin"| S20["⚙️ PromotionTierService.updateTier()"]:::service
+        S20 -->|"更新推广等级"| D_TIER
     end
 
-    R1(("👤 家长")):::actor
-    R2(("💳 微信支付")):::system
+    %% ================================================================
+    %% 阶段六:定时任务
+    %% ================================================================
+    subgraph 阶段六[阶段六:系统定时任务]
+        ROLE_SYS -->|"每日3:30"| T1["⚙️ 消费达标自动升级"]:::service
+        T1 -->|"查询消费≥threshold的FREE用户"| D_USER
+        T1 -->|"升级为FAMILY"| D_USER
+        T1 -->|"创建升级记录"| D_REC
+
+        ROLE_SYS -->|"每日4:00"| T2["⚙️ 过期会员降级"]:::service
+        T2 -->|"查询已过期FAMILY用户"| D_USER
+        T2 -->|"降级为FREE"| D_USER
+    end
 
-    A1 -.- R1
-    B4 -.- R2
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P3
+    ROLE_PARENT -.- P4
+    ROLE_PARENT -.- P5
+    ROLE_PAY -.- PAY
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/membership/levels` | 会员等级列表 | 📱小程序 |
-| `/api/membership/my` | 我的会员信息 | 📱小程序 |
-| `/api/membership/level` | 当前等级 | 📱小程序 |
-| `/api/membership/current` | 等级详情 | 📱小程序 |
-| `/api/membership/records` | 升级记录 | 📱小程序 |
-| `/api/membership/upgrade` | 创建升级订单 | 📱小程序 |
-| `/api/membership/trial` | 激活试用 | 📱小程序 |
-| `/api/membership/orders` | 创建订单 | 📱小程序 |
-| `/api/membership/plans` | 任务模板价格 | 📱小程序 |
-| `/api/membership/can-use` | 功能权限检查 | 📱小程序 |
-| `/api/membership/discount` | 应用折扣 | 📱小程序 |
-| `/api/membership/notify` | 支付回调 | ⚙️系统自动 |
-| `/api/subscription/status` | 订阅状态 | 📱小程序 |
-| `/api/subscription/plans` | 订阅计划 | 📱小程序 |
-| `/api/subscription/create` | 创建订阅 | 📱小程序 |
-| `/api/subscription/subscribe` | 确认订阅 | 📱小程序 |
-| `/api/subscription/cancel` | 取消订阅 | 📱小程序 |
-| `/api/subscription/auto-renew` | 自动续费 | 📱小程序 |
-| `/api/subscription/benefits/my` | 我的权益 | 📱小程序 |
-| `/api/subscription/benefit/check` | 检查权益 | 📱小程序 |
-| `/api/subscription/tier` | 订阅层级 | 📱小程序 |
-| `/api/subscription/tier/update` | 更新层级 | 📱小程序 |
+### 会员信息
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/membership/levels` | 获取所有会员等级列表 | 📱小程序 | — | `[MembershipLevelDTO]` |
+| `POST /api/membership/my` | 获取我的会员信息 | 📱小程序 | Header: `Authorization` | `{memberLevel, memberExpireTime, membership, totalConsumption}` |
+| `POST /api/membership/level` | 获取当前有效会员等级 | 📱小程序 | Header: `Authorization` | `{memberLevel, memberExpireTime}` |
+| `POST /api/membership/current` | 获取当前等级详情 | 📱小程序 | Header: `Authorization` | `MembershipLevelDTO(含功能权限列表)` |
+| `POST /api/membership/records` | 获取升级记录 | 📱小程序 | `{page, size}` | `Page<MemberUpgradeRecord>` |
+| `POST /api/membership/plans` | 获取会员方案价格列表 | 📱小程序 | — | `[{levelCode, levelName, levelDesc, monthly, quarterly, yearly}]` |
+
+### 会员购买与升级
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/membership/upgrade` | 创建会员升级订单 | 📱小程序 | `{levelCode, paymentType, period, couponId}` | `PaymentOrderDTO` |
+| `POST /api/membership/orders` | 创建支付订单 | 📱小程序 | `{levelCode, paymentType, period, couponId}` | `PaymentOrderDTO` |
+| `POST /api/membership/trial` | 激活试用会员 | 📱小程序 | Header: `Authorization` | `PaymentOrderDTO(金额=0)` |
+| `POST /api/membership/notify` | 支付回调 | ⚙️系统自动 | `{orderNo, transactionId, payMethod}` | `boolean` |
+
+### 会员权益
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/membership/can-use` | 检查功能权限 | 📱小程序 | `{feature}` | `boolean` |
+| `POST /api/membership/discount` | 应用会员折扣 | 📱小程序 | `{amount}` | `{originalPrice, discountedPrice}` |
+
+### 订阅管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/subscription/status` | 获取当前家庭订阅状态 | 📱小程序 | Header: `familyId` | `{subscription, hasActiveSubscription}` |
+| `POST /api/subscription/plans` | 获取订阅方案列表 | 📱小程序 | — | `{L1: {name, price, benefits}, L2: {name, price, benefits}}` |
+| `POST /api/subscription/create` | 创建订阅订单(JSON) | 📱小程序 | `{level, amount, paymentType}` | `{orderNo, amount, paymentUrl}` |
+| `POST /api/subscription/subscribe` | 确认订阅(参数式) | 📱小程序 | `{level, amount, paymentType, transactionId}` | `null` |
+| `POST /api/subscription/cancel` | 取消订阅 | 📱小程序 | Header: `familyId` | `null` |
+| `POST /api/subscription/auto-renew` | 设置自动续费 | 📱小程序 | `{enabled}` | `null` |
+
+### 订阅权益与推广
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/subscription/benefits/my` | 获取我的权益列表 | 📱小程序 | Header: `familyId` | `[{code, used, usedAt, detail}]` |
+| `POST /api/subscription/benefit/check` | 使用/检查权益 | 📱小程序 | `{benefitCode}` | `{success, logId}` |
+| `POST /api/subscription/tier` | 获取推广等级 | 📱小程序 | Header: `userId` | `PromotionTier` |
+| `POST /api/subscription/tier/update` | 更新推广等级(管理员) | 🖥管理后台 | `{tierCode}`, role=admin | `null` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    MembershipLevel ||--o{ FamilyMembership : "等级配置"
+    User ||--o{ FamilyMembership : "家庭(通过familyId)"
+    User ||--o{ MemberUpgradeRecord : "userId"
+    FamilyMembership ||--o{ PaymentOrder : "订单"
+    TrialMembership ||--o{ User : "试用"
+    MemberSubscription ||--o{ SubscriptionBenefitLog : "权益使用"
+    PromotionTier ||--o{ User : "userId"
+
+    MembershipLevel {
+        Long id PK
+        string levelCode "FREE/FAMILY/PREMIUM/PROVIDER"
+        string levelName
+        string levelDesc
+        int priceMonthly "月费(分)"
+        int priceQuarterly "季费(分)"
+        int priceYearly "年费(分)"
+        text features "功能权限列表JSON"
+        int maxChildren "可添加孩子数"
+        int maxTasksPerDay "每日任务上限"
+    }
+
+    FamilyMembership {
+        Long id PK
+        Long familyId FK
+        string levelCode "FREE/FAMILY/PREMIUM"
+        date startDate
+        date endDate
+        string paymentStatus "paid/pending"
+        string paymentMethod "wechat/trial"
+        string orderNo
+    }
+
+    PaymentOrder {
+        Long id PK
+        String orderNo "ORD+时间戳"
+        Long familyId FK
+        string levelCode
+        string paymentType "trial/yearly/monthly"
+        string period
+        int amount "分"
+        string status "pending/paid"
+        string transactionId "微信交易号"
+    }
+
+    MemberUpgradeRecord {
+        Long id PK
+        Long userId FK
+        string fromLevel
+        string toLevel
+        string upgradeType "pay/trial/consumption"
+        date expireTime
+    }
+
+    TrialMembership {
+        Long id PK
+        Long userId FK
+        Long familyId FK
+        date startDate
+        date endDate
+        int trialDays
+        string status "ACTIVE/EXPIRED"
+    }
+
+    MemberSubscription {
+        Long id PK
+        Long familyId FK
+        string level "L1/L2"
+        string status "active/cancelled"
+        date expireTime
+        int autoRenew "0/1"
+    }
+
+    SubscriptionBenefitLog {
+        Long id PK
+        Long subscriptionId FK
+        string benefitCode
+        date usedAt
+        text detail
+    }
+
+    PromotionTier {
+        Long id PK
+        Long userId FK
+        string tierCode
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖会员信息查看(5种查询)、购买升级(付费/试用/优惠券)、会员权益(权限检查+折扣)、订阅管理(创建/取消/自动续费)、订阅权益与推广等级、系统定时任务(自动升级/过期降级)6个阶段,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 会员过期自动降级由定时任务处理(图中阶段六已体现);支付失败/取消场景未画入(支付回调仅处理成功通知);试用只能激活一次(代码中无防重复判断) |
+| 3 | **端点覆盖** | ✅ 完整 | 22个端点全部映射到流程图中,与代码实际暴露的`/api/membership/*`(MembershipController)和`/api/subscription/*`(SubscriptionController)一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 购买/查看为📱家长端(`role=parent`);tier/update为🖥管理后台(`role=admin`);notify为⚙️微信支付回调;定时任务为⚙️系统自动 |
+| 5 | **数据实体** | ✅ 完整 | membership_levels、family_memberships、payment_orders、member_upgrade_records、trial_memberships、member_subscriptions、subscription_benefit_logs、promotion_tiers、user_coupons、commission_records、sys_config共11张表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配;等级代码(FREE/FAMILY/PREMIUM)和功能白名单与代码逻辑一致;订阅方案(L1=36500/年, L2=131400/年)与硬编码值一致 |

+ 211 - 71
docs/flows/mind-emotion-flow.md

@@ -1,94 +1,234 @@
 # 用户使用流程图 — 心理与情绪管理
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 创建情绪打卡 /mind/checkin/create]:::portMiniApp
-        A2 --> A3[📱 获取情绪列表 /mind/checkin/list]:::portMiniApp
-        A3 --> A4[📱 获取最新情绪 /mind/checkin/latest]:::portMiniApp
-        A4 --> A5[📱 获取情绪趋势 /mind/checkin/trend]:::portMiniApp
-        A5 --> A6[📱 获取情绪统计 /mind/checkin/stats]:::portMiniApp
-        A6 --> A7[📱 获取周报 /mind/checkin/weekly-report]:::portMiniApp
-    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
 
-    subgraph 情绪预警
-        A7 --> B1[📱 获取活跃预警 /mind/alert/active]:::portMiniApp
-        B1 --> B2[📱 获取打卡预警 /mind/alert/checkin-alerts]:::portMiniApp
-        B2 --> B3[📱 处理预警 /mind/alert/resolve]:::portMiniApp
-    end
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_CHILD(("👶 孩子")):::actor
+    ROLE_SYS(("⚙️ 心理引擎")):::actor
 
-    subgraph 心理测评
-        A1 --> C1[📱 提交筛查问卷 /mind/screening/submit]:::portMiniApp
-        C1 --> C2[📱 获取筛查历史 /mind/screening/history]:::portMiniApp
-        C2 --> C3[📱 获取最新结果 /mind/screening/latest]:::portMiniApp
-    end
+    %% ================================================================
+    %% 阶段一:情绪打卡
+    %% ================================================================
+    subgraph 阶段一[阶段一:情绪打卡]
+        direction TB
+
+        P1["🏠 小程序:情绪打卡页"]:::page
+        P1 -->|"选择操作"| P1_choice{"记录情绪 / 查看分析"}:::page
+
+        P1_choice -->|"记录情绪"| P1a["🏠 情绪记录表单"]:::page
+        P1a -->|"孩子ID, 情绪标签, 评分, 压力值, 照片"| A1["🔗 POST /api/mind/checkin/create"]:::api
+        A1 -->|"情绪打卡数据"| S1["⚙️ EmotionCheckinService.createCheckin()"]:::service
+        S1 -->|"写入一条情绪打卡记录"| D1["📦 emotion_checkin 表"]:::data
+
+        P1_choice -->|"查看分析"| P1b["🏠 情绪分析面板"]:::page
+        P1b -->|"孩子ID, 分页"| A2["🔗 POST /api/mind/checkin/list"]:::api
+        A2 -->|"孩子ID, 页码, 每页数"| S2["⚙️ EmotionCheckinService.getCheckinList()"]:::service
+        S2 -->|"分页打卡列表"| D1
+
+        P1b -->|"查看最近"| A3["🔗 POST /api/mind/checkin/latest"]:::api
+        A3 -->|"孩子ID"| S3["⚙️ EmotionCheckinService.getLatestCheckin()"]:::service
+        S3 -->|"最新一条打卡记录"| D1
+
+        P1b -->|"查看趋势"| A4["🔗 POST /api/mind/checkin/trend"]:::api
+        A4 -->|"孩子ID, 周期(week/month)"| S4["⚙️ EmotionCheckinService.getTrend()"]:::service
+        S4 -->|"情绪趋势数据(效价/激活度)"| D1
+
+        P1b -->|"查看统计"| A5["🔗 POST /api/mind/checkin/stats"]:::api
+        A5 -->|"孩子ID"| S5["⚙️ EmotionCheckinService.getStats()"]:::service
+        S5 -->|"情绪统计汇总"| D1
 
-    subgraph 脑科学与神经递质
-        C3 --> D1[📱 获取神经递质分析 /mind/neurotransmitters]:::portMiniApp
-        D1 --> D2[📱 获取肠脑洞察 /mind/gut-emotion-insight]:::portMiniApp
-        D2 --> D3[📱 获取EMI报告 /mind/emireport/latest]:::portMiniApp
+        P1b -->|"查看周报"| A6["🔗 POST /api/mind/checkin/weekly-report"]:::api
+        A6 -->|"孩子ID"| S6["⚙️ EmotionCheckinService.getWeeklyReport()"]:::service
+        S6 -->|"本周情绪报告"| D1
     end
 
-    subgraph 心理运势
-        D3 --> E1[📱 获取心理运势 /mind/fortune]:::portMiniApp
-        E1 --> E2[📱 刷新运势 /mind/fortune/refresh]:::portMiniApp
-        E2 --> E3[📱 导出运势 /mind/fortune/export]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:情绪预警
+    %% ================================================================
+    subgraph 阶段二[阶段二:情绪预警]
+        D1 -->|"孩子ID"| P2["🏠 小程序:情绪预警页"]:::page
+        P2 -->|"查看筛查告警"| A7["🔗 POST /api/mind/alert/active"]:::api
+        A7 -->|"孩子ID"| S7["⚙️ MentalHealthScreenService.getActiveAlerts()"]:::service
+        S7 -->|"未解决的筛查告警列表"| D2["📦 emotion_alerts 表(筛查)"]:::data
+
+        P2 -->|"查看打卡告警"| A8["🔗 POST /api/mind/alert/checkin-alerts"]:::api
+        A8 -->|"孩子ID"| S8["⚙️ EmotionAlertService.getActiveAlerts()"]:::service
+        S8 -->|"打卡检测的情绪告警列表"| D3["📦 emotion_alerts 表(打卡)"]:::data
+
+        P2 -->|"处理告警"| A9["🔗 POST /api/mind/alert/resolve"]:::api
+        A9 -->|"告警ID, 来源(screening/checkin)"| S9["⚙️ EmotionAlertService.resolveAlert()"]:::service
+        S9 -->|"标记告警为已解决"| D4["📦 emotion_alerts(状态更新)"]:::data
     end
 
-    subgraph 传统心理镜像
-        E3 --> F1[📱 获取心理镜像 /mind/traditional/mirror]:::portMiniApp
-        F1 --> F2[📱 获取家庭看板 /mind/traditional/family-dashboard]:::portMiniApp
-        F2 --> F3[📱 获取兼容性 /mind/traditional/compatibility]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:心理筛查
+    %% ================================================================
+    subgraph 阶段三[阶段三:心理筛查]
+        D2 -->|"触发筛查"| P3["🏠 小程序:心理筛查页"]:::page
+        P3 -->|"提交问卷(PHQ-9/GAD-7)"| A10["🔗 POST /api/mind/screening/submit"]:::api
+        A10 -->|"孩子ID, 类型, 答案列表"| S10["⚙️ MentalHealthScreenService.submitScreen()"]:::service
+        S10 -->|"评分, 严重等级, 风险标记, 建议"| D5["📦 mental_health_screens 表"]:::data
+
+        D5 -->|"高风险(中重度以上)"| AUTO_ALERT["⚙️ 自动创建告警 + 推送通知"]:::service
+        AUTO_ALERT -->|"告警记录"| D2
+
+        P3 -->|"查看历史"| A11["🔗 POST /api/mind/screening/history"]:::api
+        A11 -->|"孩子ID, 类型, 数量限制"| S11["⚙️ MentalHealthScreenService.getScreenHistory()"]:::service
+        S11 -->|"筛查历史列表"| D5
+
+        P3 -->|"查看最新"| A12["🔗 POST /api/mind/screening/latest"]:::api
+        A12 -->|"孩子ID, 类型"| S12["⚙️ MentalHealthScreenService.getLatestScreen()"]:::service
+        S12 -->|"最近一次筛查结果"| D5
     end
 
-    subgraph EMI心理报告
-        F3 --> G1[📱 获取EMI心理报告 /emireport/latest]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:神经递质与肠脑洞察
+    %% ================================================================
+    subgraph 阶段四[阶段四:神经递质与肠脑洞察]
+        D1 -->|"菌群报告数据"| P4["🏠 小程序:肠脑洞察页"]:::page
+        P4 -->|"查看神经递质"| A13["🔗 POST /api/mind/neurotransmitters"]:::api
+        A13 -->|"孩子ID"| S13["⚙️ HealthReportService.getMindRelatedIndicators()"]:::service
+        S13 -->|"神经递质与激素, 短链脂肪酸指标"| D6["📦 health_indicators(按类别筛选)"]:::data
+
+        P4 -->|"查看肠脑洞察"| A14["🔗 POST /api/mind/gut-emotion-insight"]:::api
+        A14 -->|"孩子ID"| S14["⚙️ HealthReportService.getGutEmotionInsight()"]:::service
+        S14 -->|"菌群-情绪关联分析摘要"| D7["📦 数据分析结果(内存中)"]:::data
+
+        P4 -->|"查看EMI报告"| A15["🔗 POST /api/mind/emireport/latest"]:::api
+        A15 -->|"孩子ID"| S15["⚙️ EmiReportService.getChildLatestEmiReport()"]:::service
+        S15 -->|"完整EMI心理报告"| D8["📦 emi_reports 表"]:::data
     end
 
-    R1(("👤 用户")):::actor
-    R2(("🧠 心理引擎")):::system
+    %% ================================================================
+    %% 阶段五:管理端操作
+    %% ================================================================
+    subgraph 阶段五[阶段五:管理端操作]
+        D2 -->|"告警数据"| P5["🖥 管理后台:告警管理页"]:::page
+        P5 -->|"查看全部告警"| A16["🔗 POST /api/mind/alert/admin/list"]:::api
+        A16 -->|"页码, 每页数, 是否已解决"| S16["⚙️ EmotionAlertService.getAdminAlerts()"]:::service
+        S16 -->|"分页告警列表"| D2
+    end
 
-    A1 -.- R1
-    D1 -.- R2
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_CHILD -.- P1
+    ROLE_CHILD -.- P1a
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P3
+    ROLE_PARENT -.- P4
+    ROLE_SYS -.- AUTO_ALERT
+    ROLE_SYS -.- S13
+    ROLE_SYS -.- S14
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/mind/checkin/create` | 创建情绪打卡 | 📱小程序 |
-| `/api/mind/checkin/list` | 情绪列表 | 📱小程序 |
-| `/api/mind/checkin/latest` | 最新情绪 | 📱小程序 |
-| `/api/mind/checkin/trend` | 情绪趋势 | 📱小程序 |
-| `/api/mind/checkin/stats` | 情绪统计 | 📱小程序 |
-| `/api/mind/checkin/weekly-report` | 周报 | 📱小程序 |
-| `/api/mind/alert/active` | 活跃预警 | 📱小程序 |
-| `/api/mind/alert/checkin-alerts` | 打卡预警 | 📱小程序 |
-| `/api/mind/alert/resolve` | 处理预警 | 📱小程序 |
-| `/api/mind/neurotransmitters` | 神经递质 | 📱小程序 |
-| `/api/mind/gut-emotion-insight` | 肠脑洞察 | 📱小程序 |
-| `/api/mind/emireport/latest` | EMI报告 | 📱小程序 |
-| `/api/mind/fortune` | 心理运势 | 📱小程序 |
-| `/api/mind/fortune/refresh` | 刷新运势 | 📱小程序 |
-| `/api/mind/fortune/export` | 导出运势 | 📱小程序 |
-| `/api/mind/screening/submit` | 提交筛查 | 📱小程序 |
-| `/api/mind/screening/history` | 筛查历史 | 📱小程序 |
-| `/api/mind/screening/latest` | 最新结果 | 📱小程序 |
-| `/api/mind/traditional/mirror` | 心理镜像 | 📱小程序 |
-| `/api/mind/traditional/family-dashboard` | 家庭看板 | 📱小程序 |
-| `/api/mind/traditional/compatibility` | 兼容性 | 📱小程序 |
-| `/api/emireport/latest` | EMI心理报告 | 📱小程序 |
+### 情绪打卡
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/mind/checkin/create` | 创建情绪打卡 | 📱小程序 | `{childId, moodScore, emotionType, stressLevel, arousalLevel, energyLevel, photoUrl, note}` | `EmotionCheckinVO` |
+| `POST /api/mind/checkin/list` | 获取打卡列表 | 📱小程序 | `{childId, page, size}` | `Page<EmotionCheckinVO>` |
+| `POST /api/mind/checkin/latest` | 获取最新打卡 | 📱小程序 | `{childId}` | `EmotionCheckinVO` |
+| `POST /api/mind/checkin/trend` | 获取情绪趋势 | 📱小程序 | `{childId, period(week/month)}` | `EmotionTrendVO` |
+| `POST /api/mind/checkin/stats` | 获取情绪统计 | 📱小程序 | `{childId}` | `EmotionStatsVO` |
+| `POST /api/mind/checkin/weekly-report` | 获取情绪周报 | 📱小程序 | `{childId}` | `WeeklyReportVO` |
+
+### 情绪预警
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/mind/alert/active` | 获取筛查告警 | 📱小程序 | `{childId}` | `List<EmotionAlertVO>` |
+| `POST /api/mind/alert/checkin-alerts` | 获取打卡告警 | 📱小程序 | `{childId}` | `List<EmotionAlertVO>` |
+| `POST /api/mind/alert/resolve` | 处理告警 | 📱小程序 | `{alertId, source(screening/checkin)}` | `null` |
+| `POST /api/mind/alert/admin/list` | 管理端告警列表 | 🖥管理后台 | `{page, size, resolved}` | `Page<EmotionAlertVO>` |
+
+### 心理筛查
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/mind/screening/submit` | 提交筛查问卷 | 📱小程序 | `{childId, screenType(PHQ-9/GAD-7), answers[]}` | `ScreenResultVO`(含评分/严重等级/风险标记) |
+| `POST /api/mind/screening/history` | 获取筛查历史 | 📱小程序 | `{childId, screenType, limit}` | `List<ScreenResultVO>` |
+| `POST /api/mind/screening/latest` | 获取最新筛查结果 | 📱小程序 | `{childId, screenType}` | `ScreenResultVO` |
+
+### 神经递质与肠脑洞察
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/mind/neurotransmitters` | 获取神经递质指标 | 📱小程序 | `{childId}` | `List<HealthIndicator>`(神经递质与激素类) |
+| `POST /api/mind/gut-emotion-insight` | 获取肠脑洞察摘要 | 📱小程序 | `{childId}` | `{summary, analysis}` |
+| `POST /api/mind/emireport/latest` | 获取最新EMI心理报告 | 📱小程序 | `{childId}` | `EmiReportDTO` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    Child ||--o{ EmotionCheckin : "一个孩子多条打卡"
+    Child ||--o{ MentalHealthScreen : "一个孩子多次筛查"
+    Child ||--o{ EmotionAlert : "一个孩子多个告警"
+    EmotionCheckin ||--o{ EmotionAlert : "打卡触发低风险告警"
+    MentalHealthScreen ||--o{ EmotionAlert : "高风险筛查自动创建告警"
+
+    EmotionCheckin {
+        Long id PK
+        Long childId FK
+        Integer moodScore "效价 1-10"
+        String emotionType "joy/sadness/anger/..."
+        Integer stressLevel "压力 1-10"
+        Integer arousalLevel "激活度 1-10"
+        Integer energyLevel "精力 1-10"
+        String photoUrl
+        String note
+        Integer energyAwarded "奖励能量值"
+        Date checkinDate
+    }
+
+    MentalHealthScreen {
+        Long id PK
+        Long childId FK
+        String screenType "PHQ-9 / GAD-7"
+        String answers "JSON 答案数组"
+        Integer totalScore
+        String severityLevel "正常/轻度/中度/中重度/重度"
+        String riskFlags "JSON 风险标记"
+        String suggestions "建议文案"
+        Date completedAt
+    }
+
+    EmotionAlert {
+        Long id PK
+        Long childId FK
+        String source "screening / checkin"
+        String alertType
+        String severity "high / medium / low"
+        String description
+        String suggestion
+        Boolean resolved
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖情绪打卡(6个端点)、情绪预警(4个端点)、心理筛查(3个端点)、神经递质与肠脑洞察(3个端点)共4个阶段,以及管理端告警管理,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 打卡图片查看权限(家长端隐藏孩子照片)已在Service层处理;高风险筛查自动创建告警和微信推送已覆盖 |
+| 3 | **端点覆盖** | ✅ 完整 | 16个端点全部映射到流程图中,与代码实际暴露的`/api/mind/*`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 孩子(创建打卡/查看自身)、家长(查看打卡/预警/筛查/肠脑洞察)、管理端(告警管理)均已覆盖 |
+| 5 | **数据实体** | ✅ 完整 | emotion_checkin表、mental_health_screens表、emotion_alerts表、emi_reports表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(EmotionCheckinController、EmotionAlertController、ScreeningController、MindController)中的`@PostMapping`匹配 |

+ 183 - 56
docs/flows/minigame-flow.md

@@ -1,76 +1,203 @@
 # 用户使用流程图 — 小游戏
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取小游戏列表 /list]:::portMiniApp
-        A2 --> A3[📱 获取游戏详情 /:gameCode]:::portMiniApp
-    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
 
-    subgraph 游戏执行
-        A3 --> B1{📱 游戏类型}:::portMiniApp
-        B1 -->|舒尔特方格| B2[📱 完成专注力训练]:::portMiniApp
-        B1 -->|猜数字| B3[📱 完成逻辑训练]:::portMiniApp
-        B1 -->|数独| B4[📱 完成思维训练]:::portMiniApp
-        B2 --> B5[📱 游戏完成 /complete]:::portMiniApp
-        B3 --> B5
-        B4 --> B5
-    end
+    %% ============ 角色 ============
+    A0(("👶 孩子")):::actor
+    B0(("🖥 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:游戏浏览与选择
+    %% ================================================================
+    subgraph 阶段一[阶段一:游戏浏览与选择]
+        direction TB
+
+        P1["🏠 小程序:游戏列表页"]:::page
+        P1 -->|"进入页面"| A1["🔗 POST /api/mini-game/list"]:::api
+        A1 -->|"无参数"| S1["⚙️ MiniGameService.getEnabledGames()"]:::service
+        S1 -->|"启用的游戏列表"| D1["📦 mini_games 表(status=1)"]:::data
 
-    subgraph 游戏记录
-        B5 --> C1[📱 保存游戏记录 /game/record]:::portMiniApp
-        C1 --> C2[📱 获取游戏历史 /game/history]:::portMiniApp
-        C2 --> C3[📱 获取最佳成绩 /game/best]:::portMiniApp
-        C3 --> C4[📱 获取统计概览 /game/stats]:::portMiniApp
-        C4 --> C5[📱 获取排行榜 /game/leaderboard]:::portMiniApp
+        D1 -->|"返回游戏列表"| P2["🏠 选择游戏"]:::page
+        P2 -->|"点击游戏"| P2a["🏠 游戏详情页"]:::page
+        P2a -->|"gameCode"| A2["🔗 POST /api/mini-game/{gameCode}"]:::api
+        A2 -->|"gameCode"| S2["⚙️ MiniGameService.getGameByCode()"]:::service
+        S2 -->|"单个游戏信息"| D1
     end
 
-    subgraph 管理端
-        A2 --> D1[🖥 获取所有游戏 /all]:::portAdmin
-        D1 --> D2[🖥 更新游戏状态 /:id/status]:::portAdmin
+    %% ================================================================
+    %% 阶段二:游戏执行
+    %% ================================================================
+    subgraph 阶段二[阶段二:游戏执行]
+        D1 -->|"选中的游戏"| G1{"游戏类型"}:::page
+
+        G1 -->|"舒尔特方格 / 猜数字 / 数独"| G2["🏠 标准游戏页"]:::page
+        G2 -->|"完成: childId, gameCode, completionTime, score"| A3["🔗 POST /api/mini-game/complete"]:::api
+        A3 -->|"childId, gameCode, 用时, 得分"| S3["⚙️ MiniGameService.completeGame()"]:::service
+        S3 -->|"计算积分"| S3a["⚙️ MiniGameService.calculatePoints()"]:::service
+        S3a -->|"更新余额"| D_FAM["📦 family_members 表(totalPoints)"]:::data
+        S3a -->|"积分流水"| D_PT["📦 points_log 表"]:::data
+        S3a -->|"持久化记录"| S3b["⚙️ GameRecordService.saveRecord()"]:::service
+        S3b -->|"写入游戏记录"| D_GR["📦 game_records 表"]:::data
+
+        G1 -->|"智慧数学"| G3["🏠 智慧数学页"]:::page
+        G3 -->|"开始: childId, age"| A4["🔗 POST /api/wisdom/math/start"]:::api
+        A4 -->|"childId, age"| S4["⚙️ WisdomMathService.startSession()"]:::service
+        S4 -->|"计算推荐题目"| D_MCL["📦 math_child_level 表(查询/创建)"]:::data
+        S4 -->|"题目列表, 关卡信息"| G3
+
+        G3 -->|"验证: expression, userAnswer"| A5["🔗 POST /api/wisdom/math/verify"]:::api
+        A5 -->|"表达式, 用户答案"| S5["⚙️ WisdomMathService.verifyAnswer()"]:::service
+        S5 -->|"正确/错误, 解析"| D_MATH["📦 MathQuizLog(写入)"]:::data
+
+        G3 -->|"完成: level, correctCount, totalAttempts, totalTimeMs"| A6["🔗 POST /api/wisdom/math/complete"]:::api
+        A6 -->|"关卡, 正确数, 总尝试, 总耗时"| S6["⚙️ WisdomMathService.completeSession()"]:::service
+        S6 -->|"更新等级进度"| D_MCL
     end
 
-    subgraph 智慧数学
-        A1 --> E1[📱 开始答题 /api/wisdom/math/start]:::portMiniApp
-        E1 --> E2[📱 验证答案 /api/wisdom/math/verify]:::portMiniApp
-        E2 --> E3[📱 完成游戏 /api/wisdom/math/complete]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:游戏记录与统计
+    %% ================================================================
+    subgraph 阶段三[阶段三:游戏记录与统计]
+        D_GR -->|"数据已保存"| P3["🏠 游戏记录页"]:::page
+        P3 -->|"查看历史"| A7["🔗 POST /api/game/history"]:::api
+        A7 -->|"childId, gameCode, page, size"| S7["⚙️ GameRecordService.getHistory()"]:::service
+        S7 -->|"分页历史记录"| D_GR
+
+        P3 -->|"查看最佳"| A8["🔗 POST /api/game/best"]:::api
+        A8 -->|"childId"| S8["⚙️ GameRecordService.getBestScores()"]:::service
+        S8 -->|"各游戏最佳成绩"| D_GR
+
+        P3 -->|"查看统计"| A9["🔗 POST /api/game/stats"]:::api
+        A9 -->|"childId"| S9["⚙️ GameRecordService.getStats()"]:::service
+        S9 -->|"总次数, 总积分, 连续天数"| D_GR
+
+        P3 -->|"查看排行榜"| A10["🔗 POST /api/game/leaderboard"]:::api
+        A10 -->|"gameCode, limit"| S10["⚙️ GameRecordService.getLeaderboard()"]:::service
+        S10 -->|"排名列表"| D_GR
     end
 
-    R1(("👶 孩子")):::actor
-    R2(("🎮 游戏引擎")):::system
+    %% ================================================================
+    %% 阶段四:管理端维护
+    %% ================================================================
+    subgraph 阶段四[阶段四:管理端维护]
+        P4["🏠 管理后台:游戏管理页"]:::page
+        P4 -->|"加载所有游戏"| A11["🔗 POST /api/mini-game/all"]:::api
+        A11 -->|"无参数"| S11["⚙️ MiniGameService.getAllGames()"]:::service
+        S11 -->|"全部游戏列表(含禁用)"| D1
 
-    A1 -.- R1
-    C5 -.- R2
+        P4 -->|"启用/禁用游戏"| P4a["🏠 确认状态变更"]:::page
+        P4a -->|"id, status"| A12["🔗 POST /api/mini-game/{id}/status"]:::api
+        A12 -->|"游戏ID, 目标状态"| S12["⚙️ MiniGameService.updateGameStatus()"]:::service
+        S12 -->|"更新状态字段"| D1
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    A0 -.- P1
+    A0 -.- P2
+    A0 -.- G2
+    A0 -.- G3
+    A0 -.- P3
+    B0 -.- P4
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/mini-game/list` | 小游戏列表 | 📱小程序 |
-| `/api/mini-game/{gameCode}` | 游戏详情 | 📱小程序 |
-| `/api/mini-game/complete` | 完成游戏 | 📱小程序 |
-| `/api/game/record` | 保存游戏记录 | 📱小程序 |
-| `/api/game/history` | 游戏历史 | 📱小程序 |
-| `/api/game/best` | 最佳成绩 | 📱小程序 |
-| `/api/game/stats` | 统计概览 | 📱小程序 |
-| `/api/game/leaderboard` | 排行榜 | 📱小程序 |
-| `/api/wisdom/math/start` | 开始数学游戏 | 📱小程序 |
-| `/api/wisdom/math/verify` | 验证答案 | 📱小程序 |
-| `/api/wisdom/math/complete` | 完成游戏 | 📱小程序 |
-| `/api/mini-game/all` | 所有游戏 | 🖥管理后台 |
-| `/api/mini-game/{id}/status` | 更新游戏状态 | 🖥管理后台 |
+### 标准小游戏
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/mini-game/list` | 获取启用的游戏列表 | 📱小程序 | — | `MiniGame[]`(游戏编码, 名称, 图标, 排序) |
+| `POST /api/mini-game/{gameCode}` | 获取游戏详情 | 📱小程序 | path: `gameCode` | `MiniGame` |
+| `POST /api/mini-game/complete` | 完成任务并发放积分 | 📱小程序 | `{childId, gameCode, completionTime, score}` | `{pointsEarned, newBalance, gameName}` |
+| `POST /api/mini-game/all` | 获取全部游戏(管理端) | 🖥管理后台 | — | `MiniGame[]`(含禁用状态) |
+| `POST /api/mini-game/{id}/status` | 更新游戏启用状态 | 🖥管理后台 | path: `id`, param: `status` | `boolean` |
+
+### 智慧数学
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/wisdom/math/start` | 开始智慧数学新会话 | 📱小程序 | `{childId, age}` | `{level, levelName, questions[], sessionId}` |
+| `POST /api/wisdom/math/verify` | 验证单题答案 | 📱小程序 | `{childId, expression, userAnswer}` | `{correct, correctAnswer, explanation}` |
+| `POST /api/wisdom/math/complete` | 完成智慧数学关卡 | 📱小程序 | `{childId, level, targetN, correctCount, totalAttempts, totalTimeMs, expressions}` | `{levelUp, newLevel, stats}` |
+
+### 游戏记录
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/game/record` | 保存游戏记录 | 📱小程序 | `{childId, gameCode, score, completionTime, difficulty, pointsEarned}` | `{saved}` |
+| `POST /api/game/history` | 获取游戏历史 | 📱小程序 | `{childId, gameCode, page, size}` | `{records[], total, page, size}` |
+| `POST /api/game/best` | 获取最佳成绩 | 📱小程序 | `{childId}` | `[{gameCode, bestScore, bestTime, playCount}]` |
+| `POST /api/game/stats` | 获取统计概览 | 📱小程序 | `{childId}` | `{totalGames, totalPoints, streakDays, byGame[]}` |
+| `POST /api/game/leaderboard` | 获取排行榜 | 📱小程序 | `{gameCode, limit}` | `[{rank, childName, score, completionTime}]` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    MiniGame ||--o{ GameRecord : "一个游戏多个记录"
+    FamilyMember ||--o{ GameRecord : "一个孩子多个记录"
+    FamilyMember ||--o{ PointsLog : "积分流水"
+    MathChildLevel ||--o{ MathQuizLog : "一个关卡多次答题"
+
+    MiniGame {
+        Long id PK
+        string gameCode "schulte / 1a2b / sudoku"
+        string gameName
+        string description
+        string icon
+        int defaultDuration
+        int defaultPoints
+        int sortOrder
+        int status "0禁用 1启用"
+    }
+
+    GameRecord {
+        Long id PK
+        Long childId FK
+        string gameCode
+        int score
+        int completionTime
+        string difficulty
+        int pointsEarned
+    }
+
+    MathChildLevel {
+        Long id PK
+        Long childId FK
+        int level "1-4"
+        int correctStreak
+    }
+
+    MathQuizLog {
+        Long id PK
+        Long childId FK
+        string expression
+        string userAnswer
+        bool correct
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖游戏浏览→执行(3种标准游戏+智慧数学)→记录统计→管理维护4个阶段,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 游戏不存在/孩子不存在等业务异常在Service层throw RuntimeException,由全局异常处理器捕获;游戏中答错题继续、完成时积分保底逻辑已覆盖 |
+| 3 | **端点覆盖** | ✅ 完整 | 13个端点全部映射到流程图中,与MiniGameController、WisdomMathController、GameRecordController实际代码一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 孩子(玩游戏、查看记录)和管理员(管理端启停游戏)两种角色已覆盖;智慧数学无独立管理入口 |
+| 5 | **数据实体** | ✅ 完整 | mini_games、game_records、family_members(积分)、points_log、math_child_level、math_quiz_log 6个实体均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配;积分计算逻辑(calculatePoints中的保底/加成规则)与completeGame流程一致 |

+ 264 - 71
docs/flows/nutrition-diet-flow.md

@@ -1,96 +1,289 @@
 # 用户使用流程图 — 营养与饮食推荐
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取食谱推荐 /meal/recommend]:::portMiniApp
-        A2 --> A3{📱 对推荐满意?}:::portMiniApp
-        A3 -->|不满意| A4[📱 替换指定食材(一换一菜) /meal/replace]:::portMiniApp
-        A4 --> A3
-        A3 -->|满意| A5[📱 记录饮食日志 /meal/log]:::portMiniApp
-    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
+
+    %% ================================================================
+    %% 阶段一:食谱推荐
+    %% ================================================================
+    subgraph 阶段一[阶段一:食谱推荐]
+        direction TB
 
-    subgraph 饮食记录查询
-        A5 --> B1[📱 获取近期日志 /meal/logs]:::portMiniApp
-        B1 --> B2[📱 获取营养摄入统计 /meal/nutrition-summary]:::portMiniApp
+        P1["🏠 小程序:饮食推荐页"]:::page
+        P1 -->|"请求推荐"| A1["🔗 POST /api/meal/recommend"]:::api
+        A1 -->|"userId, mealType"| S1["⚙️ MealRecommendService.aggregateContext()"]:::service
+        S1 -->|"健康报告"| S1a["⚙️ HealthReportService.getLatestReport()"]:::service
+        S1a -->|"最新报告"| D_HR["📦 health_reports 表"]:::data
+        S1 -->|"异常指标"| S1b["⚙️ HealthReportService.getReportIndicators()"]:::service
+        S1b -->|"指标列表"| D_HRI["📦 health_report_indicators 表"]:::data
+        S1 -->|"营养偏好"| S1c["⚙️ UserNutritionProfileService.getByUserId()"]:::service
+        S1c -->|"用户偏好"| D_NP["📦 user_nutrition_profile 表"]:::data
+        S1 -->|"近期摄入"| S1d["⚙️ MealLogService.getNutritionSummary()"]:::service
+        S1d -->|"7日营养汇总"| D_ML["📦 meal_logs 表"]:::data
+        S1 -->|"候选食材"| S1e["⚙️ FoodService.listAll() + SeasonalFoodService"]:::service
+        S1e -->|"当季活跃食材"| D_FOOD["📦 foods 表"]:::data
+
+        S1 -->|"聚合上下文"| S1_final["⚙️ MealRecommendService.buildDifyInputs()"]:::service
+        S1_final -->|"用户画像, 健康摘要, 候选食材"| S_AI["⚙️ AIService.sendNutritionMessage() — Dify AI"]:::service
+        S_AI -->|"AI返回JSON食谱"| P1
+
+        P1 -->|"一换一菜"| A2["🔗 POST /api/meal/replace"]:::api
+        A2 -->|"foodId, userId"| S2["⚙️ MealRecommendService.findReplaceCandidate()"]:::service
+        S2 -->|"同品类同价位替换食材"| D_FOOD
     end
 
-    subgraph 食材推荐指数
-        B2 --> C1[📱 获取食材推荐指数 /food/recommendation/index]:::portMiniApp
-        C1 --> C2[📱 获取指数变更历史 /food/recommendation/history]:::portMiniApp
-        C2 --> C3[📱 按家庭分组获取 /food/recommendation/by-family]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:饮食记录
+    %% ================================================================
+    subgraph 阶段二[阶段二:饮食记录]
+        P1 -->|"满意, 记录饮食"| P2["🏠 记录饮食页"]:::page
+        P2 -->|"提交饮食日志"| A3["🔗 POST /api/meal/log"]:::api
+        A3 -->|"userId, childId, mealType, foods, note, mealDate"| S3["⚙️ MealLogService.create()"]:::service
+        S3 -->|"写入一条记录"| D_ML
+
+        P2 -->|"查看近期日志"| A4["🔗 POST /api/meal/logs"]:::api
+        A4 -->|"userId, days"| S4["⚙️ MealLogService.getRecentMeals()"]:::service
+        S4 -->|"近期饮食列表"| D_ML
+
+        P2 -->|"查看营养统计"| A5["🔗 POST /api/meal/nutrition-summary"]:::api
+        A5 -->|"userId, days"| S5["⚙️ MealLogService.getNutritionSummary()"]:::service
+        S5 -->|"营养摄入汇总"| D_ML
     end
 
-    subgraph 营养偏好
-        C3 --> D1[📱 获取营养偏好 /nutrition/profile/get]:::portMiniApp
-        D1 --> D2[📱 保存营养偏好 /nutrition/profile/save]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:食材推荐指数
+    %% ================================================================
+    subgraph 阶段三[阶段三:食材推荐指数]
+        P2 -->|"打开食材指数"| P3["🏠 食材推荐指数页"]:::page
+        P3 -->|"查看指数"| A6["🔗 POST /api/food/recommendation/index"]:::api
+        A6 -->|"userId"| S6["⚙️ FoodRecommendService.getIndexByUser()"]:::service
+        S6 -->|"食材推荐指数列表"| D_FRI["📦 food_recommend_index 表"]:::data
+
+        P3 -->|"查看变更历史"| A7["🔗 POST /api/food/recommendation/history"]:::api
+        A7 -->|"userId, foodId"| S7["⚙️ FoodRecommendService.getIndexHistory()"]:::service
+        S7 -->|"指数变更记录"| D_FRIL["📦 food_recommend_idx_log 表"]:::data
+
+        P3 -->|"按家庭分组"| A8["🔗 POST /api/food/recommendation/by-family"]:::api
+        A8 -->|"familyId"| S8["⚙️ FoodRecommendService.getByFamily()"]:::service
+        S8 -->|"家庭成员指数(按成员分组)"| D_FRI
     end
 
-    subgraph 营养师服务
-        D2 --> E1[📱 申请营养师 /nutritionist/apply]:::portMiniApp
-        E1 --> E2[📱 获取申请状态 /nutritionist/status]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:营养偏好管理
+    %% ================================================================
+    subgraph 阶段四[阶段四:营养偏好管理]
+        P3 -->|"管理偏好"| P4["🏠 营养偏好设置页"]:::page
+        P4 -->|"获取偏好"| A9["🔗 POST /api/nutrition/profile/get"]:::api
+        A9 -->|"userId"| S9["⚙️ UserNutritionProfileService.getByUserId()"]:::service
+        S9 -->|"当前偏好配置"| D_NP
+
+        P4 -->|"保存偏好"| A10["🔗 POST /api/nutrition/profile/save"]:::api
+        A10 -->|"userId, budgetMonthly, familyTastePreferences, cuisineStyle, mealCount, cookingAbility"| S10["⚙️ UserNutritionProfileService.save()"]:::service
+        S10 -->|"插入/更新"| D_NP
     end
 
-    subgraph 北京营养知识库
-        E2 --> FA1[📱 查询知识库 /nutrition/beijing/kb/query]:::portMiniApp
-        FA1 --> FA2[📱 知识库列表 /nutrition/beijing/kb/list]:::portMiniApp
-        FA2 --> FA3[📱 知识库详情 /nutrition/beijing/kb/info]:::portMiniApp
-        FA3 --> FA4[📱 AI推荐 /nutrition/beijing/recommend]:::portMiniApp
-        FA4 --> FA5[📱 自定义推荐 /nutrition/beijing/recommend/custom]:::portMiniApp
-        FA5 --> FA6[📱 菌群保存 /nutrition/beijing/bacteria/save]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:北京营养知识库
+    %% ================================================================
+    subgraph 阶段五[阶段五:北京营养知识库]
+        P4 -->|"打开精准营养"| P5["🏠 北京精准营养页"]:::page
+        P5 -->|"查询菌属"| A11["🔗 POST /api/nutrition/beijing/kb/query"]:::api
+        A11 -->|"name(拉丁名/中文名)"| S11["⚙️ BacteriaFoodMapping.findAny()"]:::service
+        S11 -->|"菌属详情: 功能, 升降建议, 食物"| D_KBB["📦 BacteriaFoodMapping(内存知识库)"]:::data
+
+        P5 -->|"知识库列表"| A12["🔗 POST /api/nutrition/beijing/kb/list"]:::api
+        A12 -->|"无参数"| S12["⚙️ BacteriaFoodMapping.getAllEntries()"]:::service
+        S12 -->|"全部菌属列表"| D_KBB
+
+        P5 -->|"知识库概况"| A13["🔗 POST /api/nutrition/beijing/kb/info"]:::api
+        A13 -->|"无参数"| S13["⚙️ BacteriaFoodMapping.getMetadata()"]:::service
+        S13 -->|"元数据 + 总菌属数"| D_KBB
+
+        P5 -->|"保存菌群状态"| A14["🔗 POST /api/nutrition/beijing/bacteria/save"]:::api
+        A14 -->|"userId, bacteriaList[{latinName, chineseName, status}]"| S14["⚙️ BeijingNutritionService.saveBacteriaStatus()"]:::service
+        S14 -->|"写入菌群记录"| D_BAC["📦 bacteria_status 表"]:::data
+
+        P5 -->|"基于菌群推荐食材"| A15["🔗 POST /api/nutrition/beijing/recommend"]:::api
+        A15 -->|"userId, limit"| S15["⚙️ BeijingNutritionService.recommendFromDb()"]:::service
+        S15 -->|"推荐食材, 原因, 注意事项"| D_BAC
+
+        P5 -->|"自定义菌群推荐"| A16["🔗 POST /api/nutrition/beijing/recommend/custom"]:::api
+        A16 -->|"userId, bacteriaList[{latinName, chineseName, status}]"| S16["⚙️ BeijingNutritionService.recommend()"]:::service
+        S16 -->|"临时菌群状态→推荐食材"| D_KBB
     end
 
-    subgraph 推荐商品
-        E2 --> F1[📱 获取维度页推荐 /recommend/dimension-products]:::portMiniApp
-        F1 --> F2[📱 获取复购提醒 /recommend/repurchase-reminders/list]:::portMiniApp
-        F2 --> F3[📱 标记已点击 /repurchase-reminders/click]:::portMiniApp
-        F3 --> F4[📱 标记已购买 /repurchase-reminders/purchased]:::portMiniApp
+    %% ================================================================
+    %% 阶段六:营养师申请
+    %% ================================================================
+    subgraph 阶段六[阶段六:营养师申请]
+        P5 -->|"申请营养师"| P6["🏠 营养师申请页"]:::page
+        P6 -->|"提交申请"| A17["🔗 POST /api/nutritionist/apply"]:::api
+        A17 -->|"userId(从token提取)"| S17["⚙️ NutritionistController — 设置nutritionistStatus=pending"]:::service
+        S17 -->|"更新用户营养师状态 + 添加nutritionist角色"| D_USER["📦 users 表"]:::data
+
+        P6 -->|"查询申请状态"| A18["🔗 POST /api/nutritionist/status"]:::api
+        A18 -->|"userId(从token提取)"| S18["⚙️ NutritionistController — 查询状态字段"]:::service
+        S18 -->|"nutritionistStatus, rejectReason"| D_USER
     end
 
-    R1(("👤 用户")):::actor
-    R2(("🥗 食谱引擎")):::system
+    %% ================================================================
+    %% 阶段七:推荐商品与复购
+    %% ================================================================
+    subgraph 阶段七[阶段七:推荐商品与复购]
+        P6 -->|"维度页推荐"| P7["🏠 五维推荐商品区"]:::page
+        P7 -->|"获取推荐"| A19["🔗 POST /api/recommend/dimension-products"]:::api
+        A19 -->|"dimensionCode, familyId, memberId, excludeProductIds, limit"| S19["⚙️ ProductRecommendationService.getDimensionRecommendations()"]:::service
+        S19 -->|"维度相关商品列表"| D_PROD["📦 products 表"]:::data
 
-    A1 -.- R1
-    A2 -.- R2
+        P7 -->|"复购提醒列表"| A20["🔗 POST /api/recommend/repurchase-reminders/list"]:::api
+        A20 -->|"userId(从token提取)"| S20["⚙️ RepurchaseReminderService.getPendingReminders()"]:::service
+        S20 -->|"待处理复购提醒"| D_RR["📦 repurchase_reminder_records 表"]:::data
+
+        P7 -->|"标记已点击"| A21["🔗 POST /api/recommend/repurchase-reminders/click"]:::api
+        A21 -->|"reminderId"| S21["⚙️ RepurchaseReminderService.onReminderClicked()"]:::service
+        S21 -->|"更新点击状态和时间"| D_RR
+
+        P7 -->|"标记已购买"| A22["🔗 POST /api/recommend/repurchase-reminders/purchased"]:::api
+        A22 -->|"reminderId, orderId"| S22["⚙️ RepurchaseReminderService.onReminderPurchased()"]:::service
+        S22 -->|"更新购买状态和订单关联"| D_RR
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    A0 -.- P1
+    A0 -.- P2
+    A0 -.- P3
+    A0 -.- P4
+    A0 -.- P5
+    A0 -.- P6
+    A0 -.- P7
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/meal/recommend` | 获取食谱推荐 | 📱小程序 |
-| `/api/meal/replace` | 替换指定食材 | 📱小程序 |
-| `/api/meal/log` | 记录饮食日志 | 📱小程序 |
-| `/api/meal/logs` | 获取近期日志 | 📱小程序 |
-| `/api/meal/nutrition-summary` | 营养摄入统计 | 📱小程序 |
-| `/api/food/recommendation/index` | 食材推荐指数 | 📱小程序 |
-| `/api/food/recommendation/history` | 指数变更历史 | 📱小程序 |
-| `/api/food/recommendation/by-family` | 按家庭分组 | 📱小程序 |
-| `/api/nutrition/profile/get` | 获取营养偏好 | 📱小程序 |
-| `/api/nutrition/profile/save` | 保存营养偏好 | 📱小程序 |
-| `/api/nutritionist/apply` | 申请营养师 | 📱小程序 |
-| `/api/nutritionist/status` | 申请状态 | 📱小程序 |
-| `/api/nutrition/beijing/kb/query` | 查询知识库 | 📱小程序 |
-| `/api/nutrition/beijing/kb/list` | 知识库列表 | 📱小程序 |
-| `/api/nutrition/beijing/kb/info` | 知识库详情 | 📱小程序 |
-| `/api/nutrition/beijing/recommend` | AI推荐 | 📱小程序 |
-| `/api/nutrition/beijing/recommend/custom` | 自定义推荐 | 📱小程序 |
-| `/api/nutrition/beijing/bacteria/save` | 菌群保存 | 📱小程序 |
-| `/api/recommend/dimension-products` | 维度推荐商品 | 📱小程序 |
-| `/api/recommend/repurchase-reminders/list` | 复购提醒列表 | 📱小程序 |
-| `/api/recommend/repurchase-reminders/click` | 标记已点击 | 📱小程序 |
-| `/api/recommend/repurchase-reminders/purchased` | 标记已购买 | 📱小程序 |
+### 食谱推荐与记录
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/meal/recommend` | 获取AI食谱推荐 | 📱小程序 | `{mealType, conversationId}` | `{answer(JSON食谱), conversationId, replaceOptions, nutritionSummary}` |
+| `POST /api/meal/replace` | 一换一菜 — 替换食材 | 📱小程序 | `{foodId}` | `Food`(同类替代食材) |
+| `POST /api/meal/log` | 记录饮食日志 | 📱小程序 | `{childId, mealType, foods, note, mealDate}` | `{id, message}` |
+| `POST /api/meal/logs` | 获取近期饮食日志 | 📱小程序 | `{days}` | `[MealLog]` |
+| `POST /api/meal/nutrition-summary` | 营养摄入统计 | 📱小程序 | `{days}` | `{calories, protein, fat, carb, ...}` |
+
+### 食材推荐指数
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/food/recommendation/index` | 获取用户食材推荐指数 | 📱小程序 | `{userId}` | `[FoodRecommendIndex(食材, 推荐等级, 理由)]` |
+| `POST /api/food/recommendation/history` | 指数变更历史 | 📱小程序 | `{userId, foodId}` | `[FoodRecommendIdxLog(变更记录)]` |
+| `POST /api/food/recommendation/by-family` | 按家庭分组获取指数 | 📱小程序 | `{familyId}` | `Map<成员ID, [FoodRecommendIndex]>` |
+
+### 营养偏好
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/nutrition/profile/get` | 获取当前用户营养偏好 | 📱小程序 | — | `UserNutritionProfile` |
+| `POST /api/nutrition/profile/save` | 保存营养偏好 | 📱小程序 | `{budgetMonthly, familyTastePreferences, cuisineStyle, mealCount, cookingAbility}` | `"ok"` |
+
+### 北京精准营养(菌群知识库)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/nutrition/beijing/bacteria/save` | 保存用户菌群状态 | 📱小程序 | `{userId, bacteriaList[{latinName, chineseName, status}]}` | `"保存成功"` |
+| `POST /api/nutrition/beijing/recommend` | 基于已保存菌群推荐食材 | 📱小程序 | `{userId, limit}` | `NutritionRecommendResponse(分类推荐列表)` |
+| `POST /api/nutrition/beijing/recommend/custom` | 自定义菌群状态推荐食材 | 📱小程序 | `{userId, bacteriaList[{latinName, chineseName, status}]}` | `NutritionRecommendResponse` |
+| `POST /api/nutrition/beijing/kb/query` | 查询菌属知识库 | 📱小程序 | `{name}` | `BacteriaEntry(功能, 升降建议, 适配食物)` |
+| `POST /api/nutrition/beijing/kb/list` | 知识库菌属列表 | 📱小程序 | — | `[BacteriaEntry]` |
+| `POST /api/nutrition/beijing/kb/info` | 知识库概况 | 📱小程序 | — | `{metadata, 总菌属数, 菌属列表}` |
+
+### 营养师申请
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/nutritionist/apply` | 提交营养师申请 | 📱小程序 | — | `"营养师申请已提交,请等待审核"` |
+| `POST /api/nutritionist/status` | 查询营养师申请状态 | 📱小程序 | — | `{nutritionistStatus, nutritionistRejectReason}` |
+
+### 推荐商品与复购提醒
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/recommend/dimension-products` | 获取维度页推荐商品 | 📱小程序 | `{dimensionCode, familyId, memberId, excludeProductIds, limit}` | `[{productId, name, price, image, ...}]` |
+| `POST /api/recommend/repurchase-reminders/list` | 获取待处理复购提醒 | 📱小程序 | — | `[{id, productName, lastPurchaseDate, ...}]` |
+| `POST /api/recommend/repurchase-reminders/click` | 标记复购提醒已点击 | 📱小程序 | `{id}` | — |
+| `POST /api/recommend/repurchase-reminders/purchased` | 标记复购提醒已购买 | 📱小程序 | `{id, orderId}` | — |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    User ||--o| UserNutritionProfile : "一个用户一个偏好"
+    User ||--o{ MealLog : "一个用户多条日志"
+    User ||--o{ FoodRecommendIndex : "一个用户多个食材指数"
+    FamilyMember ||--o{ FoodRecommendIndex : "一个成员多个食材指数"
+    User ||--o{ RepurchaseReminderRecord : "一个用户多个复购提醒"
+    Product ||--o{ RepurchaseReminderRecord : "一个商品多个复购提醒"
+
+    UserNutritionProfile {
+        Long id PK
+        Long userId FK
+        int budgetMonthly "月预算(元)"
+        string familyTastePreferences "口味偏好"
+        string cuisineStyle "菜系偏好"
+        int mealCount "每日餐数"
+        string cookingAbility "烹饪能力"
+    }
+
+    MealLog {
+        Long id PK
+        Long userId FK
+        Long childId "关联孩子(可选)"
+        string mealType "早餐/午餐/晚餐/加餐"
+        string foods "食物JSON数组"
+        string note "备注"
+        date mealDate "就餐日期"
+    }
+
+    FoodRecommendIndex {
+        Long id PK
+        Long userId FK
+        Long foodId FK
+        string recommendLevel "推荐/适量/谨慎/避免"
+        string reason "推荐理由"
+    }
+
+    RepurchaseReminderRecord {
+        Long id PK
+        Long userId FK
+        Long productId FK
+        string status "pending/clicked/purchased"
+        date lastPurchaseDate
+        date remindDate
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖食谱推荐→饮食记录→食材指数→偏好管理→精准营养(北京菌群)→营养师申请→商品推荐7个阶段,构成完整"推荐→记录→分析→优化"闭环 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 食谱推荐失败返回错误信息(catch Exception);食材替换无候选时返回"没有可替换的食材";营养师重复提交被拒绝;但AI服务超时/降级等未在流程图体现 |
+| 3 | **端点覆盖** | ✅ 完整 | 22个端点全部映射到流程图中,与MealRecommendController、FoodRecommendController、UserNutritionProfileController、BeijingNutritionController、NutritionistController、ProductRecommendationController、RepurchaseReminderController实际代码一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 用户/家长端可操全部7个阶段;营养师申请需管理员审核(管理后台操作未在本图展开);商品推荐可被所有角色使用 |
+| 5 | **数据实体** | ✅ 完整 | user_nutrition_profile、meal_logs、foods、food_recommend_index、food_recommend_idx_log、health_reports、health_report_indicators、bacteria_status、repurchase_reminder_records、products 10个实体/数据源均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配;AI食谱推荐调用的Dify服务链路(aggregateContext→buildDifyInputs→AIService.sendNutritionMessage)与实际Service代码一致 |

+ 281 - 53
docs/flows/points-exchange-flow.md

@@ -1,72 +1,300 @@
 # 用户使用流程图 — 积分兑换
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取积分余额 /balance]:::portMiniApp
-        A2 --> A3[📱 获取积分流水 /logs]:::portMiniApp
-        A3 --> A4[📱 按分类查询 /logs-by-category]:::portMiniApp
-        A4 --> A5[📱 管理系统余额 /system-balance]:::portMiniApp
-    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_CHILD(("👶 孩子")):::actor
+    ROLE_SYSTEM(("⚙️ 积分引擎")):::actor
+
+    %% ================================================================
+    %% 阶段一:积分概览
+    %% ================================================================
+    subgraph 阶段一[阶段一:积分概览]
+        direction TB
+
+        P1["🏠 小程序:积分中心"]:::page
+        P1 -->|"选择操作"| P1_choice{"查看余额 / 流水 / 系统积分"}
+
+        P1_choice -->|"查看余额"| P1a["🏠 积分余额页"]
+        P1a -->|"孩子ID"| A1["🔗 POST /api/points/balance"]:::api
+        A1 -->|"孩子ID"| S1["⚙️ PointsService.getBalance()"]:::service
+        S1 -->|"当前积分 + 过期时间"| D1["📦 family_members 表(totalPoints查询)"]:::data
+
+        P1_choice -->|"积分流水"| P1b["🏠 积分流水页"]
+        P1b -->|"孩子ID, 分页"| A2["🔗 POST /api/points/logs"]:::api
+        A2 -->|"孩子ID, 页码, 页大小"| S2["⚙️ PointsService.getPointsLogs()"]:::service
+        S2 -->|"积分变动记录(类型+金额+描述)"| D2["📦 points_logs 表"]:::data
 
-    subgraph 积分调整
-        A5 --> B1[📱 手动调整积分 /adjust]:::portMiniApp
+        P1_choice -->|"按分类筛选"| P1c["🏠 流水分类筛选"]
+        P1c -->|"孩子ID, 分类, 分页"| A3["🔗 POST /api/points/logs-by-category"]:::api
+        A3 -->|"分类(task/system)"| S3["⚙️ PointsService.getPointsLogsByCategory()"]:::service
+        S3 -->|"按分类过滤的流水"| D2
+
+        P1_choice -->|"系统积分余额"| P1d["🏠 系统积分页"]
+        P1d -->|"孩子ID"| A4["🔗 POST /api/points/system-balance"]:::api
+        A4 -->|"孩子ID"| S4["⚙️ PointsService.getSystemPointsBalance()"]:::service
+        S4 -->|"系统积分数量"| D1
     end
 
-    subgraph 兑换商城
-        A2 --> C1[📱 获取兑换商品列表 /product/list]:::portMiniApp
-        C1 --> C2[📱 获取商品详情 /product/detail]:::portMiniApp
-        C2 --> C3[📱 提交兑换 /submit]:::portMiniApp
-        C3 --> C4[📱 获取兑换记录 /records]:::portMiniApp
-        C4 --> C5[📱 获取兑换统计 /stats]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:积分调整
+    %% ================================================================
+    subgraph 阶段二[阶段二:积分调整]
+        D1 -->|"孩子积分"| P2["🖥 管理后台:积分调整页"]:::page
+        P2 -->|"手动调整"| A5["🔗 POST /api/points/adjust"]:::api
+        A5 -->|"孩子ID, 调整金额, 原因, 家长密码"| S5["⚙️ PointsService.adjustPoints()"]:::service
+        S5 -->|"更新余额 + 写入流水"| D1
+        S5 -->|"调整记录"| D2
+
+        P2 -->|"系统发放"| P2a["⚙️ 系统自动奖励"]
+        P2a -->|"孩子ID, 金额, 原因"| S5a["⚙️ PointsService.awardSystemPoints()"]:::service
+        S5a -->|"增加系统积分 + 流水"| D1
+        S5a -->|"奖励记录"| D2
+
+        P2a -->|"系统扣除"| P2b["⚙️ 系统自动扣除"]
+        P2b -->|"孩子ID, 金额, 原因"| S5b["⚙️ PointsService.deductSystemPoints()"]:::service
+        S5b -->|"余额不足返回-1, 否则扣除"| D1
+        S5b -->|"扣除记录"| D2
     end
 
-    subgraph 奖励系统
-        A4 --> D1[📱 创建奖励 /create]:::portMiniApp
-        D1 --> D2[📱 获取奖励模板 /templates]:::portMiniApp
-        D2 --> D3[📱 兑换奖励 /:id/exchange]:::portMiniApp
-        D3 --> D4[📱 审批奖励 /:id/approve]:::portMiniApp
-        D4 --> D5[📱 兑换历史 /exchange-history]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:积分兑换商城
+    %% ================================================================
+    subgraph 阶段三[阶段三:积分兑换商城]
+        D1 -->|"积分余额"| P3["📱 小程序:兑换商城页"]:::page
+        P3 -->|"商品列表"| A6["🔗 POST /api/points/exchange/product/list"]:::api
+        A6 -->|"分类, 分页"| S6["⚙️ PointsExchangeService.getProductList()"]:::service
+        S6 -->|"已启用的兑换商品(按排序)"| D3["📦 points_exchange_products 表"]:::data
+
+        P3 -->|"商品详情"| P3a["📱 商品详情页"]
+        P3a -->|"商品ID"| A7["🔗 POST /api/points/exchange/product/detail"]:::api
+        A7 -->|"商品ID"| S7["⚙️ PointsExchangeService.getProductDetail()"]:::service
+        S7 -->|"商品完整信息"| D3
+
+        P3a -->|"提交兑换"| P3b["📱 兑换确认"]
+        P3b -->|"商品ID, 孩子ID, 数量"| A8["🔗 POST /api/points/exchange/submit"]:::api
+        A8 -->|"商品ID, 孩子ID, 数量"| S8["⚙️ PointsExchangeService.exchangeProduct()"]:::service
+        S8 -->|"校验库存/每日限额/积分→扣积分→生成兑换码"| S8a["⚙️ PointsService.deductSystemPoints()"]:::service
+        S8a -->|"扣除积分"| D1
+        S8 -->|"写入兑换记录"| D4["📦 points_exchange_records 表"]:::data
+        S8 -->|"扣减库存"| D3
+
+        P3 -->|"兑换记录"| P3c["📱 兑换记录页"]
+        P3c -->|"用户ID"| A9["🔗 POST /api/points/exchange/records"]:::api
+        A9 -->|"用户ID"| S9["⚙️ PointsExchangeService.getExchangeRecords()"]:::service
+        S9 -->|"兑换记录列表"| D4
+
+        P3 -->|"兑换统计"| P3d["📱 今日兑换次数"]
+        P3d -->|"用户ID"| A10["🔗 POST /api/points/exchange/stats"]:::api
+        A10 -->|"用户ID"| S10["⚙️ PointsExchangeService.getExchangeStats()"]:::service
+        S10 -->|"今日兑换次数"| D4
     end
 
-    R1(("👤 家长/孩子")):::actor
-    R2(("💎 积分引擎")):::system
+    %% ================================================================
+    %% 阶段四:奖励心愿系统
+    %% ================================================================
+    subgraph 阶段四[阶段四:奖励心愿系统]
+        D1 -->|"孩子积分"| P4["📱 孩子端:心愿页"]:::page
+        P4 -->|"创建心愿"| P4a["📱 心愿表单"]
+        P4a -->|"标题, 分类"| A11["🔗 POST /api/rewards/create"]:::api
+        A11 -->|"用户ID, 标题, 分类, 孩子ID"| S11["⚙️ RewardService.createReward()"]:::service
+        S11 -->|"写入心愿, 状态=available"| D5["📦 rewards 表"]:::data
+
+        P4a -->|"创建心愿(孩子→等待家长填积分)"| P4b["📱 孩子创建待审批心愿"]
+        P4b -->|"标题, 分类"| A11a["🔗 POST /api/reward-wishlist/create"]:::api
+        A11a -->|"用户ID, 心愿信息"| S11a["⚙️ RewardWishlistService.create()"]:::service
+        S11a -->|"写入心愿单, 状态=pending"| D6["📦 reward_wishlists 表"]:::data
+
+        P4 -->|"心愿列表"| P4c["📱 心愿列表"]
+        P4c -->|"孩子ID"| A12["🔗 POST /api/rewards/wishlist"]:::api
+        A12 -->|"孩子ID"| S12["⚙️ RewardService.getWishlist()"]:::service
+        S12 -->|"可兑换的心愿列表"| D5
+
+        P4 -->|"奖励模板"| P4d["📱 奖励模板"]
+        P4d -->|""| A13["🔗 POST /api/rewards/templates"]:::api
+        A13 -->|""| S13["⚙️ RewardService.getTemplates()"]:::service
+        S13 -->|"奖励模板列表"| D5
+
+        D5 -->|"可兑换心愿"| P4e["📱 兑换心愿"]
+        P4e -->|"心愿ID, 孩子ID"| A14["🔗 POST /api/rewards/{id}/exchange"]:::api
+        A14 -->|"心愿ID, 孩子ID"| S14["⚙️ RewardService.exchangeReward()"]:::service
+        S14 -->|"校验积分→扣积分→状态=pending"| D1
+        S14 -->|"记录积分消耗"| D2
+        S14 -->|"更新心愿状态"| D5
+
+        D6 -->|"待审批心愿"| P4f["🖥 家长端:审批心愿页"]
+        P4f -->|"获取家庭心愿"| A15["🔗 POST /api/reward-wishlist/family"]:::api
+        A15 -->|"用户ID"| S15["⚙️ RewardWishlistService.getByFamilyId()"]:::service
+        S15 -->|"家庭所有心愿单"| D6
+
+        P4f -->|"审批通过"| P4g["🖥 审批弹窗"]
+        P4g -->|"心愿ID"| A16["🔗 POST /api/reward-wishlist/{id}/approve"]:::api
+        A16 -->|"心愿ID, approved=true"| S16["⚙️ RewardWishlistService.approve()"]:::service
+        S16 -->|"更新状态=exchanged"| D6
+
+        P4f -->|"审批拒绝"| P4h["🖥 拒绝弹窗"]
+        P4h -->|"心愿ID"| A16
+        S16 -->|"更新状态=rejected"| D6
+
+        D5 -->|"待审批兑换"| P4i["🖥 家长端:审批兑换页"]
+        P4i -->|"审批"| A17["🔗 POST /api/rewards/{id}/approve"]:::api
+        A17 -->|"心愿ID, approved"| S17["⚙️ RewardService.approveReward()"]:::service
+        S17 -->|"同意→状态=exchanged; 拒绝→退积分"| D5
 
-    A1 -.- R1
-    A3 -.- R2
+        P4 -->|"兑换历史"| P4j["📱 兑换历史"]
+        P4j -->|"孩子ID, 分页"| A18["🔗 POST /api/rewards/exchange-history"]:::api
+        A18 -->|"孩子ID, 页码, 页大小"| S18["⚙️ RewardService.getExchangeHistory()"]:::service
+        S18 -->|"已兑换/已拒绝的心愿历史"| D5
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P4f
+    ROLE_PARENT -.- P4i
+    ROLE_CHILD -.- P1
+    ROLE_CHILD -.- P4
+    ROLE_CHILD -.- P4e
+    ROLE_SYSTEM -.- P2a
+    ROLE_SYSTEM -.- P2b
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/points/balance` | 获取积分余额 | 📱小程序 |
-| `/api/points/logs` | 获取积分流水 | 📱小程序 |
-| `/api/points/adjust` | 手动调整积分 | 📱小程序 |
-| `/api/points/system-balance` | 系统余额 | 📱小程序 |
-| `/api/points/logs-by-category` | 按分类查询流水 | 📱小程序 |
-| `/api/points/exchange/product/list` | 兑换商品列表 | 📱小程序 |
-| `/api/points/exchange/product/detail` | 商品详情 | 📱小程序 |
-| `/api/points/exchange/submit` | 提交兑换 | 📱小程序 |
-| `/api/points/exchange/records` | 兑换记录 | 📱小程序 |
-| `/api/points/exchange/stats` | 兑换统计 | 📱小程序 |
-| `/api/rewards/create` | 创建奖励 | 📱小程序 |
-| `/api/rewards/wishlist` | 奖励清单 | 📱小程序 |
-| `/api/rewards/{id}/exchange` | 兑换奖励 | 📱小程序 |
-| `/api/rewards/{id}/approve` | 审批奖励 | 📱小程序 |
-| `/api/rewards/templates` | 奖励模板 | 📱小程序 |
-| `/api/rewards/exchange-history` | 兑换历史 | 📱小程序 |
+### 积分概览与流水
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/points/balance` | 获取积分余额 | 📱小程序 | `{childId}` | `{balance, expireDate}` |
+| `POST /api/points/logs` | 获取积分流水 | 📱小程序 | `{childId, page, size}` | `分页积分流水(类型/金额/描述)` |
+| `POST /api/points/logs-by-category` | 按分类查询流水 | 📱小程序 | `{childId, category, page, size}` | `按分类过滤的流水` |
+| `POST /api/points/system-balance` | 系统积分余额 | 📱小程序 | `{childId}` | `{systemPoints}` |
+
+### 积分调整
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/points/adjust` | 手动调整积分 | 🖥管理后台 | `{childId, amount, reason, password}` | `{newBalance}` |
+| `POST /api/points/adjust` | 手动调整积分 | 📱小程序 | `{childId, amount, reason, password}` | `{newBalance}` |
+
+### 积分兑换商城
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/points/exchange/product/list` | 兑换商品列表 | 📱小程序 | `{category, pageNum, pageSize}` | `分页兑换商品列表` |
+| `POST /api/points/exchange/product/detail` | 商品详情 | 📱小程序 | `{id}` | `PointsExchangeProduct对象` |
+| `POST /api/points/exchange/submit` | 提交兑换 | 📱小程序 | `{productId, childId, quantity}` | `PointsExchangeRecord(含兑换码)` |
+| `POST /api/points/exchange/records` | 兑换记录 | 📱小程序 | Header: `userId` | `兑换记录列表` |
+| `POST /api/points/exchange/stats` | 兑换统计 | 📱小程序 | Header: `userId` | `{todayCount}` |
+
+### 奖励心愿系统
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/rewards/create` | 创建奖励(家长直接创建) | 📱小程序 | `{childId, title, pointsRequired, category}` | `奖励ID` |
+| `POST /api/rewards/wishlist` | 获取心愿列表 | 📱小程序 | `{childId}` | `可兑换的心愿列表(含进度)` |
+| `POST /api/rewards/{id}/exchange` | 兑换奖励 | 📱小程序 | `{childId}` | `{success, newBalance}` |
+| `POST /api/rewards/{id}/approve` | 审批奖励(家长) | 📱小程序 | `{approved}` | `boolean` |
+| `POST /api/rewards/templates` | 获取奖励模板 | 📱小程序 | — | `奖励模板列表` |
+| `POST /api/rewards/exchange-history` | 兑换历史 | 📱小程序 | `{childId, page, size}` | `分页兑换历史` |
+| `POST /api/reward-wishlist/create` | 创建心愿(孩子→待家长审批) | 📱小程序 | `{title, description, category}` | `心愿ID` |
+| `POST /api/reward-wishlist/my` | 我的心愿单 | 📱小程序 | Header: `userId` | `心愿单列表` |
+| `POST /api/reward-wishlist/family` | 家庭心愿单 | 📱小程序 | Header: `userId` | `家庭所有心愿单` |
+| `POST /api/reward-wishlist/{id}/exchange` | 兑换心愿 | 📱小程序 | path: `id` | `boolean` |
+| `POST /api/reward-wishlist/{id}/approve` | 审核心愿 | 📱小程序 | `{approved}` | `boolean` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    FamilyMember ||--o{ PointsLog : "一个孩子多条积分流水"
+    FamilyMember ||--o{ Reward : "一个孩子多个心愿"
+    FamilyMember ||--o{ PointsExchangeRecord : "一个孩子多次兑换"
+    FamilyMember ||--o{ RewardWishlist : "一个孩子多个心愿单"
+    PointsExchangeProduct ||--o{ PointsExchangeRecord : "一个商品多次兑换"
+
+    FamilyMember {
+        Long id PK
+        int totalPoints "总积分"
+        int systemPoints "系统积分"
+        string nickname
+    }
+
+    PointsLog {
+        Long id PK
+        Long childId FK
+        int amount "正=收入, 负=支出"
+        string type "earn / spend / adjust / refund"
+        string category "task / system"
+        string description
+    }
+
+    PointsExchangeProduct {
+        Long id PK
+        string name
+        int pointsPrice
+        int stock "-1=不限"
+        string category
+        string status "enabled / disabled"
+    }
+
+    PointsExchangeRecord {
+        Long id PK
+        Long userId FK
+        Long familyMemberId FK
+        Long productId FK
+        string productName
+        int pointsCost
+        int quantity
+        string status "completed / expired"
+        string redeemCode
+    }
+
+    Reward {
+        Long id PK
+        Long familyId FK
+        Long childId FK
+        string title
+        int pointsRequired
+        string category
+        string status "pending_approval / available / pending / exchanged / rejected"
+        int exchangeApproved
+    }
+
+    RewardWishlist {
+        Long id PK
+        Long familyId FK
+        Long userId FK
+        string title
+        string description
+        int pointsRequired
+        string status "pending / exchanged / rejected"
+        int exchangeApproved
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖积分概览→积分调整→兑换商城→奖励心愿系统4个阶段,包含家长端、孩子端、管理后台、系统自动4种视角 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 积分不足、余额为负保护、每日兑换限额、库存不足已覆盖;心愿审批拒绝退积分逻辑已覆盖;密码验证失败等前端校验未在图里展开 |
+| 3 | **端点覆盖** | ✅ 完整 | 16个端点全部映射到流程图中,与代码中PointsController、PointsExchangeController、RewardController、RewardWishlistController一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长(查看/调整积分/审批心愿)、孩子(查看/兑换/创建心愿)、系统(自动奖励/扣除)、管理后台(调整积分)均已覆盖 |
+| 5 | **数据实体** | ✅ 完整 | family_members、points_logs、points_exchange_products、points_exchange_records、rewards、reward_wishlists 6张表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配,Service方法名与代码中的业务方法一致(getBalance/getPointsLogs/exchangeProduct/createReward等) |

+ 276 - 79
docs/flows/promotion-flow.md

@@ -1,104 +1,301 @@
 # 用户使用流程图 — 推广分销
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 绑定推广关系 /bind]:::portMiniApp
-        A2 --> A3[📱 获取佣金列表 /commission/list]:::portMiniApp
-        A3 --> A4[📱 获取绑定列表 /bindings/list]:::portMiniApp
-    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长/推广员")):::actor
+    ROLE_TEACHER(("📋 规划师")):::actor
+    ROLE_ADMIN(("🖥 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:推广关系绑定
+    %% ================================================================
+    subgraph 阶段一[阶段一:推广关系绑定]
+        P1["🏠 推广端:推广首页"]:::page
+        P1 -->|"输入邀请码, promoterFamilyId"| A1["🔗 POST /api/promotion/bind"]:::api
+        A1 -->|"inviteCode, promoterFamilyId"| S1["⚙️ FamilyCommissionService.bindByInviteCode()"]:::service
+        S1 -->|"写入推广绑定关系"| D_BIND["📦 promotion_binding 表"]:::data
 
-    subgraph 销售邀请
-        A1 --> B1[📱 生成销售邀请码 /generate]:::portMiniApp
-        B1 --> B2[📱 校验邀请码 /validate]:::portMiniApp
-        B2 --> B3[📱 获取我的虚拟团队 /my-teams]:::portMiniApp
-        B3 --> B4[📱 获取团队位置 /my-position]:::portMiniApp
+        P1 -->|"查看绑定列表"| A2["🔗 POST /api/promotion/bindings/list"]:::api
+        A2 -->|"familyId"| S2["⚙️ FamilyCommissionService.getBindings()"]:::service
+        S2 -->|"该家庭的所有绑定记录"| D_BIND
+
+        P1 -->|"查看佣金列表"| A3["🔗 POST /api/promotion/commission/list"]:::api
+        A3 -->|"familyId, page, size"| S3["⚙️ FamilyCommissionService.getCommissionList()"]:::service
+        S3 -->|"分页佣金记录"| D_FC["📦 family_commission 表"]:::data
     end
 
-    subgraph 佣金系统
-        A3 --> C1[📱 获取佣金汇总 /summary]:::portMiniApp
-        C1 --> C2[📱 获取佣金明细 /list]:::portMiniApp
-        C2 --> C3[📱 获取团队佣金 /team]:::portMiniApp
-        C3 --> C4[📱 获取佣金统计 /stats]:::portMiniApp
-        C4 --> C5[📱 获取佣金余额 /balance]:::portMiniApp
-        C5 --> C6[📱 团队列表 /team/list]:::portMiniApp
-        C6 --> C7[📱 获取转化漏斗 /funnel]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:邀请码与虚拟团队
+    %% ================================================================
+    subgraph 阶段二[阶段二:邀请码与虚拟团队]
+        P2["🏠 推广端:销售邀请页"]:::page
+        P2 -->|"生成邀请码"| A4["🔗 POST /api/distribution/invite/generate"]:::api
+        A4 -->|"systemId, userId"| S4["⚙️ DistributionService.generateInviteCode()"]:::service
+        S4 -->|"生成唯一邀请码"| D_RELATION["📦 distribution_relations 表"]:::data
+        S4 -->|"虚拟团队信息"| D_SYSTEM["📦 distribution_systems 表"]:::data
+
+        P2 -->|"校验邀请码"| A5["🔗 POST /api/distribution/invite/validate"]:::api
+        A5 -->|"inviteCode"| S5["⚙️ DistributionService.findByInviteCode()"]:::service
+        S5 -->|"inviterId, systemId, teamName"| D_RELATION
+
+        P2 -->|"查看虚拟团队"| A6["🔗 POST /api/distribution/invite/my-teams"]:::api
+        A6 -->|"userId"| S6["⚙️ DistributionService.getUserTeams()"]:::service
+        S6 -->|"我参与的所有虚拟团队"| D_SYSTEM
+
+        P2 -->|"查看团队位置"| A7["🔗 POST /api/distribution/invite/my-position"]:::api
+        A7 -->|"systemId, userId"| S7["⚙️ DistributionService.getUserPosition()"]:::service
+        S7 -->|"上级, 下级, 深度"| D_RELATION
     end
 
-    subgraph 推广素材
-        C7 --> D1[📱 获取素材列表 /list]:::portMiniApp
-        D1 --> D2[📱 获取素材详情 /detail]:::portMiniApp
-        D2 --> D3[📱 按场景获取 /by-scenario]:::portMiniApp
-        D3 --> D4[📱 创建素材 /create]:::portMiniApp
-        D4 --> D5[📱 更新素材 /update]:::portMiniApp
-        D5 --> D6[📱 删除素材 /delete]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:佣金总览
+    %% ================================================================
+    subgraph 阶段三[阶段三:佣金总览]
+        P3["🏠 推广端:佣金中心"]:::page
+        P3 -->|"获取佣金汇总"| A8["🔗 POST /api/commission/summary"]:::api
+        A8 -->|"userId"| S8["⚙️ CommissionService.getSummary()"]:::service
+        S8 -->|"累计佣金, 可提现, 待结算, 已提现"| D_SUMMARY["📦 CommissionSummaryDTO"]:::data
+
+        P3 -->|"获取佣金统计"| A9["🔗 POST /api/commission/stats"]:::api
+        A9 -->|"userId"| S9["⚙️ CommissionService.getCommissionStats()"]:::service
+        S9 -->|"今日/本月/累计/L1/L2等面板数据"| D_STATS["📦 统计聚合(内存)"]:::data
+
+        P3 -->|"获取可提现余额"| A10["🔗 POST /api/commission/balance"]:::api
+        A10 -->|"userId"| S10["⚙️ CommissionService.getSummary()"]:::service
+        S10 -->|"availableAmount, settledAmount, pendingAmount"| D_SUMMARY
     end
 
-    subgraph 佣金记录
-        A3 --> E1[📱 记录佣金 /record]:::portMiniApp
-        E1 --> E2[📱 家庭佣金汇总 /family-total]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:佣金明细与团队
+    %% ================================================================
+    subgraph 阶段四[阶段四:佣金明细与团队]
+        P3 -->|"查看佣金明细"| A11["🔗 POST /api/commission/list"]:::api
+        A11 -->|"userId, page, size"| S11["⚙️ CommissionService.getList()"]:::service
+        S11 -->|"分页佣金记录"| D_RECORDS["📦 commission_records 表"]:::data
+
+        P3 -->|"查看团队统计"| A12["🔗 POST /api/commission/team"]:::api
+        A12 -->|"userId"| S12["⚙️ CommissionService.getTeamStats()"]:::service
+        S12 -->|"L1/L2人数, 团队佣金"| D_RECORDS
+
+        P3 -->|"查看团队列表"| A13["🔗 POST /api/commission/team/list"]:::api
+        A13 -->|"userId, level, page, size"| S13["⚙️ CommissionService.getTeamList()"]:::service
+        S13 -->|"分页团队成员"| D_RECORDS
+
+        P3 -->|"查看转化漏斗"| A14["🔗 POST /api/commission/funnel"]:::api
+        A14 -->|"userId"| S14["⚙️ CommissionService.getCommissionFunnel()"]:::service
+        S14 -->|"转化各阶段人数/金额"| D_STATS
+
+        P1 -->|"记录佣金"| A15["🔗 POST /api/promotion/commission/record"]:::api
+        A15 -->|"Commission对象"| S15["⚙️ PromotionCommissionService.recordCommission()"]:::service
+        S15 -->|"写入佣金记录"| D_COMM["📦 promotion_commission 表"]:::data
+
+        P1 -->|"家庭佣金汇总"| A16["🔗 POST /api/promotion/commission/family-total"]:::api
+        A16 -->|"familyId"| S16["⚙️ PromotionCommissionService.getFamilyTotal()"]:::service
+        S16 -->|"该家庭佣金总额"| D_COMM
     end
 
-    subgraph 提现
-        C5 --> F1[📱 申请提现 /apply]:::portMiniApp
-        F1 --> F2[📱 提现记录 /history]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:推广素材管理
+    %% ================================================================
+    subgraph 阶段五[阶段五:推广素材管理]
+        P4["🏠 推广端:素材中心"]:::page
+        P4 -->|"素材列表"| A17["🔗 POST /api/promotion/material/list"]:::api
+        A17 -->|"materialType, usageScenario, keyword"| S17["⚙️ PromotionMaterialService.getMaterials()"]:::service
+        S17 -->|"分页素材列表"| D_MAT["📦 promotion_materials 表"]:::data
+
+        P4 -->|"素材详情"| A18["🔗 POST /api/promotion/material/detail"]:::api
+        A18 -->|"id"| S18["⚙️ PromotionMaterialService.getById()"]:::service
+        S18 -->|"素材完整信息"| D_MAT
+
+        P4 -->|"按场景获取"| A19["🔗 POST /api/promotion/material/by-scenario"]:::api
+        A19 -->|"scenario"| S19["⚙️ PromotionMaterialService.getByScenario()"]:::service
+        S19 -->|"该场景下的所有素材"| D_MAT
+
+        P4 -->|"管理员:创建素材"| A20["🔗 POST /api/promotion/material/create"]:::api
+        A20 -->|"PromotionMaterial对象"| S20["⚙️ PromotionMaterialService.createMaterial()"]:::service
+        S20 -->|"新建素材记录"| D_MAT
+
+        P4 -->|"管理员:更新素材"| A21["🔗 POST /api/promotion/material/update"]:::api
+        A21 -->|"PromotionMaterial对象(id必填)"| S21["⚙️ PromotionMaterialService.updateMaterial()"]:::service
+        S21 -->|"更新素材记录"| D_MAT
+
+        P4 -->|"管理员:删除素材"| A22["🔗 POST /api/promotion/material/delete"]:::api
+        A22 -->|"id"| S22["⚙️ PromotionMaterialService.deleteMaterial()"]:::service
+        S22 -->|"删除素材记录"| D_MAT
     end
 
-    subgraph 推广排行榜
-        E2 --> G1[📱 获取排行榜 /top]:::portMiniApp
-        G1 --> G2[📱 获取我的排名 /my-rank]:::portMiniApp
+    %% ================================================================
+    %% 阶段六:提现
+    %% ================================================================
+    subgraph 阶段六[阶段六:提现]
+        P3 -->|"申请提现"| A23["🔗 POST /api/withdrawal/apply"]:::api
+        A23 -->|"amount, accountInfo"| S23["⚙️ WithdrawalService.apply()"]:::service
+        S23 -->|"新建提现申请(待审核)"| D_WITHDRAW["📦 withdrawal_requests 表"]:::data
+
+        P3 -->|"提现记录"| A24["🔗 POST /api/withdrawal/history"]:::api
+        A24 -->|"page, size"| S24["⚙️ WithdrawalService.getHistory()"]:::service
+        S24 -->|"该用户的历史提现记录"| D_WITHDRAW
+
+        P5["🖥 管理后台:佣金审核页"]:::page
+        P5 -->|"提现列表"| A25["🔗 POST /api/admin/commission/withdrawals"]:::api
+        A25 -->|"status, page, size"| S25["⚙️ WithdrawalService.getAdminList()"]:::service
+        S25 -->|"全平台提现申请"| D_WITHDRAW
+
+        P5 -->|"审核提现"| A26["🔗 POST /api/admin/commission/audit"]:::api
+        A26 -->|"requestId, status, remark"| S26["⚙️ WithdrawalService.audit()"]:::service
+        S26 -->|"更新提现状态(approved/rejected)"| D_WITHDRAW
+
+        P5 -->|"退款记录"| A27["🔗 POST /api/admin/commission/refunds/pending"]:::api
+        A27 -->|"status, orderType, page, size"| S27["⚙️ PendingRefundService.getAllPendingRefunds()"]:::service
+        S27 -->|"待处理退款列表"| D_REFUND["📦 pending_refunds 表"]:::data
+
+        P5 -->|"中止退款"| A28["🔗 POST /api/admin/commission/refunds/cancel"]:::api
+        A28 -->|"refundId"| S28["⚙️ PendingRefundService.cancelPendingRefund()"]:::service
+        S28 -->|"取消退款流程"| D_REFUND
     end
 
-    R1(("👤 推广员")):::actor
-    R2(("💰 佣金系统")):::system
+    %% ================================================================
+    %% 阶段七:排行榜与里程碑
+    %% ================================================================
+    subgraph 阶段七[阶段七:排行榜与里程碑]
+        P1 -->|"查看排行榜"| A29["🔗 POST /api/leaderboard/top"]:::api
+        A29 -->|"weekStart"| S29["⚙️ ReferralLeaderboardService.getTopUsers()"]:::service
+        S29 -->|"推广排行前20名"| D_RANK["📦 排行聚合(内存)"]:::data
 
-    A1 -.- R1
-    C1 -.- R2
+        P1 -->|"我的排名"| A30["🔗 POST /api/leaderboard/my-rank"]:::api
+        A30 -->|"userId, weekStart"| S30["⚙️ ReferralLeaderboardService.getMyRank()"]:::service
+        S30 -->|"当前用户排名及上下级差"| D_RANK
+
+        P1 -->|"里程碑列表"| A31["🔗 POST /api/invite/milestone/list"]:::api
+        A31 -->|"userId"| S31["⚙️ InviteMilestoneService.getMilestones()"]:::service
+        S31 -->|"已达成/未达成的里程碑"| D_MILESTONE["📦 invite_milestones 表"]:::data
+
+        P1 -->|"领取里程碑奖励"| A32["🔗 POST /api/invite/milestone/claim"]:::api
+        A32 -->|"userId, milestone"| S32["⚙️ InviteMilestoneService.claimReward()"]:::service
+        S32 -->|"发放奖励, 更新状态"| D_MILESTONE
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P3
+    ROLE_PARENT -.- P4
+    ROLE_TEACHER -.- P2
+    ROLE_ADMIN -.- P5
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/promotion/bind` | 绑定推广关系 | 📱小程序 |
-| `/api/promotion/commission/list` | 佣金列表 | 📱小程序 |
-| `/api/promotion/bindings/list` | 绑定列表 | 📱小程序 |
-| `/api/promotion/commission/record` | 记录佣金 | 📱小程序 |
-| `/api/promotion/commission/family-total` | 家庭佣金汇总 | 📱小程序 |
-| `/api/promotion/material/list` | 素材列表 | 📱小程序 |
-| `/api/promotion/material/detail` | 素材详情 | 📱小程序 |
-| `/api/promotion/material/by-scenario` | 按场景获取 | 📱小程序 |
-| `/api/promotion/material/create` | 创建素材 | 📱小程序 |
-| `/api/promotion/material/update` | 更新素材 | 📱小程序 |
-| `/api/promotion/material/delete` | 删除素材 | 📱小程序 |
-| `/api/commission/summary` | 佣金汇总 | 📱小程序 |
-| `/api/commission/list` | 佣金明细 | 📱小程序 |
-| `/api/commission/team` | 团队佣金 | 📱小程序 |
-| `/api/commission/stats` | 佣金统计 | 📱小程序 |
-| `/api/commission/balance` | 余额 | 📱小程序 |
-| `/api/commission/team/list` | 团队列表 | 📱小程序 |
-| `/api/commission/funnel` | 转化漏斗 | 📱小程序 |
-| `/api/distribution/invite/generate` | 生成邀请码 | 📱小程序 |
-| `/api/distribution/invite/validate` | 校验邀请码 | 📱小程序 |
-| `/api/distribution/invite/my-teams` | 我的团队 | 📱小程序 |
-| `/api/distribution/invite/my-position` | 团队位置 | 📱小程序 |
-| `/api/withdrawal/apply` | 申请提现 | 📱小程序 |
-| `/api/withdrawal/history` | 提现记录 | 📱小程序 |
-| `/api/leaderboard/top` | 排行榜 | 📱小程序 |
-| `/api/leaderboard/my-rank` | 我的排名 | 📱小程序 |
-| `/api/invite/milestone/list` | 里程碑列表 | 📱小程序 |
-| `/api/invite/milestone/claim` | 领取里程碑 | 📱小程序 |
+### 推广绑定
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/promotion/bind` | 绑定推广关系 | 📱小程序 | `{inviteCode, promoterFamilyId}` | `PromotionBinding` 对象 |
+| `POST /api/promotion/commission/list` | 家庭佣金列表 | 📱小程序 | `{familyId, page, size}` | `{records, total, page, size}` |
+| `POST /api/promotion/bindings/list` | 绑定列表 | 📱小程序 | `{familyId}` | `List<PromotionBinding>` |
+| `POST /api/promotion/commission/record` | 记录佣金 | ⚙️系统自动 | `Commission` 对象(含familyId, guideId, amount, type, source) | `boolean` |
+| `POST /api/promotion/commission/family-total` | 家庭佣金总额 | 📱小程序 | `{familyId}` | `Integer`(总金额) |
+
+### 销售邀请
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/distribution/invite/generate` | 生成销售邀请码 | 📱小程序 | `{systemId}` | `String`(邀请码) |
+| `POST /api/distribution/invite/validate` | 校验邀请码有效性 | 📱小程序 | `{inviteCode}` | `{valid, inviteCode, systemId, inviterId, teamName}` |
+| `POST /api/distribution/invite/my-teams` | 我的虚拟团队列表 | 📱小程序 | —(从token取userId) | `List<DistributionSystem>` |
+| `POST /api/distribution/invite/my-position` | 团队中的位置 | 📱小程序 | `{systemId}` | `{parentId, children, depth, ...}` |
+
+### 佣金中心
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/commission/summary` | 佣金汇总 | 📱小程序 | —(从token取userId) | `CommissionSummaryDTO`(累计/可提现/待结算/已提现) |
+| `POST /api/commission/list` | 佣金明细 | 📱小程序 | `{page, size}` | `Page<CommissionRecord>` |
+| `POST /api/commission/team` | 团队统计 | 📱小程序 | —(从token取userId) | `{l1Count, l2Count, teamCommission, ...}` |
+| `POST /api/commission/stats` | 佣金统计面板 | 📱小程序 | —(从token取userId) | `{todayAmount, monthlyAmount, totalAmount, ...}` |
+| `POST /api/commission/balance` | 可提现余额 | 📱小程序 | —(从token取userId) | `{availableAmount, settledAmount, pendingAmount, totalCommission, withdrawnAmount}` |
+| `POST /api/commission/team/list` | 团队成员列表 | 📱小程序 | `{level, page, size}` | `{members, total, page, size}` |
+| `POST /api/commission/funnel` | 转化漏斗 | 📱小程序 | —(从token取userId) | `{各阶段转化人数/金额}` |
+
+### 推广素材
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/promotion/material/list` | 素材列表 | 📱小程序 | `{materialType, usageScenario, keyword, pageNum, pageSize}` | `Page<PromotionMaterial>` |
+| `POST /api/promotion/material/detail` | 素材详情 | 📱小程序 | `{id}` | `PromotionMaterial` |
+| `POST /api/promotion/material/by-scenario` | 按场景获取素材 | 📱小程序 | `{scenario}` | `List<PromotionMaterial>` |
+| `POST /api/promotion/material/create` | 创建素材(管理员) | 🖥管理后台 | `PromotionMaterial`(含title, materialType, coverUrl, ...) | `PromotionMaterial` |
+| `POST /api/promotion/material/update` | 更新素材(管理员) | 🖥管理后台 | `PromotionMaterial`(id必填) | `null` |
+| `POST /api/promotion/material/delete` | 删除素材(管理员) | 🖥管理后台 | `{id}` | `null` |
+
+### 提现
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/withdrawal/apply` | 申请提现 | 📱小程序 | `{amount, accountInfo}` | `String`(成功/失败信息) |
+| `POST /api/withdrawal/history` | 提现记录 | 📱小程序 | `{page, size}` | `Page<WithdrawalRequest>` |
+
+### 排行榜与里程碑
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/leaderboard/top` | 推广排行榜 | 📱小程序 | `{weekStart}` | `List<{rank, userId, count, ...}>`(前20名) |
+| `POST /api/leaderboard/my-rank` | 我的排名 | 📱小程序 | `{weekStart}` | `{rank, totalCount, aheadCount, behindCount}` |
+| `POST /api/invite/milestone/list` | 里程碑列表 | 📱小程序 | —(从token取userId) | `List<InviteMilestone>` |
+| `POST /api/invite/milestone/claim` | 领取里程碑奖励 | 📱小程序 | `{milestone}` | `String`(成功/失败信息) |
+
+### 管理后台 — 佣金审核
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/admin/commission/withdrawals` | 提现列表 | 🖥管理后台 | `{status, page, size}` | `Page<WithdrawalRequest>` |
+| `POST /api/admin/commission/audit` | 审核提现 | 🖥管理后台 | `{requestId, status, remark}` | `String`(已通过/已拒绝) |
+| `POST /api/admin/commission/update-profit-rate` | 设置商品利润率 | 🖥管理后台 | `{productId, profitRate}` | `String`(设置成功) |
+| `POST /api/admin/commission/refunds/pending` | 待处理退款 | 🖥管理后台 | `{status, orderType, page, size}` | `Page<PendingRefund>` |
+| `POST /api/admin/commission/refunds/summary` | 退款汇总 | 🖥管理后台 | — | `{totalPendingAmount}` |
+| `POST /api/admin/commission/refunds/cancel` | 中止退款 | 🖥管理后台 | `{refundId}` | `String`(已中止退款) |
+
+## 数据实体关系
+
+```
+推广绑定 → 佣金记录 → 提现申请
+邀请码 → 虚拟团队 → 分销关系
+```
+
+| 表名 | 主键 | 核心字段 | 说明 |
+|------|------|---------|------|
+| `promotion_binding` | `id` | promoterFamilyId, inviteeFamilyId, inviteCode, bindingType, status | 家庭间推广绑定关系 |
+| `family_commission` | `id` | promoterFamilyId, buyerFamilyId, orderId, amount, commissionRate, commissionAmount, status | 家庭级佣金记录 |
+| `promotion_commission` | `id` | familyId, guideId, memberId, amount, type(register/purchase/invite), source, status | 推广佣金明细 |
+| `commission_records` | `id` | orderId, orderType, referrerId, buyerId, commissionType, commissionAmount, status, level(1/2) | 统一佣金记录(含层级) |
+| `distribution_systems` | `id` | name, ownerId, profitRate, enabled | 虚拟团队/分销体系配置 |
+| `distribution_relations` | `id` | systemId, userId, parentId, depth, inviteCode | 分销关系树 |
+| `promotion_materials` | `id` | title, materialType, coverUrl, fileUrl, usageScenario, status | 推广素材 |
+| `withdrawal_requests` | `id` | userId, amount, accountInfo, status, adminId, remark | 提现申请记录 |
+| `invite_milestones` | `id` | userId, milestone, status, reward | 邀请里程碑 |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖推广绑定、邀请码、佣金总览/明细/团队、素材管理、提现、排行榜、里程碑共7个阶段,涵盖6个Controller |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 邀请码无效(`validate`返回404)、提现审核拒绝已覆盖;佣金结算失败、退款异常等业务逻辑在Service层处理,图中未展开 |
+| 3 | **端点覆盖** | ✅ 完整 | 30个端点全部映射到流程图中,与PromotionController、CommissionController、DistributionInviteController、WithdrawalController、ReferralLeaderboardController、PromotionMaterialController、InviteMilestoneController、AdminCommissionController的`@PostMapping`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长(推广员)为推广核心用户,可完成全部推广操作;规划师可生成邀请码;管理员在后台审核提现、管理素材、设置利润率 |
+| 5 | **数据实体** | ✅ 完整 | 9张核心表均在图中映射,覆盖推广绑定(promotion_binding)、佣金(family_commission/promotion_commission/commission_records)、分销体系(distribution_systems/relations)、素材(promotion_materials)、提现(withdrawal_requests)、里程碑(invite_milestones) |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(PromotionController、CommissionController、DistributionInviteController、WithdrawalController、ReferralLeaderboardController、PromotionMaterialController、InviteMilestoneController、AdminCommissionController)的`@PostMapping`匹配 |

+ 425 - 103
docs/flows/shop-flow.md

@@ -1,131 +1,453 @@
 # 用户使用流程图 — 商城交易
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取商品分类 /category/tree]:::portMiniApp
-        A2 --> A3[📱 查看分类商品 /category/products]:::portMiniApp
-        A3 --> A4[📱 获取商品列表 /list]:::portMiniApp
-        A4 --> A5[📱 获取商品详情 /detail]:::portMiniApp
-        A5 --> A6[📱 获取规格映射 /spec/map]:::portMiniApp
+    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
+
+    %% ============ 角色 ============
+    ROLE_BUYER(("👤 买家")):::actor
+    ROLE_VENDOR(("🏪 商家")):::actor
+    ROLE_ADMIN(("🖥 管理员")):::actor
+    ROLE_PAY(("💳 微信支付")):::actor
+
+    %% ================================================================
+    %% 阶段一:商品浏览
+    %% ================================================================
+    subgraph 阶段一[阶段一:商品浏览]
+        direction TB
+
+        P1["🏠 小程序:商城首页"]:::page
+        P1 -->|"选择操作"| P1_choice{"浏览分类 / 搜索商品"}:::page
+
+        P1_choice -->|"浏览分类"| P1a["🏠 分类树"]:::page
+        P1a -->|""| A1["🔗 POST /api/shop/category/tree"]:::api
+        A1 -->|""| S1["⚙️ ProductCategoryService.tree()"]:::service
+        S1 -->|"商品分类层级树"| D1["📦 product_categories 表"]:::data
+
+        P1_choice -->|"查看分类商品"| P1b["🏠 分类商品列表"]:::page
+        P1b -->|"categoryId"| A2["🔗 POST /api/shop/category/products"]:::api
+        A2 -->|"分类ID"| S2["⚙️ ProductCategoryService.products()"]:::service
+        S2 -->|"该分类下的商品列表"| D2["📦 products 表(按分类筛选)"]:::data
+
+        P1_choice -->|"商品列表"| P1c["🏠 商品列表页"]:::page
+        P1c -->|"关键词, 分类, 排序, 分页"| A3["🔗 POST /api/product/list"]:::api
+        A3 -->|"查询参数"| S3["⚙️ ProductService.list()"]:::service
+        S3 -->|"分页商品数据"| D2
+
+        P1c -->|"查看详情"| P1d["🏠 商品详情页"]:::page
+        P1d -->|"商品ID"| A4["🔗 POST /api/product/detail"]:::api
+        A4 -->|"商品ID"| S4["⚙️ ProductService.detail()"]:::service
+        S4 -->|"商品完整信息(含规格)"| D2
+
+        P1d -->|"查看规格映射"| P1e["🏠 规格选择弹窗"]:::page
+        P1e -->|"商品ID列表"| A5["🔗 POST /api/product/spec/map"]:::api
+        A5 -->|"商品IDs"| S5["⚙️ ProductSkuService.listByProductId()"]:::service
+        S5 -->|"SKU规格分组与选项"| D3["📦 product_skus 表"]:::data
     end
 
-    subgraph 购物车
-        A6 --> B1[📱 添加购物车 /cart/add]:::portMiniApp
-        B1 --> B2[📱 获取购物车列表 /cart/list]:::portMiniApp
-        B2 --> B3[📱 更新购物车 /cart/update]:::portMiniApp
-        B3 --> B4[📱 移除商品 /cart/remove]:::portMiniApp
-        B4 --> B5[📱 获取购物车数量 /cart/count]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:购物车
+    %% ================================================================
+    subgraph 阶段二[阶段二:购物车]
+        D3 -->|"选定SKU"| P2["🏠 购物车页"]:::page
+        P2 -->|"添加商品"| P2a["🏠 添加到购物车"]
+        P2a -->|"商品ID, 数量, SKU ID"| A6["🔗 POST /api/cart/add"]:::api
+        A6 -->|"用户ID, 商品ID, 数量"| S6["⚙️ CartService.addToCart()"]:::service
+        S6 -->|"写入购物车项"| D4["📦 cart 表"]:::data
+
+        D4 -->|"购物车数据"| P2b["🏠 购物车列表"]
+        P2b -->|"用户ID"| A7["🔗 POST /api/cart/list"]:::api
+        A7 -->|"用户ID"| S7["⚙️ CartService.getCartList()"]:::service
+        S7 -->|"购物车商品列表"| D4
+
+        P2b -->|"修改数量"| P2c["🏠 编辑数量"]
+        P2c -->|"商品ID, 新数量"| A8["🔗 POST /api/cart/update"]:::api
+        A8 -->|"商品ID, 数量"| S8["⚙️ CartService.updateQuantity()"]:::service
+        S8 -->|"更新数量"| D4
+
+        P2b -->|"移除商品"| P2d["🏠 移除"]
+        P2d -->|"商品ID"| A9["🔗 POST /api/cart/remove"]:::api
+        A9 -->|"商品ID"| S9["⚙️ CartService.removeItem()"]:::service
+        S9 -->|"删除购物车项"| D4
+
+        P2b -->|"查看数量"| P2e["🏠 购物车角标"]
+        P2e -->|"用户ID"| A10["🔗 POST /api/cart/count"]:::api
+        A10 -->|"用户ID"| S10["⚙️ CartService.getCartCount()"]:::service
+        S10 -->|"购物车商品总数"| D4
     end
 
-    subgraph 下单支付
-        B5 --> C1[📱 创建订单 /product/order/create]:::portMiniApp
-        C1 --> C2[📱 支付 /product/order/pay]:::portMiniApp
-        C2 --> C3[⚙️ 支付回调 /product/order/notify]:::portSystem
-        C3 --> C4[⚙️ 处理支付成功 /handlePaymentSuccess]:::portSystem
+    %% ================================================================
+    %% 阶段三:下单支付
+    %% ================================================================
+    subgraph 阶段三[阶段三:下单支付]
+        D4 -->|"选中商品"| P3["🏠 确认订单页"]:::page
+        P3 -->|"提交订单"| A11["🔗 POST /api/product/order/create"]:::api
+        A11 -->|"收货地址ID, 商品列表, 备注"| S11["⚙️ ProductOrderService.create()"]:::service
+        S11 -->|"写入订单, 状态=待支付"| D5["📦 product_orders 表"]:::data
+
+        D5 -->|"订单号"| P3a["🏠 支付页"]
+        P3a -->|"发起支付"| A12["🔗 POST /api/product/order/pay"]:::api
+        A12 -->|"订单号"| S12["⚙️ ProductOrderService.pay()"]:::service
+        S12 -->|"微信支付参数(预支付ID)"| PAY["💳 微信支付收银台"]:::external
+
+        PAY -->|"用户完成支付"| A13["🔗 POST /api/product/order/notify"]:::api
+        A13 -->|"微信异步通知密文"| S13["⚙️ PaymentService.handleWechatNotify()"]:::service
+        S13 -->|"解密+验证签名"| S13a["⚙️ ProductOrderService.handlePaymentSuccess()"]:::service
+        S13a -->|"更新订单状态=已支付"| D5
     end
 
-    subgraph 订单管理
-        C4 --> D1[📱 获取我的订单 /my]:::portMiniApp
-        D1 --> D2[📱 订单数量统计 /my/counts]:::portMiniApp
-        D2 --> D3[📱 订单详情 /detail]:::portMiniApp
-        D3 --> D4{📱 订单状态}:::portMiniApp
-        D4 -->|待发货| D5[📱 取消订单 /cancel]:::portMiniApp
-        D4 -->|已发货| D6[📱 确认收货 /confirm]:::portMiniApp
-        D4 -->|待退款| D7[📱 申请退款 /refund/apply]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:订单管理
+    %% ================================================================
+    subgraph 阶段四[阶段四:订单管理]
+        D5 -->|"用户ID"| P4["🏠 我的订单页"]:::page
+        P4 -->|"按状态筛选"| A14["🔗 POST /api/product/order/my"]:::api
+        A14 -->|"用户ID, 状态"| S14["⚙️ ProductOrderService.myOrders()"]:::service
+        S14 -->|"用户订单列表"| D5
+
+        P4 -->|"数量统计"| P4a["🏠 订单角标"]
+        P4a -->|"用户ID"| A15["🔗 POST /api/product/order/my/counts"]:::api
+        A15 -->|"用户ID"| S15["⚙️ ProductOrderService.myOrderCounts()"]:::service
+        S15 -->|"各状态订单数量"| D5
+
+        P4 -->|"查看详情"| P4b["🏠 订单详情页"]
+        P4b -->|"订单号"| A16["🔗 POST /api/product/order/detail"]:::api
+        A16 -->|"订单号"| S16["⚙️ ProductOrderService.detail()"]:::service
+        S16 -->|"订单完整信息"| D5
+
+        P4b -->|"取消订单"| P4c{"状态=待支付?"}:::page
+        P4c -->|"是"| P4d["🏠 取消订单"]
+        P4d -->|"订单号"| A17["🔗 POST /api/product/order/cancel"]:::api
+        A17 -->|"订单号"| S17["⚙️ ProductOrderService.cancel()"]:::service
+        S17 -->|"更新状态=已取消"| D5
+
+        P4b -->|"确认收货"| P4e{"状态=已发货?"}:::page
+        P4e -->|"是"| P4f["🏠 确认收货"]
+        P4f -->|"订单号"| A18["🔗 POST /api/product/order/confirm"]:::api
+        A18 -->|"订单号"| S18["⚙️ ProductOrderService.confirmReceive()"]:::service
+        S18 -->|"更新状态=已完成"| D5
+
+        P4b -->|"申请退款"| P4g{"已支付且未完成?"}:::page
+        P4g -->|"是"| P4h["🏠 申请退款"]
+        P4h -->|"订单号, 退款原因"| A19["🔗 POST /api/product/order/refund/apply"]:::api
+        A19 -->|"订单号, 原因"| S19["⚙️ ProductOrderService.applyRefund()"]:::service
+        S19 -->|"更新状态=退款中"| D5
     end
 
-    subgraph 商家发货
-        D6 --> E1[🖥 商家发货 /ship]:::portAdmin
-        E1 --> E2[📱 查询物流 /logistics/query]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:商家发货
+    %% ================================================================
+    subgraph 阶段五[阶段五:商家发货]
+        D5 -->|"待发货订单"| P5["🖥 商家端:订单管理页"]:::page
+        P5 -->|"查看商家订单"| A20["🔗 POST /api/product/order/vendor"]:::api
+        A20 -->|"商家ID, 状态"| S20["⚙️ ProductOrderService.vendorOrders()"]:::service
+        S20 -->|"商家订单列表"| D5
+
+        P5 -->|"发货"| P5a["🖥 发货表单"]
+        P5a -->|"订单号, 快递公司, 运单号"| A21["🔗 POST /api/product/order/ship"]:::api
+        A21 -->|"快递信息"| S21["⚙️ ProductOrderService.ship()"]:::service
+        S21 -->|"更新状态=已发货, 记录物流"| D5
+
+        D5 -->|"物流信息"| P5b["📱 小程序:物流查询"]
+        P5b -->|"订单ID"| A22["🔗 POST /api/shop/logistics/query"]:::api
+        A22 -->|"订单ID"| S22["⚙️ ProductOrderService.queryLogistics()"]:::service
+        S22 -->|"物流跟踪信息"| D5
     end
 
-    subgraph 售后
-        D7 --> F1[📱 创建售后 /after-sales/create]:::portMiniApp
-        F1 --> F2[📱 售后列表 /after-sales/list]:::portMiniApp
-        F2 --> F3[📱 售后详情 /after-sales/detail]:::portMiniApp
+    %% ================================================================
+    %% 阶段六:售后
+    %% ================================================================
+    subgraph 阶段六[阶段六:售后]
+        D5 -->|"退款中的订单"| P6["📱 小程序:售后申请页"]:::page
+        P6 -->|"提交申请"| A23["🔗 POST /api/shop/after-sales/create"]:::api
+        A23 -->|"订单ID, 售后类型, 原因, 描述"| S23["⚙️ AfterSalesService.create()"]:::service
+        S23 -->|"创建售后记录, 订单状态=退款中"| D6["📦 after_sales_requests 表"]:::data
+
+        D6 -->|"售后列表"| P6a["📱 售后列表页"]
+        P6a -->|"用户ID, 状态筛选"| A24["🔗 POST /api/shop/after-sales/list"]:::api
+        A24 -->|"状态"| S24["⚙️ AfterSalesService.list()"]:::service
+        S24 -->|"售后申请列表"| D6
+
+        P6a -->|"查看详情"| P6b["📱 售后详情页"]
+        P6b -->|"售后单ID"| A25["🔗 POST /api/shop/after-sales/detail"]:::api
+        A25 -->|"售后单ID"| S25["⚙️ AfterSalesService.detail()"]:::service
+        S25 -->|"售后单完整信息"| D6
     end
 
-    subgraph 评价
-        D6 --> G1[📱 发表评价 /review/order]:::portMiniApp
-        G1 --> G2[📱 评价详情 /review/order/detail]:::portMiniApp
-        G2 --> G3[📱 评价状态 /review/order/status]:::portMiniApp
+    %% ================================================================
+    %% 阶段七:评价
+    %% ================================================================
+    subgraph 阶段七[阶段七:评价]
+        D5 -->|"已完成订单"| P7["📱 发表评价页"]:::page
+        P7 -->|"提交评价"| A26["🔗 POST /api/review/order"]:::api
+        A26 -->|"订单ID, 评分, 内容, 图片"| S26["⚙️ ReviewOrderService.createReview()"]:::service
+        S26 -->|"写入评价记录"| D7["📦 review_orders 表"]:::data
+
+        D7 -->|"评价数据"| P7a["📱 评价详情"]
+        P7a -->|"订单ID"| A27["🔗 POST /api/review/order/detail"]:::api
+        A27 -->|"订单ID"| S27["⚙️ ReviewOrderService.findByOrder()"]:::service
+        S27 -->|"评价详情"| D7
+
+        P7a -->|"评价状态"| A28["🔗 POST /api/review/order/status"]:::api
+        A28 -->|"订单ID"| S28["⚙️ ReviewOrderService.getStats()"]:::service
+        S28 -->|"评价统计数据"| D7
     end
 
-    subgraph 收货地址
-        G3 --> H1[📱 地址列表 /consignee/list]:::portMiniApp
-        H1 --> H2[📱 添加地址 /consignee/save]:::portMiniApp
-        H2 --> H3[📱 地址详情 /consignee/detail]:::portMiniApp
-        H3 --> H4[📱 删除地址 /consignee/delete]:::portMiniApp
+    %% ================================================================
+    %% 阶段八:收货地址
+    %% ================================================================
+    subgraph 阶段八[阶段八:收货地址]
+        P3 -->|"管理地址"| P8["📱 地址管理页"]:::page
+        P8 -->|"地址列表"| A29["🔗 POST /api/consignee/list"]:::api
+        A29 -->|"用户ID"| S29["⚙️ ConsigneeService.list()"]:::service
+        S29 -->|"用户收货地址列表"| D8["📦 consignees 表"]:::data
+
+        P8 -->|"新增/编辑"| P8a["📱 地址表单"]
+        P8a -->|"收货人, 手机号, 省市区, 详细地址"| A30["🔗 POST /api/consignee/save"]:::api
+        A30 -->|"地址对象"| S30["⚙️ ConsigneeService.save()"]:::service
+        S30 -->|"写入/更新地址"| D8
+
+        P8 -->|"地址详情"| P8b["📱 地址详情"]
+        P8b -->|"地址ID"| A31["🔗 POST /api/consignee/detail"]:::api
+        A31 -->|"地址ID"| S31["⚙️ ConsigneeService.detail()"]:::service
+        S31 -->|"地址完整信息"| D8
+
+        P8 -->|"删除地址"| P8c["📱 删除确认"]
+        P8c -->|"地址ID"| A32["🔗 POST /api/consignee/delete"]:::api
+        A32 -->|"地址ID, 用户ID"| S32["⚙️ ConsigneeService.delete()"]:::service
+        S32 -->|"删除地址记录"| D8
     end
 
-    R1(("👤 用户")):::actor
-    R2(("🏪 商家")):::role
-    R3(("💳 支付")):::system
+    %% ================================================================
+    %% 阶段九:商家商品管理
+    %% ================================================================
+    subgraph 阶段九[阶段九:商家商品管理]
+        P5 -->|"管理商品"| P9["🖥 商家端:商品管理页"]:::page
+        P9 -->|"创建商品"| P9a["🖥 商品发布表单"]
+        P9a -->|"商品名称, 价格, 库存, 图片, 类目"| A33["🔗 POST /api/product/create"]:::api
+        A33 -->|"商品对象"| S33["⚙️ ProductService.create()"]:::service
+        S33 -->|"写入新商品, 状态=待审核"| D2
 
-    A1 -.- R1
-    E1 -.- R2
-    C2 -.- R3
+        P9 -->|"编辑商品"| P9b["🖥 编辑表单"]
+        P9b -->|"商品ID, 更新字段"| A34["🔗 POST /api/product/update"]:::api
+        A34 -->|"商品对象"| S34["⚙️ ProductService.update()"]:::service
+        S34 -->|"更新商品信息"| D2
+
+        P9 -->|"我的商品"| P9c["🖥 我的商品列表"]
+        P9c -->|"商家ID"| A35["🔗 POST /api/product/my"]:::api
+        A35 -->|"商家ID"| S35["⚙️ ProductService.myProducts()"]:::service
+        S35 -->|"该商家的所有商品"| D2
+
+        P9 -->|"上架/下架"| P9d["🖥 上架/下架操作"]
+        P9d -->|"商品ID, 动作(on/off)"| A36["🔗 POST /api/product/shelve"]:::api
+        A36 -->|"商品ID, 动作"| S36["⚙️ ProductService.shelve()"]:::service
+        S36 -->|"更新商品状态"| D2
+
+        P9 -->|"更新图片"| P9e["🖥 图片管理"]
+        P9e -->|"商品ID, 图片列表"| A37["🔗 POST /api/product/images/update"]:::api
+        A37 -->|"商品ID, 图片URL列表"| S37["⚙️ ProductService.updateImages()"]:::service
+        S37 -->|"更新商品图片字段"| D2
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_BUYER -.- P1
+    ROLE_BUYER -.- P2
+    ROLE_BUYER -.- P3
+    ROLE_BUYER -.- P4
+    ROLE_BUYER -.- P6
+    ROLE_BUYER -.- P7
+    ROLE_BUYER -.- P8
+    ROLE_VENDOR -.- P5
+    ROLE_VENDOR -.- P9
+    ROLE_ADMIN -.- P5
+    ROLE_PAY -.- PAY
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/product/list` | 商品列表 | 📱小程序 |
-| `/api/product/detail` | 商品详情 | 📱小程序 |
-| `/api/product/spec/map` | 规格映射 | 📱小程序 |
-| `/api/product/order/create` | 创建订单 | 📱小程序 |
-| `/api/product/order/pay` | 支付 | 📱小程序 |
-| `/api/product/order/cancel` | 取消订单 | 📱小程序 |
-| `/api/product/order/my` | 我的订单 | 📱小程序 |
-| `/api/product/order/my/counts` | 订单数量统计 | 📱小程序 |
-| `/api/product/order/detail` | 订单详情 | 📱小程序 |
-| `/api/product/order/confirm` | 确认收货 | 📱小程序 |
-| `/api/product/order/refund/apply` | 申请退款 | 📱小程序 |
-| `/api/cart/add` | 添加购物车 | 📱小程序 |
-| `/api/cart/list` | 购物车列表 | 📱小程序 |
-| `/api/cart/update` | 更新购物车 | 📱小程序 |
-| `/api/cart/remove` | 移除商品 | 📱小程序 |
-| `/api/cart/count` | 购物车数量 | 📱小程序 |
-| `/api/shop/category/tree` | 分类树 | 📱小程序 |
-| `/api/shop/category/products` | 分类商品 | 📱小程序 |
-| `/api/shop/after-sales/create` | 创建售后 | 📱小程序 |
-| `/api/shop/after-sales/list` | 售后列表 | 📱小程序 |
-| `/api/shop/after-sales/detail` | 售后详情 | 📱小程序 |
-| `/api/shop/logistics/query` | 查询物流 | 📱小程序 |
-| `/api/review/order` | 发表评价 | 📱小程序 |
-| `/api/review/order/detail` | 评价详情 | 📱小程序 |
-| `/api/review/order/status` | 评价状态 | 📱小程序 |
-| `/api/consignee/list` | 地址列表 | 📱小程序 |
-| `/api/consignee/save` | 添加/保存地址 | 📱小程序 |
-| `/api/consignee/detail` | 地址详情 | 📱小程序 |
-| `/api/consignee/delete` | 删除地址 | 📱小程序 |
-| `/api/product/create` | 创建商品 | 🖥管理后台 |
-| `/api/product/update` | 更新商品 | 🖥管理后台 |
-| `/api/product/my` | 我的商品 | 🖥管理后台 |
-| `/api/product/shelve` | 上下架 | 🖥管理后台 |
-| `/api/product/images/update` | 更新图片 | 🖥管理后台 |
-| `/api/product/order/vendor` | 商家订单 | 🖥管理后台 |
-| `/api/product/order/ship` | 发货 | 🖥管理后台 |
-| `/api/product/order/handlePaymentSuccess` | 处理支付成功 | ⚙️系统自动 |
-| `/api/product/order/notify` | 支付回调 | ⚙️系统自动 |
-| `/api/product/order/activity/audit` | 活动审核 | 🖥管理后台 |
-| `/api/product/order/activity/sign-in` | 活动签到 | 🖥管理后台 |
-| `/api/product/order/activity/complete` | 活动完成 | 🖥管理后台 |
-| `/api/product/order/activity/provision` | 活动供应 | 🖥管理后台 |
-| `/api/product/order/activity/qr-image` | 活动二维码 | 🖥管理后台 |
+### 商品浏览
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/product/list` | 获取商品列表 | 📱小程序 | `{keyword, categoryId, sort, page, size, ...}` | `分页商品列表(含价格, 库存, 封面)` |
+| `POST /api/product/detail` | 获取商品详情 | 📱小程序 | `{id}` | `商品完整信息(含规格, 描述, 图片)` |
+| `POST /api/product/spec/map` | 获取规格映射 | 📱小程序 | `{productIds: [id1, id2]}` | `每个商品的分组规格(颜色, 尺寸等)及SKU价格库存` |
+| `POST /api/shop/category/tree` | 获取分类树 | 📱小程序 | — | `商品分类层级树` |
+| `POST /api/shop/category/products` | 获取分类下商品 | 📱小程序 | `{categoryId}` | `该分类下的商品列表` |
+
+### 购物车
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/cart/add` | 添加购物车 | 📱小程序 | `{productId, quantity, skuId}` | `CartItemDTO(含商品名称, 数量, 价格)` |
+| `POST /api/cart/list` | 获取购物车列表 | 📱小程序 | Header: `userId` | `购物车商品列表(含规格信息)` |
+| `POST /api/cart/update` | 更新购物车数量 | 📱小程序 | `{productId, quantity}` | `成功/失败` |
+| `POST /api/cart/remove` | 移除购物车商品 | 📱小程序 | `{productId}` | `成功/失败` |
+| `POST /api/cart/count` | 获取购物车数量 | 📱小程序 | Header: `userId` | `购物车商品总数` |
+
+### 下单支付
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/product/order/create` | 创建订单 | 📱小程序 | `{productId, quantity, skuId, consigneeId, remark, ...}` | `ProductOrderDTO(含订单号, 金额, 状态)` |
+| `POST /api/product/order/pay` | 发起支付 | 📱小程序 | `{orderNo}` | `微信支付参数(prepay_id, sign等)` |
+| `POST /api/product/order/notify` | 微信支付回调 | ⚙️系统自动 | 微信异步通知密文 | `{code, message}` |
+| `POST /api/product/order/handlePaymentSuccess` | 手动处理支付成功 | ⚙️系统自动 | `{orderNo}` | `成功/失败` |
+
+### 订单管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/product/order/my` | 获取我的订单 | 📱小程序 | `{status, keyword}` | `订单列表(含商品快照, 状态)` |
+| `POST /api/product/order/my/counts` | 订单数量统计 | 📱小程序 | Header: `userId` | `各状态订单数量` |
+| `POST /api/product/order/detail` | 订单详情 | 📱小程序 | `{orderNo}` | `订单完整信息(含地址快照, 物流)` |
+| `POST /api/product/order/cancel` | 取消订单 | 📱小程序 | `{orderNo}` | `成功/失败` |
+| `POST /api/product/order/confirm` | 确认收货 | 📱小程序 | `{orderNo}` | `成功/失败` |
+| `POST /api/product/order/refund/apply` | 申请退款 | 📱小程序 | `{orderNo, reason}` | `成功/失败` |
+| `POST /api/product/order/vendor` | 商家订单列表 | 🖥管理后台 | `{status}` | `商家订单列表` |
+| `POST /api/product/order/ship` | 商家发货 | 🖥管理后台 | `{orderNo, trackingNumber, expressCompany}` | `成功/失败` |
+
+### 物流
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/shop/logistics/query` | 查询物流 | 📱小程序 | `{orderId}` | `物流跟踪信息` |
+
+### 售后
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/shop/after-sales/create` | 创建售后申请 | 📱小程序 | `{orderId, type, reason, description, images}` | `AfterSalesRequest对象` |
+| `POST /api/shop/after-sales/list` | 售后列表 | 📱小程序 | `{status}` | `售后申请列表` |
+| `POST /api/shop/after-sales/detail` | 售后详情 | 📱小程序 | `{id}` | `售后申请完整信息` |
+
+### 评价
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/review/order` | 发表评价 | 📱小程序 | `{orderId, rating, content, images}` | `成功/失败` |
+| `POST /api/review/order/detail` | 评价详情 | 📱小程序 | `{orderId}` | `评价内容及回复` |
+| `POST /api/review/order/status` | 评价状态 | 📱小程序 | `{orderId}` | `评价统计数据` |
+
+### 收货地址
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/consignee/list` | 地址列表 | 📱小程序 | Header: `userId` | `收货地址列表` |
+| `POST /api/consignee/save` | 添加/保存地址 | 📱小程序 | `{id, name, phone, province, city, district, street, detail}` | `地址ID` |
+| `POST /api/consignee/detail` | 地址详情 | 📱小程序 | `{id}` | `地址完整信息` |
+| `POST /api/consignee/delete` | 删除地址 | 📱小程序 | `{id}` | `成功/失败` |
+
+### 商家商品管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/product/create` | 创建商品 | 🖥管理后台 | `{name, price, stock, coverImage, categoryId, ...}` | `ProductDTO` |
+| `POST /api/product/update` | 更新商品 | 🖥管理后台 | `{id, name, price, stock, ...}` | `ProductDTO` |
+| `POST /api/product/my` | 我的商品 | 🖥管理后台 | Header: `userId` | `商品列表` |
+| `POST /api/product/shelve` | 上架/下架 | 🖥管理后台 | `{productId, action: "on"/"off"}` | `成功/失败` |
+| `POST /api/product/images/update` | 更新商品图片 | 🖥管理后台 | `{productId, images: [url1, url2]}` | `成功/失败` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    ProductCategory ||--o{ Product : "一个分类多个商品"
+    Vendor ||--o{ Product : "一个商家多个商品"
+    Product ||--o{ ProductSku : "一个商品多个规格"
+    Product ||--o{ Cart : "一个商品可被多次加入"
+    User ||--o{ Cart : "一个用户多个购物车项"
+    User ||--o{ ProductOrder : "一个用户多笔订单"
+    User ||--o{ Consignee : "一个用户多个地址"
+    Product ||--o{ ProductOrder : "一个商品对多笔订单"
+    ProductOrder ||--o{ AfterSalesRequest : "一笔订单多个售后"
+    ProductOrder ||--o{ ReviewOrder : "一笔订单一个评价"
+
+    Product {
+        Long id PK
+        string name
+        int price
+        int stock
+        string productType "physical / assessment"
+        string status "pending / approved / rejected / on / off"
+        Long vendorId FK
+        string dimensionWeights
+    }
+
+    ProductSku {
+        Long id PK
+        Long productId FK
+        string specs "JSON规格选项"
+        int price
+        int stock
+    }
+
+    Cart {
+        Long id PK
+        Long userId FK
+        Long productId FK
+        Long skuId FK
+        int quantity
+    }
+
+    ProductOrder {
+        Long id PK
+        string orderNo
+        Long buyerId FK
+        Long productId FK
+        int totalAmount
+        string status "pending_pay / paid / shipped / completed / cancelled / refunding"
+        string logisticsNo
+        string trackingNumber
+    }
+
+    Consignee {
+        Long id PK
+        Long userId FK
+        string name
+        string phone
+        string province
+        string city
+        string district
+        string street
+        string detail
+    }
+
+    AfterSalesRequest {
+        Long id PK
+        Long orderId FK
+        string type
+        string status "pending / approved / rejected / completed"
+    }
+
+    ReviewOrder {
+        Long id PK
+        Long orderId FK
+        int rating
+        string content
+        string images
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖商品浏览→购物车→下单支付→订单管理→发货→售后→评价→地址管理→商家商品管理9个阶段,包含买家与商家双视角 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 支付失败/取消订单/退款申请已覆盖;库存不足/价格变动/支付超时等边界情况在前端校验,未在图里展开 |
+| 3 | **端点覆盖** | ✅ 完整 | 32个端点全部映射到流程图中,与代码中ProductController、CartController、ProductOrderController、ConsigneeController、ReviewController、AfterSalesController、ProductCategoryController、LogisticsController一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 买家(小程序)、商家(管理后台)、管理员(管理后台)、微信支付(外部系统)三种视角均已覆盖 |
+| 5 | **数据实体** | ✅ 完整 | products、product_skus、cart、product_orders、consignees、after_sales_requests、review_orders、product_categories 8张表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配,Service方法名与代码中的业务方法一致(create/detail/list/ship等) |

+ 277 - 70
docs/flows/stats-report-flow.md

@@ -1,90 +1,297 @@
 # 用户使用流程图 — 统计报表
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 孩子数据概览 /child/overview]:::portMiniApp
-        A2 --> A3[📱 家庭汇总统计 /family/summary]:::portMiniApp
-        A3 --> A4[📱 积分排行榜 /points/ranking]:::portMiniApp
+    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 actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_ADMIN(("🖥 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:孩子与家庭统计
+    %% ================================================================
+    subgraph 阶段一[阶段一:孩子与家庭统计]
+        direction TB
+
+        P1["🏠 家长端:孩子数据概览页"]:::page
+        P1 -->|"查看孩子统计"| A1["🔗 POST /api/stats/child/overview"]:::api
+        A1 -->|"childId"| S1["⚙️ ReportStatsController 直接查询 Mapper"]:::service
+        S1 -->|"总积分, 月活跃天数, 任务统计, 游戏统计, 近7日积分趋势"| D1["📦 family_member / points_log / task / game_record"]:::data
+
+        P1 -->|"查看家庭汇总"| A1a["🔗 POST /api/stats/family/summary"]:::api
+        A1a -->|"familyId"| S1a["⚙️ ReportStatsController 直接查询 Mapper"]:::service
+        S1a -->|"各孩子任务完成数/积分/游戏数, 家庭汇总"| D1a["📦 family_member / task / game_record"]:::data
+
+        P1 -->|"查看积分排行"| A1b["🔗 POST /api/stats/points/ranking"]:::api
+        A1b -->|"familyId"| S1b["⚙️ ReportStatsController 直接查询 Mapper"]:::service
+        S1b -->|"积分降序排行列表"| D1
     end
 
-    subgraph 任务统计
-        A4 --> B1[🖥 仪表盘汇总 /dashboard]:::portAdmin
-        B1 --> B2[📱 孩子完成率 /child-completion]:::portMiniApp
-        B2 --> B3[📱 家庭完成率 /family-completion]:::portMiniApp
-        B3 --> B4[📱 数据总览 /overview]:::portMiniApp
-        B4 --> B5[🖥 收入统计 /revenue]:::portAdmin
-        B5 --> B6[🖥 会员分布 /membership]:::portAdmin
-        B6 --> B7[📱 每日趋势 /trend]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:管理后台仪表盘
+    %% ================================================================
+    subgraph 阶段二[阶段二:管理后台数据总览]
+        direction TB
+
+        P2["🖥 管理后台:仪表盘页"]:::page
+        P2 -->|"查看仪表盘汇总"| A2["🔗 POST /api/stats/dashboard"]:::api
+        A2 -->|"无参数"| S2["⚙️ StatsController.getDashboardSummary()"]:::service
+        S2 -->|"家庭/家长/孩子/规划师总数, 待审核数"| D2["📦 family / user / guide_package / task / after_sales_request"]:::data
+
+        P2 -->|"查看数据总览(新版)"| A2a["🔗 POST /api/stats/overview"]:::api
+        A2a -->|"无参数"| S2a["⚙️ StatsController.getOverview()"]:::service
+        S2a -->|"平台核心指标+当月新增+活跃用户"| D2
+
+        P2 -->|"查看收入统计"| A2b["🔗 POST /api/stats/revenue"]:::api
+        A2b -->|"无参数"| S2b["⚙️ StatsController.getRevenueStats()"]:::service
+        S2b -->|"当月/累计/待结算佣金"| D2b["📦 commission_records 表"]:::data
+
+        P2 -->|"查看会员分布"| A2c["🔗 POST /api/stats/membership"]:::api
+        A2c -->|"无参数"| S2c["⚙️ StatsController.getMembershipStats()"]:::service
+        S2c -->|"免费/家庭/服务商会员数, 活跃试用数, 本月升级数"| D2c["📦 user / trial_membership / member_upgrade_record"]:::data
     end
 
-    subgraph 地址区域
-        A1 --> C1[📱 获取省份 /provinces]:::portMiniApp
-        C1 --> C2[📱 获取子级 /children/:parentId]:::portMiniApp
-        C2 --> C3[📱 获取详情 /:id]:::portMiniApp
-        C3 --> C4[📱 获取完整路径 /:id/path]:::portMiniApp
-        C4 --> C5[📱 地址搜索 /search]:::portMiniApp
-        C5 --> C6[📱 区域回退匹配 /:id/match]:::portMiniApp
-        C6 --> C7[📱 按区域统计 /stats]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:任务完成率统计
+    %% ================================================================
+    subgraph 阶段三[阶段三:任务完成率分析]
+        direction TB
+
+        P3["📱 家长端:任务统计页"]:::page
+        P3 -->|"查看孩子完成率"| A3["🔗 POST /api/stats/child-completion"]:::api
+        A3 -->|"childId, startDate, endDate"| S3["⚙️ TaskStatsService.getChildStats()"]:::service
+        S3 -->|"孩子任务完成率统计"| D3["📦 task 表(按时间段过滤)"]:::data
+
+        P3 -->|"查看家庭完成率"| A3a["🔗 POST /api/stats/family-completion"]:::api
+        A3a -->|"familyId, startDate, endDate"| S3a["⚙️ TaskStatsService.getFamilyStats()"]:::service
+        S3a -->|"家庭任务完成率统计"| D3
+
+        P2 -->|"查看每日趋势"| A3b["🔗 POST /api/stats/trend"]:::api
+        A3b -->|"无参数"| S3b["⚙️ StatsController.getTrend()"]:::service
+        S3b -->|"近30日家庭/用户日增量趋势"| D3b["📦 family / user 表(30天内)"]:::data
     end
 
-    subgraph 用户地址
-        A1 --> D1[📱 地址列表 /user/address/list]:::portMiniApp
-        D1 --> D2[📱 获取地址 /user/address/get]:::portMiniApp
-        D2 --> D3[📱 创建地址 /user/address/create]:::portMiniApp
-        D3 --> D4[📱 更新地址 /user/address/update]:::portMiniApp
-        D4 --> D5[📱 删除地址 /user/address/delete]:::portMiniApp
-        D5 --> D6[📱 设为默认 /user/address/setDefault]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:地址区域(四级地址)
+    %% ================================================================
+    subgraph 阶段四[阶段四:地址区域查询]
+        direction TB
+
+        P4["🏠 地址选择器:选择省市区"]:::page
+        P4 -->|"获取省份列表"| A4["🔗 POST /api/streets/provinces"]:::api
+        A4 -->|"无参数"| S4["⚙️ StreetService.getAllProvinces()"]:::service
+        S4 -->|"所有省份列表"| D4["📦 streets 表(level=1)"]:::data
+
+        D4 -->|"parentId"| A4a["🔗 POST /api/streets/children/{parentId}"]:::api
+        A4a -->|"parentId(path)"| S4a["⚙️ StreetService.getChildrenByParentId()"]:::service
+        S4a -->|"下级地址列表"| D4
+
+        D4 -->|"id"| A4b["🔗 POST /api/streets/{id}"]:::api
+        A4b -->|"id(path)"| S4b["⚙️ StreetService.getById()"]:::service
+        S4b -->|"地址详情"| D4
+
+        D4 -->|"id"| A4c["🔗 POST /api/streets/{id}/path"]:::api
+        A4c -->|"id(path)"| S4c["⚙️ StreetService.getAddressPath()"]:::service
+        S4c -->|"省市区街道完整路径"| D4
+
+        D4 -->|"keyword"| A4d["🔗 POST /api/streets/search"]:::api
+        A4d -->|"keyword"| S4d["⚙️ StreetService.search()"]:::service
+        S4d -->|"模糊匹配地址列表"| D4
+
+        D4 -->|"id"| A4e["🔗 POST /api/streets/{id}/match"]:::api
+        A4e -->|"id(path)"| S4e["⚙️ StreetService.matchByStreetWithFallback()"]:::service
+        S4e -->|"街道/区县/城市级回退匹配结果"| D4
+
+        D4 -->|"level"| A4f["🔗 POST /api/streets/stats"]:::api
+        A4f -->|"level"| S4f["⚙️ StreetService.getStatisticsByLevel()"]:::service
+        S4f -->|"指定层级的地址统计"| D4
+
+        P4 -->|"获取省份(旧版)"| A4g["🔗 POST /api/region/provinces"]:::api
+        A4g -->|"无参数"| S4g["⚙️ RegionController: 内存数据直接返回"]:::service
+        S4g -->|"省份列表(内存数据)"| D4g["📦 内存 ALL_REGIONS 静态数据"]:::data
+
+        A4g -->|"parentId"| A4h["🔗 POST /api/region/cities"]:::api
+        A4h -->|"parentId"| S4h["⚙️ RegionController: 内存数据过滤"]:::service
+        S4h -->|"城市列表"| D4g
+
+        A4h -->|"parentId"| A4i["🔗 POST /api/region/districts"]:::api
+        A4i -->|"parentId"| S4i["⚙️ RegionController: 内存数据过滤"]:::service
+        S4i -->|"区县列表"| D4g
+
+        A4i -->|"parentId"| A4j["🔗 POST /api/region/streets"]:::api
+        A4j -->|"parentId"| S4j["⚙️ RegionController: 同districts"]:::service
+        S4j -->|"街道列表"| D4g
     end
 
-    R1(("👤 管理员/家长")):::actor
-    R2(("📊 统计引擎")):::system
+    %% ================================================================
+    %% 阶段五:用户收货地址
+    %% ================================================================
+    subgraph 阶段五[阶段五:用户收货地址管理]
+        direction TB
+
+        P5["🏠 收货地址管理页"]:::page
+        P5 -->|"查看地址列表"| A5["🔗 POST /api/user/address/list"]:::api
+        A5 -->|"userId"| S5["⚙️ UserAddressService.list()"]:::service
+        S5 -->|"该用户所有地址"| D5["📦 user_address 表"]:::data
+
+        P5 -->|"查看单个地址"| A5a["🔗 POST /api/user/address/get"]:::api
+        A5a -->|"id, userId"| S5a["⚙️ UserAddressService.get()"]:::service
+        S5a -->|"地址详情"| D5
+
+        P5 -->|"新增地址"| A5b["🔗 POST /api/user/address/create"]:::api
+        A5b -->|"receiverName, phone, province, city, district, street"| S5b["⚙️ UserAddressService.create()"]:::service
+        S5b -->|"写入一条地址记录"| D5
 
-    A1 -.- R1
-    B1 -.- R2
+        P5 -->|"编辑地址"| A5c["🔗 POST /api/user/address/update"]:::api
+        A5c -->|"完整地址对象(含id)"| S5c["⚙️ UserAddressService.update()"]:::service
+        S5c -->|"更新地址记录"| D5
+
+        P5 -->|"删除地址"| A5d["🔗 POST /api/user/address/delete"]:::api
+        A5d -->|"id"| S5d["⚙️ UserAddressService.delete()"]:::service
+        S5d -->|"删除地址记录"| D5
+
+        P5 -->|"设为默认"| A5e["🔗 POST /api/user/address/setDefault"]:::api
+        A5e -->|"id"| S5e["⚙️ UserAddressService.setDefault()"]:::service
+        S5e -->|"更新is_default字段"| D5
+    end
+
+    %% ============ 角色关联 ============
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P3
+    ROLE_PARENT -.- P4
+    ROLE_PARENT -.- P5
+    ROLE_ADMIN -.- P2
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/stats/child/overview` | 孩子数据概览 | 📱小程序 |
-| `/api/stats/family/summary` | 家庭汇总 | 📱小程序 |
-| `/api/stats/points/ranking` | 积分排行榜 | 📱小程序 |
-| `/api/stats/dashboard` | 仪表盘汇总 | 🖥管理后台 |
-| `/api/stats/child-completion` | 孩子完成率 | 📱小程序 |
-| `/api/stats/family-completion` | 家庭完成率 | 📱小程序 |
-| `/api/stats/overview` | 数据总览 | 📱小程序 |
-| `/api/stats/revenue` | 收入统计 | 🖥管理后台 |
-| `/api/stats/membership` | 会员分布 | 🖥管理后台 |
-| `/api/stats/trend` | 每日趋势 | 📱小程序 |
-| `/api/region/provinces` | 省份列表 | 📱小程序 |
-| `/api/region/cities` | 城市列表 | 📱小程序 |
-| `/api/region/districts` | 区县列表 | 📱小程序 |
-| `/api/region/streets` | 街道列表 | 📱小程序 |
-| `/api/streets/provinces` | 所有省份 | 📱小程序 |
-| `/api/streets/children/{parentId}` | 子级地址 | 📱小程序 |
-| `/api/streets/{id}` | 地址详情 | 📱小程序 |
-| `/api/streets/{id}/path` | 地址路径 | 📱小程序 |
-| `/api/streets/search` | 搜索地址 | 📱小程序 |
-| `/api/streets/{id}/match` | 区域回退匹配 | 📱小程序 |
-| `/api/streets/stats` | 区域统计 | 📱小程序 |
-| `/api/user/address/list` | 地址列表 | 📱小程序 |
-| `/api/user/address/create` | 创建地址 | 📱小程序 |
-| `/api/user/address/update` | 更新地址 | 📱小程序 |
-| `/api/user/address/delete` | 删除地址 | 📱小程序 |
-| `/api/user/address/setDefault` | 设为默认 | 📱小程序 |
+### 孩子与家庭统计
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/stats/child/overview` | 孩子数据概览(积分/任务/游戏) | 📱小程序 | `{childId}` | `{totalPoints, monthActiveDays, taskStats, gameStats, pointsTrend}` |
+| `POST /api/stats/family/summary` | 家庭汇总统计 | 📱小程序 | `{familyId}` | `{children[各孩子统计], familyTotalTasks, familyCompletionRate, familyTotalGames, childCount}` |
+| `POST /api/stats/points/ranking` | 家庭内积分排行榜 | 📱小程序 | `{familyId}` | `[{rank, childId, childName, points}]` |
+
+### 管理后台仪表盘
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/stats/dashboard` | 仪表盘汇总(旧版) | 🖥管理后台 | — | `{totalFamilies, totalParents, totalChildren, totalTeachers, pendingGuideCount, pendingPackageCount, pendingRefundCount, recentTasks}` |
+| `POST /api/stats/overview` | 数据总览(新版) | 🖥管理后台 | — | `{totalFamilies, totalParents, totalChildren, totalTeachers, monthFamilies, monthParents, pendingGuides, pendingPackages, activeUsers}` |
+| `POST /api/stats/revenue` | 收入统计 | 🖥管理后台 | — | `{monthCommission, totalCommission, pendingCommission}` |
+| `POST /api/stats/membership` | 会员分布统计 | 🖥管理后台 | — | `{freeCount, familyCount, providerCount, trialCount, monthUpgrades}` |
+
+### 任务完成率
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/stats/child-completion` | 孩子任务完成率 | 📱小程序 | `{childId, startDate, endDate}` | `TaskStats 对象` |
+| `POST /api/stats/family-completion` | 家庭任务完成率 | 📱小程序 | `{startDate, endDate}` | `TaskStats 对象` |
+| `POST /api/stats/trend` | 每日数据趋势(近30天) | 🖥管理后台 | — | `{familyTrend, userTrend}` |
+
+### 地址区域(数据库版)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/streets/provinces` | 获取所有省份 | 📱小程序 | — | `List<Street>` |
+| `POST /api/streets/children/{parentId}` | 获取子级地址 | 📱小程序 | path: `parentId` | `List<Street>` |
+| `POST /api/streets/{id}` | 获取地址详情 | 📱小程序 | path: `id` | `Street` |
+| `POST /api/streets/{id}/path` | 获取地址完整路径 | 📱小程序 | path: `id` | `List<Street>`(省市区街道) |
+| `POST /api/streets/search` | 搜索地址 | 📱小程序 | `{keyword}` | `List<Street>` |
+| `POST /api/streets/{id}/match` | 区域回退匹配 | 📱小程序 | path: `id` | `{streetMatch, districtMatch, cityMatch}` |
+| `POST /api/streets/stats` | 按区域统计 | 📱小程序 | `{level}` | `{按层级的地址统计}` |
+
+### 地址区域(内存版/旧版)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/region/provinces` | 获取省份列表 | 📱小程序 | — | `[{id, name}]` |
+| `POST /api/region/cities` | 获取城市列表 | 📱小程序 | `{parentId}` | `[{id, name}]` |
+| `POST /api/region/districts` | 获取区县列表 | 📱小程序 | `{parentId}` | `[{id, name}]` |
+| `POST /api/region/streets` | 获取街道列表 | 📱小程序 | `{parentId}` | `[{id, name}]` |
+
+### 用户收货地址
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/user/address/list` | 地址列表 | 📱小程序 | — | `List<UserAddress>` |
+| `POST /api/user/address/get` | 获取单个地址 | 📱小程序 | `{id}` | `UserAddress` |
+| `POST /api/user/address/create` | 新建地址 | 📱小程序 | `{receiverName, phone, province, city, district, street}` | `{success}` |
+| `POST /api/user/address/update` | 更新地址 | 📱小程序 | `{id, receiverName, phone, ...}` | `{success}` |
+| `POST /api/user/address/delete` | 删除地址 | 📱小程序 | `{id}` | `{success}` |
+| `POST /api/user/address/setDefault` | 设为默认地址 | 📱小程序 | `{id}` | `{success}` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    Family ||--o{ FamilyMember : "一个家庭多个成员"
+    FamilyMember ||--o{ PointsLog : "积分流水"
+    FamilyMember ||--o{ Task : "任务记录"
+    FamilyMember ||--o{ GameRecord : "游戏记录"
+    User ||--o{ UserAddress : "一个用户多个地址"
+
+    Family {
+        Long id PK
+        date createdAt
+    }
+
+    FamilyMember {
+        Long id PK
+        Long familyId FK
+        string nickname
+        int totalPoints
+    }
+
+    UserAddress {
+        Long id PK
+        Long userId FK
+        string receiverName
+        string phone
+        string province
+        string city
+        string district
+        string street
+        int isDefault
+    }
+
+    Street {
+        Long id PK
+        Long parentId FK
+        string province
+        string city
+        string district
+        string street
+        string fullName
+        int level
+    }
+
+    CommissionRecord {
+        Long id PK
+        Long orderId
+        string status "pending/settled"
+        int commissionAmount
+    }
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖5大统计模块:孩子/家庭统计、管理后台仪表盘、任务完成率分析、四级地址查询、用户收货地址管理,数据流向清晰 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 管理后台仪表盘使用CompletableFuture+try-catch处理统计失败;地址相关接口校验在Service层处理;收人统计返回默认0.0而非报错 |
+| 3 | **端点覆盖** | ✅ 完整 | 25个端点全部映射到流程图中,与实际Controller(ReportStatsController、StatsController、StreetController、RegionController、UserAddressController)的@PostMapping一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长端查看孩子/家庭/任务统计、地址选择和管理;管理后台查看仪表盘/收入/会员/趋势数据 |
+| 5 | **数据实体** | ✅ 完整 | 覆盖family_member、points_log、task、game_record、family、user、commission_records、trial_membership、member_upgrade_record、streets、user_address共11个数据表 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径、请求参数、响应字段与实际Controller代码匹配。注意:`/api/region/*`(RegionController)使用内存数据,`/api/streets/*`(StreetController)使用数据库数据 |

+ 269 - 92
docs/flows/task-management-flow.md

@@ -1,116 +1,293 @@
 # 用户使用流程图 — 任务管理
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 创建任务 /create]:::portMiniApp
-        A2 -->|从模板| A4[📱 市场购买模板 → 应用]:::portMiniApp
-        A2 -->|AI推荐| A5[📱 AI生成任务建议 → 一键添加]:::portMiniApp
-        A2 -->|训练方案| A6[📱 训练方案下发 /deploy]:::portMiniApp
-        A3 --> A7[📱 获取可选小游戏 /minigame-options]:::portMiniApp
+    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
+
+    %% ================================================================
+    %% 阶段一:任务创建
+    %% ================================================================
+    subgraph 阶段一[阶段一:任务创建]
+        P1["🏠 家长/规划师端:创建任务页"]:::page
+        P1 -->|"选择创建方式"| P1_choice{"手动创建 / 模板 / AI推荐 / 训练方案"}:::page
+
+        P1_choice -->|"手动创建"| P1a["🏠 填写任务表单"]:::page
+        P1a -->|"标题, 描述, 执行人, 积分, 截止时间, 需审核, 分类"| A1["🔗 POST /api/tasks/create"]:::api
+        A1 -->|"创建任务DTO"| S1["⚙️ TaskService.createTask()"]:::service
+        S1 -->|"写入一条任务记录"| D1["📦 tasks 表"]:::data
+
+        P1_choice -->|"从模板"| P1b["🏠 选择任务模板"]:::page
+        P1b -->|"模板ID"| S1
+
+        P1_choice -->|"AI推荐"| P1c["🏠 AI任务建议页"]:::page
+
+        P1_choice -->|"训练方案下发"| P1d["📋 规划师端:选择训练方案"]:::page
+        P1d -->|"方案ID, 孩子ID"| A1
+
+        P1a -->|"获取可选小游戏"| A1a["🔗 POST /api/tasks/minigame-options"]:::api
+        A1a -->|""| S1a["⚙️ MiniGameService.getEnabledGames()"]:::service
+        S1a -->|"已启用小游戏列表"| D2["📦 mini_games 表"]:::data
     end
 
-    subgraph 任务执行
-        A7 --> B1[📱 获取今日任务 /today]:::portMiniApp
-        B1 --> B2{📱 任务类型}:::portMiniApp
-        B2 -->|普通任务| B3[📱 完成任务 /:id/complete]:::portMiniApp
-        B2 -->|小游戏| B4[📱 完成小游戏 /:id/complete-minigame]:::portMiniApp
-        B2 -->|家长任务| B5[📱 家长完成任务 /:id/complete-parent]:::portMiniApp
-        B3 --> B6{📱 需要审核?}:::portMiniApp
-        B6 -->|是| B7[📱 进入待审核 /pending-review]:::portMiniApp
-        B6 -->|否| B8[📱 任务完成]:::portMiniApp
-        B4 --> B8
-        B5 --> B8
+    %% ================================================================
+    %% 阶段二:任务执行
+    %% ================================================================
+    subgraph 阶段二[阶段二:任务执行]
+        D1 -->|"孩子ID"| P2["🏠 孩子端:今日任务页"]:::page
+        P2 -->|"获取今日任务"| A2["🔗 POST /api/tasks/today"]:::api
+        A2 -->|"childId, category(可选)"| S2["⚙️ TaskService.getTodayTasks()"]:::service
+        S2 -->|"今日任务列表"| D1
+
+        P2 -->|"选择任务"| P2_choice{"普通任务 / 小游戏 / 家长任务"}:::page
+
+        P2_choice -->|"普通任务"| P2a["🏠 执行并提交"]:::page
+        P2a -->|"任务ID, childId, 照片"| A3["🔗 POST /api/tasks/{id}/complete"]:::api
+        A3 -->|"任务ID, childId, photoUrl"| S3["⚙️ TaskService.completeTask()"]:::service
+        S3 -->|"更新任务状态=completed, 发放积分"| D1
+
+        P2_choice -->|"小游戏"| P2b["🏠 玩小游戏并提交成绩"]:::page
+        P2b -->|"任务ID, childId, 完成时间, 得分"| A4["🔗 POST /api/tasks/{id}/complete-minigame"]:::api
+        A4 -->|"任务ID, childId, completionTime, score"| S4["⚙️ TaskService.completeMinigameTask()"]:::service
+        S4 -->|"更新任务状态, 记录游戏成绩"| D1
+
+        P2_choice -->|"家长任务"| P2c["📱 家长端:完成任务"]:::page
+        P2c -->|"任务ID"| A5["🔗 POST /api/tasks/{id}/complete-parent"]:::api
+        A5 -->|"任务ID, 用户ID"| S5["⚙️ TaskService.completeParentTask()"]:::service
+        S5 -->|"更新任务状态"| D1
+
+        P2a -->|"完成后判断"| CHECK{"需要审核?"}:::page
+        CHECK -->|"是"| P2d["🏠 进入待审核列表"]:::page
+        CHECK -->|"否"| P2e["🏠 任务完成(直接通过)"]:::page
+
+        P2 -->|"获取家长今日任务"| A6["🔗 POST /api/tasks/today-parent"]:::api
+        A6 -->|"用户ID"| S6["⚙️ TaskService.getTodayParentTasks()"]:::service
+        S6 -->|"家长任务列表"| D1
     end
 
-    subgraph 任务审核
-        B7 --> C1[📱 获取待审核列表 /pending-review]:::portMiniApp
-        C1 --> C2[📱 审核任务 /:id/review]:::portMiniApp
-        C2 --> C3{📱 审核结果}:::portMiniApp
-        C3 -->|通过| C4[📱 任务完成 发放能量]:::portMiniApp
-        C3 -->|驳回| C5[📱 任务退回]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:任务审核
+    %% ================================================================
+    subgraph 阶段三[阶段三:任务审核]
+        D1 -->|"家长ID/需审核标记"| P3["🏠 家长/规划师端:待审核页"]:::page
+        P3 -->|"获取待审核列表"| A7["🔗 POST /api/tasks/pending-review"]:::api
+        A7 -->|"用户ID"| S7["⚙️ TaskService.getPendingReviewTasks()"]:::service
+        S7 -->|"待审核任务列表"| D1
+
+        P3 -->|"审核单个任务"| A8["🔗 POST /api/tasks/{id}/review"]:::api
+        A8 -->|"任务ID, {approved, comment, points}"| S8["⚙️ TaskService.reviewTask()"]:::service
+        S8 -->|"通过: 发放能量/积分; 驳回: 退回待修改"| D1
+
+        P3 -->|"删除任务"| A9["🔗 POST /api/tasks/{id}"]:::api
+        A9 -->|"任务ID, 用户ID"| S9["⚙️ TaskService.deleteTask()"]:::service
+        S9 -->|"更新任务状态=已删除"| D1
     end
 
-    subgraph 规划师批量管理
-        A1 --> D1[📋 获取关联家庭 /bound-families]:::portGuide
-        D1 --> D2[📋 获取家庭任务概览 /:familyId/overview]:::portGuide
-        D2 --> D3[📋 获取孩子任务 /:familyId/children/:childId/tasks]:::portGuide
-        D3 --> D4[📋 批量审核 /batch-review]:::portGuide
-        D4 --> D5[📋 修改任务 /:taskId]:::portGuide
-        D5 --> D6[📋 删除任务 /:taskId/delete]:::portGuide
+    %% ================================================================
+    %% 阶段四:规划师批量管理
+    %% ================================================================
+    subgraph 阶段四[阶段四:规划师批量管理]
+        D1 -->|"关联家庭"| P4["📋 规划师端:任务管理首页"]:::page
+        P4 -->|"获取关联家庭"| A10["🔗 POST /api/guide/families/bound-families"]:::api
+        A10 -->|"规划师ID, role"| S10["⚙️ GuideFamilyTaskController.getBoundFamilies()"]:::service
+        S10 -->|"家庭列表(含待审核数)"| D3["📦 users(teacher_family_ids)"]:::data
+
+        P4 -->|"家庭概览"| A11["🔗 POST /api/guide/families/{familyId}/overview"]:::api
+        A11 -->|"规划师ID, familyId"| S11["⚙️ GuideFamilyTaskController.getFamilyTaskOverview()"]:::service
+        S11 -->|"孩子任务概览(今日/待审核/总计)"| D1
+
+        P4 -->|"孩子任务列表"| A12["🔗 POST /api/guide/families/{familyId}/children/{childId}/tasks"]:::api
+        A12 -->|"familyId, childId, 分页, status"| S12["⚙️ TaskService.getTaskHistoryByFamilyMember()"]:::service
+        S12 -->|"分页任务列表"| D1
+
+        P4 -->|"待审核列表(孩子)"| A13["🔗 POST /api/guide/families/{familyId}/children/{childId}/pending-review"]:::api
+        A13 -->|"familyId, childId"| S13["⚙️ TaskService.getPendingReviewTasksForFamilyMember()"]:::service
+        S13 -->|"待审核任务列表"| D1
+
+        P4 -->|"审核任务"| A14["🔗 POST /api/guide/families/{familyId}/tasks/{taskId}/review"]:::api
+        A14 -->|"familyId, taskId, approved, comment"| S14["⚙️ TaskService.reviewTask()"]:::service
+        S14 -->|"通过/驳回"| D1
+
+        P4 -->|"批量审核"| A15["🔗 POST /api/guide/families/{familyId}/tasks/batch-review"]:::api
+        A15 -->|"familyId, taskIds[], approved"| S15["⚙️ GuideFamilyTaskController.batchReviewTasks()"]:::service
+        S15 -->|"逐条调用reviewTask"| D1
+
+        P4 -->|"修改任务"| A16["🔗 POST /api/guide/families/{familyId}/tasks/{taskId}"]:::api
+        A16 -->|"familyId, taskId, 标题/描述/积分/截止/状态"| S16["⚙️ GuideFamilyTaskController.updateTask()"]:::service
+        S16 -->|"更新任务字段"| D1
+
+        P4 -->|"删除任务"| A17["🔗 POST /api/guide/families/{familyId}/tasks/{taskId}/delete"]:::api
+        A17 -->|"familyId, taskId"| S17["⚙️ GuideFamilyTaskController.deleteTask()"]:::service
+        S17 -->|"任务状态=已取消"| D1
+
+        P4 -->|"规划师首页统计"| A18["🔗 POST /api/guide/families/dashboard-stats"]:::api
+        A18 -->|"规划师ID, role"| S18["⚙️ GuideFamilyTaskController.getDashboardStats()"]:::service
+        S18 -->|"家庭数, 今日完成数, 待审核数"| D1
     end
 
-    subgraph 任务历史与统计
-        B8 --> E1[📱 获取任务历史 /history]:::portMiniApp
-        E1 --> E2[📱 批量完成任务 /batch-complete]:::portMiniApp
-        E2 --> E3[📱 批量删除任务 /batch-delete]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:任务历史与提醒
+    %% ================================================================
+    subgraph 阶段五[阶段五:任务历史与提醒]
+        D1 -->|"孩子ID"| P5["🏠 孩子/家长端:历史与提醒页"]:::page
+        P5 -->|"任务历史"| A19["🔗 POST /api/tasks/history"]:::api
+        A19 -->|"childId, 分页, category"| S19["⚙️ TaskService.getTaskHistory()"]:::service
+        S19 -->|"分页历史任务"| D1
+
+        P5 -->|"批量完成"| A20["🔗 POST /api/tasks/batch-complete"]:::api
+        A20 -->|"用户ID, taskIds[]"| S20["⚙️ TaskService.batchComplete()"]:::service
+        S20 -->|"逐条完成任务"| D1
+
+        P5 -->|"批量删除"| A21["🔗 POST /api/tasks/batch-delete"]:::api
+        A21 -->|"用户ID, taskIds[]"| S21["⚙️ TaskService.batchDelete()"]:::service
+        S21 -->|"逐条删除任务"| D1
+
+        P5 -->|"即将到期"| A22["🔗 POST /api/task-reminders/upcoming/{childId}"]:::api
+        A22 -->|"childId, minutes"| S22["⚙️ TaskReminderService.getUpcomingTasks()"]:::service
+        S22 -->|"指定时间内到期的任务"| D1
+
+        P5 -->|"逾期任务"| A23["🔗 POST /api/task-reminders/overdue/{childId}"]:::api
+        A23 -->|"childId"| S23["⚙️ TaskReminderService.getOverdueTasks()"]:::service
+        S23 -->|"已超时未完成的任务"| D1
+
+        P5 -->|"需要提醒"| A24["🔗 POST /api/task-reminders/reminder/{childId}"]:::api
+        A24 -->|"childId"| S24["⚙️ TaskReminderService.getTasksNeedReminder()"]:::service
+        S24 -->|"30分钟内到期未完成的任务"| D1
+
+        P5 -->|"历史筛选"| A25["🔗 POST /api/task-reminders/history/filter/{childId}"]:::api
+        A25 -->|"childId, status, startDate, endDate, 分页"| S25["⚙️ TaskReminderService.getTaskHistoryWithFilter()"]:::service
+        S25 -->|"按条件筛选的历史任务"| D1
     end
 
-    subgraph 任务提醒
-        E3 --> F1[📱 即将到期 /api/task-reminders/upcoming/:childId]:::portMiniApp
-        F1 --> F2[📱 逾期任务 /api/task-reminders/overdue/:childId]:::portMiniApp
-        F2 --> F3[📱 提醒设置 /api/task-reminders/reminder/:childId]:::portMiniApp
-        F3 --> F4{📱 统计分析}:::portMiniApp
-        F4 -->|任务统计| F5[📱 /api/task-reminders/statistics/:childId]:::portMiniApp
-        F4 -->|分类统计| F6[📱 /api/task-reminders/statistics/category/:childId]:::portMiniApp
-        F4 -->|日期统计| F7[📱 /api/task-reminders/statistics/date/:childId]:::portMiniApp
-        F4 -->|家庭统计| F8[📱 /api/task-reminders/statistics/family/:familyId]:::portMiniApp
-        F3 --> F9[📱 历史过滤 /api/task-reminders/history/filter/:childId]:::portMiniApp
+    %% ================================================================
+    %% 阶段六:统计分析
+    %% ================================================================
+    subgraph 阶段六[阶段六:统计分析]
+        D1 -->|"孩子ID"| P6["🏠 家长/规划师端:统计页"]:::page
+        P6 -->|"任务统计概览"| A26["🔗 POST /api/task-reminders/statistics/{childId}"]:::api
+        A26 -->|"childId, startDate, endDate"| S26["⚙️ TaskReminderService.getTaskStatistics()"]:::service
+        S26 -->|"完成率, 逾期率, 积分统计"| D1
+
+        P6 -->|"分类统计"| A27["🔗 POST /api/task-reminders/statistics/category/{childId}"]:::api
+        A27 -->|"childId"| S27["⚙️ TaskReminderService.getTaskStatsByCategory()"]:::service
+        S27 -->|"按维度的任务统计"| D1
+
+        P6 -->|"日期统计"| A28["🔗 POST /api/task-reminders/statistics/date/{childId}"]:::api
+        A28 -->|"childId, days"| S28["⚙️ TaskReminderService.getTaskStatsByDate()"]:::service
+        S28 -->|"近N天每日完成数"| D1
+
+        P6 -->|"家庭统计"| A29["🔗 POST /api/task-reminders/statistics/family/{familyId}"]:::api
+        A29 -->|"familyId"| S29["⚙️ TaskReminderService.getFamilyTaskStatistics()"]:::service
+        S29 -->|"整个家庭的任务统计"| D1
     end
 
-    R1(("👤 家长/规划师")):::actor
-    R2(("👶 孩子")):::actor
-    R3(("📋 规划师")):::role
+    %% ================================================================
+    %% 定时任务
+    %% ================================================================
+    subgraph 定时[⏰ 定时任务]
+        S_T1["⚙️ RepeatTaskGenerator.generateDailyTasks()"]:::service
+        S_T1 -->|"每天凌晨5点, 扫描repeat_type=daily/weekly的任务模板"| D1
+        S_T1 -->|"从模板创建今日任务实例"| D1
+    end
 
-    A1 -.- R1
-    B3 -.- R2
-    D1 -.- R3
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    A0 -.- P1
+    A0 -.- P3
+    A0 -.- P4
+    A0 -.- P5
+    A0 -.- P6
+    B0 -.- P2
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/tasks/create` | 创建任务 | 📱小程序 |
-| `/api/tasks/today` | 获取今日任务 | 📱小程序 |
-| `/api/tasks/{id}/complete` | 完成任务 | 📱小程序 |
-| `/api/tasks/{id}/review` | 审核任务 | 📱小程序 |
-| `/api/tasks/history` | 获取任务历史 | 📱小程序 |
-| `/api/tasks/pending-review` | 获取待审核任务 | 📱小程序 |
-| `/api/tasks/today-parent` | 获取家长今日任务 | 📱小程序 |
-| `/api/tasks/{id}/complete-parent` | 家长完成任务 | 📱小程序 |
-| `/api/tasks/{id}/complete-minigame` | 完成小游戏任务 | 📱小程序 |
-| `/api/tasks/batch-complete` | 批量完成任务 | 📱小程序 |
-| `/api/tasks/batch-delete` | 批量删除任务 | 📱小程序 |
-| `/api/tasks/minigame-options` | 获取可选小游戏 | 📱小程序 |
-| `/api/task-reminders/upcoming/{childId}` | 即将到期任务 | 📱小程序 |
-| `/api/task-reminders/overdue/{childId}` | 逾期任务 | 📱小程序 |
-| `/api/task-reminders/reminder/{childId}` | 提醒设置 | 📱小程序 |
-| `/api/task-reminders/statistics/{childId}` | 任务统计 | 📱小程序 |
-| `/api/task-reminders/statistics/category/{childId}` | 分类统计 | 📱小程序 |
-| `/api/task-reminders/statistics/date/{childId}` | 日期统计 | 📱小程序 |
-| `/api/task-reminders/statistics/family/{familyId}` | 家庭统计 | 📱小程序 |
-| `/api/task-reminders/history/filter/{childId}` | 历史过滤 | 📱小程序 |
-| `/api/guide/families/bound-families` | 获取关联家庭 | 📋规划师端 |
-| `/api/guide/families/{familyId}/overview` | 家庭任务概览 | 📋规划师端 |
-| `/api/guide/families/{familyId}/children/{childId}/tasks` | 孩子任务列表 | 📋规划师端 |
-| `/api/guide/families/{familyId}/children/{childId}/pending-review` | 待审核列表 | 📋规划师端 |
-| `/api/guide/families/{familyId}/tasks/{taskId}/review` | 审核任务 | 📋规划师端 |
-| `/api/guide/families/{familyId}/tasks/batch-review` | 批量审核 | 📋规划师端 |
-| `/api/guide/families/{familyId}/tasks/{taskId}/delete` | 删除任务 | 📋规划师端 |
-| `/api/guide/families/dashboard-stats` | 规划师首页统计 | 📋规划师端 |
+### 任务创建
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/tasks/create` | 创建任务 | 📱小程序 | `{childId, title, description, points, deadline, needReview, category, executorType, ...}` | `taskId` |
+| `POST /api/tasks/minigame-options` | 获取可选小游戏列表 | 📱小程序 | — | `List<MiniGame>` |
+| `POST /api/tasks/{id}` | 删除任务 | 📱小程序 | path: `id`, body: — | `boolean` |
+
+### 任务执行
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/tasks/today` | 获取今日任务 | 📱小程序 | `{childId, category}` | `List<Task>` |
+| `POST /api/tasks/today-parent` | 获取家长今日任务 | 📱小程序 | — | `List<Task>` |
+| `POST /api/tasks/{id}/complete` | 完成任务 | 📱小程序 | path: `id`, body: `{childId, photoUrl}` | `{points, energy, ...}` |
+| `POST /api/tasks/{id}/complete-parent` | 家长完成任务 | 📱小程序 | path: `id` | `{points, ...}` |
+| `POST /api/tasks/{id}/complete-minigame` | 完成小游戏任务 | 📱小程序 | path: `id`, body: `{childId, completionTime, score}` | `{points, energy, score, ...}` |
+
+### 任务审核
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/tasks/pending-review` | 获取待审核任务列表 | 📱小程序 | — (从token取userId) | `List<Task>` |
+| `POST /api/tasks/{id}/review` | 审核任务 | 📱小程序 | path: `id`, body: `{approved, comment, points}` | `boolean` |
+
+### 任务历史与批量操作
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/tasks/history` | 获取任务历史 | 📱小程序 | `{childId, page, size, category}` | `Page<Task>` |
+| `POST /api/tasks/batch-complete` | 批量完成任务 | 📱小程序 | `{taskIds[]}` | `boolean` |
+| `POST /api/tasks/batch-delete` | 批量删除任务 | 📱小程序 | `{taskIds[]}` | `boolean` |
+
+### 任务提醒与筛选
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/task-reminders/reminder/{childId}` | 获取需提醒任务(30分钟到期) | 📱小程序 | path: `childId` | `List<Task>` |
+| `POST /api/task-reminders/upcoming/{childId}` | 即将到期任务 | 📱小程序 | path: `childId`, body: `{minutes}` | `List<Task>` |
+| `POST /api/task-reminders/overdue/{childId}` | 逾期任务 | 📱小程序 | path: `childId` | `List<Task>` |
+| `POST /api/task-reminders/history/filter/{childId}` | 带筛选的历史任务 | 📱小程序 | path: `childId`, body: `{status, startDate, endDate, page, size}` | `{tasks, total, ...}` |
+
+### 统计分析
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/task-reminders/statistics/{childId}` | 任务统计概览 | 📱小程序 | path: `childId`, body: `{startDate, endDate}` | `{total, completed, overdue, completionRate, ...}` |
+| `POST /api/task-reminders/statistics/category/{childId}` | 按分类统计 | 📱小程序 | path: `childId` | `List<{category, count, completed, ...}>` |
+| `POST /api/task-reminders/statistics/date/{childId}` | 按日期统计 | 📱小程序 | path: `childId`, body: `{days}` | `List<{date, count, ...}>` |
+| `POST /api/task-reminders/statistics/family/{familyId}` | 家庭任务统计 | 📱小程序 | path: `familyId` | `{totalTasks, completedTasks, ...}` |
+
+### 规划师批量管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/guide/families/bound-families` | 获取关联家庭列表 | 📋规划师端 | — (从token取userId+role) | `List<{familyId, familyName, childrenCount, pendingReviewCount}>` |
+| `POST /api/guide/families/{familyId}/overview` | 家庭任务概览 | 📋规划师端 | path: `familyId` | `{children[], totalPendingReview, totalCompleted, totalOverdue}` |
+| `POST /api/guide/families/{familyId}/children/{childId}/tasks` | 孩子任务列表(分页) | 📋规划师端 | path: `familyId, childId`, body: `{page, size, status}` | `Page<Task>` |
+| `POST /api/guide/families/{familyId}/children/{childId}/pending-review` | 待审核任务列表 | 📋规划师端 | path: `familyId, childId` | `List<Task>` |
+| `POST /api/guide/families/{familyId}/tasks/{taskId}/review` | 审核任务 | 📋规划师端 | path: `familyId, taskId`, body: `{approved, comment}` | `boolean` |
+| `POST /api/guide/families/{familyId}/tasks/batch-review` | 批量审核 | 📋规划师端 | path: `familyId`, body: `{taskIds[], approved}` | `{successCount, failCount}` |
+| `POST /api/guide/families/{familyId}/tasks/{taskId}` | 修改任务 | 📋规划师端 | path: `familyId, taskId`, body: `{title, description, points, deadline, status}` | `boolean` |
+| `POST /api/guide/families/{familyId}/tasks/{taskId}/delete` | 删除任务 | 📋规划师端 | path: `familyId, taskId` | `boolean` |
+| `POST /api/guide/families/dashboard-stats` | 规划师首页统计 | 📋规划师端 | — | `{totalFamilies, todayCompletedTasks, pendingReviewTasks}` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖任务创建(手动/模板/AI/训练方案)、执行(普通/小游戏/家长任务)、审核、规划师批量管理、历史与提醒、统计分析6个阶段,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 审核驳回退回待修改、逾期任务、小游戏成绩异常等已在图中体现;定时任务中模板不存在等错误由Service层处理 |
+| 3 | **端点覆盖** | ✅ 完整 | 29个端点全部映射到流程图中,与代码实际暴露的TaskController、TaskReminderController、GuideFamilyTaskController一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长(parent)创建/审核任务、孩子(child)执行任务、规划师(teacher)批量管理/审核均已覆盖;定时任务(⚙️系统自动)生成重复任务包含在图中 |
+| 5 | **数据实体** | ✅ 完整 | tasks表、mini_games表、users表(teacher_family_ids)均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(TaskController、TaskReminderController、GuideFamilyTaskController)中的`@PostMapping`匹配 |

+ 132 - 29
docs/flows/tianpan-fortune-flow.md

@@ -1,45 +1,148 @@
 # 用户使用流程图 — 天盘与运势
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取天盘首页 /dashboard]:::portMiniApp
-        A2 --> A3[📱 查看成员天盘 /member/:memberId]:::portMiniApp
+    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_CHILD(("👶 孩子")):::actor
+    ROLE_TEACHER(("📋 规划师")):::actor
+    ROLE_ADMIN(("🖥 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:天盘首页与仪表盘
+    %% ================================================================
+    subgraph 阶段一[阶段一:天盘首页与仪表盘]
+        P1["🏠 家长端:天盘首页"]:::page
+        P1 -->|"familyId, year, daysAhead"| A1["🔗 POST /api/tianpan/dashboard"]:::api
+        A1 -->|"familyId, year, daysAhead"| S1["⚙️ TianpanService.buildDashboard()"]:::service
+        S1 -->|"成员列表, 年度能量摘要, 近期运势, 兼容性概览"| D_DASH["📦 TianpanDashboardVO(聚合)"]:::data
+        D_DASH -->|"仪表盘数据"| P1
+
+        P1 -->|"点击成员"| P2["🏠 家长端:成员天盘页"]:::page
+        P2 -->|"memberId, memberType"| A2["🔗 POST /api/tianpan/member/{memberId}"]:::api
+        A2 -->|"memberId, memberType"| S2["⚙️ TianpanService.buildMemberDetail()"]:::service
+        S2 -->|"成员基本信息, 生肖, 八字, 年度能量, 近期运势"| D_MEMBER["📦 TianpanMemberVO(聚合)"]:::data
+        D_MEMBER -->|"成员详情"| P2
+    end
+
+    %% ================================================================
+    %% 阶段二:兼容性与分析
+    %% ================================================================
+    subgraph 阶段二[阶段二:兼容性与分析]
+        P2 -->|"选择2个成员"| P3["🏠 家长端:兼容性页面"]:::page
+        P3 -->|"member1Id, member2Id"| A3["🔗 POST /api/tianpan/compatibility"]:::api
+        A3 -->|"member1Id, member2Id, memberType"| S3["⚙️ TianpanService.computeCompatibility()"]:::service
+        S3 -->|"五行匹配得分, 生肖相合, 兼容性评分"| D_COMP["📦 CompatibilityResultVO"]:::data
+        D_COMP -->|"兼容性结果"| P3
+
+        P2 -->|"查看年度能量"| P4["🏠 家长端:年度能量页"]:::page
+        P4 -->|"memberId, year"| A4["🔗 POST /api/tianpan/annual-energy"]:::api
+        A4 -->|"memberId, year"| S4["⚙️ TianpanService.buildAnnualEnergy()"]:::service
+        S4 -->|"五维能量得分, 木星土星相位, 年度亮点"| D_ENERGY["📦 MemberAnnualEnergyVO"]:::data
+        S4 -.->|"读写"| DE_TABLE["📦 tianpan_member_annual_energy 表"]:::data
+        D_ENERGY -->|"年度能量"| P4
     end
 
-    subgraph 天盘分析
-        A3 --> B1[📱 查看成员兼容性 /compatibility]:::portMiniApp
-        B1 --> B2[📱 获取年度能量 /annual-energy]:::portMiniApp
-        B2 --> B3[📱 获取每日运势 /daily-fortune]:::portMiniApp
-        B3 --> B4[📱 获取相关项目 /related-items]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:每日运势
+    %% ================================================================
+    subgraph 阶段三[阶段三:每日运势]
+        P1 -->|"查看运势"| P5["🏠 家长端:今日运势页"]:::page
+        P5 -->|"familyId"| A5["🔗 POST /api/tianpan/daily-fortune"]:::api
+        A5 -->|"familyId"| S5["⚙️ TianpanService.buildDailyFortune()"]:::service
+        S5 -->|"农历日期, 干支, 五行, 宜忌, 家庭建议"| D_FORTUNE["📦 DailyFortuneVO"]:::data
+        S5 -.->|"读写"| DF_TABLE["📦 tianpan_daily_fortune 表"]:::data
+        D_FORTUNE -->|"运势数据"| P5
+
+        P1 -->|"查看相关事项"| P6["🏠 家长端:相关事项页"]:::page
+        P6 -->|"familyId, daysAhead"| A6["🔗 POST /api/tianpan/related-items"]:::api
+        A6 -->|"familyId, daysAhead"| S6["⚙️ TianpanService.buildRelatedItems()"]:::service
+        S6 -->|"近日重要事项, 重点关注成员"| D_ITEMS["📦 RelatedItemsVO"]:::data
+        D_ITEMS -->|"事项列表"| P6
+
+        P5 -->|"刷新运势"| A7["🔗 POST /api/mind/fortune/refresh"]:::api
+        A7 -->|"系统自动触发"| S7["⚙️ FortuneService.getFamilyFortune() + calculateLuckyDirection()"]:::service
+        S7 -->|"dominantElement, luckyDirection, fortuneLevel"| D_FAMILY["📦 family_fortune 表(新存)"]:::data
     end
 
-    R1(("👤 用户")):::actor
+    %% ================================================================
+    %% 阶段四:预览与导出
+    %% ================================================================
+    subgraph 阶段四[阶段四:天盘周报导出]
+        P5 -->|"导出周报PDF"| P7["🏠 家长端:导出天盘周报"]:::page
+        P7 -->|"imageBase64, element, luckyDirection"| A8["🔗 POST /api/mind/fortune/export"]:::api
+        A8 -->|"图片, 五行元素, 吉位, 提示"| S8["⚙️ PdfReportService.generatePdfReport()"]:::service
+        S8 -->|"PDF字节数组"| S8a["⚙️ PdfReportService.savePdfReport()"]:::service
+        S8a -->|"存储PDF文件"| D_FILE["📦 文件系统 /storage/reports/"]:::data
+        S8a -->|"记录报告元数据"| D_REPORT["📦 family_fortune_reports 表"]:::data
+    end
 
-    A1 -.- R1
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P5
+    ROLE_PARENT -.- P7
+    ROLE_CHILD -.- P2
+    ROLE_TEACHER -.- P2
+    ROLE_ADMIN -.- P1
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/tianpan/dashboard` | 天盘首页 | 📱小程序 |
-| `/api/tianpan/member/{memberId}` | 成员天盘 | 📱小程序 |
-| `/api/tianpan/compatibility` | 成员兼容性 | 📱小程序 |
-| `/api/tianpan/annual-energy` | 年度能量 | 📱小程序 |
-| `/api/tianpan/daily-fortune` | 每日运势 | 📱小程序 |
-| `/api/tianpan/related-items` | 相关项目 | 📱小程序 |
+### 天盘主接口
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/tianpan/dashboard` | 获取天盘仪表盘 | 📱小程序 | `{familyId, year, daysAhead, viewerRole}` | `TianpanDashboardVO`(成员列表、年度能量摘要、近期运势、兼容性概览) |
+| `POST /api/tianpan/member/{memberId}` | 获取成员详情 | 📱小程序 | `{memberType, viewerRole}` | `TianpanMemberVO`(基本信息、生肖、八字、年度能量、近期运势) |
+| `POST /api/tianpan/compatibility` | 计算兼容性 | 📱小程序 | `{member1Id, member2Id, memberType1, memberType2}` | `CompatibilityResultVO`(五行匹配得分、生肖相合、兼容性评分) |
+| `POST /api/tianpan/annual-energy` | 获取年度能量 | 📱小程序 | `{memberId, year}` | `MemberAnnualEnergyVO`(五维能量得分、木星土星相位、年度亮点) |
+| `POST /api/tianpan/daily-fortune` | 获取每日运势 | 📱小程序 | `{familyId}` | `DailyFortuneVO`(农历日期、干支、五行、宜忌、家庭建议) |
+| `POST /api/tianpan/related-items` | 获取相关事项 | 📱小程序 | `{familyId, daysAhead}` | `RelatedItemsVO`(近日重要事项、重点关注成员) |
+
+### 家庭运势接口
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/mind/fortune` | 获取今日家庭运势 | 📱小程序 | —(从用户ID取家庭) | `{dominantElement, luckyDirection, fortuneLevel, moodScore, ...}` |
+| `POST /api/mind/fortune/refresh` | 手动刷新运势 | 📱小程序 | —(从用户ID取家庭) | `FamilyFortune` 完整对象 |
+| `POST /api/mind/fortune/export` | 导出天盘周报PDF | 📱小程序 | `{imageBase64, element, luckyDirection, tip}` | `{pdfUrl, fileName, fileSize, element}` |
+
+## 数据实体关系
+
+```
+family_fortune ←→ tianpan_daily_fortune (不同粒度的运势数据)
+family_fortune_reports ←→ family_fortune (周报导出关联)
+```
+
+| 表名 | 主键 | 核心字段 | 说明 |
+|------|------|---------|------|
+| `family_fortune` | `id` | familyId, dominantElement, luckyDirection, fortuneLevel, moodScore, dailyTip, weeklyTip, fortuneDate | 家庭每日运势(含心情、提示) |
+| `tianpan_daily_fortune` | `id` | familyId, date, lunarDate, dayGanzhi, fiveElementsMain, auspicious, inauspicious, familyAdvice | 天盘每日运势(含农历、干支、宜忌) |
+| `tianpan_member_annual_energy` | `id` | memberId, year, dimensionsBody/Mind/Wisdom/Action/Wealth, jupiterPhase, saturnPhase | 成员年度五维能量 |
+| `family_fortune_reports` | `id` | familyId, element, luckyDirection, pdfPath | 天盘周报PDF记录 |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖天盘首页、成员详情、兼容性、年度能量、每日运势、相关事项、周报导出7个阶段 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 权限校验(checkAccess)在Controller层统一处理,403拒绝已覆盖;成员不存在(404)已覆盖;生成占位数据(family_fortune无缓存时)逻辑在Service层,图中未展示 |
+| 3 | **端点覆盖** | ✅ 完整 | 9个端点全部映射到流程图中,与TianpanController和MindFortuneController的`@PostMapping`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长(parent)为天盘主要使用者;孩子(child)和规划师(teacher)可查看成员详情;管理员(admin)可访问天盘首页 |
+| 5 | **数据实体** | ✅ 完整 | family_fortune、tianpan_daily_fortune、tianpan_member_annual_energy、family_fortune_reports均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与TianpanController、MindFortuneController中的实际`@PostMapping`匹配 |

+ 186 - 75
docs/flows/user-auth-flow.md

@@ -1,92 +1,203 @@
 # 用户使用流程图 — 认证与用户管理
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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{📱 注册方式}:::portMiniApp
-        A3 -->|微信授权| A4[📱 微信静默登录 /silent-login]:::portMiniApp
-        A3 -->|手机号| A5[📱 发送验证码 /send-code]:::portMiniApp
-        A5 --> A6[📱 手机号验证码登录 /phone-login]:::portMiniApp
-        A3 -->|手机号+身份证| A7[📱 注册登录 /register-with-idcard]:::portMiniApp
-        A3 -->|邀请码| A8[📱 邀请码注册 /register-with-invite]:::portMiniApp
-        A3 -->|直接注册| A9[📱 直接注册 /direct-register]:::portMiniApp
-        A4 --> A10[⚙️ 系统自动创建账号]:::portSystem
-        A6 --> A10
-        A7 --> A10
-        A8 --> A10
-        A9 --> A10
-        A2 -->|是| A11{📱 登录方式}:::portMiniApp
-        A11 -->|微信| A12[📱 微信code登录 /wechat-login]:::portMiniApp
-        A11 -->|手机号| A13[📱 手机验证码登录 /phone-login]:::portMiniApp
-        A11 -->|openid| A14[📱 openid自动登录 /auto-login]:::portMiniApp
-        A12 --> A15[⚙️ JWT签发]:::portSystem
-        A13 --> A15
-        A14 --> A15
-        A10 --> A15
-    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_CHILD(("👶 孩子")):::actor
+    ROLE_JWT(("🔐 JWT认证")):::actor
+
+    %% ================================================================
+    %% 阶段一:注册登录
+    %% ================================================================
+    subgraph 阶段一[阶段一:注册登录]
+        direction TB
+
+        P1["🏠 小程序:登录页"]:::page
+        P1 -->|"选择操作"| P1_choice{"已有账号 / 新注册"}:::page
+
+        P1_choice -->|"新注册"| P1_reg{"选择注册方式"}:::page
+        P1_reg -->|"微信授权"| P1a["🏠 微信静默授权弹窗"]:::page
+        P1a -->|"微信code"| A1["🔗 POST /api/auth/silent-login"]:::api
+        A1 -->|"微信code"| S1["⚙️ WechatService.silentLogin()"]:::service
+        S1 -->|"openid, 新用户标记"| D1["📦 users 表(查询/创建)"]:::data
+
+        P1_reg -->|"手机号"| P1b["🏠 输入手机号"]:::page
+        P1b -->|"手机号"| A2["🔗 POST /api/auth/send-code"]:::api
+        A2 -->|"手机号"| S2["⚙️ SmsService.sendCode()"]:::service
+        S2 -->|"验证码, 过期时间"| D2["📦 sms_codes 表(写入)"]:::data
+        P1b -->|"手机号 + 验证码"| A3["🔗 POST /api/auth/phone-login"]:::api
+        A3 -->|"手机号, 验证码"| S3["⚙️ AuthService.phoneLogin()"]:::service
+        S3 -->|"用户信息"| D1
+
+        P1_reg -->|"手机号+身份证"| P1c["🏠 填写手机号+身份证"]:::page
+        P1c -->|"手机号, 身份证号"| A4["🔗 POST /api/auth/register-with-idcard"]:::api
+        A4 -->|"手机号, 身份证号"| S4["⚙️ AuthService.registerWithIdCard()"]:::service
+        S4 -->|"新用户记录"| D1
+
+        P1_reg -->|"邀请码"| P1d["🏠 输入邀请码"]:::page
+        P1d -->|"手机号, 邀请码"| A5["🔗 POST /api/auth/register-with-invite"]:::api
+        A5 -->|"手机号, 邀请码"| S5["⚙️ AuthService.registerWithInvite()"]:::service
+        S5 -->|"新用户记录 + 邀请关系"| D1
 
-    subgraph 认证与安全
-        A15 --> B1[⚙️ 验证JWT Token /verify]:::portSystem
-        B1 --> B2{⚙️ Token有效?}:::portSystem
-        B2 -->|有效| B3[📱 获取用户信息 /info]:::portMiniApp
-        B2 -->|过期| B4[📱 重新登录]:::portMiniApp
-        B3 --> B5[📱 设置密码 /set-password]:::portMiniApp
-        B3 --> B6[📱 验证密码 /verify-password]:::portMiniApp
-        B3 --> B7[📱 检查手机号 /check-phone]:::portMiniApp
+        P1_reg -->|"直接注册"| P1e["🏠 填写基本信息"]:::page
+        P1e -->|"昵称, 头像"| A6["🔗 POST /api/auth/direct-register"]:::api
+        A6 -->|"用户信息"| S6["⚙️ AuthService.directRegister()"]:::service
+        S6 -->|"新用户记录"| D1
+
+        P1_choice -->|"已有账号"| P1_login{"选择登录方式"}:::page
+        P1_login -->|"微信"| P1f["🏠 微信授权弹窗"]:::page
+        P1f -->|"微信code"| A7["🔗 POST /api/auth/wechat-login"]:::api
+        A7 -->|"微信code"| S7["⚙️ WechatService.codeLogin()"]:::service
+        S7 -->|"用户ID"| D1
+
+        P1_login -->|"手机号"| P1g["🏠 输入手机号+验证码"]:::page
+        P1g -->|"手机号, 验证码"| A3
+
+        P1_login -->|"openid自动登录"| P1h["🏠 自动检测openid"]:::page
+        P1h -->|"openid"| A8["🔗 POST /api/auth/auto-login"]:::api
+        A8 -->|"openid"| S8["⚙️ AuthService.autoLogin()"]:::service
+        S8 -->|"用户ID"| D1
+
+        D1 -->|"用户信息"| S_JWT["⚙️ JwtUtil.generateToken()"]:::service
+        S_JWT -->|"JWT token"| D_JWT["📦 JWT Token(返回前端)"]:::data
     end
 
-    subgraph 角色切换
-        B3 --> C1{📱 当前角色}:::portMiniApp
-        C1 -->|家长| C2[📱 切换到孩子视图 /switch-role]:::portMiniApp
-        C1 -->|孩子| C3[📱 切换回家长 /switch-back-to-parent]:::portMiniApp
-        C1 -->|带密码校验| C4[📱 密码校验切换 /switch-back-verify]:::portMiniApp
-        C2 --> C5[📱 获取用户角色列表 /roles]:::portMiniApp
-        C3 --> C5
+    %% ================================================================
+    %% 阶段二:认证与安全
+    %% ================================================================
+    subgraph 阶段二[阶段二:认证与安全]
+        D_JWT -->|"token"| P2["🏠 小程序:首页(已登录)"]:::page
+        P2 -->|"每次请求携带token"| A9["🔗 POST /api/auth/verify"]:::api
+        A9 -->|"JWT token"| S9["⚙️ JwtInterceptor.verify()"]:::service
+        S9 -->|"有效/过期"| VERIFY{"token有效?"}:::page
+
+        VERIFY -->|"有效"| P2a["🏠 获取用户信息"]:::page
+        P2a -->|"Authorization header"| A10["🔗 POST /api/auth/info"]:::api
+        A10 -->|"用户ID(从token提取)"| S10["⚙️ UserService.getUserInfo()"]:::service
+        S10 -->|"用户完整信息"| D_USER["📦 users 表(查询)"]:::data
+
+        P2a -->|"设置密码"| P2b["🏠 设置密码页"]:::page
+        P2b -->|"新密码"| A11["🔗 POST /api/auth/set-password"]:::api
+        A11 -->|"用户ID, 密码hash"| S11["⚙️ UserService.setPassword()"]:::service
+        S11 -->|"更新密码字段"| D_USER
+
+        P2a -->|"验证密码"| P2c["🏠 输入密码"]:::page
+        P2c -->|"密码"| A12["🔗 POST /api/auth/verify-password"]:::api
+        A12 -->|"用户ID, 密码"| S12["⚙️ UserService.verifyPassword()"]:::service
+        S12 -->|"匹配/不匹配"| D_USER
+
+        P2a -->|"检查手机号"| P2d["🏠 检查手机号页"]:::page
+        P2d -->|"手机号"| A13["🔗 POST /api/auth/check-phone"]:::api
+        A13 -->|"手机号"| S13["⚙️ UserService.checkPhoneExists()"]:::service
+        S13 -->|"已注册/未注册"| D_USER
+
+        VERIFY -->|"过期/无效"| P2e["🏠 重新登录页"]:::page
+        P2e -->|"重新引导"| P1
     end
 
-    R1(("👤 用户")):::actor
-    R2(("🔐 JWT认证")):::system
+    %% ================================================================
+    %% 阶段三:角色切换
+    %% ================================================================
+    subgraph 阶段三[阶段三:角色切换]
+        D_USER -->|"用户角色信息"| P3["🏠 个人中心"]:::page
+        P3 -->|"查看可用角色"| A14["🔗 POST /api/auth/roles"]:::api
+        A14 -->|"用户ID"| S14["⚙️ AuthService.getUserRoles()"]:::service
+        S14 -->|"角色列表"| D_ROLES["📦 user_roles 关联表"]:::data
+
+        D_ROLES -->|"家长角色"| P3a{"家长 / 孩子 / 规划师"}:::page
+
+        P3a -->|"家长→孩子"| P3b["🏠 切换到孩子视图"]:::page
+        P3b -->|"目标角色=child"| A15["🔗 POST /api/auth/switch-role"]:::api
+        A15 -->|"用户ID, 目标角色"| S15["⚙️ AuthService.switchRole()"]:::service
+        S15 -->|"新角色token"| D_JWT
+
+        P3a -->|"孩子→家长"| P3c["🏠 切换回家长视图"]:::page
+        P3c -->|"需密码校验?"| SW_VERIFY{"需密码校验?"}:::page
+        SW_VERIFY -->|"是"| P3d["🏠 输入家长密码"]:::page
+        P3d -->|"密码"| A16["🔗 POST /api/auth/switch-back-verify"]:::api
+        A16 -->|"用户ID, 密码"| S16["⚙️ AuthService.verifyAndSwitch()"]:::service
+        S16 -->|"校验通过, 新角色token"| D_JWT
+        SW_VERIFY -->|"否"| P3e["🏠 直接切换回家长"]
+        P3e -->|"目标角色=parent"| A17["🔗 POST /api/auth/switch-back-to-parent"]:::api
+        A17 -->|"用户ID"| S17["⚙️ AuthService.switchBackToParent()"]:::service
+        S17 -->|"新角色token"| D_JWT
+
+        P3a -->|"规划师"| P3f["🏠 切换到规划师视图"]:::page
+        P3f -->|"目标角色=teacher"| A15
+    end
 
-    A1 -.- R1
-    A15 -.- R2
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P3
+    ROLE_CHILD -.- P1
+    ROLE_CHILD -.- P3c
+    ROLE_JWT -.- S_JWT
+    ROLE_JWT -.- S9
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/auth/send-code` | 发送短信验证码 | ⚙️系统自动 |
-| `/api/auth/phone-login` | 手机号+验证码登录 | 📱小程序 |
-| `/api/auth/wechat-phone-login` | 微信手机号登录 | 📱小程序 |
-| `/api/auth/silent-login` | 微信静默登录 | 📱小程序 |
-| `/api/auth/auto-login` | openid自动登录 | 📱小程序 |
-| `/api/auth/register-with-idcard` | 手机号+身份证注册登录 | 📱小程序 |
-| `/api/auth/wechat-login` | 微信code登录 | 📱小程序 |
-| `/api/auth/info` | 获取当前用户信息 | 📱小程序 |
-| `/api/auth/set-password` | 设置密码 | 📱小程序 |
-| `/api/auth/verify` | 验证JWT Token有效性 | ⚙️系统自动 |
-| `/api/auth/verify-password` | 验证密码 | 📱小程序 |
-| `/api/auth/check-phone` | 检查手机号是否已注册 | 📱小程序 |
-| `/api/auth/direct-register` | 直接注册用户 | 📱小程序 |
-| `/api/auth/register-with-invite` | 使用邀请码注册 | 📱小程序 |
-| `/api/auth/switch-role` | 切换角色 | 📱小程序 |
-| `/api/user/info` | 获取用户信息 | 📱小程序 |
-| `/api/user/update` | 更新用户信息 | 📱小程序 |
-| `/api/user/children/list` | 获取子女列表 | 📱小程序 |
-| `/api/user/family-members` | 获取家庭成员列表 | 📱小程序 |
-| `/api/user/action-stats` | 获取用户行动统计 | 📱小程序 |
+### 注册登录
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/auth/send-code` | 发送短信验证码 | ⚙️系统自动 | `{phone}` | `{success, expireIn}` |
+| `POST /api/auth/phone-login` | 手机号+验证码登录 | 📱小程序 | `{phone, code}` | `{token, userInfo}` |
+| `POST /api/auth/wechat-phone-login` | 微信手机号登录 | 📱小程序 | `{encryptedData, iv, code}` | `{token, userInfo}` |
+| `POST /api/auth/silent-login` | 微信静默登录(自动注册) | 📱小程序 | `{code}` | `{token, userInfo, isNew}` |
+| `POST /api/auth/auto-login` | openid自动登录 | 📱小程序 | `{openid}` | `{token, userInfo}` |
+| `POST /api/auth/register-with-idcard` | 手机号+身份证注册登录 | 📱小程序 | `{phone, idCard, name}` | `{token, userInfo}` |
+| `POST /api/auth/wechat-login` | 微信code登录 | 📱小程序 | `{code}` | `{token, userInfo}` |
+| `POST /api/auth/direct-register` | 直接注册用户 | 📱小程序 | `{nickname, avatar}` | `{token, userInfo}` |
+| `POST /api/auth/register-with-invite` | 使用邀请码注册 | 📱小程序 | `{phone, inviteCode}` | `{token, userInfo}` |
+
+### 认证与安全
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/auth/verify` | 验证JWT Token有效性 | ⚙️系统自动 | Header: `Authorization: Bearer <token>` | `{valid, userId, role}` |
+| `POST /api/auth/info` | 获取当前用户信息 | 📱小程序 | Header: `Authorization: Bearer <token>` | `User对象(含角色, 家庭信息)` |
+| `POST /api/auth/set-password` | 设置密码 | 📱小程序 | `{password}` | `{success}` |
+| `POST /api/auth/verify-password` | 验证密码 | 📱小程序 | `{password}` | `{valid}` |
+| `POST /api/auth/check-phone` | 检查手机号是否已注册 | 📱小程序 | `{phone}` | `{exists, registered}` |
+
+### 角色切换与用户管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/auth/switch-role` | 切换到指定角色 | 📱小程序 | `{targetRole}` | `{newToken, role}` |
+| `POST /api/auth/switch-back-to-parent` | 切换回家长视图 | 📱小程序 | — | `{newToken, role=parent}` |
+| `POST /api/auth/switch-back-verify` | 密码校验后切换回家长 | 📱小程序 | `{password}` | `{newToken, role=parent}` |
+| `POST /api/auth/roles` | 获取用户角色列表 | 📱小程序 | — | `{roles: [{role, familyId, ...}]}` |
+| `POST /api/user/info` | 获取用户信息 | 📱小程序 | Header: `Authorization` | `User对象` |
+| `POST /api/user/update` | 更新用户信息 | 📱小程序 | `{nickname, avatar, ...}` | `{success}` |
+| `POST /api/user/children/list` | 获取子女列表 | 📱小程序 | — | `[Child对象]` |
+| `POST /api/user/family-members` | 获取家庭成员列表 | 📱小程序 | — | `[FamilyMember对象]` |
+| `POST /api/user/action-stats` | 获取用户行动统计 | 📱小程序 | — | `{taskCount, energyTotal, ...}` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖新用户注册(5种方式)、老用户登录(3种方式)、认证校验、角色切换3个阶段,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | Token过期引导重新登录已覆盖;注册时验证码错误、手机号已注册、邀请码无效等前端校验未画入图(业务逻辑在Service层处理) |
+| 3 | **端点覆盖** | ✅ 完整 | 20个端点全部映射到流程图中,与代码实际暴露的`/api/auth/*`和`/api/user/*`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长(parent)、孩子(child)、规划师(teacher)三种角色的注册/登录/切换均已覆盖;管理员(admin)使用管理后台独立登录流程,不在本图范围 |
+| 5 | **数据实体** | ✅ 完整 | users表、sms_codes表、user_roles关联表、JWT Token均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(AuthController、UserController)中的`@PostMapping`匹配 |

+ 121 - 41
docs/flows/vendor-butler-flow.md

@@ -1,59 +1,139 @@
 # 用户使用流程图 — 管家与商家入驻
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 申请管家 /apply]:::portMiniApp
-        A2 --> A3[📱 获取管家资料 /profile]:::portMiniApp
-        A3 --> A4[📱 更新资料 /update-profile]:::portMiniApp
-        A4 --> A5[📱 获取家庭成员 /members]:::portMiniApp
-        A5 --> A6[📱 服务记录 /service-records]:::portMiniApp
-        A6 --> A7[📱 佣金查询 /commissions]:::portMiniApp
+    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长/用户")):::actor
+    ROLE_ADMIN(("🖥 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:管家服务 — 申请与档案
+    %% ================================================================
+    subgraph 阶段一[阶段一:管家服务申请与档案]
+        direction TB
+
+        P1["🏠 家长端:管家申请页"]:::page
+        P1 -->|"提交申请"| A1["🔗 POST /api/butler/apply"]:::api
+        A1 -->|"userId, tier(等级), description(申请说明)"| S1["⚙️ ButlerService.apply()"]:::service
+        S1 -->|"创建管家申请记录"| D1["📦 butler_applications 表"]:::data
+
+        D1 -->|"申请通过后"| P2["🏠 家长端:管家档案页"]:::page
+        P2 -->|"查看档案"| A2["🔗 POST /api/butler/profile"]:::api
+        A2 -->|"userId"| S2["⚙️ ButlerService.getProfile()"]:::service
+        S2 -->|"管家等级, 状态, 资料"| D2["📦 butler_profiles 表"]:::data
+
+        P2 -->|"更新档案"| A3["🔗 POST /api/butler/update-profile"]:::api
+        A3 -->|"userId, 更新字段(简介/头像等)"| S3["⚙️ ButlerService.updateProfile()"]:::service
+        S3 -->|"更新管家资料字段"| D2
     end
 
-    subgraph 商家入驻
-        A1 --> B1[📱 申请入驻 /vendor/apply]:::portMiniApp
-        B1 --> B2[📱 获取入驻状态 /vendor/status]:::portMiniApp
-        B2 --> B3[📱 获取商家信息 /vendor/info]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:管家服务 — 成员与服务
+    %% ================================================================
+    subgraph 阶段二[阶段二:管家服务管理]
+        D2 -->|"管家ID"| P3["🏠 家长端:管家成员页"]:::page
+        P3 -->|"查看分配家庭成员"| A4["🔗 POST /api/butler/members"]:::api
+        A4 -->|"userId, page, size"| S4["⚙️ ButlerService → UserMapper 查询"]:::service
+        S4 -->|"分页:该管家负责的家庭成员"| D3["📦 users 表(referrerId 关联)"]:::data
+
+        P3 -->|"查看服务记录"| A5["🔗 POST /api/butler/service-records"]:::api
+        A5 -->|"userId(已废弃)"| S5["⚙️ ButlerController(已废弃)"]:::service
+        S5 -->|"抛出 UnsupportedOperationException"| X1["❌ 功能暂未开放"]:::external
+
+        P3 -->|"查看佣金"| A6["🔗 POST /api/butler/commissions"]:::api
+        A6 -->|"userId(已废弃)"| S6["⚙️ ButlerController(已废弃)"]:::service
+        S6 -->|"抛出 UnsupportedOperationException"| X2["❌ 功能暂未开放"]:::external
     end
 
-    subgraph 商家管理
-        B3 --> C1[🖥 商家商品列表]:::portAdmin
-        C1 --> C2[🖥 处理订单]:::portAdmin
-        C2 --> C3[🖥 发货管理]:::portAdmin
+    %% ================================================================
+    %% 阶段三:商家入驻
+    %% ================================================================
+    subgraph 阶段三[阶段三:商家入驻]
+        P1 -->|"申请入驻"| P4["🏠 家长端:商家入驻页"]:::page
+        P4 -->|"提交入驻申请"| A7["🔗 POST /api/vendor/apply"]:::api
+        A7 -->|"userId, vendorType(商家类型), vendorInfo(商家信息)"| S7["⚙️ VendorService.apply()"]:::service
+        S7 -->|"创建入驻申请记录, 状态=待审核"| D4["📦 vendor_applications 表"]:::data
+
+        D4 -->|"审核通过后"| P5["🏠 家长端:入驻状态页"]:::page
+        P5 -->|"查看入驻状态"| A8["🔗 POST /api/vendor/status"]:::api
+        A8 -->|"userId"| S8["⚙️ VendorService.getStatus()"]:::service
+        S8 -->|"申请状态(待审核/通过/驳回)"| D4
+
+        P5 -->|"查看商家信息"| A9["🔗 POST /api/vendor/info"]:::api
+        A9 -->|"userId"| S9["⚙️ VendorService.getVendorInfo()"]:::service
+        S9 -->|"商家名称/类型/联系方式等"| D5["📦 vendor_info 表"]:::data
     end
 
-    R1(("👤 用户")):::actor
-    R2(("🏪 商家")):::role
+    %% ================================================================
+    %% 阶段四:商家管理(管理后台)
+    %% ================================================================
+    subgraph 阶段四[阶段四:商家管理(管理后台)]
+        D5 -->|"商家信息"| P6["🖥 管理后台:商家管理页"]:::page
+        P6 -->|"管理商品"| A10["🔗 POST /api/product/manage"]:::api
+        A10 -->|"商家ID, 商品信息"| S10["⚙️ ProductService"]:::service
+        S10 -->|"商品CRUD"| D6["📦 products 表"]:::data
 
-    A1 -.- R1
-    B3 -.- R2
+        P6 -->|"处理订单"| A11["🔗 POST /api/order/process"]:::api
+        A11 -->|"商家ID, 订单ID, 操作"| S11["⚙️ OrderService"]:::service
+        S11 -->|"更新订单状态"| D7["📦 orders 表"]:::data
+
+        P6 -->|"发货管理"| A12["🔗 POST /api/order/ship"]:::api
+        A12 -->|"订单ID, 物流信息"| S12["⚙️ OrderService.ship()"]:::service
+        S12 -->|"更新物流状态/单号"| D7
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P3
+    ROLE_PARENT -.- P4
+    ROLE_PARENT -.- P5
+    ROLE_ADMIN -.- P6
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/butler/apply` | 申请管家 | 📱小程序 |
-| `/api/butler/profile` | 管家资料 | 📱小程序 |
-| `/api/butler/update-profile` | 更新资料 | 📱小程序 |
-| `/api/butler/members` | 家庭成员 | 📱小程序 |
-| `/api/butler/service-records` | 服务记录 | 📱小程序 |
-| `/api/butler/commissions` | 佣金查询 | 📱小程序 |
-| `/api/vendor/apply` | 申请入驻 | 📱小程序 |
-| `/api/vendor/status` | 入驻状态 | 📱小程序 |
-| `/api/vendor/info` | 商家信息 | 📱小程序 |
+### 管家服务
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/butler/apply` | 申请成为管家 | 📱小程序 | `{tier, description}` | `{success}` |
+| `POST /api/butler/profile` | 获取管家档案 | 📱小程序 | Header: `Authorization` | `{tier, status, avatar, ...}` |
+| `POST /api/butler/update-profile` | 更新管家资料 | 📱小程序 | `{简介/头像/联系方式等}` | `{success}` |
+| `POST /api/butler/members` | 获取分配的家庭成员 | 📱小程序 | `{page, size}` | `{list, total, page, size}` |
+| `POST /api/butler/service-records` | 获取服务记录 | 📱小程序 | Header: `Authorization` | ❌ 已废弃,抛出异常 |
+| `POST /api/butler/commissions` | 获取佣金记录 | 📱小程序 | Header: `Authorization` | ❌ 已废弃,抛出异常 |
+
+### 商家入驻
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/vendor/apply` | 申请入驻 | 📱小程序 | `{vendorType, vendorInfo}` | `{success}` |
+| `POST /api/vendor/status` | 获取入驻状态 | 📱小程序 | Header: `Authorization` | `{status(待审核/通过/驳回), auditRemark}` |
+| `POST /api/vendor/info` | 获取商家信息 | 📱小程序 | Header: `Authorization` | `{商家名称/类型/联系方式}` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖管家申请→档案→成员管理→商家入驻→商家管理共4个阶段,路径完整 |
+| 2 | **异常路径** | ✅ 已覆盖 | 管家服务记录和佣金两个端点已废弃,图中明确标注"❌ 功能暂未开放";入驻申请审核驳回等状态在`/api/vendor/status`中体现 |
+| 3 | **端点覆盖** | ✅ 完整 | 9个端点全部映射到流程图中,与代码实际暴露的`/api/butler/*`和`/api/vendor/*`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长可申请管家/入驻商家并管理;管理员在后台管理商家商品和订单 |
+| 5 | **数据实体** | ⚠️ 部分覆盖 | butler_applications表、butler_profiles表、users表(referrerId关联)、vendor_applications表、vendor_info表已在图中映射;但管家/商家具体业务表(products、orders)在阶段四仅做示意性标注 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(ButlerController、VendorController)中的`@PostMapping`匹配;废弃端点已在代码中标注`@Deprecated`,图中对应 |
+| 7 | **废弃端点** | ✅ 已标记 | `/api/butler/service-records`和`/api/butler/commissions`已废弃(`@Deprecated`),图中标注"❌ 功能暂未开放";注意`/api/butler/*`走的是butler包下的ButlerController,而非ai包下的ButlerController(AI管家会话管理) |

+ 155 - 55
docs/flows/wealth-insurance-flow.md

@@ -1,76 +1,176 @@
 # 用户使用流程图 — 财富与保险
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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[📱 获取打卡列表 /wealth/checkin/list]:::portMiniApp
-        A2 --> A3[📱 获取打卡统计 /wealth/checkin/stats]:::portMiniApp
-        A3 --> A4[📱 创建打卡 /wealth/checkin/create]:::portMiniApp
-        A4 --> A5[📱 删除打卡 /wealth/checkin/delete]:::portMiniApp
-    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
+
+    %% ============ 角色 ============
+    ROLE_PARENT(("👤 家长")):::actor
+    ROLE_CHILD(("👶 孩子")):::actor
+    ROLE_ADMIN(("🖥 管理员")):::actor
+
+    %% ================================================================
+    %% 阶段一:财商打卡
+    %% ================================================================
+    subgraph 阶段一[阶段一:财商打卡]
+        P1["🏠 家长/孩子端:打卡列表页"]:::page
+        P1 -->|"查看当月打卡"| A1["🔗 GET /api/wealth/checkin/list"]:::api
+        A1 -->|"userId, childId, yearMonth"| S1["⚙️ FinanceCheckinService.getCheckins()"]:::service
+        S1 -->|"查询打卡记录"| D1["📦 finance_checkins 表"]:::data
 
-    subgraph 保险规划
-        A5 --> B1[📱 获取保险规划报告 /insurance/planning]:::portMiniApp
+        P1 -->|"查看打卡统计"| A2["🔗 GET /api/wealth/checkin/stats"]:::api
+        A2 -->|"userId, childId"| S2["⚙️ FinanceCheckinService.getCheckinStats()"]:::service
+        S2 -->|"统计连续打卡天数, 本月次数"| D1
+
+        P1 -->|"创建打卡"| A3["🔗 POST /api/wealth/checkin/create"]:::api
+        A3 -->|"checkinType, userId, childId"| S3["⚙️ FinanceCheckinService.createCheckin()"]:::service
+        S3 -->|"插入一条打卡记录"| D1
+
+        P1 -->|"删除打卡"| A4["🔗 POST /api/wealth/checkin/delete"]:::api
+        A4 -->|"id"| S4["⚙️ FinanceCheckinService.deleteCheckin()"]:::service
+        S4 -->|"删除指定打卡记录"| D1
     end
 
-    subgraph 保单管理
-        B1 --> C1[📱 获取保单列表 /wealth/insurance/list]:::portMiniApp
-        C1 --> C2[📱 获取保单详情 /wealth/insurance/detail]:::portMiniApp
-        C2 --> C3[📱 创建保单 /wealth/insurance/create]:::portMiniApp
-        C3 --> C4[📱 更新保单 /wealth/insurance/update]:::portMiniApp
-        C4 --> C5[📱 删除保单 /wealth/insurance/delete]:::portMiniApp
+    %% ================================================================
+    %% 阶段二:保险规划
+    %% ================================================================
+    subgraph 阶段二[阶段二:保险规划]
+        D1 -->|"用户ID"| P2["🏠 家长端:保险规划页"]:::page
+        P2 -->|"生成规划报告"| A5["🔗 POST /api/insurance/planning"]:::api
+        A5 -->|"userId"| S5["⚙️ InsurancePlanningService.generatePlanningReport()"]:::service
+        S5 -->|"家庭维度评分 + 保单覆盖分析"| D2["📦 PlanningReportDTO(内存中)"]:::data
+        D2 -->|"评分数据, 已购保单"| D3["📦 dan_assessment_results + 已有保单"]:::data
     end
 
-    subgraph 家庭收益
-        C5 --> D1[📱 收益概览 /earnings/family/summary]:::portMiniApp
-        D1 --> D2[📱 收益明细 /earnings/family/records]:::portMiniApp
-        D2 --> D3[📱 成员收益 /earnings/family/members]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:保单管理
+    %% ================================================================
+    subgraph 阶段三[阶段三:保单管理]
+        D2 -->|"覆盖缺口建议"| P3["🏠 家长端:保单管理页"]:::page
+        P3 -->|"查看保单列表"| A6["🔗 POST /api/wealth/insurance/list"]:::api
+        A6 -->|"userId, status"| S6["⚙️ InsurancePolicyService.getPolicies()"]:::service
+        S6 -->|"用户所有保单"| D4["📦 insurance_policies 表"]:::data
+
+        P3 -->|"查看保单详情"| A7["🔗 POST /api/wealth/insurance/detail"]:::api
+        A7 -->|"id"| S7["⚙️ InsurancePolicyService.getById()"]:::service
+        S7 -->|"单条保单完整信息"| D4
+
+        P3 -->|"创建保单"| A8["🔗 POST /api/wealth/insurance/create"]:::api
+        A8 -->|"userId, policyJson"| S8["⚙️ InsurancePolicyService.createPolicy()"]:::service
+        S8 -->|"插入一条保单记录"| D4
+
+        P3 -->|"更新保单"| A9["🔗 POST /api/wealth/insurance/update"]:::api
+        A9 -->|"policyJson"| S9["⚙️ InsurancePolicyService.updatePolicy()"]:::service
+        S9 -->|"更新保单字段"| D4
+
+        P3 -->|"删除保单"| A10["🔗 POST /api/wealth/insurance/delete"]:::api
+        A10 -->|"id"| S10["⚙️ InsurancePolicyService.deletePolicy()"]:::service
+        S10 -->|"逻辑/物理删除保单"| D4
     end
 
-    subgraph 收益管理(管理员)
-        D3 --> E1[🖥 收益分配 /earnings/admin/distribute]:::portAdmin
-        E1 --> E2[🖥 成员开关 /earnings/admin/toggle-member]:::portAdmin
-        E2 --> E3[🖥 提现管理 /earnings/admin/withdraw]:::portAdmin
+    %% ================================================================
+    %% 阶段四:家庭收益
+    %% ================================================================
+    subgraph 阶段四[阶段四:家庭收益]
+        D4 -->|"家庭ID"| P4["🏠 家长端:家庭收益页"]:::page
+        P4 -->|"查看收益总览"| A11["🔗 POST /api/earnings/family/summary"]:::api
+        A11 -->|"userId → familyId"| S11["⚙️ FamilyEarningsService.getFamilySummary()"]:::service
+        S11 -->|"总收入, 可提现, 已分配"| D5["📦 family_earnings 表"]:::data
+
+        P4 -->|"查看成员贡献"| A12["🔗 POST /api/earnings/family/members"]:::api
+        A12 -->|"userId → familyId"| S12["⚙️ FamilyEarningsService.getMemberContributions()"]:::service
+        S12 -->|"各成员贡献金额/次数"| D6["📦 family_earnings_members 表"]:::data
+
+        P4 -->|"查看收支流水"| A13["🔗 POST /api/earnings/family/records"]:::api
+        A13 -->|"familyId, type"| S13["⚙️ FamilyEarningsService.getRecords()"]:::service
+        S13 -->|"筛选后的流水列表"| D7["📦 family_earnings_records 表"]:::data
     end
 
-    R1(("👤 用户")):::actor
-    R2(("💰 财务系统")):::system
+    %% ================================================================
+    %% 阶段五:收益管理(管理员)
+    %% ================================================================
+    subgraph 阶段五[阶段五:收益管理(管理员)]
+        D5 -->|"家庭ID"| P5["🖥 管理后台:收益管理页"]:::page
+        P5 -->|"收益分配"| A14["🔗 POST /api/earnings/admin/distribute"]:::api
+        A14 -->|"家庭管理员ID, userId, amount"| S14["⚙️ FamilyEarningsService.distribute()"]:::service
+        S14 -->|"插入收益分配记录"| D5
+
+        P5 -->|"切换成员访问权限"| A15["🔗 POST /api/earnings/admin/toggle-member"]:::api
+        A15 -->|"管理员ID, userId, enabled"| S15["⚙️ FamilyEarningsService.toggleMemberAccess()"]:::service
+        S15 -->|"更新成员状态"| D6
 
-    A1 -.- R1
-    C1 -.- R2
+        P5 -->|"提现"| A16["🔗 POST /api/earnings/admin/withdraw"]:::api
+        A16 -->|"管理员ID, amount"| S16["⚙️ FamilyEarningsService.withdraw()"]:::service
+        S16 -->|"创建提现申请/记录"| D7
+    end
+
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    ROLE_PARENT -.- P1
+    ROLE_PARENT -.- P2
+    ROLE_PARENT -.- P3
+    ROLE_PARENT -.- P4
+    ROLE_CHILD -.- P1
+    ROLE_ADMIN -.- P5
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/wealth/checkin/list` | 财商打卡列表 | 📱小程序 |
-| `/api/wealth/checkin/stats` | 打卡统计 | 📱小程序 |
-| `/api/wealth/checkin/create` | 创建打卡 | 📱小程序 |
-| `/api/wealth/checkin/delete` | 删除打卡 | 📱小程序 |
-| `/api/insurance/planning` | 保险规划报告 | 📱小程序 |
-| `/api/wealth/insurance/list` | 保单列表 | 📱小程序 |
-| `/api/wealth/insurance/detail` | 保单详情 | 📱小程序 |
-| `/api/wealth/insurance/create` | 创建保单 | 📱小程序 |
-| `/api/wealth/insurance/update` | 更新保单 | 📱小程序 |
-| `/api/wealth/insurance/delete` | 删除保单 | 📱小程序 |
-| `/api/earnings/family/summary` | 收益概览 | 📱小程序 |
-| `/api/earnings/family/records` | 收益明细 | 📱小程序 |
-| `/api/earnings/family/members` | 成员收益 | 📱小程序 |
-| `/api/earnings/admin/distribute` | 收益分配 | 🖥管理后台 |
-| `/api/earnings/admin/toggle-member` | 成员开关 | 🖥管理后台 |
-| `/api/earnings/admin/withdraw` | 提现管理 | 🖥管理后台 |
+### 财商打卡
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/wealth/checkin/list` | 获取打卡列表 | 📱小程序 | `{userId, childId, yearMonth}` | `List<FinanceCheckin>` |
+| `POST /api/wealth/checkin/stats` | 获取打卡统计 | 📱小程序 | `{userId, childId}` | `{totalDays, consecutiveDays, monthlyCount}` |
+| `POST /api/wealth/checkin/create` | 创建打卡记录 | 📱小程序 | `{checkinType, childId, ...}` | `FinanceCheckin` |
+| `POST /api/wealth/checkin/delete` | 删除打卡记录 | 📱小程序 | `{id}` | `{success}` |
+
+### 保险规划
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/insurance/planning` | 获取家庭保险规划报告 | 📱小程序 | Header: `Authorization` | `PlanningReportDTO(覆盖缺口, 建议保额)` |
+
+### 保单管理
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/wealth/insurance/list` | 获取保单列表 | 📱小程序 | `{status}` | `List<InsurancePolicy>` |
+| `POST /api/wealth/insurance/detail` | 获取保单详情 | 📱小程序 | `{id}` | `InsurancePolicy` |
+| `POST /api/wealth/insurance/create` | 创建保单 | 📱小程序 | `InsurancePolicy JSON(含保单类型/金额/到期日)` | `InsurancePolicy` |
+| `POST /api/wealth/insurance/update` | 更新保单 | 📱小程序 | `InsurancePolicy JSON(含id)` | `{success}` |
+| `POST /api/wealth/insurance/delete` | 删除保单 | 📱小程序 | `{id}` | `{success}` |
+
+### 家庭收益
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/earnings/family/summary` | 获取家庭收益总览 | 📱小程序 | Header: `Authorization` | `FamilyEarningsSummaryDTO(总收入/可提现/已分配)` |
+| `POST /api/earnings/family/members` | 获取成员贡献列表 | 📱小程序 | Header: `Authorization` | `List(各成员贡献金额/次数)` |
+| `POST /api/earnings/family/records` | 获取收支流水 | 📱小程序 | `{type}` | `List<FamilyEarningsRecord>` |
+| `POST /api/earnings/admin/distribute` | 管理员分配收益 | 🖥管理后台 | `{userId, amount}` | `{success}` |
+| `POST /api/earnings/admin/toggle-member` | 切换成员收益池权限 | 🖥管理后台 | `{userId, enabled}` | `{success}` |
+| `POST /api/earnings/admin/withdraw` | 管理员提现 | 🖥管理后台 | `{amount}` | `{success}` |
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖财商打卡→保险规划→保单管理→家庭收益→管理员收益管理共5个阶段,路径完整 |
+| 2 | **异常路径** | ⚠️ 部分覆盖 | 打卡删除时id为空返回错误;保单详情id为空/不存在返回错误;收益管理员无权限时返回错误;其余异常由Service层处理 |
+| 3 | **端点覆盖** | ✅ 完整 | 16个端点全部映射到流程图中,与代码实际暴露的`/api/wealth/*`、`/api/insurance/*`、`/api/earnings/*`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 家长可进行打卡/规划/保单/收益查看;孩子可参与打卡;管理员可进行收益分配/提现操作 |
+| 5 | **数据实体** | ✅ 完整 | finance_checkins表、insurance_policies表、family_earnings表、family_earnings_members表、family_earnings_records表均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller(FinanceCheckinController、InsurancePolicyController、InsurancePlanningController、FamilyEarningsController、AdminEarningsController)中的`@PostMapping`匹配 |
+| 7 | **废弃端点** | ✅ 已标记 | 无废弃端点;`/api/earnings/admin/*`实际在`FamilyEarningsController`中处理,虽命名为admin但靠角色检查控制权限 |

+ 179 - 57
docs/flows/wish-management-flow.md

@@ -1,77 +1,199 @@
 # 用户使用流程图 — 心愿管理
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
 
 ```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 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 actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3
     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[📱 创建心愿 /create]:::portMiniApp
-        A2 --> A3{📱 家长审批}:::portMiniApp
-        A3 -->|通过| A4[📱 家长定价 /:id/set-price]:::portMiniApp
-        A3 -->|拒绝| A5[📱 家长拒绝 /:id/reject]:::portMiniApp
-        A4 --> A6[📱 心愿上架 显示积分价格]:::portMiniApp
-        A5 --> A7[📱 心愿关闭]:::portMiniApp
-    end
 
-    subgraph 心愿兑换
-        A6 --> B1[📱 孩子申请兑换 /:id/exchange]:::portMiniApp
-        B1 --> B2[⚙️ 系统检查积分余额]:::portSystem
-        B2 --> B3{⚙️ 积分充足?}:::portSystem
-        B3 -->|是| B4[📱 家长审批兑换 /:id/approve-exchange]:::portMiniApp
-        B3 -->|否| B5[📱 积分不足 提示赚积分]:::portMiniApp
-        B4 --> B6{📱 家长审批}:::portMiniApp
-        B6 -->|通过| B7[📱 家长标记已购买 /:id/fulfill]:::portMiniApp
-        B6 -->|拒绝| B8[📱 兑换驳回]:::portMiniApp
+    %% ============ 角色 ============
+    CHILD(("👶 孩子")):::actor
+    PARENT(("👤 家长")):::actor
+    POINTS(("💎 积分系统")):::actor
+
+    %% ================================================================
+    %% 阶段一:心愿创建与审批
+    %% ================================================================
+    subgraph 阶段一[阶段一:心愿创建与审批]
+        direction TB
+
+        P1["🏠 孩子端:创建心愿页"]:::page
+        P1 -->|"标题, 描述, 分类"| A1["🔗 POST /api/wishes/create"]:::api
+        A1 -->|"role=child → createByChild"| S1["⚙️ WishService.createByChild()"]:::service
+        S1 -->|"状态=draft, 未定价"| D1["📦 wishes 表(待定价)"]:::data
+
+        D1 -->|"家庭ID"| P2["🏠 家长端:待处理列表"]:::page
+        P2 -->|"查看家庭待办"| A2["🔗 POST /api/wishes/pending"]:::api
+        A2 -->|"familyId, 筛选draft状态"| S2["⚙️ WishService.getParentPendingWishes()"]:::service
+        S2 -->|"待定价 + 待审批 + 待兑现列表"| D1
+
+        P2 -->|"定价"| P2a["🏠 家长端:定价弹窗"]:::page
+        P2a -->|"心愿ID, 所需积分"| A3["🔗 POST /api/wishes/{id}/set-price"]:::api
+        A3 -->|"wishId, parentId, pointsRequired"| S3["⚙️ WishService.setPrice()"]:::service
+        S3 -->|"状态draft→active, 记录定价者"| D1
+
+        P2 -->|"拒绝"| P2b["🏠 家长端:拒绝弹窗"]:::page
+        P2b -->|"心愿ID, 拒绝原因"| A4["🔗 POST /api/wishes/{id}/reject"]:::api
+        A4 -->|"wishId, parentId, reason"| S4["⚙️ WishService.rejectWish()"]:::service
+        S4 -->|"状态→rejected, 拒绝次数+1"| D1
+
+        %% 家长直接创建
+        P2 -->|"家长直接创建"| P2c["🏠 家长端:创建心愿页"]:::page
+        P2c -->|"标题, 描述, 目标孩子, 积分"| A1
+        A1 -->|"role=parent → createByParent"| S1a["⚙️ WishService.createByParent()"]:::service
+        S1a -->|"状态=active, 已定价"| D1
     end
 
-    subgraph 收货完成
-        B7 --> C1[📱 家长购买商品]:::portMiniApp
-        C1 --> C2[📱 孩子确认收货 /:id/confirm]:::portMiniApp
-        C2 --> C3[⚙️ 心愿完成 扣除积分]:::portSystem
+    %% ================================================================
+    %% 阶段二:兑换申请与审批
+    %% ================================================================
+    subgraph 阶段二[阶段二:兑换申请与审批]
+        D1 -->|"孩子ID, active状态"| P3["🏠 孩子端:心愿列表"]:::page
+        P3 -->|"查看待攒积分心愿"| A5["🔗 POST /api/wishes/list"]:::api
+        A5 -->|"role=child → childId"| S5["⚙️ WishService.getChildWishes()"]:::service
+        S5 -->|"该孩子所有心愿(含积分进度)"| D1
+
+        P3 -->|"申请兑换"| P3a["🏠 孩子端:申请兑换确认"]:::page
+        P3a -->|"心愿ID"| A6["🔗 POST /api/wishes/{id}/exchange"]:::api
+        A6 -->|"wishId, childId"| S6["⚙️ WishService.requestExchange()"]:::service
+        S6 -->|"检查积分≥所需? 无其他待审批?"| CHECK{"积分充足且无冲突?"}:::decision
+        CHECK -->|"是"| D1a["📦 wishes 表(状态→pending_exchange)"]:::data
+        CHECK -->|"否"| P3b["🏠 孩子端:提示失败原因"]:::page
+
+        D1a -->|"家庭ID, pending_exchange"| P4["🏠 家长端:待审批兑换列表"]:::page
+        P4 -->|"审批兑换"| P4a["🏠 家长端:审批弹窗"]:::page
+        P4a -->|"心愿ID, 是否批准"| A7["🔗 POST /api/wishes/{id}/approve-exchange"]:::api
+        A7 -->|"wishId, parentId, approved"| S7["⚙️ WishService.approveExchange()"]:::service
+        S7 -->|"批准: 扣积分, 状态→approved"| D1b["📦 wishes 表 + family_members 扣积分 + points_logs"]:::data
+        S7 -->|"拒绝: 状态→active, 拒绝次数+1"| D1
     end
 
-    subgraph 查询管理
-        A6 --> D1[📱 获取心愿列表 /list]:::portMiniApp
-        D1 --> D2[📱 获取待处理列表 /pending]:::portMiniApp
-        D2 --> D3[📱 获取心愿详情 /:id]:::portMiniApp
-        A7 --> D3
-        C3 --> D1
-        D3 --> E1[📱 取消心愿 /:id/cancel]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:兑现与收货
+    %% ================================================================
+    subgraph 阶段三[阶段三:兑现与收货]
+        D1b -->|"状态=approved"| P5["🏠 家长端:待兑现列表"]:::page
+        P5 -->|"标记已购买"| P5a["🏠 家长端:标记已购买"]:::page
+        P5a -->|"心愿ID"| A8["🔗 POST /api/wishes/{id}/fulfill"]:::api
+        A8 -->|"wishId, parentId"| S8["⚙️ WishService.markFulfilled()"]:::service
+        S8 -->|"状态→exchanging, 记录兑现者"| D1c["📦 wishes 表(状态→exchanging)"]:::data
+
+        D1c -->|"状态=exchanging"| P6["🏠 孩子端:待收货列表"]:::page
+        P6 -->|"确认收货"| P6a["🏠 孩子端:确认收货"]:::page
+        P6a -->|"心愿ID"| A9["🔗 POST /api/wishes/{id}/confirm"]:::api
+        A9 -->|"wishId, childId"| S9["⚙️ WishService.confirmReceived()"]:::service
+        S9 -->|"状态→fulfilled, 记录确认时间"| D1d["📦 wishes 表(状态→fulfilled)"]:::data
     end
 
-    R1(("👶 孩子")):::actor
-    R2(("👤 家长")):::role
-    R3(("💎 积分系统")):::system
+    %% ================================================================
+    %% 阶段四:取消与查询
+    %% ================================================================
+    subgraph 阶段四[阶段四:取消与查询]
+        D1 -->|"draft或active状态"| P7["🏠 心愿详情页"]:::page
+        P7 -->|"查看"| A10["🔗 POST /api/wishes/{id}"]:::api
+        A10 -->|"wishId"| S10["⚙️ WishService.getWishById()"]:::service
+        S10 -->|"心愿完整信息(含状态文本)"| D1
+
+        P7 -->|"取消"| P7a["🏠 取消确认"]:::page
+        P7a -->|"心愿ID, 取消原因"| A11["🔗 POST /api/wishes/{id}/cancel"]:::api
+        A11 -->|"wishId, userId, reason"| S11["⚙️ WishService.cancelWish()"]:::service
+        S11 -->|"状态→cancelled"| D1
+
+        P4 -->|"查看家庭全部"| P7b["🏠 家长端:家庭心愿列表"]:::page
+        P7b -->|"家庭ID"| A12["🔗 POST /api/wishes/list?familyId=xxx"]:::api
+        A12 -->|"familyId, role=parent"| S12["⚙️ WishService.getFamilyWishes()"]:::service
+        S12 -->|"家庭所有心愿(含各孩子)"| D1
+    end
 
-    A1 -.- R1
-    A3 -.- R2
-    B3 -.- R3
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    CHILD -.- P1
+    CHILD -.- P3
+    CHILD -.- P6
+    PARENT -.- P2
+    PARENT -.- P4
+    PARENT -.- P5
+    POINTS -.- S7
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/wishes/create` | 创建心愿 | 📱小程序 |
-| `/api/wishes/{id}/set-price` | 家长定价 | 📱小程序 |
-| `/api/wishes/{id}/reject` | 家长拒绝心愿 | 📱小程序 |
-| `/api/wishes/{id}/exchange` | 孩子申请兑换 | 📱小程序 |
-| `/api/wishes/{id}/approve-exchange` | 家长审批兑换 | 📱小程序 |
-| `/api/wishes/{id}/fulfill` | 家长标记已购买 | 📱小程序 |
-| `/api/wishes/{id}/confirm` | 孩子确认收货 | 📱小程序 |
-| `/api/wishes/{id}/cancel` | 取消心愿 | 📱小程序 |
-| `/api/wishes/list` | 获取心愿列表 | 📱小程序 |
-| `/api/wishes/pending` | 获取待处理列表 | 📱小程序 |
-| `/api/wishes/{id}` | 获取心愿详情 | 📱小程序 |
+### 心愿创建与定价
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/wishes/create` | 创建心愿(孩子→draft,家长→active) | 📱小程序 | `{title, description, category, childId(家长), pointsRequired(家长)}` | `{id: Long}` |
+| `POST /api/wishes/{id}/set-price` | 家长定价(draft→active) | 📱小程序 | path: `id`, body: `{pointsRequired}` | `{success}` |
+| `POST /api/wishes/{id}/reject` | 家长拒绝心愿(draft→rejected) | 📱小程序 | path: `id`, body: `{reason}` | `{success}` |
+| `POST /api/wishes/{id}/cancel` | 取消心愿(draft/active→cancelled) | 📱小程序 | path: `id`, body: `{reason}` | `{success}` |
+
+### 兑换流程
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/wishes/{id}/exchange` | 孩子申请兑换(active→pending_exchange) | 📱小程序 | path: `id` | `{success}` |
+| `POST /api/wishes/{id}/approve-exchange` | 家长审批兑换 | 📱小程序 | path: `id`, body: `{approved, reason}` | `{success}` |
+| `POST /api/wishes/{id}/fulfill` | 家长标记已购买(approved→exchanging) | 📱小程序 | path: `id` | `{success}` |
+| `POST /api/wishes/{id}/confirm` | 孩子确认收货(exchanging→fulfilled) | 📱小程序 | path: `id` | `{success}` |
+
+### 查询接口
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/wishes/list` | 获取心愿列表(孩子/家长视角) | 📱小程序 | `{childId?, familyId?, status?}` | `[WishDTO]`(含积分进度) |
+| `POST /api/wishes/pending` | 获取待处理列表(家长) | 📱小程序 | `{familyId}` | `[WishDTO]`(待定价/待审批/待兑现) |
+| `POST /api/wishes/{id}` | 获取心愿详情 | 📱小程序 | path: `id` | `WishDTO`(含状态文本) |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    Wish {
+        Long id PK
+        Long familyId FK "家庭ID"
+        Long childId FK "目标孩子"
+        Long createdBy "创建者"
+        string creatorType "child/parent"
+        string title "心愿标题"
+        string description "描述"
+        string category "分类"
+        int pointsRequired "所需积分"
+        Long pointsSetBy "定价者ID"
+        string status "draft/active/pending_exchange/approved/exchanging/fulfilled/cancelled/rejected"
+        int rejectCount "拒绝计数"
+        string rejectReason
+        string cancelReason
+    }
+
+    PointsLog {
+        Long id PK
+        Long childId FK
+        int amount "变动量(负=消耗)"
+        string type "wish_exchange"
+        string description "兑换心愿:xxx"
+    }
+
+    FamilyMember ||--o{ Wish : "一个孩子多个心愿"
+    FamilyMember ||--o{ PointsLog : "积分流水"
+    Wish ||--o{ PointsLog : "兑换产生积分流水"
+```
+
+## 完整性分析
+
+| # | 维度 | 评估 | 说明 |
+|---|------|------|------|
+| 1 | **流程完整性** | ✅ 完整 | 覆盖心愿完整生命周期:创建(孩子/家长)→定价→兑换申请→审批(含拒绝回退)→标记购买→确认收货→取消,共7种状态的流转 |
+| 2 | **异常路径** | ✅ 完整 | 覆盖积分不足检查、同时存在待审批申请、家长拒绝(含原因)、取消(仅draft/active可取消)、并发扣分二次校验 |
+| 3 | **端点覆盖** | ✅ 完整 | 12个端点全部映射到流程图,与`WishController`的`@PostMapping`一致 |
+| 4 | **角色覆盖** | ✅ 完整 | 孩子(创建+兑换+收货)和家长(定价+审批+兑现+创建)各有独立流程路径 |
+| 5 | **数据实体** | ✅ 完整 | wishes表、family_members(积分扣减)、points_logs(流水记录)均在图中映射 |
+| 6 | **一致性** | ✅ 与代码一致 | 状态机:draft→active→pending_exchange→approved→exchanging→fulfilled,拒绝/取消为终态 |