后端(主 agent 独立复跑验证,非采信子 agent 自报): - 新建 game-module-ad(广告引擎)+ game-module-trade(分账/结算/提现),克隆黄金模板 project - 契约先行已锁:ad.yaml/trade.yaml + Flyway V6/V7;ad 计费 uk_trace 收紧为 (trace_id,event_type,tenant_id) 防 reward 被 impression 静默吞掉 - ad↔trade Feign seam(AdRevenueApi.getUnsettledRevenue/markSettled)+ project-api 归因(getCreatorUserId,game 模块首个跨模块 Feign,仿 yudao DictDataApi) - AdProvider SPI(mock,留 csj/gdt 注入位);资金安全:金额用分/uk 幂等/状态机 CAS/防超扣/T+1 结算补偿 - pay 不建,复用 yudao-pay 后置(Doc B:收单归 pay、钱包提现归 trade;MVP 钱财闭环 ad→trade 不经收单) - 验证:mvn -pl yudao-server -am compile 全量 BUILD SUCCESS;ad 15 + trade 24 = 39 单测绿;huijing 残留=0、裸 select*=0 前端 game-admin(运营后台): - 克隆 yudao-ui-admin-vue3 裁剪(删 crm/erp/mall/mes/iot 等无关业务模块)+ 5 个 MVP 运营页接 admin-api(审核/精选/看板/广告位/提现审核)+ mock 兜底 - 构建验证移至 mini-desktop(本机 5.8G 内存 OOM,见执行 spec) 文档:HJ-PAR-002 review+execution 双 spec + Workflow 编排脚本 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
158 lines
16 KiB
JavaScript
158 lines
16 KiB
JavaScript
export const meta = {
|
||
name: 'admin-wave2-phase1',
|
||
description: 'Wave2 并行建设:ad→trade 后端变现链 ∥ game-admin 运营后台裁剪接线',
|
||
phases: [
|
||
{ title: 'Phase1-并行建设', detail: 'ad广告引擎→trade分账 串行链 ∥ admin运营台 裁剪接线' },
|
||
],
|
||
}
|
||
|
||
// ===========================================================================
|
||
// 公共前缀:所有 agent 必读的事实源与铁律
|
||
// ===========================================================================
|
||
const COMMON = `
|
||
你是造梦AI(wanxiang) 工程师。命名空间一律 wanxiang(cn.wanxiang.game / 包/类/前缀),勿用 huijing;yudao 框架 cn.iocoder.yudao + Maven groupId cn.iocoder.cloud 保持不动。中文注释完整。
|
||
契约是单一事实源(已锁,禁改既有已锁契约):仓根 contracts/(README.md 索引、api-schemas/*.yaml、db-schemas/V*.sql、ad-slot.schema.json#7、events.schema.json#5、sdk-interface.d.ts#3)。
|
||
工程规范见 .agents/skills/add-business-module.md(克隆配方)、.agents/rules/engineering-conventions.md、.agents/rules/security-and-reliability.md。
|
||
铁律:禁裸 select*(必显式列、大表命中索引);金额一律「分」(BIGINT) 禁浮点;资金写入有幂等键 + uk;状态机 tinyint,非法流转 Service 拒绝(DO 层不校验);@Transactional 只加 Service 层且范围小;跨模块只依赖对方 -api 走 Feign,禁依赖对方 -server;不改 yudao framework 层;DataPermission 做数据隔离(创作者只见自己),不自己写 SQL 隔离。
|
||
你的最终输出 = 给主 agent 的结构化汇报(不是给人的客套),含:filesWritten / 关键实现点 / selfVerify(命令+真实结果) / issues / contractGaps / decisions。
|
||
`
|
||
|
||
// ===========================================================================
|
||
// Track 后端①:ad 广告引擎(克隆黄金模板 + AdRevenueApi Feign + ProjectApi 归因)
|
||
// ===========================================================================
|
||
const AD_PROMPT = `${COMMON}
|
||
|
||
# 任务:在 game-cloud 新建 game-module-ad(广告引擎),并为归因给 project-api 加一个 Feign 方法。
|
||
|
||
## 必读(先读后写)
|
||
1. contracts/api-schemas/ad.yaml —— 你的 API 契约(app/admin 端、计费幂等 uk=(trace_id,event_type,tenant_id)、收入口径、x-feign-contracts seam)。
|
||
2. contracts/db-schemas/V6.0.0__create_game_ad.sql —— 你的建表(game_ad_slot 对齐#7 + game_ad_revenue 收入台账)。
|
||
3. contracts/ad-slot.schema.json(#7) —— 广告位字段权威。
|
||
4. .agents/skills/add-business-module.md —— 双模块(-api/-server)克隆配方、分层、单测(BaseMockitoUnitTest 照抄 ProjectServiceImplTest)。
|
||
5. 黄金样板 game-cloud/game-module-project/(照抄结构/分层/pom/注释/错误码/单测)。
|
||
6. yudao 跨模块 Feign 样板:game-cloud/yudao-module-system/.../api/dict/DictDataApi.java(@FeignClient(name=ApiConstants.NAME)+@GetMapping(PREFIX+...)+CommonResult<T>) 与 DictDataApiImpl.java(@RestController @Primary @Validated implements,委托 Service),以及 system 的 enums/ApiConstants.java(NAME/PREFIX)。game 模块尚无 Feign,你来建立此模式。
|
||
|
||
## 产出 A:game-module-ad 模块(cn.wanxiang.game.module.ad)
|
||
- -api:enums/ApiConstants(NAME=\"ad-server\" 或仿 system 风格、PREFIX 仿 system rpc 前缀)、enums/ErrorCodeConstants(错误码段 1-111-***-***,至少:广告位 slotId 重复、广告位不存在、合规拦截/会话超限不计费 等)、api/AdRevenueApi(@FeignClient 接口,按 ad.yaml x-feign-contracts 精确签名:List<AdRevenueRespDTO> getUnsettledRevenue(LocalDate statDate) + boolean markSettled(List<Long> revenueIds);返回 CommonResult 包裹)、dto/AdRevenueRespDTO(id/creatorUserId/revenueAmount/statDate/traceId)。
|
||
- -server:controller/app/AdController(/app-api/ad:slot/list-enabled、report/impression、report/reward) + controller/admin/AdSlotController(/admin-api/ad/slot CRUD+page) + controller/admin/AdRevenueController(/admin-api/ad/revenue/page) + 各 vo;service(AdSlotService + AdRevenueService:计费落台账/合规校验/幂等)、dal/dataobject(AdSlotDO/AdRevenueDO)、dal/mysql(Mapper,显式列查询、命中索引)、convert(MapStruct)、api/AdRevenueApiImpl(@RestController @Primary 实现 AdRevenueApi)。
|
||
- AdProvider SPI:interface AdProvider{计算单次收入 + 校验激励}(mock 实现 MockAdProvider:revenue=ecpmFloor/1000 向下取整,激励直通 rewarded=true);留 csj/gdt 扩展位(不实现)。真实联盟由审核闸门后注入。
|
||
- 计费幂等:game_ad_revenue.uk_trace=(trace_id,event_type,tenant_id),重复上报命中即跳过返回上次结果(firstBilling=false)。收入口径:type=rewarded 收入计在 reward(impression revenue=0);其它类型计在 impression。
|
||
- Flyway:把 contracts/db-schemas/V6.0.0__create_game_ad.sql 复制到 game-module-ad-server/src/main/resources/db/migration/(与契约源 diff-identical,禁改)。
|
||
- 归因:report 时由 gameId 反查 creator_user_id(调你下面给 project 加的 ProjectApi.getCreatorUserId),落 game_ad_revenue.creator_user_id。
|
||
|
||
## 产出 B:给 project-api 加归因 Feign 方法(只有 ad 用,不与他 track 冲突)
|
||
- game-module-project-api:新增 enums/ApiConstants(若无) + api/ProjectApi(@FeignClient) 方法 CommonResult<Long> getCreatorUserId(Long gameId)(按 game_project.id 返回 creator_user_id)。
|
||
- game-module-project-server:新增 api/ProjectApiImpl(@RestController @Primary implements ProjectApi),委托 ProjectService 按 id 查 creator_user_id(显式列、命中主键;不存在抛 project 段错误码或返回 null 由 ad 侧处理)。ProjectService 若无对应方法则加一个最小只读方法。
|
||
- 不改 project 其它逻辑/表/已锁契约。
|
||
|
||
## 单测
|
||
- AdSlotService / AdRevenueService 的 ServiceImplTest 继承 BaseMockitoUnitTest(纯 Mockito,无 DB);mock BaseMapper.insert/selectOne 用 any(XxxDO.class) 消歧(裸 any() 会因重载报错)。覆盖:计费幂等(重复 traceId 不重复计)、合规拦截、收入口径。
|
||
|
||
## selfVerify(必须真跑并附真实输出,不准空报成功)
|
||
0. 先把 \`<module>game-module-ad</module>\` 追加进 game-cloud/pom.xml 的 <modules>(reactor 成员,self-verify 前提;仅追加你自己的模块,勿动/删他人条目)。
|
||
1. \`cd /root/games-development-ai/game-cloud && mvn -q -pl game-module-project/game-module-project-api,game-module-project/game-module-project-server -am install -DskipTests\` —— project 加方法后能编译+install(供 ad/他模块引用)。
|
||
2. \`mvn -q -pl game-module-ad/game-module-ad-server -am test\` —— ad 模块编译 + 单测绿。
|
||
3. **关键:ad 建好后务必 \`mvn -q -pl game-module-ad/game-module-ad-api -am install -DskipTests\` 把 game-module-ad-api 装进本地 .m2,供后续 trade 模块依赖。**
|
||
注意 -am 必带(避免 .m2 陈旧 jar)。把每条命令的真实结尾输出(BUILD SUCCESS/FAILURE、Tests run)放进汇报。
|
||
## 边界:写 game-cloud/game-module-ad/**、game-cloud/game-module-project/**(仅加归因方法 ProjectApi/Impl,勿动 project 其它逻辑)、game-cloud/pom.xml(仅追加 game-module-ad 模块条目);不碰 trade、不碰 admin、不碰 yudao-server/pom.xml(加载到运行服务的依赖接线由主 agent Phase 2 做)。
|
||
`
|
||
|
||
// ===========================================================================
|
||
// Track 后端②:trade 分账/结算/提现(依赖 ad-api,故在 ad 之后串行)
|
||
// ===========================================================================
|
||
const TRADE_PROMPT = `${COMMON}
|
||
|
||
# 任务:在 game-cloud 新建 game-module-trade(分账/结算/提现域)。上游 ad 模块已建好并 install 了 game-module-ad-api。
|
||
|
||
## 必读
|
||
1. contracts/api-schemas/trade.yaml —— 你的 API 契约(账户/收益流水/提现 app端 + 提现审核/营收 admin端;消费 ad 的 AdRevenueApi)。
|
||
2. contracts/db-schemas/V7.0.0__create_game_trade.sql —— 建表(game_trade_account 物化汇总 + game_trade_income uk_source 防重分账 + game_trade_withdraw 状态机)。
|
||
3. contracts/api-schemas/ad.yaml 的 x-feign-contracts —— ad↔trade seam 权威签名(getUnsettledRevenue/markSettled)。
|
||
4. game-cloud/game-module-ad/game-module-ad-api/.../api/AdRevenueApi.java —— ad 已实现的 Feign 接口(你 @FeignClient 依赖它,照 yudao DictDataApi 消费方式注入调用)。
|
||
5. .agents/skills/add-business-module.md + 黄金样板 game-module-project。
|
||
|
||
## 产出:game-module-trade 模块(cn.wanxiang.game.module.trade)
|
||
- -api:enums/ApiConstants、enums/ErrorCodeConstants(1-106-***-***:余额不足、低于提现门槛、提现状态非法流转、账户不存在 等)。(trade 暂不需对外暴露 Feign 给别人,-api 可只放枚举/错误码;如需对外再加。)
|
||
- -server:
|
||
- controller/app/TradeController(/app-api/trade:account/mine、income/page、withdraw/apply、withdraw/page) + controller/admin/TradeAdminController(/admin-api/trade:withdraw/page、withdraw/audit、income/page、report/revenue) + vo。
|
||
- service:AccountService(收益账户:建账户幂等 uk_user、余额原子增减带充足校验防超扣)、IncomeService(分账入账:net=gross×share_rate,uk_source 防重)、WithdrawService(提现:申请校验 amount≥Nacos trade.withdraw-min 且 ≤balance、冻结 balance→frozen;审核状态机 0→1/3、打款 1→2/4,驳回/失败资金原路退回 frozen→balance)。
|
||
- dal/dataobject(AccountDO/IncomeDO/WithdrawDO)、dal/mysql(Mapper 显式列)、convert。
|
||
- job/SettlementJob:T+1 结算(按 ad.yaml settlementFlow):调 AdRevenueApi.getUnsettledRevenue(statDate) → 按 creatorUserId 聚合 gross → ×Nacos trade.creator-share(默认0.80) 算 net → 写 game_trade_income(uk_source 防重,source=1 ad,source_ref=ad_revenue.id) + 累加 account.balance/total_income → 调 AdRevenueApi.markSettled(revenueIds) 回标。先入账后回标,回标失败下轮 job 被 uk_source 拦截重复入账、仅补偿回标,不重复发钱。
|
||
- 配置:trade.creator-share=0.80 / trade.withdraw-min=500(分)走 Nacos(@Value 或 yudao 配置类读取,禁硬编码死值;share_rate 落账定格快照存 income.share_rate)。
|
||
- Flyway:复制 contracts/db-schemas/V7.0.0__create_game_trade.sql 到 game-module-trade-server/src/main/resources/db/migration/(diff-identical,禁改)。
|
||
- pom:game-module-trade-server 依赖 game-module-trade-api + game-module-ad-api(消费 AdRevenueApi)。
|
||
|
||
## 单测(BaseMockitoUnitTest,纯 Mockito)
|
||
- AccountService:余额原子增减、超扣拒绝、建账户幂等。
|
||
- IncomeService:分账 net 计算、uk_source 防重复入账。
|
||
- WithdrawService:提现门槛校验、余额不足拒绝、状态机合法/非法流转、驳回资金退回。
|
||
- SettlementJob:mock AdRevenueApi(getUnsettledRevenue 返回样例 + markSettled)、聚合分账正确、回标调用、重复结算被 uk 拦截不重复发钱。
|
||
- mock BaseMapper 方法用 any(XxxDO.class) 消歧。
|
||
|
||
## selfVerify(真跑附真实输出)
|
||
0. 先把 \`<module>game-module-trade</module>\` 追加进 game-cloud/pom.xml 的 <modules>(仅追加你自己的模块,勿动/删他人条目,含上游 ad 刚加的 game-module-ad 条目要保留)。
|
||
1. \`cd /root/games-development-ai/game-cloud && mvn -q -pl game-module-trade/game-module-trade-server -am test\` —— 编译(含对 game-module-ad-api 的依赖解析)+ 单测绿。-am 必带。
|
||
若报找不到 game-module-ad-api,说明上游未 install,请在汇报里明确指出(不要私自改 ad 模块)。
|
||
## 边界:写 game-cloud/game-module-trade/**、game-cloud/pom.xml(仅追加 game-module-trade 模块条目,保留 ad 条目);不碰 ad(只读其 -api)、不碰 admin、不碰 yudao-server/pom.xml。
|
||
`
|
||
|
||
// ===========================================================================
|
||
// Track 前端:game-admin 运营后台(裁剪克隆来的 yudao admin + 接 admin-api)
|
||
// ===========================================================================
|
||
const ADMIN_PROMPT = `${COMMON}
|
||
|
||
# 任务:把已克隆到 game-admin/ 的完整 yudao-ui-admin-vue3(Vue3.5+Vite8+Element Plus+pnpm)裁剪为造梦AI运营后台,接我方 admin-api,pnpm build 绿。
|
||
|
||
## 背景
|
||
game-admin/ 是上游 yudao-ui-admin-vue3 完整克隆(2236 src 文件,含 ai/bpm/crm/erp/im/iot/mall/mes/mp/pay/report/wms 等大量 MVP 无关业务模块)。保留基建(axios/RBAC/login/layout/router/store/permission/system 账号角色菜单),删无关业务模块,加 MVP 运营页接我方 admin-api。
|
||
|
||
## 必读(我方 admin-api 契约,运营页据此对接)
|
||
- contracts/api-schemas/project.yaml(/admin-api/project/review 审核)
|
||
- contracts/api-schemas/feed.yaml(/admin-api/feed/featured 精选)
|
||
- contracts/api-schemas/telemetry.yaml(/admin-api/telemetry/game-stat 看板数据)
|
||
- contracts/api-schemas/ad.yaml(/admin-api/ad/slot CRUD + /admin-api/ad/revenue/page)
|
||
- contracts/api-schemas/trade.yaml(/admin-api/trade/withdraw/page+audit、income/page、report/revenue)
|
||
- contracts/README.md §三(端与鉴权:admin-api 走 yudao 管理员 Token+RBAC,CommonResult {code,data,msg} code=0 成功)
|
||
|
||
## 步骤
|
||
1. **裁剪**:删 src/views 与 src/api 下 MVP 无关业务模块目录:ai bpm crm erp im iot mall member mes mp pay report wms(保留 Login Home Profile Redirect Error system infra 中的必要项;system 保留 user/role/menu/dept/dict 等 RBAC 基建,infra 可大幅精简或保留 codegen 之外最小项)。同步清理 router(src/router) 与 permission/菜单里对已删模块的静态引用,保证不残留死 import。
|
||
2. **改品牌**:package.json name → game-admin;标题/Logo 文案 yudao→造梦AI 运营后台(仅文案,不改框架)。
|
||
3. **接后端**:src/config/axios 或 .env 把 admin-api baseURL 指向我方后端(http://localhost:48080,端前缀 /admin-api);沿用 yudao 的 Token/RBAC 请求封装与 CommonResult 解包。
|
||
4. **加 5 个 MVP 运营页**(src/views/wanxiang/ 下,配 src/api/wanxiang/ 接口模块,挂进路由+菜单):
|
||
- review/ 项目审核队列(拉 /admin-api/project/review 列表→通过/驳回,对齐 project.yaml ReviewDecision)。
|
||
- featured/ 游戏流精选管理(/admin-api/feed/featured 增删/排序)。
|
||
- dashboard/ 数据看板(/admin-api/telemetry/game-stat/page 表格+关键指标卡)。
|
||
- ad-slot/ 广告位管理(/admin-api/ad/slot CRUD+page,表单字段对齐 ad.yaml AdSlotSaveReqVO;含 provider/type/placement/ecpmFloor/compliance)。
|
||
- withdraw/ 提现审核(/admin-api/trade/withdraw/page 队列→audit 通过/驳回;只读 income/page、report/revenue 营收)。
|
||
用 Element Plus 组件 + 复用 yudao 既有 CRUD/表格/表单封装风格(照抄 system 模块页风格),不引新 UI 库、不复用 game-studio(Vant) 组件。
|
||
5. **mock 兜底**:MVP 后端可能未起,admin 用 yudao 既有 mock 机制或在 api 层做可切换 mock,保证页面可独立 build 且开发期可见;严格贴 admin-api 契约,发现缺口记 contractGaps、不私造契约。
|
||
|
||
## selfVerify(真跑附真实输出,前端铁律:用 build 不用 vue-tsc --noEmit)
|
||
1. \`cd /root/games-development-ai/game-admin && pnpm install\`(或 npm i,若 pnpm 不可用)—— 附结尾输出。
|
||
2. \`pnpm run build\` —— 必须绿(含 vue-tsc 类型检查);附 BUILD 结尾输出与产物 dist 是否生成。若 build 失败,把首个错误贴出并修到绿。
|
||
## 边界:只写 game-admin/**;不碰 game-cloud/contracts。
|
||
`
|
||
|
||
// ===========================================================================
|
||
// 编排:后端链(ad→trade 串行) ∥ admin(并行)
|
||
// ===========================================================================
|
||
phase('Phase1-并行建设')
|
||
log('启动 Phase1:后端 ad→trade 串行链 ∥ game-admin 裁剪接线(3 Opus agent)')
|
||
|
||
const [backendChain, adminRes] = await parallel([
|
||
// 后端链:ad 先建并 install ad-api → trade 依赖 ad-api 后建
|
||
async () => {
|
||
const ad = await agent(AD_PROMPT, { label: '后端①:ad 广告引擎+归因', phase: 'Phase1-并行建设' })
|
||
const trade = await agent(TRADE_PROMPT, { label: '后端②:trade 分账/提现', phase: 'Phase1-并行建设' })
|
||
return { ad, trade }
|
||
},
|
||
// admin 独立仓,与后端链并行
|
||
() => agent(ADMIN_PROMPT, { label: '前端:admin 运营台裁剪接线', phase: 'Phase1-并行建设' }),
|
||
])
|
||
|
||
return {
|
||
ad: backendChain?.ad ?? null,
|
||
trade: backendChain?.trade ?? null,
|
||
admin: adminRes ?? null,
|
||
}
|