18 KiB
交接:票 11(Bruno 真实示例落地)+ Map 产出总结
日期:2026-08-28 晚(交接自中断会话,用户换机续做)。effort 状态机:.scratch/opportunity-e2e/(map.md + issues/)。
本文档供新会话冷启动续做票 11 剩余步骤,并回答用户的「Map 产出总结」问题(§6 素材现成)。
0. 新环境先决检查(第一件事)
d:\code\crm-backend-matt(代码仓)与D:\code\crm-api-docs(独立文档仓,Bruno 集合所在)都存在且可写。- 后端 8080 是否可达(原机器有后台 java 进程,换机后自然没了)。只影响一个可选补采(§3.3),不影响生成 .bru 主体工作。起服须带
CRM_MINIO_AK/SK(见 map.md 环境节)。 - Python + requests 可用(.scratch 脚本依赖)。PowerShell 5.1 无
&&,用;。
1. 当前进度
| 步骤 | 状态 |
|---|---|
| t11-1 盘点 + 读源码 + 采标本 | ✅ specimens.json 30 标本(29 只读 code=0 + board_cards 补采) |
| t11-3 注入商机模块 48 个 .bru | ✅ 完成并验证(参数块值/请求示例/响应示例三类全换真实值) |
| t11-4 生成规则族 25 + 自定义视图 4 新 .bru | ⬅ 从这里开始,完整设计在 §3 |
| t11-5 bruno-sync 口径对账验证 | 待做,做法在 §4 |
| t11-6 销票 + map.md 回写 + research 补记录 | 待做,清单在 §5 |
| t11-7 回答用户 Map 产出总结 | 答案素材在 §6(用户在等这个) |
已验证不再动的:.scratch/opportunity-e2e/inject-examples.py 已修好 mreq 缩进正则并重跑通过
(changed=47 kept=1;22 条「未找到机械推导响应示例段」warning 是幂等正常表现——响应示例早已换成实测摘录,不再匹配旧占位正则)。抽查过 商机模块\商机详情\主体\商机详情.bru 请求示例已是 GET /api/opportunity/detail?id=748556126794022912。
2. 票 11 背景速查(不重复,给路径)
- 票面与验收口:
.scratch/opportunity-e2e/issues/11-bruno-examples.md(验收口=用户在 Bruno 点开任一商机接口照抄即得真实响应) - 机制结论(铁律「结构听源码表述听人」、合并式 sync 手改安全):
.scratch/opportunity-e2e/research-bruno-examples.md - 全局状态:
.scratch/opportunity-e2e/map.md(Decisions 区 64-71 行一带,依赖图票 11 待标 ✅) - skill 全文:
C:\Users\luowj\.qoder\skills\bruno-sync/SKILL.md(.bru 模板/示例生成规则/铁律,写文件时对照;换机后路径可能不同,用 Skill 工具调 bruno-sync 即可加载)
3. t11-4:写 gen-rules-views.py 生成 29 个 .bru(完整设计,照做即可)
脚本落 .scratch/opportunity-e2e/gen-rules-views.py,读 specimens.json 取真实值,写 D:\code\crm-api-docs\商机模块\ 下新目录。
3.1 目录与 folder.bru
商机模块/商机管理/商机规则/folder.bru (seq = 商机模块下现有 folder.bru seq 的 max+10,动态读)
商机模块/商机管理/商机规则/公海规则/folder.bru + 8 个 .bru
商机模块/商机管理/商机规则/阶段模板/folder.bru + 8 个 .bru
商机模块/商机管理/商机规则/方案卡模板/folder.bru + 9 个 .bru
商机模块/销售机会/自定义视图/folder.bru + 4 个 .bru
(目录落点裁决:源码 @Tag 是「商机管理/商机规则」「销售机会/自定义视图」,但现有集合树是 gen_v2_folders.py 的人为规划(顶层「商机模块/」),遵循现有树避免顶层重复文件夹。)
folder.bru 格式(无 type、无 tags,照现有 商机模块/商机管理/folder.bru):
meta {
name: 公海规则
seq: 1
}
子目录内接口文件 seq 从 1 递增。接口 .bru 骨架照现有 商机公海/商机分页.bru 风格:
meta{name,type: http,seq,tags:[generated]} + post{url: {{baseUrl}}路径, body: formUrlEncoded|json, auth: inherit} 或 get{...body: none} + params:query{} / body:form-urlencoded{} / body:json{} + docs{}。
docs 块所有行 2 空格缩进;首行 # 动作语义名、第二行反引号 `METHOD 路径`(对账钥匙勿动);节顺序:说明段 → ## 请求参数 → ## 请求示例 → ## 响应 data 结构 → ## 响应示例。
3.2 文件清单与真实值(29 个)
真实值来源:specimens.json 键 pool_page/stage_page/scheme_page/pool_detail/scheme_detail/field_defs/pool_versions/stage_detail/view_list。
关键 id:POOL_RULE=748507245062389760、SCHEME_TPL=748508098259320832、stage 种子 id 从 specimens['stage_detail']['params']['id'] 现取。seed viewId 从 specimens['view_list']['resp']['data'] 里 name 含「测试视图」的条目现取。
公海规则 /api/rule/opp-pool-rule(8)
| # | 文件名 | 钥匙 | 参数块值 | 响应示例 |
|---|---|---|---|---|
| 1 | 公海规则分页 | POST /page | form current=1&size=10(照 specimens.pool_page.form 回填) |
slim(pool_page) |
| 2 | 公海规则详情 | GET /detail | query id=748507245062389760 |
pool_detail 完整 data |
| 3 | 保存公海规则草稿 | POST /save-draft | form(见下「写构造」) | {"code":0,...,"data":null} |
| 4 | 发布公海规则 | POST /publish | 同 3 + id=1 ⚠警告 |
data:null |
| 5 | 复制公海规则 | POST /copy | form id=748507245062389760(照抄=新建草稿副本,无害) |
data:"1"(机械) |
| 6 | 停用公海规则 | POST /disable | form id=1(说明:仅发布中可停用,须替换) |
data:null |
| 7 | 删除公海规则 | POST /delete | form id=1(说明:仅草稿可删) |
data:null |
| 8 | 公海规则版本列表 | GET /versions | query id=748507245062389760 |
slim(pool_versions) |
3 的写构造(e2e-rules.py 实测通过口径):ruleName=e2e-演示-公海规则&applyScope=1&isDefault=0&allowManualPool=1&autoRecycleEnabled=1&recycleDays=30&allowFreeClaim=1&recycleRemindEnabled=1&remindDays=7&ruleDesc=票11演示。
阶段模板 /api/rule/opp-stage-template(8,与公海规则对称):分页/详情/保存草稿/发布/复制/停用/删除/版本列表。差异点:
- 详情与复制/版本的 id 用 stage 种子 id(specimens 现取)。
- 保存草稿 form(nodes 索引式绑定是 e2e R01 实测通过的关键知识):
templateName=e2e-演示-阶段模板&applyScope=1&isDefault=0&templateDesc=票11演示&nodes[0].stageDictCode=OPP_STAGE_01&nodes[0].workGoal=需求确认&nodes[1].stageDictCode=OPP_STAGE_02&nodes[1].customNodeName=方案深化 - 发布 = 同 form +
id=1+ 警告「发布将顶替同编码发布中版本,严禁对种子 OPP_STAGE_TPL_01 直接执行;id 须替换为 save-draft 产出的草稿 id」。
方案卡模板 /api/rule/opp-scheme-template(9):比阶段模板多一个「系统字段库列表 GET /field-defs」(无参,响应=slim(field_defs))。差异点:
- 保存草稿 form 的 fields 索引式,fieldKey 必须取 field_defs 标本实测值(非自由造):
templateName=e2e-演示-方案卡模板&applyScope=1&isDefault=0&templateDesc=票11演示&fields[0].fieldKey=<data[0].fieldKey>&fields[0].isVisible=1&fields[0].isRequired=1&fields[1].fieldKey=<data[1].fieldKey>&fields[1].isVisible=1&fields[1].isRequired=0 - 详情/复制/版本 id=
748508098259320832;发布同警告(种子=OPP_SCHEME_TPL_04)。
自定义视图 /api/preference/view(4)
| # | 文件名 | 钥匙 | 参数块 | 响应示例 |
|---|---|---|---|---|
| 1 | 自定义视图列表 | GET /list | query scopeKey=opportunity |
slim(view_list) |
| 2 | 保存自定义视图 | POST /save | query scopeKey=opportunity + body:json(集合首个 json body) |
data=seed 真实 viewId(19 位雪花串) |
| 3 | 删除自定义视图 | POST /delete | form scopeKey=opportunity&viewId=1 ⚠说明「替换为本人视图 id(view/list 查),勿对他人/种子视图执行」 |
data:null |
| 4 | 设为默认视图 | POST /set-default | form 同 3 ⚠同警告 | data:null |
save 的 JSON body(seed-opportunity.py 实测通过构造,viewId 不传=新建):
{"name": "e2e-B-测试视图-我的推进",
"conditions": [{"field": "opportunityName", "operator": "like", "value": "e2e-"},
{"field": "oppStatus", "operator": "eq", "value": "2"}],
"sortField": "createTime", "sortDirection": "desc", "isDefault": false, "seqNo": 99}
请求示例里 JSON 部分包 ```json 代码块(SKILL 规则,否则 Markdown 渲染吞缩进)。
3.3 可选补采(仅当 8080 可达)
stage/scheme 的 versions 无标本。可写 10 行脚本(debug token 照 collect-specimens.py 开头:GET /api/auth/debug/token?userId=739564171091247104 取 admin token):
GET /api/rule/opp-stage-template/versions?id=<stage种子id>、GET /api/rule/opp-scheme-template/versions?id=748508098259320832,追加进 specimens.json(键 stage_versions/scheme_versions)。
8080 不可达则降级:versions 响应示例按 SKILL「示例生成」规则从结构表机械推导(数组 1 条元素),不加「实测」注释行。
3.4 docs 结构表内容来源(源码已全部读过,字段如下)
- 请求参数表:page = BaseParam(current 默认1/size 默认10/keyword/orderBy/asc 默认false)+ applyScope/status(各 PageParam @Schema 原文);detail/copy/disable/delete/versions = 单参数 id。
- pool save-draft/publish 入参(OpportunityPoolRuleDTO 表单绑定):id(编辑时)/ruleName*/applyScope(1所有部门通用 2对应部门专用)/isDefault/allowManualPool/autoRecycleEnabled/recycleDays/allowFreeClaim/recycleRemindEnabled/remindDays/ruleDesc/deptIds(逗号分隔,applyScope=2 必填至少一个);ruleCode/versionNo/status/deptNames 标「系统生成只读,入参忽略」。
- stage:id/templateName*/applyScope(1所有商机 2指定部门)/isDefault/templateDesc/deptIds/nodes[N].stageDictCode*(索引式 N 从 0 递增)/nodes[N].customNodeName/nodes[N].workGoal;说明注明末位固定节点 OPP_STAGE_05 系统保证、入参不可伪造(发了 64000 类校验拒)。
- scheme:id/templateName*/applyScope/isDefault/templateDesc/deptIds/fields[N].fieldKey*/fields[N].isVisible/fields[N].isRequired;说明注明 fieldName/fieldType 入参忽略取系统字段快照、关显示清必填。
- view/save:query scopeKey + JSON 字段表 viewId(空=新建非空=覆盖编辑)/name*/conditions[].field,operator,value/sortField/sortDirection/isDefault/seqNo。
响应 data 结构表(从源码 DTO/实体,逐字段一行):
- pool DTO = id/createTime/updateTime(BaseDTO) + ruleCode/ruleName/versionNo/status(1草稿2发布中3已停用)/applyScope/isDefault/allowManualPool/autoRecycleEnabled/recycleDays/allowFreeClaim/recycleRemindEnabled/remindDays/ruleDesc/deptIds[]/deptNames[]
- stage DTO 另加 nodes[](NodeItem:id/seqNo/stageDictCode/customNodeName/workGoal/isFixed)
- scheme DTO 另加 fields[](FieldItem:id/seqNo/fieldKey/fieldName/fieldType/isVisible/isRequired)
- field-defs = FieldDefDTO:id/createTime/updateTime/fieldKey/fieldName/fieldType(RELATED_OBJECT/SINGLE_SELECT/AUTOFILL/YES_NO/ATTACHMENT/AMOUNT/TEXT_SINGLE/TEXT_MULTI/DATE)/optionSource/refTarget/autofillSource/defaultValue/isDeletable
- versions = 实体直出(pool 12 业务列;stage/scheme 各 7 业务列 templateCode/templateName/versionNo/status/applyScope/isDefault/desc + BaseEntity 3 列 id/createTime/updateTime;无 deptIds/nodes/fields 子表)
- view/list = SavedView:viewId/name/conditions[]/sortField/sortDirection/isDefault/seqNo;conditions[]{field/operator/value};出参不回显 scopeKey(票 07 契约事实)
- 写操作 data=null(copy 返回 Long→"1"、view/save 返回 viewId 字符串)
- 分页表加 PageResult 外壳(content/total/size/current/pages/empty,类型照现有
商机公海/商机分页.bru64-87 行现成模板)
响应示例注释行:有标本的写 // 实测响应摘录(20260828 · 用户X · e2e 种子库;数组字段只示第 1 条)(X=view_list 用 B、其余 admin);机械推导的写 // 示例数据,字段结构以上表为准,非真实返回。
3.5 写文件纪律
- UTF-8 无 BOM、
\n换行(open(..., 'w', encoding='utf-8', newline='\n'));生成后可跑 BOM 扫描(AGENTS.md 有现成 PowerShell 片段) - 幂等:目标文件已存在则跳过(防重复生成)
- 完成后跑 inspect-bru.py(root 改成 docs 根)盘点钥匙,应 77 个接口文件全列出
4. t11-5:bruno-sync 口径对账验证
写 .scratch/opportunity-e2e/verify_sync.py:
- 源码侧:正则扫 crm-opportunity 8 控制器 + crm-rule 3 控制器(
OpportunityPoolRuleController/OpportunityStageTemplateController/OpportunitySchemeCardTemplateController)+ crm-preferenceSavedViewController的@(Get|Post)Mapping,拼类级 @RequestMapping 得全量钥匙集。 - 文件侧:遍历
D:\code\crm-api-docs全部 .bru(排除 folder.bru/collection.bru/environments),有tags:[generated]者从 docs 首行反引号提钥匙。 - 报告三向差集:源码有文件无 / 文件有源码无 / 两侧都有计数。预期:商机模块 48 + 新增 29 = 77 全命中、双零差集。
- 结论表述:sync 若重跑,结构已镜像源码 → 全部「不动」;实参值与示例在 docs 块属表述(铁律 1)→ 不会丢。票面「跑一次 /bruno-sync 验证示例不丢」以此对账 + 抽查 2-3 个文件结构达成(skill 的执行者就是 agent 本身,无可独立执行的脚本)。
5. t11-6:销票收尾清单
issues/11-bruno-examples.md:Status: open → resolved,写 Answer:48 注入 + 29 新建 + 对账结论 + 新契约事实:- board 两端点(stage-summary/cards)源码无 viewType 参数(
OpportunityCollabController实锤:stage-summary 只收 stageTemplateId、cards 只收 stageId/offset/limit)——e2e 发的 viewType 被 Spring 静默忽略 = D-20「公海看板未过滤」根因;.bru 参数表本来就对。 - scopeKey 实测值=
opportunity(seed/demo/e2e 全用此值);注意OpportunityViewQueryImpl内部常量SAVED_VIEW_SCOPE="opportunity.sales"与前端写入 scope 不一致——列表页 savedViewId 叠加可能读不到已保存视图,值得在 Answer 里挂一句「疑似新缺陷候选,未实测」。 - nodes/fields 索引式表单绑定、deptIds 逗号分隔、publish 顶替语义、viewId upsert、
Result<Void>data=null 非失败。
- board 两端点(stage-summary/cards)源码无 viewType 参数(
map.md:依赖图票 11 标 ✅;Decisions 区按 64-71 行格式追加一行(产出=77 接口真实示例 + 29 新端点入集合)。research-bruno-examples.md:追加执行记录段(collect/inject/gen/verify 四脚本 + 结果数字)。- 向用户交付 §6 总结(即 t11-7)。
6. t11-7:Map 产出总结(用户在等,答案素材现成)
用户已知 3 件:demo html、bug 汇总、接口文档。完整清单(前 3 + 补充 8):
用户已知
demo/index.html(969 行单文件 + 8 张自测截图)——浏览器验收自测e2e-report.md(132 行六章节,150 用例 ✅125⚠17❌9,缺陷 D-01..D-22 分级清单)——bug 汇总D:/code/crm-api-docsBruno 集合——接口文档(本票后:商机模块 48 接口全真实示例 + 规则族 25/自定义视图 4 新入集合)
补充产出
4. spec-flows.md v2——F01-F15 核心域 + R01-R03 规则族流程规格冻结(199 行,含 U01-U08 拍板记录),后续修缺陷/回归的对账基线
5. env-inventory.md——环境盘点:账号矩阵(admin+A/B/C 跨部门)、部门树、字典 22 组、存量数据与规则缺口
6. seed-opportunity.py + seed-manifest.json/seed-data-manifest.md——幂等种子库(12 商机跨 3 部门 + 跟进/勘察/方案卡/关注/自定义视图 + 2 条发布中规则),重跑 5 次验证,任何环境一条命令复现全套测试数据
7. e2e-core.py(894 行)+ e2e-rules.py(534 行)——150 用例可重跑 E2E 套件(缺陷修复后直接回归)
8. research-bruno-examples.md——bruno-sync 机制调研结论(合并式 sync 手改安全,票 11 的执行依据)
9. boot-verify.md——起服指引与环境事实三连(MinIO 凭据、PS5.1 中文 mojibake、一次性 401 重试)
10. specimens.json + 采集/注入/生成脚本——30 接口实测标本库,本次注入与未来文档再生的真实数据源
11. 散装新契约事实(已写入各票 Answer):U01 新建即推进中、board 无 viewType=D-20 根因实锤、savedView upsert、surveySeq 必填(调用方传)、valuesJson 只认绑定模板显示字段(66007)等
一句话版本:「除了你说的三件,还有:冻结的流程规格、环境盘点、幂等种子库、可重跑的 150 用例 E2E 套件、sync 机制结论、起服指引,以及 30 个接口的实测标本库——『种子→E2E→报告→回归』的闭环整套都是可复用资产。」
7. Suggested skills
bruno-sync:t11-4 写文件与 t11-5 对账时对照 SKILL.md 铁律与模板(用 Skill 工具调用加载)wayfinder:一般不必调;map.md + issues/ 既有格式直接模仿即可
8. 关键路径速查
| 什么 | 哪里 |
|---|---|
| 标本库 | .scratch/opportunity-e2e/specimens.json |
| 注入脚本(已完成勿动) | .scratch/opportunity-e2e/inject-examples.py |
| 采集脚本(补采参考) | .scratch/opportunity-e2e/collect-specimens.py |
| 写操作实测构造 | .scratch/opportunity-e2e/e2e-rules.py(R01-R03)、e2e-core.py f15() |
| .bru 风格基准 | D:\code\crm-api-docs\商机模块\商机公海\商机分页.bru(form 类)、商机详情\主体\商机详情.bru(GET 类) |
| 源码(结构表依据) | crm-rule/.../controller/Opportunity*Controller.java + `domain/dto |
| 钥匙盘点工具 | .scratch/opportunity-e2e/inspect-bru.py(root 改成 docs 根即可复用) |