docs(p1r): 补齐 Market 真实 API 规格计划
This commit is contained in:
parent
1f0b18534c
commit
f02defd367
221
docs/memorys/2026-06-03-P1R6Market规格计划.md
Normal file
221
docs/memorys/2026-06-03-P1R6Market规格计划.md
Normal file
@ -0,0 +1,221 @@
|
||||
# P1R6 Market 规格计划
|
||||
|
||||
日期:2026-06-03
|
||||
|
||||
## 背景
|
||||
|
||||
本次进入 P1R-6 Market Real API 的规格、计划和 review gate 阶段,只完成事实盘点、规格、执行计划、review 修订和阶段留痕,不进入代码实现。
|
||||
|
||||
真实工作面:
|
||||
|
||||
```text
|
||||
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
|
||||
```
|
||||
|
||||
分支:
|
||||
|
||||
```text
|
||||
dev/1.0.0
|
||||
```
|
||||
|
||||
开始前已执行:
|
||||
|
||||
```bash
|
||||
git status --short --branch
|
||||
git log --oneline -5
|
||||
git pull --ff-only origin dev/1.0.0
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
```text
|
||||
## dev/1.0.0...origin/dev/1.0.0
|
||||
48c750b test(p1r): 补齐 AI 与 Knowledge 外部端到端验收
|
||||
Already up to date.
|
||||
```
|
||||
|
||||
## 已验证事实
|
||||
|
||||
当前 coverage summary:
|
||||
|
||||
```text
|
||||
completedOperations 100
|
||||
needsVerificationOperations 100
|
||||
incompleteOperations 33
|
||||
genericPersistenceOperations 32
|
||||
ssePlaceholderOperations 1
|
||||
```
|
||||
|
||||
当前按域状态:
|
||||
|
||||
```text
|
||||
account 33 dedicated / needs_verification
|
||||
ai 41 dedicated / completed
|
||||
content 51 dedicated / needs_verification
|
||||
events 1 sse_placeholder / incomplete
|
||||
knowledge 59 dedicated / completed
|
||||
market 32 generic_persistence / incomplete
|
||||
meta 16 dedicated / needs_verification
|
||||
```
|
||||
|
||||
Market 32 个 operation 当前全部为:
|
||||
|
||||
```text
|
||||
generic_persistence / incomplete
|
||||
```
|
||||
|
||||
当前 Market 实现事实:
|
||||
|
||||
- `docs/api-contracts/market/openapi.yaml` 声明 32 个 Market operation。
|
||||
- `muse-module-market-server` 当前合同入口仍是 `AdminMuseMarketContractController` 和 `AppMuseMarketContractController`。
|
||||
- 当前 Market 合同入口统一委托 `MuseContractPersistenceService`,不能作为真实 API 完成证据。
|
||||
- `muse-module-market-server` 当前只依赖 `muse-module-market-api`、security、mybatis。
|
||||
- `muse-server` 当前同时装配 `muse-module-market-server` 和 `muse-module-member-server`。
|
||||
- `muse-module-member-server` 已有 `MarketAccountProjectionFacade`、默认 fail-closed `UnavailableMarketAccountProjectionFacade`、`muse_account_record_projection` DO/Mapper 和 V11 DDL。
|
||||
|
||||
当前 DDL 事实:
|
||||
|
||||
- V6 已有 Market 初始资产、版本、安装、发布申请、申诉和 handoff 表。
|
||||
- V8 已有 workflow task、favorite、purchase 表。
|
||||
- V11 已有 Account 查询读模型 `muse_account_record_projection`。
|
||||
- P1R-5 已使用 V14;P1R-6 如新增迁移,推荐使用 `V15__extend_market_real_api_schema.sql`。
|
||||
|
||||
## 本阶段产物
|
||||
|
||||
- 规格:`docs/superpowers/specs/2026-06-03-P1R-6-market-real-api-design.md`
|
||||
- 计划:`docs/superpowers/plans/2026-06-03-P1R-6-market-real-api.md`
|
||||
- 留痕:`docs/memorys/2026-06-03-P1R6Market规格计划.md`
|
||||
|
||||
## Review 结果
|
||||
|
||||
本阶段按要求执行 fresh review gate。
|
||||
|
||||
Spec compliance review:
|
||||
|
||||
```text
|
||||
PASS_WITH_WARNINGS
|
||||
```
|
||||
|
||||
已修复首轮阻塞点:
|
||||
|
||||
- 计划开头错误写成只允许执行 `Task 1-12`,但正文实际包含 Task 13。已修为 `Task 1-13`。
|
||||
|
||||
Spec review 非阻塞提醒:
|
||||
|
||||
- handoff token 业务状态里的 `completed` 不能和 coverage `completionStatus=completed` 混淆。计划已补充消歧说明。
|
||||
|
||||
Quality / feasibility review:
|
||||
|
||||
```text
|
||||
PASS_WITH_WARNINGS
|
||||
```
|
||||
|
||||
已修复阻塞点:
|
||||
|
||||
- Task 5 不再要求 Market 模块另建同名 `MarketAccountProjectionFacade` / `UnavailableMarketAccountProjectionFacade`。
|
||||
- 已明确 P1R-6 Account 投影采用最小可执行接线方案:`muse-module-market-server` 显式依赖 `muse-module-member-server`,复用 member 侧既有 `MarketAccountProjectionFacade`、`AccountRecordProjectionDO`、`AccountRecordProjectionMapper`。
|
||||
- 已明确 `muse_market_account_projection` 只表达 Market 侧 projection sync / outbox 状态,不是 Account 查询读模型。
|
||||
- 已明确 Account 查询读模型只能是 V11 已有 `muse_account_record_projection`。
|
||||
- 已要求实现阶段用 Maven reactor 或 dependency-tree 验证不形成 Maven 循环,并用 Spring context 测试证明真实 provider 替换默认 unavailable bean。
|
||||
|
||||
Quality review 非阻塞提醒:
|
||||
|
||||
- 当前 worktree 仍有 P1R-4 / P1R-5 coverage/test/script 未提交 diff,P1R-6 spec/plan/memory 也是未跟踪文件。进入 P1R-6 实现前必须先提交或明确保留这些 diff,避免阶段混账。
|
||||
|
||||
## 关键设计结论
|
||||
|
||||
- P1R-6 目标状态只能是 `dedicated / needs_verification`,不能写成 `completed`。
|
||||
- Market owner 是 `muse-module-market`,负责市场来源侧事实、授权、安装、handoff、发布、治理和申诉。
|
||||
- Market 不直接写 AI / Knowledge / Content canonical facts。
|
||||
- 购买只产生授权,不等于安装;安装只进入账户可用列表,不等于绑定目标 owner。
|
||||
- Account 只消费 Market 写入的投影;Account 查询读模型为 `muse_account_record_projection`。
|
||||
- `needs_recheck` 不能作为 Market `SourceStatus` 值,只能表达为 action policy / recheck reasons。
|
||||
- P1R-7 统一 Events SSE 不属于 P1R-6。
|
||||
- 不修改 `docs/api-contracts/market/openapi.yaml`,不修改 scanner 掩盖缺口。
|
||||
|
||||
## 验证命令与结果
|
||||
|
||||
coverage audit:
|
||||
|
||||
```bash
|
||||
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
```text
|
||||
Generated docs/superpowers/reports/p1r-api-coverage.json
|
||||
Generated docs/superpowers/reports/p1r-api-coverage.md
|
||||
```
|
||||
|
||||
coverage 对账:
|
||||
|
||||
```bash
|
||||
jq -r '.summary | [.completedOperations,.needsVerificationOperations,.incompleteOperations,.genericPersistenceOperations,.ssePlaceholderOperations] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
|
||||
jq -r '.operations[] | select(.domain == "market") | [.implementationStatus,.completionStatus] | @tsv' docs/superpowers/reports/p1r-api-coverage.json | sort | uniq -c
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
```text
|
||||
100 100 33 32 1
|
||||
32 generic_persistence incomplete
|
||||
```
|
||||
|
||||
文档结构检查:
|
||||
|
||||
```bash
|
||||
python3 - <<'PY'
|
||||
import re, pathlib
|
||||
plan=pathlib.Path('docs/superpowers/plans/2026-06-03-P1R-6-market-real-api.md').read_text()
|
||||
spec=pathlib.Path('docs/superpowers/specs/2026-06-03-P1R-6-market-real-api-design.md').read_text()
|
||||
print('plan_tasks', re.findall(r'^## Task (\d+):', plan, re.M))
|
||||
print('spec_operation_rows', len(re.findall(r'^\| `[^`]+` \| (GET|POST|DELETE|PUT|PATCH) \| `/', spec, re.M)))
|
||||
print('plan_operation_lines', len(re.findall(r'^[A-Za-z].+ (GET|POST|DELETE|PUT|PATCH) /', plan, re.M)))
|
||||
PY
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
```text
|
||||
plan_tasks ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13']
|
||||
spec_operation_rows 32
|
||||
plan_operation_lines 32
|
||||
```
|
||||
|
||||
diff hygiene:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
```
|
||||
|
||||
结果:无输出。
|
||||
|
||||
OpenAPI diff 检查:
|
||||
|
||||
```bash
|
||||
git status --short -- docs/api-contracts/market/openapi.yaml docs/api-contracts/ai/openapi.yaml docs/api-contracts/knowledge/openapi.yaml
|
||||
```
|
||||
|
||||
结果:无输出。
|
||||
|
||||
## 当前阶段边界
|
||||
|
||||
本阶段只完成 P1R-6 规格、计划、review 修订和 memory 留痕,没有实现代码。
|
||||
|
||||
当前不应把任何 Market operation 标为 `completed`。
|
||||
|
||||
## 下一步
|
||||
|
||||
进入 P1R-6 实现前必须先处理工作面:
|
||||
|
||||
1. 提交或明确保留 P1R-4 / P1R-5 coverage completed 推进 diff。
|
||||
2. 提交或明确保留 P1R-6 spec / plan / memory 文档 diff。
|
||||
3. 再按 `docs/superpowers/plans/2026-06-03-P1R-6-market-real-api.md` Task 1-13 执行。
|
||||
|
||||
实现阶段执行规则:
|
||||
|
||||
- 同一实现 Task 内复用最近 implementer。
|
||||
- 新 Task 才 fresh implementer。
|
||||
- 每个 Task 完成后仍必须 fresh spec review 和 fresh quality / feasibility review。
|
||||
- review 结论不能替代真实运行态验收或 coverage `completed` 批准。
|
||||
534
docs/superpowers/plans/2026-06-03-P1R-6-market-real-api.md
Normal file
534
docs/superpowers/plans/2026-06-03-P1R-6-market-real-api.md
Normal file
@ -0,0 +1,534 @@
|
||||
# P1R-6 Market Real API Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` to implement this plan task-by-task. `superpowers:executing-plans` is acceptable only when subagents are unavailable. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 将 Market 32 个 operation 从 `generic_persistence / incomplete` 推进到专用 Market Controller / Service / DTO / DAL / DDL / 测试可验收的 `dedicated / needs_verification`。
|
||||
|
||||
**Architecture:** 以 `muse-module-market` 为 owner,新增 Market 合同专用 app/admin 入口和应用服务。Market 只持有来源侧市场事实、授权摘要、安装、handoff、发布审核和治理状态;AI / Knowledge / Content 目标 owner 事实必须通过各自 owner 完成,Market 不直接写入。Account 只消费 Market 写入 `muse_account_record_projection` 的投影,并通过 member 模块既有 `MarketAccountProjectionFacade` 判断投影是否可用,不成为 Market 的运行时代码 owner。
|
||||
|
||||
**Tech Stack:** Java 21、Spring Boot、Yudao `CommonResult<T>`、Spring Security `@PreAuthorize`、MyBatis Plus、PostgreSQL/Flyway、JUnit 5、Mockito/MockMvc、P1R coverage JSON。
|
||||
|
||||
**Implementation Status:** 本文件是 P1R-6 规格计划阶段产物;review gate 待执行;当前不进入实现代码。收到“进入 P1R-6 实现阶段”后才允许按 Task 1-13 执行。
|
||||
|
||||
---
|
||||
|
||||
## 0. 执行边界
|
||||
|
||||
- 工作目录:`/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0`
|
||||
- 分支:`dev/1.0.0`
|
||||
- 不在 `/Users/qingse/Sync/local-git/oh-my-muse` 的其他 checkout 上写阶段文档或实现代码。
|
||||
- 不修改 `docs/api-contracts/market/openapi.yaml`。
|
||||
- 不修改 `docs/api-contracts/ai/openapi.yaml`、`docs/api-contracts/knowledge/openapi.yaml`。
|
||||
- 不修改 `muse-cloud/scripts/**` 把 Market 伪装成 `completed`。
|
||||
- 不破坏 AI 41、Knowledge 59 当前 `dedicated / completed`。
|
||||
- 不破坏 Content 51、Meta 16、Account 33 当前 `dedicated / needs_verification`。
|
||||
- 不把 Market operation 标为 `completed`。
|
||||
- 不跨入 P1R-7 统一 `/app-api/muse/events`。
|
||||
- 如果新增或修改 DDL,阶段收口前必须在同一 PostgreSQL 实例的 `_test` 数据库跑真实 Flyway。
|
||||
|
||||
## 1. 当前事实盘点
|
||||
|
||||
Market operation 清单:
|
||||
|
||||
```text
|
||||
listMarketplaceAssets GET /app-api/muse/marketplace/assets
|
||||
listMarketplaceCategories GET /app-api/muse/marketplace/categories
|
||||
listMarketplaceRecommendations GET /app-api/muse/marketplace/recommendations
|
||||
getMarketplaceAsset GET /app-api/muse/marketplace/assets/{assetId}
|
||||
favoriteAsset POST /app-api/muse/marketplace/assets/{assetId}/favorite
|
||||
unfavoriteAsset DELETE /app-api/muse/marketplace/assets/{assetId}/favorite
|
||||
purchaseAsset POST /app-api/muse/marketplace/assets/{assetId}/purchase
|
||||
installMarketplaceAsset POST /app-api/muse/marketplace/assets/{assetId}/install
|
||||
createBindPrecheck POST /app-api/muse/marketplace/assets/{assetId}/bind-precheck
|
||||
createMarketplaceHandoff POST /app-api/muse/marketplace/handoffs
|
||||
getHandoffStatus GET /app-api/muse/marketplace/handoffs/{handoffToken}
|
||||
cancelHandoff POST /app-api/muse/marketplace/handoffs/{handoffToken}/cancel
|
||||
savePublishDraft POST /app-api/muse/marketplace/publish-drafts
|
||||
runPublishCheck POST /app-api/muse/marketplace/publish-drafts/{draftId}/checks
|
||||
submitPublishRequest POST /app-api/muse/marketplace/publish-requests
|
||||
withdrawPublishRequest POST /app-api/muse/marketplace/publish-requests/{requestId}/withdraw
|
||||
listMyPublishRecords GET /app-api/muse/marketplace/my-publish-records
|
||||
getGovernanceImpact GET /app-api/muse/marketplace/assets/{assetId}/governance-impact
|
||||
submitAppeal POST /app-api/muse/marketplace/appeals
|
||||
supplementAppeal POST /app-api/muse/marketplace/appeals/{appealId}/supplements
|
||||
withdrawAppeal POST /app-api/muse/marketplace/appeals/{appealId}/withdraw
|
||||
adminListMarketAssets GET /admin-api/muse/market/assets
|
||||
adminGetMarketAsset GET /admin-api/muse/market/assets/{assetId}
|
||||
adminPreviewGovernanceImpact POST /admin-api/muse/market/assets/{assetId}/governance-impact
|
||||
adminDelistAsset POST /admin-api/muse/market/assets/{assetId}/delist
|
||||
adminRecallAsset POST /admin-api/muse/market/assets/{assetId}/recall
|
||||
adminListPublishRequests GET /admin-api/muse/market/publish-requests
|
||||
adminApprovePublishRequest POST /admin-api/muse/market/publish-requests/{requestId}/approve
|
||||
adminRejectPublishRequest POST /admin-api/muse/market/publish-requests/{requestId}/reject
|
||||
adminListAppeals GET /admin-api/muse/market/appeals
|
||||
adminGetAppeal GET /admin-api/muse/market/appeals/{appealId}
|
||||
adminResolveAppeal POST /admin-api/muse/market/appeals/{appealId}/resolve
|
||||
```
|
||||
|
||||
全部 32 个当前状态均为 `generic_persistence / incomplete`,当前实现 owner 是 `AdminMuseMarketContractController` / `AppMuseMarketContractController` + `MuseContractPersistenceService`。
|
||||
|
||||
## 2. 子代理执行规则
|
||||
|
||||
同一实现 Task 内,复用最近一次负责该任务的 implementer;只有进入新的实现 Task 时,才启用 fresh implementer。
|
||||
|
||||
每个实现 Task 完成后必须两轮 fresh review:
|
||||
|
||||
1. spec compliance review:检查是否符合 `docs/superpowers/specs/2026-06-03-P1R-6-market-real-api-design.md` 和本计划。
|
||||
2. quality / feasibility review:检查最小改动、可维护性、测试质量、外部 owner 失败路径、无脚本掩盖。
|
||||
|
||||
review 未通过不能进入下一 Task。review 修复仍属于同一实现 Task,复用最近 implementer;重新 review 必须 fresh reviewer。
|
||||
|
||||
## Task 1: Preflight 与覆盖基线冻结
|
||||
|
||||
**Files:**
|
||||
|
||||
- Read: `docs/superpowers/reports/p1r-api-coverage.json`
|
||||
- Read: `docs/superpowers/reports/p1r-api-coverage.md`
|
||||
- Read: `docs/api-contracts/market/openapi.yaml`
|
||||
- Read: `muse-cloud/muse-module-market/**`
|
||||
- Read: `muse-cloud/sql/muse/**`
|
||||
- Read: `docs/memorys/2026-06-03-P1R4P1R5完成状态推进.md`
|
||||
|
||||
- [ ] **Step 1: 核实工作面**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git status --short --branch
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
## dev/1.0.0...origin/dev/1.0.0
|
||||
```
|
||||
|
||||
进入实现前,P1R-4 / P1R-5 coverage 状态推进和 P1R-6 spec/plan 必须已提交,或明确作为唯一待提交文档/coverage diff 存在。不得混入其它代码 diff。
|
||||
|
||||
- [ ] **Step 2: 统计 Market operation 状态**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
jq -r '.operations[] | select(.domain == "market") | [.implementationStatus,.completionStatus] | @tsv' docs/superpowers/reports/p1r-api-coverage.json | sort | uniq -c
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
32 generic_persistence incomplete
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 冻结 operation 清单**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
jq -r '.operations[] | select(.domain == "market") | [.operationId,.method,.path,.implementationStatus,.completionStatus] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
|
||||
```
|
||||
|
||||
Expected: 输出 32 行,且 operationId 与本计划第 1 节一致。
|
||||
|
||||
- [ ] **Step 4: 检查禁止修改面**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git status --short -- docs/api-contracts/market/openapi.yaml docs/api-contracts/ai/openapi.yaml docs/api-contracts/knowledge/openapi.yaml muse-cloud/scripts
|
||||
```
|
||||
|
||||
Expected: 无输出;如果存在 P1R-4 / P1R-5 coverage 脚本已批准改动,必须在进入 P1R-6 实现前先提交。
|
||||
|
||||
## Task 2: Market 基础设施与 V15 DDL
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `muse-cloud/muse-module-market/muse-module-market-server/pom.xml`
|
||||
- Create/Modify: `muse-cloud/muse-module-market/muse-module-market-api/src/main/java/cn/iocoder/muse/module/market/enums/ErrorCodeConstants.java`
|
||||
- Create: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/domain/muse/*.java`
|
||||
- Create: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/*.java`
|
||||
- Create: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/dal/dataobject/muse/*.java`
|
||||
- Create: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/dal/mysql/muse/*.java`
|
||||
- Create: `muse-cloud/sql/muse/V15__extend_market_real_api_schema.sql`
|
||||
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketMigrationSqlTest.java`
|
||||
|
||||
- [ ] **Step 1: 确认 Market server 模块依赖**
|
||||
|
||||
确认或补齐 validation、web、security、mybatis、test 依赖。P1R-6 Account 投影采用最小可执行接线方案:`muse-module-market-server` 显式依赖 `muse-module-member-server`,复用 member 侧既有 `MarketAccountProjectionFacade`、`AccountRecordProjectionDO` 和 `AccountRecordProjectionMapper`。当前 `member-server` 不依赖 `market-server`,该依赖方向不得形成 Maven 循环;实现时必须用 Maven reactor 或 dependency-tree 验证。不要引入 AI / Knowledge / Content 作为强 owner 依赖;跨 owner 能力通过本模块 facade 明确隔离。
|
||||
|
||||
- [ ] **Step 2: 增加 Market 错误码**
|
||||
|
||||
至少覆盖:
|
||||
|
||||
- `MARKET_API_VERSION_UNSUPPORTED`
|
||||
- `MARKET_COMMAND_ID_REQUIRED`
|
||||
- `MARKET_COMMAND_ID_CONFLICT`
|
||||
- `MARKET_ASSET_NOT_EXISTS`
|
||||
- `MARKET_ASSET_NOT_LISTED`
|
||||
- `MARKET_ASSET_GOVERNANCE_BLOCKED`
|
||||
- `MARKET_LICENSE_NOT_EXISTS`
|
||||
- `MARKET_LICENSE_NOT_PURCHASABLE`
|
||||
- `MARKET_INSTALL_NOT_EXISTS`
|
||||
- `MARKET_INSTALL_NOT_BINDABLE`
|
||||
- `MARKET_HANDOFF_NOT_EXISTS`
|
||||
- `MARKET_HANDOFF_EXPIRED`
|
||||
- `MARKET_HANDOFF_NOT_CANCELLABLE`
|
||||
- `MARKET_PUBLISH_DRAFT_NOT_EXISTS`
|
||||
- `MARKET_PUBLISH_CHECK_NOT_EXISTS`
|
||||
- `MARKET_PUBLISH_CHECK_EXPIRED`
|
||||
- `MARKET_PUBLISH_REQUEST_NOT_EXISTS`
|
||||
- `MARKET_PUBLISH_REQUEST_STATUS_CONFLICT`
|
||||
- `MARKET_GOVERNANCE_PREVIEW_REQUIRED`
|
||||
- `MARKET_APPEAL_NOT_EXISTS`
|
||||
- `MARKET_APPEAL_STATUS_CONFLICT`
|
||||
- `MARKET_TARGET_OWNER_UNAVAILABLE`
|
||||
- `MARKET_ACCOUNT_PROJECTION_UNAVAILABLE`
|
||||
|
||||
- [ ] **Step 3: 编写 V15 迁移**
|
||||
|
||||
至少新增或扩展:
|
||||
|
||||
- `muse_market_command`
|
||||
- `muse_market_authorization_snapshot`
|
||||
- `muse_market_authorization_summary`
|
||||
- `muse_market_handoff_event`
|
||||
- `muse_market_publish_draft`
|
||||
- `muse_market_publish_check`
|
||||
- `muse_market_review_event`
|
||||
- `muse_market_governance_preview`
|
||||
- `muse_market_governance_action`
|
||||
- `muse_market_governance_impact`
|
||||
- `muse_market_appeal_material`
|
||||
- `muse_market_appeal_event`
|
||||
- `muse_market_account_projection`
|
||||
- `muse_market_source_status_event`
|
||||
|
||||
DDL 必须有 tenant、command、status、revision、audit 时间、必要唯一约束和查询索引。其中 `muse_market_account_projection` 只表达 Market 侧投影同步/outbox 状态,不是 Account 查询读模型;Account 查询读模型只能是 V11 已有的 `muse_account_record_projection`。
|
||||
|
||||
- [ ] **Step 4: DDL 静态测试**
|
||||
|
||||
`P1rMarketMigrationSqlTest` 至少验证:
|
||||
|
||||
- V15 文件存在。
|
||||
- 新表名存在。
|
||||
- `muse_market_command` 有 `command_id`、`request_hash` 和唯一约束。
|
||||
- handoff token 不以明文作为唯一安全依据,必须存在 token hash 或等价字段。
|
||||
- governance action / preview / impact 三类事实不被压成一个字段。
|
||||
|
||||
## Task 3: Market command、version、owner guard
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.../domain/muse/MarketApiVersionGuard.java`
|
||||
- Create: `.../domain/muse/MarketCommandGuard.java`
|
||||
- Create: `.../domain/muse/MarketOwnerGuard.java`
|
||||
- Create: `.../application/muse/MarketCommandService.java`
|
||||
- Create: `.../application/muse/MarketCommandServiceImpl.java`
|
||||
- Test: `.../application/muse/MarketCommandServiceTest.java`
|
||||
|
||||
- [ ] **Step 1: 实现 API version guard**
|
||||
|
||||
所有 dedicated Controller 入口必须校验 `X-API-Version`,不支持版本返回业务错误,不进入应用服务写事实。
|
||||
|
||||
- [ ] **Step 2: 实现 command 幂等 guard**
|
||||
|
||||
相同 command + 相同 request hash 返回已保存结果;相同 command + 不同 request hash 返回冲突。
|
||||
|
||||
- [ ] **Step 3: 实现 owner/tenant guard**
|
||||
|
||||
App 查询只能看当前用户可见资产、授权、安装、发布记录和申诉。Admin 查询必须保留权限注解,不能用 app user 可见性替代。
|
||||
|
||||
## Task 4: 资产发现、分类、推荐、详情、收藏
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.../controller/app/muse/AppMuseMarketplaceAssetController.java`
|
||||
- Create: `.../controller/app/muse/vo/*.java`
|
||||
- Create: `.../application/muse/MarketAssetQueryService.java`
|
||||
- Create: `.../application/muse/MarketFavoriteService.java`
|
||||
- Test: `.../controller/app/muse/AppMuseMarketplaceAssetControllerTest.java`
|
||||
- Test: `.../application/muse/MarketFavoriteServiceTest.java`
|
||||
|
||||
- [ ] **Step 1: 实现资产列表、分类、推荐、详情**
|
||||
|
||||
读取 Market 资产、版本和展示摘要。无独立推荐数据时可以使用可解释 fallback 排序,但必须在响应摘要中体现来源,不允许 fake 个性化。
|
||||
|
||||
- [ ] **Step 2: 实现收藏/取消收藏**
|
||||
|
||||
写 `muse_market_favorite`,保持幂等。取消收藏不能删除审计事实,只能更新状态。
|
||||
|
||||
- [ ] **Step 3: 测试合同字段和可见性**
|
||||
|
||||
测试覆盖 listed/delisted/recall、当前用户收藏状态、分页结构、未登录和不可见资产。
|
||||
|
||||
## Task 5: 授权购买、安装和 Account 投影
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.../controller/app/muse/AppMuseMarketLicenseController.java`
|
||||
- Create: `.../application/muse/MarketLicenseService.java`
|
||||
- Create: `.../application/muse/MarketInstallService.java`
|
||||
- Create: `.../application/muse/MarketAccountProjectionProvider.java`
|
||||
- Implement: `cn.iocoder.muse.module.member.application.account.facade.MarketAccountProjectionFacade` provider bean
|
||||
- Use: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountRecordProjectionDO.java`
|
||||
- Use: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountRecordProjectionMapper.java`
|
||||
- Test: `.../application/muse/MarketLicenseServiceTest.java`
|
||||
- Test: `.../application/muse/MarketInstallServiceTest.java`
|
||||
- Test: `.../application/muse/MarketAccountProjectionProviderTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceTest.java`
|
||||
|
||||
- [ ] **Step 1: 实现 purchaseAsset**
|
||||
|
||||
校验资产可获取、许可可用、治理策略允许新获取。写购买/授权快照,并向既有 `muse_account_record_projection` 写入 `purchase` / `license` 投影。重复 command 返回同一授权结果。
|
||||
|
||||
- [ ] **Step 2: 实现 installMarketplaceAsset**
|
||||
|
||||
安装必须消费有效授权。安装智能体和知识库只进入账户可用列表,并更新 Account `license` 投影状态;不写 AI / Knowledge 目标事实。作品资产不走安装流程。
|
||||
|
||||
- [ ] **Step 3: Account projection fail-closed**
|
||||
|
||||
不得在 Market 模块另建同名 `MarketAccountProjectionFacade` 或 `UnavailableMarketAccountProjectionFacade` 作为运行态契约。Market 必须通过 `market-server -> member-server` 依赖对接 member 模块既有 `cn.iocoder.muse.module.member.application.account.facade.MarketAccountProjectionFacade`,并提供真实 provider bean 替换 member 默认 auto-configuration 注册的 unavailable bean:当 Market projection provider 未接入时,Account 查询继续 fail-closed;当 provider 接入且投影写入成功后,测试必须证明 Account `purchase` / `license` / `publish` 查询不再命中默认 unavailable 实现。投影写入失败时,Market 业务事实只能记录为 projection pending / blocked,不能伪造成 Account 已同步。
|
||||
|
||||
## Task 6: 来源授权摘要与 Handoff
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.../controller/app/muse/AppMuseMarketHandoffController.java`
|
||||
- Create: `.../application/muse/MarketHandoffService.java`
|
||||
- Create: `.../application/muse/facade/MarketTargetOwnerFacade.java`
|
||||
- Create: `.../application/muse/facade/UnavailableMarketTargetOwnerFacade.java`
|
||||
- Test: `.../application/muse/MarketHandoffServiceTest.java`
|
||||
- Test: `.../controller/app/muse/AppMuseMarketHandoffControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 实现 createBindPrecheck**
|
||||
|
||||
生成来源侧 authorization summary 和 authorization snapshot。结果不能包含目标 owner precheck ID。
|
||||
|
||||
- [ ] **Step 2: 实现 createMarketplaceHandoff**
|
||||
|
||||
生成一次性 handoff token、token hash、过期时间和目标页。Market 不消费 token,不写目标 owner。
|
||||
|
||||
- [ ] **Step 3: 实现 getHandoffStatus / cancelHandoff**
|
||||
|
||||
查询不改变状态。取消只能取消 pending / owner_precheck_created 前的 token;已 completed、expired、cancelled 不可取消。这里的 `completed` 只表示 handoff token 业务生命周期状态,不等于 coverage `completionStatus=completed`,不得据此推进 Market operation completed。
|
||||
|
||||
## Task 7: 发布草稿、发布检查、提交与撤回
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.../controller/app/muse/AppMuseMarketPublishController.java`
|
||||
- Create: `.../application/muse/MarketPublishService.java`
|
||||
- Test: `.../application/muse/MarketPublishServiceTest.java`
|
||||
- Test: `.../controller/app/muse/AppMuseMarketPublishControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 实现 savePublishDraft**
|
||||
|
||||
保存发布材料草稿,不提交审核、不上架。作品资产高阶模式只允许保存为 `read_only_favorite_license`。
|
||||
|
||||
- [ ] **Step 2: 实现 runPublishCheck**
|
||||
|
||||
检查权利、隐私、许可、治理和材料 hash。检查通过只允许 submit,不上架。
|
||||
|
||||
- [ ] **Step 3: 实现 submitPublishRequest / withdrawPublishRequest / listMyPublishRecords**
|
||||
|
||||
提交必须原子消费未过期、匹配草稿版本和材料 hash 的检查结果。撤回只允许非终态申请。
|
||||
|
||||
## Task 8: 管理端审核、上架、拒绝
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.../controller/admin/muse/AdminMuseMarketReviewController.java`
|
||||
- Create: `.../application/muse/AdminMarketReviewService.java`
|
||||
- Test: `.../application/muse/AdminMarketReviewServiceTest.java`
|
||||
- Test: `.../controller/admin/muse/AdminMuseMarketReviewControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 实现 adminListPublishRequests**
|
||||
|
||||
支持审核状态、资产类型、风险标签、发布者筛选。
|
||||
|
||||
- [ ] **Step 2: 实现 adminApprovePublishRequest**
|
||||
|
||||
通过必须消费审核校验结果,写审核事件,更新资产/版本为 listed,可见状态必须可查询。
|
||||
|
||||
- [ ] **Step 3: 实现 adminRejectPublishRequest**
|
||||
|
||||
拒绝必须写理由和证据标签,发布者可后续申诉。终态申请不可重复审核。
|
||||
|
||||
## Task 9: 管理端资产治理、下架、召回和影响预览
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.../controller/admin/muse/AdminMuseMarketAssetController.java`
|
||||
- Create: `.../application/muse/AdminMarketGovernanceService.java`
|
||||
- Test: `.../application/muse/AdminMarketGovernanceServiceTest.java`
|
||||
- Test: `.../controller/admin/muse/AdminMuseMarketAssetControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 实现 adminListMarketAssets / adminGetMarketAsset**
|
||||
|
||||
管理端详情必须包含版本、授权、安装、治理和来源摘要。
|
||||
|
||||
- [ ] **Step 2: 实现 adminPreviewGovernanceImpact**
|
||||
|
||||
生成影响预览,覆盖授权、安装、handoff、绑定摘要、运行中任务、Shadow 候选、Knowledge Draft 和导出限制。
|
||||
|
||||
- [ ] **Step 3: 实现 adminDelistAsset / adminRecallAsset**
|
||||
|
||||
必须消费有效 `impactPreviewId` 和 expectedStatus。召回要写 source status propagation 事实,owner facade 不可用时记录 blocked,并把需要重验的信息写入 action policy / recheck reasons;`needs_recheck` 不能作为 Market `SourceStatus` 值。
|
||||
|
||||
## Task 10: 申诉提交、补充、撤回与管理端处理
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.../controller/app/muse/AppMuseMarketAppealController.java`
|
||||
- Create: `.../controller/admin/muse/AdminMuseMarketAppealController.java`
|
||||
- Create: `.../application/muse/MarketAppealService.java`
|
||||
- Test: `.../application/muse/MarketAppealServiceTest.java`
|
||||
- Test: `.../controller/app/muse/AppMuseMarketAppealControllerTest.java`
|
||||
- Test: `.../controller/admin/muse/AdminMuseMarketAppealControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 实现用户端申诉**
|
||||
|
||||
提交、补充、撤回必须校验申诉期限、关联关系和 expectedStatus。补充材料保存脱敏摘要,不记录密钥或无关正文全文。
|
||||
|
||||
- [ ] **Step 2: 实现管理端申诉查询与处理**
|
||||
|
||||
只读取申诉材料和发布资产,不读取用户私有副本。恢复上架必须消费治理影响预览。
|
||||
|
||||
## Task 11: Retire Market 合同兜底与 coverage gate
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/AdminMuseMarketContractController.java`
|
||||
- Modify: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/AppMuseMarketContractController.java`
|
||||
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketRealApiGateTest.java`
|
||||
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketRouteOwnershipTest.java`
|
||||
|
||||
- [ ] **Step 1: 精确退役 32 个 Market 路由兜底**
|
||||
|
||||
合同兜底 Controller 不能继续捕获 P1R-6 32 个路由。可以删除或精确避让,但必须由 route ownership test 证明。
|
||||
|
||||
- [ ] **Step 2: coverage gate**
|
||||
|
||||
`P1rMarketRealApiGateTest` 必须证明:
|
||||
|
||||
- Market operation 数量为 32。
|
||||
- 32 个 operation 全部 `dedicated / needs_verification`。
|
||||
- Market 不包含 `generic_persistence`、`catch_all`、`sse_placeholder`、`missing`。
|
||||
- `completedOperations` 仍为 100。
|
||||
- AI / Knowledge 仍是 `dedicated / completed`。
|
||||
- Content / Meta / Account 仍是 `dedicated / needs_verification`。
|
||||
- Events P1R-7 `streamEvents` 仍是唯一 SSE placeholder。
|
||||
|
||||
- [ ] **Step 3: route ownership gate**
|
||||
|
||||
`P1rMarketRouteOwnershipTest` 必须证明 32 个 Market 路由 handler 不属于 `*MarketContractController`,且不调用 `MuseContractPersistenceService`。
|
||||
|
||||
## Task 12: PostgreSQL / Flyway `_test` 迁移验收
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketFlywayMigrationIT.java`
|
||||
|
||||
- [ ] **Step 1: 构建 reactor**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd muse-cloud
|
||||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||||
mvn -o clean install -DskipTests -Dspring-boot.repackage.skip=true -pl muse-server -am
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 跑真实 PostgreSQL / Flyway**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd muse-cloud
|
||||
set -a
|
||||
. ~/.config/muse-repo/infra.env
|
||||
set +a
|
||||
export P1R_FLYWAY_PASSWORD="$MUSE_POSTGRES_PASSWORD"
|
||||
P1R6_TEST_DB="${P1R6_TEST_DB:-muse_local_p1r6_test}"
|
||||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||||
mvn -o test -pl muse-server \
|
||||
-Dtest=P1rMarketFlywayMigrationIT \
|
||||
-Dp1r.flyway.url="jdbc:postgresql://${MUSE_POSTGRES_HOST}:${MUSE_POSTGRES_PORT}/${P1R6_TEST_DB}" \
|
||||
-Dp1r.flyway.user="$MUSE_POSTGRES_USERNAME" \
|
||||
-Dp1r.flyway.locations="filesystem:sql/muse"
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
migrations_executed >= 15
|
||||
target_schema_version = 15
|
||||
flyway_latest = 15:extend market real api schema
|
||||
```
|
||||
|
||||
## Task 13: 最终验证、报告对账与 memory
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `docs/superpowers/reports/p1r-api-coverage.json`
|
||||
- Modify: `docs/superpowers/reports/p1r-api-coverage.md`
|
||||
- Create: `docs/memorys/YYYY-MM-DD-P1R6Market真实API收口.md`
|
||||
|
||||
- [ ] **Step 1: 重新生成 coverage**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 对账 coverage**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
jq -r '.operations | group_by(.domain)[] | [.[0].domain, (length|tostring), ([group_by(.implementationStatus + "/" + .completionStatus)[] | (.[0].implementationStatus + "/" + .[0].completionStatus + ":" + (length|tostring))] | join(", "))] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
|
||||
jq -r '.summary | [.completedOperations,.needsVerificationOperations,.incompleteOperations,.genericPersistenceOperations,.ssePlaceholderOperations] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
market dedicated/needs_verification:32
|
||||
completedOperations = 100
|
||||
genericPersistenceOperations = 0
|
||||
ssePlaceholderOperations = 1
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Maven gate**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd muse-cloud
|
||||
JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -pl muse-server -Dtest=P1rApiCoverageReportTest,P1rMarketRealApiGateTest,P1rMarketRouteOwnershipTest,P1rMarketMigrationSqlTest test
|
||||
```
|
||||
|
||||
- [ ] **Step 4: focused tests**
|
||||
|
||||
Run the focused Market service/controller tests created in Tasks 3-11.
|
||||
|
||||
- [ ] **Step 5: diff hygiene**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
git status --short -- docs/api-contracts/market/openapi.yaml docs/api-contracts/ai/openapi.yaml docs/api-contracts/knowledge/openapi.yaml
|
||||
```
|
||||
|
||||
Expected: no OpenAPI diff and no whitespace errors.
|
||||
|
||||
## 3. Review handoff
|
||||
|
||||
完成本计划文档后必须执行两轮 fresh review:
|
||||
|
||||
1. spec compliance review:确认本计划覆盖 `docs/superpowers/specs/2026-06-03-P1R-6-market-real-api-design.md`,没有跨入目标 owner 事实写入。
|
||||
2. quality / feasibility review:确认任务拆分、DDL、测试门禁、失败路径和验证命令足够可执行。
|
||||
|
||||
review 通过前不得进入 P1R-6 代码实现。
|
||||
@ -0,0 +1,365 @@
|
||||
# P1R-6:Market Real API 规格
|
||||
|
||||
- 版本:v1
|
||||
- 日期:2026-06-03
|
||||
- 状态:review gate 待执行
|
||||
- 上游规格:`docs/superpowers/specs/2026-05-25-P1R-muse-cloud-real-api-design.md`
|
||||
- 基线输入:`docs/superpowers/reports/p1r-api-coverage.json`
|
||||
- 范围:`muse-cloud/muse-module-market/**` 中 Market 专用实现、Market 相关追加迁移、授权/安装/handoff/发布/治理/申诉状态机、P1R-6 覆盖门禁
|
||||
- 非范围:P1R-7 统一 Events SSE、目标 owner 绑定确认、AI / Knowledge / Content canonical 写入、修改 `docs/api-contracts/market/openapi.yaml`、把 Market operation 标为 `completed`
|
||||
|
||||
## 1. 结论
|
||||
|
||||
P1R-6 的目标不是继续用 `MuseContractPersistenceService` 记录市场合同请求,也不是把 Market 设计成能直接替目标 owner 写入作品、智能体槽位或知识库绑定事实的“中间缝合层”。
|
||||
|
||||
本阶段要把 Market 域从“通用持久化可响应”推进到“专用 Market API 可验证”:
|
||||
|
||||
1. Market 32 个 operation 当前全部是 `generic_persistence / incomplete`,必须退出通用持久化完成口径。
|
||||
2. Market owner 落在 `muse-module-market`,负责市场资产、版本、分类/推荐曝光、收藏、购买授权、安装、来源授权摘要、handoff、发布草稿、发布检查、发布申请、管理端审核、下架、召回和申诉。
|
||||
3. Market 只生成来源侧授权摘要和 handoff token。目标 owner 的预检、确认和事实写入仍由 AI、Knowledge 或 Content 自己完成。
|
||||
4. 购买只产生授权记录,不等于安装;安装只把资产放入账户可用列表,不等于绑定作品或写目标事实。
|
||||
5. 作品资产高阶模式默认关闭。未完成 ADR、Schema/API、lineage 和授权快照前,只允许 `read_only_favorite_license`。
|
||||
6. 下架/召回必须形成治理影响预览、状态传播和审计事实,不能只改 `listing_status`。
|
||||
7. P1R-6 实现通过后的覆盖目标只能是 `dedicated / needs_verification`。没有 P1R-7 真实跨域端到端验收前,Market 不能写成 `completed`。
|
||||
|
||||
## 2. 已验证事实
|
||||
|
||||
### 2.1 执行工作面
|
||||
|
||||
真实工作面:
|
||||
|
||||
```text
|
||||
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
|
||||
```
|
||||
|
||||
当前分支:
|
||||
|
||||
```text
|
||||
dev/1.0.0
|
||||
```
|
||||
|
||||
当前 worktree 已存在 P1R-4 / P1R-5 coverage 状态推进相关未提交 diff。进入 P1R-6 实现前,必须先提交或明确保留这些已验证改动,避免新阶段实现和上一阶段 coverage 收口混在不可追踪状态里。
|
||||
|
||||
### 2.2 覆盖矩阵
|
||||
|
||||
当前全局 summary:
|
||||
|
||||
```text
|
||||
completedOperations 100
|
||||
needsVerificationOperations 100
|
||||
incompleteOperations 33
|
||||
genericPersistenceOperations 32
|
||||
ssePlaceholderOperations 1
|
||||
```
|
||||
|
||||
按域状态:
|
||||
|
||||
```text
|
||||
account 33 dedicated / needs_verification
|
||||
ai 41 dedicated / completed
|
||||
content 51 dedicated / needs_verification
|
||||
events 1 sse_placeholder / incomplete
|
||||
knowledge 59 dedicated / completed
|
||||
market 32 generic_persistence / incomplete
|
||||
meta 16 dedicated / needs_verification
|
||||
```
|
||||
|
||||
P1R-6 preflight 命令:
|
||||
|
||||
```bash
|
||||
jq -r '.operations[] | select(.domain == "market") | [.operationId,.method,.path,.targetStage,.implementationStatus,.completionStatus] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
|
||||
```
|
||||
|
||||
输出事实:32 行,全部为 `P1R-6 Market Real API / generic_persistence / incomplete`。
|
||||
|
||||
### 2.3 OpenAPI 事实
|
||||
|
||||
`docs/api-contracts/market/openapi.yaml` 声明 32 个 Market operation:
|
||||
|
||||
| 分组 | 数量 | operation |
|
||||
|---|---:|---|
|
||||
| 用户端发现 | 4 | `listMarketplaceAssets`、`listMarketplaceCategories`、`listMarketplaceRecommendations`、`getMarketplaceAsset` |
|
||||
| 收藏 | 2 | `favoriteAsset`、`unfavoriteAsset` |
|
||||
| 授权与安装 | 2 | `purchaseAsset`、`installMarketplaceAsset` |
|
||||
| Handoff | 4 | `createBindPrecheck`、`createMarketplaceHandoff`、`getHandoffStatus`、`cancelHandoff` |
|
||||
| 发布 | 5 | `savePublishDraft`、`runPublishCheck`、`submitPublishRequest`、`withdrawPublishRequest`、`listMyPublishRecords` |
|
||||
| 用户端治理与申诉 | 4 | `getGovernanceImpact`、`submitAppeal`、`supplementAppeal`、`withdrawAppeal` |
|
||||
| 管理端资产治理 | 5 | `adminListMarketAssets`、`adminGetMarketAsset`、`adminPreviewGovernanceImpact`、`adminDelistAsset`、`adminRecallAsset` |
|
||||
| 管理端发布审核 | 3 | `adminListPublishRequests`、`adminApprovePublishRequest`、`adminRejectPublishRequest` |
|
||||
| 管理端申诉 | 3 | `adminListAppeals`、`adminGetAppeal`、`adminResolveAppeal` |
|
||||
|
||||
关键合同约束:
|
||||
|
||||
1. 所有接口使用 `X-API-Version`。
|
||||
2. 写命令使用 `commandId` 并结合 `expectedStatus` 或检查快照防止盲写。
|
||||
3. `purchaseAsset` 只获取授权,不安装、不绑定、不写目标 owner。
|
||||
4. `installMarketplaceAsset` 只写安装事实,不写作品事实。
|
||||
5. `createBindPrecheck` 只生成来源侧授权摘要和 handoff 准备信息,不生成目标 owner 预检 ID。
|
||||
6. `createMarketplaceHandoff` 只生成一次性 token 和目标页,不替换绑定、不解绑、不降权、不改作品事实。
|
||||
7. `runPublishCheck` 只证明草稿可提交审核,不直接上架。
|
||||
8. `submitPublishRequest` 必须原子消费未过期且匹配草稿 hash 的发布检查结果。
|
||||
9. `adminDelistAsset` / `adminRecallAsset` 必须绑定治理影响预览,不能盲下架或盲召回。
|
||||
10. 申诉处理只能读取申诉材料和发布资产,不读取用户私有副本。
|
||||
|
||||
### 2.4 当前代码事实
|
||||
|
||||
当前 Market 合同入口:
|
||||
|
||||
- `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/AdminMuseMarketContractController.java`
|
||||
- `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/AppMuseMarketContractController.java`
|
||||
|
||||
两个 Controller 都统一委托:
|
||||
|
||||
```text
|
||||
MuseContractPersistenceService.handle(...)
|
||||
```
|
||||
|
||||
当前 `muse-module-market-server` 只有合同 Controller 和 `package-info.java`,没有 Market Application Service、专用 VO/DTO、DO、Mapper、状态机、owner facade 或 P1R-6 gate test。
|
||||
|
||||
`muse-server/pom.xml` 已装配:
|
||||
|
||||
```text
|
||||
muse-module-market-server
|
||||
```
|
||||
|
||||
因此 P1R-6 实现应继续在 `muse-module-market-server` 内落 owner,不需要新增合同模块或把 Market 逻辑写入 Account、AI、Knowledge 或 Content。
|
||||
|
||||
### 2.5 当前 DDL
|
||||
|
||||
`muse-cloud/sql/muse/V6__init_market_schema.sql` 已有:
|
||||
|
||||
- `muse_market_asset`
|
||||
- `muse_market_asset_version`
|
||||
- `muse_market_installation`
|
||||
- `muse_market_publish_request`
|
||||
- `muse_market_appeal`
|
||||
- `muse_market_handoff`
|
||||
|
||||
`muse-cloud/sql/muse/V8__add_contract_workflow_and_market_interaction.sql` 已有:
|
||||
|
||||
- `muse_domain_workflow_task`
|
||||
- `muse_market_favorite`
|
||||
- `muse_market_purchase`
|
||||
|
||||
这些表不足以完成 P1R-6:
|
||||
|
||||
1. 没有 Market 专用 command/requestHash/replay 表。
|
||||
2. 没有来源侧授权摘要、授权快照、兼容性结果和 handoff 消费状态的独立事实。
|
||||
3. 没有发布草稿、发布检查、发布检查快照、发布材料 hash、审核校验结果和审核证据记录。
|
||||
4. 没有治理影响预览、治理动作、治理传播、受影响授权/安装/绑定/任务/候选的可查询结果。
|
||||
5. 没有申诉补充材料、申诉处理历史、申诉证据脱敏摘要。
|
||||
6. 没有分类/推荐/曝光读模型或可降级策略。
|
||||
7. 没有 Account 投影同步状态,无法证明购买、安装、授权能被 Account 查询消费。
|
||||
|
||||
P1R-5 已使用 V14;P1R-6 如新增迁移,推荐使用:
|
||||
|
||||
```text
|
||||
muse-cloud/sql/muse/V15__extend_market_real_api_schema.sql
|
||||
```
|
||||
|
||||
## 3. 目标
|
||||
|
||||
1. 将 Market 32 个 operation 从 `generic_persistence / incomplete` 推进到 `dedicated / needs_verification`。
|
||||
2. 建立 `muse-module-market` 专用 Admin/App Controller、Application Service、VO/DTO、DO、Mapper、Assembler 和 domain guard。
|
||||
3. 建立 Market command 幂等、API version guard、tenant/user/owner guard、expectedStatus guard。
|
||||
4. 建立资产、版本、分类、推荐、详情和收藏真实读写模型。
|
||||
5. 建立购买授权、安装、Account projection 同步状态和授权快照。
|
||||
6. 建立来源侧 bind precheck、authorization summary、authorization snapshot 和 handoff token 生命周期。
|
||||
7. 建立发布草稿、发布检查、发布申请、撤回和我的发布记录状态机。
|
||||
8. 建立管理端审核、下架、召回、治理影响预览和申诉处理状态机。
|
||||
9. 建立 owner facades,明确 Account、AI、Knowledge、Content 不可用时的 fail-closed 边界。
|
||||
10. 建立 P1R-6 coverage gate,防止 Market operation 继续被合同兜底、通用持久化或 `completed` 混淆。
|
||||
|
||||
## 4. 非目标
|
||||
|
||||
1. 不修改 Market OpenAPI 来适配当前代码。
|
||||
2. 不修改 scanner 掩盖 Market 仍未 dedicated 的事实。
|
||||
3. 不把 Market operation 标为 `completed`。
|
||||
4. 不实现 P1R-7 `/app-api/muse/events`。
|
||||
5. 不让 Market 直接写 AI agent slot、Knowledge binding、Content work/block/canonical 事实。
|
||||
6. 不在 P1R-6 开放作品资产 `full`、`reference`、`context_use` 高阶模式。
|
||||
7. 不把 `MuseContractPersistenceService`、空列表、固定样例或 `muse_domain_workflow_task` 原始行作为完成证据。
|
||||
8. 不把 Account、AI、Knowledge、Content owner unavailable 伪造成 success。
|
||||
|
||||
## 5. Operation 清单与目标 owner
|
||||
|
||||
| operationId | Method | Path | 当前状态 | P1R-6 owner | P1R-6 目标 |
|
||||
|---|---|---|---|---|---|
|
||||
| `listMarketplaceAssets` | GET | `/app-api/muse/marketplace/assets` | `generic_persistence / incomplete` | Market Asset Query | `dedicated / needs_verification` |
|
||||
| `listMarketplaceCategories` | GET | `/app-api/muse/marketplace/categories` | `generic_persistence / incomplete` | Market Discovery Query | `dedicated / needs_verification` |
|
||||
| `listMarketplaceRecommendations` | GET | `/app-api/muse/marketplace/recommendations` | `generic_persistence / incomplete` | Market Discovery Query | `dedicated / needs_verification` |
|
||||
| `getMarketplaceAsset` | GET | `/app-api/muse/marketplace/assets/{assetId}` | `generic_persistence / incomplete` | Market Asset Query | `dedicated / needs_verification` |
|
||||
| `favoriteAsset` | POST | `/app-api/muse/marketplace/assets/{assetId}/favorite` | `generic_persistence / incomplete` | Market Favorite Command | `dedicated / needs_verification` |
|
||||
| `unfavoriteAsset` | DELETE | `/app-api/muse/marketplace/assets/{assetId}/favorite` | `generic_persistence / incomplete` | Market Favorite Command | `dedicated / needs_verification` |
|
||||
| `purchaseAsset` | POST | `/app-api/muse/marketplace/assets/{assetId}/purchase` | `generic_persistence / incomplete` | Market License Command | `dedicated / needs_verification` |
|
||||
| `installMarketplaceAsset` | POST | `/app-api/muse/marketplace/assets/{assetId}/install` | `generic_persistence / incomplete` | Market Install Command | `dedicated / needs_verification` |
|
||||
| `createBindPrecheck` | POST | `/app-api/muse/marketplace/assets/{assetId}/bind-precheck` | `generic_persistence / incomplete` | Market Handoff Source Command | `dedicated / needs_verification` |
|
||||
| `createMarketplaceHandoff` | POST | `/app-api/muse/marketplace/handoffs` | `generic_persistence / incomplete` | Market Handoff Command | `dedicated / needs_verification` |
|
||||
| `getHandoffStatus` | GET | `/app-api/muse/marketplace/handoffs/{handoffToken}` | `generic_persistence / incomplete` | Market Handoff Query | `dedicated / needs_verification` |
|
||||
| `cancelHandoff` | POST | `/app-api/muse/marketplace/handoffs/{handoffToken}/cancel` | `generic_persistence / incomplete` | Market Handoff Command | `dedicated / needs_verification` |
|
||||
| `savePublishDraft` | POST | `/app-api/muse/marketplace/publish-drafts` | `generic_persistence / incomplete` | Market Publish Draft Command | `dedicated / needs_verification` |
|
||||
| `runPublishCheck` | POST | `/app-api/muse/marketplace/publish-drafts/{draftId}/checks` | `generic_persistence / incomplete` | Market Publish Check Command | `dedicated / needs_verification` |
|
||||
| `submitPublishRequest` | POST | `/app-api/muse/marketplace/publish-requests` | `generic_persistence / incomplete` | Market Publish Request Command | `dedicated / needs_verification` |
|
||||
| `withdrawPublishRequest` | POST | `/app-api/muse/marketplace/publish-requests/{requestId}/withdraw` | `generic_persistence / incomplete` | Market Publish Request Command | `dedicated / needs_verification` |
|
||||
| `listMyPublishRecords` | GET | `/app-api/muse/marketplace/my-publish-records` | `generic_persistence / incomplete` | Market Publish Query | `dedicated / needs_verification` |
|
||||
| `getGovernanceImpact` | GET | `/app-api/muse/marketplace/assets/{assetId}/governance-impact` | `generic_persistence / incomplete` | Market Governance Query | `dedicated / needs_verification` |
|
||||
| `submitAppeal` | POST | `/app-api/muse/marketplace/appeals` | `generic_persistence / incomplete` | Market Appeal Command | `dedicated / needs_verification` |
|
||||
| `supplementAppeal` | POST | `/app-api/muse/marketplace/appeals/{appealId}/supplements` | `generic_persistence / incomplete` | Market Appeal Command | `dedicated / needs_verification` |
|
||||
| `withdrawAppeal` | POST | `/app-api/muse/marketplace/appeals/{appealId}/withdraw` | `generic_persistence / incomplete` | Market Appeal Command | `dedicated / needs_verification` |
|
||||
| `adminListMarketAssets` | GET | `/admin-api/muse/market/assets` | `generic_persistence / incomplete` | Admin Market Asset Query | `dedicated / needs_verification` |
|
||||
| `adminGetMarketAsset` | GET | `/admin-api/muse/market/assets/{assetId}` | `generic_persistence / incomplete` | Admin Market Asset Query | `dedicated / needs_verification` |
|
||||
| `adminPreviewGovernanceImpact` | POST | `/admin-api/muse/market/assets/{assetId}/governance-impact` | `generic_persistence / incomplete` | Admin Governance Command | `dedicated / needs_verification` |
|
||||
| `adminDelistAsset` | POST | `/admin-api/muse/market/assets/{assetId}/delist` | `generic_persistence / incomplete` | Admin Governance Command | `dedicated / needs_verification` |
|
||||
| `adminRecallAsset` | POST | `/admin-api/muse/market/assets/{assetId}/recall` | `generic_persistence / incomplete` | Admin Governance Command | `dedicated / needs_verification` |
|
||||
| `adminListPublishRequests` | GET | `/admin-api/muse/market/publish-requests` | `generic_persistence / incomplete` | Admin Publish Review Query | `dedicated / needs_verification` |
|
||||
| `adminApprovePublishRequest` | POST | `/admin-api/muse/market/publish-requests/{requestId}/approve` | `generic_persistence / incomplete` | Admin Publish Review Command | `dedicated / needs_verification` |
|
||||
| `adminRejectPublishRequest` | POST | `/admin-api/muse/market/publish-requests/{requestId}/reject` | `generic_persistence / incomplete` | Admin Publish Review Command | `dedicated / needs_verification` |
|
||||
| `adminListAppeals` | GET | `/admin-api/muse/market/appeals` | `generic_persistence / incomplete` | Admin Appeal Query | `dedicated / needs_verification` |
|
||||
| `adminGetAppeal` | GET | `/admin-api/muse/market/appeals/{appealId}` | `generic_persistence / incomplete` | Admin Appeal Query | `dedicated / needs_verification` |
|
||||
| `adminResolveAppeal` | POST | `/admin-api/muse/market/appeals/{appealId}/resolve` | `generic_persistence / incomplete` | Admin Appeal Command | `dedicated / needs_verification` |
|
||||
|
||||
## 6. 目标架构
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
APP[App Market Controllers] --> SVC[Market Application Services]
|
||||
ADM[Admin Market Controllers] --> SVC
|
||||
SVC --> CMD[Market Command Service]
|
||||
SVC --> ASSET[Asset and Discovery Service]
|
||||
SVC --> LIC[License and Install Service]
|
||||
SVC --> HND[Handoff Service]
|
||||
SVC --> PUB[Publish Service]
|
||||
SVC --> GOV[Governance Service]
|
||||
SVC --> APL[Appeal Service]
|
||||
CMD --> DB[(Market Tables)]
|
||||
ASSET --> DB
|
||||
LIC --> DB
|
||||
HND --> DB
|
||||
PUB --> DB
|
||||
GOV --> DB
|
||||
APL --> DB
|
||||
LIC --> ACC[Account Projection Facade]
|
||||
HND --> AI[AI Owner Facade]
|
||||
HND --> KNO[Knowledge Owner Facade]
|
||||
HND --> CON[Content Owner Facade]
|
||||
GOV --> SRC[Source Status Propagation Facades]
|
||||
```
|
||||
|
||||
## 7. 关键设计
|
||||
|
||||
### 7.1 Market 是来源授权 owner,不是目标事实 owner
|
||||
|
||||
Market 只能输出:
|
||||
|
||||
- 授权记录。
|
||||
- 安装记录。
|
||||
- 来源授权摘要。
|
||||
- 授权快照。
|
||||
- handoff token。
|
||||
- 治理影响和来源状态。
|
||||
|
||||
Market 不能直接输出:
|
||||
|
||||
- AI agent slot binding。
|
||||
- Knowledge binding。
|
||||
- Content work/block/canonical 写入。
|
||||
- 目标 owner precheck ID。
|
||||
|
||||
### 7.2 写命令必须幂等且可审计
|
||||
|
||||
所有写命令至少包含:
|
||||
|
||||
- `commandId`
|
||||
- `operationId`
|
||||
- `requestHash`
|
||||
- `actorUserId`
|
||||
- `ownerUserId`
|
||||
- `targetType`
|
||||
- `targetId` 或 `targetKey`
|
||||
- `correlationId`
|
||||
- `status`
|
||||
- `resultSnapshot`
|
||||
|
||||
相同 `commandId` + 相同 `requestHash` 返回同一业务结果;相同 `commandId` + 不同 `requestHash` 必须冲突。
|
||||
|
||||
### 7.3 授权、安装和 handoff 不可互相替代
|
||||
|
||||
`purchaseAsset`:
|
||||
|
||||
- 校验资产可获取、许可可用、治理策略允许新获取。
|
||||
- 写 `muse_market_purchase` 和授权快照。
|
||||
- 投影给 Account。
|
||||
- 不安装、不绑定。
|
||||
|
||||
`installMarketplaceAsset`:
|
||||
|
||||
- 消费有效授权。
|
||||
- 写 `muse_market_installation`。
|
||||
- 不写目标 owner。
|
||||
- Account 投影采用既有 member owner 契约:Market 实现只写 V11 已有 `muse_account_record_projection` 读模型,并提供 member 侧 `MarketAccountProjectionFacade` 的真实 provider;Market 侧追加表只允许表达投影同步/outbox 状态,不能另建第二套 Account 查询读模型。
|
||||
|
||||
`createBindPrecheck` / `createMarketplaceHandoff`:
|
||||
|
||||
- 消费有效安装和来源状态。
|
||||
- 生成来源侧授权摘要、授权快照和 token。
|
||||
- 不创建目标 owner 的预检或绑定事实。
|
||||
|
||||
### 7.4 发布审核是硬门槛
|
||||
|
||||
`savePublishDraft` 只保存草稿。
|
||||
|
||||
`runPublishCheck` 只产出有有效期的检查结果。
|
||||
|
||||
`submitPublishRequest` 必须消费未过期且匹配草稿版本/材料 hash 的检查结果。
|
||||
|
||||
`adminApprovePublishRequest` 才能让资产版本进入上架可见状态。
|
||||
|
||||
### 7.5 治理动作必须有影响预览和传播边界
|
||||
|
||||
下架和召回前必须生成 `impactPreviewId`,并记录受影响:
|
||||
|
||||
- 授权。
|
||||
- 安装。
|
||||
- handoff。
|
||||
- 目标 owner 绑定摘要。
|
||||
- 运行中任务。
|
||||
- Shadow 候选。
|
||||
- Knowledge Draft。
|
||||
- 导出限制。
|
||||
|
||||
传播给 AI、Knowledge、Content、Account 时只能通过 facade 或 projection;目标 owner 不可用时必须记录 `blocked`,不能伪造成已传播。需要重验时只能写入 action policy / recheck reasons,不能把 `needs_recheck` 写成 Market `SourceStatus`,因为合同内 `SourceStatus` 只表达来源可用性。
|
||||
|
||||
### 7.6 申诉只能处理治理事实
|
||||
|
||||
申诉处理读取申诉材料、资产、治理动作和发布申请,不读取用户私有副本正文。补充材料必须脱敏,禁止记录密钥或无关正文全文。
|
||||
|
||||
## 8. 验收标准
|
||||
|
||||
P1R-6 实现阶段完成后,必须满足:
|
||||
|
||||
1. Market 32 个 operation 全部为 `dedicated / needs_verification`。
|
||||
2. AI 41 和 Knowledge 59 继续保持 `dedicated / completed`。
|
||||
3. Content 51、Meta 16、Account 33 继续保持 `dedicated / needs_verification`。
|
||||
4. Events 仍只有 P1R-7 `streamEvents` 为 `sse_placeholder / incomplete`。
|
||||
5. `completedOperations` 仍为 100,除非后续有真实端到端验收证据并获得单独批准。
|
||||
6. `docs/api-contracts/market/openapi.yaml` 无 diff。
|
||||
7. `muse-cloud/scripts/p1r-audit-api-coverage.py` 不为 Market 特判 `completed`。
|
||||
8. 若新增 V15,必须通过真实 PostgreSQL / Flyway `_test` 迁移验收。
|
||||
|
||||
## 9. Review gate 待检查项
|
||||
|
||||
Spec review 应重点检查:
|
||||
|
||||
1. Market 是否没有越权写 AI / Knowledge / Content 目标事实。
|
||||
2. 购买、安装、handoff 是否分层清楚。
|
||||
3. 发布检查、审核和上架是否没有被压扁成一个开关。
|
||||
4. 下架/召回是否包含影响预览、传播和审计。
|
||||
5. 申诉是否没有读取私有副本。
|
||||
|
||||
Quality review 应重点检查:
|
||||
|
||||
1. 是否能按小任务拆实现。
|
||||
2. 是否有足够的 gate test 和 focused tests。
|
||||
3. 是否避免大而全抽象。
|
||||
4. 是否保持 OpenAPI、coverage 和实现三者一致。
|
||||
5. 是否明确失败、重试、幂等和回滚边界。
|
||||
Loading…
x
Reference in New Issue
Block a user