# 浠艾福(XAF)后端接口参考文档 > **维护规范:** > 1. 新增接口前必须先查阅本文档,确认是否已有可复用或可修改的接口 > 2. 有相似功能但需调整 → 评估修改成本,必要时新增(标注依赖) > 3. 实在没有 → 才新增接口,并在此文档同步记录 > 4. 废弃接口保留注释,不直接删除,待确认无调用后清理 --- ## 一、接口规范 ### 1.1 统一约定 | 项目 | 规范 | |------|------| | 请求方法 | 统一 `@PostMapping`,禁止 `@GetMapping/@PutMapping/@DeleteMapping`(仅支付回调等第三方 webhook 例外) | | 响应格式 | `Result` — `{ code, message, data }` | | 认证 | JWT Bearer Token,Header: `Authorization: Bearer {token}` | | 角色校验 | Controller 内手动检查 `@RequestAttribute("role")` | | DI | `@Resource`,字段名与 Bean Name 一致 | | 公开路径(免鉴权)| `/api/auth/*`、`/api/config/public/*`、`/api/media/upload`、`/api/articles/*`(部分)| ### 1.2 新增接口检查清单 ```bash # 1. 搜索现有相似接口 grep -rn "功能关键词" cfc-backend/src/main/java/com/etotem/cfc/controller/ --include="*.java" # 2. 检查路由冲突 grep -rn '@PostMapping("' cfc-backend/src/main/java/com/etotem/cfc/controller/ | grep -oP '@\w+Mapping\("\K[^"]*' | sort -u # 3. 检查 Bean 命名冲突(新增 Service/Controller 时) find cfc-backend/src/main/java -name "*XxxService.java" -o -name "*XxxController.java" | xargs grep -l "class Xxx" ``` --- ## 二、Controller 总览 | Controller | 路由前缀 | 说明 | 废弃状态 | |------------|----------|------|----------| | `AuthController` | `/api/auth` | 登录/注册/角色切换 | — | | `UserController` | `/api/user` | 用户信息/头像/吉祥物 | — | | `FamilyController` | `/api/family` | 家庭基础操作 | 部分废弃见下 | | `FamilyMembersController` | `/api/family/member` | 家庭成员 CRUD/切换/可见性 | — | | `FamilyInviteController` | `/api/family/invite` | 邀请码/二维码/申请加入 | — | | `FamilyUserController` | `/api/family/user` | 家长端家庭成员管理 | 部分废弃见下 | | `PointsController` | `/api/points` | 积分余额/流水 | — | | `TaskController` | `/api/tasks` | 任务 CRUD/完成/审核 | — | | `WishController` | `/api/wishes` | 心愿 CRUD/审批/兑换 | — | | `RewardController` | `/api/rewards` | 奖励模板/兑换 | — | | `AssessmentAppointmentController` | `/api/assessment/appointment` | 测评预约 | — | | `DanAssessmentController` | `/api/dan-assessment` | DAN 测评全链路 | — | | `EnergyController` | `/api/energy` | 五维能量概览/流水/配置 | — | | `GrowthController` | `/api/growth` | 成长记录 | — | | `GrowthPlanController` | `/api/growth/plan` | 成长计划 | — | | `HealthCheckinController` | `/api/health/checkin` | 健康打卡(行为记录) | — | | `DailyCheckinController` | `/api/daily/checkin` | 每日健康打卡(饮食/运动/心情) | — | | `EmotionCheckinController` | `/api/mind/checkin` | 情绪日记(心情打卡同步目标) | — | | `HealthStatusController` | `/api/health-status` | 健康现状档案 | — | | `ProductController` | `/api/product` | 商品 | — | | `ProductOrderController` | `/api/product/order` | 商品订单 | — | | `CartController` | `/api/cart` | 购物车 | — | | `MembershipController` | `/api/membership` | 会员 | — | | `SubscriptionController` | `/api/subscription` | 订阅 | — | | `AIChatController` | `/api/ai` | AI 对话 | — | | `InnatePortraitController` | `/api/mind/innate` | 先天画像(画像/AI解读/数字能量/成长轨迹) | — | | `ArticleController` | `/api/articles` | 文章 | — | | `NotificationController` | `/api/notification` | 通知 | — | | `StatsController` | `/api/stats` | 统计 | — | | `CfCommissionController` | `/api/commission/cf` | CF 分佣(团队规模/比例/钱包/流水) | — | | `CfTransferController` | `/api/cf/transfer` | CF 成员间转让 | — | | `CfBalanceController` | `/api/cf` | C 端 CF 查询(余额快照/流水/家庭券,只读) | F-7a | | `AdminCfRateTierController` | `/api/admin/cf-rate-tier` | CF 返佣阶梯配置(admin) | — | | `ContactController` | `/api/contact` | 联系人 CRUD/互动/邀请入家庭 | — | | `ContactMatchController` | `/api/contact/match` | 联系人对接(send/accept/reject/列表) | — | | `OctopusController` | `/api/octopus` | 章鱼图(帮助记录/触手聚合) | — | | `PearlController` | `/api/pearl` | 珍珠图(25 类社会连接聚合 + 互动/提醒/优先级) | — | | `AbilityController` | `/api/ability` | 能力图(SKILL 帮助记录聚合为能力节点) | — | | `ServiceRoleApplicationController` | `/api/service-role` | 统一服务角色申请(多角色合一 + 管理端审批) | — | | `GuideTeamController` | `/api/guide/team` | 规划师团队/邀请码/上下级 | — | | `GuideFamilyTaskController` | `/api/guide/families` | 规划师侧家庭任务管理 + 家庭解绑 | — | | `PlannerCertificationController` | `/api/planner` | 规划师培训认证中心(我的认证/课程/线下课打卡/考核) | — | | `XiaoeWebhookController` | `/api/xiaoe` | 小鹅通 webhook 回调(线上课时事件) | — | | `AdminPlannerCertCategoryController` | `/api/admin/planner-cert-categories` | 管理端-学习种类 CRUD | — | | `AdminPlannerCourseController` | `/api/admin/planner-courses` | 管理端-线上课程 CRUD | — | | `AdminPlannerOfflineCourseController` | `/api/admin/planner-offline-course-map` | 管理端-线下课↔类别映射 CRUD | — | | `AdminActivityCheckinController` | `/api/admin/activity-checkins` | 管理端-签到记录/手动补录 | — | | `AdminPlannerExamController` | `/api/admin/planner-exam` | 管理端-试卷/题库 CRUD | — | | `AdminPlannerCertificationController` | `/api/admin/planner-certifications` | 管理端-认证看板/同步课时/存量补登 | — | | `HuaweiHealthController` | `/api/huawei-health` | 华为运动健康接入(授权URL/callback/同步/撤销/状态) | — | | `XiaomiHealthController` | `/api/xiaomi-health` | 小米运动健康云服务接口接入(授权URL/callback/同步/撤销/状态) | — | --- ## 三、已废弃接口清单 > 标记 `410 Gone` 响应,前端已迁移至新接口。可考虑在确认无调用后清理。 ### 3.1 `FamilyController` — 邀请码系统(已废弃) | 路径 | 说明 | 替代接口 | |------|------|----------| | `POST /api/family/invite-code` | 获取邀请码(已废弃) | `POST /api/family/invite/generate` | | `POST /api/family/invite-code/generate` | 生成邀请码(已废弃) | `POST /api/family/invite/generate` | ### 3.2 `FamilyUserController` — 角色切换(已废弃) | 路径 | 说明 | 替代接口 | |------|------|----------| | `POST /api/family/user/switch-mode` | 切换家长/孩子模式(已废弃) | `POST /api/family/member/switch` | | `POST /api/family/user/switch-to-child` | 切换到孩子身份(已废弃) | `POST /api/family/member/switch` | | `POST /api/family/user/switch-back-to-parent` | 切回家长身份(已废弃) | `POST /api/family/member/switch` | | `POST /api/family/user/switch-back-verify` | 切换验证(已废弃) | — | ### 3.3 `ButlerController` — 服务记录/佣金(已废弃) | 路径 | 说明 | 替代接口 | |------|------|----------| | `POST /api/butler/service-records` | 服务记录(已废弃) | — | | `POST /api/butler/commissions` | 佣金记录(已废弃) | — | ### 3.4 `TeacherController` — 教学任务(已废弃) | 路径 | 说明 | 替代接口 | |------|------|----------| | `POST /api/teacher/tasks` | 创建教学任务(已废弃) | `POST /api/guide/families/{familyId}/tasks/{taskId}` | | 其余 `/api/teacher/*` 多个接口均标注 `@Deprecated` | — | — | ### 3.5 `DanAssessmentController` — 当前测评(已废弃) | 路径 | 说明 | 替代接口 | |------|------|----------| | `POST /api/dan-assessment/current` | 获取当前测评(已废弃) | — | ### 3.6 `NoticeController` — 公告列表(已废弃) | 路径 | 说明 | 替代接口 | |------|------|----------| | `GET /api/notices/list` | 使用 GET 方法,违反统一 POST 规范 | — | --- ## 四、接口详细清单 ### 4.1 认证与用户(`/api/auth`, `/api/user`) | 路径 | 说明 | 参数 | 废弃 | |------|------|------|------| | `POST /api/auth/send-code` | 发送验证码 | phone | — | | `POST /api/auth/phone-login` | 手机号登录 | phone, code | — | | `POST /api/auth/wechat-phone-login` | 微信一键绑定手机号 | code | — | | `POST /api/auth/silent-login` | 静默登录(仅获取 token) | — | — | | `POST /api/auth/auto-login` | 自动登录(refresh token) | — | — | | `POST /api/auth/register-with-idcard` | 身份证注册 | — | — | | `POST /api/auth/wechat-login` | 微信授权登录 | code | — | | `POST /api/auth/info` | 获取当前用户信息 | — | — | | `POST /api/auth/set-password` | 设置密码 | password | — | | `POST /api/auth/verify` | 验证密码 | password | — | | `POST /api/auth/check-phone` | 检查手机号是否存在 | phone | — | | `POST /api/auth/direct-register` | 直接注册(无邀请码) | — | — | | `POST /api/auth/register-with-invite` | 邀请码注册 | inviteCode | — | | `POST /api/auth/switch-role` | 切换角色 | role | — | | `POST /api/user/address/list` | 收货地址列表 | — | — | | `POST /api/user/address/get` | 获取地址详情 | id | — | | `POST /api/user/address/create` | 创建地址 | — | — | | `POST /api/user/address/update` | 更新地址 | — | — | | `POST /api/user/address/delete` | 删除地址 | id | — | | `POST /api/user/address/setDefault` | 设为默认 | id | — | | `POST /api/user/mascot/set` | 设置吉祥物 | mascotId | — | | `POST /api/user/mascot/get` | 获取吉祥物 | — | — | ### 4.2 家庭与成员(`/api/family/*`, `/api/family/member/*`) | 路径 | 说明 | 废弃 | |------|------|------| | `POST /api/family/invite-code` | ~~获取邀请码~~ | ✅ 废弃 | | `POST /api/family/invite-code/generate` | ~~生成邀请码~~ | ✅ 废弃 | | `POST /api/family/guide-bind` | 绑定规划师 | — | | `POST /api/family/member/add` | 添加成员 | — | | `POST /api/family/member/list` | 成员列表(统一入口) | — | | `POST /api/family/member/switch` | 切换成员视角 | — | | `POST /api/family/member/kick` | 移除成员 | — | | `POST /api/family/member/leave` | 主动退出家庭(微信用户;创建者需先转让管理员) | — | | `POST /api/family/member/recycle` | 从回收箱回收成员(管理员操作) | — | | `POST /api/family/member/update` | 更新成员信息;body 可含 `isChild`(1=孩子/0=非孩子,仅家庭管理员可设置,落库到 users.is_child;非管理员返回 403) | — | | `POST /api/family/member/rename-family` | 修改家庭名称(仅家庭管理员);body `{name}`,返回新名称 | — | | `POST /api/family/member/editable` | 检查是否可编辑 | — | | `POST /api/family/member/logs` | 成员变更日志 | — | | `POST /api/family/invite/qrcode` | 生成邀请二维码 | — | | `POST /api/family/invite/request-join-by-code` | 申请加入(token 路径绑定邀请人,等待邀请人确认;旧码路径管理员兜底) | inviteCode 或 token + familyRole | — | | `POST /api/family/invite/approve-request` | 同意加入申请(审批人=邀请人且仍为目标家庭成员;旧数据无邀请人时家庭管理员兜底) | — | | `POST /api/family/invite/reject-request` | 拒绝加入申请(权限规则同上) | — | | `POST /api/family/invite/pending-requests` | 待我处理的申请列表(按邀请人查询;旧数据由目标家庭管理员兜底可见) | — | | `POST /api/family/invite/my-request` | 我的申请 | — | | `POST /api/family/invite/cancel-request` | 取消申请 | — | | `POST /api/family/invite/generate` | 生成邀请令牌(复用同家庭未过期未用尽的有效令牌;仅未过期记录计入 10 条额度) | — | | `POST /api/family/invite/validate` | 验证邀请令牌 | — | | `POST /api/family/invite/accept` | 接受邀请 | — | | `POST /api/family/invite/check-family` | 检查家庭状态 | — | | `POST /api/family/invite/revoke` | 撤销邀请 | — | | `POST /api/family/invite/transfer-admin` | 转让管理员 | — | | `POST /api/family/invite/validate-family-code` | **验证家庭短邀请码(落地页展示用,不创建请求)** | `inviteCode` | | `POST /api/family/invite/bind-inviter` | **绑定家庭邀请人(仅首次注册调用)** | `familyInviteCode` | ### 4.2 Family Member 接口详细(切换/回收箱) #### `POST /api/family/member/leave` — 主动退出家庭 **说明**:微信登录用户主动退出当前家庭,回到自己的初始家庭(自己创建的家庭 `families.creator_id = userId`);若无初始家庭则自动创建新家庭。退出时成员资产(测评/报告/能量值/档案属性)随成员迁移到目标家庭,CF 值(`system_points`)清零丢弃留在原家庭。 **约束**: - 仅微信登录用户可退出(`openid` 非 `phone:` 前缀);非微信用户调用返回错误 - 家庭创建者禁止退出,需先通过 `POST /api/family/invite/transfer-admin` 转让管理员 - 退出后该用户自动归属初始家庭(或新建家庭),不会处于"无家庭"状态 **请求体**:无(空 body 或 `{}`) **响应**: ```json { "code": 200, "message": "退出成功", "data": null } ``` **错误码**: | code | message | 处理建议 | |------|---------|----------| | 500 | 您是家庭创建者,请先转让管理员权限后再退出 | 先转让管理员 | | 500 | 非微信登录用户不能自主退出家庭 | 非微信用户不支持主动退出 | | 500 | 用户未加入家庭 / 家庭不存在 / 未找到该用户的家庭成员记录 | 提示用户状态异常 | --- #### `POST /api/family/member/kick` — 移除成员(含回收箱分流) **说明**:家庭管理员将成员移出家庭。行为按成员类型分流: - **微信登录用户**:资产迁移回其初始家庭(无则自动创建),CF 值(`system_points`)随成员带走,同时收回该家庭发放给该成员的人口券(POPULATION,来源 `member:{id}`,仅作废 AVAILABLE 状态的券) - **非微信登录用户**:进入回收箱(`family_members.status = recycled`),`users.family_id` 置空,资产保留在原家庭记录上,后续可通过 `POST /api/family/member/recycle` 回收 - **无关联用户的手动成员**:直接删除记录 **约束**:仅家庭创建者可踢出;不能踢出家庭创建者本人。 **请求体**: ```json { "memberId": 12345 } ``` **响应**: ```json { "code": 200, "message": "踢出成功", "data": null } ``` --- #### `POST /api/family/member/recycle` — 从回收箱回收成员 **说明**:目标家庭管理员将回收箱中的成员(非微信用户,`status=recycled`)重新加入指定家庭,资产(测评/报告/能量值/档案属性)迁移到目标家庭,关联用户 `family_id` 归位到目标家庭。 **约束**:仅目标家庭创建者可回收;成员必须在回收箱中。 **请求体**: ```json { "memberId": 12345, "targetFamilyId": 67890 } ``` **响应**: ```json { "code": 200, "message": "回收成功", "data": null } ``` **错误码**: | code | message | 处理建议 | |------|---------|----------| | 500 | 该成员不在回收箱中 | 仅回收箱成员可回收 | | 500 | 只有目标家庭管理员才能回收成员 | 权限不足 | --- ### 4.2 Family Invite 接口详细 #### `POST /api/family/invite/request-join-by-code` — 申请加入家庭 **说明**:用户通过邀请码/令牌提交加入家庭的申请,等待邀请人审批。 **请求体**: ```json { "inviteCode": "fam_abc123", // 必填,邀请码或令牌 "familyRole": "爸爸" // 可选,用户在目标家庭中的身份 } ``` **响应**: ```json { "code": 200, "message": "申请已提交,等待邀请人确认", "data": { "requestId": 12345, "familyName": "张三的家庭" } } ``` --- #### `POST /api/family/invite/bind-inviter` — 绑定家庭邀请人 **说明**:新用户首次注册时调用,建立「被邀请人 → 邀请人」关系,用于追踪邀请来源。**仅首次注册调用**,已有家庭邀请人的用户调用会返回失败。 **请求体**: ```json { "familyInviteCode": "fam_abc123" } ``` **响应**: ```json { "code": 200, "message": "绑定成功", "data": null } ``` **错误码**: | code | message | 处理建议 | |------|---------|----------| | 400 | 用户已有家庭邀请人 | 跳过,已在目标家庭中 | | 404 | 邀请码无效 | 提示用户链接无效 | --- #### `POST /api/family/invite/validate` — 验证邀请令牌 **说明**:邀请落地页使用,验证 token 有效性并返回家庭信息(仅供展示)。 **请求体**: ```json { "token": "abc123def456" } ``` **响应**: ```json { "code": 200, "data": { "familyId": 100, "familyName": "张三的家庭", "inviterName": "张三", "inviterAvatar": "/static/avatar.jpg", "memberCount": 3 } } ``` --- #### `POST /api/family/invite/check-family` — 检查用户家庭状态 **请求体**:无额外参数(从 JWT 取 userId) **响应**: ```json { "code": 200, "data": { "inFamily": true, "familyId": 100, "familyName": "张三的家庭", "isAdmin": true } } ``` --- #### `POST /api/family/invite/pending-requests` — 查询待我处理的申请 **说明**:邀请人视角,查询他人提交给自己的加入申请。 **请求体**:无额外参数 **响应**: ```json { "code": 200, "data": [ { "id": 1001, "requesterUserId": 200, "requesterNickname": "李四", "requesterAvatar": "/static/avatar.jpg", "familyRole": "妈妈", "status": "pending", "createdAt": "2026-08-31T10:00:00" } ] } ``` --- #### `POST /api/family/invite/approve-request` — 批准加入申请 **请求体**: ```json { "requestId": 1001, "comment": "" } ``` **响应**: ```json { "code": 200, "message": "已同意" } ``` --- #### `POST /api/family/invite/reject-request` — 拒绝加入申请 **请求体**: ```json { "requestId": 1001, "comment": "不符合条件" } ``` **响应**: ```json { "code": 200, "message": "已拒绝" } ``` --- #### `POST /api/family/invite/my-request` — 查询我的申请 **请求体**:无额外参数 **响应**: ```json { "code": 200, "data": { "id": 1001, "targetFamilyId": 100, "targetFamilyName": "张三的家庭", "familyRole": "爸爸", "status": "pending", "createdAt": "2026-08-31T10:00:00" } } ``` **status 枚举**:`pending` | `approved` | `rejected` ### 4.3 任务(`/api/tasks`) | 路径 | 说明 | |------|------| | `POST /api/tasks/minigame-options` | 小游戏选项 | | `POST /api/tasks/create` | 创建任务 | | `POST /api/tasks/today` | 今日任务(`memberId` 查单成员;`familyWide=true` 查全家庭今日任务) | | `POST /api/tasks/{id}/start` | 开始任务(两阶段入口,含购物任务自动加购/下单) | | `POST /api/tasks/{id}/complete` | 完成任务 | | `POST /api/tasks/{id}/review` | 审核任务 | | `POST /api/tasks/history` | 历史任务 | | `POST /api/tasks/pending-review` | 待审核 | | `POST /api/tasks/today-parent` | 家长今日任务 | | `POST /api/tasks/{id}` | 任务详情 | | `POST /api/tasks/{id}/complete-minigame` | 小游戏完成 | | `POST /api/tasks/batch-complete` | 批量完成 | | `POST /api/tasks/batch-delete` | 批量删除 | | `POST /api/tasks/my-pending` | 我的待办 | | `POST /api/tasks/accept` | 接受任务 | | `POST /api/tasks/reject/{id}` | 拒绝任务 | #### 4.3.1 购物任务联动(`actionType = cart/order`) 任务创建时通过 `actionType` + `actionConfig` 声明购物联动;调用 `POST /api/tasks/{id}/start` 时,后端自动执行加购/下单。 **actionConfig JSON 格式:** | 字段 | 必填 | 说明 | |------|------|------| | `productId` | ✅ | 商品ID | | `quantity` | ❌ | 数量,默认 1 | | `skuId` | ❌ | SKU ID(可选) | | `consigneeId` | ❌ | 收货地址ID(`order` 模式下可选;未提供时取用户默认地址) | | `deliveryMethod` | ❌ | 配送方式:1=快递/2=自提/4=线上可选人/5=线上单人 | **actionType 行为:** | actionType | 行为 | 返回字段 | |-----------|------|---------| | `minigame` | 跳转小游戏页 | — | | `focus` | 跳转专注计时器页 | — | | `survey` | 跳转问卷填写页 | — | | `article` | 跳转文章中心页 | — | | `activity` | 跳转活动列表页 | — | | `cart` | 自动加购,返回加购结果 | `execution.extra` 含 `cartAdded=true`、`productId`、`quantity` | | `order` | 先加购,再创建 pending 订单 | `execution.extra` 含 `orderId`、`orderNo`(成功时)或 `orderFailed=true`、`orderError`(失败时) | | `diet` | 跳转饮食打卡页(`/pages/growth/diet-checkin?taskId={id}`) | — | | `sleep` | 跳转睡眠打卡页(`/pages/growth/sleep-checkin?taskId={id}`) | — | | `exercise` | 跳转运动打卡页(`/pages/growth/exercise-checkin?taskId={id}`) | — | **下单失败常见原因:** 缺默认收货地址、商品已下架、库存不足、配送方式校验失败。失败时加购结果保留,任务状态正常置 `in_progress`,前端可引导用户去购物车/结算页手动完成。 ### 4.4 心愿(`/api/wishes`) | 路径 | 说明 | |------|------| | `POST /api/wishes/create` | 创建心愿 | | `POST /api/wishes/{id}/set-price` | 设置价格 | | `POST /api/wishes/{id}/reject` | 拒绝心愿 | | `POST /api/wishes/{id}/exchange` | 兑换心愿 | | `POST /api/wishes/{id}/approve-exchange` | 审批兑换 | | `POST /api/wishes/{id}/fulfill` | 完成心愿 | | `POST /api/wishes/{id}/confirm` | 确认心愿 | | `POST /api/wishes/{id}/cancel` | 取消心愿 | | `POST /api/wishes/list` | 心愿列表 | | `POST /api/wishes/pending` | 待审批心愿 | | `POST /api/wishes/{id}` | 心愿详情 | ### 4.5 能量与积分(`/api/energy`, `/api/points`) | 路径 | 说明 | |------|------| | `POST /api/energy/overview` | 能量概览 | | `POST /api/energy/logs` | 能量流水 | | `POST /api/energy/config` | 能量配置 | | `POST /api/energy/dimension` | 五维详情 | | `POST /api/points/balance` | 积分余额 | | `POST /api/points/logs` | 积分流水 | | `POST /api/points/adjust` | 手动调整 | | `POST /api/points/system-balance` | 系统余额 | | `POST /api/points/logs-by-category` | 分类流水 | ### 4.6 成长档案(`/api/growth/*`) | 路径 | 说明 | |------|------| | `POST /api/growth/record/create` | 创建记录 | | `POST /api/growth/record/create-with-order` | 下单关联创建 | | `POST /api/growth/record/list` | 记录列表 | | `POST /api/growth/record/child/{memberId}` | 指定成员记录 | | `POST /api/growth/record/{id}` | 记录详情 | | `POST /api/growth/record/{id}/delete` | 删除记录 | | `POST /api/growth/record/external/sync` | 外部同步 | | `POST /api/growth/record/upload-and-parse` | 上传解析 | | `POST /api/growth/record/create-from-upload` | 从上传创建 | | `POST /api/growth/record/supplement` | 补充记录 | | `POST /api/growth/plan/create` | 创建计划 | | `POST /api/growth/plan/child/{memberId}` | 成员计划 | | `POST /api/growth/plan/{id}` | 计划详情 | | `POST /api/growth/plan/{id}/review` | 审核计划 | ### 4.7 健康打卡(`/api/health/*`, `/api/daily/checkin`, `/api/mind/checkin`) | 路径 | 说明 | |------|------| | `POST /api/health/checkin/list` | 行为打卡列表 | | `POST /api/health/checkin/create` | 创建行为打卡 | | `POST /api/daily/checkin/list` | 每日打卡列表(饮食/运动/睡眠/心情) | | `POST /api/daily/checkin/create` | 创建每日打卡 | | `POST /api/daily/checkin/update` | 更新打卡 | | `POST /api/daily/checkin/delete` | 删除打卡 | | `POST /api/mind/checkin/create` | 情绪日记创建 | | `POST /api/mind/checkin/list` | 情绪日记列表 | | `POST /api/mind/checkin/latest` | 最新情绪日记 | | `POST /api/mind/checkin/trend` | 情绪趋势 | | `POST /api/mind/checkin/stats` | 情绪统计 | | `POST /api/mind/checkin/weekly-report` | 周报 | | `POST /api/mind/checkin/emotion/recognize` | ~~情绪识别(URL方式,走Dify)~~ — 已废弃 | | `POST /api/mind/emotion/analyze` | 照片情绪识别(文件上传,走 LangGraph DeepFace) | | `POST /api/mind/emotion/analyze-url` | 照片情绪识别(URL方式,走 LangGraph DeepFace) | | `POST /api/health-status/get` | 健康现状档案获取 | | `POST /api/health-status/save` | 健康现状档案保存 | | `POST /api/health-status/signature` | 提交手签名(仅更新 `signature` + `signed_at` 列,不影响其他字段;body: `{memberId, signature}`,signature 为 base64 PNG data URL) | | `POST /api/health/exercise/sync-wechat-steps` | 同步微信运动步数(传 encryptedData+iv,返回当日步数与近30天数据) | | `POST /api/health/meal/list` | 饮食打卡列表 | | `POST /api/health/meal/create` | 创建饮食打卡(支持 taskId 任务联动 + isBackfill 补打) | | `POST /api/health/meal/daily` | 获取某天的饮食记录 | | `POST /api/health/meal/weekly` | 获取某周食材频次与营养汇总 | | `POST /api/health/meal/alerts` | 获取食材摄入预警 | | `POST /api/health/sleep/list` | 睡眠打卡列表 | | `POST /api/health/sleep/create` | 创建睡眠打卡(支持 taskId 任务联动) | | `POST /api/health/exercise/list` | 运动打卡列表 | | `POST /api/health/exercise/create` | 创建运动打卡(支持 taskId 任务联动 + stepCount 微信步数) | #### 健康打卡任务联动(`taskId` 参数) 饮食/睡眠/运动打卡接口均支持可选 `taskId` 参数(Long),用于将打卡记录与任务系统联动。 **请求体新增参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `taskId` | Long | ❌ | 关联任务ID;为 null 时仅存打卡记录,不触发任务逻辑 | **联动逻辑:** | 场景 | 行为 | |------|------| | `taskId` 指向 `tasks.is_daily_progress=1` 的任务 | 调用 `TaskService.updateProgress(userId, taskKey, 1)` 累加进度,达标后自动 completed + 发放积分/能量 | | `taskId` 指向普通任务(`is_daily_progress=0`) | 调用 `TaskService.completeTask(taskId, memberId, ...)` 直接完成 | | `taskId` 为 null | 仅存打卡记录 + 发放 5CF 打卡积分,不触发任务逻辑 | | 补打(`isBackfill=1`)| **忽略 taskId**,不触发任何任务逻辑 | **taskKey 约定(每日进度型任务):** | actionType | taskKey | 匹配方式 | |-----------|---------|---------| | `diet` | `"DIET"` | title 精确匹配 OR title 以 `"[DIET]"` 前缀匹配 | | `sleep` | `"SLEEP"` | 同上 | | `exercise` | `"EXERCISE"` | 同上 | 前端跳转路径:`/pages/growth/{type}-checkin?taskId={id}`(由 `tasks.vue` 的 `navigateByAction()` 自动构造) ### 4.8 商品与订单(`/api/product/*`) | 路径 | 说明 | |------|------| | `POST /api/product/list` | 商品列表 | | `POST /api/product/detail` | 商品详情 | | `POST /api/product/create` | 创建商品 | | `POST /api/product/update` | 更新商品 | | `POST /api/product/my` | 我的商品 | | `POST /api/product/shelve` | 上下架 | | `POST /api/product/order/create` | 创建订单 | | `POST /api/product/order/pay` | 支付 | | `POST /api/product/order/cancel` | 取消订单 | | `POST /api/product/order/my` | 我的订单 | | `POST /api/product/order/detail` | 订单详情 | | `POST /api/product/order/confirm` | 确认收货 | | `POST /api/product/order/refund/apply` | 申请退款 | | `POST /api/product/order/vendor` | 服务商查询收到的订单 | | `POST /api/product/order/vendor-confirm` | 服务商确认发出/服务完成 | | `POST /api/product/order/ship` | 服务商/管理端发货(填物流单号+快递公司)。发货成功后自动调用微信「小程序交易管理服务」`upload_shipping_info` 同步物流到微信订单管理(用户在微信侧收发货通知/查物流/确认收货);自提订单或无单号跳过;失败只记日志不阻塞(fail-open);`wechat.test-mode=true` 或 `wechat.fulfillment-enabled=false`(环境变量 `WECHAT_FULFILLMENT_ENABLED`)时跳过 | | `POST /api/product/order/review/update` | 供应商审核修改待支付订单(修改价格/配送方式/添加优惠券/赠品) | | `POST /api/cart/add` | 加入购物车 | | `POST /api/cart/list` | 购物车列表 | | `POST /api/cart/update` | 更新数量 | | `POST /api/cart/remove` | 移除商品 | | `POST /api/cart/count` | 购物车数量 | | `POST /api/consignee/list` | 收货地址列表 | | `POST /api/consignee/save` | 保存地址 | | `POST /api/consignee/delete` | 删除地址 | ### 4.9 AI 对话(`/api/ai/*`) | 路径 | 说明 | |------|------| | `POST /api/ai/chat/send` | 发送消息 | | `POST /api/ai/chat/conversations` | 对话列表 | | `POST /api/ai/chat/messages` | 消息列表 | | `POST /api/ai/chat/conversations/{id}/delete` | 删除对话 | | `POST /api/ai/nutrition/send` | 营养对话 | | `POST /api/ai/health-coach/send` | 健康教练(请求体可选字段 `coach_id` 由服务端自动注入,客户端无需传;LangGraph 按 xibao/fubao 三级回退路由话术) | | `POST /api/ai/butler/send` | 管家对话 | | `POST /api/ai/context` | 上下文管理 | | `POST /api/butler/sessions/create` | 创建会话 | | `POST /api/butler/sessions/update-conversation` | 更新会话 | | `POST /api/butler/sessions/archive` | 归档会话 | | `POST /api/butler/sessions/list` | 会话列表 | | `POST /api/butler/sessions/detail` | 会话详情 | | `POST /api/butler/sessions/delete` | 删除会话 | ### 4.10 测评(`/api/assessment/*`, `/api/dan-assessment/*`) | 路径 | 说明 | |------|------| | `POST /api/assessment/appointment/create` | 预约测评 | | `POST /api/assessment/appointment/confirm/{id}` | 确认预约 | | `POST /api/assessment/appointment/cancel/{id}` | 取消预约 | | `POST /api/assessment/appointment/my-list` | 我的预约 | | `POST /api/assessment/latest-result` | 最新测评结果 | | `POST /api/assessment/history` | 测评历史 | | `POST /api/dan-assessment/result/upload` | 上传报告 | | `POST /api/dan-assessment/result/{resultId}/guidance/save` | 保存指导建议 | | `POST /api/dan-execution/complete` | 完成测评执行 | | `POST /api/dan-execution/confirm` | 确认执行 | | `POST /api/dan-execution/rate` | 评分 | | `POST /api/dan-execution/my-list` | 我的执行记录 | ### 4.11 饮食推荐(`/api/diet/*`) | 路径 | 说明 | |------|------| | `POST /api/diet/preferences/current-member` | 当前成员饮食偏好 | | `POST /api/diet/preferences/save` | 保存饮食偏好 | | `POST /api/diet/recommendation/today` | 今日推荐(返回 `data.id / data.menu / data.nutritionSummary / data.status`) | | `POST /api/diet/recommendation/generate` | 生成推荐(body: `date, meal_type, selected_foods JSON string`;返回 `data.id / data.menu / data.nutritionSummary`) | | `POST /api/diet/recommendation/complete` | 完成推荐 | | `POST /api/diet/record/save` | 保存饮食记录 | | `POST /api/diet/record/daily` | 每日记录 | | `POST /api/diet/ingredients/suggest` | 食材推荐(返回 `data.ingredients` 列表) | | `POST /api/diet/ingredients/recommend` | 换一批(返回 `data.ingredients`,每次不同) | | `POST /api/diet/ingredients/search` | 搜索食材(body `{keyword}`,返回 `data.foods:[{id, name, category}]`) | | `POST /api/diet/meals/config` | 餐食配置(body: `date_type` + `meal_type`,返回 `data.participantMemberIds` 等) | | `POST /api/diet/meals/config/save` | 保存餐食配置,**批量格式**(推荐,单次调用):body `{date_type:"weekday", configs:{breakfast:"[1,2]", lunch:"[]", dinner:"[3]"}}`(各餐次值为成员ID数组的 JSON 字符串);亦兼容**单条格式**:body `{date_type, meal_type, participant_member_ids, notes?}`。前端 `saveMealConfig` 位于 `cfc-frontend/utils/api.js`(2772行) | ### 4.12 内容(`/api/articles`, `/api/content/*`) | 路径 | 说明 | |------|------| | `POST /api/articles/list` | 文章列表 | | `POST /api/articles/detail` | 文章详情 | | `POST /api/articles/featured` | 精选文章 | | `POST /api/articles/record-read` | 记录阅读 | | `POST /api/articles/report-reading-time` | 上报阅读时长(按 articleId+childId+日期累加,首次上报递增 view_count) | | `POST /api/articles/reading-stats` | 阅读统计 | | `POST /api/articles/daily-tip` | 每日提示 | | `POST /api/articles/ai-questions` | AI 生成问题 | | `POST /api/articles/submit-answers` | 提交答案 | | `POST /api/articles/my-posts` | 我的文章 | | `POST /api/articles/comments/list` | 评论列表 | | `POST /api/articles/comments/create` | 创建评论 | | `POST /api/articles/comments/audit` | 审核评论 | | `POST /api/articles/quiz/generate` | 生成测验 | | `POST /api/articles/quiz/submit` | 提交测验 | | `POST /api/content-sections/visible` | 可见区块 | | `POST /api/content-sections/list` | 区块列表 | | `POST /api/content/related-items` | 内容关联推荐:以活动/文章/商品任一为源(`sourceType`+`sourceId`),按共享标签一次返回 `data.articles / data.activities / data.products` 三组(支持 `size`/`page` 分页,游客可访问) | ### 4.13 管理员接口(`/api/admin/*`) > 管理员接口需 `role=admin`,详见 `AdminInterceptor`。 | 路径前缀 | 说明 | |----------|------| | `/api/admin/articles/*` | 文章管理 | | `POST /api/admin/articles/move` | 调整精选文章的推荐顺序(`{ id, direction: 'up'|'down' }`,已边界时返回 400) | | `/api/admin/articles/reading-records` | 按文章查询阅读记录明细(分页,含孩子昵称/时长) | | `/api/admin/assessment/*` | 测评材料管理 | | `/api/admin/bazi-config/*` | 八字配置 | | `/api/admin/blood-type-config/*` | 血型配置 | | `/api/admin/butler/*` | 管家分配管理(分配列表/强制解绑/停接开关) | | `/api/admin/commission/*` | 佣金管理 | | `/api/admin/dimension/*` | 维度配置 | | `/api/admin/dimension-config/*` | 维度权重 | | `/api/admin/energy/*` | 能量配置 | | `/api/admin/energy-config/*` | 五行能量来源/每日限制配置 | | `/api/admin/ecom-supplier/*` | 电商供应商管理 | | `/api/admin/file-record/*` | 后台素材库(上传入库/检索/标签字典/统计,见 §4.56) | | `/api/admin/guide/*` | 成长规划师管理(申请/套餐) | | `/api/admin/growth-archive-product/*` | 成长档案关联商品 | | `/api/admin/health-plan/*` | 健康方案管理(跨家庭列表/详情) | | `/api/admin/knowledge-base/*` | 知识库管理 | | `/api/admin/notices/*` | 公告管理 | | `/api/admin/innate-portrait-config/*` | 先天画像来源权重配置(list/update/invalidate) | | `/api/admin/numsoul-detail-config/*` | 数字能量详细配置(list/create/update/delete) | | `/api/admin/package-templates/*` | 套餐模板 | | `/api/admin/ppoint-config/*` | P点配置(品类级比例+商品级固定值) | | `/api/admin/product/*` | 商品管理 | | `/api/admin/report-parser/*` | 报告解析配置 | | `/api/admin/report-template/*` | 报告展示模板管理 | | `/api/admin/supply-*` | 供应链相关 | | `/api/admin/system/*` | 系统配置 | | `/api/admin/unlock-gates/*` | 通关配置 | | `/api/migration/run` | 数据迁移 | ### 4.14 先天画像(`/api/mind/innate/*`) > 五维能量体系"心维度"先天画像聚合接口,基于星座/八字/血型/数字能量生成,AI 解读失败时自动降级模板文案。 | 路径 | 说明 | |------|------| | `POST /api/mind/innate/portrait` | 先天画像(聚合 mind_base_score + 数字能量详情 + 来源贡献明细) | | `POST /api/mind/innate/reading` | AI 解读(缓存到 innate_portrait_report,失败降级模板) | | `POST /api/mind/innate/numsoul` | 数字能量计算(生命灵数/天赋数/生日数/命运数) | | `POST /api/mind/innate/trajectory` | 先天+后天成长轨迹(EnergyBalance 后天能量对比) | **请求参数**(portrait/reading/trajectory): ```json { "memberId": 123, "memberType": "child", "familyId": 1 } ``` **numsoul 请求参数**: ```json { "year": 1990, "month": 5, "day": 15 } ``` ### 4.15 统计与通知(`/api/stats`, `/api/notification`) | 路径 | 说明 | |------|------| | `POST /api/stats/dashboard` | 统计仪表盘 | | `POST /api/stats/overview` | 总览 | | `POST /api/stats/revenue` | 收入统计 | | `POST /api/stats/membership` | 会员统计 | | `POST /api/stats/trend` | 趋势 | | `POST /api/notification/list` | 通知列表 | | `POST /api/notification/read` | 标记已读 | ### 4.16 报告模板管理(`/api/admin/report-template`) | 路径 | 说明 | |------|------| | `POST /api/admin/report-template/list` | 模板列表,支持 `reportType`/`isActive` 过滤 | | `POST /api/admin/report-template/get` | 按 reportType 获取模板,参数 `reportType` | | `POST /api/admin/report-template/save` | 保存模板(创建或更新),body 含 `id/name/reportType/config` | | `POST /api/admin/report-template/delete` | 删除模板,参数 `id` | | `POST /api/admin/report-template/toggle` | 启停模板,body `{ id, isActive }` | | `POST /api/admin/report-template/indicators` | 获取可选指标列表,支持 `domain` 过滤 | **config JSON 结构:** ```json { "fixedBlocks": [ { "type": "score", "title": "健康评分", "items": ["overallScore","gutHealthScore"] }, { "type": "indicator", "title": "血脂指标", "groupLabel": "血脂", "indicatorNames": ["总胆固醇","甘油三酯"] }, { "type": "list", "title": "菌种详情", "listKey": "flora" }, { "type": "text", "title": "评语", "content": "..." } ], "freeDisplay": { "enabled": true, "groupName": "其他指标" } } ``` ### 4.17 其他接口 | 路径 | 说明 | |------|------| | `POST /api/config/public/value` | 公开配置值 | | `POST /api/media/upload` | 媒体上传(免鉴权) | | `POST /api/recommend/search` | 推荐搜索 | | `POST /api/recommend/repurchase-reminders` | 复购提醒 | | `POST /api/task-reminders/upcoming/{memberId}` | 即将到期提醒 | | `POST /api/tianpan/dashboard` | 天盘概览 | | `POST /api/tianpan/member/{memberId}` | 成员详情 | | `POST /api/tianpan/compatibility` | 兼容性分析 | | `POST /api/tianpan/annual-energy` | 年度能量 | | `POST /api/tianpan/daily-fortune` | 每日运势 | | `POST /api/tianpan/related-items` | 相关事项 | | `POST /api/tianpan/recalibrate` | 重算五维基础分(管理员) | | `POST /api/wisdom/gut-cognition` | 肠道认知 | | `POST /api/wealth/checkin/*` | 财富打卡 | | `POST /api/insurance/*` | 保险规划 | ### 4.18 日常任务聚合(`/api/daily-task/*`) | 路径 | 说明 | |------|------| | `POST /api/daily-task/overview` | 今日任务总览(打卡/任务/阅读活动/测评报告四类聚合) | ### 4.19 健康维度评分(`/api/dimension/*`) | 路径 | 说明 | |------|------| | `POST /api/dimension/overview` | 获取健康维度概览(七维评分+百分位) | | `POST /api/dimension/upload` | 手动录入维度评分 | | `POST /api/dimension/questionnaire` | 问卷提交维度评分 | | `POST /api/dimension/history` | 获取维度历史记录 | ### 4.20 家庭成员关系质量(`/api/family/relationship/*`) | 路径 | 说明 | |------|------| | `POST /api/family/relationship/scores` | 获取家庭成员关系质量评分 | | `POST /api/family/relationship/calculate` | 计算并保存关系质量评分 | | `POST /api/family/relationship/health-alerts` | 获取健康预警列表 | | `POST /api/family/relationship/milestones` | 获取即将到来的里程碑 | | `POST /api/family/relationship/pairwise` | 获取以指定成员为中心的所有成员关系 | ### 4.21 佣金管理(`/api/commission/*`) | 路径 | 说明 | |------|------| | `POST /api/commission/summary` | 获取佣金汇总 | | `POST /api/commission/list` | 佣金流水列表 | | `POST /api/commission/team` | 团队统计(L1/L2) | | `POST /api/commission/stats` | 佣金统计面板 | | `POST /api/commission/balance` | 可提现余额详情 | | `POST /api/commission/team/list` | 团队成员列表 | | `POST /api/commission/funnel` | 佣金转化漏斗 | | `POST /api/commission/team/list` | 扩展:返回中每个成员新增 `memberConsumption`(该成员已完成履约订单总额,分)、`myCfEarnedFromMember`(我从该成员消费获得的 CF 总额,分) | | `POST /api/commission/team/consumption` | 团队总消费额分级汇总,请求 `{maxLevel}`(默认 3),返回 `{totalConsumption: 分, levelBreakdown[{level, memberCount, consumption}], totalMembers, maxLevel}` | | `POST /api/commission/my-referrer` | 获取我的直推人信息,返回 `{hasReferrer, referrerId, nickname, avatar, referralCode, bindTime}`,无推荐人时 hasReferrer=false | | `POST /api/commission/team/tree` | 团队树形扁平数据(不含根节点),请求 `{maxLevel}`(默认 3),返回 `{nodes[{userId, nickname, avatar, level, parentId, referrerId, memberConsumption, myCfEarnedFromMember}], totalMembers, maxLevel}` | ### 4.22 管理端-能量配置(`/api/admin/energy-config/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/energy-config/source-list` | 能量来源配置列表 | | `POST /api/admin/energy-config/source-save` | 保存能量来源配置(新增/更新) | | `POST /api/admin/energy-config/source-delete` | 删除能量来源配置 | | `POST /api/admin/energy-config/daily-limits` | 获取每日能量限制 | | `POST /api/admin/energy-config/daily-limit-save` | 保存每日能量限制 | | `POST /api/admin/energy-config/overview` | 能量配置总览(来源+限制) | ### 4.23 管理端-公告(`/api/admin/notices/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/notices/list` | 公告列表(分页) | | `POST /api/admin/notices/all` | 全量公告列表 | | `POST /api/admin/notices/create` | 创建公告 | | `POST /api/admin/notices/update` | 更新公告 | | `POST /api/admin/notices/delete` | 删除公告(软删) | | `POST /api/admin/notices/pin` | 置顶公告 | ### 4.24 管理端-成长规划师(`/api/admin/guide/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/guide/applications/pending` | 待审批规划师申请 | | `POST /api/admin/guide/applications/{id}/approve` | 审批通过 | | `POST /api/admin/guide/applications/{id}/reject` | 驳回申请 | | `POST /api/admin/guide/guides` | 获取所有成长规划师列表 | | `POST /api/admin/guide/guides/level/{level}` | 按级别获取规划师 | | `POST /api/admin/guide/guides/approved` | 获取已入驻(approved)的服务商列表 | | `POST /api/admin/guide/packages` | 获取所有套餐模板 | | `POST /api/admin/guide/packages/create` | 创建套餐 | | `POST /api/admin/guide/packages/{id}/update` | 更新套餐 | | `POST /api/admin/guide/packages/{id}/status` | 更新套餐状态 | ### 4.25 管理端-商品(`/api/admin/product/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/product/list` | 商品列表(分页/筛选/搜索) | | `POST /api/admin/product/review` | 审核商品(approve/reject) | | `POST /api/admin/product/shelve` | 商品上下架 | | `POST /api/admin/product/detail` | 商品详情 | | `POST /api/admin/product/create` | 创建商品 | | `POST /api/admin/product/update` | 更新商品 | | `POST /api/admin/product/copy` | 复制商品 | | `POST /api/admin/product/delete` | 删除商品 | | `POST /api/admin/product/batch-shelve` | 批量上下架(body: `{productIds, shelve}`) | ### 4.26 管理端-成长档案关联商品(`/api/admin/growth-archive-product/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/growth-archive-product/save` | 保存关联商品规则 | | `POST /api/admin/growth-archive-product/detail` | 关联商品规则详情 | | `POST /api/admin/growth-archive-product/delete` | 删除关联商品规则 | ### 4.27 管理端-电商供应商(`/api/admin/ecom-supplier/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/ecom-supplier/list` | 供应商列表(分页/搜索) | | `POST /api/admin/ecom-supplier/all` | 所有供应商(下拉选择) | | `POST /api/admin/ecom-supplier/save` | 创建供应商 | | `POST /api/admin/ecom-supplier/update` | 更新供应商 | | `POST /api/admin/ecom-supplier/delete` | 删除供应商 | ### 4.28 管理端-测评材料(`/api/admin/assessment/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/assessment/materials` | 测评资料列表 | | `POST /api/admin/assessment/materials/{id}` | 测评资料详情 | | `POST /api/admin/assessment/materials/create` | 创建测评资料 | | `POST /api/admin/assessment/materials/{id}/update` | 更新测评资料 | | `POST /api/admin/assessment/materials/{id}/delete` | 删除测评资料(软删) | | `POST /api/admin/assessment/config` | 获取积分配置 | | `POST /api/admin/assessment/config/update` | 更新积分配置 | ### 4.29 管理端-P点配置(`/api/admin/ppoint-config/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/ppoint-config/category/list` | 品类级P点比例列表 | | `POST /api/admin/ppoint-config/category/save` | 保存品类级P点比例 | | `POST /api/admin/ppoint-config/category/delete` | 删除品类级P点比例 | | `POST /api/admin/ppoint-config/category/by-category` | 按品类ID获取P点比例 | | `POST /api/admin/ppoint-config/product/list` | 商品级P点列表 | | `POST /api/admin/ppoint-config/product/save` | 保存商品级P点 | | `POST /api/admin/ppoint-config/product/delete` | 删除商品级P点 | | `POST /api/admin/ppoint-config/product/by-product` | 按商品ID获取P点 | | `POST /api/admin/ppoint-config/effective` | 获取商品综合有效P点值 | ### 4.30 管理端-报告解析(`/api/admin/report-parser/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/report-parser/types` | 报告类型列表 | | `POST /api/admin/report-parser/types/save` | 保存/更新报告类型 | | `POST /api/admin/report-parser/types/toggle` | 启用/停用报告类型 | | `POST /api/admin/report-parser/types/delete` | 删除报告类型 | | `POST /api/admin/report-parser/fingerprints/list` | 指纹规则列表 | | `POST /api/admin/report-parser/fingerprints/save` | 保存指纹规则 | | `POST /api/admin/report-parser/fingerprints/delete` | 删除指纹规则 | | `POST /api/admin/report-parser/imports` | 导入记录列表 | | `POST /api/admin/report-parser/imports/import` | 上传导入包 | | `POST /api/admin/report-parser/imports/approve` | 审批导入 | | `POST /api/admin/report-parser/imports/reject` | 驳回导入 | | `POST /api/admin/report-parser/unknown-clusters` | 未知报告聚类列表 | | `POST /api/admin/report-parser/unknown-uploads` | 聚类上传记录 | | `POST /api/admin/report-parser/generate-type` | 自学习生成报告类型 | --- ## 五、新增接口流程 ``` 1. 搜索现有接口:grep -rn "关键词" cfc-backend/src/main/java/com/etotem/cfc/controller/ 2. 检查路由冲突:grep -rn '@PostMapping("' cfc-backend/src/main/java/com/etotem/cfc/controller/ | grep -oP '@\w+Mapping\("\K[^"]*' | sort -u 3. 检查 Bean 冲突:find ... -name "*XxxService.java" | xargs grep "class Xxx" 4. 如有相似接口:评估修改成本,必要时扩展 5. 如确需新增: a. 创建 Entity(如需要新表) b. 创建 Mapper c. 创建 Service d. 创建 Controller(放在合适子目录) e. 数据库迁移(DatabaseInitializer + schema.sql) f. 更新本文档 6. mvn clean compile 验证 ``` ### 4.31 家庭管家选择(`/api/butler/*`) | 路径 | 说明 | |------|------| | `POST /api/butler/available-list` | 可选管家列表(浏览开放,脱敏;仅 L2 有效订阅家庭可绑定) | | `POST /api/butler/my-butler` | 我家当前管家绑定信息(含管家昵称/等级/分配时间) | | `POST /api/butler/select` | 绑定/更换管家(校验 L2 订阅、管家容量与接单状态;换绑自动解绑旧关系) | ### 4.32 优惠券(家庭维度,`/api/coupon/*` + `/api/admin/coupon/*`) > 2026-08-31 起,优惠券由「用户维度」全链路改为「家庭维度」。`user_coupon` 保留历史数据,新发放与消费统一走 `family_coupon`。 | 路径 | 说明 | |------|------| | `POST /api/admin/coupon/list` | 优惠券模板分页列表(admin),`{ page, size, keyword?, sort? }`,返回 `Page`(records/total/current/size),keyword 对名称/ID 模糊匹配 | | `POST /api/admin/coupon/create` | 新建优惠券模板(admin) | | `POST /api/admin/coupon/update` | 更新优惠券模板(admin) | | `POST /api/admin/coupon/issue` | 批量发放到家庭,`{ couponId, familyIds: [Long] }`(admin) | | `POST /api/admin/coupon/issue-family` | 单家庭发放,`{ familyId, couponId, quantity }`(admin,家庭管理页使用) | | `POST /api/admin/coupon/grant-log` | 家庭发券流水查询,`{ familyId?, couponId?, grantType?, source? }`(admin,返回 family_coupon_grant_log,每行含批量填充的 `familyName`,消除前端逐条查家庭名 N+1) | | `POST /api/admin/coupon/grant-user` | 管理员定向发放「会员升级券」给指定用户,`{ userId, amountYuan \| amount, validUntil?, remark? }`(admin,自动创建 applicableTo=MEMBERSHIP 无门槛券模板并发放到该用户家庭,落 grantType=MANUAL 流水) | | `POST /api/admin/coupon/toggle-status` | 启用/停用优惠券模板(admin) | | `POST /api/coupon/list` | 当前家庭可用优惠券(小程序) | | `POST /api/coupon/my` | 我的(家庭)优惠券(小程序) | | `POST /api/coupon/apply` | 下单抵扣(家庭券) | | `POST /api/coupon/claim` | 领取优惠券(发到家庭) | | `POST /api/coupon/checkout-list` | 结算页可兑换未拥有券 | | `POST /api/coupon/available-templates` | 领券中心可取券模板:上架(status 空/ACTIVE)、有效期内、未领完(total_count 空/≤0 视为不限量,否则 used_count`(字段为 `id` 等模板字段),与 `/claim` 去重口径对齐(COUPON-C3) | --- ### 4.33 CF 值分佣(`/api/commission/cf/*`) > CF 值(平台积分)统一分佣体系(F-4 分佣收口,2026-10-25):普通订单双返(当前消费人 F02 + 推荐人两级销售奖),会员/订阅只返推荐人,同家庭互推跳过本人上溯。 > 推荐人返佣收口为 **F03a 直接销售奖 + F03b 间接销售奖**,共同基数 = 本单消费产生的 P 点;旧「团队规模阶梯 `cf_rate_tier`」已废弃(表保留只读,仅等级展示/历史查询使用)。 | 路径 | 说明 | |------|------| | `POST /api/commission/cf/rate` | 我的团队规模 + 两级销售奖档位。返回 `{ totalTeamSize, ratePercent, tierName, teamDepth, teamAnnualPpoints, selfAnnualPpoints, directRatePercent, directTierName, indirectRatePercent, indirectTierName }`;legacy 字段 `ratePercent/tierName` 取 F03a 值供旧端兼容(未入档时 ratePercent=0、tierName="未入档") | | `POST /api/commission/cf/summary` | 我的 CF 钱包汇总,返回 `PlatformBalanceService.getBalance(userId)` 结果 | | `POST /api/commission/cf/list` | 我的 CF 流水(分页),请求 `{ page, size }`,返回 `Page` | **两级销售奖档位(迁移418 种子,管理端可配置):** 共同基数 = 本单消费产生的 P 点(商品:实付元 × 有效 P 点 / 100;非商品:实付元 × `cf.commission.service_rate`(bps) / 10000)。第 1 个非同家庭引荐人拿 F03a,第 2 个拿 F03b,最多两级。 F03a 直接销售奖(`cf_direct_sales_tier`,按**团队 8 层内滚动一年累计 P 点**): | 团队年度 P 点下限 | 档位 | 比例 | |:---:|:---:|:---:| | 100 | 青铜 | 10% | | 500 | 白银 | 25% | | 2000 | 黄金 | 40% | | 5000 | 铂金 | 55% | | 10000 | 钻石 | 70% | F03b 间接销售奖(`cf_indirect_sales_tier`,按**自身滚动一年累计消费 P 点**): | 自身年度 P 点下限 | 档位 | 比例 | |:---:|:---:|:---:| | 100 | 青铜 | 2% | | 500 | 白银 | 5% | | 2000 | 黄金 | 10% | | 5000 | 铂金 | 15% | | 10000 | 钻石 | 20% | > 匹配语义:`enabled=1 AND min_xxx <= 值 ORDER BY min_xxx DESC LIMIT 1`,无匹配档位不发放;比例按 `cf_earn_rule.params_json.max_rate_percent`(F03a=70、F03b=20)封顶。 > 金额由 `cf_earn_rule.formula = floor(base_ppoints * rate_percent / 100)` 计算,发放统一走 `CfBalanceService.earnByRule`(幂等键复用 F-2 `uk_ref_type`),只写 `cf_balance` + `cf_balance_log`。 > 滚动一年口径:消费支付成功时落 `ppoint_consumption_log` 一行(唯一键 `order_type + order_id` 幂等),按 `created_at >= now() - 365d` 聚合(迁移420)。 ### 4.34 CF 成员间转让(`/api/cf/transfer/*`) | 路径 | 说明 | |------|------| | `POST /api/cf/transfer/send` | 成员间转让 CF,请求 `{ toUserId, amount }`。仅限同一家庭(校验 familyId 一致);amount 必须为正数。转出扣减 + 转入增加在同一事务 | | `POST /api/cf/transfer/list` | 转让记录(分页,按当前用户家庭过滤),请求 `{ page, size }`,返回 `Page` | ### 4.35 CF 返佣阶梯配置(admin,`/api/admin/cf-rate-tier/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/cf-rate-tier/list` | 阶梯列表(按 sort_order 升序),返回 `List` | | `POST /api/admin/cf-rate-tier/save` | 新增/更新阶梯,请求体为 `CfRateTier`(含 id 则更新,否则新增,默认 enabled=1),返回 "已保存" | | `POST /api/admin/cf-rate-tier/delete` | 删除阶梯,请求 `{ id }`,返回 "已删除" | **`CfRateTier` 字段:** `id` / `tierName`(档位名)/ `minTeamSize`(团队规模下限含)/ `ratePercent`(返佣比例%)/ `sortOrder`(排序,越大越高)/ `enabled`(1启用/0停用)/ `createdAt` / `updatedAt`。 > 注意:家庭券接口为 `POST /api/coupon/my` 与 `POST /api/coupon/list`(见 4.32),不存在 `/api/coupon/family/list` 路由。 ### 4.36 健康报告异步采集(`/api/health/report/*`, `/api/report-parser/*`) 健康报告上传后进入**异步采集流程**:后端解析 PDF(先 `pdftotext` 提取文本内联,避免依赖代理工具执行),指纹判定报告类型 → 已知类型走专用采集脚本,未知类型交本地 opencode 服务(模型 `agnes-ai/agnes-2.5-flash`,在 session body 中显式指定)。前端提示「数据采集中」,完成后自动入库,列表页轮询刷新,无需用户等待。 | 路径 | 说明 | |------|------| | `POST /api/health/report/upload-only` | 生产小程序上传入口:上传 PDF → 落草稿 `health_report_drafts`(`parse_status=collecting`)→ **异步触发采集** → 返回草稿 ID(前端留意 `data.draftId` 后轮询) | | `POST /api/report-parser/upload` | 专用采集接口:同 async 流程,统一进异步采集 | | `POST /api/health/report/collect/status` | 查询单草稿采集状态,请求 `{ draftId }`,返回 `{ status, parseError }`(`collecting`/`completed`/`failed`) | | `POST /api/health/report/collecting-list` | 当前用户「采集中」草稿列表,返回 `List`(前端轮询用) | **采集流程状态机:** - `collecting`:指纹判定 + 异步解析中 - `completed`:解析成功 + 已自动入库(指标/菌群/疾病风险/食材) - `failed`:解析失败,`parse_error` 记录原因 **专属采集脚本路径(在 `HealthReportDraftService`):** `getDraftById` / `markCollecting` / `updateParseMethod` / `markCollectCompleted` / `markCollectFailed` / `listCollectingByUser`。 ### 4.36.1 报告归属管理(`/api/health/report/*`) 报告归属由 `health_reports.subject_id` 字段表示(关联家庭成员 ID,可为 null)。无归属的报告**不参与方案生成**,但可在管理端或小程序手动绑定/重新分配。 | 路径 | 说明 | |------|------| | `POST /api/health/report/reassign` | 重新分配报告归属(含维度重算),请求 `{ reportId, subjectId? }`,`subjectId` 为 null 表示解绑 | | `POST /api/health/report/unlinked` | 获取家庭内所有未绑定归属的报告,请求 `{ familyId }`,返回 `List` | | `POST /api/health/report/bind` | 绑定报告到成员(仅绑定,不可解绑),请求 `{ reportId, subjectId }` | **`/api/health/report/reassign` 请求体:** ```json { "reportId": 123, "subjectId": 456 // 可为 null 表示解除绑定 } ``` **响应:** `Result`,`"归属已更新"` **归属变更触发联动:** - 旧归属成员(若有):五维能量重算 + 食材推荐指数刷新 - 新归属成员(若有):五维能量重算 + 食材推荐指数刷新 - 方案生成:`subject_id IS NULL` 的报告自动跳过(`triggerAutoPlanAfterConfirm` 已有此逻辑) **权限检查:** 通过 `familyId`(JWT 注入)验证报告属于当前家庭,跨家庭操作抛出 `RuntimeException("报告不属于该家庭")`。 --- ### 4.36.2 舌诊 AI 集成(`/api/health/report/*`) 舌诊功能已集成 `aikanshe.com`(愛看舌)开放 API,**作为首选方案**;当 aikanshe.com 不可用时回退至 LangGraph Python 服务。调用流程如下: **请求路径**:`POST /api/health/report/parse-preview`(`type=tongue`) **请求体示例**: ```json { "type": "tongue", // 必填:指定舌诊流程 "memberId": 12345, // 可选:家庭成员 ID "filePath": "/data/...",// 可选:图片路径(auto模式会先检测} } ``` **响应结构**: ```json { "code": 200, "message": "success", "data": { "recordId": 67890, // 舌诊记录 ID "imageUrl": "http://...", // 图片访问 URL "overallAssessment": "舌象基本正常...", // 整体评估 "indicators": [ // 7类舌诊指标 {"code": "tongue_color", "value": "淡红"}, {"code": "coating_color", "value": "薄白"}, {"code": "coating_texture", "value": "润"}, {"code": "fissure", "value": "无"}, {"code": "teeth_mark", "value": "无齿痕"}, {"code": "sublingual_vein", "value": "无点刺"}, {"code": "constitution", "value": "平和质"} ], "createTime": "2026-10-08T..." } } ``` **优先级方案**(aikanshe.com 优先,LangGraph 兜底): 1. **首选**:调用 `aikanshe.com` API(`POST /agency/quanxi`,基于 AI 视觉模型) 2. **兜底**:若 aikanshe.com 超时/失败,自动回退至 LangGraph Python 服务(`/api/v1/tongue/diagnose`) 3. **最终兜底**:两者均失败时返回默认 mock 数据,确保业务不中断 **置信度阈值**:默认 `0.2`,可通过 `application.yml` 的 `aikanshe.confidence` 配置。 **相关配置**: ```yaml aikanshe: appkey: ${AIKANSHE_APPKEY:} base-url: ${AIKANSHE_BASE_URL:https://api.aikanshe.com} token: ${AIKANSHE_TOKEN:} confidence: ${AIKANSHE_CONFIDENCE:0.2} lang: ${AIKANSHE_LANG:zh-CN} ``` **已废弃接口(保留,待清理)**: - `POST /api/health/report/upload-only`(PDF流程入口,已被 `/api/health/report/parse-preview?type=tongue` 部分取代) ### 4.37 报告反馈与 AI 解答(`/api/health/feedback/*`) 用户对健康报告提交疑问/建议,后端**持久化**到 `report_feedback` 表并调用 AI 解答(经 `AiGateway`,免费版每日 1 次,付费版不限)。反馈记录含 `aiAnswer`/`aiStatus`,前端可据此展示 AI 解答结果。 | 路径 | 说明 | |------|------| | `POST /api/health/feedback/submit` | 提交报告反馈(持久化 + AI 解答),请求 `{ reportId?, draftId?, memberId?, type, content }`,返回 `Result` | | `POST /api/health/feedback/list` | 我的报告反馈列表(含 AI 解答),请求 `{ reportId? }`,返回 `Result>`(按创建时间倒序,最多 50 条) | **`/api/health/feedback/submit` 请求体:** ```json { "reportId": 123, // 可选,关联健康报告ID "draftId": null, // 可选,关联解析草稿ID(reportId 与 draftId 二选一,均可为空) "memberId": 456, // 可选,关联家庭成员ID(默认当前成员) "type": "question", // question=疑问 / suggestion=建议,其他值默认 question "content": "这份报告里菌群多样性偏低是什么意思?" } ``` **响应示例(`Result`,`data` 字段):** ```json { "code": 200, "message": "ok", "data": { "id": 1, "userId": 1001, "memberId": 456, "reportId": 123, "draftId": null, "feedbackType": "question", "content": "这份报告里菌群多样性偏低是什么意思?", "aiAnswer": "菌群多样性反映肠道微生物的丰富程度……", "aiStatus": "answered", "conversationId": "conv_abc123", "createdAt": "2026-09-22 14:30:00" } } ``` - `aiStatus` 取值:`pending`(待解答)/ `answered`(AI 已解答)/ `failed`(AI 调用失败,仍会落库,`aiAnswer` 为空)。 - 免费版每日仅限 1 次反馈解答(Redis 计数 `report:feedback:free:{userId}:{date}`,`memberLevel=FREE` 或为空时生效),超限返回 `Result.error("免费版每日仅限 1 次反馈解答,升级会员解锁更多")`;Redis 异常时 fail-open 放行。 - `content` 必填且不超过 500 字。 --- ### 4.38 认知维度(`/api/cognitive/*`) 六维认知体系:感知(perception) / 专注(focus) / 记忆(memory) / 逻辑(logic) / 空间(spatial) / 加工速度(processingSpeed)。 | 路径 | 说明 | |------|------| | `POST /api/cognitive/child` | 获取孩子最新六维认知得分 | | `POST /api/cognitive/family` | 获取家庭所有孩子最新六维认知得分 | | `POST /api/cognitive/update` | 更新认知维度得分(由规划师录入,需已有 completed 行) | | `POST /api/cognitive/self-test` | 提交认知自测结果(自动创建档案,写入六维认知档案,综合分自动计算) | | `POST /api/cognitive/norms` | 获取认知维度百分位常模 | | `POST /api/cognitive/trend` | 获取认知维度历史趋势 | | `POST /api/cognitive/recommendations` | 获取认知训练建议(按薄弱维度生成) | | `POST /api/cognitive/recommendations/create-task` | 从建议创建每日任务 | **`/api/cognitive/self-test` 请求体:** ```json { "memberId": 12345, "dimension": "memoryScore", "score": 85 } ``` dimension 取值:`memoryScore` / `logicScore` / `perceptionScore` / `spatialScore` / `processingSpeedScore` score 范围:0-100(整数) **响应:** `Result`,成功返回 "提交成功",失败返回错误原因。 **行为:** 若该孩子尚无任何 `status=completed` 的 DanAssessmentResult 行,自动创建(source='self_test'),写入对应维度分,重新计算综合分(7 维度非空均值)。 **已记录认知自测 API 端点 — 禁止重复注册。** ### 4.39 珍珠图/能力图(`/api/pearl/*`, `/api/ability/*`) 关系三图体系:章鱼图(谁帮过我)→ 珍珠图(我有什么)→ 能力图(谁会什么)。珍珠图聚合 25 类社会连接(12 必备内圈 + 13 理想外圈),附带互动日志、价值分级、定期提醒。 | 路径 | 说明 | |------|------| | `POST /api/pearl/resources` | 珍珠图聚合:25 组(ESSENTIAL 内圈 + IDEAL 外圈)+ legacyGroups(历史资源) | | `POST /api/pearl/connection-types` | 获取 25 类连接类型列表(code/label/category/suggestIntervalMonth) | | `POST /api/pearl/item/add` | 登记珍珠图资源(connectionType 必填,type 可选,name 必填,contactId 可选) | | `POST /api/pearl/item/delete` | 删除登记的珍珠图资源(itemId) | | `POST /api/pearl/item/update-priority` | 手动覆盖优先级(itemId/priority 1-3),同步 valueScore | | `POST /api/pearl/interaction/add` | 记录互动(itemId/interactionType/content),更新价值分并关闭 PENDING 提醒 | | `POST /api/pearl/interaction/list` | 互动历史分页(itemId/page/size) | | `POST /api/pearl/reminder/list` | 待办提醒列表(PENDING) | | `POST /api/ability/map` | 能力图:SKILL 帮助记录按联系人聚合为能力节点 | **`/api/pearl/resources` 响应结构:** ```json { "code": 200, "data": { "groups": [ { "type": "MEDICAL", "typeName": "医疗", "category": "ESSENTIAL", "ring": "inner", "items": [ { "id": 1, "name": "社区王医生", "description": "儿科主治", "avatar": null, "valueScore": 72, "priority": 1, "contactId": 5, "lastInteractionAt": "2026-08-15T10:30:00", "interactionCount": 8, "daysSinceLast": 26 } ] } // ... 共 25 组,为空时 items=[] ], "legacyGroups": [ { "type": "PERSON", "typeName": "人脉", "items": [...] }, { "type": "SKILL", "typeName": "技能", "items": [...] }, { "type": "INFO", "typeName": "信息", "items": [...] }, { "type": "PLACE", "typeName": "场所", "items": [...] } ] } } ``` **价值分算法**(`/api/pearl/interaction/add` 后自动重算): - 类型基础权重:ESSENTIAL=30,IDEAL=20 - 近 90 天互动次数 × 5,上限 30 - 最近互动时效性:≤30天=+20,≤90天=+10,≤180天=+5 - 互动总量 × 2,上限 20 - 总分 0-100,`priority=1`(高/大珍珠)→ valueScore≥70,`priority=2`(中)→ 40-69,`priority=3`(低/小珍珠)→ <40 **`/api/ability/map` 响应结构:** `data` 为数组,元素结构同 SKILL 组 items(contactId/name/avatar/relationshipType/skillCount/skills/lastHelpedAt)。 **珍珠图前端组件:** `PearlDiagram.vue`(Canvas 2D,两层同心圆,内圈 radiusPct=0.28 / 外圈 0.55,珍珠半径按 priority/valueScore 映射 8-26px)。 **珍珠图定时提醒:** `PearlReminderScheduledTask` 每日 08:00 执行,遍历 connection_type 非空资源,daysSinceLast ≥ suggestIntervalMonth×30 时生成 PENDING 提醒。 **珍珠图交互流程:** 打开页 → 加载 resources → 渲染两层同心圆 → 点击珍珠弹窗(联系/优先级/删除)→ 记录互动 → 重算价值分 → 逾期角标红点。 **`/api/pearl/interaction/add` 请求体:** `{ "itemId": 1, "interactionType": "WECHAT", "content": "咨询过敏问题" }` interactionType 取值:`PHONE` / `WECHAT` / `MEETING` / `OTHER`。 **`/api/pearl/item/update-priority` 请求体:** `{ "itemId": 1, "priority": 1 }`(1=高/大珍珠,2=中,3=低/小珍珠)。 **珍珠图前端页面:** - 珍珠图:`pages/action-detail/index.vue`(内嵌 `PearlDiagram.vue` 组件) - 登记资源:`pages/action-detail/pearl-add-resource.vue`(25 类类型分组选择器) - 互动提醒:`pages/pearl-reminders/index.vue`(PENDING 提醒列表) **前端 API(`utils/api.js`):** - `getPearlResources()` - `getConnectionTypes()` - `addPearlResource(data)` (data.connectionType 必填) - `deletePearlResource(data)` - `addPearlInteraction(data)` - `getPearlInteractionList(data)` - `getPearlReminders()` - `updatePearlPriority(data)` **已记录珍珠图/能力图 API 端点 — 禁止重复注册。** ### 4.40 关键人拓展章鱼图(`/api/octopus/*`) **替代旧章鱼图(help_logs)**。核心:成效记录 → 关键人画像 → 高频词分析 → 拓展方向。 | 路径 | 说明 | |------|------| | `POST /api/octopus/tentacles` | ⚠️ **已废弃(410)** 旧章鱼图:触手榜 | | `POST /api/octopus/add` | ⚠️ **已废弃(410)** 旧章鱼图:新增帮助记录 | | `POST /api/octopus/delete` | ⚠️ **已废弃(410)** 旧章鱼图:删除帮助记录 | | `POST /api/octopus/records` | ⚠️ **已废弃(410)** 旧章鱼图:帮助记录明细 | | `POST /api/octopus/effect/list` | 成效记录分页列表(支持 effect_type 筛选) | | `POST /api/octopus/effect/add` | 新增成效(member_order_id + effect_type bitmask + amount + desc) | | `POST /api/octopus/effect/delete` | 删除成效(级联关系) | | `POST /api/octopus/key-person/add` | 新增关键人(姓名/单位/部门/职务/初识场合/如何认识) | | `POST /api/octopus/key-person/update` | 修改关键人画像 | | `POST /api/octopus/key-person/delete` | 删除关键人(级联关系) | | `POST /api/octopus/effect/key-persons` | 某成效的关键人列表 | | `POST /api/octopus/analysis/keywords` | 高频词统计(单位/部门/职务/场合/路径) | | `POST /api/octopus/analysis/summary` | 高频词提炼 ≤8 个拓展方向 | | `POST /api/octopus/expansion/suggest` | 基于分析推荐关键人画像模板(预填) | > **已记录关键人拓展 API 端点 — 禁止重复注册。** ### 4.41 DOA 个人目标(家庭打卡个人目标模块) | 路径 | 说明 | |------|------| | `POST /api/doa/stage/create` | 创建阶段(memberId?+title+durationWeeks+goals[1-3]) | | `POST /api/doa/overview` | 家庭总览:各成员当前 active 阶段 | | `POST /api/doa/stage/detail` | 阶段详情:stage + goals + weeks | | `POST /api/doa/stage/cancel` | 取消阶段(仅 active 可取消) | | `POST /api/doa/week/plan` | 提交周计划(A表周行动宣告) | | `POST /api/doa/week/review` | 提交周复盘(B表五问) | | `POST /api/doa/week/list` | 周记录列表(按阶段查周记录) | > **已记录 DOA 个人目标 API 端点 — 禁止重复注册。** ## 4.42 引导弹窗配置化管理 | 路径 | 说明 | |------|------| | `POST /api/guide/popup/list` | 查询当前用户应展示的激活弹窗列表 | | `POST /api/guide/popup/trigger` | 上报触发行为,返回匹配弹窗 | | `POST /api/guide/popup/consume` | 消费弹窗(点击/关闭上报,防止重复弹出) | | `POST /api/admin/guide/popup/list` | 管理端:列表(分页筛选 status/slug) | | `POST /api/admin/guide/popup/create` | 管理端:创建弹窗(含触发条件+步骤) | | `POST /api/admin/guide/popup/update` | 管理端:更新弹窗(全量覆盖步骤和条件) | | `POST /api/admin/guide/popup/status` | 管理端:启用/禁用(toggle) | | `POST /api/admin/guide/popup/delete` | 管理端:软删除 | | `POST /api/admin/guide/popup/stats` | 管理端:数据看板(曝光/点击/完成率/分时段趋势) | > **设计文档**:`docs/superpowers/specs/2026-09-22-guide-popup-config-design.md` > **实施计划**:`docs/superpowers/plans/2026-09-22-guide-popup-config.md` > **说明**:本功能将小程序弹窗引导页从硬编码改为配置化管理,支持管理员在后台配置弹出条件与内容。旧方案(sys_config onboarding_guide_config)保留,新方案通过 4 张新表 + 9 接口实现。 ### 4.43 华为运动健康接入(`/api/huawei-health/*`) > **设计文档**:`docs/2026-11-06-华为运动健康开放平台接入方案.md`(D1-D5) > > 令牌仅后端持有(AES/GCM 加密存库),不落小程序;`memberId` 为空时取当前登录成员(切换视角场景可显式传 `memberId` 覆盖)。全部 `@PostMapping`,需 JWT。 | 路径 | 说明 | |------|------| | `POST /api/huawei-health/auth-url` | 获取华为账号授权 URL(body: memberId?, scope?) | | `POST /api/huawei-health/callback` | 授权回调,code 换 token(body: code + memberId?) | | `POST /api/huawei-health/sync` | 触发数据同步(body: memberId? + dataType?,dataType 空=全部类型) | | `POST /api/huawei-health/revoke` | 撤销授权(合规必需,body: memberId?) | | `POST /api/huawei-health/status` | 查询绑定/同步状态(body: memberId?) | > **数据表**:`huawei_health_tokens`(D1,迁移452);同步入库 `health_data_sources`(sourceType='huawei_health',复用表,未新建)。 > > **通道开关**:`huawei.health.mock-enabled`(默认 true=mock;凭证批复后 false=真实 Health Service Kit 云侧 REST,真实调用处标注 TODO)。 --- ### 4.44 小米运动健康云服务接口接入(`/api/xiaomi-health/*`) > **设计文档**:`docs/2026-11-06-华为运动健康开放平台接入方案.md`(X1-X5) > > 令牌仅后端持有(AES 加密存库),不落小程序;`memberId` 为空时取当前登录成员(切换视角场景可显式传 `memberId` 覆盖)。全部 `@PostMapping`,需 JWT。 | 路径 | 说明 | |------|------| | `POST /api/xiaomi-health/auth-url` | 获取小米云服务授权 URL(body: memberId?, scope?) | | `POST /api/xiaomi-health/callback` | 授权回调,code 换 token(body: code + memberId?) | | `POST /api/xiaomi-health/sync` | 触发数据同步(body: memberId? + dataType?,dataType 空=全部类型) | | `POST /api/xiaomi-health/revoke` | 撤销授权(合规必需,body: memberId?) | | `POST /api/xiaomi-health/status` | 查询绑定/同步状态(body: memberId?) | > **数据表**:`xiaomi_health_tokens`(X1,迁移453);同步入库 `health_data_sources`(sourceType='xiaomi_health',复用表,未新建)。 > > **通道开关**:`xiaomi.health.mock-enabled`(默认 true=mock;凭证批复后 false=真实云服务接口 hlthopen.io.mi.com,真实调用处标注 TODO)。 > > **合规红线**:仅官方云服务认证鉴权;不引入境外聚合中转(如 Terra),不碰社区逆向接口(userId/passToken 仿冒)。 --- ## 六、待清理的废弃接口 | Controller | 废弃接口 | 替代方案 | 当前状态 | 清理条件 | |------------|----------|----------|----------|----------| |------------|----------|----------|----------|----------| | `FamilyController` | `/invite-code`, `/invite-code/generate` | `/api/family/invite/generate` | @Deprecated + 410 ✓ | 确认前端无调用 | | `FamilyUserController` | `/switch-mode`, `/switch-to-child` | `/api/family/member/switch` | @Deprecated + 410 ✓ | 确认前端无调用 | | `FamilyUserController` | `/switch-back-to-parent`, `/switch-back-verify` | `/api/family/member/switch` | 已修复:@Deprecated + 410 | 确认前端无调用 | | `ButlerController` | `/service-records`, `/commissions` | — | @Deprecated + 410 ✓ | 可删除 | | `TeacherController` | 全部 `/api/teacher/*` 方法 | `/api/guide/families/*` | @Deprecated + UnsupportedOperationException | 确认规划师端无调用 | | `DanAssessmentController` | `/current` | — | 需验证 | 无前端调用方 | | `NoticeController` | `GET /list`(违反 POST 规范) | `/api/admin/notices/list` | 已修复:@Deprecated + 410 | 可删除 | | `OctopusController` | `/tentacles`, `/add`, `/delete`, `/records` | `/api/octopus/effect/*`, `/api/octopus/key-person/*` | @Deprecated + 410 ✓(2026-09-10 替换为关键人拓展) | 确认前端无调用(旧页面已删除) | --- ### 4.37 情绪识别(`/api/mind/emotion/*`) 基于 DeepFace 的人脸情绪识别,通过 LangGraph `/api/v1/emotion/recognize` 调用。 | 路径 | 说明 | |------|------| | `POST /api/mind/emotion/analyze` | 上传照片进行情绪识别(multipart 文件) | | `POST /api/mind/emotion/analyze-url` | 通过 URL 进行情绪识别(兼容旧调用方) | **POST `/api/mind/emotion/analyze`** 请求:multipart/form-data,字段 `file`(JPEG/PNG,最大 10MB) 返回: ```json { "code": 200, "data": { "dominant_emotion": "happy", "dominant_label_zh": "开心", "emotions": [ { "emotion": "happy", "confidence": 0.85 }, { "emotion": "neutral", "confidence": 0.10 }, { "emotion": "sad", "confidence": 0.03 }, { "emotion": "surprise", "confidence": 0.01 }, { "emotion": "angry", "confidence": 0.005 }, { "emotion": "fear", "confidence": 0.003 }, { "emotion": "disgust", "confidence": 0.002 } ], "all_emotions": { "happy": 0.85, "neutral": 0.10, "sad": 0.03, "surprise": 0.01, "angry": 0.005, "fear": 0.003, "disgust": 0.002 } } } ``` **POST `/api/mind/emotion/analyze-url`** 请求体: ```json { "image_url": "https://cdn.example.com/photo.jpg" } ``` 返回:同上。 --- ### 4.43 商品赠送会员(`/api/membership/gift-membership-progress`) 家庭维度累计「赠会员商品」原价实付金额,达到阈值后自动赠送会员。 | 路径 | 说明 | |------|------| | `POST /api/membership/gift-membership-progress` | 获取当前家庭的赠会员累计进度 | **POST `/api/membership/gift-membership-progress`** 请求:无(familyId 由 JWT userId 反查) 返回: ```json { "code": 200, "data": { "familyId": 12, "accumulatedAmount": 158000, "granted": 0, "grantedLevel": null, "grantedOrderNo": null, "grantedAt": null, "threshold": 198000, "remaining": 40000 } } ``` | 字段 | 类型 | 说明 | |------|------|------| | `accumulatedAmount` | Integer | 累计赠会员商品原价金额(分),仅统计无积分/无券/无折扣的实付订单 | | `granted` | Integer | 1=已赠送 0=未赠送 | | `grantedLevel` | String | 已赠送的会员等级(当前全局配置默认 `FAMILY`) | | `threshold` | Integer | 阈值(分),由 `sys_config.gift_membership_threshold` 动态填入 | | `remaining` | Integer | 还差多少达标(分)= `max(0, threshold - accumulatedAmount)`,已达标为 `0` | > **注意**:`threshold`、`remaining` 为 `@TableField(exist = false)` 非数据库列,仅接口返回用。 > **无家庭时**:接口返回空对象,`threshold`/`remaining`/`accumulatedAmount` 均为 `null`(此时不存在赠会员累计口径),前端据此隐藏进度条。 > 阈值单位为分(1980 元 = 198000 分),实际生效值以 `sys_config` 表中 `gift_membership_threshold` 为准(`insertSysConfigSeed` 仅在缺失时插入,不覆盖已有配置)。 --- ### 4.44 统一服务角色申请(`/api/service-role/*`) 多角色(规划师/营养师/管家/供应商/内容管理员/活动策划)统一申请入口,一次提交可含多个角色,管理端审批通过后回写 `users.roles` 并按角色初始化附属记录。 | 路径 | 说明 | |------|------| | `POST /api/service-role/apply` | 提交服务角色申请(`roles` 必填) | | `POST /api/service-role/my-apply` | 查询我的最新申请记录 | | `POST /api/service-role/upload-image` | 上传身份证/资质证书图片(multipart,字段名 `file`) | | `POST /api/service-role/admin/list` | 管理端:申请列表(`status` 查询参数,默认 `0`) | | `POST /api/service-role/admin/approve` | 管理端:批准(`{ id }`) | | `POST /api/service-role/admin/reject` | 管理端:驳回(`{ id, reason }`) | > **权限**:`admin/list`、`admin/approve`、`admin/reject` 三个端点校验 `@RequestAttribute("role")`,仅 `role=admin` 或 `role=operator` 可访问(与 `AdminHealthPlanController` 审核类端点口径一致),其他角色返回「无权限」。前端菜单由 `perm: 'audit:service-role'` 控制。 **状态语义**(`service_role_applications.status`) | 值 | 含义 | |----|------| | `0` | 待审核(同一 userId 仅允许一条待审,重复提交返回「您已提交过申请,请等待审核」) | | `1` | 已通过 | | `2` | 已驳回(原因存 `reject_reason`) | **POST `/api/service-role/apply`** 请求体(`ServiceRoleApplyDTO`) | 字段 | 类型 | 说明 | |------|------|------| | `roles` | List\ | 申请角色,`@NotEmpty` 至少一个 | | `idCard` | String | 身份证号 | | `idCardImages` | List\ | 身份证图片 URL 数组(落库转 JSON 字符串) | | `certificateImages` | List\ | 资质证书图片 URL 数组 | | `province` / `city` / `district` / `street` | String | 四级地址 | | `addressDetail` | String | 详细地址 | **审批通过后的角色落地规则**(`ServiceRoleApplicationServiceImpl.approve`) | 申请角色 | 副作用 | |----------|--------| | `planner` | `guides` 新增一行(`status=active`)+ `users.roles` 追加 `teacher` | | `nutritionist` | `users.nutritionist_status=approved` + `roles` 追加 `nutritionist` | | `butler` | `users.butler_status=approved` + `butler_profiles` 新增一行 + `roles` 追加 `butler` | | `vendor` | `users.vendor_status=approved` + `roles` 追加 `supplier` | | `article_admin` | `users.article_admin_status=approved` + `roles` 追加 `knowledge_admin` | | `activity_provider` | `users.activity_provider_status=approved` + `roles` 追加 `activity_manager` | > **注意**:approve/reject 仅对 `status=0` 的记录生效,已处理返回「该申请已处理」。 > `upload-image` 对图片类型文件先走 `wechatService.checkImage()` 内容安全检测,未通过直接拒绝。 --- ### 4.45 规划师解除家庭绑定(`POST /api/guide/families/unbind`) | 路径 | 说明 | |------|------| | `POST /api/guide/families/unbind` | 规划师解除自己名下的家庭绑定(请求体 `{ id }`,即 `guide_families.id`) | - 角色校验:仅 `role=teacher` 可调用,否则返回 `Access denied`。 - 归属校验:`GuideFamilyService.unbindByGuide()` 按 `id + guide_id + status='binding'` 定位,只能解除属于自己的绑定。 - 副作用:将 `guide_families.status` 置为 `cancelled`。 - 家长侧解绑为独立接口 `POST /api/bind/unbind`(按 familyId 定位,并通知规划师)。 > **注意**:前端 `unbindFamily(id)` 需传 `guide_families.id`(绑定记录 ID),不是 `familyId`。 --- ### 4.46 规划师方案审核(`/api/health/plan/pending-review/*`) | 路径 | 说明 | |------|------| | `POST /api/health/plan/pending-review/list` | 待审核方案列表(`teacher` 取当前登录人;`admin` 可传 `teacherId` 过滤,不传则返回该家庭全部) | | `POST /api/health/plan/pending-review/update` | 编辑方案内容(仅 `status` 为 `draft`/`pending_review` 允许) | | `POST /api/health/plan/pending-review/approve` | 审核通过并发布 | | `POST /api/health/plan/pending-review/reject` | 驳回 | - 角色校验:仅 `role=teacher` 或 `role=admin`,且必须携带 `familyId`,否则返回 `familyId不能为空`。 - **未分配池规则**:`listPendingReviewPlans()` 在 `teacherId` 非空时按 `(teacher_id = ? OR teacher_id IS NULL)` 过滤 —— 规划师既能看到分配给自己的方案,也能看到本家庭内尚未指定规划师的方案(`health_plans.teacher_id` 为 `NULL`),避免用户未选规划师时保存的 `pending_review` 方案成为无人可见的孤儿记录。 - 入选范围限定 `status IN ('draft','pending_review')`,按 `created_at` 倒序。 > **注意**:`health_plans.teacher_id` 列由迁移 251 建立(`DatabaseInitializer`),`schema.sql` 已同步。 > 前端 `getPendingReviewPlans()`(`utils/api.js`)目前尚无页面消费,规划师审核页未接通;新审核工作台改用 `4.47` 的 `plans/pending` 端点,本节 4 个端点保留但不再被前端调用。 > ⚠️ 2026-10-04:`/pending-review/approve` 响应由 `Result` 改为 `Result`(新增 `taskGenerated` / `taskCount` / `message` 字段)。该端点无前端调用点(`health-plan-summary.vue` 仅有未调用的死导入),变更安全。 > ✅ 2026-10-04:`/{familyId}/overview`、`/{familyId}/children/{memberId}/tasks`、`/{familyId}/children/{memberId}/pending-review`、`/{familyId}/tasks/{taskId}/review`、`/{familyId}/tasks/batch-review`、`/{familyId}/tasks/{taskId}`、`/{familyId}/tasks/{taskId}/delete` 共 7 个端点已接入 `guide_families` 绑定校验,修复跨家庭越权。 --- ### 4.47 规划师审核工作台(`/api/guide/families/*`) 规划师侧审核工作台的统一入口,授权源为 `guide_families.status='binding'`(与 `GuideFamilyService.isBound(guideId, familyId)` 同源),不使用 `users.teacher_family_ids`。 | 端点 | 权限 | |---|---| | `POST /api/guide/families/my-families` | teacher / admin | | `POST /api/guide/families/{familyId}/members` | teacher 需 isBound;admin 放行 | | `POST /api/guide/families/{familyId}/plans/pending` | teacher 需 isBound;admin 可传 teacherId 过滤 | | `POST /api/guide/families/{familyId}/plans/{planId}/update` | 同上 + planId IDOR 反查 | | `POST /api/guide/families/{familyId}/plans/{planId}/approve` | 同上 + planId IDOR 反查;返回 `PlanApproveResultDTO` | | `POST /api/guide/families/{familyId}/plans/{planId}/reject` | 同上 + planId IDOR 反查 | - **`my-families`** 不走 `checkFamilyAccess(role, userId, null)` —— 该路径下 `familyId == null` 会把 teacher 直接拒掉,故改为显式角色判断 + 按 `guide_id` 查本人绑定家庭,返回体含 `familyName`(取自 `Family.name`,注意字段名不是 `familyName`)。 - **`members`** 返回该家庭可审核成员,供工作台「成员」选择器使用。 - **未分配池规则**:`plans/pending` 复用 `listPendingReviewPlans()`,`teacherId` 非空时按 `(teacher_id = ? OR teacher_id IS NULL)` 过滤;teacher 无需传该参数,admin 可显式传以过滤。 - **IDOR 防护**:`{planId}` 类端点先 `checkFamilyAccess(role, userId, familyId)`,再用 `getPlanForFamily(planId, familyId)` 按 familyId 反查,返回 `null` 即 403。控制器内 `resolvePlan` 的第二次 recheck 仅为纵深防御,`getPlanForFamily` 已按 familyId 过滤,**该 recheck 永不单独拦截请求**,不可依赖它替代首道校验。 - **`approve` 返回 `PlanApproveResultDTO`**:`planId` / `status` / `taskGenerated` / `taskCount` / `message`。任务生成器 `generateDailyTasksFromPlan` 返回 `void`,故实现改为生成后按 `source_type='health_plan' AND source_id=planId` 统计实际条数;生成异常或计数为 0 时方案仍发布并返回 `taskGenerated=false`,属**部分成功**,前端须与失败区分提示。 > **注意**:配套前端为 `pages/teacher/review-workbench.vue`、`review-family.vue`、`plan-detail.vue`,入口在 `pages/teacher/families.vue`。 --- ### 4.47.1 成长规划师咨询消息(`/api/guide/messages/*`) 家长(家庭主账号)与成长规划师之间的咨询消息接口。 | 端点 | 权限 | 说明 | |---|---|---| | `POST /api/guide/messages/send` | 家长(需 `familyId`) | 发送咨询,请求体 `{ teacherId, content }` | | `POST /api/guide/messages/{messageId}/reply` | 仅 `role=teacher` + 认证闸门 | 规划师回复,请求体 `{ replyContent }` | | `POST /api/guide/messages/list` | 仅 `role=teacher` | 规划师获取咨询列表(分页 `{ page, size }`),响应条目在 `content` 尾部追加 `[家庭主账号:<昵称>]` | | `POST /api/guide/messages/unread-count` | 仅 `role=teacher` | 规划师未读消息数 | | `POST /api/guide/messages/my` | 家长(按自身 `parentId` 查询,无 role 限制) | 家庭主账号获取自己的咨询记录,响应 `TeacherMessage` 列表 | - **`POST /api/guide/messages/my`**:家庭主账号获取自己的咨询记录。响应 `TeacherMessage` 列表,每条含 `teacherName`(规划师昵称,按 `teacherId` 从 `users` 表回填,查不到时留空由前端兜底「规划师」)。不新增路由、不改鉴权(`/my` 无 role 限制,按 `parentId` 查自己的记录)。 > 文档更新:2026-11-01(`/my` 新增 `teacherName` 回显,见 `specs/2026-11-01-home-greet-shortcut-and-my-messages-design.md`)。 --- ### 4.48 指标统一层(`/api/indicator/*` + `/api/admin/indicator/*`) 指标变化曲线 / 指标速查 / 指标关联的统一读接口与管理端接口。读接口 `subjectId` 必填且做家庭归属校验(`family_members.id = subjectId AND family_id = 当前用户家庭`,由 `JwtInterceptor` 注入 `@RequestAttribute("familyId")`);管理端接口校验 `@RequestAttribute("role")`,仅 `role=admin` 可访问,否则「无权操作」。 **视图接口(`IndicatorController`,`/api/indicator`)** | 端点 | 请求要点 | 用途 | |---|---|---| | `POST /api/indicator/trend` | `{subjectId, definitionIds:[...]}` | 指标曲线(按 definitionId 分组、report_date 升序点序列) | | `POST /api/indicator/change-ranking` | `{subjectId, reportType?, category?, scope:adjacent\|first-vs-latest, orderBy:up\|down\|magnitude, limit}` | 变化幅度排名(含 `overall.improvedCount/worsenedCount/flatCount` 汇总) | | `POST /api/indicator/quick-lookup` | `{subjectId, category?, page, pageSize}` | 指标速查(分类分页 + 类别汇总 + `dimensionScores` 五/七维评分小节) | | `POST /api/indicator/correlation/list` | `{subjectId, definitionId}` | 指标关联查询(含 `subjectEvidence` 成员级配对证据) | **管理端接口(`/api/admin/indicator/correlation/*`、`/api/admin/indicator/mapping/*`)** | 端点 | 请求要点 | 用途 | |---|---|---| | `POST /api/admin/indicator/correlation/save` | `{definitionIdA, definitionIdB, direction, manualStrength, description, manualLocked, sourceNote}` | 关联对定义/编辑(写入前按 `indicator_definitions.code` 字典序强制对序,保证唯一键对称) | | `POST /api/admin/indicator/correlation/list` | `{page, size}` | 关联对分页(按 `updated_at` 倒序,含校准状态) | | `POST /api/admin/indicator/correlation/calibrate` | `{pairId?}` | 手动触发校准(返回「校准完成,共更新 N 对」) | | `POST /api/admin/indicator/mapping/import` | `{sourceType, seeds:[{rawName, definitionId?}]}` | 映射种子批量导入(返回「导入完成,共 N 条」) | | `POST /api/admin/indicator/mapping/list` | `{page, size, status?, sourceType?}` | 映射规则分页/review(`status=0` 为 ai_fallback 待确认) | > **关联校准**:`save` 时 `effective_strength = manual_strength`;每日 03:00 `IndicatorCalibrationJob`(`@Scheduled(cron = "0 0 3 * * ?")`)对 `status=active` 且 `manual_locked=0` 的关联对按 subject 分组做 Spearman + Fisher z 聚合,有效样本 `>=30` 才用 `computed_strength` 覆盖 `manual_strength`。`correlation/calibrate` 手动触发同一逻辑(`pairId` 传入时仍走全量逐对幂等)。 > **统一指标层写入(单一写者)**:报告入库 / 报告编辑 / 食材推荐刷新三处流程由 `NormalizeIndicatorPipeline` 幂等写入 `indicator_values`(唯一键 `source_type + source_id + definition_id`,`upsertMapping` ON DUPLICATE KEY)。本层读接口只读 `indicator_values`,不写时序;五维/七维评分在速查接口按原表 join,不进时序。 > **关联表**:`indicator_correlations`(迁移 360)、`indicator_mapping_rules`(迁移 359)。 *文档更新:2026-10-09(指标统一层新增,见 `specs/2026-10-09-indicator-change-curve-design.md`)* > **⚠️ `/api/health/indicator/list` 已被取代**:老接口返回裸 `List`(无上一期对照、无 summary)。新接口 `/api/health/report/indicators` 返回同一批指标 + `previous` / `change` / `summary` 五档形态数据。`/api/health/indicator/list` **保留不动**(cfc-web `views/nutritionist/HealthIndicators.vue` 仍在调),新接入一律走 `/api/health/report/indicators`。 --- ### 4.48.1 指标多期展示 · 后端接口(`/api/health/report/indicators`、`/api/indicator/periods`、`/api/admin/indicator/backfill`) > 本节为 §4.48 指标统一层的多期展示增量。**所有 `change` 计算统一由 `IndicatorChangeService.computeChange` 单点产出**(trendCode 五档:`improved` / `worsened` / `flat` / `first_record` / `pending_backfill`),读路径一律过滤 `indicator_definitions.status=1`,拿不到 active definition 的观测**直接剔除,不降级为「指标」+id 假名称**(QP17)。 **① `POST /api/health/report/indicators`** — 报告指标明细(含上一期对照,D12 报告详情页接入点) | 端点 | 权限 | 请求 | 返回 | |---|---|---|---| | `POST /api/health/report/indicators` | 登录(JWT;管理员/本人/被授权成员,校验逻辑同 `/api/health/report/detail`) | `{reportId, withPrevious?}` | `{reportId, reportType, subjectId, reportDate, dateSource, olderReportCount, summary, items}` | - **入参**:`reportId`(必填);`withPrevious`(选填,默认 `true`,`false` 时跳过 previous/change 计算,供编辑模式快速返回单期)。 - **权限**:无 `subjectId` 的报告(历史未绑定成员)仅**本人上传者或家庭管理员**可见;有 `subjectId` 时走 `ReportMemberPermissionService.canViewMemberReports`。 - **items[]** 每项含:指标原字段(`indicatorId`/`definitionId`/`category`/`indicatorName`/`indicatorValue`/`numericValue`/`unit`/`refRange`/`status`)+ 字典字段(`goodDirection`/`valueType`)+ `previous`(上一期观测,无则 null)+ `change`(`{delta, deltaPct, movement, trendLabel, trendCode, skipGaps, unitMismatch, comparable}`,首期时为 `first_record`,报告日期未知时为 `pending_backfill`)。 - **summary**:`totalCount` / `abnormalCount`(`status` 非「正常」)/ `abnormalDelta`(预留字段,当前固定 `0`,单报告视角无法直接算)/ `changedCount`(`trendCode` 为 improved/worsened 的条数)/ `comparableCount` / `firstRecordCount` / `pendingCount` / `dataIncomplete`(存在 pending_backfill 时为 true,驱动残缺横幅组件)。 - **与 `withPrevious=false`**:返回单期 items(每项含 `indicatorId/category/indicatorName/indicatorValue/unit/refRange/status`,**不含** `definitionId/previous/change/goodDirection/valueType`)。 - **`olderReportCount`**:该成员在本报告之前(同 sourceType)的历史报告数,用于 `first_record` 档区分「真的首期」与「更早报告未回填」。 - **N+1 约束**:42 项指标一次请求的 SQL ≤ 5 次(指标行 1 + 上期批量解析 1 + 字典/定义 1 + 报告 1);`IndicatorMappingService.resolveBatch` 用 `indicator_mapping_rules` JOIN `indicator_definitions` 单查询批量解析,**严禁逐指标查库**。 **② `POST /api/indicator/periods`** — 期次列表(双期对比页 picker 数据源) | 端点 | 权限 | 请求 | 返回 | |---|---|---|---| | `POST /api/indicator/periods` | 登录(JWT;`subjectId` 须属于当前家庭) | `{subjectId, sourceType?}` | `{subjectId, sourceType, items}` | - **items[]**:`{reportDate, reportId, dateSource, indicatorCount}`,按 `reportDate` 倒序;`reportDate=null`(日期未知期)**恒定排最后**,picker 显示「日期未知」。 - **dateSource**:该期所有观测中**最差**的一个(`unknown < confirm < upload < real`),诚实口径——只要有一项来源是上传推断,整期就标 `upload`。 - **indicatorCount**:该期有有效值(`value` 非空)的指标数,picker 显示「2026-10-08(42 项)」。 - **不分页**(单人单类型期次数实测 < 30);只读幂等。 **③ `POST /api/admin/indicator/backfill`** — 存量时序回填(admin) | 端点 | 权限 | 请求 | 返回 | |---|---|---|---| | `POST /api/admin/indicator/backfill` | admin(`@RequestAttribute("role")` 校验,非 admin 返回「权限不足」) | `{subjectId?, reportId?, limit?, dryRun?, fixReportDates?}` | `{scanned, eligible, written, skippedNoSubject, skippedNoPayload, failed, dryRun, fixReportDates, dateFixable, dateFixed, details[]}` | - **用途**:把 confirm 链路补写之前的历史报告补进 `indicator_values`(P0-3 数据面补全),并可顺带用 `ReportDateExtractor` 修复被 `new Date()` 污染的历史报告日期。 - **入参**:`subjectId`(选填,指定成员;不传扫全部 `status=active` 报告);`reportId`(选填,只回填指定报告,灰度验证用);`limit`(选填,默认 200,上限 500);`dryRun`(默认 `true`);`fixReportDates`(默认 `false`)。 - **`dryRun=true`**:预演只统计不写入,返回 `eligible`/`dateFixable` 计数,且**不触发 `mappingService.resolve`**(避免惰性建定义这类副作用);**首次执行必须 dryRun,核对无误后传 `false`**。 - **顺序红线**:先修日期、再补时序(污染日期若固化进 `indicator_values` 再修就晚了)。日期修复判定条件:能提取到真实日期 且 `report_date != extracted` 且 `report_date >= created_at` 当天(`new Date()` 污染特征签名);修后需连带 `refreshMemberIndicatorCurrent`。 - **幂等**:`NormalizeIndicatorPipeline` 按唯一键 `source_type + source_id + definition_id` upsert,已覆盖报告返回 `already_covered`,重复执行不产生重复时序。 **④ 升级改造的既有端点(`IndicatorController`)** | 端点 | 变更 | |---|---| | `POST /api/indicator/trend` | 新增可选入参 `{sourceType, fromDate, toDate, granularity: raw\|month, sourceKind: all\|report\|device}`;出参新增 `refLow/refHigh/goodDirection/valueType/pointsCount/totalReportCount/olderReportCount/chartMode/unitMismatch/latest/change/points/missingPeriods`。**破坏性:无** | | `POST /api/indicator/change-ranking` | 新增可选入参 `{scope: pair, fromReportDate, toReportDate, filter: improved\|worsened\|flat\|incomparable\|all, page, pageSize}`;`scope=pair` 缺 `fromReportDate`/`toReportDate` 返回明确错误;**`magnitude` 排序口径从 `\|Δ\|` 改为 `\|Δ%\|` 降序**(视觉有变化,属预期修正,见 §4.48 变更汇总);`deltaPct=null` 的项恒定排最后且不参与 improved/worsened 筛选(Q14)。**破坏性:无** | | `POST /api/indicator/quick-lookup` | 新增可选入参 `{withSparkline, sparkLimit}`;出参每项新增 `previous`/`change`/`latestDateSource`/`latestReportId`/`goodDirection`/`valueType`/`sparkline`;**修复 `reportDate=null` 观测被当作最新值的 bug**。**破坏性:无** | | `POST /api/indicator/source-types` | 出参新增 `periodCount` / `latestReportDate`(曲线页类型筛选用,原只返回类型名)。**破坏性:无** | > **`chartMode` 判定表**(后端单点定义,`IndicatorChangeService.chartModeOf`):`pointsCount=0 → empty`;`=1 → single`;`=2 → pair`;`<20 → line`;`≥20 → line_aggregated`(`granularity=month` 时强制 `line_aggregated`)。 > **SQL 预算(严禁 N+1,均有单测锁死)**:`/report/indicators` 42 项指标 → 服务层恒 3 次协作调用(控制器另加 2 次,合计 ≤ 5);`/quick-lookup` 与 `/source-types` 均恒 1 次 `indicator_values` 查询(上一期与 `periodCount` 全部内存计算)。 > **`IndicatorService.listDefinitions`**:`status` 传 null 时**默认按 `status=1` 过滤**(防止 P1-6 自动创建的 `status=0` definition 冒进管理端字典列表,QP17)。 > **`missingPeriods`**:该成员有报告、但本指标无有效值的期次,`IndicatorTimelineService` 固定 2 次查询算完(原 1+缺失期数,会 N+1)。 > **老接口兼容矩阵**见 `specs/2026-10-25-indicator-timeline-display-design.md` §4.7。 *文档更新:2026-10-27(指标多期展示 T02 后端接口,见 `specs/2026-10-25-indicator-timeline-display-design.md`)* --- ### 4.48.2 指标收藏 · 后端接口(`/api/indicator/favorite/*`) > 本节为 T04「关注指标收藏」后端化(方案A)增量。收藏从 localStorage(方案B)升级为后端持久化,可跨设备同步、跨端一致。**全部 `@PostMapping`**;`JWT Bearer` 鉴权;`@Resource` 注入;`userId`/`familyId` 由 `JwtInterceptor` 注入 `@RequestAttribute`,服务端不信任前端传值。 **① `POST /api/indicator/favorite/toggle`** — 收藏/取消(存在则删、不存在则插,幂等于单次调用) | 端点 | 权限 | 请求 | 返回 | |---|---|---|---| | `POST /api/indicator/favorite/toggle` | 登录(JWT;已加入 `LOGIN_REQUIRED_PATHS`,无 token 直接 401;`memberId` 须属于当前家庭) | `{memberId, sourceType, definitionId}` | `{definitionId, added}` | - **入参**:`memberId`/`definitionId`(必填 Long)、`sourceType`(必填 String,非空)。 - **返回**:`added=true` 本次加入收藏(新插入);`added=false` 本次取消收藏(已删除)。 - **错误码**:`400`(缺参/成员不属家庭/definitionId 非法)、`401`(未登录)。 **② `POST /api/indicator/favorite/list`** — 查已收藏集合 | 端点 | 权限 | 请求 | 返回 | |---|---|---|---| | `POST /api/indicator/favorite/list` | 登录(JWT;`memberId` 须属于当前家庭) | `{memberId, sourceType}` | `{memberId, sourceType, definitionIds}` | - **`definitionIds`**:该成员×该报告类型下已收藏的指标定义 ID 列表(升序,按 `id`);空集合返回 `[]`。 - 查询范围限定 `user_id = userId AND family_id = familyId AND member_id AND source_type`(家庭/用户隔离)。 **③ `POST /api/indicator/favorite/remove`** — 移除收藏(显式删除) | 端点 | 权限 | 请求 | 返回 | |---|---|---|---| | `POST /api/indicator/favorite/remove` | 登录(JWT;`memberId` 须属于当前家庭) | `{memberId, sourceType, definitionId}` | `{definitionId, removed}` | - **`removed=true`**:该条收藏已删除(不存在则视作已删除,幂等)。供前端「清空对比/切换成员」等需显式删除而非 toggle 语义的场景使用。 *文档更新:2026-10-30(T04 指标收藏后端化,见 `specs/2026-10-30-indicator-favorite-backend-design.md`)* --- ### 4.49 健康方案删除(`/api/health/plan/delete`、`/api/admin/health-plan/delete`) 已生成的健康方案可删除,**级联删除其产生的全部任务**(含每日实例)。 | 端点 | 权限 | 请求 | 返回 | |---|---|---|---| | `POST /api/health/plan/delete` | 登录用户(JWT) | `{planId}` | `{planId, taskCount}` | | `POST /api/admin/health-plan/delete` | admin/teacher/butler/nutritionist/operator | `{planId}` | `{planId, taskCount}` | - **级联范围**:`health_plans` 方案行 + `tasks` 中 `source_type='health_plan' AND source_id=planId` 的直接任务(周期模板/一次性任务/购买锚点)+ `tasks` 中 `template_id IN 直接任务ID` 的每日实例(`RepeatTaskGenerator` 生成,只透传 `template_id` 不带 `source_id`,必须二次删除,否则任务删后次日仍被再生产)。 - **保留不删**:`points_log`(积分流水,已完成任务的积分保留不撤回)、`task_executions` / `growth_task_log`(执行历史)。 - **事务**:`HealthPlanServiceImpl.deletePlanCascade` 标注 `@Transactional(rollbackFor = Exception.class)`,任一步失败整体回滚,不留无方案的孤儿任务。 - **IDOR**:用户端接口从 `@RequestAttribute("familyId")` 取家庭做归属校验,方案不属于该家庭返回「无权删除该方案」;管理端传 `familyId=null` 跳过归属校验。 - **状态**:任何状态(draft/pending_review/published/rejected)均可删除;前端以确认弹窗兜底提醒。 *文档更新:2026-10-17(健康方案级联删除,见 `specs/2026-10-17-health-plan-deletion-design.md`)* ### 4.50 活动海报模板(`/api/admin/poster-template/*` + `/api/poster-template/*`) Web 管理端定义活动海报模板(迁移381 `activity_poster_templates` 表),小程序端活动详情页「生成海报」拉取可用模板渲染画布。管理端接口校验 `@RequestAttribute("role")`,仅 `admin`/`operator` 可访问;`templateKey` 限定 `gradient`(渐变)/`minimal`(深色)/`card`(白底卡片),`name` 全局唯一。 | 端点 | 权限 | 用途 | |---|---|---| | `POST /api/admin/poster-template/list` | admin/operator | 模板列表(含停用,按 sort_order + id 升序) | | `POST /api/admin/poster-template/save` | admin/operator | 新增/更新(body 为实体字段:`id/name/templateKey/mainColor/darkColor/lightColor/bgColors/qrSize/sortOrder/status`;`id` 为空为新增;色板须为合法 JSON 数组,空则按主色生成,`qrSize` 默认 100) | | `POST /api/admin/poster-template/delete` | admin/operator | 删除(body: `{id}`) | | `POST /api/poster-template/list` | 登录 | 小程序端可用模板(`status=1`;生成海报场景本身要求登录) | *文档更新:2026-10-17(活动海报模板管理,见 `specs/2026-10-17-activity-poster-template-design.md`)* --- ### 4.50 会员权益对比表(`/api/membership/compare`) 购买页(`pages/membership/upgrade.vue`)与会员中心(`pages/membership/index.vue`)的权益对比表数据源。**全部权益值由后端聚合实际逻辑后返回展示文本**,前端不再硬编码权益文案,避免出现「文案说不限量 / 实际 20 个」这类偏差。 | 路径 | 说明 | |------|------| | `POST /api/membership/compare` | 返回 `{columns, rows}`,无需请求参数 | **返回值结构** ```json { "code": 200, "data": { "columns": ["FREE", "BASIC", "FAMILY", "PREMIUM"], "rows": [ { "name": "商品价格", "free": "普通价格", "basic": "会员价", "family": "会员价", "premium": "会员价" }, { "name": "家庭成员上限", "free": "1人", "basic": "3人", "family": "6人", "premium": "10人" }, { "name": "每日任务上限", "free": "5个/日", "basic": "3个/日", "family": "20个/日", "premium": "50个/日" } ] } } ``` **行值口径(事实源)** | 权益行 | 数据来源 | |--------|----------| | 商品价格 | FREE=`普通价格`,BASIC/FAMILY/PREMIUM 统一=`会员价`。实际结算由 `MemberPriceResolver` 取 `products.member_price`,仅按 `products.min_discount_level` 判定是否达门槛,**不存在按等级递增的额外折扣** | | 家庭成员上限 | `membership_levels.max_children`(0/空视为无该权益 → `—`) | | 每日任务上限 | `membership_levels.max_tasks_per_day` | | AI健康顾问 / 报告解读 / 测评预约 / 食材图片解析 | `BasicQuotaService.QUOTA_LIMITS` 月度配额常量(BASIC 限次)+ `canUseFeature` 判定(FAMILY/PREMIUM 不限) | | 优惠券权益 | 普通券面向所有登录用户(`discount_purchase` feature,BASIC 起可用);会员专享券仅 FAMILY/PREMIUM(`CouponService.canUseMemberCoupon`) | | 会员专属活动 | `member_activities` feature,BASIC 及以下为部分活动 | | 邀请佣金 / 消费返佣 | `referral_commission` / `purchase_commission` feature | | 专属管家、规划师咨询 | `membership_levels.priority_support` / `teacher_consultation` 对应的产品权益设定 | > **列口径**:仅 `FREE/BASIC/FAMILY/PREMIUM` 四列。`LIFETIME` 为赠送/特殊发放、不可购买,不作为列展示;`PROVIDER` 是**服务商角色**,不属于会员权益体系(`level_order=1` 与 FREE 同级,`features` 为 NULL),不参与本表。 > **`/api/membership/plans` 同步变更**:除 `LIFETIME` 外再过滤 `PROVIDER`,并附加 `maxChildren` / `maxTasksPerDay` 两个字段,前端档位卡片可直接引用。 *文档更新:2026-10-18(会员权益对比表动态化 + PROVIDER 退出会员权益体系);2026-11-06(「商品折扣」行改为「商品价格」:FREE=普通价格,其余付费档统一=会员价,去除按等级 9折/8折 的表述)* --- *文档最后更新:2026-10-04* --- ### 5.0 减脂专题(`/api/fatloss/*`) > 减脂专题(`xiaofat-miniprogram`)新增接口,与主系统用户体系共享(JWT 认证,需登录)。 > 所有接口统一 `@PostMapping`,响应格式 `Result`。 | 端点 | 权限 | 说明 | |---|---|---| | `POST /api/fatloss/weight/list` | 登录 | 体重记录列表(params: `memberId/startDate/endDate`,memberId 优先取 params,fallback currentMemberId) | | `POST /api/fatloss/weight/create` | 登录 | 创建体重记录(body: `memberId/weight/bodyFatPercent/waistCircumference/measureDate/remark`) | | `POST /api/fatloss/weight/update` | 登录 | 更新体重记录(body: `id/weight/bodyFatPercent/waistCircumference`) | | `POST /api/fatloss/weight/delete` | 登录 | 删除体重记录(body: `id`) | | `POST /api/fatloss/diet/list` | 登录 | 饮食记录列表(params: `memberId/startDate/endDate`) | | `POST /api/fatloss/diet/create` | 登录 | 创建饮食记录(body: `memberId/mealType/foodName/foodWeight/calories/protein/fat/carbs/eatDate/remark`) | | `POST /api/fatloss/diet/delete` | 登录 | 删除饮食记录(body: `id`) | | `POST /api/fatloss/diet/calories-summary` | 登录 | 当日总热量(params: `memberId/date`,date 默认今日) | | `POST /api/fatloss/exercise/list` | 登录 | 运动记录列表(params: `memberId/startDate/endDate`) | | `POST /api/fatloss/exercise/create` | 登录 | 创建运动记录(body: `memberId/exerciseType/durationMin/distanceKm/caloriesBurned/exerciseDate/remark`) | | `POST /api/fatloss/exercise/delete` | 登录 | 删除运动记录(body: `id`) | | `POST /api/fatloss/goal/active` | 登录 | 获取当前活跃目标(params: `memberId`,返回最新 `status=active` 的目标) | | `POST /api/fatloss/goal/create` | 登录 | 创建目标(body: `memberId/startWeight/targetWeight/targetBodyFat/targetDate/startDate`,targetWeight/startWeight/startDate 必填) | | `POST /api/fatloss/goal/update` | 登录 | 更新目标(body: `id/targetWeight/targetBodyFat/targetDate`) | | `POST /api/fatloss/goal/complete` | 登录 | 完成目标(body: `id`,status → `completed`) | | `POST /api/fatloss/goal/abandon` | 登录 | 放弃目标(body: `id`,status → `abandoned`) | **新增表:** `fat_weight_record`、`fat_diet_record`、`fat_exercise_record`、`fat_goal`(迁移 355–358,DatabaseInitializer) *文档更新:2026-10-09(减脂专题新增)* --- ### 4.53 限时特价(扫码闪购) > 设计规格:`specs/2026-10-20-limited-time-special-price-design.md`; > 新建 `special_price_deals` 表(迁移 389)+ `product_orders.special_deal_id` 列(迁移 390)。 **用户端(公开接口,无需登录)** | 路径 | 说明 | |---|---| | `POST /api/special-price/info` | 查询活动详情(白名单,JwtInterceptor 公开路径;`userPurchased`/`userRemaining` 恒 0,每人限购由下单接口兜底) | 请求体:`{ "dealId": 1 }` 响应 `data` 字段: ```json { "id": 1, "productId": 10, "productName": "示例商品", "name": "开售闪购", "specialPrice": 500, "productPrice": 990, "startTime": "2026-10-20 12:00:00", "endTime": "2026-10-21 12:00:00", "totalQuantity": 100, "soldQuantity": 23, "remainingQuantity": 77, "perUserLimit": 2, "allowCoupon": 0, "runStatus": "ACTIVE", "userPurchased": 0, "userRemaining": 0 } ``` `runStatus` 枚举:`ACTIVE`(进行中)/`NOT_STARTED`(未开始)/`SOLD_OUT`(已售罄)/`ENDED`(已结束)/`DISABLED`(已停用)/`DRAFT`(草稿)/`INVALID`(活动不存在)。白名单路径不写 request attribute,每人限购由下单接口最终校验。 **下单(特价路径)** `POST /api/product/order/create` 请求体新增 `specialDealId`(Long,可选)。若 `specialDealId != null` 走特价下单分支: 1. 校验活动存在、`status=active`、`NOW() ∈ [start_time, end_time]`、商品一致 2. 每人限购校验(`countByDeal` 累计 < `perUserLimit`) 3. `allowCoupon=0` 且 `couponId` 非空 → 拒绝 4. 原子扣量 `consumeQuota(id, qty)`(失败按 runStatus 返回明确原因) 5. `insert` 订单行 `special_deal_id = dealId`,`unit_price = specialPrice` 6. 回滚挂载点:`cancel`(用户取消)、`approveRefund`(退款完成)、`OrderTimeoutCancelTask`(超时取消),三处调用 `releaseQuota`(`GREATEST(sold_quantity - qty, 0)` 防负) **供应商改价拒绝**:`reviewUpdate` 开头若 `order.specialDealId != null` 直接 `Result.error("特价订单不允许修改价格")`。 **管理端(admin 角色)** | 路径 | 权限 | 说明 | |---|---|---| | `POST /api/admin/special-price/list` | admin | 分页列表(body: `{page,size,keyword,runStatus}`;`runStatus` 可传 `ACTIVE/NOT_STARTED/SOLD_OUT/ENDED` 或 `draft/disabled`,空=全部;响应 `data.records[]` + `data.total`) | | `POST /api/admin/special-price/create` | admin | 新建(body: `{productId,name,specialPrice,startTime,endTime,totalQuantity,perUserLimit,allowCoupon}`;`specialPrice`/`productPrice`/`totalQuantity` 单位均为分;同商品互斥 active) | | `POST /api/admin/special-price/update` | admin | 修改(body 同 create + `id`;仅 `draft/disabled` 可修改) | | `POST /api/admin/special-price/status` | admin | 启停(body: `{id, action}`;`action ∈ {enable, disable}`;启用时再次校验互斥) | | `POST /api/admin/special-price/delete` | admin | 删除(body: `{id}`;已有特价订单时拒绝) | | `POST /api/admin/special-price/qrcode` | admin | 生成小程序码(body: `{id}`;`scene=id={productId}&sp={dealId}`,落地页 `product-detail`;返回 `data:{qrCodeBase64, scene, note?}`;测试模式 note 提示无法生成真实码) | *文档更新:2026-10-20(限时特价/扫码闪购新增)* ### 4.54 活动报名情况(`POST /api/activity/registration-roster`) > 活动详情页「报名情况」区块数据源。面向所有访客(含游客,`/api/**` 下无需登录),返回脱敏的报名统计与最近已通过报名人,用于社交证明与名额紧迫感展示。姓名经 `DataMaskUtil.maskName` 脱敏(如"张小明"→"张某"),**不返回手机号**。 **请求体:** `{ "activityId": 1 }`(兼容 `id`) **响应 `data` 字段:** ```json { "activityId": 1, "maxParticipants": 50, "approvedCount": 12, "pendingCount": 3, "remaining": 38, "registrants": [ { "name": "张某", "registeredAt": "2026-10-22T10:00:00" } ] } ``` | 字段 | 说明 | |---|---| | `maxParticipants` | 人数上限(0 = 不限制) | | `approvedCount` | 已通过报名人数 | | `pendingCount` | 待审核报名人数 | | `remaining` | 剩余名额 = `max - approved`(不限制时为 `null`,下限 0) | | `registrants` | 最多 20 条已通过报名人(按报名时间倒序,姓名脱敏) | 前端使用:`activity-detail.vue` 加载详情后并行拉取;报名成功/取消报名后重新拉取。区块仅当 `activity.requireRegistration === 1` 时展示,含统计列、进度条(限人数时)与最近报名人列表。 *文档更新:2026-10-22(活动详情页新增报名情况)* ### 4.55 活动报名/签到/问卷(本次回归补登记) > 以下接口在 2026-10-23 的 T15/T16/T17 任务链路中新增或变更,此前未在本文档登记,此处统一补录。 #### 4.55.1 活动报名(`ActivityController`,前缀 `/api/activity`) | 路径 | 说明 | |---|---| | `POST /api/activity/register` | 活动报名(body: `activityId`;批量报名历史字段 `registrants`)。活动 `requireReview=1`(默认免审)→ 报名记录为 `pending` 不占名额;免审即 `approved` 并原子占用名额 | #### 4.55.2 活动签到与签到审核(`ActivityController`) | 路径 | 说明 | |---|---| | `POST /api/activity/checkin` | 活动签到(body: `activityId`)。活动级 `requireCheckinReview=1` 时签到进入 `pending_review`,审核通过才发奖励;免审直接发放 | | `POST /api/activity/checkin-review` | 签到审核(仅活动管理员/平台管理员)。通过发放积分/能量/CF,驳回不发放 | #### 4.55.3 管理端签到(`AdminActivityCheckinController`,前缀 `/api/admin/activity-checkins`) | 路径 | 说明 | |---|---| | `POST /api/admin/activity-checkins/list` | 按活动分页查询签到记录 | | `POST /api/admin/activity-checkins/add` | 手动补录签到(幂等,桥接触发课时入账) | | `POST /api/admin/activity-checkins/review` | 修改签到审核状态(通过发放课时/奖励) | **与规划师课时桥接**:签到审核通过会触发课时发放,与 `AdminPlannerOfflineCourseController` 的活动↔类别映射联动(见第五章)。 #### 4.55.4 家庭关系问卷(`RelationshipQuestionnaireController`,前缀 `/api/family/questionnaire`) | 路径 | 说明 | |---|---| | `POST /api/family/questionnaire/generate` | AI 生成关系问卷快照(body: `memberId`;`respondentId` 由后端按登录用户覆盖,校验调用人与目标成员同家庭),返回题目集与 `snapshotId` | | `POST /api/family/questionnaire/submit` | 提交答卷(body: `snapshotId` + 答案),写入响应记录 | | `POST /api/family/questionnaire/snapshot/{memberId}` | 查询某成员当前快照 | | `POST /api/family/questionnaire/history/{memberId}` | 某成员问卷历史提交记录 | #### 4.55.5 报名名册数据口径(2026-10-23 本次回归涉及) `POST /api/activity/registration-roster` 的 `approvedCount` 现直接读 `activities.approved_count`(迁移回填),不再实时统计;剩余名额 = `max - approved`,下单/退款链路(`register`/`cancel`/`OrderTimeoutCancelTask`)通过原子 SQL 维护该计数,防超卖。 #### 4.55.6 审核中心统计口径变更(2026-10-23) `ReviewCenterController` 的 `guidePending` / `nutritionistPending` 统计新增 `real_name IS NOT NULL` 过滤,与列表接口口径一致(commit `f61547a21`);前端 `ArticleAudit.vue` 驳回原因字段由 `row.reason` 修正为 `row.rejectReason`。 *文档更新:2026-10-23(T15/T16/T17 回归补登记:活动报名、签到与签到审核、管理端签到、家庭关系问卷、名册口径、审核中心统计口径)* --- ### 4.56 活动管理团队(`ActivityTeamController`,前缀 `/api/activity/team`)—— T35 > **T35 规格 §2.2/§5**:新增「活动管理团队」类型,`activities.team_id` 关联 `activity_team`;团队成员可协作运营团队名下活动,复用服务指派机制(`service_type=ACTIVITY_SUPPORT`,见 T34)。团队数据独立于 supply_system(供应体系),避免活动运营人员误入商品分销同体系判定。 **权限规则:** - 平台活动角色(admin / activity_admin / activity_manager)可管理全部团队; - 团队团长/运营主管(owner/manager)可管理本团队; - 普通在团成员可查看与协作(编辑活动/报名审核/签到等)。 | 路径 | 说明 | |---|---| | `POST /api/activity/team/create` | 创建活动团队(body: `{name, description?}`,管理员可指定 `ownerId`;普通用户以自己 userId 建团,自动成为团长 owner) | | `POST /api/activity/team/list` | 我的团队列表(管理员返回全部;普通用户返回在团团队),含 id/name/description/ownerId/status | | `POST /api/activity/team/detail` | 团队详情(body: `{teamId}`),返回 team + members | | `POST /api/activity/team/member/list` | 团队成员列表(body: `{teamId}`) | | `POST /api/activity/team/member/add` | 添加成员(body: `{teamId, userId, role?}`,role 可选:owner/manager/operator,默认 operator;幂等:已在团则更新角色) | | `POST /api/activity/team/member/remove` | 移出成员(body: `{teamId, userId}`,团长不可被移出;移出时级联撤销该成员在团内的 ACTIVITY_SUPPORT 指派) | | `POST /api/activity/team/assign` | 服务指派(ACTIVITY_SUPPORT,body: `{teamId, targetType, targetId, assigneeId, role, remark?}`,targetType: ACTIVITY/ACTIVITY_TEAM,role: lead/support/checkin/content;被指派人须为团队在团成员) | | `POST /api/activity/team/assign/list` | 服务指派列表(body: `{teamId, targetType?, targetId?}`) | | `POST /api/activity/team/assign/revoke` | 撤销服务指派(body: `{id, teamId?}`) | | `POST /api/activity/team/activities` | 团队名下活动列表(body: `{teamId}`) | **ActivityController 权限扩展(T35 协作判定):** - `/api/activity/create`:团队活动(`teamId` 非空)须由团队在团成员创建; - `/api/activity/update`:团队活动的编辑权限扩展到团队在团成员 + 该活动(或其团队)的 ACTIVITY_SUPPORT 被指派人。 *文档更新:2026-11-01(T35 活动管理团队:活动团队创建/成员管理/服务指派、ActivityController 协作权限扩展)* --- ## 4.48 组织管理(机构/企业组织) 平台角色(admin/operator/finance)可管理所有组织并查看全量统计;组织管理员(`users.roles` 含 `org_admin`)登录管理端后默认跳转自身组织统计大屏,仅能访问本组织数据。实现方案见规格 `docs/superpowers/specs/2026-10-22-org-admin-management-design.md`。 **数据模型:** - `organizations`:组织主表(name/type/code/admin_user_id/contact_*/description/status) - `org_members`:组织成员关联表(org_id/user_id/member_type/role_in_org/status),唯一键 `(org_id, user_id)` **权限规则:** - 平台角色(admin/operator/finance)→ 全量访问 - `org_admin` → 仅能访问自身组织(`organizations.admin_user_id = userId` 且 `status='active'`),返回 403「无权访问该组织」/「组织已停用」 - 组织管理员身份登录复用现有 `/api/admin/auth/login` 流(`AdminRoles.RESIDENT_ROLES` 新增 `org_admin`) ### 接口列表(13 个,全部 `@PostMapping`) | 路径 | 说明 | |---|---| | `/api/admin/org/list` | 组织列表(分页/筛选;org_admin 只返回自己组织) | | `/api/admin/org/create` | 创建组织(同步创建管理员账号;仅平台角色) | | `/api/admin/org/update` | 更新组织信息 | | `/api/admin/org/disable` | 停用/启用组织(仅平台角色) | | `/api/admin/org/detail` | 组织详情 | | `/api/admin/org/my-org` | 组织管理员获取自身组织(登录跳转目标) | | `/api/admin/org/user/search` | 按手机号/昵称搜索平台用户(添加成员下拉选人) | | `/api/admin/org/member/list` | 成员列表(含家庭数/订单数/消费额摘要) | | `/api/admin/org/member/add` | 添加成员(软删成员复活为 active 并更新类型) | | `/api/admin/org/member/remove` | 移除成员(软删 status=inactive) | | `/api/admin/org/member/change-type` | 变更成员类型(planner ↔ user,复活 inactive) | | `/api/admin/org/stats/overview` | 总览卡片(成员/规划师/家庭/订单/消费) | | `/api/admin/org/stats/families` | 家庭维度(活跃家庭/任务完成率/打卡率) | | `/api/admin/org/stats/active` | 活跃度趋势(任务完成/打卡/报告上传,按天) | | `/api/admin/org/stats/revenue` | 营收(订单金额/会员订阅/佣金,按天) | | `/api/admin/org/stats/trend` | 趋势图(活跃成员数/订单数/收入,按天) | **请求参数:** 成员/统计接口统一从 body 取 `orgId`;stats 可选 `startDate`/`endDate`(`yyyy-MM-dd`,默认近 30 天)。 **统计口径:** - 成员范围:`org_members` 中 `status='active'` 的 `user_id` 集合 - 家庭数:`families.creator_id IN (成员userId)` 去重计数 - 订单:`product_orders.buyer_id IN (成员userId) AND status IN ('PAID','COMPLETED')` - 消费:上述订单 `total_amount` 求和(单位分) - 打卡:`health_checkins.user_id` + `daily_checkin`(经 `family_members.user_id` 关联)+ `emotion_checkin` - 报告:`dan_report_uploads.uploader_user_id` - 佣金:`commission_records.referrer_id`(受益人)`commission_amount` 求和 - 订阅:`member_subscription_order.status='paid'` **前端入口:** cfc-web 新增 `/org` 路由四页面(List/Form/Detail/Dashboard);菜单「组织管理」挂在系统配置分组下。组织管理员登录后自动跳 `/org/:id/dashboard`,不展示组织列表页。 *文档更新:2026-10-22(组织管理功能上线)* --- ### 4.57 成长规划师域(planner-zone,32 SC 契约核对) > 契约文档:`docs/superpowers/specs/2026-11-07-planner-zone-contract.md`(EVD-10,32 个 SC 端点核验表 + 建议能力键映射 + 实现缺口清单) > 开工包:`docs/tdd/orchestration/planner-zone-kickoff-20261107.md` > 前置:O-7 契约补建工作流(主理人 2026-11-06 23:59 追认生效)——契约核对 = 文档核对 + 端点比对(防假 RED),产出契约文档后转测试侧(TR-13)补契约 JUnit + 三类流证据,**渐进而非全量**。 > 角色:成长规划师(`role=teacher`)双角色,可登录规划师端,也可切换回家长视角(`POST /api/auth/switch-role`)。 **核对结论:32/32 SC 均有端点载体锚定(29 个完全满足;3 个存在子能力缺口 G-1/G-2/G-3,见契约文档 §4),0 个实现级硬缺失。** | SC | 场景 | 端点载体(回填实测) | |----|------|---------------------| | SC-T-01 | 规划师登录 + 切回家长 | `AuthController` `/api/auth/*`(`switch-role`) | | SC-T-02 | 绑定测试家庭 | `GuideFamilyQueryController` `/api/guide/families/my-families`;`BindInviteController` `/api/guide/bind`;`TeacherFamilyBindingController` `/api/family/teacher-bindings/*`(pending/approve/reject/my-requests/cancel) | | SC-T-03 | 代传报告 + 确认入库 ⭐ | `HealthReportController` `/api/health/report/proxy-parse`、`/proxy-confirm`(L2775/L2945),`/transfer/*` | | SC-T-04 | 方案审核列表 + 批准 | `GuidePlanReviewController` `/api/guide/families/{familyId}/plans/*`(pending/approve/reject/update);`PlanReviewController` `/api/guide/plans/*`(family-list/review/detail);`ReviewCenterController` `/api/admin/review-center/summary` | | SC-T-05 | 激活方案拆任务(幂等)⭐ | `PlanReviewController` `POST /api/guide/plans/activate` → `PlanActivationService.activate`(`PlannerCertificationGuard` 认证闸门 + `IllegalStateException` 状态守卫) | | SC-T-06 | 家庭任务审核 | `GuideFamilyTaskController` `/api/guide/families/{familyId}/tasks/{taskId}/review`、`/tasks/batch-review`、`/children/{memberId}/pending-review` | | SC-T-07 | 录入测评结果触发方案 ⭐ | `DanAssessmentController` `/api/dan-assessment/result/record`、`/record/create`、`/record/complete`、`/report/parse-preview` | | SC-T-08 | 成长计划 / 套餐创建 | `TrainingPlanController` `/api/guide/training-plans/*`(create/update/list/detail/delete);`GrowthPlanController` `/api/growth/plan/create` | | SC-T-09 | 测评预约确认(状态守卫) | `AssessmentAppointmentController` `/api/assessment/appointment/*`(create/confirm/{id}/cancel/{id}/my-list/guide-list/assessor-list);`DanAssessmentController` `/appointment/confirm` | | SC-T-10 | 测评预约完成/未到 | 完成 `DanAssessmentController /appointment/complete`;**未到(status=4)无独立端点 → 缺口 G-1** | | SC-T-11 | DAN 报告上传与解析 | `DanReportController` `/api/dan-report/*`(upload/{id}/confirm/{id}/discard/{id}/complete-analysis/list/compare) | | SC-T-12 | DAN 八类报告查看 | `AssessmentReportController` `/api/dan-assessment/result/*`(plans/list/upload/{resultId}/guidance);`DanAssessmentController` /result/{id}/my-results/child-results | | SC-T-13 | 规划师视角数据隔离 | 授权源 `guide_families.status='binding'`(`GuideFamilyService.isBound`)+ `JwtInterceptor` 角色隔离;`GuideFamilyQueryController /my-families`、`GuideFamilyTaskController /bound-families`、`PlanReviewController family-list`(JWT familyId 过滤) | | SC-T-14 | 方案编辑(规划师侧) | `GrowthPlanController /api/growth/plan/update`、`/create`;`HealthPlanController /api/health/plan/save`、`/generate` | | SC-T-15 | 套餐任务项管理 | `TrainingPlanController /api/guide/training-plans/items/*`(add/update/delete) | | SC-T-16 | 客户健康总览 | `GuideFamilyTaskController /{familyId}/overview`、`/dashboard-stats`;`GuideFamilyQueryController /my-families` | | SC-T-17 | 成长计划进度跟踪 | `GuideFamilyTaskController /{familyId}/children/{memberId}/tasks`;`GrowthPlanController /child/{memberId}/active` | | SC-T-18 | 批量任务下发 | `TrainingPlanController /api/guide/training-plans/deploy`;`PlanReviewController /activate`;`GuideFamilyTaskController /tasks/batch-review` | | SC-T-19 | 消息推送客户 | `TeacherMessageController /api/guide/messages/*`(send/reply/list/unread-count/my);`UserNotificationController /api/notification/*` | | SC-T-20 | 退出/切换账号 | `AuthController /api/auth/switch-role`;退出为前端清 JWT(无服务端 logout,观察项) | | SC-T-21 | 报告对比分析 | `AssessmentComparisonController /api/assessment/compare/*`(by-child/by-child-dimension/by-family/narrative);`DanReportController /compare` | | SC-T-22 | 方案归档 | **无 archive 专用端点 → 缺口 G-2**(`HealthReportController /report/archive` 为报告归档参考) | | SC-T-23 | 报告代传(规划师代客户传)⭐ | `HealthReportController /report/proxy-parse`、`/proxy-confirm`、`/report/reassign`、`/transfer/*` | | SC-T-24 | 解绑/重分配客户家庭 | `GuideFamilyTaskController POST /api/guide/families/unbind`(4.45 已登记);`TeacherFamilyBindingController` 绑定审批流 | | SC-T-25 | 舌诊/情绪测评录入(规划师)⚠ | 舌诊:`HealthReportController /report/parse-preview`(type=tongue)+ `/report/confirm`(type=tongue)+ `/report/discard`;情绪:`EmotionCheckinController /api/mind/checkin/*`(create/list/latest/trend/stats/weekly-report/emotion/recognize) | | SC-T-26 | 精准营养方案制定 | `DietRecommendationController /api/diet/recommendation/*`(today/generate/update/regenerate/complete);`HealthReportController /api/health/nutrition/*`;`NutritionProductController /api/nutrition/product/*` | | SC-T-27 | 家庭天盘解读(规划师)⚠ | `TianpanController /api/tianpan/*`(dashboard/member/{memberId}/compatibility/annual-energy/daily-fortune/related-items/recalibrate);`TraditionalMirrorController /api/mind/traditional/*`;`MindFortuneController /api/mind/fortune/export`;`AdminFamilyOverviewController /api/admin/families/{id}/overview` | | SC-T-28 | AI 方案内容安全复核 | `PlanReviewController /review`;`GuidePlanReviewController approve/reject`;`ReviewCenterController /summary`;`ContentFilterController /api/content/*` | | SC-T-29 | 客户档案数据导出(合规)⚠ | `UserController POST /api/user/data-export`(个保法可携带权,`AccountCleanupService.exportUserData`);**`AdminOrgMemberController /api/admin/org/member/*` 无 export → 缺口 G-3** | | SC-T-30 | 测评录入触发五维维度变化 | `DanAssessmentController /result/record`;`EnergyController /api/energy/*`(overview/logs/grant/score-history/family-score-history) | | SC-T-31 | 手动维度打分覆盖/调整 | `ManualDimensionScoreController /api/family/manual-score/*`(submit/latest/history) | | SC-T-32 | 五维自评录入与变化 | `FiveDimensionSelfCheckController /api/family/self-check/*`(questions/submit/latest/history/status/ignore/generate-plan/trend-analysis/ai-generate-questions);`EnergyController` | **建议能力键映射(16 键,O-2 方案 A 定稿)**:`teacher.login.switch`(T-01/20)、`teacher.family.bind`(T-02/24)、`teacher.report.proxy`(T-03/23)、`teacher.plan.review`(T-04/28)、`teacher.plan.activate`(T-05)、`teacher.task.review`(T-06/18)、`teacher.assessment.record`(T-07/11/12)、`teacher.plan.create`(T-08/14)、`teacher.appointment.guard`(T-09/10)、`teacher.data.isolation`(T-13)、`teacher.family.overview`(T-16/17/21/27)、`teacher.message.push`(T-19)、`teacher.mind.record`(T-25)、`teacher.nutrition.plan`(T-26)、`teacher.export`(T-29)、`teacher.dimension.score`(T-30/31/32)。已核对与 `guide.*` / `family.parent.*` / `energy.*` 既有键无冲突。 **实现缺口(3 项,回传研发侧,见契约文档 §4)**:G-1 预约未到(no-show)无独立端点(SC-T-10);G-2 方案归档无专用端点(SC-T-22);G-3 管理端/规划师侧客户档案导出缺失(SC-T-29)。 > 转测试侧:研发负责人登记 TR-13 补契约 JUnit + 三类流执行证据,重点 SC-T-13 数据隔离权限流 / SC-T-05 幂等 / SC-T-09 预约状态守卫(详见契约文档 §5)。 --- ## 五、规划师培训认证(`/api/planner/*`, `/api/admin/planner-*`, `/api/xiaoe/*`) > 设计文档:`docs/superpowers/specs/2026-10-22-planner-learning-assessment-gate-design.md` > 核心链路:身份审核通过 → Guide.status=pending_cert + 按类别初始化 `planner_certifications` > → 线上课时(小鹅通 webhook/手动同步)+ 线下课时(activities 打卡桥接)→ 考核通过 → > 类别 `certified`(基础类别 planner 通过时同步翻 `Guide.status=active`)→ 接单闸门放行。 ### 5.1 规划师端(`/api/planner/*`) | 路径 | 说明 | |------|------| | `POST /api/planner/certification/my` | 我的全部类别认证状态(线上/线下课时拆分、考核分、证书号、是否可考) | | `POST /api/planner/courses` | 某类别线上课程列表(含小鹅通跳转/H5 链接;body: `categoryCode`) | | `POST /api/planner/training-activities` | 可报名/签到的培训活动列表(复用 activities,过滤映射表+规划师可见) | | `POST /api/planner/training-activities/check-in` | 扫码/手动签到(body: `qr_token` 或 `activityId`+`admin`)→ 桥接发放课时 | | `POST /api/planner/exam/start` | 开始某类别考核(前置校验课时达标;body: `categoryCode`) | | `POST /api/planner/exam/submit` | 提交判分(body: `attemptId`+答案,写入 exam_score/exam_passed) | | `POST /api/planner/exam/result` | 考核结果 | ### 5.2 管理端(`/api/admin/*`) | 路径 | 说明 | |------|------| | `POST /api/admin/planner-cert-categories/list` | 学习种类列表 | | `POST /api/admin/planner-cert-categories/create` | 创建学习种类(含 required_hours、is_base,首批种子:planner/nutritionist/assessor) | | `POST /api/admin/planner-cert-categories/update` | 更新学习种类 | | `POST /api/admin/planner-cert-categories/delete` | 删除学习种类 | | `POST /api/admin/planner-courses/list` | 线上课程列表 | | `POST /api/admin/planner-courses/create` | 创建线上课程(挂类别) | | `POST /api/admin/planner-courses/update` | 更新线上课程 | | `POST /api/admin/planner-courses/delete` | 删除线上课程 | | `POST /api/admin/planner-offline-course-map/list` | 培训活动↔类别映射列表 | | `POST /api/admin/planner-offline-course-map/create` | 创建映射(activities 建课后关联类别与计课时) | | `POST /api/admin/planner-offline-course-map/update` | 更新映射 | | `POST /api/admin/planner-offline-course-map/delete` | 删除映射 | | `POST /api/admin/activity-checkins/list` | 签到记录查询 | | `POST /api/admin/activity-checkins/add` | 手动补录签到(桥接触发课时入账) | | `POST /api/admin/activity-checkins/review` | 签到审核 | | `POST /api/admin/planner-exam/papers` | 试卷列表(按类别) | | `POST /api/admin/planner-exam/paper/create` | 创建试卷 | | `POST /api/admin/planner-exam/paper/update` | 更新试卷 | | `POST /api/admin/planner-exam/paper/delete` | 删除试卷 | | `POST /api/admin/planner-exam/questions` | 题库列表 | | `POST /api/admin/planner-exam/questions/save` | 保存题目(新建/更新) | | `POST /api/admin/planner-certifications/list` | 认证看板(按类别:课时进度、考核分、证书号、有效期) | | `POST /api/admin/planner-certifications/sync-hours` | 手动同步线上课时(小鹅通 webhook 兜底,body: `userId`+`categoryCode`+课时) | | `POST /api/admin/planner-certifications/sync-hours/batch` | 批量同步线上课时 | | `POST /api/admin/planner-certifications/init-by-user` | 按用户初始化各类别认证记录 | | `POST /api/admin/planner-certifications/backfill` | 存量补登(迁移401 幂等重跑) | ### 5.3 小鹅通回调(`/api/xiaoe/*`) | 路径 | 说明 | |------|------| | `POST /api/xiaoe/webhook` | 线上学习进度/课程完成事件(签名校验、幂等;课时入账 + 认证记录更新) | | `POST /api/xiaoe/webhook/test` | webhook 联调用测试入口 | ### 5.4 接单闸门(`PlannerCertificationGuard`) - 中央守卫 `assertCertified(userId, categoryCode[, baseRequired])`:查询该类别 `planner_certifications.status == certified`(且 `Guide.status == active`)方可放行,否则返回 `Result.error("规划师未完成【类别名】培训认证,暂不可提供该类服务")`(null=放行,非 null=拒绝)。 - 已注入闸门的服务入口(设计 §9 映射表): | 服务动作 | 入口 | 所需类别 | |----------|------|----------| | 上架/修改服务套餐 | `GuideManagementController` package/add、package/{packageId}/update | `planner` | | 家庭绑定(开始服务) | `BindController.accept` | `planner` | | 激活成长方案(下发任务) | `PlanReviewController.activate` | `planner` | | 咨询响应/接单 | `TeacherMessageController.reply` | `planner` | | 订单中心(列表/统计/详情) | `GuideOrderController` /list、/stats、/detail | `planner` | | 测评录入/解读 | `GuideAssessmentController` family/enable | `assessor` | - 待建设入口(当前代码不存在,预留):营养方案/饮食建议(`nutritionist`)。 --- ## 六、CF 值体系统一 · 配置治理接口(F-1 / W0.1) > 口径:`docs/superpowers/plans/2026-10-24-cf-value-unification-plan.md` §3.6.6 / §3.7 W0.1 > 本批只提供 **数据层 + 配置层** 接口,发放/扣减接口在 F-2/F-3 批新增。 ### 6.1 服务配置中心(`/api/admin/service-config`) 唯一配置中心(`service_config` 表):CF 通用运营参数(key 前缀 `cf.`,`product_key` 为空)+ product 侧配置(`product_key` 非空,key 形如 `product.{productKey}.{key}`,W0.2 由 `product_config` 并入)。保存后自动 `CfConfigCache.invalidate()`(本地缓存 TTL 60s)+ `cf.version` 自增。 | 路径 | 说明 | |------|------| | `POST /api/admin/service-config/list` | 配置列表,body 可选 `{"groupKey":"cf.rate","productKey":"gut_health"}`,不传返回全部(`productKey` 为产品维度筛选,W0.2 新增) | | `POST /api/admin/service-config/save` | 保存配置(upsert),body `{"configKey":"cf.rate.points_multiplier","configValue":"1.0","updatedBy":1}`;传 `productKey` 则写入 product 侧配置(自动加 `product.{productKey}.` 前缀并回填 `product_key`,W0.2 新增),可另传 `description` | | `POST /api/admin/service-config/invalidate` | 手动失效 CF 配置缓存(排障用) | 已登记配置项:`cf.rate.points_multiplier`、`cf.rate.repeat_rate_default`、`cf.commission.settle_days`、`cf.invite.valid_days`、`cf.price.default_factor`、`cf.stock.deduction_mode`、`cf.rate.share_read_reward_points`、`cf.commission.service_rate`、`cf.product.gut_health_price`、`cf.product.platform_points_share`、`cf.version`。 ### 6.2 CF 值获取规则(`/api/admin/cf-earn-rule`) 24 条规则(F02–F24,F03 拆 F03a/F03b)配置入口;每次保存/开关写 `cf_earn_rule_history` 并失效配置缓存。 | 路径 | 说明 | |------|------| | `POST /api/admin/cf-earn-rule/list` | 规则列表,body 可选 `{"category":"behavior","enabled":1}` | | `POST /api/admin/cf-earn-rule/save` | 新建/编辑(按 `code` 判重),body 含 `code/name/category/ruleType/amount/formula/paramsJson/dailyLimitPerMember/totalLimitPerMember/cooldownSeconds/dedupRefType/remark/changedBy/changeReason` | | `POST /api/admin/cf-earn-rule/toggle` | 启停,body `{"code":"F07","enabled":0,"changedBy":1,"changeReason":"..."}` | | `POST /api/admin/cf-earn-rule/history` | 变更历史,body 可选 `{"code":"F07","limit":100}` | > 读取封装:`ConfigService.getConfig(key)`(缓存 60s → DB → 兜底常量);product 侧配置读取:`ConfigService.getProductConfig(productKey, key)`(W0.2);规则读取:`CfEarnRuleService.getByCode(code)`。 ### 6.3 产品配置中心(`/api/admin/product-config`,**已废弃 410 Gone**) W0.2 双配置中心合并:`product_config` 已并入 `service_config`(唯一配置中心),product 侧配置通过 `product_key` 关联产品;本控制器写接口统一返回 410 Gone(HTTP 410 + body `code=410`),保留 30 天只读窗口后由运维删表。 | 路径 | 说明 | |------|------| | `POST /api/admin/product-config/list` | 【410 Gone】已废弃,改用 `POST /api/admin/service-config/list`(body 传 `productKey` 筛选) | | `POST /api/admin/product-config/save` | 【410 Gone】已废弃,改用 `POST /api/admin/service-config/save`(body 传 `productKey`) | 时间线:2026-10-24 起写接口下线(product_config 只读保留 30 天回滚用);2026-11-23 起确认无回滚需求后删表并移除本控制器。 ### 6.4 F-6 存量账本迁移(迁移417,无新增接口) 启动时由 `DatabaseInitializer` → `CfLegacyLedgerMigrationService` 一次性执行,无 REST API。迁移只读旧表、不回写旧表: | 来源 | 目标成员 | `cf_balance_log.ref_type` | `ref_id` | 口径 | |------|----------|---------------------------|----------|------| | `family_platform_balance` | 家庭 `families.creator_id` 对应的 `family_members` | `migration_family_pool` | `0` | `available + frozen` 合入新 `available`,`withdrawn`/`exchanged` 原样带入 | | `family_members.system_points > 0` | 当前成员 | `migration_system_points` | `family_members.id` | `system_points` 合入新 `available` | | `user_platform_balance` | 该用户本人对应的 `family_members` | `migration_user_wallet` | `user_platform_balance.id` | `available + frozen` 合入新 `available`,`withdrawn`/`exchanged` 原样带入 | 幂等键为 `(member_id, type='adjust', ref_type, ref_id)`(对齐 F-2 迁移416 升级后的唯一键 `uk_ref_type`);重复启动按三类 `ref_type` 逐笔跳过,余额与流水同事务提交。三套旧账本保留为只读历史,写接口 410 Gone 由 F-8 收口。 ### 6.5 F-4 分佣收口 + F03a/F03b 发放接入(迁移418 / 迁移420,无新增接口) > 口径:计划 §四 / §3.1 / §4.2 / §4.4。发放链路由 `CfCommissionService` 统一承载,无新增 REST 接口;`/api/commission/cf/rate` 返回值扩展两级档位字段(见 4.33)。 **迁移内容:** | 迁移 | 内容 | 幂等键 | |------|------|--------| | 418 | `cf_direct_sales_tier` / `cf_indirect_sales_tier` 各补 5 档种子(青铜/白银/黄金/铂金/钻石,缺行才补、不覆盖)+ `cf_earn_rule.dedup_ref_type` 对齐为规则编码(F03a→'F03a'、F03b→'F03b') | 按 `min_annual_ppoints` / `min_self_ppoints` 判重;UPDATE 带 `WHERE dedup_ref_type <> code` | | 420 | 新建 `ppoint_consumption_log`(滚动一年档位聚合数据源:消费支付成功落一行,`created_at >= now()-365d` 聚合)。注:迁移419 已被 `membership_levels.max_daily_analyze` 占用,本表顺延为 420 | `UNIQUE uk_order (order_type, order_id)` 同一订单重复触发只记一行 | **发放链路(`CfCommissionService.settle` / `settleReferrerOnly`):** ``` 本单 P 点基数(商品: 元×有效P点/100;非商品: 元×service_rate bps/10000) → 落 ppoint_consumption_log(幂等) → referral_tree 按 level 升序上溯,跳过同家庭(D5) → 第1个非同家庭引荐人 → getTeamAnnualPpoints(referrerId, 8) → matchDirectSalesTier → F03a → 第2个非同家庭引荐人 → getSelfAnnualPpoints(referrerId) → matchIndirectSalesTier → F03b → cfBalanceService.earnByRule(memberId, "F03a"/"F03b", orderId, {base_ppoints, rate_percent}) (公式 floor(base_ppoints*rate_percent/100),幂等键复用 F-2 uk_ref_type,只写 cf_balance + cf_balance_log) → F03a 且非幂等命中时 autoCreateGratitudeEffect(感恩记录) ``` - 数量与比例零硬编码:比例来自档位表,上限来自 `cf_earn_rule.params_json.max_rate_percent`,金额由公式计算。 - 与 F-3a 共存:`CfCommissionService` 同时承载两条链路 —— 当前消费人 F02(`CfEarnDispatchService.earnConsumeCf`,按实付金额,商品订单实付与分润基数分离)与推荐人 F03a/F03b(本节);两条链路都只写 `cf_balance` + `cf_balance_log`,`cf_transfer_record` 不再由本服务写入。 - 旧分佣写接口 `CommissionDistService.distribute` 已废弃:抛 `IllegalStateException`(消息含 "410 Gone",经 `GlobalExceptionHandler` 转 `Result.error(400, ...)`),无调用方;`commission_dist_log` 转只读历史表,管理端读取接口(`/api/admin/commission-dist/*`)保留不变。 - `cf_rate_tier` 表保留只读,仅供等级展示(`PromotionTierService` / 管理端档位配置)使用。 *文档更新:2026-10-24(CF 值体系统一 F-1 数据层 + W0.1 配置归口:8 张新表/迁移407-412 + service_config 与 cf_earn_rule 管理端接口);同日补登 W0.2 双配置中心合并(service_config 收编 product_config:迁移413 + product_key 维度 + product-config 接口 410 Gone + 配置中心统一入口);同日补登 F-6 存量迁移(迁移417 + 三套旧账本幂等迁入 cf_balance);2026-10-25 补登 F-4 分佣收口(迁移418/420 + 两级销售奖档位 + /rate 扩展字段 + CommissionDistService.distribute 410 Gone)* ### 6.6 C 端 CF 查询接口(F-7a,只读) > 口径:计划 §七 F-7a。个人 CF 值账本为成员维度(`family_members.id`),登录 `userId → memberId` > 解析与 `CfEarnDispatchService.resolveMemberId`(F-3a)口径一致:`user_id` 匹配 + 按 `id` 升序 > `LIMIT 1`;未找到对应家庭成员时返回 `Result.error(404, "未找到当前用户对应的家庭成员,...")`,不返回空数据。 > > 控制器:`CfBalanceController`,前缀 `/api/cf`(**GET,需登录**;注:本项目接口惯例为 POST,本组 > 只读接口按 F-7a 任务要求采用 GET,若团队统一要求 POST 可一行改回)。 | 路径 | 说明 | |---|---| | `GET /api/cf/balance` | 我的 CF 值快照。按登录用户解析 memberId 后读 `cf_balance`,返回 `CfBalanceView`:`memberId` / `available`(可用) / `frozen`(冻结) / `totalEarned`(累计获得) / `totalWithdrawn`(已提现) / `exchanged`(已兑换消费)。无 `cf_balance` 记录时返回全 0 | | `GET /api/cf/logs?page=1&size=20` | 我的 CF 流水分页(时间倒序),复用 `CfBalanceService.getLogs(memberId, page, size)`,输出转 `CfBalanceLogVO`:`id` / `type`(earn/spend/freeze/unfreeze/withdraw/adjust/skip) / `refType`(规则编码或迁移标识) / `amount`(带符号变动) / `balanceAfter`(变动后可用余额) / `remark` / `createdAt`(ISO 8601)。返回 MyBatis-Plus `Page` 结构(current/size/total/pages/records) | | `GET /api/cf/family-coupons` | 家庭共享优惠券列表(N3 口径)。复用 `CouponService.listMyCoupons(userId)`:按登录用户所属家庭查 `family_coupon` + `coupon` 联合数据(券家庭化全链路已切换至 `family_coupon`,`user_coupon` 为只读历史表),返回 `userCouponId` / `couponId` / `name`(券名) / `type` / `value`(面额,分) / `discountRate` / `minSpend` / `applicableTo` / `status`(AVAILABLE/USED/EXPIRED/DISABLED) / `validFrom` / `validUntil`(有效期) / `receivedAt` / `usedAt` / `orderId` / `productId`,家庭内成员共享可见 | - 实现走统一账本 `CfBalanceService` / `CouponService`,本控制器不直接写库、不提供任何写接口。 - 流水/余额响应结构单测:`cfc-backend/src/test/java/com/etotem/cfc/unit/CfBalanceControllerTest.java`(memberId 解析命中/未命中 + balance/logs 字段映射)。 ### 4.56 管理端-素材库(`/api/admin/file-record/*`) > 控制器:`FileRecordController`(`controller/admin/FileRecordController.java`),前缀 `/api/admin/file-record`。 > 服务层:`FileRecordService`;文件存储复用 `StorageService.storeFileRecord(MultipartFile, category)` > (`JdCloudStorageService` / `LocalDiskStorageService` 实现),统一写入 `file_record` 并推导 `file_type`。 > 权限:全部 `@PostMapping`,控制器内 `@RequestAttribute("role") == "admin"` 守卫(无 token 时为 `anonymous`,直接拒绝)。 > 数据表:`file_record`(唯一键 `uk_hash` 去重)、`file_tag`(`uk_name`)、`file_tag_rel`(`uk_file_tag`),均为既有表,无新增迁移。 **`file_type` 口径**(与 `util/FileTypeResolver.java` 一致): | file_type | 判定 | |-----------|------| | `image` | `content_type LIKE 'image/%'` | | `video` | `content_type LIKE 'video/%'` | | `audio` | `content_type LIKE 'audio/%'` | | `document` | `content_type LIKE 'text/%'` 或 PDF/Office/RTF/ODF 白名单 | | `other` | 其它(含 `application/octet-stream`、content_type 缺失) | > 写入侧(新数据):content_type 缺失或为 `application/octet-stream` 时按扩展名兜底;历史回填见 `docs/migrations/20261025_asset_library_file_type_backfill.sql`(严格按 content_type 分类,不用扩展名兜底)。 **接口清单:** | 路径 | 说明 | |------|------| | `POST /api/admin/file-record/list` | 分页检索。Body:`{ page, pageSize, category, fileType, search, dateFrom, dateTo, tagIds }`;`tagIds` 为数组或逗号分隔字符串,**前置过滤**(先按标签 JOIN 过滤再分页,保证 total 正确)。返回 `{ records, total, page, pageSize }`,records 元素含 `id/hash/url/fileSize/contentType/originalFilename/category/fileType/description/createdAt/updatedAt/tags` | | `POST /api/admin/file-record/upload` | 统一上传入库。multipart 字段:`file`(必填)、`category`(选填,默认 `general`)、`tagIds`(选填,数组或逗号分隔)。存储 → 写 `file_record`(SHA-256 去重,命中返回既有记录并补打本次标签)→ 关联标签。图片(contentType 以 image 开头)先过微信内容安全检测(`WechatServiceInterface.checkImage`,fail-open,与旧 `AdminArticleController#uploadImage` 保持一致)。返回素材记录 map | | `POST /api/admin/file-record/update` | 更新描述/标签。Body:`{ id, description?, tagIds? }`;`tagIds` 传空数组表示清空标签,不传表示不改动 | | `POST /api/admin/file-record/delete` | 删除素材。Body:`{ id }`;先删 OSS 文件(失败仅告警)再删记录及其标签关联 | | `POST /api/admin/file-record/tags` | 标签字典列表(按 sortOrder 排序) | | `POST /api/admin/file-record/tag/create` | 新建标签。Body:`{ name, color?, sortOrder? }`,name 唯一 | | `POST /api/admin/file-record/tag/update` | 更新标签。Body:`{ id, name?, color?, sortOrder? }` | | `POST /api/admin/file-record/tag/delete` | 删除标签。Body:`{ id }`(级联清理 `file_tag_rel`) | | `POST /api/admin/file-record/stats` | 统计。返回 `{ total, totalBytes, byFileType: [{file_type, cnt}], byCategory: [{category, cnt}] }` | **上传响应示例(`data` 为素材记录):** ```json { "id": 1024, "hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "url": "https://bucket.endpoint/uploads/general/xxx.png", "fileSize": 102400, "contentType": "image/png", "originalFilename": "cover.png", "category": "articles", "fileType": "image", "description": null, "createdAt": "2026-10-25T12:00:00", "updatedAt": "2026-10-25T12:00:00", "tags": [] } ``` **前端配套:** `cfc-web/src/utils/asset.js`(API 封装 + `resolveAssetUrl`)、`cfc-web/src/components/AssetPicker.vue`(素材选择弹窗,image/video/document 三类)、`cfc-web/src/views/admin/AssetLibrary.vue`(素材库管理页,路由 `/admin/asset-library`)、`cfc-web/src/utils/editorAssetUpload.js`(wangEditor 上传配置公共封装,端点统一指向本组 upload)。 **上传点接入范围与跳过说明(`cfc-web/src` 全量 `el-upload` 排查结果):** | 页面 | 处理 | |------|------| | `ArticleEdit` / `ActivityEdit` / `ProductEdit` | 接入:富文本 `MENU_CONF.uploadImage/uploadVideo.server` 改指本组 upload(`fieldName=file` + Bearer),`customInsert` 统一 `resolveAssetUrl`;新增「从素材库选择图片/视频」按钮 | | `HomeBannerManage` / `ProductSkuEditor` / `GuidePackages` | 接入:封面上传改指本组 upload,并加「从素材库选择」 | | `KnowledgeDialog` | 接入:文档可从素材库选取(`assetType=document`),原有的本地知识文件上传通道保留不变 | | `Activities` / `ArticleManage` / `SupplierProductManage` | 跳过:仅列表展示页,无上传控件 | | `RecommendationRules` / `IndicatorMappings` | 跳过:无文件上传控件(后者为文本批量导入) | | `ProxyReportUpload` / `teacher/ProxyReport` / `ReportParserImport` / `ReportCollectorTrainer` / `ReportUnknownCluster` / `teacher/GrowthRecords` | 跳过:业务报告/JSON 解析包上传,走报告解析专用端点(`/api/admin/report-parser/*` 等),非 jdcloud 媒体资产,纳入素材库会污染 `file_record` 分类语义 | | `ReportTemplateManage` | 跳过:仅表单 tab,无图片字段 | > 旧端点 `POST /api/admin/articles/upload/image|video` **保留可用**(兼容既有调用方),但后台页面已统一改走素材库 upload,以便自动入库与打标签。 **存量回填:** `docs/migrations/20261025_asset_library_file_type_backfill.sql`(备份 → 按 content_type 回填 file_type → 修正列注释 → 校验),不占用 DatabaseInitializer 迁移编号(407-421 为 CF 体系保留)。 *文档更新:2026-10-25(后台素材库:/api/admin/file-record/* 上传入库 + 标签字典 + 统计;file_type 口径统一为 image/video/audio/document/other)* --- ## 4.49 家庭归因核心闭环(`/api/attribution/*` + `/api/survey/attribution/*`) > 阶段二(ATT-S2,B1–B4):「归因分析 → 条件问卷 → 自然语言调整 → 七章干预方案」。 > **E12 合规后置**:全流程由 `app.attribution.enabled`(默认 `false`)开关控制,仅测试/mock 数据环境开启; > 真实用户放行 = 阶段四 D1 完成日。未开启时返回 `Result.error(4001, …)`。 > **合规即服务**:红线 RL01–RL10 由规则层硬注入,AI 只产叙述/调整,不负责合规判定(§1.3)。 ### `POST /api/attribution/analyze` — ③ 归因分析(十节结构报告) - **Body**:`{ familyId?, memberIds[], gutReportIds[], danResultIds[], confirmSurveyRecordId?, planId?, mock?, mockFlags? }` (`mockFlags` 仅 E12 测试环境,可显式注入中间态键) - **Resp** `data`:`AttributionReportVO { id, familyId, status, reportJson, intermediateState, redlineHits, conclusionLocked, createdAt }` - `reportJson`:十节结构(一结论先行/二四人数据速览/三逐人归因/四家庭系统归因/五应对方案/六12周可检验目标/七教练提问序列/八问诊清单/九红线与转介/十一句话收尾) - `intermediateState`:含 `l.reuteriAbnormal/ironLow/hasDan/isFemaleTeen/hasDiabetes` 等键(B1 中间态) - `redlineHits`:RL01–RL08(阶段③④注入);RL09/RL10 属方案阶段⑤ - 状态流转:`ANALYZING`(插入)→ `READY`(回填报告后更新) - **前置**:常模缺失指标 → 「待补」,不猜值(`warnings` 携带说明) ### `POST /api/survey/attribution/confirm-questions` — ② 条件问卷路由 - **Body**:`{ familyId, memberId, attributionId, answeredSummary? }` - **Resp** `data`:`ConfirmQuestionVO { templateId, questions[], hasHighRisk, highRiskQuestionIds }` - `questions[]`:按 对象×年龄×结论 条件下发 `family_attribution` 模板子集(16 条中) - 对象级题目只下发给该对象;家庭级(四人/全家)恒发 - Q11–Q13 携带 `riskLevel=high`;命中 → `hasHighRisk=true`(E4 弱提示,不阻断) ### `POST /api/survey/submit` — ② 提交(B2 扩展:riskHits) - **Body**:`{ userId, memberId, templateId, answersJson, periodStart?, periodEnd?, riskHits? }` - `riskHits`(Q11/Q12/Q13 命中标记)并入 `answersJson._attributionRiskHits` 落库,供 B1 红线检测 - E4:高风险命中不阻断提交,仅标记「建议专业评估」 ### `POST /api/attribution/adjust` — ④ 自然语言调整 - **Body**:`{ attributionId, message, conversationId? }` - **Resp** `data`:`AdjustResult { attributionId, status, answer, fieldDeltas, intermediateState, redlineHits, redlineTerminate, blocking, referral, planInvalidated }` - AI 回答可携带 `[ATTR_DELTA]{"键":新值}` 结构化增量 → 回填 `intermediate_state`(七层 Socratic,PRD §C ④) - RL02 命中 → `redlineTerminate=true`、`blocking=false`(E4 弱提示不阻断)、`referral` 露出转介信息 + 家长确认 - 若已关联方案且 `status=GENERATED` → 作废为 `INVALIDATED`(⑤ 失效重生成) - AI 不可用 → 规则兜底话术,流程不阻断 ### `POST /api/attribution/confirm-adjust` — ④ 确认调整 - **Body**:`{ attributionId }` - **Resp** `data`:`AdjustResult { status=CONFIRMED, conclusionLocked=true }`(结论锁定,B4 前置条件) ### `POST /api/attribution/plan` — ⑤ 七章干预方案 - **Body**:`{ attributionId }` - **前置**:归因结论须 `CONFIRMED`(否则 `Result.error(4000, …)`) - **Resp** `data`:`FamilyPlanVO { planId, planJson, totalDays, status }` - `planJson`:`header` + 7 章(数据速览/主线产品/分人方案/家庭共享/12周节奏/红线与转介/附录) - 人范围:仅 妈妈/女儿/儿子(E6,爸爸链外);每动作带 `level`(P0/P1/daily/P2) + `reviewHook`(复盘钩子) - 儿童补剂动作仅写「医生定」,无剂量数字(RL03);产品品牌级(Enagic 还原水/姜黄、PHGG、菌株名)且带 RL05 合规口径 - 落库 `health_plans`,`plan_type=family_attribution_plan`,`status=GENERATED`(⑤) *文档更新:2026-10-28(家庭归因核心闭环 B1–B4:/api/attribution/analyze、/api/attribution/adjust、/api/attribution/confirm-adjust、/api/attribution/plan、/api/survey/attribution/confirm-questions;/api/survey/submit 扩展 riskHits)* --- ## 4.57 家庭指标聚合方式配置 + 珍珠图/章鱼图家庭汇集 > 五维能量页(身/智/富/行/心)三视角:① 个人看自己各维度;② 家庭管理员看家庭成员各维度;③ 看整个家庭各维度汇总。 > 家庭各维度汇总方式可配置:**SUM=合计 / AVG=平均 / COLLECT=汇集**(如行页面珍珠图、章鱼图)。 > 配置作用域 = **平台级全局一份**(`family_metric_agg_config` 表,按数据项一行一条,迁移433)。 > 默认五维 AVG 保持既有页面数值表现不变(向后兼容);SUM/COLLECT 由后台配置页调整即生效。 **数据表 `family_metric_agg_config`**: | 字段 | 说明 | |------|------| | `metric_key` (UNIQUE) | 数据项唯一标识:`energy.body`/`energy.mind`/`energy.wisdom`/`energy.action`/`energy.wealth`/`energy.overall`/`pearl.resources`/`octopus.effects` | | `metric_name` | 中文名 | | `dimension_code` | 所属维度:body/mind/wisdom/action/wealth/common | | `agg_type` | SUM=合计 / AVG=平均 / COLLECT=汇集 | | `value_type` | NUMBER(数值)/ COLLECTION(集合) | | `display_mode` | number/bar/radar/merge_graph | | `sort_order` / `status` / `remark` | 排序 / active|disabled / 备注 | **配置 CRUD**(`/api/admin/family-metric-agg/*`,供 cfc-web 管理端,`admin` 角色守卫): | 路径 | 说明 | |------|------| | `POST /api/admin/family-metric-agg/list` | 全量配置列表(配置项 < 50,无需分页)。返回 `[ { id, metricKey, metricName, dimensionCode, aggType, valueType, displayMode, sortOrder, status, remark } ]` | | `POST /api/admin/family-metric-agg/save` | 新增/更新(body 带 `id` 则更新,否则新增)。Body:`{ id?, metricKey, metricName, dimensionCode, aggType, valueType, displayMode?, sortOrder?, status?, remark? }` → `true` | | `POST /api/admin/family-metric-agg/delete` | Body `{ id }` → `true` | | `POST /api/admin/family-metric-agg/update-status` | Body `{ id, status }` → `true` | **家庭汇集数据**(供小程序行页面,全 POST): | 路径 | 说明 | |------|------| | `POST /api/pearl/family/resources` | 珍珠图家庭汇集。data:`{ members: [ { memberId, memberName, memberType, colorKey, items: [原珍珠资源项结构 + groupType/groupTypeName/ring] } ] }` | | `POST /api/octopus/effect/family/list` | 章鱼图家庭汇集。data:`{ members: [ { memberId, memberName, memberType, colorKey, effects: [原章鱼成效项结构] } ] }` | - `memberType`:`user`(家庭主账号,memberId=users.id)/ `member`(家庭成员,memberId=family_members.id) - `colorKey`:稳定色值键(0..n-1 索引,同一成员前后一致),供前端按成员着色 - 成员收集与 `EnergyService.doCalculateFamilyEnergy` 一致(家庭主账号 role=parent + `getActualChildren` 去重);个人数据查询复用既有逻辑(`ResourceService.getPearlResources` / `KeyPersonService.listEffects`),不重写业务规则 **五维聚合改造(`EnergyService.doCalculateFamilyEnergy` 第 4 步)**:按 `metric_key`(`energy.body`…)查配置取 `agg_type`: - AVG → 既有平均逻辑(默认,行为不变) - SUM → 合计(sum,不再除以 count) - COLLECT → 数值维度不适用,回落 AVG + 日志记录 - 读不到配置 → 回落 AVG(保证兼容) *文档更新:2026-10-31(家庭数据汇总方式配置(后端):family_metric_agg_config 表 + 配置 CRUD 4 接口 + 珍珠图/章鱼图家庭汇集 2 接口 + 五维聚合读配置)* --- ## 4.58 供应商团队邀请(`/api/admin/supply-team/*`)—— T38 > **需求来源**:廖总 2026-11-02「在我的团队加一个邀请功能,邀请其他用户加入团队」。规格:`docs/superpowers/specs/2026-11-01-team-system-design.md` §3.5 / §4.2 / §4.3(任务 T38)。 > > **语义**:团队成员 = **邀请加入**(与 `referral_tree` 推广返佣是两套独立模型,不在此范围)。凭邀请码加入者成为**团队成员**(非客户),且以邀请人为**上级**(`supply_hierarchy.parent_id=邀请人`,`level=父级level+1`)→ 成员子树 = 该成员自己的团队,与 §0.5「唯一负责人整体结算、平台不拆分」口径一致。 > > **数据模型**:`supply_system_member` 扩列 `invite_code VARCHAR(50)`(个人专属邀请码,迁移444 幂等 `ensureColumn` + 唯一索引 `uk_supply_member_invite_code`;schema.sql 已同步)。 ### 接口列表(3 个,全部 `@PostMapping`) | 路径 | 说明 | |------|------| | `POST /api/admin/supply-team/invite-code` | 生成/获取**我的**邀请码(幂等)。body:`{ systemId, refresh? }`;`refresh=true` 重置旧码(旧码立即失效)。返回 `{ inviteCode, systemId, teamName, shareText }`。**越权防护**:须为该体系的 admin/active 成员 | | `POST /api/admin/supply-team/invite/info` | 邀请码信息(**确认页**展示)。body:`{ inviteCode }` → `{ systemId, teamName, inviterId, inviterNickname, inviterAvatar, memberCount, active }`。仅展示团队名/邀请人昵称头像/成员数,**不泄露其他隐私** | | `POST /api/admin/supply-team/invite/join` | 凭邀请码**加入团队**(挂邀请人为上级)。body:`{ inviteCode }` → 加入后的团队/邀请人信息(同 invite/info 结构) | ### 边界规则 - **同一 `(systemId, userId)` 仅加入一次**:已 active 加入 → 报错「您已在该团队中,无需重复加入」;被移除(`status=inactive`)→ **可再次申请**(自动恢复 active)。 - **自助加入即生效**(默认口径),团队负责人可随时移除;`role=member` **不可自助变更**(沿用 `member/change-role` 管理员权限)。 - **邀请码永久有效 + 唯一**(唯一索引兜底);`refresh` 可重置为新码。 - **邀请不与资金/佣金直接挂钩**:结算走唯一负责人口径(§0.5),平台不拆分团队内部分配。 - 团队 `status != active` 时不可生成邀请码、不可加入。 ### 前端 - `cfc-frontend/pages/vendor/team-system/team-system.vue`:团队成员区新增「邀请成员」按钮 → 弹窗(邀请码 + 复制 + 刷新重置;小程序码可后置)。 - `cfc-frontend/pages/vendor/team-invite/team-invite.vue`(新增,已注册 `pages.json`):受邀确认页——展示邀请人/团队 → 点「加入团队」→ 成功态 → 跳转「我的团队」;支持 `?code=XXX` 带参进入,也可手动输入邀请码。 - `cfc-frontend/utils/api.js`:`getVendorInviteCode` / `getVendorInviteInfo` / `joinVendorTeamByInvite`(各 URL 唯一规范入口)。 *文档更新:2026-11-02(T38 团队邀请功能:supply_system_member 扩 invite_code + 邀请码生成/信息/凭码加入 3 接口 + 前端邀请入口与受邀确认页)* --- ## 4.59 报告闭环批次契约补写(B-2,2026-11-06 开工包核对) > 来源:`docs/tdd/orchestration/report-closedloop-kickoff-20261106.md`(23 SC → 19 能力键)。 > 本批为**契约核对补全**:对照 `origin/cfclub` 实际 Controller 源码(`git show origin/cfclub:<路径>`), > 将开工包「契约接口范围」映射到**实际已存在端点**,补齐 API_REFERENCE 缺失条目。 > 统一 `@PostMapping`、响应 `Result`、JWT 鉴权(JwtInterceptor 拦截 `/api/**`)。 > **未实现端点**(`/api/search/global`、`/api/provider/report-parse/connect`、`/api/health/report/{compare,trend,diet,share,refresh-dim}`) > 见 4.59.10 契约缺口。 ### 4.59.1 管理端-报告解析进度 / 解析中台(SC-A-02 `admin.reportParse.typeList`) > Controller:`ReportParseAdminController`(`/api/admin/report-parse`)+ `ReportParserAdminController`(`/api/admin/report-parser`)。 > 鉴权:JwtInterceptor 对 `/api/**` 统一拦截;管理员角色校验在 `JwtInterceptor` 之后(admin 登录态)。 | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/admin/report-parse/list` | `{page=1, size=20, parseStatus?, reportType?, keyword?}`(keyword 匹配 originalFilename/userId) | `{total, records[]}`;records 元素:`draftId/userId/reportType/originalFilename/fileHash/parseStatus/parseMethod/parseError/parseAttempt/nextRetryAt/parseStartedAt/parseFinishedAt/collectValidation/draftStatus/confirmedReportId/createdAt/updatedAt` | 草稿解析进度分页查询(按 updatedAt 倒序) | | `POST /api/admin/report-parse/retry` | `{draftId}` | `{draftId, parseStatus:"collecting"}` | 手动重试:重置解析进度(`resetForManualRetry`)并重新提交异步采集(`submitAsyncCollect`) | | `POST /api/admin/report-parse/backfill-food` | `{reportId}` | `{reportId, foodCount}`;失败返回 `Result.error(e.getMessage())` | 食材回填:重新解析报告并覆盖写入 foods(失败保留旧载荷);`IllegalArgumentException`/`IllegalStateException` 转错误 | | `POST /api/admin/report-parser/dan/reparse` | `{uploadId, dimension}`(均必填) | `danReportUploadService.reparseUpload(...)` 结果 | DAN 报告按维度重新解析(`ReportParserAdminController`) | > `ReportParserAdminController` 其余端点(`types`/`types/save`/`types/toggle`/`types/delete`/`fingerprints/list`/`fingerprints/save`/`fingerprints/delete`/`imports`/`imports/import`/`imports/approve`/`imports/reject`/`unknown-clusters`/`unknown-uploads`/`generate-type`)已在 4.30 登记。 ### 4.59.2 健康报告全链路契约(SC-C-06 `health.report.view` / SC-X-02 `health.report.closedLoop`) > Controller:`HealthReportController`(前缀 `/api/health`)。报告归属由 `health_reports.subject_id`(family_members.id,可 null)表示; > 无归属报告不参与方案生成。成员级查看权限(管理员 / 本人 / 被授权成员)在 `list/detail/payload` 逐接口校验。 > **两阶段入库**:Phase 1 上传建草稿(`/upload-only` 或 `/report/parse`)→ Phase 2 确认入库(`/report/confirm`)。 | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/health/report/create` | body:`{memberId?, reportType, overallScore?, gutHealthScore?, chronicDiseaseScore?, nutritionScore?, gutAge?, gutType?, gutBalanceScore?, gutDiversityScore?, beneficialBacteriaScore?, harmfulBacteriaScore?, ...}`(reportType 必填:`physical_exam`/`gut_flora`) | `HealthReport`(含 id) | 创建健康报告(含指标明细)。付费墙:未购买「健康启航计划」返回 `code=4001`「请先购买健康启航计划体验包」;memberId 缺省取 `currentMemberId` | | `POST /api/health/report/latest` | `{memberId?}`(缺省 currentMemberId) | `HealthReport`(无则 null) | 获取成员最新健康报告 | | `POST /api/health/report/list` | `{memberId?, page?, size?}` | `page` 未传 → `List`(兼容小程序);`page` 传 → 分页结构 `{total, records[]}` | 报告列表。未传 memberId 返回当前家庭全部报告(按 `visibleIdentityIds` 权限过滤;管理员全部可见);传 memberId 且无查看权限 → 空列表 | | `POST /api/health/report/detail` | `{reportId}` | `Map`:报告详情(含指标明细 + 菌群数据 + 疾病风险评估) | 完整详情;权限校验(本人/管理员/被授权成员),无权返回「无权查看该报告」 | | `POST /api/health/report/payload` | `{reportId}` | `Map`:报告 payload(编辑回填用,按需加载) | 同 detail 权限校验 | | `POST /api/health/report/edit` | `{reportId, subjectId?, payload}` | `"已更新"` | 编辑已发布报告(修正 AI 解析错误值);subjectId 可 null 表示解绑,变更时重算旧/新成员维度分 | | `POST /api/health/report/delete` | `{reportId}` | `"已删除"` | 删除报告 | | `POST /api/health/report/download` | `{reportId}` | `{fileUrl, fileName}`(本地相对路径 `/uploads/**` 自动拼当前域名) | 报告文件下载信息(供 uni.downloadFile) | | `POST /api/health/report/upload` | multipart `file`(仅 PDF) | 兼容接口:自动执行「解析→确认」两阶段(内部 `pdfParseService.parse`) | 向后兼容旧调用;新链路走 `/upload-only` + `/report/parse` + `/report/confirm` | | `POST /api/health/report/parse` | `{draftId}` | 解析结果(draftId/payload/matchedMemberId/extracted/needBind 等) | Phase 1 按草稿 ID 触发解析:LangGraph 优先(`/api/v1/report/parse`),失败回退本地 Java 解析 | | `POST /api/health/report/confirm` | `{type="pdf", draftId, subjectId?, payload?}`;`type=tongue` 时 `{recordId, subjectId?, indicators?}` | `{reportId, ...}` | Phase 2 确认草稿入库:写正式表 → 归一化指标管道 → 绑定成员 → 刷新 7 维评分/指标当前值/食材推荐 → 自动生成方案(非 tongue 类型)。`payload` 可回传修改后指标(用户在线编辑后整体提交) | | `POST /api/health/report/discard` | `{type="pdf", draftId}`;`type=tongue` 时 `{recordId}` | `"草稿已放弃"` | 放弃草稿(仅草稿创建者本人) | | `POST /api/health/report/archive` | `{reportId}` | `"报告已归档"` | 归档报告(软删除) | | `POST /api/health/report/archive-batch` | `{reportIds:[Long]}` | `"已归档 N 份报告"` | 批量归档(管理端选中删除) | | `POST /api/health/report/audit/pending` | `{page=1, size=20}` | `List` | 管理端:待审核报告草稿列表 | | `POST /api/health/report/audit/confirm` | `{draftId, subjectId?}` | `{reportId, subjectId, ...}` | 管理端:审核确认入库。B2-3:平台角色(admin/AdminRoles)可确认任意草稿,非平台角色仅确认自己创建草稿;确认后刷新食材推荐 | | `POST /api/health/report/audit/discard` | `{draftId}` | `"报告已丢弃"` | 管理端:审核丢弃 | > 报告归属(reassign/unlinked/bind)见 4.36.1;报告跨家庭转移(transfer/request、approve、deny、list)为本链路的跨家庭归属场景,已实现(`reportTransferService`),契约随 4.36.1 口径(`{reportId}` → `{requestId, status}`)。 ### 4.59.3 报告代传闭环(SC-P-67 / SC-T-03 / SC-T-23 `health.report.proxyUpload` / SC-X-13 `health.report.proxyClosedLoop`) > 开工包建议路径 `/api/health/report/proxy-upload`,**实际实现为两阶段**:`/api/health/report/proxy-parse`(预览,仅解析不入库)+ `/api/health/report/proxy-confirm`(确认入库)。 > Controller:`HealthReportController`。 | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/health/report/proxy-parse` | multipart/query:`file`(新上传)**或** `fileUrl`(草稿过期后基于原文件重新解析,B3-2 降级),`familyId`(必填),`subjectId?`,`reportType=auto`(空/auto→`gut_flora`),`note?` | 预览结果:`{draftId, payload, matchedMemberId, extracted*, needBind, fileUrl, proxyUploaderId, proxyUploadNote, reparse, parseMethod("langgraph"/"local"), parseFallback}` | 代上传报告(预览模式)。权限三层校验:① `isProxyUploader`(admin/teacher/approved 营养师/approved 规划师,否则 `code=500`「无权限代上传报告…」)② `canProxyForFamily`(B2-2,非平台角色须 familyId ∈ 有效家庭集,否则「无权为该家庭代传报告」,不建草稿不写文件)③ `FamilyAccessInterceptor` 兜底(HTTP 403 `{"code":403,"message":"无权访问该家庭数据"}`)。建草稿拿 draftId → LangGraph 解析(失败回退本地 Java,`parseFallback=true`/`parseMethod="local"`) | | `POST /api/health/report/proxy-confirm` | `{draftId, subjectId?}` | `{reportId, subjectId, aiAnalysis?, aiAnalysisStatus("success"/reason), aiAnalysisMessage?}` | 代确认报告(入库)。B2-3:仅草稿创建者本人或平台角色可确认(`auditConfirm(draftId, subjectId, userId, isAdmin)`);确认后写入 `health_reports.proxy_uploader_id`/`proxy_upload_note`(取草稿 remark)→ 刷新食材推荐 → 触发 AI 解读(T29-B1-5:失败不静默吞错,`aiAnalysisStatus`/`aiAnalysisMessage` 回传) | > 代传与自传共用同一「归属校验」口径:`subjectId` 绑定成员 + `health_reports.subject_id` 落库,跨角色闭环(家长/规划师代传 → 归属校验 → 确认入库)经 `proxy-parse`/`proxy-confirm` 完成,无独立 `proxy-upload` 端点。 ### 4.59.4 报告查看权限 / 分享(SC-P-84 `health.report.share`) > 开工包建议路径 `/api/health/report/share`,**实际实现**为「报告成员级权限管理」(`ReportMemberPermissionController` + `HealthReportController` `/report/permission/*`)+ 通用内容分享(`ShareController` `/api/share`)。 #### 4.59.4.1 报告查看权限(`/api/health/report/member-permission/*`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/health/report/member-permission/list` | 无 body | `List`:家庭全部授权记录 | 家庭管理员操作;`IllegalArgumentException` 转 `Result.error` | | `POST /api/health/report/member-permission/members/{memberId}` | path `memberId` | `List`:已授权用户 ID 列表 | 查询某成员的已授权用户 | | `POST /api/health/report/member-permission/grant` | `{targetMemberId, granteeUserId}` | `Boolean` | 授权:让指定用户可查看某成员的报告 | | `POST /api/health/report/member-permission/revoke` | `{targetMemberId, granteeUserId}` | `Boolean` | 撤销授权 | | `POST /api/health/report/member-permission/visible-members` | 无 body | `Set`(null=管理员全部可见) | 查询用户可见的成员 ID 集合 | #### 4.59.4.2 报告级权限(`HealthReportController` `/report/permission/*`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/health/report/permission/add` | `{reportId, userId}` | `"权限添加成功"` | 添加报告查看权限(授权家庭成员查看该报告) | | `POST /api/health/report/permission/remove` | `{reportId, userId}` | `"权限移除成功"` | 移除报告查看权限 | | `POST /api/health/report/permission/check` | `{reportId, userId}` | `Boolean` | 检查用户是否有该报告查看权限 | #### 4.59.4.3 通用内容分享(`ShareController` `/api/share`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/share/create` | `{targetType, targetId, shareChannel="wechat", title=""}`(需登录) | `ShareEvent` | 创建分享记录(报告/方案/文章/商品统一入口,`targetType` 区分) | | `POST /api/share/click` | `{shareEventId}` | `null` | 记录分享点击 | | `POST /api/share/read` | `{shareEventId, duration=0}` | `{rewarded:Boolean}` | 记录分享阅读;首次阅读且登录 → 发放阅读奖励积分 | | `POST /api/share/my` | 无 body(需登录) | `List`(最多 50 条) | 我的分享记录 | | `POST /api/share/stats` | 无 body(需登录) | `Map`:分享统计 | 分享统计 | | `POST /api/share/family-footprint` | 无 body(familyId 由 JWT 注入) | `Map`:家庭健康足迹 | P3 分享页:家庭健康足迹 | | `POST /api/share/qrcode` | `{page, scene?}`(scene ≤32 字符,需登录) | `{qrCodeBase64:"data:image/png;base64,..."}` | 生成分享小程序码(商品/活动/文章详情页海报) | ### 4.59.5 DAN 报告模块(SC-C-07 / SC-T-12 `dan.assessment.viewReport`、SC-T-11 `dan.assessment.uploadReport`、SC-P-39 `dan.assessment.viewResult`、SC-P-24 / SC-T-21 `health.report.compare`) #### 4.59.5.1 DAN 报告独立流程(`DanReportController` `/api/dan-report`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/dan-report/upload` | multipart:`file`(PDF)、`dimension`、`memberId` | `Map`:`uploadAndParse` 结果(预览 + 解析字段) | Phase 1 上传并预览 DAN PDF | | `POST /api/dan-report/{id}/edit` | body `DanReportEditDTO` | `DanReportUploadVO` | 编辑草稿 | | `POST /api/dan-report/{id}/confirm` | `{childName?, assessmentDate?}` | `DanReportUploadVO` | Phase 2 确认入库 | | `POST /api/dan-report/{id}/discard` | 无 body | `null` | 放弃草稿 | | `POST /api/dan-report/{id}/complete-analysis` | 无 body | `null` | 完成分析(标记) | | `POST /api/dan-report/{id}` | path `id` | `DanReportUploadVO` | 详情(权限:有归属成员须 `canViewMemberReports`;无归属仅上传者本人/家庭管理员) | | `POST /api/dan-report/list` | `{memberId?, dimension?}` | `List` | 列表。未传 memberId 按可见身份过滤该家庭全部;传 memberId 校验 `canViewMemberReports`(无权限返回空列表) | | `POST /api/dan-report/compare` | `{uploadIdA, uploadIdB}` | `uploadService.compareUploads` 结果 | DAN 报告两版对比(按 uploaded_at 对齐 parsed/edited_items 算 delta) | #### 4.59.5.2 测评对比(`AssessmentComparisonController` `/api/assessment/compare`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/assessment/compare/by-child` | `{memberId?}`(缺省 currentMemberId) | `CompareResult`(首次 vs 最新测评对比) | 至少两次完成测评,否则 `Result.error("至少需要两次完成测评才能对比")` | | `POST /api/assessment/compare/by-child-dimension` | `{memberId, dimensionCode}` | `DimensionDelta`(单维度变化) | 数据不足 → `"暂无足够数据"` | | `POST /api/assessment/compare/by-family` | 无 body(familyId JWT 注入) | `List` | 家庭所有成员首次 vs 最新;无家庭 → `Result.noFamily` | | `POST /api/assessment/compare/narrative` | `{memberId?}` | `String`(进步叙事) | 获取进步叙事 | #### 4.59.5.3 测评结果 / 报告查询(`guide/AssessmentController` `/api/assessment` + `AssessmentResultController`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/assessment/result/{id}` | path `id` | `DanAssessmentResult` | 测评报告详情。**仅 `role=teacher` 可查看**(否则「只有指导师可以查看测评报告」);`canViewAssessment` 权限校验 | | `POST /api/assessment/my-results` | 无 body | `List` | 指导师自己的测评报告列表(仅 teacher) | | `POST /api/assessment/child-results` | 无 body | `List` | 下级指导师的测评报告列表(仅 teacher,`getAccessibleAssessments`) | | `POST /api/assessment/latest-result` | `{memberId?}`(缺省 currentMemberId) | `AssessmentResultDTO`(无则 null) | 成员最新认知测评结果(已在 4.10 登记,此处补 DTO 字段:memberId/childName/overallScore/attentionScore/focusScore/memoryScore/logicScore/perceptionScore/spatialScore/processingSpeedScore/analysisReport/growthSuggestions/assessmentDate) | | `POST /api/assessment/history` | `{memberId, size=5}` | `List`(assessmentDate/overallScore) | 成员测评历史(status=completed,按 assessmentDate 倒序) | #### 4.59.5.4 测评报告上传 / 指导意见 / 方案(`AssessmentReportController` `/api/dan-assessment/result`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/dan-assessment/result/plans/list` | query/body `{familyId?, childId?}`(缺省 JWT familyId) | `List`(按 createdAt 倒序) | 家庭/成员已生成的测评方案列表;缺 familyId → `"缺少familyId参数…"` | | `POST /api/dan-assessment/result/upload` | multipart `file`(仅 PDF)、`memberId`、`notes?` | `DanAssessmentResult`(status=draft,异步解析) | 家庭主账号上传测评报告(已在 4.10 登记);非 PDF → HTTP 415 `{code:415}` | | `POST /api/dan-assessment/result/{resultId}/guidance/save` | `{items:[GrowthGuidance]}`(非空) | `List` | 保存结构化指导意见(已在 4.10 登记) | | `POST /api/dan-assessment/result/{resultId}/guidance` | 无 body | `List` | 获取结构化指导意见 | | `POST /api/dan-assessment/result/{resultId}/confirm-inbox` | `{overallScore?}` | `DanAssessmentResult`(status=completed) | 用户确认报告入库并**自动生成测评方案**(无需规划师审核) | ### 4.59.6 报告趋势 & 饮食推荐闭环(SC-P-25 `health.report.trend`、SC-P-26 `health.report.dietRecommend`、SC-X-10 `health.report.trendClosedLoop`) > 开工包建议路径 `/api/health/report/trend`、`/api/health/report/diet`;**实际实现**:趋势走 `/api/health/nutrition/trend`(报告营养趋势)与 `/api/food/recommendation/trend`(食材推荐趋势);饮食推荐走 `/api/food/recommendation/*`、`/api/meal/*`、`/api/diet/*`(4.11 已登记)。 #### 4.59.6.1 报告趋势(`HealthReportController` `/api/health/nutrition/trend`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/health/nutrition/trend` | `{memberId}` | `Map`(`childNutritionProfileService.getReportTrendData`) | 报告趋势数据(营养档案多期序列) | #### 4.59.6.2 食材推荐(`FoodRecommendController` `/api/food/recommendation`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/food/recommendation/index` | `{memberId?}` | 当前食材推荐指数列表 | 按成员取推荐(`foodRecommendService`) | | `POST /api/food/recommendation/history` | `{memberId?}` | 历史推荐 | 食材推荐历史 | | `POST /api/food/recommendation/by-family` | `{familyId?}`(JWT) | 家庭成员食材推荐汇总 | 家庭维度汇总 | | `POST /api/food/recommendation/caution` | `{memberId?}` | 慎用/忌口清单 | 食材提醒 | | `POST /api/food/recommendation/members` | `{familyId?}` | 家庭内参与成员 | 推荐参与成员列表 | | `POST /api/food/recommendation/trend` | `{memberId?}` | 推荐趋势 | 食材推荐多期趋势 | > 报告确认/代确认后 `foodRecommendService.recalculateForUser(subjectId)` 自动刷新食材推荐指数(见 4.59.2 `/report/confirm` 与 4.59.3 `/proxy-confirm`)。 #### 4.59.6.3 餐食推荐(`MealRecommendController` `/api/meal`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/meal/recommend` | `{...}` | 推荐菜单 | 基于报告/偏好推荐餐食 | | `POST /api/meal/replace` | `{...}` | 替换后菜单 | 换一道菜 | | `POST /api/meal/log` | `{...}` | 保存结果 | 记录食用 | | `POST /api/meal/logs` | `{memberId?, date?}` | 记录列表 | 食用记录列表 | | `POST /api/meal/nutrition-summary` | `{memberId?, date?}` | 营养汇总 | 营养摄入汇总 | ### 4.59.7 报告类型链接 / 检测(`ReportParserController` `/api/report-parser`,4.36 补充) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/report-parser/types/links` | 无 body | `List<{typeId, displayName, linkedProductId, productName}>` | 小程序公开:返回已激活且配置了商城商品链接的报告类型(`is_active=1 AND linked_product_id IS NOT NULL`),供「查看商品」入口;未配置链接的类型不出现在结果中 | | `POST /api/report-parser/detect` | `{...}` | 指纹检测结果 | 报告指纹检测(同步返回,供调用方识别类型) | ### 4.59.8 报告摘要(`ReportSummaryController` / `ReportSummaryAdminController`) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/report-summary/list` | `{...}` | 摘要列表 | 报告摘要列表(C 端) | | `POST /api/report-summary/detail/{id}` | path `id` | 摘要详情 | 报告摘要详情 | | `POST /api/report-summary/download/{id}` | path `id` | 下载信息 | 报告摘要下载 | | `POST /api/admin/report-summary/list` | `{page?, size?, ...}` | 分页摘要 | 管理端摘要列表 | | `POST /api/admin/report-summary/sync` | `{...}` | 同步结果 | 管理端手动同步报告摘要 | ### 4.59.9 LangGraph 报告解读依赖登记(SC-B-04 `coach.growthReport.interpret` / SC-B-11 `coach.growthReport.ask`) > **本批仅登记依赖,不做实现**(契约在 cfc-langgraph 侧)。Java 侧通过 `HealthReportController` 内 `restTemplate` 调用, > `langgraph.base-url`(报告解析)/ `python.base-url`(通用 AI)由 `application.yml` 配置。 | LangGraph 端点 | 请求 | 用途 | Java 侧触发点 | |----------------|------|------|---------------| | `POST {langgraph}/api/v1/report/parse` | `{file_path, user_id, family_id?}` | 报告解析(PDF → 结构化载荷) | `/api/health/report/parse`、`/proxy-parse`(`callLangGraphParse`);失败回退本地 Java 解析 | | `POST {langgraph}/api/v1/analyze` | `{report_id, user_id, focus}` | 报告 AI 解读(growthReport.interpret) | `/proxy-confirm` 的 `triggerAiAnalysis`(REPORT_READING 配额:BASIC 1 次/月,FAMILY 及以上不限;失败回传 `aiAnalysisStatus`) | | `POST {langgraph}/api/v1/chat` | 会话上下文 | 报告细节追问(growthReport.ask) | 对话链路(AIChatController / 报告反馈 `/api/health/feedback/*`,见 4.37) | > 依赖边界:报告解读/追问能力**不在 cfc-backend 实现**,由 cfc-langgraph graph 提供;本批只登记调用契约,不新增 Java 端点。 ### 4.59.10 契约缺口(开工包建议路径与现状不符,**待实现 / 等价物替代**) | 开工包建议路径 | 现状 | 说明 | |----------------|------|------| | `POST /api/search/global` | **不存在**(无 SearchController) | SC-P-82 `misc.globalSearch` 全局搜索(报告/方案/任务/商品)**未实现**;搜索需求当前分散:`/api/diet/ingredients/search`(食材)、文章/商品搜索各自接口。待实现时在本节登记 | | `POST /api/provider/report-parse/connect` | **不存在**(无 ProviderController) | SC-S-09 `provider.reportParse.connect` 商品服务商报告解析接入**未实现**;服务商(PROVIDER 角色)当前经 `/api/vendor/*`、`/api/admin/supply-*` 体系管理,无独立报告解析对接端点 | | `POST /api/health/report/compare` | **不存在** | SC-P-24/T-21 `health.report.compare` 报告对比由等价物承载:`/api/dan-report/compare`(DAN 两版对比)+ `/api/assessment/compare/*`(测评首次 vs 最新)。如需跨报告类型统一对比,待实现 | | `POST /api/health/report/trend` | **不存在** | SC-P-25 `health.report.trend` 由等价物承载:`/api/health/nutrition/trend` + `/api/food/recommendation/trend`(+ 既有 `/api/indicator/trend`、`/api/cognitive/trend`) | | `POST /api/health/report/diet` | **不存在** | SC-P-26 `health.report.dietRecommend` 由等价物承载:`/api/food/recommendation/*` + `/api/meal/*` + `/api/diet/*`(4.11) | | `POST /api/health/report/share` | **不存在** | SC-P-84 `health.report.share` 由等价物承载:`/api/share/*`(通用分享)+ `/api/health/report/member-permission/*`(成员级授权,4.59.4) | | `POST /api/health/report/refresh-dim` | **不存在** | SC-P-91 `health.report.refreshFiveDim` 无显式端点:五维能量重算在 `/report/confirm`、`/proxy-confirm`、`/report/reassign` 链内自动触发(`dimensionScoreService.refreshFromGutReport` + `refreshMemberIndicatorCurrent` + `recalculateForUser`);如需手动重算入口待实现 | *文档更新:2026-11-06(B-2 报告闭环开工包契约核对补全:4.59.1 报告解析中台 `/api/admin/report-parse/*` + `dan/reparse`;4.59.2 健康报告全链路;4.59.3 代传闭环 `proxy-parse`/`proxy-confirm`;4.59.4 报告权限/分享;4.59.5 DAN 报告模块;4.59.6 趋势与饮食推荐;4.59.7 报告类型链接/检测;4.59.8 报告摘要;4.59.9 LangGraph 依赖登记;4.59.10 契约缺口与等价物映射)* --- ### 4.60 平台运营能力(SC-A-01~22、A-25~27,EVD-11 契约核对增补) > 平台运营 = Web 管理端(`cfc-web`)与运营治理端点。以下为 2026-11-07 契约核对(EVD-11,开工包 `docs/tdd/orchestration/admin-ops-kickoff-20261107.md`)实测回填的端点存在性。完整核验表与实现缺口见 `docs/superpowers/specs/2026-11-07-admin-ops-contract.md`。 > 约定:所有端点 `POST`;管理端端点需 `role=admin`(`JwtInterceptor` + 控制器内角色检查)。 #### 4.60.1 管理端登录(`AdminAuthController`,类级前缀 `/api/admin-auth`) > ⚠ 注意:类级前缀是 `/api/admin-auth`,**不是** `/api/admin/auth`(开工包初核曾写后者,实测为准)。 | 路径 | 说明 | |------|------| | `POST /api/admin-auth/login` | 账号密码登录(获取 JWT) | | `POST /api/admin-auth/login-by-password` | 密码登录(备选) | | `POST /api/admin-auth/send-code` | 发送验证码 | | `POST /api/admin-auth/info` | 当前管理员信息 | | `POST /api/admin-auth/change-password` | 修改密码 | | `POST /api/admin-auth/reset-password` | 重置密码 | | `POST /api/admin-auth/update-info` | 更新管理员信息 | | `POST /api/admin-auth/account-roles` | 账号角色列表 | | `POST /api/admin-auth/wechat-scan-qr` | 微信扫码登录二维码 | | `POST /api/admin-auth/wechat-scan-poll` | 微信扫码登录轮询 | #### 4.60.2 全局统计(`StatsController` `/api/stats`) | 路径 | 说明 | |------|------| | `POST /api/stats/dashboard`、`/overview`、`/trend`、`/revenue`、`/traffic`、`/membership` | 全局统计大盘(概览/趋势/营收/流量/会员) | | `POST /api/stats/family/summary` | 家庭维度汇总 | | `POST /api/stats/child/overview`、`/child-completion`、`/family-completion` | 孩子/家庭完成度 | | `POST /api/stats/points/ranking`、`/product-view` | 积分排行 / 商品浏览统计 | #### 4.60.3 报告解析中台(`ReportParseAdminController` `/api/admin/report-parse`,SC-A-02/A-16) > 类名注意:源码类名为 `ReportParseAdminController`(非 `AdminReportParseController`),前缀 `/api/admin/report-parse`。 | 路径 | 说明 | |------|------| | `POST /api/admin/report-parse/list` | 解析任务列表 | | `POST /api/admin/report-parse/types`、`/types/save`、`/types/delete`、`/types/toggle` | 报告类型 CRUD | | `POST /api/admin/report-parse/unknown-clusters`、`/unknown-uploads`、`/generate-type` | 未知类型聚类 / 待标注 / 生成类型(自学习) | | `POST /api/admin/report-parse/fingerprints/list`、`/save`、`/delete` | 指纹管理 | | `POST /api/admin/report-parse/imports`、`/imports/import`、`/imports/approve`、`/imports/reject`、`/retry` | 解析导入审批链(SC-A-16 标注链) | | `POST /api/admin/report-parse/dan/reparse`、`/backfill-food` | DAN 重解析 / 食物回填 | #### 4.60.4 文章发布-审核(`AdminArticleController` `/api/admin/articles`,SC-A-03) | 路径 | 说明 | |------|------| | `POST /api/admin/articles/list`、`/detail`、`/create`、`/update`、`/delete`、`/move` | 文章 CRUD + 排序 | | `POST /api/admin/articles/publish`、`/{id}/publish`、`/submit-review`、`/audit`、`/withdraw`、`/re-draft` | 发布-审核流 | | `POST /api/admin/articles/categories/list`、`/create`、`/update`、`/delete` | 文章分类管理 | | `POST /api/admin/articles/comments/list`、`/reading-records` | 评论/阅读记录 | | `POST /api/admin/articles/upload/image`、`/upload/video`、`/toggle-featured`、`/backfill-tags` | 素材上传 / 精选 / 标签回填 | #### 4.60.5 勋章配置 CRUD(`BadgeController` `/api/badges` + `AdminChallengeScoreConfigController`,SC-A-05) | 路径 | 说明 | |------|------| | `POST /api/badges/all`、`/list`、`/detail`、`/create`、`/update`、`/delete` | 勋章字典 CRUD | | `POST /api/badges/grant`、`/statistics/member`、`/member/list`、`/ranking/family`、`/favorite` | 发放 / 统计 / 成员视角 / 排行 / 收藏 | | `POST /api/admin/challenge-score-config/list`、`/update` | 挑战分规则配置 | #### 4.60.6 供应商管理(`SupplyManageController` `/api/admin/supply-manage` + `SupplyHierarchyController` `/api/admin/supply-hierarchy` + `AdminSupplierController` `/api/admin/supplier`,SC-A-06) | 路径 | 说明 | |------|------| | `POST /api/admin/supply-manage/list`、`/detail`、`/create`、`/update`、`/delete`、`/add-role`、`/remove-role`、`/adjust-tier` | 供应商 CRUD + 角色/层级调整 | | `POST /api/admin/supply-hierarchy/tree`、`/my`、`/parent`、`/parent-chain`、`/direct-children`、`/all-children`、`/set`、`/remove` | 供应层级树 | | `POST /api/admin/supply-hierarchy/change/apply`、`/change-requests`、`/change/review` | 层级变更审批 | | `POST /api/admin/supplier/list`、`/save`、`/update`、`/delete` | 供应商主体管理 | #### 4.60.7 活动配置(`AdminActivityController` `/api/admin/activity` + `AdminActivityCheckinController`,SC-A-07) | 路径 | 说明 | |------|------| | `POST /api/admin/activity/list`、`/detail`、`/audit`、`/review`、`/submit-review`、`/withdraw`、`/re-draft`、`/backfill-tags` | 活动审核流 | | `POST /api/admin/activity-checkins/list`、`/add`、`/review`、`/export` | 活动打卡配置与审核 | #### 4.60.8 知识库管理(`KnowledgeBaseController` `/api/admin/knowledge-base`,SC-A-08) > 载体为 `KnowledgeBaseController`(非开工包猜测的 `AdminKnowledgeController`)。 | 路径 | 说明 | |------|------| | `POST /api/admin/knowledge-base/list`、`/get`、`/save`、`/delete`、`/upload-file`、`/fetch-url` | 知识条目 CRUD / 导入 | | `POST /api/admin/knowledge-base/bind-tags`、`/bind-dimensions`、`/backfill-tags` | 标签/维度关联 | | `POST /api/admin/knowledge-base/vector/documents`、`/stats`、`/sync`、`/delete-source`、`/update-document` | 向量库管理(`KnowledgeBaseVectorController`) | | `POST /api/admin/knowledge-tag/list`、`/save`、`/delete` | 知识标签字典(`KnowledgeTagController`) | | `POST /api/admin/knowledge-base/unified/overview`、`/section`、`/update`、`/reset` | 统一知识库(`AdminUnifiedKnowledgeController`) | #### 4.60.9 维度配置与维度注册(`DimensionAdminController` `/api/admin/dimension` + `DimensionConfigController` + `DimensionRegistryController`,SC-A-09/A-25) | 路径 | 说明 | |------|------| | `POST /api/admin/dimension/data-source/list`、`/save`、`/delete`、`/detail` | 维度数据源配置 | | `POST /api/admin/dimension/norm/list`、`/save`、`/delete` | 维度参考标准配置 | | `POST /api/admin/dimension-config/list`、`/get`、`/save`、`/delete`、`/tree` | 维度配置 CRUD + 树 | | `POST /api/dimension-registry/*` | 维度注册表查询(`DimensionRegistryController`) | #### 4.60.10 数据迁移 / 参数校验(`DataMigrationController` `/api/migration` + `MigrationController` + `SysConfigController`,SC-A-10) | 路径 | 说明 | |------|------| | `POST /api/migration/run` | 手动触发数据迁移(`DataMigrationController`) | | `POST /api/migrate/guide-packages`、`/migrate/knowledge-base-to-articles` | 专项迁移(`MigrationController`) | | `POST /api/admin/config/list`、`/update`、`/all` | 系统参数/配置校验与维护(`SysConfigController`) | > 补充载体:`DatabaseInitializer` 为启动期自动迁移(非 HTTP),report-parse 参数校验在内置校验逻辑内。 #### 4.60.11 用户/家庭查询治理(`AdminController` `/api/admin` + `AdminOrgMemberController`,SC-A-11) | 路径 | 说明 | |------|------| | `POST /api/admin/users`、`/users/create`、`/user/search`、`/users/{id}`、`/users/{id}/update`、`/users/{id}/delete`、`/users/{id}/reset-password` | 用户治理 | | `POST /api/admin/families`、`/families/{id}`、`/families/{id}/update`、`/families/{id}/delete`、`/families/{id}/members`、`/families/{id}/members/set-admin` | 家庭治理 | | `POST /api/admin/children`、`/children/{id}`、`/children/{id}/update`、`/children/{id}/adjust-points` | 孩子视角管理 | | `POST /api/admin/org/member/list`、`/add`、`/remove`、`/change-type` | 组织成员治理(`AdminOrgMemberController`) | | `POST /api/admin/families/{id}/overview`、`/families/{id}/tasks` | 家庭概览(`AdminFamilyOverviewController`) | #### 4.60.12 订单/退款人工处理(`AdminProductOrderController` `/api/admin/product/order`,SC-A-12) | 路径 | 说明 | |------|------| | `POST /api/admin/product/order/list`、`/detail`、`/ship`、`/update-express`、`/close` | 订单人工处理 | | `POST /api/admin/product/order/refund/approve`、`/refund/reject` | 退款人工审批 | #### 4.60.13 内容安全审核(`ReviewCenterController` `/api/admin/review-center` + 业务 audit 端点,SC-A-13/A-18) | 路径 | 说明 | |------|------| | `POST /api/admin/review-center/summary` | 待审聚合队列(13 类:文章/商品/规划师/服务商/管家/套餐/活动/报名/提现/退款/层级变更/营养师/知识) | | `POST /api/admin/articles/audit`、`/api/admin/activity/audit` | 文章 / 活动审核动作 | | `POST /api/admin/articles/comments/list` | 评论审核列表 | #### 4.60.14 操作审计日志(`OperationLogController` `/api/admin/logs` + `AdminAuditController`,SC-A-15) | 路径 | 说明 | |------|------| | `POST /api/admin/logs/operations` | 操作日志分页查询(按用户/类型/日期过滤) | | `POST /api/admin/logs/recent` | 近期操作日志 | | `POST /api/admin/audit/list` | 审计列表(`AdminAuditController`) | #### 4.60.15 优惠券/活动配置管理(`AdminCouponController` `/api/admin/coupon`,SC-A-17) | 路径 | 说明 | |------|------| | `POST /api/admin/coupon/list`、`/create`、`/update`、`/delete`、`/toggle-status` | 券模板 CRUD | | `POST /api/admin/coupon/issue`、`/issue-family` | 发放(个人 / 家庭) | | `POST /api/admin/coupon/grant-log`、`/grant-user`、`/family-coupons`、`/family-coupon-usage`、`/gift-transfers` | 发放记录 / 家庭券 / 转赠 | #### 4.60.16 能量配置治理(`AdminEnergyConfigController` `/api/admin/energy-config` + `AdminEnergyRuleController` `/api/admin/energy-rule`,SC-A-25/A-26) | 路径 | 说明 | |------|------| | `POST /api/admin/energy-config/overview`、`/daily-limits`、`/daily-limit-save` | 每日上限配置 | | `POST /api/admin/energy-config/source-list`、`/source-save`、`/source-delete` | 能量来源比例配置(SC-A-26) | | `POST /api/admin/energy-rule/list`、`/dimensions`、`/create`、`/update`、`/delete`、`/toggle` | 归因权重规则(SC-A-26) | | `POST /api/admin/dimension-weight/list`、`/save` | 维度权重配置(`DimensionWeightController`,SC-A-25) | #### 4.60.17 睡眠选项维护(`SysConfigController` + `PublicConfigController` + `HealthSleepController`,SC-A-27) | 路径 | 说明 | |------|------| | `POST /api/admin/config/list`、`/update`、`/all` | 管理端维护 `sleep.config.tags`(状态机键 `sleep.config.tags`,YELLOW) | | `POST /api/config/public/value` | 小程序端拉取 `sleep.quality.tags`(`PublicConfigController`) | | `POST /api/health/sleep/list`、`/create` | 睡眠记录(C 端,`HealthSleepController`) | > SC-A-27 已在状态机(YELLOW),本批只登记映射不新建任务(见契约文档 §2)。 #### 4.60.18 契约缺口(无端点载体,需产品侧确认验收方式) | SC | 场景 | 现状 | 处置 | |----|------|------|------| | SC-A-04 | 关系类型 CRUD | 无 `/api/admin/relationship-types`;`relationship_types` 表已废弃 DROP,关系由 `family_relationships`(`/api/family/member/add|update` + `FamilyRelationshipService`)承载 | 无端点载体,需产品侧确认 | | SC-A-14 | 系统监控/告警 | 仅 `POST /api/system/health`(JVM/内存/CPU 探活),无告警规则/记录端点 | 无端点载体,需产品侧确认 | | SC-A-19 | 账号注销/数据导出工单处理 | 无运营工单端点;用户侧自助 `POST /api/user/deactivate`、`POST /api/user/data-export` 已实现 | 无端点载体,需产品侧确认 | | SC-A-20 | 限流/熔断配置 | 无 HTTP 配置端点;`RateLimitInterceptor`(Redis 滑动窗口)+ `AiGateway` 熔断为代码内置 | 无端点载体,需产品侧确认 | | SC-A-21 | 舌诊/情绪模型管理 | `POST /api/admin/innate-portrait-config/{list,update,invalidate}` + `POST /api/mind/emotion/{analyze,analyze-url}` 存在;舌诊模型无独立 admin 端点(内联报告解析链) | 端点载体部分存在,需产品侧确认 | *文档更新:2026-11-07(EVD-11 平台运营 25 SC 契约核对增补「平台运营能力」段落 4.60:管理端登录 / 统计 / 报告解析中台 / 文章审核 / 勋章 / 供应商 / 活动 / 知识库 / 维度 / 迁移 / 用户家庭治理 / 订单退款 / 审核队列 / 审计日志 / 优惠券 / 能量配置 / 睡眠选项 + 契约缺口。完整核验表见 `docs/superpowers/specs/2026-11-07-admin-ops-contract.md`)* ## 4.61 孩子端(不能登录用户视角)接口(EVD-9 契约核对,2026-11-07) > 来源:EVD-9 孩子端 26 SC 契约核对,依据开工包 `docs/tdd/orchestration/child-zone-kickoff-20261107.md`(26 SC,6 个 ⚠ 待核实项已全部实测关闭)。 > 本节端点由 `cfc-backend` 源码全量提取(1935 个 `@PostMapping`)后逐条比对得出;场景口径另参 `tests/user-scenarios/应用场景总览.md` § 四。 > 完整核验表 / 能力键建议 / 缺口清单见 `docs/superpowers/specs/2026-11-07-child-zone-contract.md`。 > 开工包候选载体与实测不一致的 6 处(C-07/C-08/C-12/C-14/C-22/C-24)在下方按实测路径登记。 > 覆盖 SC-C-01 ~ SC-C-26。统一 `@PostMapping`、响应 `Result`、JWT 鉴权(`JwtInterceptor` 拦 `/api/**`)。 > **"不能登录用户"没有自己的 JWT**:孩子端写操作都发生在家长会话下,通过 `memberId` / `currentMemberId` 指定被代管成员。 ### 4.61.1 身份与视角切换(SC-C-01 / SC-C-17 / SC-C-18) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/auth/silent-login` | `{code}`(WechatLoginDTO) | `LoginResultDTO`(`token`/`userId`/`role`/...) | 微信静默登录 | | `POST /api/auth/wechat-login` | `{code,...}`(WechatLoginDTO) | `LoginResultDTO` | 微信授权登录 | | `POST /api/auth/phone-login` | `{phone, code}` | `LoginResultDTO` | 手机号验证码登录 | | `POST /api/auth/auto-login` | `{openid,...}` | `LoginResultDTO` | 自动登录 | | `POST /api/auth/verify` | 无 body,Header `Authorization: Bearer ` | `{userId, role}`;token 无效或用户不存在 → `401` | 会话校验(前端启动探活) | | `POST /api/family/member/switch` | `{memberId, source?}` | `SwitchMemberVO{memberId, source, effectiveRole, nickname, isSwitchable}` | **现行切视角端点**:家长切到孩子视角(孩子端入口) | | `POST /api/family/user/switch-back-verify` | `{password}` | `Boolean` | 密码校验后切回家长视角 | | `POST /api/family/user/switch-to-child` | `{memberId}` | **`410`** | **已废弃**,返回"请使用 /api/family/member/switch" | | `POST /api/family/user/switch-back-to-parent` | 无 | **`410`** | **已废弃**,同上 | | `POST /api/family/invite/check-family` | 无 | 家庭绑定状态 | 账号是否已绑定家庭 | | `POST /api/family/invite/validate` | `{token}` | 校验结果 | 家庭邀请令牌校验 | | `POST /api/family/invite/validate-family-code` | `{inviteCode}` | 校验结果 | 家庭邀请码校验 | > **缺口**:无 `logout` 端点(JWT 无状态,退出=前端清 token,G-03);无任何设备维度(无 deviceId/设备表/异常设备二次验证,G-04)。 > **路径缺陷**:前端 `utils/api.js` 仍调 `/api/user/switch-to-child`、`/api/user/switch-back-to-parent`、`/api/user/switch-mode`、`/api/user/roles`、`/api/user/switch-role`,这些 `/api/user/*` 在 `UserController` 中**无映射(404)**(G-08)。 ### 4.61.2 任务 / 打卡 / 方案进度(SC-C-02 / C-05 / C-08 / C-14) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/tasks/today` | `{memberId?, dimensionCode?, category?}` | `Task[]` | 今日任务 | | `POST /api/tasks/my-pending` | `{memberId?}` | `Task[]` | 待接受任务 | | `POST /api/tasks/accept` | `{taskId, memberId}` | `Boolean` | **⚠ 参数绑定错误**:后端 `@PathVariable Long id` 但路径无 `{id}` → 必抛 `MissingPathVariableException`(G-12) | | `POST /api/tasks/reject/{id}` | `{memberId?}` | `Boolean` | 孩子拒接任务 | | `POST /api/tasks/{id}/start` | `{memberId?}` | `Boolean`/Task | 开始任务 | | `POST /api/tasks/{id}/complete` | `CompleteTaskDTO{memberId?, photoUrl, content, contentType}` | `Map`(奖励/状态) | 打卡提交 | | `POST /api/tasks/{id}/complete-minigame` | `{memberId?, completionTime?, score?}` | `Map` | 以小游戏结果完成任务 | | `POST /api/tasks/{id}/review` | `{approved? , result?, reason?}` | `Boolean` | 家长审核;`approved=false` → `status` 回 `pending`,孩子可重做(C-14) | | `POST /api/tasks/history` | `{memberId?, page, size}` | `Page` | 任务历史 | | `POST /api/daily/checkin/create` | `DailyHealthCheckin`(饮食/运动/睡眠/饮水/心情) | 记录 | 通用每日打卡 | | `POST /api/daily/checkin/list` | `{memberId?, date?}` | `DailyHealthCheckin[]` | 打卡列表 | | `POST /api/health/plan/list` | `{memberId?, page, size}` | `Page` | 成长方案列表 | | `POST /api/health/plan/detail` | `{planId}` | `HealthPlan` | 方案详情 | | `POST /api/health/plan/tasks` | `{planId}` | `Task[]` | 方案任务与进度(含 `plan.getFamilyId()` 归属校验) | | `POST /api/growth-task/list` | `{type?, dimension?}` | `GrowthTask[]` | 成长任务(今日/周期) | | `POST /api/growth-task/claim` | `{taskId?}` | `String` | 领取成长任务(奖励在完成时自动发放) | ### 4.61.3 小游戏与五维能量(SC-C-03 / C-24 / C-25) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/mini-game/list` | `{}`(`familyId` 取自会话) | `MiniGame[]` | 启用的小游戏 | | `POST /api/mini-game/complete` | `CompleteGameDTO{memberId, gameCode, completionTime, score}` | `{pointsEarned, ...}` | 成绩上报:加积分 + 写流水 + 写 `game_record` + 能量 | | `POST /api/game/record` | `{memberId, gameCode, score, completionTime, difficulty?, pointsEarned?}` | `Map` | 直接写游戏记录(`pointsEarned` 由客户端传入,**存在刷分风险**) | | `POST /api/game/history` / `/best` / `/stats` / `/leaderboard` | `{memberId, gameCode?, page?, size?}` | 记录/最高分/统计/排行榜 | 游戏数据查询 | | `POST /api/energy/sandbox` | `{view: "personal"|"family", memberId?}` | `{locked, view, personalData, familyData, familyUnlocked, familyGate?}` | 五维能量(个人+全家一次返回);需先过 `SELF_CHECK` 关卡,未过返回 `locked=true` | | `POST /api/energy/overview` | `{memberId?}` | `Map`(五维分值/变化) | 五维概览 | | `POST /api/energy/logs` | `{memberId?, dimensionCode?, page?, size?}` | `Page` | 能量流水 | | `POST /api/energy/score-history` | `{memberId?, dimensionCode?, page?, size?}` | `Page`(历史快照) | 分值历史 | > **缺口**:`/api/mini-game/complete` 无幂等、`score` 无上限(`score=999999` 可换巨额积分并污染 Redis 排行榜,G-09);`/api/game/record` 的 `pointsEarned` 由前端决定。 > 能量写入只落 `energy_balance` + `energy_log`,**不写 `five_dimension_score` 快照**;`overview`/`logs` 未校验 `memberId` 归属(跨家庭可读,G-10)。 ### 4.61.4 勋章(SC-C-09 / C-10) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/badges/list` | 无 | `Badge[]` | 启用勋章定义(勋章墙底图) | | `POST /api/badges/member/list` | `{memberId}` | `[{memberBadge, badge}]` | 成员已得勋章(收藏优先、获得时间倒序) | | `POST /api/badges/statistics/member` | `{memberId}` | 统计(已得数/分类等) | 勋章统计 | | `POST /api/badges/ranking/family` | 无(`familyId` 取自会话) | 家庭排行 | 成员勋章排行 | | `POST /api/badges/detail` | `{id}` | `Badge` | 勋章详情(达成条件) | | `POST /api/badges/favorite` | `{memberId, badgeId}` | `Boolean` | 收藏/取消收藏 | | `POST /api/badges/grant` | `{memberId?, badgeId}` | `String` | 授予勋章(管理端/家长);**不写通知** | > **缺口**:`BadgeService.grantBadge` 只写 `member_badges`,无 `user_notification`、无推送 → C-10「解锁提醒」未实现(G-01); > 无"任务/打卡自动聚合授予"逻辑(场景要求"勋章来自任务/打卡聚合")。判重已满足(重复授予直接 return)。 ### 4.61.5 报告与成长档案(SC-C-06 / C-07 / C-11 / C-20) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/health/report/list` | `{memberId?, reportType?, page, size}` | `Page` | 健康报告列表(详见 4.59.2) | | `POST /api/health/report/latest` | `{memberId?, reportType?}` | 最新报告 | 最新报告 | | `POST /api/health/report/detail` | `{id}` | 报告详情 | 详情(含 `member-permission` 校验) | | `POST /api/dan-report/list` | `{memberId?, page, size}` | `Page` | DAN 测评报告列表(详见 4.59.5.1) | | `POST /api/dan-report/{id}` | 路径参数 | 报告详情 | 详情(`canViewMemberReports` 校验) | | `POST /api/dan-report/compare` | `{memberId, id1, id2}` | 对比结果 | 两版对比 | | `POST /api/growth/record/list` | 无(取 `userId`) | `GrowthRecord[]` | 本人成长档案 | | `POST /api/growth/record/child/{memberId}` | 路径参数 | `GrowthRecord[]` | 指定成员档案(**⚠ 无归属校验**,G-11) | | `POST /api/growth/record/child-records` | body 为裸 `Long memberId` | `GrowthRecord[]` | 同上(带 `currentMemberId` 缺省逻辑) | | `POST /api/growth/record/{id}` | 路径参数 | `GrowthRecord` | 记录详情(**⚠ 无归属校验**,G-11) | | `POST /api/user/data-export` | 无 | `Map`(`userInfo`/`children`/`assessmentResults`/`healthReports`/`tasks`) | **仅导出登录用户本人**;无 `memberId` 入参 → 无"家长代导出孩子"(G-05) | ### 4.61.6 商城 / 心愿 / 积分(SC-C-04 / C-22) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/wishes/create` | `CreateWishDTO{title, description?, category?, imageUrl?, linkUrl?, estimatedPrice?, memberId?, pointsRequired?}` | `Long`(心愿 id) | 提心愿 | | `POST /api/wishes/list` | `{memberId?, status?, page?, size?}` | `Wish[]` | 心愿列表 | | `POST /api/wishes/{id}` | 路径参数 | `Wish` | 心愿详情 | | `POST /api/wishes/{id}/cancel` | 路径参数 | `Boolean` | 撤销心愿 | | `POST /api/wishes/pending` | 无 | `Wish[]` | 家长待审批 | | `POST /api/wishes/{id}/price` | `{pointsRequired}` | `Boolean` | 家长定价 | | `POST /api/wishes/{id}/approve-exchange` | `{approved}` | `Boolean` | 审批兑换 | | `POST /api/wishes/{id}/reject` | `{reason}` | `Boolean` | 驳回(驳回后不可兑) | | `POST /api/wishes/{id}/fulfill` / `/{id}/confirm` / `/{id}/exchange` | 路径参数 | `Boolean` | 兑现/确认/兑换 | | `POST /api/product/list` | `{page, size, domain?, keyword?}` | `Page` | 商城浏览 | | `POST /api/product/detail` | `{id}` | `Product` | 商品详情 | | `POST /api/points/exchange/product/list` | `{category?, pageNum?, pageSize?}` | `Page` | 积分兑换商品列表 | | `POST /api/points/exchange/product/detail` | `{id}` | `PointsExchangeProduct` | 兑换商品详情 | | `POST /api/points/exchange/submit` | `{productId, memberId, quantity?}` | `PointsExchangeRecord` | 提交兑换(积分不足/重复由 Service 拦截) | | `POST /api/points/exchange/records` | 无(取 `userId`) | `PointsExchangeRecord[]` | 兑换记录 | | `POST /api/points/exchange/stats` | 无(取 `userId`) | `{todayCount}` | 兑换统计 | | `POST /api/points/balance` | `{memberId?}` | `{balance, ...}` | 积分余额 | | `POST /api/points/logs` | `{memberId, page?, size?}` | `Page` | 积分流水 | ### 4.61.7 消息 / 反馈 / 资料(SC-C-15 / C-16 / C-19 / C-23) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/notification/list` | 无(取 `userId`) | `UserNotification[]`(未读优先,`LIMIT 100`) | 站内通知 | | `POST /api/notification/read` | `{id?}` / `{ids?}` / 空(全部已读) | `Boolean` | 标记已读 | | `POST /api/guide/messages/my` | 无(取 `userId`) | `TeacherMessage[]` | 规划师消息 | | `POST /api/guide/messages/unread-count` | 无 | `Long` | 未读数 | | `POST /api/user/info` / `/api/auth/info` / `/api/family/user/info` | 无(取 `userId`) | **完整 `User`**(仅 `password` 置空) | 个人资料(**无受限投影**,G-02) | | `POST /api/user/update` / `/api/family/user/update` | `UpdateUserDTO`/`User` | `Boolean` | 修改资料 | | `POST /api/health/feedback/submit` | 报告反馈 DTO | — | 报告反馈(**仅报告维度**) | | `POST /api/activity/feedback/submit` | 活动评价 DTO | — | 活动评价(**仅活动维度**) | | `POST /api/feedback/today` / `/read` / `/recent` | 无/`{id}`/`{limit?}` | 每日反馈 | **家长→孩子**方向,与"孩子提意见"相反 | > **缺口**:无通用"意见反馈"端点/表/管理端受理(G-06)。 ### 4.61.8 饮食 / AI / 舌诊情绪 / 睡眠(SC-C-12 / C-13 / C-21 / C-26) | 路径 | 请求 | 响应 `data` | 说明 | |------|------|-------------|------| | `POST /api/diet/recommendation/today` | `{date}`(**必填**,空→`Result.error("date不能为空")`) | 今日食谱 | 饮食推荐 | | `POST /api/diet/recommendation/generate` | `{date, ...}` | 食谱 | 生成/重新生成 | | `POST /api/diet/recommendation/complete` | `{date, ...}` | `Boolean` | 完成标记 | | `POST /api/health/meal/daily` / `/weekly` / `/list` | `{memberId?, date?}` | 餐次数据 | 餐次记录 | | `POST /api/ai/chat/send` | `{query, conversationId?}` | `Map`(`answer`/`conversationId`/...) | AI 对话(会员门禁 `checkGate`) | | `POST /api/ai/chat/conversations` / `/chat/messages` | `{conversationId?}` | 会话/消息列表 | 多轮上下文 | | `POST /api/health/report/upload-only` | `multipart(file, memberId?, type=tongue)` | `{type:"tongue", ...}` | 舌诊拍照上传 + 预览(含 `aiGateway.detectTongue` 自动识别分支) | | `POST /api/health/report/parse-preview` | `{recordId?, memberId?, type=tongue}` | 舌诊指标预览 | 解析预览 | | `POST /api/health/report/confirm` | `{recordId, subjectId/memberId, indicators, type=tongue}` | 入库结果 | 舌诊确认 | | `POST /api/health/report/discard` | `{recordId, type=tongue}` | `Boolean` | 放弃草稿 | | `POST /api/mind/emotion/analyze` / `/analyze-url` | 图片/URL | 情绪识别结果 | 情绪自拍识别 | | `POST /api/mind/checkin/create` / `/list` / `/latest` / `/trend` | 身心打卡 DTO | 记录/列表/趋势 | 情绪打卡记录 | | `POST /api/health/sleep/list` | `{memberId?}`(缺省 `currentMemberId`) | `HealthSleepRecord[]` | 睡眠记录 | | `POST /api/health/sleep/create` | `HealthSleepRecord{memberId?, sleepTime:"HH:mm", wakeTime:"HH:mm", durationMinutes?, qualityScore?, remark?, taskId?}` | `HealthSleepRecord` | 睡眠打卡(`taskId` 透传自动完成/累计任务) | | `POST /api/config/public/value` | `{key}` | `String` | 配置读取;睡眠标签应为 `key=sleep.quality.tags` | > **缺口**:`sleep_record` **无 `tags` 列**,标签被前端拼进 `remark` 文本;`/api/health/sleep/tags`、`/api/admin/sleep/tags` 均未实现;key 命名 `sleep.quality.tags`(需求/用例)与 `sleep.config.tags`(sc-key-map)不一致;`sleep-checkin.vue` 仍硬编码 8 项、无「正常」(G-07)。 > AI 对话无适龄过滤入参;舌诊 confirm 需家长会话代传 `memberId`。 ### 4.61.9 契约缺口汇总(详见 `docs/superpowers/specs/2026-11-07-child-zone-contract.md` § 5) | ID | 关联 SC | 一句话 | |----|---------|--------| | G-01 | C-10 | 勋章解锁无通知/推送(`grantBadge` 不写 `user_notification`) | | G-02 | C-16 | 个人资料无受限投影(三处 info 返完整 `User`) | | G-03 | C-17 | 无服务端 `logout`(JWT 无状态) | | G-04 | C-18 | 无设备绑定/异常设备二次验证 | | G-05 | C-20 | 无"家长代导出指定成员";`exportUserData` 只认 `userId` | | G-06 | C-23 | 无通用意见反馈端点/表/管理端 | | G-07 | C-26 | 睡眠标签无 `tags` 列/无专用端点/无管理端/前端硬编码 | | G-08 | C-01/C-17 | 前端 `/api/user/switch-*` 无映射(404);旧 `/api/family/user/switch-to-child` 已 410 | | G-09 | C-02/C-03/C-24 | 小游戏上报无幂等、分数无上限、`pointsEarned` 前端可控 | | G-10 | C-06/C-24 | `energy/overview`、`energy/logs` 未校验 `memberId` 归属(可跨家庭读) | | G-11 | C-11/C-20 | `growth/record/child/{memberId}`、`/record/{id}` 无归属校验 | | G-12 | C-02 | `/api/tasks/accept` 的 `@PathVariable id` 与路径不匹配 → 调用必失败 | > 统计:**26/26 有承载端点**;场景完整闭环 **19/26**;场景级缺口 **7**(C-10/C-16/C-17/C-18/C-20/C-23/C-26);跨切面缺陷 **5**(G-08 ~ G-12)。 *文档更新:2026-11-07(EVD-9 孩子端 26 SC 契约核对:4.61.1 身份与视角切换;4.61.2 任务/打卡/方案进度;4.61.3 小游戏与五维能量;4.61.4 勋章;4.61.5 报告与成长档案;4.61.6 商城/心愿/积分;4.61.7 消息/反馈/资料;4.61.8 饮食/AI/舌诊情绪/睡眠;4.61.9 缺口汇总 G-01~G-12)* ### 4.62 商品服务商域(SC-S-01/05/07/08/10/11,EVD-12R2 契约核对增补) > 归属:契约补建计划 P0「商品服务商域」· 核对 2026-11-07(EVD-12R2) > 核对方法:类级 `@RequestMapping` + 方法级 `@PostMapping` 实测定位(防假 RED)。SC-S-02/03/04/06 由 EVD-4 商城-会员覆盖;SC-S-09 由 EVD-7R 报告闭环覆盖。 > 完整核验表见 `docs/superpowers/specs/2026-11-07-service-provider-contract.md`。 #### 4.62.1 服务商入驻申请(`SupplySystemController /api/admin/supply-system`,SC-S-01 `supplier.apply`) > ⚠ 载体置换:开工包候选 `AdminSupplierController /api/admin/supplier`、`EcomSupplierController /api/admin/ecom-supplier` 均标注「【已废弃】请使用 /api/admin/supply-system/list」,活跃载体为 `SupplySystemController`。 | 路径 | 说明 | |------|------| | `POST /api/admin/supply-system/list` | 服务商体系分页(keyword/status/page/size) | | `POST /api/admin/supply-system/create` | 服务商体系建档(入驻申请提交) | | `POST /api/admin/supply-system/update` | 服务商体系更新 | | `POST /api/admin/supply-system/detail` | 服务商体系详情 | | `POST /api/admin/supply-system/toggle-status` | 启停审核(入驻审核动作) | | `POST /api/admin/supply-system/list-all` | 全量体系(下拉选择) | | `POST /api/admin/supply-system/my-system` | 当前用户所属体系 | | `POST /api/admin/supply-system/my-teams` | 一人多团队(顶部切换器) | | `POST /api/admin/supply-system/member/list` | 体系成员列表 | | `POST /api/admin/supply-system/member/add` | 添加体系成员 | | `POST /api/admin/supply-system/member/remove` | 移除体系成员 | | `POST /api/admin/supply-system/member/change-role` | 成员角色变更 | > 边界:体系层级/团队治理(`SupplyManageController /api/admin/supply-manage`:list/detail/create/update/delete/add-role/remove-role/adjust-tier)由 EVD-11 SC-A-06 覆盖,不重复登记。 #### 4.62.2 库存管理(`AdminInventoryController /api/admin/inventory` + `SupplierProductController /api/admin/supplier/product`,SC-S-05 `supplier.inventory.manage`) **AdminInventoryController `/api/admin/inventory`** | 路径 | 说明 | |------|------| | `POST /api/admin/inventory/inbound/create` | 入库单创建 | | `POST /api/admin/inventory/inbound/list` | 入库单列表 | | `POST /api/admin/inventory/inbound/detail` | 入库单详情 | | `POST /api/admin/inventory/inbound/confirm` | 入库确认 | | `POST /api/admin/inventory/inbound/cancel` | 入库取消 | | `POST /api/admin/inventory/outbound/create` | 出库单创建 | | `POST /api/admin/inventory/outbound/list` | 出库单列表 | | `POST /api/admin/inventory/transactions/list` | 库存流水列表 | | `POST /api/admin/inventory/counting/create` | 盘点单创建 | | `POST /api/admin/inventory/counting/confirm` | 盘点确认 | | `POST /api/admin/inventory/counting/list` | 盘点单列表 | | `POST /api/admin/inventory/alert/list` | 库存告警列表 | | `POST /api/admin/inventory/product/stock` | 商品库存查询 | | `POST /api/admin/inventory/combo/items` | 组合商品项 | | `POST /api/admin/inventory/combo/items/list` | 组合商品项列表 | **SupplierProductController `/api/admin/supplier/product`** | 路径 | 说明 | |------|------| | `POST /api/admin/supplier/product/list` | 服务商商品列表 | | `POST /api/admin/supplier/product/create` | 服务商商品创建 | | `POST /api/admin/supplier/product/update` | 服务商商品更新 | | `POST /api/admin/supplier/product/detail` | 服务商商品详情 | | `POST /api/admin/supplier/product/delete` | 服务商商品删除 | | `POST /api/admin/supplier/product/shelve` | 服务商商品上/下架 | #### 4.62.3 营销活动报名(`ActivityController /api/activity` + `AdminActivityController /api/admin/activity` + `ActivityOrderController /api/activity/order`,SC-S-07 `supplier.activity.signup`) **ActivityController `/api/activity`** | 路径 | 说明 | |------|------| | `POST /api/activity/list` | 活动列表 | | `POST /api/activity/detail` | 活动详情 | | `POST /api/activity/create` | 活动创建 | | `POST /api/activity/update` | 活动更新 | | `POST /api/activity/publish` | 活动发布 | | `POST /api/activity/end` | 活动结束 | | `POST /api/activity/submit-review` | 提交审核 | | `POST /api/activity/register` | 活动报名 | | `POST /api/activity/cancel-registration` | 取消报名 | | `POST /api/activity/my-registrations` | 我的报名列表 | | `POST /api/activity/registration-roster` | 报名名单/核销 | | `POST /api/activity/checkin` | 活动签到 | | `POST /api/activity/checkin-review` | 签到审核 | **AdminActivityController `/api/admin/activity`** | 路径 | 说明 | |------|------| | `POST /api/admin/activity/list` | 活动管理列表 | | `POST /api/admin/activity/review` | 审核 | | `POST /api/admin/activity/detail` | 详情 | | `POST /api/admin/activity/submit-review` | 提交审核 | | `POST /api/admin/activity/audit` | 审核动作 | | `POST /api/admin/activity/backfill-tags` | 标签回填 | | `POST /api/admin/activity/withdraw` | 撤回 | | `POST /api/admin/activity/re-draft` | 退回草稿 | **ActivityOrderController `/api/activity/order`** | 路径 | 说明 | |------|------| | `POST /api/activity/order/create` | 报名订单创建 | | `POST /api/activity/order/pay` | 报名订单支付 | | `POST /api/activity/order/handlePaymentSuccess` | 支付成功回调处理 | | `POST /api/activity/order/notify` | 支付通知 | | `POST /api/activity/order/status` | 订单状态查询 | #### 4.62.4 对账/结算(`AdminSettlementController /api/admin/dan-settlement` + `SupplySettlementController /api/admin/supply-settlement`,SC-S-08 `supplier.settlement.reconcile`) **AdminSettlementController `/api/admin/dan-settlement`** | 路径 | 说明 | |------|------| | `POST /api/admin/dan-settlement/list` | DAN 结算列表 | | `POST /api/admin/dan-settlement/detail/{settlementId}` | DAN 结算详情 | | `POST /api/admin/dan-settlement/confirm/{settlementId}` | DAN 结算确认 | | `POST /api/admin/dan-settlement/stats` | DAN 结算统计 | **SupplySettlementController `/api/admin/supply-settlement`** | 路径 | 说明 | |------|------| | `POST /api/admin/supply-settlement/list` | 供货结算列表 | | `POST /api/admin/supply-settlement/detail` | 供货结算详情 | | `POST /api/admin/supply-settlement/detail-items` | 供货结算明细 | | `POST /api/admin/supply-settlement/create` | 供货结算创建 | | `POST /api/admin/supply-settlement/confirm` | 供货结算确认 | #### 4.62.5 营养/食谱数据供给(`NutritionProductController /api/nutrition/product` + `BeijingNutritionController /api/nutrition/beijing` + `UserNutritionProfileController /api/nutrition/profile`,SC-S-10 `supplier.nutrition.supply`) **NutritionProductController `/api/nutrition/product`** | 路径 | 说明 | |------|------| | `POST /api/nutrition/product/category/list` | 营养品分类列表 | | `POST /api/nutrition/product/brand/list` | 营养品品牌列表 | | `POST /api/nutrition/product/search` | 营养品搜索 | | `POST /api/nutrition/product/detail` | 营养品详情 | | `POST /api/nutrition/product/recommend` | 营养品推荐 | | `POST /api/nutrition/product/price-compare` | 营养品价格对比 | | `POST /api/nutrition/product/from-product` | 从商品转换 | **BeijingNutritionController `/api/nutrition/beijing`** | 路径 | 说明 | |------|------| | `POST /api/nutrition/beijing/bacteria/save` | 北京食谱菌群保存 | | `POST /api/nutrition/beijing/recommend` | 北京食谱推荐 | | `POST /api/nutrition/beijing/recommend/custom` | 北京食谱自定义推荐 | | `POST /api/nutrition/beijing/kb/query` | 食谱知识库查询 | | `POST /api/nutrition/beijing/kb/list` | 食谱知识库列表 | | `POST /api/nutrition/beijing/kb/info` | 食谱知识库详情 | | `POST /api/nutrition/beijing/analysis` | 食谱分析 | **UserNutritionProfileController `/api/nutrition/profile`** | 路径 | 说明 | |------|------| | `POST /api/nutrition/profile/get` | 营养画像查询 | | `POST /api/nutrition/profile/save` | 营养画像保存 | #### 4.62.6 数据导出合规(`UserController /api/user` + `ReportMemberPermissionController /api/health/report/member-permission`,SC-S-11 `supplier.export.compliance`) **UserController `/api/user`(用户侧自助,个保法数据可携带权)** | 路径 | 说明 | |------|------| | `POST /api/user/data-export` | 导出用户数据(`AccountCleanupService.exportUserData`) | | `POST /api/user/deactivate` | 注销账号(数据匿名化,`AccountCleanupService.deactivateAccount`) | **ReportMemberPermissionController `/api/health/report/member-permission`(授权使用约束)** | 路径 | 说明 | |------|------| | `POST /api/health/report/member-permission/list` | 报告授权列表 | | `POST /api/health/report/member-permission/members/{memberId}` | 指定成员的授权详情 | | `POST /api/health/report/member-permission/grant` | 授予报告查看权 | | `POST /api/health/report/member-permission/revoke` | 撤销报告查看权 | | `POST /api/health/report/member-permission/visible-members` | 可见成员列表 | > 边界:EVD-11 SC-A-19 的**运营工单处理**(账号注销/数据导出工单)无端点载体,属平台运营域需产品侧确认;本 SC 为用户侧自助能力。 *文档更新:2026-11-07(EVD-12R2 商品服务商域 6 SC 契约核对增补「商品服务商域」段落 4.62:服务商入驻 / 库存管理 / 活动报名 / 对账结算 / 营养食谱数据供给 / 数据导出合规 + 边界归位说明。完整核验表见 `docs/superpowers/specs/2026-11-07-service-provider-contract.md`)* ### 4.63 家长域剩余(SC-P-02~85,EVD-13 契约核对增补) > 家长域 96 个 SC 中已由既有开工包覆盖:家庭-成员(EVD-2)、任务-心愿(EVD-3)、商城-会员(EVD-4)、五维能量(EVD-5)、报告闭环(EVD-7R)、测评-方案(EVD-8R);本批 = P 域剩余 30 个无键 SC(SC-P-02/04/05/20~23/28~31/49~51/54/61~66/69~71/73/76/78/79/83/85),端点载体逐条实测核验。完整核验表与实现缺口见 `docs/superpowers/specs/2026-11-07-parent-rest-contract.md`。 > 约定:所有端点 `POST`(`NoticeController /api/notices/list` 为 GET+POST 双方法历史遗留,API_REFERENCE §3.6 已记录)。 > **已 GREEN 键复用登记(仅登记不新建,O-2 方案 A 防键重复)**:`health.report.upload`(SC-P-20~23)、`health.report.createReport`(SC-P-23)、`growth.history.view`(SC-P-50)、`langgraph.questionnaire.generate`(SC-P-49)。 #### 4.63.1 家庭与成员 / 上下文(SC-P-02/04/05/73) | 路径 | 说明 | |------|------| | `POST /api/family/member/add`、`/update`、`/list`、`/editable` | 添加/编辑成员(`generationLevel`/`peerType` → `FamilyRelationshipService` 关系写入)、成员列表(统一入口,`visibleOnly`/`includeFamily`)、可编辑检查 | | `POST /api/family/member/switch` | 切换成员/孩子上下文视角(`SwitchMemberVO`,替代已废弃 `/api/family/user/switch-mode` 族) | | `POST /api/family/invite/generate`、`/qrcode`、`/validate`、`/accept`、`/bind-inviter`、`/request-join-by-code` | 邀请成员(令牌复用/补发,`family.invite.reissue` 语义) | | `POST /api/family/relationship/scores`、`/pairwise` | 关系质量查询(`RelationshipQualityController`,命名回填:候选 `RelationshipController` 不存在) | #### 4.63.2 健康报告上传解析(SC-P-20~23,复用 `health.report.upload`/`createReport`) | 路径 | 说明 | |------|------| | `POST /api/health/report/upload-only` | 生产上传入口:PDF → 草稿 `health_report_drafts`(parse_status=collecting)→ **异步采集** → 返回 draftId(前端轮询) | | `POST /api/health/report/upload` | 兼容接口:自动执行「解析→确认」两阶段 | | `POST /api/health/report/parse`、`/parse-preview` | 异步解析 / 解析预览(`type=auto/image/tongue` 识别) | | `POST /api/health/report/collect/status`、`/collecting-list` | 采集进度轮询 / 采集中草稿列表 | | `POST /api/health/report/confirm`、`/discard`、`/audit/confirm`、`/audit/discard` | 确认入库 / 废弃 / 审核确认(SC-P-23 确认入库,`health.report.createReport` 语义) | | `POST /api/report-parser/detect`、`/types/links` | 报告类型识别(`ReportParserController`,SC-P-21) | #### 4.63.3 食谱 / 营养(SC-P-28/29/30/69) | 路径 | 说明 | |------|------| | `POST /api/food/recommendation/index`、`/caution`、`/members`、`/trend`、`/by-family` | 食谱推荐 / 忌口(caution)/ 家庭成员 / 趋势(SC-P-28) | | `POST /api/diet/preferences/current-member`、`/save` | 忌口参数(`DietPreferencesController`,命名回填:候选 `UserFoodPreferenceController` 不存在) | | `POST /api/diet/ingredients/suggest`、`/search`、`/add`、`/remove` | 食材筛选(SC-P-28) | | `POST /api/meal/replace`;`POST /api/diet/recommendation/update`、`/regenerate`、`/complete` | 食谱调整(SC-P-29「调整」);**「收藏」无端点 → 缺口 G-1** | | `POST /api/nutrition/profile/get`、`/save` | 精准营养目标(SC-P-69,`UserNutritionProfileController`) | | `POST /api/diet/recommendation/generate` | 按营养目标生成/对齐(SC-P-30) | | `POST /api/health/nutrition/profile`、`/deficiency`、`/deficiency-summary`、`/trend` | 营养报告段(SC-P-69) | #### 4.63.4 测评类型 / AI 对话(SC-P-31/49) | 路径 | 说明 | |------|------| | `POST /api/dan-assessment/material/active`、`/material/list`、`/points-config`、`/family/config` | 测评类型浏览(DAN 材料/积分配置/家庭测评配置,SC-P-31) | | `POST /api/ai/chat/send`、`/health-coach/send`、`/health-coach/gate`、`/gate` | AI 健康管家对话(SC-P-49,`AiGateway.chat` → LangGraph chat_graph;**复用 `langgraph.questionnaire.generate`,仅登记不新建**) | #### 4.63.5 成长记录(SC-P-50/51) | 路径 | 说明 | |------|------| | `POST /api/growth/record/list`、`/record/child/{memberId}`、`/record/child-records`、`/record/{id}`、`/record/{id}/supplements`、`/record/check-duplicate` | 成长记录查看(SC-P-50,**复用 `growth.history.view`,仅登记不新建**) | | `POST /api/family/relationship/milestones`;`POST /api/invite/milestone/list`、`/claim` | 关系/邀请里程碑(SC-P-51 主场景载体,**成长里程碑无独立端点 → 缺口 G-2**) | #### 4.63.6 商城加购/下单(SC-P-54,EVD-4 已覆部分) | 路径 | 说明 | |------|------| | `POST /api/cart/add`、`/list`、`/update`、`/remove`、`/count`、`/combo-offer`、`/replace-combo` | 购物车(`CartController`) | | `POST /api/product/order/create`、`/pay`、`/cancel`、`/my`、`/my/counts`、`/detail` | 商品订单(`ProductOrderController`;键归属 EVD-4 商城-会员批次 `order.*` 域,本批不新建键) | #### 4.63.7 联系人 / 社交(SC-P-61~63) | 路径 | 说明 | |------|------| | `POST /api/contact/create`、`/list`、`/detail`、`/interaction`、`/invite-to-family` | 联系人添加/详情/互动/邀请入家庭(SC-P-61/63) | | `POST /api/contact/import-phone` | 通讯录导入(SC-P-62,候选 `ContactImportController` 不存在;**分组无端点 → 缺口 G-3**) | | `POST /api/family/user/members/visible`、`/members/update-visibility` | 联系人/成员可见性权限(SC-P-63) | | `POST /api/health/report/member-permission/list`、`/grant`、`/revoke`、`/visible-members` | 报告查看权限(SC-P-63) | #### 4.63.8 设置与通知(SC-P-64/65/66/78/79) | 路径 | 说明 | |------|------| | `POST /api/user/update`、`/info`、`/profile/backfill`、`/profile-stats`;`POST /api/family/user/update`;`POST /api/profile/my` | 个人资料编辑(SC-P-64) | | `POST /api/notification/list`、`/read` | 消息中心/通知查看 + 已读(SC-P-65/78,`UserNotificationController`) | | `POST /api/task/reminder-config/get`、`/save` | 提醒设置(开关/渠道/时机/偏移,SC-P-65/79) | | `POST /api/consent/record`、`/withdraw`、`/status`、`/check` | 隐私授权同意(SC-P-66,`ConsentController`) | | `POST /api/notices/list` | 公告(SC-P-78,GET+POST 历史遗留) | #### 4.63.9 舌诊/情绪采集 · 账号 · 活动 · 反馈 · 会话(SC-P-70/71/76/83/85) | 路径 | 说明 | |------|------| | `POST /api/health/report/parse-preview`(type=tongue)、`/report/confirm`(type=tongue)、`/report/discard` | 舌诊照片采集(SC-P-70,`TongueDiagnosisService` 链) | | `POST /api/mind/checkin/create`、`/list`、`/latest`、`/trend`、`/stats`、`/emotion/recognize` | 情绪打卡/照片识别(SC-P-70,`EmotionCheckinController`) | | `POST /api/user/deactivate`、`/data-export` | 账号注销(`AccountCleanupService.deactivateAccount` 数据匿名化)+ 个保法可携带权导出(SC-P-71) | | `POST /api/activity/register`、`/cancel-registration`、`/my-registrations`、`/registration-roster`、`/checkin` | 活动报名(名额/并发,SC-P-76,`ActivityRegistrationService.occupyQuota` 原子占用名额);`POST /api/activity/order/create`、`/pay` 付费活动 | | `POST /api/health/feedback/submit`、`/list`;`POST /api/activity/feedback/submit`、`/list`、`/my`;`POST /api/feedback/today`、`/read`、`/recent` | 意见反馈(SC-P-83;**在线客服无专用端点 → 缺口 G-4**) | | `POST /api/auth/phone-login`、`/wechat-login`、`/silent-login`、`/auto-login`、`/sso-login`、`/sso-ticket` | 登录族 + SSO 一次性票据(SC-P-85;**无单端互斥/旧会话踢出 → 缺口 G-5**,JWT 无状态) | #### 4.63.10 契约缺口(无完整端点载体,需产品侧确认验收方式) | SC | 场景 | 现状 | 处置 | |----|------|------|------| | SC-P-29 | 食谱收藏/调整 | 「调整」已存在(/api/meal/replace、/api/diet/recommendation/update|regenerate);「收藏」无端点(仅指标收藏 /api/indicator/favorite/* 为异构) | 缺口 G-1,需产品侧确认 | | SC-P-51 | 成长里程碑 | `GrowthController /api/growth` 无里程碑端点;关系/邀请里程碑(/api/family/relationship/milestones、/api/invite/milestone/*)非成长;成长页里程碑为前端聚合 | 缺口 G-2,需产品侧确认 | | SC-P-62 | 联系人分组/导入 | 导入已存在(/api/contact/import-phone);分组无端点 | 缺口 G-3,需产品侧确认 | | SC-P-83 | 意见反馈/在线客服 | 反馈已存在(/api/health/feedback/*、/api/activity/feedback/*、/api/feedback/*);在线客服无专用端点 | 缺口 G-4,需产品侧确认 | | SC-P-85 | 多端登录/会话互斥 | 登录族 + SSO 票据存在;无单端互斥/旧 token 踢出(JWT 无状态) | 缺口 G-5,需产品侧确认 | *文档更新:2026-11-07(EVD-13 家长域剩余 30 SC 契约核对增补「家长域剩余」段落 4.63:家庭与成员 / 健康报告上传解析 / 食谱营养 / 测评类型与 AI 对话 / 成长记录 / 商城加购下单 / 联系人与社交 / 设置与通知 / 舌诊情绪·账号·活动·反馈·会话 + 已 GREEN 键复用登记 4 处 + 契约缺口 5 项。完整核验表见 `docs/superpowers/specs/2026-11-07-parent-rest-contract.md`)* ### 4.64 AI成长教练 + 真人管家域(SC-B-01~12 / SC-H-01~07,EVD-14 契约核对增补) > AI 成长教练(AI 管家)10 SC + 真人管家 7 SC = 17 SC 契约核对(EVD-14,开工包 `docs/tdd/orchestration/ai-butler-kickoff-20261107.md`)实测回填的端点存在性。完整核验表、语义偏差与缺口见 `docs/superpowers/specs/2026-11-07-ai-butler-contract.md`。 > 约定:所有端点 `POST`;`/api/ai/*` 走登录态 + `checkGate(userId)` 会员门禁(`AiGateStatus.UPGRADE_REQUIRED` 拦截);`/api/admin/butler/*` 需 `role=admin/finance`(控制器内角色检查);AI 统一走 `AiGateway`(熔断 failure-threshold=3 / reset-timeout-ms=30000,不可用时降级返回空或显式错误)。 #### 4.64.1 成长咨询对话(`AIChatController` `/api/ai`,SC-B-01/B-11) | 路径 | 说明 | |------|------| | `POST /api/ai/chat/send` | 成长咨询对话(会员门禁 + 家庭上下文/画像注入;LangGraph 不可用 → 空 answer/空 tasks 降级) | | `POST /api/ai/chat/conversations` | 会话历史列表(追问上下文全链路) | | `POST /api/ai/chat/messages` | 指定会话消息列表 | | `POST /api/ai/chat/conversations/{id}/delete` | 删除会话 | > SC-B-01 咨询对话、SC-B-11 报告细节追问(同 conversationId 续聊)共用该组端点。 #### 4.64.2 AI 会员门禁与隐私(`AIChatController`、`PiisService`、`WechatService`,SC-B-05) | 路径 | 说明 | |------|------| | `POST /api/ai/gate` | AI 教练会员门禁状态(`membershipService.checkAiFeatureGate` → status/enabled/canUse/features) | | `POST /api/ai/health-coach/gate` | 健康教练会员付费开关状态(兼容保留,前端统一改调 `/api/ai/gate`) | > ⚠ **语义口径**:上两 gate 为**会员付费门禁**,非敏感词/内容门控。敏感问题拦截与隐私保护的实际载体 = `PiisService` PII 脱敏(姓名→化名、手机号/身份证/邮箱/地址→`[已脱敏]`)接入 AI 输入侧;`WechatService.msg_sec_check`(文本内容安全检测)仅用于文章/媒体发布链路,不在教练对话链路。无独立敏感词拦截端点(缺口,见契约文档 §2.2)。 #### 4.64.3 健康教练跟进与主动成长提醒(`AIChatController` `/api/ai`,SC-B-02/B-12) | 路径 | 说明 | |------|------| | `POST /api/ai/health-coach/send` | 健康教练定向跟进:会员门禁 + focus/memberId/画像注入,解析 `[RECOMMEND]` + `[TASK]` 标记 | > ⚠ SC-B-12「同步规划师建议主动跟进」当前为**用户发起式**(health-coach/send focus 定向),无服务端定时推送端点;`task/` 包 `@Scheduled` 仅业务提醒(BASIC 到期/佣金结算等)。验收按用户主动触发口径。 #### 4.64.4 成长报告智能解读(`AIChatController` `/api/ai`,SC-B-04) | 路径 | 说明 | |------|------| | `POST /api/ai/report/analyze` | 成长报告智能解读(LangGraph 解析;不可用时返回「AI服务暂不可用」显式错误) | #### 4.64.5 营养/任务推荐与采纳(`AIChatController` `/api/ai`,SC-B-07) | 路径 | 说明 | |------|------| | `POST /api/ai/nutrition/send` | 营养推荐:`reportId` 必填 → 菌群分析(`HealthAnalysisService.analyze`)→ 家庭上下文/画像注入 → LangGraph 解析 `[RECOMMEND]`(`parseSimpleJson`)+ `[TASK]` 生成任务列表 | > 推荐采纳载体为 nutrition/send(TASK 即为采纳入口);`/api/butler/commissions` 已废弃 410(见 4.64.7 废弃清单)。 #### 4.64.6 真人管家后勤与家庭自助选择(`butler/ButlerController`、`FamilyButlerSelectController` `/api/butler`,SC-B-01/B-10) | 路径 | 说明 | |------|------| | `POST /api/butler/apply` | 申请成为真人管家(并 SC-B-01 场景载体之一) | | `POST /api/butler/profile` | 管家个人资料详情 | | `POST /api/butler/update-profile` | 更新管家资料 | | `POST /api/butler/members` | 管家绑定家庭成员列表(家庭成长看板单体载体) | | `POST /api/butler/available-list` | 可选择的管家列表(浏览开放) | | `POST /api/butler/my-butler` | 我的管家信息 | | `POST /api/butler/select` | 家庭自助选择管家(L2 绑定受限校验,`ButlerService.selectButler`) | > ⚠ SC-B-09「教练转接成长规划师」实际载体为**规划师绑定流**:`/api/guide/bind/invite` → `/validate` → `/confirm`(BindInviteController)+ `/api/bind/accept`、`/api/bind/unbind`(BindController);`/api/butler/apply|select` 是管家申请/选管家,非转接。 > ⚠ SC-B-10 聚合台账以 admin 侧为准确认(4.64.8),家庭端复用 `/api/butler/members` 单体。 #### 4.64.7 已废弃端点(410,本域旧载体) | 路径 | 状态 | |------|------| | `POST /api/butler/service-records` | `@Deprecated` 410(无替代方案提示);台账替代 = `/api/admin/butler/service-records` | | `POST /api/butler/commissions` | `@Deprecated` 410(无替代方案提示);结算替代 = `/api/admin/butler/settlements` | #### 4.64.8 真人管家运营管理(`AdminButlerController` `/api/admin/butler`,SC-H-01~05/07) | 路径 | 说明 | |------|------| | `POST /api/admin/butler/user-list` | 用户维度管家列表 | | `POST /api/admin/butler/list` | 管家列表(资源清单载体) | | `POST /api/admin/butler/review` | 管家申请审核(升级介入,SC-H-01) | | `POST /api/admin/butler/assign-member` | 指派管家到家庭(一对一家长陪跑,SC-H-02) | | `POST /api/admin/butler/service-records` | 服务记录台账(多方沟通记录 / 质检台账,SC-H-03/H-07;分页) | | `POST /api/admin/butler/settlements` | 佣金结算列表(月结 `calculateButlerSettlement`,SC-H-07) | | `POST /api/admin/butler/assignments` | 管家-家庭分配关系列表(SC-H-01/H-03) | | `POST /api/admin/butler/unassign` | 解绑管家-家庭(SC-H-04,⚠ 语义:停接/解绑运维开关,非应急接管) | | `POST /api/admin/butler/toggle-accepting` | 管家接单开关(SC-H-04,⚠ 语义间接:应急处理验收口径需产品确认) | > 服务记录由 `ButlerCommissionService.createServiceRecord(butlerId, memberUserId, amount, remark)` 落库(`butler_service_records`),结算由 `ButlerCommissionScheduledTask` 月结触发。 #### 4.64.9 AI 管家会话(`ai/ButlerController` `/api/ai/butler`,SC-H-06 协同的会话底座) | 路径 | 说明 | |------|------| | `POST /api/ai/butler/sessions/create` | 创建 AI 管家会话 | | `POST /api/ai/butler/sessions/update-conversation` | 更新会话绑定 conversationId | | `POST /api/ai/butler/sessions/archive` | 归档会话 | | `POST /api/ai/butler/sessions/list` | 会话列表 | | `POST /api/ai/butler/sessions/detail` | 会话详情 | | `POST /api/ai/butler/sessions/delete` | 删除会话 | #### 4.64.10 AI→真人管家协同与资源对接(`AIChatController`、`GuideActivityController`,SC-H-05/H-06) | 路径 | 说明 | |------|------| | `POST /api/ai/butler/send` | AI→管家协同:会员门禁 + child_id/report_id/focus + 画像注入 → answer/tasks(SC-H-06 主载体) | | `POST /api/guide/activities/list`(及 CRUD 组) | 规划师端线下活动创建/编辑/发布(`GuideActivityController`,SC-H-05 活动对接实际载体) | > ⚠ SC-H-05「线下资源与活动对接」:`/api/ai/gate` 为会员门禁,非资源/活动对接;资源清单 = `/api/admin/butler/list`,活动载体 = `/api/guide/activities/*`。验收语义需产品确认。 #### 4.64.11 契约缺口与语义待确认(不建伪实现任务) | SC | 场景 | 现状 | 处置 | |----|------|------|------| | SC-B-05 | 敏感词门控 | 无独立教练对话敏感词拦截端点;隐私载体=`PiisService` PII 脱敏;`msg_sec_check` 仅文章/媒体链路 | 以 PII 脱敏 + 会员门禁验收,敏感拦截需产品确认 | | SC-B-12 | 主动跟进 | 无规划师建议定时推送端点;`health-coach/send` 为用户发起式 | 验收按用户主动触发口径 | | SC-B-06 | Fallback | `AiGateway` 熔断+超时 → null → 空 Map 降级 / report/analyze 显式错误;**无内容级 mock 兜底** | 按空降级+显式错误验收 | | SC-H-04 | 升级与应急 | unassign/toggle-accepting 为停接/解绑开关,语义间接 | 需产品确认应急处理验收口径 | | SC-H-05 | 资源/活动对接 | 活动载体在 `/api/guide/activities/*`(非本域新增) | 需产品确认验收语义 | *文档更新:2026-11-07(EVD-14 AI成长教练 10 SC + 真人管家 7 SC 契约核对增补「AI成长教练 + 真人管家域」段落 4.64:成长咨询对话 / AI 会员门禁与隐私 / 健康教练跟进 / 报告智能解读 / 营养任务推荐 / 真人管家后勤与家庭自助选择 / 已废弃 410 / 真人管家运营管理 / AI 管家会话 / AI→真人管家协同与资源对接 + 契约缺口。完整核验表见 `docs/superpowers/specs/2026-11-07-ai-butler-contract.md`)* ### 4.65 跨角色域剩余(SC-X-03/08/11/14/15/16/17/18,EVD-15 契约核对增补) > 跨角色域 22 个 SC(SC-X-01~22)中已由既有开工包覆盖 13 个(测评-方案 EVD-8R:X-01/06/09;报告闭环 EVD-7R:X-02/10/13;任务-心愿 EVD-3:X-05;五维能量 EVD-5:X-19/20/21;商城-会员 EVD-4:X-07/12;家庭-成员 EVD-2:X-04;CF 值预估 TR-5:X-22);本批 = 剩余 8 个无键 SC,端点载体逐条实测核验。完整核验表与实现缺口见 `docs/superpowers/specs/2026-11-07-cross-role-contract.md`。 > 约定:所有端点 `POST`;越权语义统一 403(`FamilyAccessInterceptor` enforcement 模式 + `canAccessFamily`)。 > **命名回填**:SC-X-03 候选 `ParentController` 实为心愿单 `/api/parent/wishlist*`(非视角切换,视角切换 = `/api/family/member/switch` + `/api/auth/switch-role`);SC-X-08 候选 `AdminArticleController /api/admin/article/*` 实际为 `/api/admin/articles`(带 s)。 #### 4.65.1 双角色数据隔离越权(SC-X-03) | 路径 | 说明 | |------|------| | `POST /api/family/member/add`、`/list`、`/switch`、`/kick`、`/leave`、`/recycle`、`/update`、`/rename-family`、`/editable`、`/logs` | 成员 CRUD/权限(`FamilyMembersController`,`canAccessFamily` 校验有效家庭集,越权 403;`/switch` 切成员/孩子上下文视角 `SwitchMemberVO`) | | `POST /api/family/teacher-bindings/pending`、`/approve`、`/reject`、`/my-requests`、`/cancel` | 规划师绑定审核(`TeacherFamilyBindingController`) | | `POST /api/auth/switch-role` | 角色切换(`switchRoleForLogin` 重签 token,权限提升须登录,JwtInterceptor 强制登录) | | `POST /api/parent/wishlist`、`/wishlist/list`、`/wishlist/family`、`/wishlist/{id}/approve`、`/wishlist/{id}/exchange` | 家庭主账号心愿单(`ParentController`——**命名回填:非视角切换**) | > 越权语义载体:`FamilyAccessInterceptor`(请求携带 familyId 必须属于调用者有效家庭集,enforcement 模式越权 → 403「无权访问该家庭数据」,注册于 `WebConfig.addInterceptors`)+ `FamilyMembersController.canAccessFamily`(控制器内 403)。 #### 4.65.2 文章发布闭环(SC-X-08) | 路径 | 说明 | |------|------| | `POST /api/article/publish`、`/my-posts`、`/updated-since`、`/detail`、`/list`、`/featured`、`/record-read`、`/related`、`/related-products`、`/audio`、`/report-reading-time`、`/reading-stats`、`/daily-tip` | 文章发布/详情/列表(`ArticleController`,`/api/articles` 与 `/api/article` 双前缀兼容) | | `POST /api/articles/categories` | 文章分类(`ArticleCategoryController`) | | `POST /api/articles/comments/list`、`/create`、`/audit`、`/pending`、`/my`;`/quiz/generate`、`/quiz/submit` | 文章评论 + 答题(`ArticleCommentController`) | | `POST /api/admin/articles/list`、`/create`、`/update`、`/detail`、`/delete`、`/{id}/publish`、`/publish`、`/audit`、`/submit-review`、`/withdraw`、`/re-draft`、`/toggle-featured`、`/move`、`/upload/image`、`/upload/video`、`/comments/list`、`/categories/list`、`/categories/create`、`/categories/update`、`/categories/delete`、`/reading-records` | 文章管理端审核/上架/下架(`AdminArticleController`,**路径带 s:`/api/admin/articles`**) | | `POST /api/admin/review-center/summary` | 审核中心汇总(`ReviewCenterController`) | > 闭环 = 发布→审核→上架→评论,端点齐全 ✅。 #### 4.65.3 消息通知闭环(SC-X-11) | 路径 | 说明 | |------|------| | `POST /api/notification/list`、`/read` | 站内消息查看 + 已读(`UserNotificationController`,已读闭环) | | `POST /api/admin/notification-template/list`、`/save`、`/delete` | 通知模板/通道配置(`AdminNotificationTemplateController`) | | `NotificationDispatchService.sendByTemplate(type,userId,vars,refType,refId,defaultTitle,defaultContent)` | 通知发送统一入口(W3 五通道:in_app/sms/wechat/gzh/phone;in_app + wechat-webhook 投产,sms/gzh/phone/wechat-订阅 预留禁用) | | `InAppNotificationChannel`(isEnabled=true) | 站内通道,写 `user_notifications` 表 | | `WebhookNotificationChannel`(channelType=wechat,isEnabled=true) | 微信待办 webhook 通道,复用 `WechatWaitMsgService.sendWaitMsg`(按用户手机号定向 msgLabel) | > 事件触发 = 10 个 service 调 sendByTemplate(`TaskService`/`PointsService`/`EnergyService`/`CfBalanceServiceImpl`/`CouponGiftService`/`DanReportUploadService`/`ProblemCompletionService`/`ProcurementTaskService`/`ReportTransferService`/`TaskReminderScheduledTask`)。**⚠ 部分存在**:订单/活动/支付事件(`ProductOrderController`/`ActivityOrderController`/`VirtualPayController`)未挂接统一分发;微信订阅消息通道未接入 → 缺口 X-G-1。 #### 4.65.4 解绑/重分配跨角色协同(SC-X-14) | 路径 | 说明 | |------|------| | `POST /api/bind/accept`、`/guides`、`/unbind` | 家庭绑定/解绑(`BindController`) | | `POST /api/family/invite/generate`、`/validate`、`/request-join-by-code`、`/approve-request`、`/reject-request`、`/pending-requests`、`/my-request`、`/cancel-request`、`/bind-inviter`、`/accept`、`/check-family`、`/revoke`、`/transfer-admin` | 邀请重分配/管理员转移(`FamilyInviteController`) | | `POST /api/cf/transfer/send`、`/list` | CF 余额转移(`CfTransferController`) | > 协同 = 规划师/成员解绑(`/unbind`)+ 成员数据重分配(`/transfer-admin`、`/revoke`)+ CF 转移。 #### 4.65.5 注销/数据导出跨角色(SC-X-15) | 路径 | 说明 | |------|------| | `POST /api/user/deactivate` | 账号注销(`AccountCleanupService.deactivateAccount`:匿名化主账号 openid 哈希 + realName/idCard/phone/unionid/nickname/avatar/address/sessionKey 清空 + deleted=1,匿名化关联 `family_member` 记录,处理 PaymentOrder(familyId)/AssessmentOrder(userId)) | | `POST /api/user/data-export` | 个保法可携带权导出(`AccountCleanupService.exportUserData`) | > 跨角色语义 = 家长注销后家庭成员记录/家庭订单处理。 #### 4.65.6 活动名额并发(SC-X-16)⭐ | 路径 | 说明 | |------|------| | `POST /api/activity/register`、`/cancel-registration`、`/my-registrations`、`/registration-roster`、`/checkin`、`/checkin-review` | 活动报名/取消/名单/签到(`ActivityController`) | | `ActivityRegistrationService.occupyQuota` | 原子占用名额:`UPDATE activity SET approved_count=approved_count+1 WHERE id=? AND approved_count0,**多端并发报名不超发**;`releaseQuota` 原子回退) | | `POST /api/activity/order/create`、`/pay`、`/notify`、`/status` | 付费活动订单(`ActivityOrderController`) | > 并发语义 = 同名额多端并发报名不超发,载体 = `occupyQuota` 条件自增(DB 行锁)。 #### 4.65.7 多端登录会话互斥(SC-X-17) | 路径 | 说明 | |------|------| | `POST /api/auth/wechat-login`、`/silent-login`、`/phone-login`、`/switch-role`、`/sso-ticket`、`/sso-login`、`/verify`、`/verifyToken` | 登录族 + token 签发/校验(`AuthController`) | | `POST /api/auth/wechat-web/qr`、`/scan`、`/poll` | 微信 web 登录(`WechatWebAuthController`) | | `JwtInterceptor` | token 签名/过期校验(无效/过期 → 401,公开路径降级匿名放行) | > **⚠ 互斥无载体**:无 token 互斥/单点踢下线(无 tokenVersion/kickout/blacklist/会话注册表;JWT 无状态;SSO 为一次性免登票据非互斥踢出)→ 缺口 X-G-2(同因 EVD-13 SC-P-85 G-5)。 #### 4.65.8 推送跨端送达(SC-X-18) | 路径 | 说明 | |------|------| | `WechatService.sendTemplateMessage(toUserOpenid, templateId, keywordMap)` | 公众号模板消息(`/cgi-bin/message/template/send`,调用方 `WechatAlertTemplateService`/`PromotionTierEvalService`) | | `WechatWaitMsgService.sendWaitMsg(content, label)` | 微信待办 webhook 定向推送(调用方 `WebhookNotificationChannel`) | | `POST /api/internal/virtual-pay/notify`(GET URL 验证 + POST 签名校验) | 微信虚拟支付消息推送**接收**端点(`VirtualPayController`,非主动推送) | > **⚠ 部分存在**:小程序订阅消息(requestSubscribeMessage/subscribeMessage)前后端全仓 0 命中,`WechatNotificationChannel` isEnabled=false 预留禁用;cfc-langgraph 无推送载体 → 缺口 X-G-3。 #### 4.65.9 契约缺口(无完整端点载体,需产品侧确认验收方式) | SC | 场景 | 现状 | 处置 | |----|------|------|------| | SC-X-11 | 消息通知闭环(事件挂接/订阅通道) | 五通道框架完整(in_app + wechat-webhook 投产);订单/活动/支付事件未挂接统一分发;微信订阅消息通道 `WechatNotificationChannel` 预留禁用 | 缺口 X-G-1,需产品侧确认 | | SC-X-17 | 多端登录会话互斥 | 登录族 + JwtInterceptor token 校验存在;无 token 互斥/单点踢出(JWT 无状态) | 缺口 X-G-2,需产品侧确认(同因 EVD-13 SC-P-85 G-5) | | SC-X-18 | 推送跨端送达 | 公众号模板消息 + 微信待办 webhook 已投产;小程序订阅消息(requestSubscribeMessage/subscribeMessage)前后端 0 命中,`WechatNotificationChannel` 预留禁用;cfc-langgraph 无推送 | 缺口 X-G-3,需产品侧确认 | > 本批仅登记缺口不实现,转产品/运维侧确认后由后续批次落地。 *文档更新:2026-11-07(EVD-15 跨角色域剩余 8 SC 契约核对增补「跨角色域剩余」段落 4.65:双角色数据隔离越权 / 文章发布闭环 / 消息通知闭环 / 解绑重分配 / 注销数据导出 / 活动名额并发 / 多端登录互斥 / 推送跨端送达 + 命名回填 2 处 + 契约缺口 3 项。完整核验表见 `docs/superpowers/specs/2026-11-07-cross-role-contract.md`)*