chore: update experience index and documentation for various roles

- Added recent experience entries for roles including Assistant, Mini Program Developer, Backend Engineer, Product Manager, Software Tester, and Team.
- Enhanced documentation structure in the development assistant's experience list and project index.
- Updated role-flow control documentation to reflect new methodologies and programming thinking.
- Improved error handling in the mini program and backend API for better user feedback during operations.

Made-with: Cursor
This commit is contained in:
乘风
2026-04-14 11:24:18 +08:00
parent e391115938
commit 35e18a7ccb
44 changed files with 502 additions and 43 deletions

View File

@@ -0,0 +1,6 @@
# 产品经理 经验记录 - 2026-04-13
## 会议:按功能同步开发文档
- **要点**:以可验收功能点为最小同步单位;主需求与《以界面定需求》为验收真源;跨端规则变更须同时更新需求清单状态与优先级。
- **待办**:核对 2026-04-02 以来实现与文档差异vip-members/融合一期验收口径在需求文档中单点定稿。

View File

@@ -0,0 +1,7 @@
# 产品经理 经验记录 - 2026-04-14
## 吸收沉淀:同步开发需求
- **需求清单**:在 `开发文档/1、需求/需求汇总.md` 维护编号行SYNC / LOOP / MAINT 等),状态与责任角色与纪要待办一致。
- **验收绑定**:功能完成 = 实现可合并 + **需求表或项目索引当日一行**;跨端规则须在需求或运营与变更中单点写清优先级。
- **管理端必要性**:沿用产品 Skill — 纯文案/纯视觉可不建管理端;**配置/开关/审核/统计** 必须显式在需求表标「管理端入口」避免壳功能。

View File

@@ -6,3 +6,5 @@
| 2026-03-05 | 文章详情@某人高亮与一键加好友验收标准与待确认 | [2026-03-05.md](./2026-03-05.md) |
| 2026-03-10 | 管理端迁移 Mycontent-temp主导航收敛与隐藏页面入口承载策略 | [2026-03-10.md](./2026-03-10.md) |
| 2026-03-24 | 开发进度同步会议:文档同步原则、项目索引补齐 | [2026-03-24.md](./2026-03-24.md) |
| 2026-04-13 | 按功能同步开发文档会议:验收与需求真源、功能完成定义 | [2026-04-13.md](./2026-04-13.md) |
| 2026-04-14 | 吸收沉淀:需求汇总表维护、验收与管理端必要性 | [2026-04-14.md](./2026-04-14.md) |

View File

@@ -0,0 +1,6 @@
# 后端工程师 经验记录 - 2026-04-13
## 会议:按功能同步开发文档
- **要点**接口变更须写明路由组miniprogram/admin/db、路径、字段与错误码表结构/迁移在部署文档或临时需求池留痕;历史待办按 P0/P1 标注与依赖方。
- **待办**router/ossConfig、vip-members 等待办在文档中优先级化。

View File

@@ -0,0 +1,6 @@
# 后端工程师 经验记录 - 2026-04-14
## 吸收沉淀:接口与需求文档同步
- 新增/变更接口须在需求或运营摘要中写明 **路由组miniprogram/admin/db**、路径、关键字段与错误码;迁移写在 `开发文档/8、部署/` 或临时需求池(若存在)。
- **P0/P1 待办**router、ossConfig、vip-members 等)在 `需求汇总.md` 已单列 BACKEND-P0 行,合并前更新状态与依赖方。

View File

@@ -10,3 +10,5 @@
| 2026-03-16 | ParseAutoLinkContent data-label存客宝 create planType/sceneId/status | [2026-03-16.md](./2026-03-16.md) |
| 2026-03-17 | 代付 PayNotify beneficiaryUserID 权益归发起人gift-pay detail 返回 initiatorUserId | [2026-03-17.md](./2026-03-17.md) |
| 2026-03-24 | router 缺失四 handlerBookRanking、DBPersonPinnedToken、CKBPinnedPerson、AdminDashboardLeads | [2026-03-24.md](./2026-03-24.md) |
| 2026-04-13 | 按功能同步开发文档:接口/迁移文档化与 P0/P1 标注 | [2026-04-13.md](./2026-04-13.md) |
| 2026-04-14 | 吸收沉淀接口与需求表同步、BACKEND-P0 行 | [2026-04-14.md](./2026-04-14.md) |

View File

@@ -0,0 +1,6 @@
# 团队 经验记录 - 2026-04-13
## 会议:按功能同步开发文档(跨角色)
- **决议**:功能完成定义包含 **代码可合并状态 + 当日文档/项目索引一行摘要(含日期)**;跨端字段或接口变更除各角色文档外,须在团队 evolution 或会议纪要留契约摘要。
- **关联**:详见 `agent/产品经理|后端工程师|管理端开发工程师|小程序开发工程师|软件测试/evolution/2026-04-13.md``.cursor/meeting/2026-04-13_按功能同步开发文档.md`

View File

@@ -0,0 +1,19 @@
# 团队 经验记录 - 2026-04-14
## 吸收沉淀:小程序优先闭环 + 需求同步
### 场景
评审「功能是否闭环」、区分界面写死与配置化、识别仅有样式无管理端入口、评估对其它模块的影响。
### 结论(团队约定)
1. **逆推顺序**:从小程序用户路径出发 → 数据来源(常量 / 本地 / `app.request`)→ `/api/miniprogram/*` 是否存在与错误语义 → 是否需要 **管理端或远程配置**(运营是否会改、是否与钱/风控相关)→ 是否影响支付/登录/分享/其它页 `onShow`
2. **写死 vs 配置化**:按 **变更频率、责任主体(运营/研发)、风险** 决策;需运行时开关/灰度时采用 **Feature Toggle** 思路(见业界 Martin Fowler *Feature Toggles*),避免永久堆砌 `if(flag)` 无退役计划。
3. **壳功能信号**:有入口但无 API、仅有样式、管理端无对应配置且业务上明显需运营改的标为 **技术债或假完成**,需求表状态不得标「已完成」。
4. **跨模块同步**:契约线(字段/枚举/缓存)、流程线(支付/分销/scene、权限配置线变更须在 **需求汇总 / 运营与变更 / 纪要** 之一可追溯,并双写本文件或 `2026-04-13` 纪要中的契约摘要。
5. **仓库需求真源**:本仓库已建 `开发文档/1、需求/需求汇总.md``开发文档/10、项目管理/运营与变更.md`,与 `.cursor/meeting/`、各角色 evolution 交叉引用。
### 同时影响
小程序、管理端、后端、测试、产品(文档与验收)。

View File

@@ -0,0 +1,50 @@
# 团队 经验记录 - 2026-04-15
## 联网吸收:优秀编程思维 → 智能体执行约束
> 以下为公开资料的**提炼与落地映射**,便于 Soul 多智能体Cursor 角色)统一行为;**非**替代项目 boundary / Skill 全文。
### 1. 垂直切片Vertical slicing
- **含义**:按「用户可感知的一小条价值」贯穿 **展示 → 接口 → 数据/配置**,而不是长期只做「全后端再全前端」的水平分层半成品。
- **对智能体**:拆任务时优先 **end-to-end 最小可演示**(例如:一条只读列表从真实 API 出数),再迭代字段与交互;避免单次会话产出大量未接线 UI。
**参考**:敏捷社区对 vertical slicing 的讨论(如 *The Art of the Vertical Slice* 等文章,关键词 *vertical slice user story*)。
### 2. 追踪弹Tracer bullets
- **出处思想**《The Pragmatic Programmer》——用一发「能穿过各层的薄路径」验证架构是否通畅。
- **与原型区别**:原型可丢;追踪弹是**进主分支的骨架**,后续在其上增厚。
- **对智能体**:强制 **小步、可编译、可运行、可测** 的增量;先打通再美化,降低大模型「一次写太多未验证代码」的风险。延伸阅读:*Tracer Bullets: Keeping AI Slop Under Control*`https://www.aihero.dev/tracer-bullets`)。
### 3. AI 编码与多智能体:验证优先
- **上下文优先**:先给目的、约束、边界、失败模式,再让生成代码(多篇 20242025 *AI coding best practices* 共性)。
- **分块生成 + 人审合并**:大纲 → 分文件小改 → 跑测试/静态检查;不把未读 diff 直接合并。
- **评估维度(借鉴 Agent 质量讨论)**:任务是否完成、工具/接口调用是否准确、是否引入多余依赖(参见 AWS 等「Agent 质量评估」类文章中的 TCR、工具准确率等提法
### 4. 工程文化:无责复盘与简单性
- **Blameless postmortem**:复盘关注**系统与流程**如何允许失误、行动项是否可验证避免归罪个人利于真实写入经验库Google SRE Book — Postmortem Culture`https://sre.google/sre-book/postmortem-culture/`)。
- **简单性**:偏好无聊但清晰的实现;与 Feature Toggle 一样,**实验性分支要有退役计划**。
### 5. 映射到本仓库Soul
| 外部思维 | 本仓库落地 |
|----------|------------|
| 垂直切片 / 追踪弹 | 跨端任务走 `role-flow-control`:先契约与最小联调,再扩功能;纪要/需求表可追溯 |
| 验证优先 | `change-checklist`、测试 Skill、`app.request` 与三端路由自检 |
| 无责复盘 | `.cursor/meeting/*` 问题与作答区 + 各角色 `evolution` 按日沉淀 |
| 简单性 | 禁止跨端乱调路由;避免无退役计划的永久 feature flag |
---
## 业务补齐(同日追加)
- **`app.request`**`success:false` 与部分非 200 响应在 `reject``Error` 上挂载 **`response`**,与 `miniprogram-dev` Skill 及 `referral/my` 提现分支一致。
- **导师咨询支付**`productType=mentor_consultation``getStandardPrice` 校验预约单归属与金额;`activateOrderBenefits` + `PayNotify``mentor_consultations.status``paid`**分销佣金**对导师单显式跳过(待产品另定规则)。
- **资源对接 `investor`**`CKBJoin` 未购章节时 **`success:false` + `errorCode: CONTENT_PURCHASE_REQUIRED`**,小程序 `match.js``e.response` 展示文案。
---
**最后更新**2026-04-15

View File

@@ -11,3 +11,6 @@
| 2026-03-16 | TipTap Mention 需 data-label否则显示 token | [2026-03-16.md](./2026-03-16.md) |
| 2026-03-17 | 代付美团式流程与权益归属约定:读页→代付页→分享;权益/分佣归发起人 | [2026-03-17.md](./2026-03-17.md) |
| 2026-03-24 | 文档同步原则:实现变更后同步需求/运营与变更/项目索引 | [2026-03-24.md](./2026-03-24.md) |
| 2026-04-13 | 按功能同步开发文档:功能完成=实现+索引;跨端契约双写 | [2026-04-13.md](./2026-04-13.md) |
| 2026-04-14 | 小程序优先闭环审计、写死vs配置化、需求表骨架与 role-flow §1.2 | [2026-04-14.md](./2026-04-14.md) |
| 2026-04-15 | 联网垂直切片、追踪弹、AI验证优先、无责复盘role-flow §1.3 | [2026-04-15.md](./2026-04-15.md) |

View File

@@ -0,0 +1,6 @@
# 小程序开发工程师 经验记录 - 2026-04-13
## 会议:按功能同步开发文档
- **要点**:页面级记录 `/api/miniprogram/*`、scene、支付/登录、分享 singlePage 等行为变更;纯 UI 无接口变更时也注明,便于测试裁剪回归。
- **待办**:主路径未记入文档的改动补索引一行。

View File

@@ -0,0 +1,6 @@
# 小程序开发工程师 经验记录 - 2026-04-14
## 吸收沉淀:闭环与硬编码自检
- 新功能自检:**页面 → 数据从哪来**;若仅为写死展示,在索引注明「无接口/无配置」以免误判完成度。
- 涉及 **scene、支付、登录、分享 singlePage** 的改动必须在 `需求汇总` 或项目索引可追溯,并评估对 **我的/阅读/代付** 等邻页的副作用。

View File

@@ -15,3 +15,5 @@
| 2026-03-17 | 代付美团式:读页→代付页→分享;详情页双态(发起人/好友);目录 loading、最新新增 5 条折叠 | [2026-03-17.md](./2026-03-17.md) |
| 2026-03-30 | 阅读页 `navigateToMiniProgram` 时 path 追加 `phone`(已登录且已绑定) | [2026-03-30.md](./2026-03-30.md) |
| 2026-04-11 | 阅读付费墙三态框体统一、`shareTipLine` 与文末分享区一致、需求文档闭环 | [2026-04-11-阅读付费墙三态与营销句闭环.md](./2026-04-11-阅读付费墙三态与营销句闭环.md) |
| 2026-04-13 | 按功能同步开发文档:页面级接口与分享行为、无接口变更亦标注 | [2026-04-13.md](./2026-04-13.md) |
| 2026-04-14 | 吸收沉淀:闭环与硬编码自检、邻页副作用 | [2026-04-14.md](./2026-04-14.md) |

View File

@@ -0,0 +1,6 @@
# 开发助理(橙子)经验记录 - 2026-04-14
## 吸收沉淀:各智能体同步开发需求
- 触发:用户「各智能体吸收经验沉淀,同步开发需求」→ 执行 `assistant-doc-sync` §5 + 文档同步:补齐仓库根 `开发文档/` 骨架,写入 `需求汇总.md``运营与变更.md`
- 同步 `经验清单.md``智能体-技能-经验总索引.md`、各角色 `evolution/索引.md`、项目索引一行、`sync-log`;轻量升级 `role-flow-control` §1.2(小程序逆推闭环)。

View File

@@ -0,0 +1,7 @@
# 开发助理 经验记录 - 2026-04-15
## 联网吸收:编程思维写入智能体
- **触发**:用户要求联网吸收优秀编程思维并沉淀到智能体。
- **动作**检索垂直切片、追踪弹、AI 编码验证、SRE 无责复盘等公开论述;写入 `agent/团队/evolution/2026-04-15.md`;在 `role-flow-control/SKILL.md` 增加 **§1.3 智能体协作提要**;更新 `经验清单``智能体-技能-经验总索引`、团队/助理橙子项目索引、`sync-log`
- **注意**:外链为思想参考;执行顺序仍以本仓库 `.cursor/rules` 与各主 Skill 为准。

View File

@@ -6,3 +6,5 @@
|------|------|------|
| 2026-03-21 | MBTI 头像小程序全链路兜底 + 匹配接口回填 | 2026-03-21-MBTI头像C端全链路兜底.md |
| 2026-03-16 | 用户交互习惯分析(基于 agent-transcripts | 2026-03-16-交互习惯分析.md |
| 2026-04-14 | 各智能体吸收经验沉淀开发文档骨架、经验清单、role-flow §1.2 | 2026-04-14.md |
| 2026-04-15 | 联网吸收编程思维:团队 evolution、role-flow §1.3、索引与 sync-log | 2026-04-15.md |

View File

@@ -53,6 +53,8 @@
| 2026-03-17 | 后端、团队 | 架构/最佳实践 | api-dev SKILL | Redis 缓存parts/hot/recommended/stats/config/章节 content容灾回退 DBOSS 上传;/health 返回 database/redis 状态 |
| 2026-03-18 | 小程序、团队 | 业务规则/最佳实践 | - | 分享链路兼容好友/朋友圈 singlePage单页模式能力降级不支付/不自动领取),引导点击底部“前往小程序”进入完整版 |
| 2026-03-18 | 产品、后端、管理端、测试 | 文档归档/需求口径 | - | 文档归档整理:以《以界面定需求》为基准,各角色重整“功能需求+验收口径+风险点”并写入各自经验库;补齐《项目落地推进表》 |
| 2026-04-14 | 团队、产品、后端、管理端、小程序、测试、助理橙子 | 方法论/需求同步 | role-flow-control SKILL §1.2、assistant-doc-sync 文档树说明 | 吸收沉淀小程序逆推闭环、写死vs配置、需求汇总+运营与变更骨架;各角色 evolution/2026-04-14.md |
| 2026-04-15 | 团队、助理橙子 | 方法论(联网) | role-flow-control SKILL §1.3 | 垂直切片、追踪弹与 AI slop 控制、验证优先、Google SRE 无责复盘;详 `agent/团队/evolution/2026-04-15.md` |
---
@@ -63,4 +65,4 @@
---
**最后更新**2026-03-18
**最后更新**2026-04-15

View File

@@ -6,7 +6,7 @@
## 项目总结
Soul 创业派对产品定位:面向创业者的社区/工具型小程序。核心需求文档在 `开发文档/1、需求/2026-03-20-需求.md`(主需求清单),闭环结论见 `开发文档/10、项目管理/闭环与文档同步-2026-04-07.md`,临时需求/分析在 `临时需求池/`
Soul 创业派对产品定位:面向创业者的社区/工具型小程序。核心需求文档在 `开发文档/1、需求/2026-03-20-需求.md`(主需求清单,若未入库见同目录 `需求汇总.md`),闭环结论见 `开发文档/10、项目管理/闭环与文档同步-2026-04-07.md`(若存在),临时需求/分析在 `临时需求池/`(按需创建)
---
@@ -31,9 +31,11 @@ Soul 创业派对产品定位:面向创业者的社区/工具型小程序。
| 2026-03-31 | 会议:超级个体列表与 @ 列表融合方案(先数据互链再单页);一期验收口径待拍板 | 待续 |
| 2026-04-02 | 会议:工作进度与需求同步;一期融合验收口径澄清、各端索引与需求 delta 跟进 | 进行中 |
| 2026-04-07 | 开发文档与主需求交叉同步;闭环分析落盘(主路径成立、规则/风控与纪要问题区待闭环) | 已完成 |
| 2026-04-13 | 会议:按功能同步开发文档;功能完成=实现+文档/索引可追溯;待办见纪要问题区 | 进行中 |
| 2026-04-14 | 吸收沉淀:新建 `开发文档/1、需求/需求汇总.md``开发文档/10、项目管理/运营与变更.md`;需求清单 SYNC/LOOP/MAINT/BACKEND 行 | 进行中 |
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD状态用已完成 / 进行中 / 待续 / 搁置
---
**最后更新**2026-04-07
**最后更新**2026-04-14

View File

@@ -26,9 +26,11 @@
| 2026-03-17 | 会议收尾:源码优化完成与测试流程定稿;纪要、经验入库、开发文档同步 | 已完成 |
| 2026-04-02 | 会议收尾:工作进度与需求同步会;纪要、各角色 evolution、项目索引与会议索引更新 | 已完成 |
| 2026-04-07 | 同步开发文档与主需求;新增《闭环与文档同步-2026-04-07》并更新索引、sync-log | 已完成 |
| 2026-04-14 | 吸收经验:各角色 evolution/2026-04-14、开发文档骨架、经验清单、总索引、role-flow §1.2 | 已完成 |
| 2026-04-15 | 联网吸收编程思维:团队 evolution/2026-04-15、role-flow §1.3、经验清单与 sync-log | 已完成 |
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD状态用已完成 / 进行中 / 待续 / 搁置
---
**最后更新**2026-04-07文档同步与闭环分析
**最后更新**2026-04-15

View File

@@ -43,9 +43,12 @@ soul-apiGo + Gin + GORM + MySQL提供三组路由`/api/miniprogram/*`
| 2026-03-24 | 会议:三端闭环评审;提现/CKB/匹配后端校验与 errorCode 为 P0/P1 | 已完成 |
| 2026-03-31 | 会议:超级个体与 @ 列表融合;优先扩展 vip-members 聚合 Person 关联字段 | 待续 |
| 2026-04-02 | 会议工作进度与需求同步deploy 验证后提交vip-members 聚合优先router/ossConfig 历史待办跟进 | 进行中 |
| 2026-04-13 | 会议:按功能同步开发文档;接口/迁移变更须标路由组与 P0/P1文档待补齐 | 进行中 |
| 2026-04-14 | 吸收沉淀:`需求汇总.md` 增加 BACKEND-P0 行;接口说明与迁移落文档 | 进行中 |
| 2026-04-15 | 业务补齐:`mentor_consultation` 支付计价/回调/权益;`CKBJoin` investor 显式失败;`getStandardPrice` 增加 buyerUserID | 已完成 |
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD状态用已完成 / 进行中 / 待续 / 搁置
---
**最后更新**2026-04-02
**最后更新**2026-04-15

View File

@@ -34,9 +34,12 @@ Soul 创业派对全项目架构与约定路由隔离miniprogram/admin/db
| 2026-03-31 | 会议:超级个体与 @ 列表融合;先数据与入口融合、路由边界不变 | 已完成 |
| 2026-04-02 | 会议:工作进度与需求同步;融合落地顺序与 deploy 验证门禁、问题与作答区待闭环 | 已完成 |
| 2026-04-07 | 文档同步:需求与开发文档索引对齐;闭环结论:主路径成立、规则/风控待加固项见《闭环与文档同步-2026-04-07》 | 已完成 |
| 2026-04-13 | 会议:按功能同步开发文档;功能完成=实现+索引一行;跨端契约双写团队/纪要 | 进行中 |
| 2026-04-14 | 吸收沉淀:小程序逆推闭环方法论;`role-flow-control` §1.2;开发文档需求真源 | 进行中 |
| 2026-04-15 | 联网:垂直切片/追踪弹/验证优先/无责复盘 → `role-flow-control` §1.3、`团队/evolution/2026-04-15.md` | 已完成 |
> **格式说明**:每次架构级讨论后在此追加一行,日期格式 YYYY-MM-DD
---
**最后更新**2026-04-07
**最后更新**2026-04-15

View File

@@ -49,9 +49,12 @@
| 2026-03-30 | 会议:文章详情 # 跳转关联小程序(如 MBTI时 path 追加 `phone`read.js 已实现 | 已完成 |
| 2026-03-31 | 会议:超级个体与 @ 列表融合C 端默认不改接口,仅回归 | 已完成 |
| 2026-04-02 | 会议:工作进度与需求同步;全局 app/request 类改动需主路径冒烟;融合仍以回归为主 | 已完成 |
| 2026-04-13 | 会议:按功能同步开发文档;页面级记 miniprogram 接口与分享行为;无接口变更亦标注 | 进行中 |
| 2026-04-14 | 吸收沉淀:逆推闭环自检写入 evolutionLOOP 需求行 | 进行中 |
| 2026-04-15 | 业务补齐:`app.js``err.response`;导师详情微信支付;找伙伴 join 失败展示后端文案 | 已完成 |
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD状态用已完成 / 进行中 / 待续 / 搁置
---
**最后更新**2026-04-02
**最后更新**2026-04-15

View File

@@ -36,7 +36,9 @@
| 2026-03-24 | 会议三端闭环评审API 绕过负例与双入口提现回归待契约落地后执行 | 已完成 |
| 2026-03-31 | 会议:超级个体与 @ 列表融合;回归清单含排序/@/绑定/Webhook 边界 | 待续 |
| 2026-04-02 | 会议工作进度与需求同步融合清单待联调后执行deploy PR 增加 compose/health/smoke | 待续 |
| 2026-04-13 | 会议:按功能同步开发文档;以文档与索引为真源更新回归;契约未入文档可阻塞 | 进行中 |
| 2026-04-14 | 吸收沉淀LOOP 需求与逆推清单纳入回归裁剪依据 | 进行中 |
---
**最后更新**2026-04-02
**最后更新**2026-04-14

View File

@@ -48,11 +48,13 @@
| 2026-03-24 | 会议:三端闭环评审;管理端与小程序配套整体齐全;类型债择机修 | 已完成 |
| 2026-03-31 | 会议:超级个体与 @ 列表融合UsersPage 表格加 @ 状态与跳转内容页 | 待续 |
| 2026-04-02 | 会议工作进度与需求同步UsersPage 待接口字段就绪后联调deploy 文档基址与后端对齐 | 进行中 |
| 2026-04-13 | 会议:按功能同步开发文档;页面粒度记 admin/db 依赖;类型债排期入文档 | 进行中 |
| 2026-04-14 | 吸收沉淀MAINT-ADMIN-TS 入需求表;配置入口与运营与变更联动 | 进行中 |
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD状态用已完成 / 进行中 / 待续 / 搁置
---
**最后更新**2026-04-02
**最后更新**2026-04-14
> soul-admin 构建仍有 DistributionPage Order.description 类型错误(与本次迁移无关),待修复。

View File

@@ -7,25 +7,37 @@
## 1. 经验索引(按角色)
- 助理橙子:`agent/开发助理/evolution/索引.md`
- 2026-04-15联网编程思维沉淀 + role-flow §1.3
- 2026-04-14各智能体吸收沉淀 + 开发文档骨架与 role-flow §1.2
- 2026-03-21MBTI 头像小程序全链路兜底 + 匹配接口回填
- 2026-03-16用户交互习惯分析基于 agent-transcripts
- 小程序开发工程师:`agent/小程序开发工程师/evolution/索引.md`
- 2026-04-14吸收沉淀闭环自检、邻页副作用
- 2026-04-13按功能同步开发文档页面级接口与分享、无接口变更标注
- 2026-03-30阅读页 `navigateToMiniProgram` 时 path 追加 `phone`
- 2026-03-17代付美团式流程与目录 loading/折叠
- 2026-03-16编辑资料页分享名片Canvas 封面)
- 管理端开发工程师:`agent/管理端开发工程师/evolution/索引.md`
- 2026-04-14吸收沉淀配置入口、MAINT-ADMIN-TS
- 2026-04-13按功能同步开发文档页面粒度 admin/db、字段对齐
- 2026-03-16链接人与事复制/删除 Dialog、planId/apiKey 列)
- 2026-03-10迁移 Mycontent-temp主导航收敛/Settings 承载)
- 2026-03-05文章详情@某人(编辑页插入 @ 用户)
- 后端工程师:`agent/后端工程师/evolution/索引.md`
- 2026-04-14吸收沉淀接口与需求表、BACKEND-P0
- 2026-04-13按功能同步开发文档接口/迁移文档化、P0/P1
- 2026-03-24router 缺失四 handler 补齐BookRanking 等)
- 2026-03-17PayNotify 权益归属发起人
- 2026-03-14内容排名算法修正rank 分公式)
- 产品经理:`agent/产品经理/evolution/索引.md`
- 2026-04-14吸收沉淀需求汇总表、管理端必要性
- 2026-04-13按功能同步开发文档会议功能完成定义/验收真源)
- 2026-03-24开发进度同步会议文档同步原则/项目索引补齐)
- 2026-03-10需求同步管理端迁移入口策略
- 2026-03-05文章详情@某人(验收标准与待确认)
- 软件测试:`agent/软件测试/evolution/索引.md`
- 2026-04-14吸收沉淀LOOP 逆推清单回归)
- 2026-04-13按功能同步开发文档文档为真源、契约缺失可阻塞
- 2026-03-16scripts/test/process 流程测试目录
- 2026-03-05文章详情@某人(用例、联调与回归点)
- 2026-03-10管理端迁移回归鉴权/跳转可达性)
@@ -33,6 +45,9 @@
- 2026-03-20挖矿病毒排查经验转化为 Skills
- 2026-03-20部署 API / 部署触发词(环境与脚本映射)
- 团队(跨角色共享):`agent/团队/evolution/索引.md`
- 2026-04-15联网编程思维垂直切片、追踪弹、验证优先、无责复盘
- 2026-04-14小程序优先闭环、写死vs配置化、需求真源路径
- 2026-04-13按功能同步开发文档实现+索引、跨端契约双写)
- 2026-03-16TipTap Mention 需 data-label
- 2026-03-17代付美团式流程与权益归属约定
- 2026-03-24文档同步原则实现变更后同步需求/运营/索引)
@@ -58,7 +73,7 @@
- 触发:开个会、团队会议、需求评审、方案讨论
- 变更关联检查(防漏改,改完必过):`skills/change-checklist/SKILL.md`
- 触发:变更完成、检查一下、准备提交
- 跨端协同流程(职责分工/联想补齐):`skills/role-flow-control/SKILL.md`
- 跨端协同流程(职责分工/联想补齐/小程序逆推闭环/智能体协作提要`skills/role-flow-control/SKILL.md`
- 触发:跨端功能开发、三端联动优化
- 三端架构分析/迁移拆解约束:`skills/three-tier-arch/SKILL.md`
- 触发:拆解、迁移、框架选择、三端架构

View File

@@ -0,0 +1,6 @@
# 管理端开发工程师 经验记录 - 2026-04-13
## 会议:按功能同步开发文档
- **要点**:以页面/菜单为粒度同步至运营与变更或项目索引;标注所用 `/api/admin/*``/api/db/*`;与小程序共用字段写明来源。
- **待办**DistributionPage 类型债是否纳入排期,在文档或索引中闭环。

View File

@@ -0,0 +1,6 @@
# 管理端开发工程师 经验记录 - 2026-04-14
## 吸收沉淀:配置入口与需求表
-**页面/菜单** 为粒度在 `运营与变更.md` 或项目索引记录所用 `/api/admin/*``/api/db/*`;与小程序对齐的字段写明来源。
- **MAINT-ADMIN-TS**`DistributionPage` 等类型债已进 `需求汇总.md`,排期修复后更新状态为已完成。

View File

@@ -8,3 +8,5 @@
| 2026-03-05 | 文章详情@某人:编辑页插入 @用户、保存约定 content 格式 | [2026-03-05.md](./2026-03-05.md) |
| 2026-03-10 | 管理端迁移 Mycontent-temp 菜单/布局主导航收敛、Settings Tab 承载 author/admin | [2026-03-10.md](./2026-03-10.md) |
| 2026-03-16 | 链接人与事table 布局、planId/apiKey 列、复制图标、删除 Dialog 弹窗 | [2026-03-16.md](./2026-03-16.md) |
| 2026-04-13 | 按功能同步开发文档:页面粒度 admin/db 与字段对齐说明 | [2026-04-13.md](./2026-04-13.md) |
| 2026-04-14 | 吸收沉淀:配置入口与 MAINT-ADMIN-TS 需求行 | [2026-04-14.md](./2026-04-14.md) |

View File

@@ -0,0 +1,6 @@
# 软件测试 经验记录 - 2026-04-13
## 会议:按功能同步开发文档
- **要点**:以更新后的开发文档与各角色项目索引为真源维护回归与联调清单;契约未入文档可标阻塞。
- **待办**依据各端索引更新融合与主路径用例deploy/health/smoke 与项目管理文档交叉引用。

View File

@@ -0,0 +1,6 @@
# 软件测试 经验记录 - 2026-04-14
## 吸收沉淀:以文档为真源的回归
- **LOOP-20260414**:按「小程序优先逆推」清单编写/裁剪用例;文档与索引未更新的契约项可标 **阻塞—待文档** 并指向纪要问题区。
- 主路径冒烟与 deploy/health/smoke 要求见 `运营与变更.md` 与历史纪要交叉引用。

View File

@@ -10,3 +10,5 @@
| 2026-03-16 | scripts/test/process 流程测试:跨端多接口串联 | [2026-03-16-scripts目录与测试关联.md](./2026-03-16-scripts目录与测试关联.md) |
| 2026-03-16 | pytest 架构、配置从项目读取、运行前显示测试环境 | [2026-03-16-scripts目录与测试关联.md](./2026-03-16-scripts目录与测试关联.md) |
| 2026-03-16 | 测试用例归档规则混合→process、纯端→miniapp/web需求变更时更新 | [2026-03-16-scripts目录与测试关联.md](./2026-03-16-scripts目录与测试关联.md) |
| 2026-04-13 | 按功能同步开发文档:以文档与索引为真源、契约缺失可阻塞 | [2026-04-13.md](./2026-04-13.md) |
| 2026-04-14 | 吸收沉淀LOOP 需求行与逆推清单回归 | [2026-04-14.md](./2026-04-14.md) |

View File

@@ -0,0 +1,108 @@
# 会议纪要 - 2026-04-13 | 按功能同步开发文档
> 本文件由**助理橙子**在会议结束后自动生成。
---
## 基本信息
- **时间**2026-04-13 10:00
- **议题**:各角色依据本人负责的开发功能,同步开发文档(需求汇总、运营与变更、项目索引、临时需求池与接口契约说明)
- **触发方式**:开个会 / 团队会议(文档同步专项)
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员、乘风(主持)、助理橙子(书记)
---
## 各角色发言
### 【产品经理】
需求侧以 `开发文档/1、需求/` 主需求与《以界面定需求》为验收基准。各端每完成一块可交付功能,须在 **需求清单/验收口径** 中对应更新状态;跨端规则(如 VIP、提现、@ 人)变更必须写清业务规则与优先级,避免「代码已上、文档仍旧」。
### 【后端开发】
每新增或变更接口,须在实现合并前同步:`路由组miniprogram/admin/db`、路径、请求/响应关键字段、错误码约定;涉及表结构或迁移的,在 `开发文档/8、部署/` 或临时需求池技术分析中留痕。历史待办(如 router/ossConfig、vip-members 聚合)在文档中标注 **P0/P1** 与依赖方。
### 【管理端开发工程师】
管理端功能以页面/菜单为粒度,在 `开发文档/10、项目管理/运营与变更.md` 或需求汇总中追加「做了什么、调了哪些 `/api/admin/*` `/api/db/*`」;与小程序字段对齐处(列表、详情、配置项)写明字段来源,便于测试写用例。
### 【小程序开发工程师】
C 端以页面与核心流程为粒度同步:涉及 `/api/miniprogram/*` 的变更、scene、支付/登录分支、分享 singlePage 行为,须在开发文档或角色项目索引中可追溯;仅改 UI 也需注明「无接口变更」以便测试裁剪回归范围。
### 【测试人员】
文档同步后,测试以 **文档与索引为真源** 更新回归清单与联调顺序;三端契约变更若文档未更新,测试有权将项标为「阻塞—待文档」并在问题与作答区登记。
---
## 讨论过程
- **【管理端开发工程师】回复【产品经理】**:界面定需求已存在,建议「功能完成」定义包含:代码合并 + 文档/索引一行摘要,避免遗漏。
- **【后端开发】回复【小程序开发工程师】**miniprogram 与 admin 路由隔离不变;文档中写清「仅供某端调用」可避免联调误用。
- **【测试人员】回复【全员】**deploy/health/smoke 与关键路径用例在 `开发文档/10、项目管理` 与测试索引中保持交叉引用,便于发版前自检。
---
## 会议决议
1. **按功能粒度同步**:以「可验收功能点」为最小单位,责任角色在合并前或合并当日更新:对应 `开发文档` 章节、`.cursor/agent/开发助理/项目索引/{角色}.md` 开发进度表一行(**必须含日期**)。
2. **跨端变更双写**:影响两端的字段或接口,除本角色文档外,须在 `agent/团队/evolution/` 或会议纪要中留架构/契约摘要,并在相关角色索引中各记一行。
3. **待确认项进表**:接口路径、错误码、验收口径未定的,一律落入本次会议「问题与作答区」,由责任角色补充作答后闭环。
---
## 待办事项
| 责任角色 | 任务 | 优先级 | 截止建议 |
|---------|------|--------|---------|
| 产品经理 | 核对主需求与《以界面定需求》与各端近期实现差异,更新需求汇总状态 | 高 | 2026-04-20 |
| 后端开发 | 将 router/ossConfig、vip-members 等待办在文档中标注优先级与依赖 | 中 | 2026-04-20 |
| 管理端开发工程师 | soul-admin 近期页面/接口变更写入运营与变更或索引 | 中 | 2026-04-20 |
| 小程序开发工程师 | 阅读/支付/分享等主路径若有未记文档的改动,补索引与说明 | 中 | 2026-04-20 |
| 测试人员 | 依据更新后的文档刷新融合与主路径回归清单 | 中 | 2026-04-20 |
---
## 问题与作答区
> 会议中提出的待确认问题在此列出;作答区域供后续补充答案,便于追溯闭环。
| # | 问题 | 责任角色 | 作答 |
|---|------|---------|------|
| 1 | 各端「最近一次合并到主分支」的功能清单是否与项目索引 2026-04-02 之后实际代码一致? | 各角色负责人 | (待补充) |
| 2 | vip-members 聚合与超级个体/@ 融合一期验收口径是否已在需求文档中单点定稿? | 产品经理 | (待补充) |
| 3 | DistributionPage `Order.description` 类型债是否纳入本迭代文档与修复排期? | 管理端开发工程师 | (待补充) |
---
## 各角色经验与业务理解更新
### 产品经理
- 文档同步与验收基准绑定:功能完成 = 实现 + 文档/索引可追溯。
### 后端开发
- 接口与迁移变更必须标明路由组与优先级,避免管理端/小程序误调。
### 管理端开发工程师
- 以页面为粒度记录 admin/db 依赖,字段与小程序对齐处显式写出。
### 小程序开发工程师
- 无接口变更的纯 UI 迭代也应在索引中标注,便于测试裁剪范围。
### 测试人员
- 以更新后的文档与索引为真源维护回归清单;文档缺失可阻塞验收。
### 团队共享
- 延续 2026-03-24 文档同步原则:实现变更后同步需求、运营与变更、各角色项目索引;跨端契约写入团队 evolution 或会议纪要。
---
*会议纪要由助理橙子生成 | 各角色经验已同步至 `agent/{角色}/evolution/2026-04-13.md`*

View File

@@ -85,3 +85,4 @@ YYYY-MM-DD_会议主题.md
| 2026-03-30 | 文章详情 # 标签跳转 MBTI 小程序传手机号 | 产品、后端、管理端、小程序、测试 | [2026-03-30_文章详情跳转MBTI小程序传手机号.md](2026-03-30_文章详情跳转MBTI小程序传手机号.md) |
| 2026-03-31 | 超级个体列表与 @ 列表融合方案 | 产品、后端、管理端、小程序、测试、团队 | [2026-03-31_超级个体与@列表融合.md](2026-03-31_超级个体与@列表融合.md) |
| 2026-04-02 | 工作进度与需求同步会 | 产品、后端、管理端、小程序、测试、团队 | [2026-04-02_工作进度与需求同步会.md](2026-04-02_工作进度与需求同步会.md) |
| 2026-04-13 | 按功能同步开发文档 | 产品、后端、管理端、小程序、测试、团队 | [2026-04-13_按功能同步开发文档.md](2026-04-13_按功能同步开发文档.md) |

View File

@@ -157,13 +157,13 @@ description: Trigger when 小橙/橙子/讨论完毕/记录一下/同步文档/
## 文档结构速查
```
开发文档/
开发文档/ # 仓库根目录下;若尚未克隆外部大文档,可先维护本骨架与摘要
├── 1、需求/需求汇总.md # 需求清单、业务需求
├── 8、部署/ # 技术方案、部署说明
├── 8、部署/ # 技术方案、部署说明(按需创建)
├── 10、项目管理/
│ ├── 项目落地推进表.md # 里程碑、永平落地
│ ├── 项目落地推进表.md # 里程碑、永平落地(按需创建)
│ └── 运营与变更.md # 近期更新、变更记录
临时需求池/ # 需求分析、技术分析、待办
临时需求池/ # 需求分析、技术分析、待办(按需创建)
.cursor/agent/ # 每角色 evolution 经验池
├── 开发助理/evolution/、项目索引/{小程序,管理端,后端,产品,测试,助理橙子,团队}.md
├── 小程序开发工程师/evolution/

View File

@@ -6,6 +6,19 @@
---
## 2026-04-15
- 吸收经验(联网):编程思维沉淀至 `agent/团队/evolution/2026-04-15.md`;升级 `role-flow-control` §1.3`经验清单`、总索引、团队/助理橙子项目索引、sync-log 已更新
- 业务补齐:`app.request` 失败体挂 `err.response`;导师咨询 `mentor_consultation` 支付全链路;`CKBJoin` investor 假成功改为显式失败;`需求汇总` 更新
## 2026-04-14
- 吸收经验:各智能体沉淀 + 同步开发需求;新建 `开发文档/1、需求/需求汇总.md``开发文档/10、项目管理/运营与变更.md``开发文档/README.md`;各角色 `evolution/2026-04-14.md` 与索引;`经验清单``智能体-技能-经验总索引`、项目索引七处;升级 `role-flow-control` §1.2、`assistant-doc-sync` 文档树说明
## 2026-04-13
- 会议收尾:按功能同步开发文档;纪要 `.cursor/meeting/2026-04-13_按功能同步开发文档.md`;各角色 evolution、项目索引产品/后端/管理端/小程序/测试/团队、meeting/README 已更新
## 2026-04-07
- 文档同步:开发文档索引、主需求 2026-03-20、需求索引、10 项目管理 README 与《闭环与文档同步-2026-04-07》交叉引用项目索引助理橙子/团队追加进度

View File

@@ -1,6 +1,6 @@
---
name: soul-role-workflow
description: Soul 创业派对开发协同流程。小程序开发工程师、管理端开发工程师、后端开发职责与协同。跨端功能开发、新增/优化时使用。Use when 跨端协同, 角色流程, 功能开发协作.
description: Soul 创业派对开发协同流程。小程序/管理端/后端职责、垂直切片与追踪弹、智能体协作提要。跨端功能开发、新增/优化、AI 多角色执行时使用。Use when 跨端协同, 角色流程, 功能开发协作, 智能体编程思维.
---
# Soul 创业派对 - 角色流程控制 Skill
@@ -27,6 +27,30 @@ description: Soul 创业派对开发协同流程。小程序开发工程师、
- 小程序:是否按接口/配置渲染而非硬编码。
- 默认交付口径:**可配置、可运营、可联调、可验收**,否则视为未完成。
### 1.2 从小程序逆推闭环(文档 / 需求同步)
评审或收尾时优先从 **C 端页面** 逆推,避免「只有样式、无接口/无配置」被误判为完成:
1. **用户路径**:入口、前置条件(登录 / VIP / 资料)、失败提示是否可验收。
2. **数据来源**:写死常量、`app.request`、本地缓存;若无后端/配置真源,须在 `开发文档/1、需求/需求汇总.md` 或当日项目索引标注「无接口/待配置」。
3. **路由与契约**:仅调 `/api/miniprogram/*`;跨端字段变更须同步 **后端契约 + 管理端(若需运营配置)+ 需求表一行**
4. **配置化判断**:运营是否可能在线变更、是否涉款/风控/合规;需要运行时灰度/熔断的采用 **Feature Toggle** 思路并规划退役,避免永久 `if(flag)`
5. **回归影响**支付、scene、分享 singlePage、邻页 `onShow`;测试以 **文档与索引为真源**,契约未入库可标阻塞。
详见:`agent/团队/evolution/2026-04-14.md`,需求清单:`开发文档/1、需求/需求汇总.md`
### 1.3 智能体协作:联网沉淀的编程思维(提要)
> 外部资料作**思想库**;执行仍须遵守本仓库 **boundary** 与 **miniprogram / admin / db** 路由隔离。
1. **垂直切片vertical slice**:以「可演示的用户价值」为单位打通 UI→API→持久化/配置,避免长期在单一层级堆半成品(敏捷实践中对 vertical slicing 的共识:更快用事实替代猜测)。
2. **追踪弹tracer bullets《The Pragmatic Programmer》**:先落地**薄而端到端**、可进主分支的骨架路径,用真实反馈校准架构;与「用完即扔」的原型不同,追踪弹是后续扩展的基座。用于约束多智能体/大模型:**小步打通再扩面**,控制一次性大 diff业界亦用该比喻讨论 AI 生成代码的验证节奏,如 aihero.dev 对 tracer bullets 与 AI slop 的论述)。
3. **先验证再堆量verify before build**:上下文与约束写清 → 分块实现 → **测试或最小复现** 再合并;可用 AI 辅助生成边界/对抗用例人做最终把关多篇「AI coding best practices」强调 context-first 与系统化验证)。
4. **无责复盘blameless postmortem**:故障与重大返工后,复盘聚焦**系统为何允许失败**、时间线与可验证改进行动,而非个人追责(参见 Google *Site Reliability Engineering*Postmortem Culture — `https://sre.google/sre-book/postmortem-culture/`)。
5. **简单性**:优先可读、可预测实现;临时开关/实验分支需**退役计划**,避免永久 `if(flag)` 分叉。
团队详述与引用:`agent/团队/evolution/2026-04-15.md`
---
## 2. 协同流程总览(线框图)

View File

@@ -1026,8 +1026,11 @@ App({
},
success: (res) => {
const data = res.data
const rejectWithBody = (message) => {
reject(new Error(message))
/** 业务失败时挂 err.response供页面读取 needBindWechat / errorCode 等(与 miniprogram-dev Skill 一致) */
const rejectWithBody = (message, body) => {
const err = new Error(message)
if (body && typeof body === 'object') err.response = body
reject(err)
}
if (res.statusCode === 200) {
if (data && data.success === false) {
@@ -1036,7 +1039,7 @@ App({
this.logout()
}
showError(msg)
rejectWithBody(msg)
rejectWithBody(msg, data)
return
}
resolve(data)
@@ -1050,7 +1053,7 @@ App({
}
const msg = this._getApiErrorMsg(data, res.statusCode >= 500 ? '服务器异常,请稍后重试' : '请求失败')
showError(msg)
rejectWithBody(msg)
rejectWithBody(msg, data && typeof data === 'object' ? data : undefined)
},
fail: (err) => {
const msg = (err && err.errMsg)
@@ -1090,8 +1093,8 @@ App({
}
const promise = this._requestOnce(url, options, silent).catch((err) => {
const msg = (err && err.message) ? err.message : '网络异常,请重试'
throw new Error(msg)
if (err && err.message) throw err
throw new Error('网络异常,请重试')
})
if (method === 'GET') {

View File

@@ -692,7 +692,11 @@ Page({
wx.showToast({ title: res.error || '加入失败', icon: 'none' })
}
} catch (e) {
wx.showToast({ title: '网络异常,请重试', icon: 'none' })
const resp = e && e.response
wx.showToast({
title: (resp && (resp.message || resp.error)) || (e && e.message) || '网络异常,请重试',
icon: 'none',
})
} finally {
this.setData({ isJoining: false })
}

View File

@@ -3,6 +3,7 @@
* 联系导师按钮 → 弹出 v2 弹窗(选择咨询项目)
*/
const app = getApp()
const soulBridge = require('../../utils/soulBridge')
Page({
data: {
@@ -79,6 +80,11 @@ Page({
this.setData({ selectedType: item.type, selectedAmount: item.price })
},
_consultationTypeLabel(t) {
const m = { single: '单次咨询', half_year: '半年咨询', year: '年度咨询' }
return m[t] || '咨询'
},
async onConfirmConsult() {
const { mentor, selectedType } = this.data
const userId = app.globalData.userInfo?.id
@@ -94,22 +100,57 @@ Page({
method: 'POST',
data: { userId, consultationType: selectedType },
})
if (res?.success && res.data) {
this.setData({ showConsultModal: false, creating: false })
wx.showToast({ title: '预约创建成功', icon: 'success' })
// TODO: 调起支付 productType: mentor_consultation, productId: res.data.id
if (!res?.success || !res.data) {
wx.showToast({ title: res?.error || '创建失败', icon: 'none' })
return
}
this.setData({ showConsultModal: false })
const consult = res.data
const openId = await app.ensurePayOpenId()
if (!openId) {
wx.showModal({
title: '预约成功',
content: '请联系客服完成后续对接',
title: '无法拉起支付',
content: '未获取到微信支付标识,请完全关闭小程序后重新进入,或退出账号重新登录。',
showCancel: false,
})
} else {
wx.showToast({ title: res?.error || '创建失败', icon: 'none' })
return
}
wx.showLoading({ title: '正在拉起支付...', mask: true })
try {
const label = this._consultationTypeLabel(selectedType)
const payRes = await app.request('/api/miniprogram/pay', {
method: 'POST',
data: {
openId,
userId,
productType: 'mentor_consultation',
productId: String(consult.id),
amount: Number(consult.amount),
description: `导师咨询 · ${(mentor && mentor.name) || '导师'}${label}`,
referralCode: soulBridge.getReferralCodeForPay(app) || undefined,
},
})
if (payRes?.success && payRes.data?.payParams) {
try {
await soulBridge.requestWxJsapiPayment(payRes.data.payParams)
await soulBridge.syncOrderStatusQuery(app, payRes.data.orderSn)
wx.showToast({ title: '支付成功', icon: 'success' })
} catch (pe) {
const msg = pe && pe.errMsg ? String(pe.errMsg) : ''
if (msg.indexOf('cancel') !== -1) wx.showToast({ title: '支付取消', icon: 'none' })
else wx.showToast({ title: '支付未完成', icon: 'none' })
}
} else {
wx.showToast({ title: payRes?.error || '获取支付参数失败', icon: 'none' })
}
} finally {
wx.hideLoading()
}
} catch (e) {
wx.showToast({ title: '创建失败', icon: 'none' })
wx.showToast({ title: (e && e.message) || '操作失败', icon: 'none' })
} finally {
this.setData({ creating: false })
}
this.setData({ creating: false })
},
goBack() {

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
"strconv"
"strings"
"time"
"soul-api/internal/database"
@@ -160,7 +161,7 @@ func BalanceConsumePost(c *gin.Context) {
}
db := database.DB()
// 后端价格校验
standardPrice, priceErr := getStandardPrice(db, req.ProductType, req.ProductID)
standardPrice, priceErr := getStandardPrice(db, req.ProductType, req.ProductID, strings.TrimSpace(req.UserID))
if priceErr != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": priceErr.Error()})
return

View File

@@ -512,10 +512,10 @@ func CKBJoin(c *gin.Context) {
}
if body.Type == "investor" && body.UserID != "" {
if !userHasContentPurchase(database.DB(), body.UserID) {
// 交互原则:用户侧友好提示(不暴露存客宝/规则细节);后台可通过规则引导再完善
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "提交成功,我们会尽快联系您",
"success": false,
"error": "请先购买任意章节后再申请资源对接",
"errorCode": "CONTENT_PURCHASE_REQUIRED",
})
return
}

View File

@@ -102,7 +102,7 @@ func GiftPayCreate(c *gin.Context) {
productID = "fullbook"
}
}
unitPrice, priceErr := getStandardPrice(db, req.ProductType, productID)
unitPrice, priceErr := getStandardPrice(db, req.ProductType, productID, strings.TrimSpace(req.UserID))
if priceErr != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": priceErr.Error()})
return
@@ -323,7 +323,7 @@ func GiftPayDetail(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "请先登录"})
return
}
unitPrice, priceErr := getStandardPrice(db, "section", sectionId)
unitPrice, priceErr := getStandardPrice(db, "section", sectionId, callerUserID)
if priceErr != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": priceErr.Error()})
return

View File

@@ -432,6 +432,15 @@ func miniprogramPayPost(c *gin.Context) {
db := database.DB()
// 尽早解析 userId便于 mentor_consultation 等按用户校验预约单与标准价
userIDForPrice := strings.TrimSpace(req.UserID)
if userIDForPrice == "" && strings.TrimSpace(req.OpenID) != "" {
var u model.User
if err := db.Where("open_id = ?", strings.TrimSpace(req.OpenID)).First(&u).Error; err == nil {
userIDForPrice = u.ID
}
}
productID := strings.TrimSpace(req.ProductID)
if req.ProductType == "link_karuo_tip" && strings.TrimSpace(req.TipSource) == "live_mic" && productID != "" && !strings.HasPrefix(productID, "live_mic|") {
productID = "live_mic|" + productID
@@ -460,7 +469,7 @@ func miniprogramPayPost(c *gin.Context) {
if pricePID == "" {
pricePID = strings.TrimSpace(req.ProductID)
}
standardPrice, priceErr := getStandardPrice(db, req.ProductType, pricePID, req.TipSource)
standardPrice, priceErr := getStandardPrice(db, req.ProductType, pricePID, userIDForPrice, req.TipSource)
if priceErr != nil && req.ProductType == "link_karuo_tip" {
if fb, _, canonID, ferr := linkKaruoTipFallbackByAmount(db, pricePID, req.Amount, req.TipSource); ferr == nil {
standardPrice = fb
@@ -537,7 +546,10 @@ func miniprogramPayPost(c *gin.Context) {
}
// userID优先用客户端传入为空时按 openid 查用户(排除软删除,避免订单归属到旧账号)
userID := req.UserID
userID := strings.TrimSpace(req.UserID)
if userID == "" && userIDForPrice != "" {
userID = userIDForPrice
}
if userID == "" && req.OpenID != "" {
var u model.User
if err := db.Where("open_id = ?", req.OpenID).First(&u).Error; err == nil {
@@ -558,6 +570,9 @@ func miniprogramPayPost(c *gin.Context) {
case "link_karuo_tip":
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "打赏缺少礼物标识"})
return
case "mentor_consultation":
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "缺少预约单 IDproductId"})
return
default:
productID = "fullbook"
}
@@ -575,6 +590,8 @@ func miniprogramPayPost(c *gin.Context) {
description = "卡若创业派对VIP年度会员365天"
case "match":
description = "购买匹配次数"
case "mentor_consultation":
description = "导师咨询服务"
case "link_karuo_tip":
giftID := productID
if strings.HasPrefix(giftID, "live_mic|") {
@@ -912,6 +929,13 @@ func MiniprogramPayNotify(c *gin.Context) {
}
} else if attach.ProductType == "link_karuo_tip" {
fmt.Printf("[PayNotify] 打赏/上麦礼遇订单完成: user=%s order=%s\n", beneficiaryUserID, orderSn)
} else if attach.ProductType == "mentor_consultation" && attach.ProductID != "" {
if cid, err := strconv.Atoi(strings.TrimSpace(attach.ProductID)); err == nil && cid > 0 {
_ = db.Model(&model.MentorConsultation{}).
Where("id = ? AND user_id = ?", cid, beneficiaryUserID).
Updates(map[string]interface{}{"status": "paid", "updated_at": time.Now()})
fmt.Printf("[PayNotify] 导师预约已支付: user=%s consultId=%d order=%s\n", beneficiaryUserID, cid, orderSn)
}
}
productID := attach.ProductID
if productID == "" {
@@ -953,6 +977,10 @@ func processReferralCommission(db *gorm.DB, buyerUserID string, amount float64,
fmt.Printf("[PayNotify] 打赏订单跳过分销佣金: orderSn=%s\n", orderSn)
return
}
if order != nil && order.ProductType == "mentor_consultation" {
fmt.Printf("[PayNotify] 导师咨询订单跳过分销佣金: orderSn=%s\n", orderSn)
return
}
type Binding struct {
ID int `gorm:"column:id"`
ReferrerID string `gorm:"column:referrer_id"`
@@ -1326,6 +1354,17 @@ func activateOrderBenefits(db *gorm.DB, order *model.Order, payTime time.Time) {
ConfirmBalanceRechargeByOrder(db, order)
case "link_karuo_tip":
// 首页打赏 / 上麦礼遇:仅收款,无额外会员或章节权益
case "mentor_consultation":
if order.ProductID == nil || strings.TrimSpace(*order.ProductID) == "" {
return
}
cid, err := strconv.Atoi(strings.TrimSpace(*order.ProductID))
if err != nil || cid <= 0 {
return
}
_ = db.Model(&model.MentorConsultation{}).
Where("id = ? AND user_id = ?", cid, userID).
Updates(map[string]interface{}{"status": "paid", "updated_at": payTime})
}
}
@@ -1671,10 +1710,11 @@ func linkKaruoTipPriceTotal(db *gorm.DB, productID string, tipSource string) (fl
}
// getStandardPrice 从 DB 读取商品标准价(后端校验用),防止客户端篡改金额
// productType: fullbook / vip / section / match / link_karuo_tip
// productId: 章节购买时为章节 ID打赏为 giftId|qty 或 live_mic|giftId|qty
// productType: fullbook / vip / section / match / link_karuo_tip / mentor_consultation
// productId: 章节购买时为章节 ID打赏为 giftId|qty 或 live_mic|giftId|qty;导师咨询为 mentor_consultations.id
// buyerUserID: mentor_consultation 时校验预约归属;其他类型可传空字符串
// tipSource 可选live_mic / home_reward 时 link_karuo_tip 计价与置顶人物礼物配置合并
func getStandardPrice(db *gorm.DB, productType, productID string, tipSource ...string) (float64, error) {
func getStandardPrice(db *gorm.DB, productType, productID, buyerUserID string, tipSource ...string) (float64, error) {
productType = normalizePayProductType(productType)
ts := ""
if len(tipSource) > 0 {
@@ -1767,6 +1807,29 @@ func getStandardPrice(db *gorm.DB, productType, productID string, tipSource ...s
}
return *ch.Price, nil
case "mentor_consultation":
if productID == "" {
return 0, fmt.Errorf("导师咨询缺少预约单 ID")
}
cid, err := strconv.Atoi(strings.TrimSpace(productID))
if err != nil || cid <= 0 {
return 0, fmt.Errorf("无效的预约单 ID")
}
var mc model.MentorConsultation
if err := db.Where("id = ?", cid).First(&mc).Error; err != nil {
return 0, fmt.Errorf("预约单不存在")
}
if mc.Status != "" && mc.Status != "created" {
return 0, fmt.Errorf("预约单状态不可支付")
}
if strings.TrimSpace(buyerUserID) != "" && mc.UserID != buyerUserID {
return 0, fmt.Errorf("预约单与当前用户不匹配")
}
if mc.Amount <= 0 {
return 0, fmt.Errorf("预约金额无效")
}
return mc.Amount, nil
default:
return 0, fmt.Errorf("未知商品类型: %s", productType)
}

View File

@@ -21,6 +21,9 @@ func computeOrderCommission(db *gorm.DB, order *model.Order, referrerUser *model
if order.ProductType == "link_karuo_tip" {
return 0
}
if order.ProductType == "mentor_consultation" {
return 0
}
// 读取推广配置
distributorShare := 0.9
userDiscount := 0.0