基于
phase1-product-plan.md与1.0产品对齐方案.md,每个用户故事包含:标题、描述、验收标准、优先级
作为 数字能量师/C端用户
我希望 输入姓名和出生年月日,发起一次命盘咨询
以便 获取命盘展示和AI解读服务
验收标准(输入表单):
birthday、name、questions 参数跳转到登录页(/pages/login/index)POST /api/consultation/startbirth_date),但允许修改(能量师可输入客户生日)验收标准(咨询会话管理):
CalculatorService 完成,前端只负责展示(calculator.js 保留为降级兜底,不作为主路径)作为 数字能量师
我希望 看到一个清晰、美观的数字三角形,每个位置都标有数字
以便 直接用于客户讲解
验收标准:
内部三角形布局严格遵循(新字母命名):
O
/ \
M N
/ \ / \
I J K L
底部输入框布局:日(2位)| 月(2位)| 年(4位),从左到右排列(已改为"日月年"顺序)
外部三组以T形线段连接三角内部对应位置:
外部三组使用独立的计算值,非内部数字的直接重复
每个数字使用单独的圆形/方形卡片展示,字体清晰易读
五区使用不同背景色区分(左区/中区/右区/父源/母源/主性格)
数字颜色:1-9 每个数字有独立颜色(参考能量数字配色)
卓越数(11/22/33)用特殊标记突出
底部显示姓名和出生日期信息
作为 开发团队
我希望 有一份完整的位置命名与计算规则对照表作为开发基准
以便 前后端计算逻辑一致,避免歧义
| 字母 | 来源 | 示例 1990-01-15 | 说明 |
|---|---|---|---|
| A | 年份千位 | 1 | 年[0] |
| B | 年份百位 | 9 | 年[1] |
| C | 年份十位 | 9 | 年[2] |
| D | 年份个位 | 0 | 年[3] |
| E | 月份十位 | 0 | 月[0] |
| F | 月份个位 | 1 | 月[1] |
| G | 日期十位 | 1 | 日[0] |
| H | 日期个位 | 5 | 日[1] |
| 字母 | 公式 | 中文名 | 旧名对照 | 视觉层级 |
|---|---|---|---|---|
| I | reduce(E+F) |
月能量 | 旧 F | 底部左1 |
| J | reduce(G+H) |
日能量 | 旧 G | 底部左2 |
| K | reduce(A+B) |
年前半 | 旧 H | 底部右1 |
| L | reduce(C+D) |
年后半 | 旧 I | 底部右2 |
| M | reduce(I+J) |
青年综合数 | 不变 | 中层左 |
| N | reduce(K+L) |
晚年综合数 | 不变 | 中层右 |
| O | reduce(M+N) |
主性格数 | 不变 | 顶层 |
| 字母 | 公式 | 中文名 | 年龄区间 | 所属组 |
|---|---|---|---|---|
| P | reduce(I+M) |
左侧左子(left-L) | 21-40 | 左侧 |
| Q | reduce(J+M) |
左侧右子(left-R) | 21-40 | 左侧 |
| R | reduce(P+Q) |
左侧主数(left) | 21-40 | 左侧 |
| S | reduce(K+N) |
右侧左子(right-L) | 61+ | 右侧 |
| T | reduce(L+N) |
右侧右子(right-R) | 61+ | 右侧 |
| U | reduce(S+T) |
右侧主数(right) | 61+ | 右侧 |
| V | reduce(M+O) |
顶部左子(top-L) | 41-60 | 顶部 |
| W | reduce(N+O) |
顶部右子(top-R) | 41-60 | 顶部 |
| X | reduce(V+W) |
顶部主数(top) | 41-60 | 顶部 |
X
↙ ↘
V W
↙ ↘
M ───────────── N
↙ ↘ ↙ ↘
P Q S T
↙ ↘ ↙ ↘
I ─────────── J K ─────────── L
R (21-40) U (61+)
底部输入: 日 G H | 月 E F | 年 A B C D
| 组 | 位置 | 年龄区间 | 关联内部位 |
|---|---|---|---|
| 左侧组 (R, P, Q) | 三角形左外侧 | 21-40岁 | 基于 I, J, M |
| 顶部组 (X, V, W) | 三角形顶外侧 | 41-60岁 | 基于 M, N, O |
| 右侧组 (U, S, T) | 三角形右外侧 | 61+岁 | 基于 K, L, N |
reduce(N) 定义:各位数字相加归约至个位,但 11/22/33 保留为卓越数+ 操作符均先执行普通加法,再调用 reduce() 归约POST /api/consultation/start 响应示例){
"recordId": 42,
"isNew": false,
"chartData": {
"positions": {
"I": 1, "J": 2, "K": 3, "L": 4,
"M": 5, "N": 6, "O": 7,
"P": 8, "Q": 9, "R": 1,
"S": 2, "T": 3, "U": 4,
"V": 5, "W": 6, "X": 7
},
"mainCharacter": 7,
"isMasterNumber": false
},
"messages": []
}
作为 数字能量师
我希望 点击三角形中的每个数字可以查看该位置的含义和能量解读
以便 快速向客户解释命盘
验收标准(交互):
验收标准(面板内容):
验收标准(交互细节):
作为 数字能量师
我希望 将命盘生成为一张精美的图片,分享到微信或保存到相册
以便 发给客户或在朋友圈展示
验收标准(入口与权限):
验收标准(分享卡片生成):
验收标准(保存与分享):
uni.saveImageToPhotosAlbum,保存成功后 toast 提示"已保存到相册"uni.share(或小程序原生转发),携带卡片图片和默认文案"看看你的数字能量命盘"验收标准(限制与风控):
POST /api/user/share-quota 返回当日剩余次数作为 数字能量师
我希望 将命盘导出为 PDF 文件,可以直接打印或微信发送
以便 客户获得正式的纸质/电子版报告
验收标准(权限与入口):
验收标准(PDF 内容与排版):
验收标准(导出流程):
POST /api/export/pdf 传入 chartId,后端返回 PDF 文件流uni.openDocument 打开微信文件预览export_logs 表,便于统计验收标准(限制):
作为 数字能量师
我希望 在命盘生成后,看到由AI自动生成的完整文字解读
以便 直接发给客户或稍作润色后使用,节省自己查资料写解读的时间
验收标准:
POST /api/chart/interpret,后端转发至 Dify Workflow API(POST /v1/workflows/run)data.outputs JSON 后,原样或稍作格式化后返回前端作为 平台运营者
我希望 控制AI解读功能的免费与付费边界
以便 激励用户订阅C端年费或能量师年费
验收标准:
作为 平台运营者
我希望 控制AI问答互动功能的免费次数,且限定在同一个命盘上
以便 防止用户通过切换生日绕过每日限制,同时保证体验清晰可预期
验收标准(配额控制):
lastQuotaDate 跨日时自动归零验收标准(Dify Chatflow 集成):
POST /api/chat/send 发送用户消息,传入 { chartId, message }ChatService 将消息转发至 Dify Chatflow API(POST /v1/chat-messages)conversation_id),无需后端自行维护会话历史inputs 传入,后续轮次无需重复传入作为 系统
我希望 同一命盘的重复解读请求不重复调用LLM API
以便 控制成本,避免同一命盘每次查看都消耗API费用
验收标准:
作为 数字能量师
我希望 看到清晰的定价方案并进行年费支付
以便 获得AI完整解读、分销推广等全部功能
验收标准:
POST /api/pricing/current 获取)seedReason 展示不同文案
eligible:"仅剩 XX 个种子名额" + "有效期至 YYYY-MM-DD"not_founder_code / no_referrer:"种子价仅限创始人邀请用户"expired:"种子价活动已结束"quota_full:"种子名额已满"vipEndTime += 365天)作为 平台 我希望 系统自动判断用户是否享受种子价 以便 运营策略自动化,无需人工干预
种子会员定义:
种子会员 = 通过扫描创始人码注册并付费成为能量师的用户。创始人码 = 没有推荐人的能量师(invitedBy IS NULL 且 vipType='practitioner')的推广码。
即:用户 U 的直接推荐人 A 满足
A.invitedBy IS NULL AND A.vipType='practitioner'时,U 扫的是创始人码。
验收标准:
POST /api/pricing/current 返回,前端不做判断isSeedPrice = true 需同时满足三重条件:
invitedBy)是创始人(invitedBy IS NULL AND vipType='practitioner')的自然注册用户(无推荐人,invitedBy IS NULL)不享受种子价sys_config.pricing.practitioner.seed_period_end(种子价有效期截止时间)sys_config.pricing.practitioner.seed_limit(默认 300)isSeedPrice = false,返回标准价orders 表中 product_type='practitioner' AND status='paid' AND is_seed_price=true 的记录数is_seed_price 写入订单,不因后续条件变化而改变)pricing.practitioner.seed_limit、pricing.practitioner.seed_period_end)作为 付费能量师
我希望 在个人中心看到我的订阅状态、到期日,并能续费
以便 管理我的会员身份
验收标准:
vipType=NULL):品牌色(墨蓝 #1E3A5F)渐变卡片 + 权益摘要(3-4项)+ "立即开通 ¥131/年"按钮vipType='annual',有效期内):橙色渐变卡片 + "已开通C端会员" + 有效期 + "升级能量师"按钮vipType='practitioner',有效期内):紫色渐变卡片 + "能量师会员 🌟" + 有效期 + "续费"按钮vipEndTime < now):灰色卡片 + "已过期"标记 + "重新开通"按钮profile_incomplete = true)在状态卡片上方显示引导 banner:"📝 请完善个人资料,开启能量匹配"作为 C端年费用户
我希望 从年费升级为能量师时,按已付年费的剩余价值抵扣差价
以便 不需要重复支付已经买过的部分
验收标准(升级定价):
vipType='annual' 且 vipEndTime > now,可在"我的"页面 → 会员状态卡片(C端年费)点击"升级能量师"按钮升级价格由后端计算,公式:
已付年费金额 = 该用户最近一笔 annual 订单的 amount(默认 ¥131)
已用天数 = 从 annual 支付成功日到当前日的天数
剩余价值 = 已付年费金额 × (365 - 已用天数) / 365
升级价格 = 当前能量师定价(种子/标准)− 剩余价值
计算示例:用户 B 在 1月1日付 ¥131,第100天升级(种子价 ¥1,314):
剩余价值 = ¥131 × (365-100)/365 = ¥95.11
升级价格 = ¥1,314 − ¥95.11 = ¥1,218.89
升级价格 < 0(理论极限)→ 按 ¥0.01 收取
升级后 vipType 从 'annual' 变更为 'practitioner'
升级后 vipEndTime 按能量师续费规则处理(在原能量师到期日 +365天,不叠加年费剩余天数)
升级不享受种子价(种子价仅限通过创始人码首次购买 practitioner,见 US-4.2)
升级后推广码不变(如之前已有推广码)
验收标准(前端流程):
POST /api/pay/create 传 { productType: 'practitioner', isUpgrade: true, previousOrderId: xxx }paySuccess() → vipType 更新 + 佣金结算(见 US-6.3 升级场景)验收标准(接口):
POST /api/pricing/upgrade 新增接口:传入 userId,返回升级价格详情POST /api/pay/create 新增字段:
isUpgrade: booleanpreviousOrderId: Long(原年费订单ID,用于佣金补差)作为 用户
我希望 通过微信授权一键登录,随后补充生日和性别完成注册
以便 使用命盘分析和未来的能量匹配社交功能
验收标准(微信授权登录):
uni.login 获取 code)uni.getUserProfile),用户可修改{ token, isNewUser: true, profileIncomplete: true }{ token, isNewUser: false, profileIncomplete: false }{ token, profileIncomplete: true },引导补全资料验收标准(注册信息完善页):
| 字段 | 必填 | 预填 | 说明 |
|---|---|---|---|
| 头像 | 是 | 微信头像 | 可点击更换(从相册选择) |
| 昵称 | 是 | 微信昵称 | 1-20 字 |
| 性别 | 是 | 空 | 男 / 女,radio 选择 |
| 出生日期 | 是 | 空 | 年月日选择器,同命盘生日 |
| 个人简介 | 否 | 空 | 限 100 字,用于社交展示 |
| 所在城市 | 否 | 空 | 微信定位或手动选择 |
| 兴趣标签 | 否 | 空 | 多选:读书/运动/音乐/旅行/禅修/创业/心理学/玄学 |
| 想认识 | 否 | 空 | 单选:不限 / 朋友 / 导师 / 同修 |
POST /api/profile/complete 保存所有资料profile_complete = true验收标准(后端与数据库变更):
users 表新增字段:| 字段 | 类型 | 说明 |
|---|---|---|
gender |
TINYINT |
0=未知, 1=男, 2=女 |
birth_date |
DATE |
出生日期(用于命盘+社交) |
bio |
VARCHAR(200) |
个人简介 |
city |
VARCHAR(50) |
所在城市 |
tags |
VARCHAR(200) |
兴趣标签,逗号分隔 |
looking_for |
TINYINT |
0=不限, 1=朋友, 2=导师, 3=同修 |
profile_complete |
TINYINT(1) |
0=资料未完善, 1=资料已完善 |
birth_year |
INT |
出生年份(冗余,从 birth_date 提取) |
birth_month |
INT |
出生月份(冗余) |
birth_day |
INT |
出生日期(冗余) |
POST /api/auth/login 响应增加 profileIncomplete 字段POST /api/profile/complete 接口,接收所有注册字段POST /api/profile/update 接口,允许修改任意字段POST /api/profile/info 响应增加全部新字段,额外新增 isSeedPriceUser(Boolean — 当前用户是否以种子价购买的能量师)验收标准(老用户兼容):
profile_complete = false,登录后显示完善引导作为 能量师
我希望 查看我过去的所有咨询记录
以便 回顾和继续之前的咨询
验收标准:
(userId, birthday) 联合唯一)作为 用户
我希望 在个人中心编辑我的昵称、头像、简介、标签、城市等资料
以便 未来通过能量匹配结识志同道合的朋友
验收标准:
POST /api/profile/update注:能量匹配社交将根据用户的命盘主性格数(O)、外部三组数(R/U/X)等计算能量兼容度,推荐匹配用户。此功能在 Phase 2 规划。
作为 付费用户(C端 / 能量师)
我希望 在首次付费后自动获得专属推广码
以便 分享给微信好友来发展下级并赚取佣金
验收标准:
O/0/I/1(即 ABCDEFGHJKLMNPQRSTUVWXYZ23456789)作为 平台
我希望 当用户通过推广链接/扫码打开小程序时,自动记录上下级关系
以便 为佣金分成打好基础
验收标准:
验收标准(分享链路与前端缓存):
/pages/index/index?ref=ABC123(6位推广码)ref 参数onLoad(options) 读取 options.query.ref,转为大写后写入缓存 pending_referrerpending_referrer 仅在用户完成微信登录后才提交到后端建立关系,不登录不建立关系pending_referrer(无论绑定成功与否)pending_referrer,下次触发登录仍携带前端流程(咨询→登录→关系绑定):
index/index.vue)→ 填写姓名、生日、问题 → 无需登录birthday, name, questions 跳转到登录页 login/index.vuePOST /api/consultation/startpending_referrer 读取推广码提交后端 → 清除缓存profileIncomplete=true)→ 弹出资料完善浮层,预填首页传入的 birthday 和 namepending_referrer 保留但永不使用,无关系绑定后端注册逻辑(UserService.loginOrRegister()):
referrerCode 有效 → invitedBy = 上级IDreferrerCode 无效 → invitedBy = null(静默降级,不报错)referrerCode 为空 → invitedBy = null(正常注册)referrerCode 为自己的新openid → invitedBy = null(防止自邀请)referrerCode,不覆盖已有 invitedBy(关系一次性锁定)referrerCode 查询不到对应上级 → 静默跳过,不抛异常数据库更新:
inviter.directCount += 1(实时更新统计字段)边界与异常:
pending_referrer,重试时继续携带作为 平台
我希望 当能量师A的下级B升级为能量师时,自动结算固定金额佣金
以便 能量师获得推广收益
验收标准:
触发条件:
productType = "practitioner" 且支付成功 → 进入 B端佣金结算流程productType = "annual" → 走 US-6.4 C端佣金(互斥分支)佣金计算——按推荐人身份分两种情况:
vipType='practitioner') → 按标准固定金额:| 级别 | 默认值 | 配置键 |
|---|---|---|
| L1(直接上级) | ¥500 | commission.practitioner.l1 |
| L2(上上级) | ¥100 | commission.practitioner.l2 |
vipType='annual') → L1 拿半额:| 级别 | 默认值 | 配置键 |
|---|---|---|
| L1(直接上级) | ¥200 | commission.practitioner.l1_cend |
| L2(上上级) | ¥100(不变) | commission.practitioner.l2 |
vipType=null 等异常情况)→ L1/L2 不创建佣金升级场景佣金补差(isUpgrade=true):
当订单标记 isUpgrade=true(从年费升级到能量师),L1/L2 佣金需扣除已支付过的年费佣金:
应发佣金 = 本次应发金额 − 该买家此前 annual 订单已支付给同一收款人的佣金总额
计算逻辑:
commissions 表中,同一 buyer_id + 同一 收款人 且 product_type='annual' 的所有佣金之和示例——首次直接购买能量师(非升级,对比参考):
用户C为新用户(无年费记录),通过上级A(能量师)链接直接购买能量师 ¥1,314
isUpgrade = false → 全额发放:L1 = ¥500,L2 = ¥100
无年费佣金可扣除
示例——年费升级补差:
用户B第1天付¥131(annual),上级A获¥52.40(40%)
用户B第100天升级能量师(种子价¥1,314),上级A是能量师→应发¥500
实际发放:¥500 − ¥52.40 = ¥447.60
示例——C端推荐人升级补差:
用户B第1天付¥131(annual),上级A(C端)获¥52.40(40%)
用户B第100天升级能量师,上级A是C端→应发半额¥200
实际发放:¥200 − ¥52.40 = ¥147.60
收款人资格:
buyer.invitedBy 对应的上级存在 → 按上述规则计算invitedBy 对应的上上级存在 → 按上述规则计算(L2 不因身份打折,仅 L1 打折)状态与幂等:
status 直接写入 "settled"(即时到账,无 pending 冷静期)outTradeNo 重复回调 → 幂等处理,不创建重复佣金统计更新:
inviter.directCount += 1,inviter.convertedCount += 1inviter2.indirectCount += 1配置项(后台可配):
| 配置键 | 默认值 | 说明 |
|---|---|---|
commission.practitioner.l1 |
50000 |
B端一级佣金—能量师推荐(分) |
commission.practitioner.l1_cend |
20000 |
B端一级佣金—C端推荐(分) |
commission.practitioner.l2 |
10000 |
B端二级佣金(分) |
作为 平台
我希望 当C端用户B通过上级A的链接注册并付费 ¥131 时,自动按比例分成
以便 激励所有付费用户推广
验收标准:
触发条件:
productType = "annual" 且支付成功 → 进入 C端佣金结算流程佣金计算:
totalFee × directRate / 10000,从 sys_config 读取 commission.annual.direct_rate(默认 4000 = 40%)totalFee × upstreamRate / 10000,从 sys_config 读取 commission.annual.upstream_rate(默认 500 = 5%)注意:年费佣金在后续用户升级能量师时可能被部分抵扣(见 US-6.3 升级补差逻辑)。
paySuccess()记录原始佣金(用于后续补差计算),补差逻辑在升级时执行。
因此 C端佣金的status仍直接写入"settled",不需要等待升级再结算。若后续升级,再由 US-6.3 扣除已付金额。
收款人资格(与 B端不同):
buyer.invitedBy 对应的上级必须已付费(referralCode != null),才创建佣金invitedBy 对应的上上级必须已付费(referralCode != null),才创建佣金状态与幂等:
status 直接写入 "settled"与 B端的差异:
directCount/convertedCount/indirectCount(这些统计仅用于B端"升级能量师")每笔 ¥131 分配示例: | 分配对象 | 比例 | 金额 | |---------|------|------| | 直接上级 | 40% | ¥52.40 | | 上上级 | 5% | ¥6.55 | | 平台 | 55% | ¥72.05 |
配置项(后台可配):
| 配置键 | 默认值 | 说明 |
|--------|--------|------|
| commission.annual.direct_rate | 4000 | C端直接佣金比例(万分比,4000=40%) |
| commission.annual.upstream_rate | 500 | C端上级佣金比例(万分比,500=5%) |
作为 能量师
我希望 在分销面板中查看我的推广收益和团队数据
以便 追踪推广效果,激励持续推广
验收标准:
入口权限:
vipEndTime > now),普通用户看不到入口页面结构(自上而下):
① 推广码卡片:
我的推广码: ABC123 + 复制按钮② 收益统计卡片(三列等宽):
status = settled)/100)③ 团队统计(三列):
directCountindirectCountconvertedCount④ 佣金明细列表(最近50条):
⑤ 推广工具区:
页面状态:
后端 API 需求:
| 接口 | 说明 |
|------|------|
| POST /api/profile/info | 含 referralCode(已有) |
| POST /api/commission/list | 佣金明细列表(已有) |
| POST /api/commission/stats | 新增:总收益+可提现+今日新增+团队统计 |
作为 免费用户(C端)
我希望 在AI解读页底部看到 ¥131 开通完整解读的引导
以便 一键订阅获取完整服务
验收标准:
入口位置(用户已确认选项1——命盘解读页底部):
chart/index.vue 底部(聊天区下方)固定显示订阅卡片(免费用户)交互流程(未登录):
交互流程(已登录未付费):
product=annual,金额 ¥131交互流程(已付费):
支付页适配:
payment/index.vue 支持 URL 参数 product:
product=annual → 显示 C端年费 ¥131 和对应权益列表product=practitioner → 显示能量师价格(通过 API 获取种子/标准价)createOrder 接口接收 productType 参数后端适应:
productType 字段新增枚举值:"annual" | "practitioner" | "practitioner_plan"(人工方案)vipType 字段("annual" | "practitioner" | null)paySuccess() 佣金结算按 productType 分支:
annual → US-6.4 C端年费佣金practitioner → US-6.3 B端佣金(含推荐人身份判断 + isUpgrade 补差)practitioner_plan → US-9.5/9.6 人工方案佣金(通过 CommerceService 结算,平台留存模型)场景:家长为孩子选择学业方向,通过AI解读初步了解孩子的天赋倾向,如需深度方案可申请能量师出方案。 佣金模型:人工方案采用平台佣金留存模型(区别于年费的固定金额/比例模型),所有分销佣金从平台留存部分支出。 商城底座:引入 lilishop(
iwt/lilishop)作为商城引擎,本期通过CommerceService接口层预留对接,暂不实现实际商城付费。
作为 家长
我希望 输入孩子的生日后,看到针对学业方向的AI深度解读
以便 了解孩子的天赋倾向,为学业规划提供参考
验收标准:
入口:
chart/index.vue)的 AI 解读内容区域,学业方向分析作为解读内容的组成部分嵌入展示,不设独立页面入口和菜单项POST /api/chart/academic-orientationAI 解读内容:
inputs付费控制:
技术架构:
DifyService 新增方法 interpretAcademicOrientation(AcademicRequest request)作为 家长
我希望 在AI学业解读后,申请能量师为孩子出具深度人工方案
以便 获得比AI更个性化的专业指导
验收标准:
入口与表单:
需求分配:
invitedBy 且上级是能量师(vipType='practitioner')→ 自动把需求单分配给该能量师数据库新增:
plan_requests 表:id, userId, chartId, requestType, description, budgetRange, assignedPractitionerId, status(pending/accepted/negotiating/paid/completed/cancelled), price, createdAt, updatedAt作为 能量师
我希望 看到向我咨询用户的AI会话,并可以发起介入
以便 在用户需要时主动提供专业建议,促成人工方案
验收标准:
触发条件:
invitedBy 关系链中的能量师(B推荐A,A是B的上级)才能介入B的AI会话invitedBy 关系链,仅显示有实际咨询的用户)介入流程:
权限边界:
chat_interventions 表记录数据库新增:
chat_interventions 表:id, sessionId, practitionerId, startTime, endTime, endedBy(user/practitioner)chat_messages 表新增 senderType 枚举:ai / user / practitioner / system / proposal作为 能量师
我希望 在聊天中向用户发送方案提议,并可与用户协商价格
以便 双方达成一致后完成付费
验收标准:
出方案提议:
方案卡片交互:
状态管理:
plan_requests 记录对应多轮协商历史plan_request_logs 表记录数据库新增:
plan_request_logs 表:id, planRequestId, action(propose/counter/accept/reject), oldPrice, newPrice, message, operatorId, createdAt作为 家长
我希望 接受能量师方案报价后在线支付,并收到完整的方案报告
以便 获得专业的学业指导
验收标准:
支付:
createOrder(productType="practitioner_plan", planRequestId=xxx)productType = "practitioner_plan"(新增类型)CommerceService.onPaymentSuccess() 处理平台佣金计算平台佣金计算(StubCommerceService):
commerce.category.practitioner_plan.commission_rate(默认 3000 = 30%)commission.practitioner_plan.referral_rate / 10000(默认 2000 = 20%)commission.practitioner_plan.upstream_rate / 10000(默认 500 = 5%)示例计算:
方案价 ¥299,平台佣金率 30%
平台佣金 = ¥299 × 30% = ¥89.70
能量师结算 = ¥299 - ¥89.70 = ¥209.30
有直接上级:分销佣金 = ¥89.70 × 20% = ¥17.94
平台净留 = ¥89.70 - ¥17.94 = ¥71.76
交付:
plan_deliveries.text_content评价与完成:
completedpractitioner_ratings 表数据库新增:
plan_deliveries 表:id, planRequestId, deliveryType(text/pdf/mixed), textContent, fileUrl, createdAtpractitioner_ratings 表:id, planRequestId, userId, practitionerId, score(1-5), comment, createdAt作为 平台
我希望 当用户购买人工方案时,从平台佣金中自动结算分销佣金
以便 激励推广者推荐用户给能量师
验收标准:
触发条件:
productType = "practitioner_plan" 且支付成功 → 进入分佣流程佣金参数:
| 参数 | 默认值 | 配置键 |
|------|--------|--------|
| 平台佣金率 | 30% | commerce.category.practitioner_plan.commission_rate |
| 直接上级分销比例 | 20%(占平台佣金) | commission.practitioner_plan.referral_rate |
| 上上级分销比例 | 5%(占平台佣金) | commission.practitioner_plan.upstream_rate |
计算逻辑:
platformCommission = totalFee × commission_rate / 10000referralCommission = platformCommission × referral_rate / 10000upstreamCommission = platformCommission × upstream_rate / 10000状态与幂等:
status 写入 "settled"(即时到账)outTradeNo 重复回调 → 幂等处理示例:
方案价 ¥299(29,900分)
平台佣金率 30%
平台佣金 = 29,900 × 30% = 8,970分 = ¥89.70
直接上级佣金 = 8,970 × 20% = 1,794分 = ¥17.94
上上级佣金 = 8,970 × 5% = 448分 = ¥4.48
能量师结算 = 29,900 - 8,970 = 20,930分 = ¥209.30
平台净留 = 8,970 - 1,794 - 448 = 6,728分 = ¥67.28
本期不实现 lilishop 对接,先定义接口 + 桩实现。
接口:
public interface CommerceService {
/** 创建商品(能量师上架服务) */
String createProduct(CommerceProductDTO product);
/** 创建订单 */
String createOrder(CommerceOrderDTO order);
/** 订单支付回调处理 */
void onPaymentSuccess(String orderSn, String payOrderNo);
/** 查询订单 */
CommerceOrderDTO getOrder(String orderSn);
/** 获取店铺结算信息 */
CommerceSettlementDTO getSettlement(String storeId);
/** 记录分销订单 */
void recordDistribution(String orderSn);
}
Phase 1 桩实现(StubCommerceService):
| 方法 | 实现策略 |
|------|---------|
| createProduct | 写入本地 commerce_goods 映射表 |
| createOrder | 走现有本地 orders 表 + 标记 commerceReady=false |
| onPaymentSuccess | 执行本地佣金计算逻辑(US-9.5 验收标准6-9) |
| getSettlement | 从本地佣金表聚合统计 |
| recordDistribution | 走现有 commissions 表逻辑 |
Phase 2+ 对接 lilishop:
createProduct → lilishop Goods APIcreateOrder → lilishop Order APIonPaymentSuccess → 创建 StoreFlow + DistributionOrdergetSettlement → lilishop Bill APIrecordDistribution → lilishop Distribution API数据库新增:
-- lilishop 商品映射表(预留)
CREATE TABLE `commerce_goods` (
`id` bigint PRIMARY KEY AUTO_INCREMENT,
`store_id` varchar(32) NOT NULL COMMENT '能量师storeId(= userId)',
`product_type` varchar(32) NOT NULL COMMENT '商品类型:practitioner_plan',
`lilishop_goods_id` varchar(32) DEFAULT NULL COMMENT 'lilishop商品ID(Phase 2 填充)',
`category_path` varchar(255) DEFAULT NULL COMMENT 'lilishop分类路径',
`price` bigint NOT NULL COMMENT '价格(分)',
`status` varchar(16) DEFAULT 'active' COMMENT '状态',
`created_at` datetime NOT NULL,
`updated_at` datetime DEFAULT NULL
);
作为 能量师
我希望 在命盘图上添加文字批注或标记
以便 为每个客户记录个性化的解读要点
验收标准(入口与权限):
【位置X】 标签到批注文本chartId 绑定,不同命盘各自独立【主性格O】天生领导者,数字1能量突出POST /api/chart/annotation/save,传入 chartId + content验收标准(批注展示):
验收标准(后端与存储):
chart_annotations 表:| 字段 | 类型 | 说明 |
|---|---|---|
id |
BIGINT PK |
主键 |
chart_id |
BIGINT |
关联命盘记录 |
user_id |
BIGINT |
批注人(能量师) |
position |
VARCHAR(2) |
关联位置字母(A-X),可为 null |
content |
TEXT |
批注内容(富文本 HTML) |
created_at |
DATETIME |
创建时间 |
updated_at |
DATETIME |
最后修改时间 |
POST /api/annotation/save — 保存/更新批注POST /api/annotation/list — 获取命盘批注列表(按 chartId)POST /api/annotation/delete — 删除单条批注作为 能量师
我希望 为命盘记录添加简单的标签或分组
以便 对客户进行分类管理
验收标准(标签创建与选择):
[🟢 老客户] [🟠 朋友推荐] [🔵 线上引流]验收标准(标签展示与筛选):
验收标准(标签管理):
验收标准(后端与存储):
user_labels 表:| 字段 | 类型 | 说明 |
|---|---|---|
id |
BIGINT PK |
主键 |
user_id |
BIGINT |
能量师 ID |
name |
VARCHAR(20) |
标签名称 |
color |
VARCHAR(7) |
颜色值(如 #4CAF50) |
created_at |
DATETIME |
创建时间 |
chart_labels(命盘-标签多对多):| 字段 | 类型 | 说明 |
|---|---|---|
id |
BIGINT PK |
主键 |
chart_id |
BIGINT |
命盘记录 ID |
label_id |
BIGINT |
标签 ID |
created_at |
DATETIME |
关联时间 |
POST /api/label/create — 新建标签POST /api/label/list — 获取标签列表POST /api/label/update — 编辑标签名称/颜色POST /api/label/delete — 删除标签POST /api/chart/label/set — 为命盘设置标签POST /api/chart/label/list — 获取命盘标签列表(按 chartId)作为 运营管理员
我希望 在管理后台可视化编辑定价和佣金参数
以便 灵活调整运营策略,无需开发介入
DDL & Entity:
新建 sys_config 表,结构如下:
CREATE TABLE `sys_config` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`config_key` VARCHAR(64) NOT NULL COMMENT '配置键(点分命名法)',
`config_value` VARCHAR(255) DEFAULT NULL COMMENT '配置值(始终使用字符串存储)',
`description` VARCHAR(255) DEFAULT NULL COMMENT '中文说明',
`value_type` VARCHAR(20) NOT NULL DEFAULT 'string' COMMENT 'int | price | percent | string',
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_config_key` (`config_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
预置 9 条种子数据(见下,含新增的 seed_period_end)。
后端:SysConfigService + 内存缓存:
@PostConstruct loadAllToCache():启动时将全量配置读入 ConcurrentHashMap<String, String>getString(key, default)、getInt(key, default) 两个读方法,O(1) 取值key 不存在时 → 返回代码中传入的 defaultValue,永不抛异常updateConfig(key, value):更新 DB + 同步写入缓存,无需重启batchUpdate(Map<String, String>):循环调用 updateConfig,整个操作在 @Transactional 中管理后台 API:
POST /api/admin/config/list → 返回 List<SysConfig>(含全部字段)POST /api/admin/config/update → 接收 { "configKey": "value", ... } → 批量更新小程序端 API:POST /api/pricing/current:
// Request: 无参数
// Response:
{
"code": 0,
"data": {
"seedPrice": 131400, // pricing.practitioner.seed(分)
"standardPrice": 198600, // pricing.practitioner.standard(分)
"annualFee": 13100, // pricing.annual(分)
"isSeedPrice": true, // 当前用户是否能享受种子价(三重条件判断)
"seedReason": "eligible", // "eligible"=三条件均满足 | "not_founder_code"=非创始人码 | "expired"=有效期已过 | "quota_full"=名额已满 | "no_referrer"=无推荐人(自然注册)
"remainingSeats": 298, // 种子名额余量
"seedLimit": 300, // 名额上限
"seedPeriodEnd": "2027-05-31T23:59:59" // 种子价有效期截止时间
}
}
isSeedPrice 的计算逻辑(三重条件,全部满足才为 true):
invitedBy)存在,且该推荐人 invitedBy IS NULL AND vipType='practitioner'(即推荐人是创始人)pricing.practitioner.seed_period_endseedLimit(统计 orders 中 product_type='practitioner' AND status='paid' AND is_seed_price=true 的记录数)invitedBy IS NULL)→ 条件①不满足 → isSeedPrice=falseseedReason 字段用于前端展示不同提示文案(如"种子价已过期"、"种子名额已满"、"需通过创始人邀请注册"等)管理后台页面(src/views/settings/index.vue):
/settings,图标 ⚙️定价配置卡片:
countByProductTypeAndStatus + isSeedPrice=true)el-date-picker(datetime 类型),显示格式 YYYY-MM-DD HH:mm:ss,存储格式为 ISO 8601 字符串seed_period_end 比较)B端佣金配置卡片:
C端佣金配置卡片:
保存逻辑:
POST /api/admin/config/updateel-form 的 reset 行为 —— 用户手动刷新页面可恢复到上次保存的值错误与边界:
el-input-number 的 min 属性直接阻止输入POST /api/admin/config/list
// Response:
{
"code": 0,
"data": [
{
"id": 1,
"configKey": "pricing.practitioner.seed",
"configValue": "131400",
"description": "能量师种子价(分)",
"valueType": "price",
"updatedAt": "2026-05-28T10:00:00"
}
// ... 共 9 条(基础定价4+有效期1+佣金3+佣金1,详见种子数据SQL)
]
}
POST /api/admin/config/update
// Request:
{
"pricing.practitioner.seed": "131400",
"commission.practitioner.l1": "60000"
}
// Response: { "code": 0 }
POST /api/admin/config/reset(可选,单条重置)
// Request: { "configKey": "commission.practitioner.l1" }
// Response: { "code": 0, "data": { "configKey": "commission.practitioner.l1", "configValue": "50000" } }
| 类名 | 位置 | 说明 |
|---|---|---|
SysConfig |
entity/ |
JPA 实体 |
SysConfigRepository |
repository/ |
JPA 接口 |
SysConfigService |
service/ |
配置 CRUD + 内存缓存 |
AdminConfigController |
controller/ |
/api/admin/config/* 端点 |
PricingController |
controller/ |
/api/pricing/current 小程序端端点 |
OrderRepository |
repository/ |
新增 countByProductTypeAndStatus() |
SysConfigService 核心代码:
@Service
public class SysConfigService {
private final ConcurrentHashMap<String, String> cache = new ConcurrentHashMap<>();
private final SysConfigRepository repository;
@PostConstruct
public void loadAllToCache() {
cache.clear();
repository.findAllByOrderByConfigKeyAsc()
.forEach(cfg -> cache.put(cfg.getConfigKey(), cfg.getConfigValue()));
}
public String getString(String key, String defaultValue) {
return cache.getOrDefault(key, defaultValue);
}
public int getInt(String key, int defaultValue) {
String val = cache.get(key);
if (val == null) return defaultValue;
try { return Integer.parseInt(val); }
catch (NumberFormatException e) { return defaultValue; }
}
@Transactional
public void updateConfig(String key, String value) {
SysConfig cfg = repository.findByConfigKey(key)
.orElseGet(() -> new SysConfig(key, value, "auto", "string"));
cfg.setConfigValue(value);
cfg.setUpdatedAt(LocalDateTime.now());
repository.save(cfg);
cache.put(key, value);
}
public void batchUpdate(Map<String, String> configs) {
configs.forEach(this::updateConfig);
}
}
| 文件 | 操作 | 说明 |
|---|---|---|
src/views/settings/index.vue |
新增 | 系统配置页面(~200行) |
src/router/index.ts |
修改 | 新增 /settings 路由 |
src/layout/index.vue |
修改 | 新增菜单项 |
侧边栏菜单新增:
<el-menu-item index="/settings">
<el-icon><Setting /></el-icon>
<span>系统配置</span>
</el-menu-item>
页面组件结构:
settings/index.vue
├── el-card (header-toolbar: "系统配置" + [保存全部配置])
├── el-card (定价配置)
│ ├── el-form-item: 能量师种子价 → el-input-number(min=0, max=999999, step=100)
│ ├── el-form-item: 能量师标准价 → el-input-number(...)
│ ├── el-form-item: 种子价名额上限 → el-input-number(min=1, max=99999, step=50)
│ ├── el-form-item: 种子价有效期 → el-date-picker(type="datetime", format="YYYY-MM-DD HH:mm:ss")
│ ├── 注记:种子价三重条件(创始人码+有效期+名额)
│ └── el-form-item: C端年费 → el-input-number(...)
├── el-card (B端佣金配置)
│ ├── el-form-item: L1 佣金(能量师推荐)→ el-input-number
│ ├── el-form-item: L1 佣金(C端推荐)→ el-input-number
│ ├── el-form-item: L2 佣金 → el-input-number
│ └── 实时比例显示
└── el-card (C端佣金配置)
├── el-form-item: 直接佣金比例 → el-input-number(min=0, max=10000, step=500)
├── el-form-item: 上级佣金比例 → el-input-number(min=0, max=5000, step=100)
└── 实时分配预览
├── el-card (人工方案配置 — EPIC 9)
│ ├── el-form-item: 平台佣金率 → el-input-number(min=0, max=10000, step=500)
│ │ └── 注记:方案价 × 佣金率 = 平台收入,剩余结算给能量师
│ ├── el-form-item: 分销佣金占比(直接) → el-input-number(min=0, max=10000, step=500)
│ │ └── 注记:从平台佣金中提取 × 此比例 = 直接上级佣金
│ ├── el-form-item: 分销佣金占比(上级) → el-input-number(min=0, max=5000, step=100)
│ │ └── 注记:从平台佣金中提取 × 此比例 = 上上级佣金
│ ├── el-form-item: 方案最低价 → el-input-number(min=0, max=999999, step=100)
│ ├── el-form-item: 方案最高价 → el-input-number(min=0, max=999999, step=100)
│ │ └── 实时预览示例:方案价¥299→佣金¥89.70→能量师¥209.30→分销¥17.94
│ └── el-form-item: 最大协商轮次 → el-input-number(min=1, max=20, step=1)
表单校验规则:
| 字段 | 校验规则 |
|---|---|
| 所有金额(元) | > 0,整数,≤ 999999 |
| 比例(%) | 0-100,整数 |
| 名额上限 | ≥ 1,≤ 99999 |
INSERT INTO `sys_config` (`config_key`, `config_value`, `description`, `value_type`) VALUES
('pricing.practitioner.seed', '131400', '能量师种子价(分)', 'price'),
('pricing.practitioner.standard', '198600', '能量师标准价(分)', 'price'),
('pricing.practitioner.seed_limit', '300', '种子价名额上限', 'int'),
('pricing.practitioner.seed_period_end', '2027-05-31T23:59:59', '种子价有效期截止时间(ISO 8601)', 'datetime'),
('pricing.annual', '13100', 'C端年费(分)', 'price'),
('commission.practitioner.l1', '50000', 'B端一级佣金-能量师推荐(分)', 'price'),
('commission.practitioner.l1_cend', '20000', 'B端一级佣金-C端推荐(分)', 'price'),
('commission.practitioner.l2', '10000', 'B端二级佣金(分)', 'price'),
('commission.annual.direct_rate', '4000', 'C端直接佣金比例(万分比)', 'percent'),
('commission.annual.upstream_rate', '500', 'C端上级佣金比例(万分比)', 'percent'),
('commerce.category.practitioner_plan.commission_rate', '3000', '人工方案平台佣金率(万分比)', 'percent'),
('commission.practitioner_plan.referral_rate', '2000', '人工方案分销佣金占比(万分比)', 'percent'),
('commission.practitioner_plan.upstream_rate', '500', '人工方案上级佣金占比(万分比)', 'percent'),
('plan_request.enabled', 'true', '人工方案功能开关', 'bool'),
('plan_request.max_negotiation_rounds', '5', '最大协商轮次', 'int'),
('plan_request.auto_cancel_hours', '72', '协商超时自动取消(小时)', 'int'),
('plan_request.min_price', '5000', '方案最低价(分)', 'price'),
('plan_request.max_price', '999900', '方案最高价(分)', 'price');
| # | 场景 | 步骤 | 预期 |
|---|---|---|---|
| 1 | 初始加载 | 打开系统配置页 | 17个字段显示正确的默认值 |
| 2 | 修改定价 | 种子价改为 ¥2,000 → 保存 | 下次 POST /api/pricing/current 返回 seedPrice=200000 |
| 3 | 修改佣金 | L1 改为 ¥600 → 保存 | 新订单的佣金 amount=60000 |
| 4 | 比例联动 | 直接佣金改为 50% | 下方显示"每笔¥131:直接¥65.50 / 上级¥6.55 / 平台¥58.95" |
| 5 | 比例联动反向 | 种子价改为 ¥2,000 | B端卡片"L1占种子价%"从38.1%变为25.0% |
| 6 | 输入校验 | 在金额框输入 -100 | el-input-number 阻止输入,值保持为 0 |
| 7 | 保存失败 | 网络断开后保存 | 显示"保存失败",输入值保留不丢失 |
| 8 | 保存后立即生效 | 改种子价为 ¥2,000 → 保存 → 新用户打开支付页 | 显示 ¥2,000 |
| 9 | 缓存同步 | API 直接改 DB → 调用 getInt() | 返回值仍为旧值(下次 loadAllToCache 或调用 updateConfig 后更新) |
| 10 | 种子名额展示 | 3笔已支付 practitioner 种子价订单 | 显示"已使用:3 / 300" |
| 11 | 种子有效期展示 | 有效期设为未来日期 | 显示"🟢 有效期剩余 XX 天" |
| 12 | 种子有效期过期 | 有效期设为过去日期 | 显示"🔴 已过期" |
作为 运营管理员
我希望 查看所有订单记录,按产品类型和状态筛选
以便 核对收入和对账
后端 API(补全 AdminController.listOrders()):
POST /api/admin/orders → 接收筛选参数,返回分页订单列表
// Request:
{
"productType": "", // 筛选:"" 全部 | "practitioner" | "annual"
"status": "", // 筛选:"" 全部 | "paid" | "pending"
"page": 1,
"pageSize": 20
}
// Response:
{
"code": 0,
"data": {
"list": [
{
"id": 1,
"userId": 42,
"outTradeNo": "202605280001",
"totalFee": 131400,
"productType": "practitioner",
"isSeedPrice": true,
"status": "paid",
"payType": "wxpay",
"paidAt": "2026-05-28T10:00:00",
"createdAt": "2026-05-28T09:59:00"
}
],
"total": 128,
"page": 1,
"pageSize": 20
}
}
后端在 OrderRepository 中新增分页+动态筛选查询方法(使用 Specification 或 @Query 动态拼接)
前端页面:
当前代码待补全:
AdminController.listOrders() 目前返回 Result.success(null) → 需替换为真实数据Order 实体和 OrderRepository 已有,但缺 productType 和 isSeedPrice 字段 → 需新增orders 需增加 product_type 和 is_seed_price 列Pageable + Specification(或简单用 PageRequest)| 类名 | 变更 | 说明 |
|---|---|---|
Order.java |
新增字段 | productType (String)、isSeedPrice (Boolean) |
OrderRepository |
新增方法 | countByProductTypeAndStatus(productType, status) |
OrderRepository |
新增方法 | findAll(Specification, Pageable) 或 findByProductTypeAndStatus |
AdminController |
重写 listOrders() |
支持筛选+分页 |
作为 运营管理员
我希望 查看所有佣金记录和统计
以便 了解分销推广效果
后端 API(增强现有):
POST /api/admin/commissions → 支持分页和按级别筛选
// Request:
{
"level": 0, // 0: 全部 | 1: L1 | 2: L2
"page": 1,
"pageSize": 20
}
// Response:
{
"code": 0,
"data": {
"list": [
{
"id": 1,
"orderId": 101,
"fromUserId": 42,
"toUserId": 10,
"level": 1,
"amount": 50000,
"status": "settled",
"remark": "直接推荐升级能量师",
"createdAt": "2026-05-28T10:00:00"
}
],
"total": 56,
"page": 1,
"pageSize": 20,
"summary": {
"settledTotal": 350000, // 已结算总佣金(分)
"pendingTotal": 0, // 待结算总佣金(分,Phase 1 始终为 0)
"grandTotal": 350000, // 总佣金(分)
"countByLevel": { // 各级别笔数
"1": 12,
"2": 8
}
}
}
}
当前 AdminController.listAllCommissions() 返回 commissionRepository.findAll()(无分页)→ 需重写
前端页面(增强现有 commissions/index.vue):
:total="commissions.length" 是前端假分页,改为后端真分页| 当前状态 | 目标状态 | 工作量 |
|---|---|---|
AdminController.listAllCommissions() 无分页,无筛选 |
分页 + level 筛选 + summary 统计 | M |
CommissionRepository 无分页方法 |
新增 findAll(Specification, Pageable) |
S |
| 前端假分页(全量拉取) | 后端真分页 | M |
| 前端无 level 筛选 | 新增 el-select 筛选器 | S |
| 前端无备注列 | 新增 remark 列 | S |
| 前端无笔数统计卡片 | 新增第四个统计卡片 | S |
已决策:推迟,当前不做。
| 用户故事 | 优先级 | 预估工期 | 依赖 | 状态 |
|---|---|---|---|---|
| US-1.1 生日输入与咨询发起 | P0 | 3天 | US-5.1(需登录) | ✅ |
| US-1.2 三角形可视化 | P0 | 3天 | US-1.1 | ✅ |
| US-1.4 数字点击查看含义 | P2 | 1天 | US-1.2 | ✅ |
| US-2.1 分享图片 | P0 | 2天 | US-1.2 | ✅ |
| US-2.2 PDF导出 | P0 | 2天 | US-1.2 | ✅ |
| US-3.1 AI解读展示 | P0 | 2天 | US-1.1 + Dify Workflow配置(附录B) | ✅ |
| US-3.2 AI解读免费/付费控制 | P0 | 1天 | US-3.1 | ✅ |
| US-3.3 解读内容缓存 | P0 | 1天 | US-3.1 | ✅ |
| US-3.4 AI交互问答(免费/付费控制) | P0 | 2天 | US-1.1 + Dify Chatflow配置(附录B) | ✅ |
| US-4.1 能量师付费订阅 | P0 | 2天 | US-5.1 | ✅ |
| US-4.2 种子价自动判断 | P0 | 1天 | US-8.1 | ✅ |
| US-4.3 订阅状态与续费 | P0 | 1天 | US-4.1 | ✅ |
| US-4.4 年费升级能量师(升级定价) | P1 | 1.5天 | US-4.1 + US-4.2 | ✅ |
| US-5.1 微信登录+注册信息完善 | P1 | 3天 | 无 | ✅ |
| US-5.2 历史咨询记录 | P1 | 2天 | US-5.1 | ✅ |
| US-5.3 个人资料编辑(社交预留) | P2 | 1天 | US-5.1 | ✅ |
| US-6.1 推广码生成 | P0 | 1天 | US-4.1 | ✅ |
| US-6.2 分享带参注册与上下级绑定 | P0 | 2天 | US-5.1 | ✅ |
| US-6.3 B端佣金结算(含升级补差+C端半额) | P0 | 3天 | US-4.1 + US-6.2 + US-4.4 + US-8.1 | ✅ |
| US-6.4 C端佣金结算 | P0 | 1天 | US-6.6 + US-6.3 + US-8.1 | ✅ |
| US-6.5 分销面板 | P1 | 2天 | US-6.1 + US-6.3 | ✅ |
| US-6.6 C端年费订阅入口 | P0 | 1.5天 | US-3.2 + US-4.1 | ✅ |
| US-7.1 批注功能 | P2 | 2天 | P0完成 | ✅ |
| US-7.2 客户分组 | P2 | 2天 | P0完成 | ✅ |
| US-8.1 系统配置管理 | P0 | 2天 | 无(独立基础设施) | ✅ |
| US-8.2 订单管理 | P1 | 1.5天 | US-4.1 + Order 新增字段 | ✅ |
| US-8.3 佣金查看 | P1 | 1天 | US-6.3 | ✅ |
| US-9.1 学业方向AI解读 | P1 | 2天 | US-1.1 + Dify学业Workflow | ✅ |
| US-9.2 申请能量师出方案 | P1 | 1.5天 | US-5.1 + US-9.1 | ✅ |
| US-9.3 能量师介入AI会话 | P1 | 2天 | US-5.1 + US-3.4 | ✅ |
| US-9.4 方案价格协商 | P1 | 1.5天 | US-9.3 | ✅ |
| US-9.5 方案付费与交付 | P1 | 2天 | US-9.4 + CommerceService 接口 | ✅ |
| US-9.6 人工方案分销佣金 | P1 | 1天 | US-9.5 + US-8.1 | ✅ |
US-5.1 微信登录
│
▼
US-1.1 生日输入与咨询发起(后端查重(userId+birthday)→确认弹窗→后台计算→返回展示)
│
├──► US-1.2 三角形可视化(24位置新命名 I-X)
├──► US-3.4 AI交互问答(每日3轮,绑定当前命盘)
│
▼
US-5.2 历史咨询记录(按 userId+birthday 唯一归组,可恢复聊天历史)
US-8.1 系统配置管理(独立基础设施——最先完成)
│
├──► US-4.2 种子价判断
├──► US-6.3 B端佣金(读取 L1/L2 金额)
└──► US-6.4 C端佣金(读取直接/上级比例)
US-5.1 微信登录
│
▼
US-6.2 分享带参注册(需要 openid)
│
▼ 绑定上下级关系
│
US-4.1 能量师付费 + US-6.6 C端年费订阅
│ │
▼ ▼
US-6.1 推广码生成 US-6.4 C端佣金结算
│ │
▼ │
US-6.3 B端佣金结算 ◄──────────────┘(共享 paySuccess() 分支)
│
▼
US-6.5 分销面板(前端展示所有数据)
US-8.1 系统配置(人工方案参数——独立基础设施)
│
▼
US-9.1 学业方向AI解读(Dify学业Workflow)
│
▼
US-9.2 申请能量师出方案
│
├──(有上级能量师)──► US-9.3 能量师介入AI会话
│ │
└──(无上级)→ 提示找推荐链接 │
▼
US-9.4 方案价格协商
│
▼
US-9.5 方案付费与交付
│ │
│ ▼
│ US-9.6 人工方案分销佣金
│
▼
CommerceService 接口层(lilishop预留)
| 周次 | 交付内容 |
|---|---|
| Week 1 | US-5.1 登录+注册完善 → US-8.1 系统配置(独立基础设施) |
| Week 2 | US-1.1 咨询发起(依赖US-5.1登录) → US-1.2 三角可视化 → US-1.3 计算规则实现(附录A Step 1-6) |
| Week 3 | US-3.1 AI解读 + Dify Workflow配置(附录B) → US-3.3 缓存 → US-3.2 免费/付费控制 |
| Week 4 | US-3.4 AI问答 + Dify Chatflow配置(附录B) → US-2.1 分享图片 → US-2.2 PDF导出 |
| Week 5 | US-4.1 能量师付费 + US-4.2 种子价 + US-6.6 C端订阅入口 → US-9.1 学业Dify Workflow配置 |
| Week 6 | US-6.2 带参注册 → US-6.1 推广码 → US-6.3 B端佣金(含升级补差) |
| Week 7 | US-6.4 C端佣金 → US-6.5 分销面板 + US-8.2 订单管理 → US-9.2 需求单 + US-9.3 介入会话 |
| Week 8 | 联调测试 + US-8.3 佣金查看 + US-4.3 订阅状态/续费 + US-4.4 升级能量师 + BUG修复 |
| Week 9+ | US-9.4 价格协商 + US-9.5 付费交付 + US-9.6 分佣 → CommerceService 接口层 |
Phase 1 总预估:约 8 周(含联调测试) 排期原则:先做核心流程(登录→命盘→AI),再做支付分销。US-8.1(配置系统)作为基础设施优先完成,保障后续所有定价依赖。 P2 功能(US-1.4 数字点击含义 / US-5.3 资料编辑 / US-7.x 批注与标签)可在 Phase 1 后期或 Phase 2 迭代。
以下清单基于新命名体系(A-X)和咨询会话管理需求,列出所有需修改的代码文件及变更内容。
| 文件 | 变更类型 | 变更内容 |
|---|---|---|
CalculatorService.java |
重写 | 内部7位从 F,G,H,I,M,N,O → I,J,K,L,M,N,O;新增外部9位 P,Q,R,S,T,U,V,W,X 的独立计算;新增 calculateFullTriangle() 返回全部24个位置 |
ChartService.java |
改造 | 新增 startConsultation(userId, birthday, name, questions) 方法,含:①查 userId+birthday 是否已有记录;②已有则直接返回+聊天历史;③无则服务器端调 CalculatorService 计算+创建记录+可选首次AI解读 |
ChartController.java |
改造 | 保留 /api/chart/create(兼容旧版);新增 POST /api/consultation/start → 调 ChartService.startConsultation() |
ChartRecord.java |
微调 | 新增 lastInteractionAt 字段(LocalDateTime,用于列表排序);加 @Table(uniqueConstraints=...) 定义 (userId, birthday) 联合唯一 |
ChartRecordRepository.java |
新增 | Optional<ChartRecord> findByUserIdAndBirthday(Long userId, String birthday) |
UserService.java |
微调 | checkDailyQuota() 和 consumeQuota() 已有逻辑不变(3次/天全局计数),但新增注释明确"非VIP每日3次绑定当前命盘,切换生日不重置" |
ProfileController.java |
微调 | 咨询列表接口按 lastInteractionAt 倒序 |
DifyService.java |
新增 | Dify API 客户端,封装 POST /v1/workflows/run(命盘解读)和 POST /v1/chat-messages(AI问答)两个接口;含签名、错误重试、超时处理,详见附录B |
ChatService.java |
改造 | 原直调 LLM 逻辑改为调 DifyService;解读生成走 DifyService.runWorkflow();问答走 DifyService.sendChatMessage();在调用前检查配额(US-3.4) |
| 文件 | 变更类型 | 变更内容 |
|---|---|---|
client/utils/calculator.js |
废弃/降级 | calculateTriangle() 保留为离线兜底,不再作为主路径调用;内部命名改为 I,J,K,L,M,N,O;新增 calculateFullTriangle() 含外部 P-X;主入口加注释 @deprecated 请使用后端计算 |
client/stores/chart.js |
改造 | computeChart() 不再调 calculateTriangle(),改为调 consultationApi.start();返回数据中的 positions 直接写入 currentChart;不再调 analyzeTriangle()(由后端返回) |
client/components/TriangleChart.vue |
重写 matrix() | innerBottom 从 [d.F,d.G,d.H,d.I] → [d.I,d.J,d.K,d.L];outerLeft 从 {main:d.M, sub:[d.F,d.G]} → {main:d.R, sub:[d.P,d.Q]};outerRight 从 {main:d.N, sub:[d.H,d.I]} → {main:d.U, sub:[d.S,d.T]};outerTop 从 {main:d.O, sub:[d.M,d.N]} → {main:d.X, sub:[d.V,d.W]} |
client/pages/index/index.vue |
改造 | onAnalyze() 改为:①调 POST /api/consultation/start(传 birthday + name + questions);②若返回 isNew=true 且 requireConfirmation=true 则弹确认框;③确认后再次请求;④成功后跳转 chart/index;⑤"想了解的问题"加 maxlength=100 + 实时字数显示 |
client/utils/api.js |
新增 | consultationApi:start(data) → POST /api/consultation/start;detail(id) → POST /api/consultation/detail |
client/pages/chart/index.vue |
微调 | 适配新的 API 返回结构(chartData.positions 含全部 I-X);onMounted 加载历史消息逻辑不变 |
client/pages/records/index.vue |
微调 | 列表按 lastInteractionAt 排序;详情页恢复聊天历史逻辑不变 |
| 变更 | 说明 |
|---|---|
chart_records 表加联合唯一索引 |
UNIQUE INDEX uk_user_birthday (user_id, birthday),确保同用户+同生日只有一条咨询记录 |
chart_records 表加字段 |
last_interaction_at DATETIME,默认等于 created_at,每次 AI 聊天时更新,用于列表排序 |
chart_records 表现有字段 |
chart_data 列存储的 JSON 结构从 7个旧位置 → 16个新位置(内部 I-O + 外部 P-X) |
Step 1: US-1.3(本对照表)→ 开发团队通读,确保理解命名对应关系
Step 2: 数据库迁移 → 加索引+字段
Step 3: CalculatorService.java → 重写为新命名+外部计算
Step 4: ChartService.java + ChartController.java → 新增 startConsultation()
Step 5: stores/chart.js + api.js → 前端调后端新接口(主路径走后端;后端不可用时 calculator.js 降级兜底,仅展示离线计算版命盘,不提供AI解读和咨询记录)
Step 6: TriangleChart.vue → matrix() 改用新命名+独立外部值
Step 7: pages/index/index.vue → 确认弹窗 + 100字限制
Step 8: Dify 配置 →
8a. 在 Dify 平台创建 Workflow(命盘解读)和 Chatflow(AI问答)
8b. 上传知识库文档(数字能量学语料)
8c. 发布工作流,获取 API Key
Step 9: DifyService.java + ChatService.java → 集成 Dify API
Step 10: 联调 → 前后端打通 end-to-end,含 Dify 工作流调试验收
Dify 是开源 LLM 应用开发平台,提供可视化工作流编排、RAG 知识库、模型管理等能力。 本项目使用 Dify 的两个应用类型:Workflow(命盘解读生成)和 Chatflow(AI交互问答)。
┌─────────────────────────────────────────────────────────┐
│ 微信小程序前端 │
│ POST /api/chart/interpret POST /api/chat/send │
└────────────────────┬─────────────────────┬──────────────┘
│ │
┌────────────────────▼─────────────────────▼──────────────┐
│ Java 后端 (Spring Boot) │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ChatController│ │ChartController│ │ChatService │ │
│ └──────┬──────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └──────────┬──────┘ │ │
│ │ │ │
│ ┌──────────▼──────────┐ ┌───────────▼────────┐ │
│ │ DifyService.java │ │ DifyService.java │ │
│ │ runWorkflow() │ │ sendChatMessage() │ │
│ └──────────┬──────────┘ └───────────┬─────────┘ │
└────────────────────┼─────────────────────────┼───────────┘
│ │
┌────────────────────▼─────────────────────────▼───────────┐
│ Dify API (自建部署 / SaaS) │
│ │
│ ┌──────────────────┐ ┌──────────────────────┐ │
│ │ Workflow(解读) │ │ Chatflow(问答) │ │
│ │ │ │ │ │
│ │ 开始 → 知识检索 │ │ 开始 → 接收消息 │ │
│ │ → LLM生成解读 │ │ → 知识检索 → LLM回答 │ │
│ │ → 格式化输出 │ │ → 返回答案 │ │
│ └────────┬─────────┘ └──────────┬───────────┘ │
│ │ │ │
│ └──────────┬───────────────┘ │
│ │ │
│ ┌──────────▼──────────┐ │
│ │ 知识库(RAG) │ │
│ │ ├─ 主性格含义库 │ │
│ │ ├─ 组合数字含义库 │ │
│ │ ├─ 三区年龄解读库 │ │
│ │ └─ 常见命盘案例库 │ │
│ └─────────────────────┘ │
└──────────────────────────────────────────────────────────┘
关键原则:
用途: US-3.1 AI解读展示
Dify 应用类型: Workflow(工作流)——单轮执行,无需维护对话历史
触发方式: API 调用,blocking 模式
输入变量:
| 变量名 | 类型 | 说明 |
|---|---|---|
chart |
object |
24个命盘位置的值 { A:8, B:1, ..., X:5 } |
name |
string |
用户姓名 |
birthday |
string |
出生日期 YYYY-MM-DD |
工作流节点编排:
[开始节点]
↓
[知识检索 1] 查主性格(O)含义
↓
[知识检索 2] 查左区(P,R)21-40岁解读
↓
[知识检索 3] 查顶部(V,X)41-60岁解读
↓
[知识检索 4] 查右区(S,U)61+岁解读
↓
[知识检索 5] 查特殊组合(如 I+J=11, M+O 等)
↓
[LLM 节点]
系统提示词:
"你是一个专业的数字能量学分析师。
根据以下命盘数据和检索到的知识,生成完整的命盘解读。
必须严格按照以下结构输出..."
↓
[代码节点 / 输出解析]:确保输出 JSON 结构正确
↓
[结束节点] → 输出 `{ sections: [...], summary: "..." }`
输出格式(data.outputs):
{
"sections": [
{
"title": "主性格解读",
"position": "O",
"value": 6,
"content": "主性格数字 6 代表…",
"keywords": ["责任心", "家庭", "关爱"]
},
{
"title": "左区(21-40岁)",
"positions": ["P", "Q", "R"],
"values": [8, 3, 2],
"content": "左区数字组合 8-3-2 代表…"
},
{
"title": "顶部(41-60岁)",
"positions": ["V", "W", "X"],
"values": [4, 1, 5],
"content": "顶部数字组合 4-1-5 代表…"
},
{
"title": "右区(61+岁)",
"positions": ["S", "T", "U"],
"values": [6, 8, 5],
"content": "右区数字组合 6-8-5 代表…"
}
],
"summary": "整体命盘评价…",
"combination_notes": ["数字 I(4)+J(3)=7,形成…", "M(7)+O(6)=13→4,形成…"]
}
用途: US-3.4 AI交互问答
Dify 应用类型: Chatflow(对话工作流)——多轮对话,自动维护 conversation_id
触发方式: API 调用,streaming 模式(打字机效果)
第一轮消息传入的上下文变量:
{
"inputs": {
"chart": { "A":8, "B":1, "C":9, "D":6, "E":3, "F":0, "G":1, "H":4,
"I":4, "J":3, "K":6, "L":5, "M":7, "N":2, "O":6,
"P":8, "Q":3, "R":2, "S":6, "T":8, "U":5, "V":4, "W":1, "X":5 },
"user_name": "张三",
"birthday": "1996-03-14"
},
"query": "我的主性格数字6代表什么?",
"user": "uid_123",
"response_mode": "streaming"
}
后续轮次: 只传 query + conversation_id,无需重复传入命盘数据
Chatflow 节点编排:
[开始节点]
↓
[问题分类节点]
├─ 问数字含义 → [知识检索] → [LLM 回答]
├─ 问运势建议 → [知识检索] → [LLM 回答]
└─ 其他问题 → [LLM 直接回答]
↓
[LLM 节点]
系统提示词:
"你是一个数字能量学咨询助手。
用户的命盘数据已作为上下文变量传入。
请基于用户的命盘数据和知识库内容回答问题。
如果问题涉及具体数字,请引用该数字在命盘中的位置和含义。"
↓
[结束节点] → 输出答案文本
需要在 Dify 平台创建的知识库文档:
| 文档名称 | 内容 | 用途 |
|---|---|---|
| 数字能量学基础 | 数字 1-9 的基础能量含义、吉凶属性 | LLM 基础理解 |
| 主性格数字解读 | 每个主性格数字(1-9)的详细性格特质、优缺点、代表人物 | 主性格解读 |
| 位置含义对照表 | 每个位置(A-X)代表的人生领域和能量属性 | 各章节解读 |
| 组合数字解读 | 常见数字组合(如11/22/33/13/14等)的特殊含义 | 组合分析 |
| 三区年龄段解读 | 21-40 / 41-60 / 61+ 三个年龄段的典型命理模式 | 三区解读 |
| 常见命盘案例 | 典型命盘 + 完整解读示例(Few-shot 示例) | 提升解读质量 |
文档格式建议:
示例格式:
# 主性格数字 7
## 核心特质
- 关键词:分析力、哲学思维、追求真理
- 能量属性:精神导向,向内探索
## 性格描述
主性格数字7的人天生具有强烈的分析能力和探索精神…
## 优势
- 逻辑思维强
- 善于发现规律
- 独立自主
## 劣势
- 容易多疑
- 社交上偏孤僻
- 过度分析导致行动迟缓
## 代表人物
- 爱因斯坦、达芬奇
DifyService.java 核心接口:
@Service
public class DifyService {
// 配置(从 application.yml 读取)
@Value("${dify.api-base}")
private String apiBase; // e.g. "https://api.dify.ai/v1"
@Value("${dify.workflow-api-key}")
private String workflowApiKey; // 命盘解读 Workflow 密钥
@Value("${dify.chatflow-api-key}")
private String chatflowApiKey; // AI问答 Chatflow 密钥
/**
* 调用 Dify Workflow 生成命盘解读(US-3.1)
* @param chartData 24个数字的 Map
* @param userName 用户姓名
* @param birthday 出生日期
* @return 结构化解读结果(sections + summary)
*/
public InterpretationResult runInterpretation(
Map<String, Integer> chartData, String userName, String birthday
) {
// 1. 构造 inputs
// 2. POST /v1/workflows/run (blocking)
// 3. 解析 data.outputs 为 InterpretationResult
// 4. 超时 15s,重试 1 次
}
/**
* 调用 Dify Chatflow 发送消息(US-3.4)
* @param chartData 24个数字(仅首轮传入)
* @param conversationId 已有会话ID(后续轮次)
* @param query 用户问题
* @param userId 用户标识
* @param isFirstRound 是否首轮
* @return Dify 流式响应或阻塞响应
*/
public ChatResponse sendChatMessage(
Map<String, Integer> chartData,
String conversationId,
String query,
String userId,
boolean isFirstRound
) {
// 1. 首轮时传入 inputs(chart 数据)
// 2. POST /v1/chat-messages (streaming)
// 3. 返回 SSE 流或阻塞结果
}
}
ChatService.java 改造要点:
@Service
public class ChatService {
public ChatResponse sendMessage(Long userId, Long chartId, String message) {
// 1. 检查用户配额(US-3.4)
if (!isVip(userId) && getTodayQuota(userId) >= 3) {
throw new BusinessException("今日AI问答次数已用完");
}
// 2. 获取命盘数据
ChartRecord record = chartRecordRepository.findById(chartId);
Map<String, Integer> chartData = record.getChartData();
// 3. 调用 Dify(Chatflow)
String conversationId = record.getDifyConversationId();
boolean isFirstRound = (conversationId == null);
ChatResponse response = difyService.sendChatMessage(
chartData, conversationId, message, userId.toString(), isFirstRound
);
// 4. 首次对话保存 conversationId
if (isFirstRound) {
record.setDifyConversationId(response.getConversationId());
chartRecordRepository.save(record);
}
// 5. 消耗配额
consumeQuota(userId);
return response;
}
}
application.yml 新增配置:
dify:
api-base: https://api.dify.ai/v1
workflow-api-key: app-xxxxx # 命盘解读 Workflow
chatflow-api-key: app-yyyyy # AI问答 Chatflow
timeout: 15000 # 单次调用超时 15s
| 模式 | 适用阶段 | 说明 |
|---|---|---|
| Dify SaaS(cloud.dify.ai) | 开发/测试 | 快速上手,无需自建,有免费额度 |
| 自建部署(Docker) | 生产 | 数据不出域,可控成本,建议生产环境使用 |
自建部署参考:https://github.com/langgenius/dify
DifyService.java,调通 Workflow 和 Chatflow 两个 API| Dify 组件 | 对应 US | 备注 |
|---|---|---|
| Workflow(命盘解读) | US-3.1 AI解读展示、US-3.2 付费控制 | Workflow 输出由 US-3.2 决定是否全文展示 |
| Workflow(学业方向) | US-9.1 学业方向AI解读 | 新增专用Workflow,输入24个A-X数字,输出学业方向分析JSON |
| Chatflow(AI问答) | US-3.4 AI交互问答 | 配额控制在 Java 后端,不经过 Dify;能量师介入消息不走Dify |
| 知识库 | US-3.1、US-3.4、US-9.1 | 三个工作流共用同一套知识库 |
| 无(纯后端) | US-3.3 解读内容缓存、US-9.5 CommerceService | 缓存逻辑在 Java 后端,不涉及 Dify |
覆盖系统所有功能的权限边界,按角色逐一对比。
| | 普通用户 | C端年费用户 | 能量师用户 |
|--|---------|------------|-----------|
| 年费 | ¥0 | ¥131 | ¥1,314(种子)/ ¥1,986(标准) |
| 数据库标记 | vipType=NULL | vipType='annual' | vipType='practitioner' |
| 到期降级 | — | → 普通用户 | → 普通用户 |
| 续费价格 | — | 标准价 ¥131 | 标准价 ¥1,986(种子价仅限创始人码首次购买) |
| 定位 | 浏览体验 | 给自己看,轻度社交 | 给客户看,商业工具 |
能力 普通用户 C端¥131 能量师¥1,314+
───────────────────────── ────────── ────────── ──────────────
生成命盘 ✅ ✅ ✅
查看命盘可视化 ✅ ✅ ✅
数字点击查看含义 ✅ ✅ ✅
AI解读·主性格概要 1次/天 不限 不限
AI解读·完整五区 ❌ ✅ ✅
AI问答互动 3轮/天 不限 不限
学业方向AI解读 1次/天 不限 不限
分享图片到微信 1次/天 不限 不限
导出PDF报告 ❌ 不限 不限
历史记录查看 近7天 全部 全部
推广码+分销面板 ❌ ✅ ✅
推广C端年费得佣金 ❌ 40%+5%分成 40%+5%分成
推广能量师年费得佣金 ❌ ❌ ¥500 + ¥100
申请能量师出方案 ✅ ✅ ✅
能量师介入AI会话 ❌(被动) ❌(被动) ✅(主动)
接受人工方案付费 ✅ ✅ ✅
命盘批注(P2) ❌ ✅ ✅
客户标签分组(P2) ❌ ❌ ✅
个人资料编辑 ✅ ✅ ✅
个人中心标签 "普通用户" "C端会员" "能量师"
订阅引导卡片 可见 不可见 不可见
续费提醒 — 到期前7天 到期前7天
所有用户
│
├─ 微信登录 → 完善资料(昵称/头像/生日/性别)
│
└─ 输入生日 → 生成命盘 → 查看命盘图 → 查看主性格概要(免费1次)
│
├─ 遇到付费墙(完整解读/PDF/无限问答)
│ └─ 看到 ¥131 开通引导卡片
│
└─ 保持免费用户,每日 3 轮问答 + 1 次分享
普通用户点击"开通 ¥131"
│
├─ 微信支付 ¥131
├─ vipType → 'annual', vipEndTime → +365天
├─ 推广码自动生成
│
└─ 解锁能力:
├─ AI完整解读(无限次)
├─ AI问答(不限轮数)
├─ 分享图片(不限次)
├─ PDF导出(不限次)
├─ 历史记录(全部)
├─ 分销面板可见
└─ 推广C端年费赚 40% + 5%
用户点击"开通能量师"
│
├─ 通过创始人码注册 + 有效期内 + 名额未满 → 种子价 ¥1,314
├─ 其他情况 → 标准价 ¥1,986
├─ 微信支付 → vipType → 'practitioner', vipEndTime → +365天
├─ 推广码自动生成(若首次付费)
│
└─ 解锁能力(在C端基础上增加):
├─ 推广能量师年费赚 ¥500 + ¥100
├─ 客户标签分组(P2)
└─ 命盘批注(P2,C端也有但用途不同)
能量师 vs C端——AI能力完全一致。 两者在AI解读和问答上没有任何区别(都不限次、完整内容),差异只在于:
| 维度 | C端¥131 | 能量师¥1,314+ |
|---|---|---|
| 分销产品 | 仅 C端年费 | C端年费 + 能量师年费 |
| 佣金模式 | 比例(40%+5%) | 比例 + 固定(¥500+¥100) |
| 种子价资格 | ❌ | ✅(需扫创始人码+有效期内+名额未满) |
| 客户管理 | ❌ 不需要 | ✅ 批注+标签 |
| 使用场景 | 自己看命理 | 为客户解读 |
这意味着如果能量师不打算做推广,¥1,314+相比¥131的额外价值只有批注和标签(P2功能)。这可能影响高客单价转化策略——需要在能量师权益中强化"商业工具"的价值感知。
普通用户的命盘创建无限。 目前仅限制了AI问答3轮/天和AI解读1次/天,但普通用户可创建任意数量的命盘。每个命盘可获得一次免费主性格概要,理论上可通过不停创建新命盘获取多次概要。此场景消耗成本较低(1段文本),暂不设限。
-- users 表相关字段
vipType: NULL 'annual' 'practitioner'
vipEndTime: NULL 2027-05-29 2027-05-29
referralCode: NULL 'A3X7K9' 'B2Y4M8'
profile_complete: true/false true/false true/false
-- 关联表
┌─ orders ─────────────────────┐
│ user_id, product_type, │
│ amount, status, invited_by │
└──────────────────────────────┘
┌─ commissions ────────────────┐
│ order_id, level, amount, │
│ status (pending/settled) │
└──────────────────────────────┘
| 约束规则 | 所在用户故事 |
|---|---|
| AI解读:普通用户仅主性格概要1次/天 | US-3.2 |
| AI问答:普通用户3轮/天全局计数 | US-3.4 |
| 分享图片:普通用户1次/天 | US-2.1 |
| PDF导出:仅付费用户可用,不限次 | US-2.2 |
| 历史记录:普通用户仅7天 | US-5.2 |
| 推广码:仅付费后生成 | US-6.1 |
| 分销面板:仅付费用户可见 | US-6.5 |
| C端佣金:上级须已付费才结算 | US-6.4 |
| 批注:仅已付费用户 | US-7.1 |
| 标签:仅能量师(practitioner)可用 | US-7.2 |
| 学业方向AI解读:普通用户1次/天 | US-9.1 |
| 能量师介入AI会话:仅上级能量师可介入 | US-9.3 |
| 人工方案分佣:平台留存模型 | US-9.6 |