docs(p1r): 记录 Account 真实 API 收口
This commit is contained in:
parent
0dcaa9f581
commit
7c92a493d8
261
docs/memorys/2026-05-28-P1R3账户真实API规格计划.md
Normal file
261
docs/memorys/2026-05-28-P1R3账户真实API规格计划.md
Normal file
@ -0,0 +1,261 @@
|
||||
# P1R3 账户真实 API 规格计划
|
||||
|
||||
日期:2026-05-28
|
||||
|
||||
## 背景
|
||||
|
||||
本次进入 P1R-3 Account Real API spec + plan 阶段,只完成 Account 域真实 API 的事实盘点、规格和执行计划,不进入代码实现。
|
||||
|
||||
P1R-3 的核心不是继续增强 `MuseContractPersistenceService`,也不是把 `generic_persistence` 包装成业务结果,而是把 Account 域从“通用持久化可响应”推进到“真实账户业务 API 可验收”的规格和计划阶段。
|
||||
|
||||
## 执行位置
|
||||
|
||||
```text
|
||||
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
|
||||
```
|
||||
|
||||
分支:
|
||||
|
||||
```text
|
||||
dev/1.0.0
|
||||
```
|
||||
|
||||
本阶段开始和收口时,工作树只包含本阶段新增文档改动,没有实现代码改动。
|
||||
|
||||
## 已验证事实
|
||||
|
||||
P1R 覆盖矩阵中 Account 域当前状态:
|
||||
|
||||
```text
|
||||
33 generic_persistence / incomplete
|
||||
```
|
||||
|
||||
同时保持:
|
||||
|
||||
- completed operations = 0
|
||||
- Content 51 个 operation 为 `dedicated / needs_verification`
|
||||
- Meta 16 个 operation 为 `dedicated / needs_verification`
|
||||
|
||||
当前代码事实:
|
||||
|
||||
- 仓库没有 `muse-cloud/muse-module-account/**`。
|
||||
- Account 当前真实 owner 应落在 `muse-module-member` 的 Account 子域。
|
||||
- 当前 Account 合同入口仍是 `AdminMuseAccountContractController` 和 `AppMuseAccountContractController`。
|
||||
- 两个 Controller 仍通过 `MuseContractPersistenceService` 通用持久化处理 Account 路由,不是 P1R 完成证据。
|
||||
|
||||
当前 DDL 事实:
|
||||
|
||||
- V2 已有 `muse_member_entitlement`、`muse_member_entitlement_audit_log`、`muse_member_quota`、`muse_member_usage_record`、`muse_member_security_event`、`muse_member_new_api_binding`。
|
||||
- P1R-3 计划新增 `muse_account_profile`、`muse_account_audit`、`muse_account_command`、`muse_account_balance_snapshot`、`muse_account_quota_request`、`muse_account_integration_call`、`muse_account_call_attribution_job`、`muse_account_call_attribution_item`、`muse_account_export_task`、`muse_account_download_credential`、`muse_account_security_event_ack`、`muse_account_record_projection`。
|
||||
- purchase / license / publish records 统一使用 `muse_account_record_projection(record_type=...)` 作为 Account 视角读模型,不在 P1R-3 实现 Market 主流程。
|
||||
|
||||
## 本阶段产物
|
||||
|
||||
- 规格:`docs/superpowers/specs/2026-05-28-P1R-3-account-real-api-design.md`
|
||||
- 计划:`docs/superpowers/plans/2026-05-28-P1R-3-account-real-api.md`
|
||||
|
||||
## 关键设计结论
|
||||
|
||||
- P1R-3 目标状态只能是 `dedicated / needs_verification`,不能写成 `completed`。
|
||||
- Account owner 采用 `muse-module-member/account` 子域,不新增孤立 `muse-module-account`。
|
||||
- `muse_account_profile` 承载 profile 扩展事实和 `expectedVersion` 乐观锁,不污染 `member_user`。
|
||||
- `muse_account_audit` 与 `muse_account_command` 是 commandId 幂等、requestHash 冲突和审计的必需基础设施。
|
||||
- New-API binding / recheck 必须写内部 integration call,并通过 `bindingId` / `jobId` 关联 `correlationId`;现有 OpenAPI 响应不新增 `correlationId`。
|
||||
- New-API、call attribution、FileService unavailable 只能通过合同内业务错误、内部 job 状态或 OpenAPI 已声明状态表达,不能返回未声明的 `pending` 等状态,也不能 fake success。
|
||||
- `appDownloadExport` 成功响应按 OpenAPI 返回 `application/octet-stream`,错误响应仍走统一 `code/data/msg`。
|
||||
- AI runtime / task / SSE、Knowledge / RAGFlow、Market 主流程、统一 Events SSE 均不属于 P1R-3。
|
||||
|
||||
## Review 结果
|
||||
|
||||
本阶段使用 fresh subagent 做了两轮文档 review,并按 review 结果修正后复审通过。
|
||||
|
||||
Spec compliance review 最终结果:
|
||||
|
||||
```text
|
||||
SPEC REVIEW PASS
|
||||
```
|
||||
|
||||
Quality review 最终结果:
|
||||
|
||||
```text
|
||||
QUALITY REVIEW PASS
|
||||
```
|
||||
|
||||
过程中修正的关键问题:
|
||||
|
||||
- 补齐 New-API binding create / recheck inline requestBody 的 typed VO。
|
||||
- 明确 unavailable / failed / pending 等内部状态不得进入 OpenAPI 未声明 response status。
|
||||
- 将 app quota request DTO 改为 `AppQuotaRequestCreateReqVO`,避免复用 admin DTO。
|
||||
- 增加 `UnavailableNewApiAccountFacade`、`UnavailableMarketAccountProjectionFacade`、`UnavailableAccountFileServiceFacade` 的默认边界和测试要求。
|
||||
- 移除会诱导创建独立 AI / Knowledge facade 的过宽表述,AI / Knowledge 只通过 attribution source unavailable 边界表达。
|
||||
- 移除 `-Dsurefire.failIfNoSpecifiedTests=false`,并要求关键指定测试命令用 `test -f` 防止缺失测试被掩盖。
|
||||
|
||||
## 当前阶段边界
|
||||
|
||||
本阶段只完成规格、计划、review 和 memory 留痕,没有实现代码。
|
||||
|
||||
未修改:
|
||||
|
||||
- `docs/api-contracts/account/openapi.yaml`
|
||||
- `docs/superpowers/reports/p1r-api-coverage.*`
|
||||
- `muse-cloud/scripts/**`
|
||||
- `muse-cloud/muse-module-member/**` 实现代码
|
||||
- `muse-cloud/sql/muse/**`
|
||||
|
||||
当前不应把任何 Account operation 标为 `completed`。
|
||||
|
||||
## 残余风险
|
||||
|
||||
- 未运行真实 PostgreSQL / Flyway 验证,P1R-3 DDL 仍需实现阶段验证。
|
||||
- 未接真实 New-API runtime,binding / recheck / quota request 仍需保持 `needs_verification`。
|
||||
- 未接真实 FileService runtime,export task / download credential 仍需保持 `needs_verification`。
|
||||
- 外部 Market / Content / AI / Knowledge owner 未闭合时,purchase / license / publish / attribution 只能走 Account 读模型和 unavailable 边界,不能标为 completed。
|
||||
|
||||
## 下一步(规格计划阶段记录)
|
||||
|
||||
进入 P1R-3 实现前,应从 `docs/superpowers/plans/2026-05-28-P1R-3-account-real-api.md` Task 1 开始,按 fresh subagent + spec compliance review + quality review 执行。
|
||||
|
||||
实现阶段完成口径:
|
||||
|
||||
- Account 33 个 operation 退出 `generic_persistence`。
|
||||
- Account 33 个 operation 全部为 `dedicated / needs_verification`。
|
||||
- Content 51 个 operation 保持 `dedicated / needs_verification`。
|
||||
- Meta 16 个 operation 保持 `dedicated / needs_verification`。
|
||||
- 不修改脚本掩盖缺口。
|
||||
- 不把 Account 标为 `completed`。
|
||||
|
||||
## 2026-05-29 实现阶段收口更新
|
||||
|
||||
### 实现任务范围
|
||||
|
||||
本轮实现阶段在以下真实 worktree 执行:
|
||||
|
||||
```text
|
||||
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
|
||||
```
|
||||
|
||||
`4d9a242..HEAD` 已覆盖 P1R-3 Task 1-12:
|
||||
|
||||
1. Preflight 与覆盖基线冻结。
|
||||
2. Account 基础设施与 V11 追加 DDL。
|
||||
3. DTO / DAL / Mapper 骨架。
|
||||
4. App `me` / `profile` 与 Admin 用户摘要。
|
||||
5. 权益、配额、余额、用量。
|
||||
6. New-API binding、recheck、quota request、integration call。
|
||||
7. call attribution job。
|
||||
8. purchase / license / publish records Account 投影。
|
||||
9. security events。
|
||||
10. export task / download credential。
|
||||
11. Account 合同兜底退役。
|
||||
12. P1R-3 覆盖门禁与报告对账。
|
||||
|
||||
Task 10 最新事实:
|
||||
|
||||
- 已新增 Account export/download Controller、Service、FileService facade、unavailable facade、凭证与导出任务相关 DAL 和测试。
|
||||
- 下载凭证边界覆盖 credential hash、owner、expiresAt、revoked、consumed、source blocked。
|
||||
- 高敏导出在缺少可信 step-up 证明时 fail closed。
|
||||
- `appDownloadExport` 成功响应按 OpenAPI 返回 `application/octet-stream`;错误仍走统一 `code/data/msg`。
|
||||
- unavailable FileService 不返回伪造文件流。
|
||||
|
||||
Task 11 最新事实:
|
||||
|
||||
- 已删除旧 Account 合同兜底 Controller。
|
||||
- 已新增 `P1rAccountRouteOwnershipTest`,证明 33 个 P1R-3 Account 路由进入 dedicated Controller,不再回落到 `MuseContractPersistenceService`。
|
||||
|
||||
Task 12 最新事实:
|
||||
|
||||
- 已新增 `P1rAccountRealApiGateTest`。
|
||||
- 已更新 `docs/superpowers/reports/p1r-api-coverage.json` 和 `docs/superpowers/reports/p1r-api-coverage.md`。
|
||||
- Account 33 个 operation 统一收口到 `dedicated / needs_verification`,仍保留真实运行态验收缺口。
|
||||
|
||||
### Coverage 前后状态
|
||||
|
||||
实现起点 `4d9a242`:
|
||||
|
||||
```text
|
||||
Account 33 generic_persistence / incomplete
|
||||
Content 51 dedicated / needs_verification
|
||||
Meta 16 dedicated / needs_verification
|
||||
```
|
||||
|
||||
当前 `HEAD`:
|
||||
|
||||
```text
|
||||
Account 33 dedicated / needs_verification
|
||||
Content 51 dedicated / needs_verification
|
||||
Meta 16 dedicated / needs_verification
|
||||
```
|
||||
|
||||
该状态只证明仓库内 dedicated 入口、覆盖报告和门禁已收口,不代表 PostgreSQL / Flyway、New-API、FileService 或端到端运行态已验收。
|
||||
|
||||
### Review 结果
|
||||
|
||||
本轮实现按计划要求在每个实现 Task 后执行:
|
||||
|
||||
1. spec compliance review。
|
||||
2. code quality review。
|
||||
|
||||
已记录的收口事实:
|
||||
|
||||
- Task 10 在修正高敏导出 fail-closed、导出凭证消费边界、HMAC 凭证派生和 FileService 异常处理后,spec compliance review 与 code quality review 均通过。
|
||||
- Task 11 的 spec compliance review 与 code quality review 均通过。
|
||||
- Task 12 的 spec compliance review 与 code quality review 均通过。
|
||||
|
||||
这些 review 结果只证明 P1R-3 代码、报告和门禁符合当前 spec / plan,不代表外部 runtime owner 已闭合。
|
||||
|
||||
### 测试命令和结果
|
||||
|
||||
本阶段已记录的验证命令与结果:
|
||||
|
||||
```bash
|
||||
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
|
||||
```
|
||||
|
||||
结果:通过;覆盖报告保持 Account 33、Content 51、Meta 16 均为 `dedicated / needs_verification`。
|
||||
|
||||
```bash
|
||||
cd muse-cloud
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRealApiGateTest.java
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRouteOwnershipTest.java
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rApiCoverageReportTest.java
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rContentRealApiGateTest.java
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMetaRealApiGateTest.java
|
||||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||||
mvn -o test -pl muse-server -am \
|
||||
-Dtest=P1rApiCoverageReportTest,P1rContentRealApiGateTest,P1rMetaRealApiGateTest,P1rAccountRealApiGateTest,P1rAccountRouteOwnershipTest \
|
||||
-Dsurefire.failIfNoSpecifiedTests=false
|
||||
```
|
||||
|
||||
结果:通过,22 tests,0 failures。
|
||||
|
||||
说明:原计划中的 `-pl muse-server -am -Dtest=...` 命令在上游 reactor 模块没有同名测试时会触发 `failIfNoSpecifiedTests` 问题。本轮通过 `test -f` 先校验目标测试存在,再局部追加 `-Dsurefire.failIfNoSpecifiedTests=false` 避免上游模块误失败;这不是全局放宽测试缺失门禁。
|
||||
|
||||
```bash
|
||||
cd muse-cloud
|
||||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||||
mvn -o test -pl muse-module-member/muse-module-member-server -am
|
||||
```
|
||||
|
||||
结果:通过,member-server 272 tests,0 failures。
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
```
|
||||
|
||||
结果:通过,无空白错误输出。
|
||||
|
||||
### 未验证 runtime 风险
|
||||
|
||||
- 未验证真实 PostgreSQL / Flyway 执行,V11 仍需在真实数据库迁移链路确认。
|
||||
- 未接真实 New-API runtime,binding / recheck / quota request / integration call 仍保持 `needs_verification`。
|
||||
- 未接真实 FileService,export task / download credential 只能证明边界和状态机,不能证明真实文件交付。
|
||||
- Market / AI / Knowledge owner 未闭合,purchase / license / publish / attribution 只能走 Account 投影或 unavailable 边界。
|
||||
- 端到端 auth、错误响应、SSE 与跨域 runtime 行为仍需后续阶段验收。
|
||||
|
||||
### 变更面记录
|
||||
|
||||
- OpenAPI:未修改 `docs/api-contracts/account/openapi.yaml`。
|
||||
- Scanner:未修改 `muse-cloud/scripts/**`。
|
||||
- SQL:新增 `muse-cloud/sql/muse/V11__extend_account_real_api_schema.sql`。
|
||||
- Java:新增 Account Controller / Service / DTO / VO / DAL / Mapper / Facade / Guard / AutoConfiguration 及 P1R gate tests;删除旧 Account 合同兜底 Controller。
|
||||
- Coverage:更新 `docs/superpowers/reports/p1r-api-coverage.json` 和 `docs/superpowers/reports/p1r-api-coverage.md`。
|
||||
895
docs/superpowers/plans/2026-05-28-P1R-3-account-real-api.md
Normal file
895
docs/superpowers/plans/2026-05-28-P1R-3-account-real-api.md
Normal file
@ -0,0 +1,895 @@
|
||||
# P1R-3 Account 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:** 将 Account 33 个 operation 从 `generic_persistence / incomplete` 推进到专用 Account Controller / Service / DTO / DAL / DDL / 测试可验收的 `dedicated / needs_verification`。
|
||||
|
||||
**Architecture:** 以 `muse-module-member` 内 Account 子域为 owner,新增 Account 专用 app/admin 入口和应用服务。通用 `MuseContractPersistenceService` 只能作为迁移保护网,不能作为 P1R-3 完成路径;New-API、Market、AI、Knowledge、FileService 等外部 owner 不可用时返回合同内 `CommonResult` 业务错误或 pending job,不伪造完成。
|
||||
|
||||
**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:** 2026-05-29 已按 Task 1-12 执行并完成 review 收口;Account 33 个 operation 当前为 `dedicated / needs_verification`,真实 runtime owner 未闭合前不得写成 `completed`。实现阶段留痕见 `docs/memorys/2026-05-28-P1R3账户真实API规格计划.md`。
|
||||
|
||||
---
|
||||
|
||||
## 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` 的 `feature/p1-muse-cloud-backend-20260524` checkout 上落实现。
|
||||
- 不修改 `muse-cloud/scripts/**` 来改变 P1R 判断口径。
|
||||
- 不修改 `docs/api-contracts/account/openapi.yaml`,除非先单独说明合同纠偏原因、影响范围和迁移风险。
|
||||
- 不破坏 Content 当前 51 个 `dedicated / needs_verification`。
|
||||
- 不破坏 Meta 当前 16 个 `dedicated / needs_verification`。
|
||||
- 不把 Account operation 标为 `completed`。
|
||||
- 本文件是后续实现阶段的执行计划;本次 P1R-3 规格计划会话只产出 spec + plan + review + memory,收到实现指令后必须按 Task 1-12 执行。
|
||||
|
||||
## 1. 当前事实盘点
|
||||
|
||||
| operationId | Method | Path | 当前状态 | 当前实现 owner | 计划处理 |
|
||||
|---|---|---|---|---|---|
|
||||
| `adminListAccountUsers` | GET | `/admin-api/muse/account/users` | `generic_persistence / incomplete` | `AdminMuseAccountContractController` + `MuseContractPersistenceService` | Task 4 |
|
||||
| `adminGetUserEntitlements` | GET | `/admin-api/muse/account/users/{userId}/entitlements` | `generic_persistence / incomplete` | 同上 | Task 5 |
|
||||
| `adminCreateQuotaAdjustment` | POST | `/admin-api/muse/account/users/{userId}/quota-adjustments` | `generic_persistence / incomplete` | 同上 | Task 5 |
|
||||
| `adminListQuotaAdjustments` | GET | `/admin-api/muse/account/users/{userId}/quota-adjustments` | `generic_persistence / incomplete` | 同上 | Task 5 |
|
||||
| `adminListNewApiBindings` | GET | `/admin-api/muse/account/new-api-bindings` | `generic_persistence / incomplete` | 同上 | Task 6 |
|
||||
| `adminCreateNewApiBinding` | POST | `/admin-api/muse/account/users/{userId}/new-api-binding` | `generic_persistence / incomplete` | 同上 | Task 6 |
|
||||
| `adminCreateQuotaRequest` | POST | `/admin-api/muse/account/users/{userId}/quota-requests` | `generic_persistence / incomplete` | 同上 | Task 6 |
|
||||
| `adminGetBalanceSnapshots` | GET | `/admin-api/muse/account/users/{userId}/balance-snapshots` | `generic_persistence / incomplete` | 同上 | Task 5 |
|
||||
| `adminCreateCallAttributionJob` | POST | `/admin-api/muse/account/call-attribution-jobs` | `generic_persistence / incomplete` | 同上 | Task 7 |
|
||||
| `adminGetCallAttributionJob` | GET | `/admin-api/muse/account/call-attribution-jobs/{jobId}` | `generic_persistence / incomplete` | 同上 | Task 7 |
|
||||
| `adminGetIntegrationCallByCorrelation` | GET | `/admin-api/muse/account/integration-calls/by-correlation/{correlationId}` | `generic_persistence / incomplete` | 同上 | Task 6 |
|
||||
| `adminListUsageRecords` | GET | `/admin-api/muse/account/usage-records` | `generic_persistence / incomplete` | 同上 | Task 5 |
|
||||
| `adminListPurchaseRecords` | GET | `/admin-api/muse/account/purchase-records` | `generic_persistence / incomplete` | 同上 | Task 8 |
|
||||
| `getCurrentUser` | GET | `/app-api/muse/me` | `generic_persistence / incomplete` | `AppMuseAccountContractController` + `MuseContractPersistenceService` | Task 4 |
|
||||
| `getProfile` | GET | `/app-api/muse/profile` | `generic_persistence / incomplete` | 同上 | Task 4 |
|
||||
| `updateProfile` | PATCH | `/app-api/muse/profile` | `generic_persistence / incomplete` | 同上 | Task 4 |
|
||||
| `getAppEntitlements` | GET | `/app-api/muse/account/entitlements` | `generic_persistence / incomplete` | 同上 | Task 5 |
|
||||
| `getAppUsage` | GET | `/app-api/muse/account/usage` | `generic_persistence / incomplete` | 同上 | Task 5 |
|
||||
| `getAppNewApiBinding` | GET | `/app-api/muse/account/new-api-binding` | `generic_persistence / incomplete` | 同上 | Task 6 |
|
||||
| `appRecheckNewApiBinding` | POST | `/app-api/muse/account/new-api-binding/recheck` | `generic_persistence / incomplete` | 同上 | Task 6 |
|
||||
| `getAppBalanceSnapshots` | GET | `/app-api/muse/account/balance-snapshots` | `generic_persistence / incomplete` | 同上 | Task 5 |
|
||||
| `appCreateQuotaRequest` | POST | `/app-api/muse/account/quota-requests` | `generic_persistence / incomplete` | 同上 | Task 6 |
|
||||
| `appGetQuotaRequest` | GET | `/app-api/muse/account/quota-requests/{requestId}` | `generic_persistence / incomplete` | 同上 | Task 6 |
|
||||
| `appGetIntegrationCallByCorrelation` | GET | `/app-api/muse/account/integration-calls/by-correlation/{correlationId}` | `generic_persistence / incomplete` | 同上 | Task 6 |
|
||||
| `appListPurchases` | GET | `/app-api/muse/account/purchases` | `generic_persistence / incomplete` | 同上 | Task 8 |
|
||||
| `appListLicenses` | GET | `/app-api/muse/account/licenses` | `generic_persistence / incomplete` | 同上 | Task 8 |
|
||||
| `appListPublishRecords` | GET | `/app-api/muse/account/publish-records` | `generic_persistence / incomplete` | 同上 | Task 8 |
|
||||
| `appListSecurityEvents` | GET | `/app-api/muse/account/security-events` | `generic_persistence / incomplete` | 同上 | Task 9 |
|
||||
| `appGetSecurityEvent` | GET | `/app-api/muse/account/security-events/{eventId}` | `generic_persistence / incomplete` | 同上 | Task 9 |
|
||||
| `appAcknowledgeSecurityEvent` | POST | `/app-api/muse/account/security-events/{eventId}/acknowledge` | `generic_persistence / incomplete` | 同上 | Task 9 |
|
||||
| `appCreateExportTask` | POST | `/app-api/muse/account/export-tasks` | `generic_persistence / incomplete` | 同上 | Task 10 |
|
||||
| `appGetExportTask` | GET | `/app-api/muse/account/export-tasks/{taskId}` | `generic_persistence / incomplete` | 同上 | Task 10 |
|
||||
| `appDownloadExport` | GET | `/app-api/muse/account/downloads/{credentialId}` | `generic_persistence / incomplete` | 同上 | Task 10 |
|
||||
|
||||
## 2. 目标文件结构
|
||||
|
||||
| 操作 | 路径 | 责任 |
|
||||
|---|---|---|
|
||||
| Modify | `muse-cloud/muse-module-member/muse-module-member-server/pom.xml` | 确认已有 validation/security/mybatis/test 依赖,按需补测试依赖 |
|
||||
| Create | `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/*.java` | Account 管理端 dedicated API |
|
||||
| Create | `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/*.java` | Account 用户端 dedicated API |
|
||||
| Modify | `AdminMuseAccountContractController.java` | 移除或避让 P1R-3 已 dedicated 路径 |
|
||||
| Modify | `AppMuseAccountContractController.java` | 移除或避让 P1R-3 已 dedicated 路径 |
|
||||
| Create | `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/*/account/vo/*.java` | Account OpenAPI DTO |
|
||||
| Create | `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/*.java` | Account 应用服务 |
|
||||
| Create | `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/*.java` | New-API / Market projection / FileService / AttributionSource 外部边界;AI / Knowledge 只能经 `AccountAttributionSourceFacade` 的 unavailable 默认实现表达,不新增独立 AI / Knowledge facade |
|
||||
| Create | `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/domain/account/*.java` | version、owner、permission、quota、download guard |
|
||||
| Create | `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/*.java` | Account DO |
|
||||
| Create | `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/*.java` | Account Mapper |
|
||||
| Create | `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/convert/account/AccountConvert.java` | DO/facade 到 VO 组装 |
|
||||
| Modify | `muse-cloud/muse-module-member/muse-module-member-api/src/main/java/cn/iocoder/muse/module/member/enums/ErrorCodeConstants.java` | Account 错误码 |
|
||||
| Create | `muse-cloud/sql/muse/V11__extend_account_real_api_schema.sql` | Account 真实 API 追加表和约束 |
|
||||
| Create | `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRealApiGateTest.java` | P1R-3 阶段门禁 |
|
||||
|
||||
## 3. 子代理执行规则
|
||||
|
||||
每个 Task 使用 fresh subagent,模型 `gpt-5.5`,reasoning `xhigh`,等待超时 30 分钟。
|
||||
|
||||
每个实现 Task 完成后必须两轮 review:
|
||||
|
||||
1. spec compliance review:检查是否符合 `docs/superpowers/specs/2026-05-28-P1R-3-account-real-api-design.md` 和本计划。
|
||||
2. code quality review:检查最小改动、可维护性、测试质量、无脚本掩盖。
|
||||
|
||||
review 未通过不能进入下一 Task。所有 review 发现的问题必须由新的修复子代理处理,再重新 review。
|
||||
|
||||
## Task 1: Preflight 与覆盖基线冻结
|
||||
|
||||
**Files:**
|
||||
|
||||
- Read: `docs/superpowers/reports/p1r-api-coverage.json`
|
||||
- Read: `docs/superpowers/reports/p1r-api-coverage.md`
|
||||
- Read: `docs/api-contracts/account/openapi.yaml`
|
||||
- Read: `muse-cloud/muse-module-member/**`
|
||||
- Read: `muse-cloud/sql/muse/**`
|
||||
|
||||
- [ ] **Step 1: 核实工作面**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git status --short --branch
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
## dev/1.0.0...origin/dev/1.0.0
|
||||
```
|
||||
|
||||
除本规格、本计划和本阶段 memory 尚未提交时可能出现的文档外,无其他输出。
|
||||
|
||||
- [ ] **Step 2: 统计 Account operation 状态**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
jq -r '[.operations[] | select(.targetStage == "P1R-3 Account Real API" or .domain == "account")] | group_by(.implementationStatus + "/" + .completionStatus)[] | [(.[0].implementationStatus + "/" + .[0].completionStatus), length] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
generic_persistence/incomplete 33
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 冻结 operation 清单**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
jq -r '.operations[] | select(.targetStage == "P1R-3 Account Real API" or .domain == "account") | [.operationId, .method, .path, .implementationStatus, .completionStatus] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
|
||||
```
|
||||
|
||||
Expected: 输出 33 行,且 operationId 与本计划第 1 节完全一致。
|
||||
|
||||
- [ ] **Step 4: 检查脚本目录无改动**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git status --short -- muse-cloud/scripts
|
||||
```
|
||||
|
||||
Expected: 无输出。
|
||||
|
||||
## Task 2: Account 基础设施与 DDL
|
||||
|
||||
**Files:**
|
||||
|
||||
- Read/Modify: `muse-cloud/muse-module-member/muse-module-member-server/pom.xml`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/domain/account/AccountApiVersionGuard.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/domain/account/AccountOwnerGuard.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/domain/account/AccountQuotaGuard.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/domain/account/AccountDownloadGuard.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountCommandService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountCommandServiceImpl.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountAuditService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountAuditServiceImpl.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-api/src/main/java/cn/iocoder/muse/module/member/enums/ErrorCodeConstants.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountCommandDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountAuditDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountCommandMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountAuditMapper.java`
|
||||
- Create: `muse-cloud/sql/muse/V11__extend_account_real_api_schema.sql`
|
||||
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountMigrationSqlTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/domain/account/AccountApiVersionGuardTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/domain/account/AccountOwnerGuardTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/domain/account/AccountQuotaGuardTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/domain/account/AccountDownloadGuardTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountCommandServiceTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountAuditServiceTest.java`
|
||||
|
||||
- [ ] **Step 1: 确认模块依赖**
|
||||
|
||||
`muse-module-member-server/pom.xml` 已有:
|
||||
|
||||
- `muse-spring-boot-starter-security`
|
||||
- `muse-spring-boot-starter-mybatis`
|
||||
- `spring-boot-starter-validation`
|
||||
- `muse-spring-boot-starter-test`
|
||||
|
||||
如需新增依赖,先说明原因。
|
||||
|
||||
- [ ] **Step 2: 增加 Account 错误码**
|
||||
|
||||
在 `ErrorCodeConstants.java` 增加本阶段使用的 Account 错误码,至少覆盖 `ACCOUNT_API_VERSION_UNSUPPORTED`、`ACCOUNT_USER_NOT_EXISTS`、`ACCOUNT_RESOURCE_FORBIDDEN`、`ACCOUNT_COMMAND_ID_REQUIRED`、`ACCOUNT_COMMAND_ID_CONFLICT`、`ACCOUNT_VERSION_CONFLICT`、`ACCOUNT_NEW_API_BINDING_NOT_EXISTS`、`ACCOUNT_NEW_API_UNAVAILABLE`、`ACCOUNT_INTEGRATION_CALL_NOT_EXISTS`、`ACCOUNT_QUOTA_EXHAUSTED`、`ACCOUNT_DOWNLOAD_CREDENTIAL_INVALID`、`ACCOUNT_EXPORT_SOURCE_BLOCKED`。
|
||||
|
||||
- [ ] **Step 3: 实现 API version guard**
|
||||
|
||||
`AccountApiVersionGuard.requireVersion(String version)` 只接受 `"1"`,缺失或未知版本抛 `ACCOUNT_API_VERSION_UNSUPPORTED`。
|
||||
|
||||
- [ ] **Step 4: 实现 command service**
|
||||
|
||||
规则:
|
||||
|
||||
- `buildRequestHash(Object payload)` 使用稳定 JSON + SHA-256。
|
||||
- `reserveCommand(...)` 预占 commandId。
|
||||
- `getReplayCommand(...)` 相同 hash 返回旧记录。
|
||||
- 相同 commandId 不同 hash 抛 `ACCOUNT_COMMAND_ID_CONFLICT`。
|
||||
- envelope 必须校验 operationId、actor、owner、targetType、targetId。
|
||||
|
||||
- [ ] **Step 5: 实现 audit service**
|
||||
|
||||
记录字段必须覆盖 spec 第 10 节,不记录 New-API token、Prompt/Response 全文、外部订单原文、敏感 IP 明文。
|
||||
|
||||
- [ ] **Step 6: 编写 V11 迁移**
|
||||
|
||||
至少新增:
|
||||
|
||||
- `muse_account_command`
|
||||
- `muse_account_audit`
|
||||
- `muse_account_profile`
|
||||
- `muse_account_balance_snapshot`
|
||||
- `muse_account_quota_request`
|
||||
- `muse_account_integration_call`
|
||||
- `muse_account_call_attribution_job`
|
||||
- `muse_account_call_attribution_item`
|
||||
- `muse_account_export_task`
|
||||
- `muse_account_download_credential`
|
||||
- `muse_account_security_event_ack`
|
||||
- `muse_account_record_projection`
|
||||
|
||||
关键约束:
|
||||
|
||||
- command 唯一键 `(tenant_id, command_id)`。
|
||||
- account audit 必须索引 `account_user_id`、`operation_id`、`correlation_id`。
|
||||
- account profile 必须以 `account_user_id` 唯一,并用 `profile_version` 支撑 `expectedVersion`。
|
||||
- record projection 必须用 `record_type` 区分 `purchase`、`license`、`publish`,并保存 `source_table` / `source_id` / `source_revision`。
|
||||
- app 可见事实必须索引 `account_user_id`。
|
||||
- correlation 查询必须索引 `correlation_id`。
|
||||
- download credential 必须 hash 存储,不落明文 token。
|
||||
|
||||
- [ ] **Step 7: 创建迁移 SQL 门禁测试**
|
||||
|
||||
`P1rAccountMigrationSqlTest` 至少校验:
|
||||
|
||||
- `V11__extend_account_real_api_schema.sql` 存在。
|
||||
- V11 包含 `muse_account_command`、`muse_account_audit`、`muse_account_profile`、`muse_account_balance_snapshot`、`muse_account_quota_request`、`muse_account_integration_call`、`muse_account_call_attribution_job`、`muse_account_call_attribution_item`、`muse_account_export_task`、`muse_account_download_credential`、`muse_account_security_event_ack`、`muse_account_record_projection`。
|
||||
- command 唯一键、profile version、record projection `record_type`、download credential hash、account owner 索引和 correlation 索引均存在。
|
||||
- 测试不得只检查文件名,必须检查关键表名和约束片段。
|
||||
|
||||
- [ ] **Step 8: 运行迁移 SQL 门禁**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
set -e
|
||||
cd muse-cloud
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountMigrationSqlTest.java
|
||||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||||
mvn -o test -pl muse-server -am \
|
||||
-Dtest=P1rAccountMigrationSqlTest
|
||||
```
|
||||
|
||||
Expected: V11 迁移表、索引、唯一键、hash credential 字段、profile version、audit 字段和 record projection 约束均通过门禁;若 `P1rAccountMigrationSqlTest` 不存在,必须失败。
|
||||
|
||||
- [ ] **Step 9: 运行聚焦测试**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
set -e
|
||||
cd muse-cloud
|
||||
test -f muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/domain/account/AccountApiVersionGuardTest.java
|
||||
test -f muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/domain/account/AccountOwnerGuardTest.java
|
||||
test -f muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/domain/account/AccountQuotaGuardTest.java
|
||||
test -f muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/domain/account/AccountDownloadGuardTest.java
|
||||
test -f muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountCommandServiceTest.java
|
||||
test -f muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountAuditServiceTest.java
|
||||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||||
mvn -o test -pl muse-module-member/muse-module-member-server -am \
|
||||
-Dtest=AccountApiVersionGuardTest,AccountOwnerGuardTest,AccountQuotaGuardTest,AccountDownloadGuardTest,AccountCommandServiceTest,AccountAuditServiceTest
|
||||
```
|
||||
|
||||
Expected: 测试通过。
|
||||
|
||||
## Task 3: DTO / DAL / Mapper 骨架
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminAccountUserSummaryRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminUserEntitlementDetailRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/QuotaAdjustmentReqVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/QuotaAdjustmentResultRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/QuotaAdjustmentLedgerEntryRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/NewApiBindingSummaryRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/NewApiBindingCreateReqVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/NewApiBindingResultRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminQuotaRequestCreateReqVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminQuotaRequestResultRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminBalanceSnapshotEntryRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminIntegrationCallDetailRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/CallAttributionJobCreateReqVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/CallAttributionJobResultRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/CallAttributionJobDetailRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminUsageRecordRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminPurchaseRecordRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppCurrentUserSummaryRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppProfileRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppProfileUpdateReqVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppEntitlementRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppUsageSummaryRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppNewApiBindingSummaryRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppNewApiBindingRecheckReqVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppNewApiBindingRecheckRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppQuotaRequestCreateReqVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppQuotaRequestResultRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/QuotaRequestStatusRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppBalanceSnapshotEntryRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppIntegrationCallDetailRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppPurchaseRecordRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppLicenseRecordRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppPublishRecordRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/SecurityEventSummaryRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/SecurityEventDetailRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/SecurityEventAcknowledgeReqVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/SecurityEventAcknowledgeResultRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AccountExportTaskCreateReqVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AccountExportTaskResultRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AccountExportTaskDetailRespVO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountProfileDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/MemberEntitlementDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/MemberEntitlementAuditLogDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/MemberQuotaDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/MemberUsageRecordDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/MemberSecurityEventDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/MemberNewApiBindingDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountBalanceSnapshotDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountQuotaRequestDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountIntegrationCallDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountCallAttributionJobDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountCallAttributionItemDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountRecordProjectionDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountSecurityEventAckDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountExportTaskDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountDownloadCredentialDO.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountProfileMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/MemberEntitlementMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/MemberEntitlementAuditLogMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/MemberQuotaMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/MemberUsageRecordMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/MemberSecurityEventMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/MemberNewApiBindingMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountBalanceSnapshotMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountQuotaRequestMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountIntegrationCallMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountCallAttributionJobMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountCallAttributionItemMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountRecordProjectionMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountSecurityEventAckMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountExportTaskMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountDownloadCredentialMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/convert/account/AccountConvert.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/convert/account/AccountConvertTest.java`
|
||||
|
||||
- [ ] **Step 1: 按 OpenAPI 创建 VO**
|
||||
|
||||
覆盖 spec 第 6.3 节列出的最小 DTO,命名与已有项目 VO 风格一致。
|
||||
|
||||
- [ ] **Step 2: 创建 DO / Mapper**
|
||||
|
||||
覆盖 V2 表和 V11 新表;V2 表包括 `muse_member_entitlement`、`muse_member_entitlement_audit_log`、`muse_member_quota`、`muse_member_usage_record`、`muse_member_security_event`、`muse_member_new_api_binding`。对 `member_user`、Market 上游来源只创建必要 Mapper 方法,不复制其他模块状态机。
|
||||
|
||||
- [ ] **Step 3: 创建 Account assembler**
|
||||
|
||||
统一处理 ID 字符串化、分页、脱敏、枚举映射、时间字段。
|
||||
|
||||
- [ ] **Step 4: DTO 对齐测试**
|
||||
|
||||
新增单元测试校验关键 response shape,不返回 `Map<String,Object>`。
|
||||
|
||||
## Task 4: App me / profile 与 Admin 用户摘要
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountProfileController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUserController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountProfileService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountProfileServiceImpl.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountProfileDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountProfileMapper.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppCurrentUserSummaryRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppProfileRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppProfileUpdateReqVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminAccountUserSummaryRespVO.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountProfileServiceTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountProfileControllerTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUserControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 实现 `/app-api/muse/me`**
|
||||
|
||||
返回 `CurrentUserSummary` 的基础账户资料,来源为当前登录用户和 `muse_account_profile`。权益摘要、安全风险数、配额状态、New-API binding 等跨服务聚合字段在 Task 5、Task 6、Task 9 中回填;Task 4 不得为了完整摘要提前实现后续 task 的 service。
|
||||
|
||||
- [ ] **Step 2: 实现 `/app-api/muse/profile` GET/PATCH**
|
||||
|
||||
PATCH 必须校验 `commandId` 和 `expectedVersion`,联系方式不在本接口直接改。
|
||||
profile 扩展事实写入 `muse_account_profile`,不得通过扩字段污染 `member_user` 基础会员表。
|
||||
|
||||
- [ ] **Step 3: 实现 `/admin-api/muse/account/users`**
|
||||
|
||||
查询用户基础摘要,来源为 `member_user`、`muse_account_profile` 和已存在的账号状态字段。权益来源、配额状态、New-API binding、风险标记在 Task 5、Task 6、Task 9 中通过修改 `AdminAccountUserController` 和 `AdminAccountUserSummaryRespVO` 回填;Task 4 只预留可空字段,不跨 task 实现聚合服务。
|
||||
|
||||
- [ ] **Step 4: 测试**
|
||||
|
||||
覆盖当前用户、profile 更新、owner 只能是自己、版本冲突、command replay/conflict、admin 权限。
|
||||
|
||||
## Task 5: 权益 / 配额 / 余额 / 用量
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountEntitlementService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountEntitlementServiceImpl.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountQuotaService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountQuotaServiceImpl.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountUsageService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountUsageServiceImpl.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUserController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUsageController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountEntitlementController.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountBalanceSnapshotDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountBalanceSnapshotMapper.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminUserEntitlementDetailRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/QuotaAdjustmentReqVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/QuotaAdjustmentResultRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/QuotaAdjustmentLedgerEntryRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminUsageRecordRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminAccountUserSummaryRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminBalanceSnapshotEntryRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppEntitlementRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppUsageSummaryRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppBalanceSnapshotEntryRespVO.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountEntitlementServiceTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountQuotaServiceTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountUsageServiceTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUsageControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 权益查询**
|
||||
|
||||
实现:
|
||||
|
||||
- `adminGetUserEntitlements`
|
||||
- `getAppEntitlements`
|
||||
|
||||
必须从 `muse_member_entitlement` / `muse_member_quota` 装配 OpenAPI DTO。
|
||||
同时回填 `AdminAccountUserSummaryRespVO` 的权益来源和配额状态字段,不改 Task 4 的基础 owner 逻辑。
|
||||
|
||||
- [ ] **Step 2: 配额调整**
|
||||
|
||||
实现:
|
||||
|
||||
- `adminCreateQuotaAdjustment`
|
||||
- `adminListQuotaAdjustments`
|
||||
|
||||
必须记录 before/after snapshot、operator summary、reason、correlationId、auditStatus。
|
||||
|
||||
- [ ] **Step 3: 余额快照**
|
||||
|
||||
实现:
|
||||
|
||||
- `adminGetBalanceSnapshots`
|
||||
- `getAppBalanceSnapshots`
|
||||
|
||||
必须从 `muse_account_balance_snapshot` 读取;没有 New-API runtime 时只返回已有快照,不即时伪造远端余额。
|
||||
|
||||
- [ ] **Step 4: 用量摘要**
|
||||
|
||||
实现:
|
||||
|
||||
- `adminListUsageRecords`
|
||||
- `getAppUsage`
|
||||
|
||||
必须从 `muse_member_usage_record` 聚合,app 只查本人。
|
||||
|
||||
- [ ] **Step 5: 测试**
|
||||
|
||||
覆盖分页、owner guard、quota delta、before/after snapshot、usage aggregation。
|
||||
|
||||
## Task 6: New-API binding / quota request / integration call
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountNewApiController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountNewApiController.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUsageController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountNewApiBindingService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountNewApiBindingServiceImpl.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountQuotaService.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountQuotaServiceImpl.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountUsageService.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountUsageServiceImpl.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/NewApiAccountFacade.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/UnavailableNewApiAccountFacade.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountQuotaRequestDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountIntegrationCallDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountQuotaRequestMapper.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountIntegrationCallMapper.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/NewApiBindingSummaryRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/NewApiBindingCreateReqVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/NewApiBindingResultRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminQuotaRequestCreateReqVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminQuotaRequestResultRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminIntegrationCallDetailRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminAccountUserSummaryRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppNewApiBindingSummaryRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppNewApiBindingRecheckReqVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppNewApiBindingRecheckRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppQuotaRequestCreateReqVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppQuotaRequestResultRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/QuotaRequestStatusRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppIntegrationCallDetailRespVO.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountNewApiBindingServiceTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountNewApiControllerTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountNewApiControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: New-API binding 查询与创建**
|
||||
|
||||
实现:
|
||||
|
||||
- `adminListNewApiBindings`
|
||||
- `adminCreateNewApiBinding`
|
||||
- `getAppNewApiBinding`
|
||||
|
||||
不得暴露 token/provider route。
|
||||
`adminCreateNewApiBinding` 必须使用 `NewApiBindingCreateReqVO` 接收 inline requestBody,校验 `commandId`、`forceRefresh`、`reason`,不得用 `Map` 或裸对象承接请求。
|
||||
创建或刷新 binding 时必须写 `muse_account_integration_call`,内部 `correlation_id` 与 `binding_id` 关联;响应只能返回 OpenAPI 已定义的 `NewApiBindingResult` 字段,不新增 `correlationId`。
|
||||
同时回填 `AdminAccountUserSummaryRespVO` 的 New-API binding 摘要字段。
|
||||
默认 `UnavailableNewApiAccountFacade` 不得伪造远端同步成功:创建/刷新无法满足 OpenAPI `created/refreshed/idempotent_hit/idempotency_conflict` 时,HTTP 响应返回合同内业务错误 `ACCOUNT_NEW_API_UNAVAILABLE`;内部 integration call 可记录 `unavailable` / `failed` 状态,但这些状态不得进入 `NewApiBindingResult.status`。
|
||||
|
||||
- [ ] **Step 2: recheck**
|
||||
|
||||
实现:
|
||||
|
||||
- `appRecheckNewApiBinding`
|
||||
|
||||
必须使用 `AppNewApiBindingRecheckReqVO` 接收 inline requestBody,校验 `commandId`,不得用 `Map` 或裸对象承接请求。
|
||||
若真实 New-API 不可用,按合同返回业务错误 `ACCOUNT_NEW_API_UNAVAILABLE`,或在能够创建异步任务时只返回 OpenAPI 已定义的 `jobId/status=queued|processing`。服务端必须写 `muse_account_integration_call`,内部 `correlation_id` 与 `job_id` 关联;不得向响应新增 `correlationId`,也不得把内部 `unavailable/failed` 写入响应 `status`。
|
||||
测试必须断言 unavailable facade 不会产生 fake success,且不会返回 OpenAPI 未声明的状态值。
|
||||
|
||||
- [ ] **Step 3: quota request**
|
||||
|
||||
实现:
|
||||
|
||||
- `adminCreateQuotaRequest`
|
||||
- `appCreateQuotaRequest`
|
||||
- `appGetQuotaRequest`
|
||||
|
||||
`appCreateQuotaRequest` 必须使用 `AppQuotaRequestCreateReqVO` 接收 inline requestBody,校验 app 侧允许的 `requestType`,不得复用 admin DTO。
|
||||
必须生成 requestId、correlationId,并写 integration call 初始记录。
|
||||
|
||||
- [ ] **Step 4: integration call 查询**
|
||||
|
||||
实现:
|
||||
|
||||
- `adminGetIntegrationCallByCorrelation`
|
||||
- `appGetIntegrationCallByCorrelation`
|
||||
|
||||
app 必须按 owner 限制。
|
||||
|
||||
- [ ] **Step 5: 测试**
|
||||
|
||||
覆盖 command replay/conflict、quota request 响应 correlation、binding/recheck 内部 correlation 写入但不改响应合同、app 越权、New-API unavailable。
|
||||
|
||||
## Task 7: Call attribution job
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUsageController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountAttributionService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountAttributionServiceImpl.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountIntegrationCallDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountCallAttributionJobDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountCallAttributionItemDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountIntegrationCallMapper.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountCallAttributionJobMapper.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountCallAttributionItemMapper.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/AccountAttributionSourceFacade.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/UnavailableAccountAttributionSourceFacade.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/CallAttributionJobCreateReqVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/CallAttributionJobResultRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/CallAttributionJobDetailRespVO.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountAttributionServiceTest.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUsageControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 创建 job**
|
||||
|
||||
实现 `adminCreateCallAttributionJob`。只能基于已存在 `correlationId` 和可选 callIds;不能信任请求体指定归因事实。
|
||||
|
||||
- [ ] **Step 2: 查询 job**
|
||||
|
||||
实现 `adminGetCallAttributionJob`,返回 completed/failed/partially_completed 等状态和补偿建议。
|
||||
|
||||
- [ ] **Step 3: 归因边界**
|
||||
|
||||
服务端只能通过 `AccountAttributionSourceFacade` 读取 call、task、work、agent、asset、license 关系;P1R-3 默认实现为 `UnavailableAccountAttributionSourceFacade`。外部 owner 未接入时,内部 job 可保持不可执行或 failed;响应状态只能使用 OpenAPI 已声明的 `queued`、`processing`、`completed`、`failed`、`partially_completed`、`idempotent_hit`,不得返回 `pending`,不得伪造归因成功,也不跨入 AI/Content/Market/Knowledge 主流程。
|
||||
|
||||
- [ ] **Step 4: 测试**
|
||||
|
||||
覆盖 correlation 不存在、callIds 白名单、幂等、归因失败、状态查询、unavailable facade 不 fake success,且响应 `status` 不出现 OpenAPI 未声明状态。
|
||||
|
||||
## Task 8: Purchase / License / Publish records
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountPurchaseController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountMarketRecordController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceImpl.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/MarketAccountProjectionFacade.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/UnavailableMarketAccountProjectionFacade.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountRecordProjectionDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountRecordProjectionMapper.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminPurchaseRecordRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppPurchaseRecordRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppLicenseRecordRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AppPublishRecordRespVO.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountMarketRecordControllerTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountPurchaseControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: purchase records**
|
||||
|
||||
实现:
|
||||
|
||||
- `adminListPurchaseRecords`
|
||||
- `appListPurchases`
|
||||
|
||||
来源为 `muse_account_record_projection(record_type=purchase)`,上游同步自 `muse_market_purchase`;不实现购买/退款/发票。
|
||||
默认 `UnavailableMarketAccountProjectionFacade` 必须返回明确 projection unavailable 边界,不能回填伪造购买记录。
|
||||
|
||||
- [ ] **Step 2: license records**
|
||||
|
||||
实现 `appListLicenses`。来源为 `muse_account_record_projection(record_type=license)`,上游同步自 `muse_market_installation`;不修改 licenseStatus。
|
||||
|
||||
- [ ] **Step 3: publish records**
|
||||
|
||||
实现 `appListPublishRecords`。来源为 `muse_account_record_projection(record_type=publish)`,上游同步自 `muse_market_publish_request`;不审核、不上架、不下架、不申诉。
|
||||
|
||||
- [ ] **Step 4: 测试**
|
||||
|
||||
覆盖 app owner、admin query、脱敏、record_type 过滤、Market projection unavailable,且 unavailable facade 不产生 fake record。
|
||||
|
||||
## Task 9: Security events
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountSecurityController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountSecurityService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountSecurityServiceImpl.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountSecurityEventAckDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountSecurityEventAckMapper.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/SecurityEventSummaryRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/SecurityEventDetailRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/SecurityEventAcknowledgeReqVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/SecurityEventAcknowledgeResultRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/vo/AdminAccountUserSummaryRespVO.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountSecurityServiceTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountSecurityControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 列表与详情**
|
||||
|
||||
实现:
|
||||
|
||||
- `appListSecurityEvents`
|
||||
- `appGetSecurityEvent`
|
||||
|
||||
只能查看本人安全事件,敏感值脱敏。
|
||||
同时回填 `AdminAccountUserSummaryRespVO` 的风险标记或安全事件计数字段,不提前接入 session 管理。
|
||||
|
||||
- [ ] **Step 2: acknowledge**
|
||||
|
||||
实现 `appAcknowledgeSecurityEvent`。必须 append-only 写确认动作、note、riskSummary;不得删除事件。
|
||||
|
||||
- [ ] **Step 3: session_revoked 边界**
|
||||
|
||||
若 session 管理服务未接入,返回明确业务错误或 pending action,不伪造 session 已撤销。
|
||||
|
||||
- [ ] **Step 4: 测试**
|
||||
|
||||
覆盖 owner guard、ack 幂等、重复确认、session_revoked external unavailable。
|
||||
|
||||
## Task 10: Export task / download credential
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountExportController.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountExportService.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountExportServiceImpl.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/AccountFileServiceFacade.java`
|
||||
- Create: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/UnavailableAccountFileServiceFacade.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountExportTaskDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountDownloadCredentialDO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountExportTaskMapper.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountDownloadCredentialMapper.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AccountExportTaskCreateReqVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AccountExportTaskResultRespVO.java`
|
||||
- Modify: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/vo/AccountExportTaskDetailRespVO.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountExportServiceTest.java`
|
||||
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountExportControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 创建导出任务**
|
||||
|
||||
实现 `appCreateExportTask`。必须校验 exportType、dateRange、step-up requirement,并写 command/audit。
|
||||
|
||||
- [ ] **Step 2: 查询导出任务**
|
||||
|
||||
实现 `appGetExportTask`。只能查本人 task。
|
||||
|
||||
- [ ] **Step 3: 下载凭证**
|
||||
|
||||
实现 `appDownloadExport`。必须校验 credential hash、owner、expiresAt、revoked/consumed/source blocked。成功响应必须返回 OpenAPI 定义的 `application/octet-stream` 文件流;错误响应仍走项目统一 `code/data/msg`。
|
||||
|
||||
- [ ] **Step 4: FileService 边界**
|
||||
|
||||
默认 `UnavailableAccountFileServiceFacade` 表示 FileService 未接入;内部 task 可保持不可执行或 failed,不返回伪造文件流。响应状态只能使用 OpenAPI 已声明的 `queued`、`processing`、`completed`、`failed`、`idempotent_hit`,不得返回 `pending`。
|
||||
|
||||
- [ ] **Step 5: 测试**
|
||||
|
||||
覆盖高敏导出、安全事件生成、过期凭证、跨用户凭证、source blocked、成功下载响应不是 `CommonResult`,unavailable facade 不返回 fake stream,且响应 `status` 不出现 OpenAPI 未声明状态。
|
||||
|
||||
## Task 11: Account 合同兜底退役
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify/Delete: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/AdminMuseAccountContractController.java`
|
||||
- Modify/Delete: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/AppMuseAccountContractController.java`
|
||||
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRouteOwnershipTest.java`
|
||||
|
||||
- [ ] **Step 1: 删除或收窄 P1R-3 路由兜底**
|
||||
|
||||
优先方案:删除两个 Account 合同兜底 Controller。若还有非 P1R-3 Account 合同路径必须保留,必须把兜底路径收窄到这些非 P1R-3 路径,并在测试里证明 P1R-3 路径不会进入 `MuseContractPersistenceService`。
|
||||
|
||||
- [ ] **Step 2: route ownership 测试**
|
||||
|
||||
测试必须证明:
|
||||
|
||||
- 33 个 P1R-3 路由都命中 dedicated Controller。
|
||||
- 33 个 P1R-3 路由不会调用 `MuseContractPersistenceService.handle(...)`。
|
||||
- 没有 wildcard `/**` 把 dedicated 路由重新兜住。
|
||||
|
||||
- [ ] **Step 3: 运行 route ownership 测试**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
set -e
|
||||
cd muse-cloud
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRouteOwnershipTest.java
|
||||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||||
mvn -o test -pl muse-server -am \
|
||||
-Dtest=P1rAccountRouteOwnershipTest
|
||||
```
|
||||
|
||||
Expected: `P1rAccountRouteOwnershipTest` 通过;若测试文件不存在,必须失败。
|
||||
|
||||
## Task 12: P1R-3 覆盖门禁与报告对账
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRealApiGateTest.java`
|
||||
- Modify: `docs/superpowers/reports/p1r-api-coverage.json`
|
||||
- Modify: `docs/superpowers/reports/p1r-api-coverage.md`
|
||||
- Read: `muse-cloud/scripts/p1r-audit-api-coverage.py`
|
||||
|
||||
- [ ] **Step 1: 运行覆盖审计**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- 脚本成功。
|
||||
- Content 仍是 51 个 `dedicated / needs_verification`。
|
||||
- Meta 仍是 16 个 `dedicated / needs_verification`。
|
||||
- Account 33 个 operation 是 `dedicated / needs_verification`。
|
||||
- Account 不出现 `completed`。
|
||||
|
||||
如果脚本不能识别 dedicated Account 实现,先分析脚本识别规则和代码结构差异;不能直接改脚本掩盖缺口。需要修改脚本时必须先说明这是扫描规则纠偏还是状态口径变更,并单独取得确认。
|
||||
|
||||
- [ ] **Step 2: 增加 Account 阶段门禁测试**
|
||||
|
||||
`P1rAccountRealApiGateTest` 至少校验:
|
||||
|
||||
- Account operation 数量为 33。
|
||||
- Account operation 清单与本计划第 1 节一致。
|
||||
- Account operation 不允许 `generic_persistence`、`catch_all`、`sse_placeholder`、`missing`。
|
||||
- Account operation 不允许 `completionStatus=completed`。
|
||||
- Account operation 必须全部保持 `dedicated / needs_verification`,不能使用 `blocked` 或 `completed` 作为 P1R-3 收口状态。
|
||||
|
||||
- [ ] **Step 3: 运行 P1R 门禁**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
set -e
|
||||
cd muse-cloud
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRealApiGateTest.java
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRouteOwnershipTest.java
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rApiCoverageReportTest.java
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rContentRealApiGateTest.java
|
||||
test -f muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMetaRealApiGateTest.java
|
||||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||||
mvn -o test -pl muse-server -am \
|
||||
-Dtest=P1rApiCoverageReportTest,P1rContentRealApiGateTest,P1rMetaRealApiGateTest,P1rAccountRealApiGateTest,P1rAccountRouteOwnershipTest
|
||||
```
|
||||
|
||||
Expected: 测试通过。
|
||||
|
||||
- [ ] **Step 4: 运行 Account/Member 模块聚焦测试**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
set -e
|
||||
cd muse-cloud
|
||||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||||
mvn -o test -pl muse-module-member/muse-module-member-server -am
|
||||
```
|
||||
|
||||
Expected: 测试通过。
|
||||
|
||||
- [ ] **Step 5: 基础卫生检查**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
git status --short -- muse-cloud/scripts
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `git diff --check` 无输出。
|
||||
- `muse-cloud/scripts/**` 无改动,除非用户已批准扫描规则纠偏。
|
||||
|
||||
## 4. Review 门禁
|
||||
|
||||
每个 Task 完成后交给两个 fresh subagent:
|
||||
|
||||
### Spec compliance review
|
||||
|
||||
检查:
|
||||
|
||||
- 是否完全覆盖对应 operation。
|
||||
- 是否符合 P1R-3 spec。
|
||||
- 是否没有标 `completed`。
|
||||
- 是否没有用 generic persistence / operation record / workflow task / sample JSON 伪装完成。
|
||||
- 是否没有越权写其他 owner。
|
||||
- 是否没有跨入 P1R-4/P1R-5/P1R-6/P1R-7。
|
||||
|
||||
### Code quality review
|
||||
|
||||
检查:
|
||||
|
||||
- 改动是否最小。
|
||||
- Controller / Service / Domain / DAL 是否职责清晰。
|
||||
- DTO 是否对齐 OpenAPI。
|
||||
- 测试是否覆盖成功、冲突、非法状态、权限、幂等、审计。
|
||||
- 是否无无关重构。
|
||||
- 是否无 `muse-cloud/scripts/**` 掩盖性修改。
|
||||
|
||||
## 5. 回滚策略
|
||||
|
||||
- 文档与测试回滚:回退本阶段新增 spec/plan/gate test。
|
||||
- 代码回滚:回退 `muse-module-member` 新增 Account Controller/Service/DTO/DAL/Domain。
|
||||
- DDL 回滚:开发阶段可删除未合入迁移;迁移合入后不得修改历史 V11,只能新增 V12 修正。
|
||||
- 覆盖报告回滚:重新运行 P1R audit,确保 Content 和 Meta 保持当前状态。
|
||||
|
||||
## 6. 完成条件
|
||||
|
||||
P1R-3 实现阶段完成时必须同时满足:
|
||||
|
||||
1. Account 33 个 operation 有专用实现。
|
||||
2. Account 不存在 `generic_persistence`、`catch_all`、`sse_placeholder`、`missing` 残留。
|
||||
3. Account 全部保持 `dedicated / needs_verification`,不存在 `completed` 或 `blocked` 收口状态。
|
||||
4. Account/Member 模块测试通过。
|
||||
5. `P1rAccountMigrationSqlTest` 通过,证明 V11 迁移包含 `muse_account_audit`、`muse_account_profile`、`muse_account_record_projection` 等必要表和约束。
|
||||
6. `P1rAccountRouteOwnershipTest` 通过,证明 33 个 P1R-3 路由不再进入 `MuseContractPersistenceService`。
|
||||
7. P1R 门禁测试通过。
|
||||
8. `muse-cloud/scripts/**` 未被用来掩盖缺口。
|
||||
9. Content 51 个 operation 仍为 `dedicated / needs_verification`。
|
||||
10. Meta 16 个 operation 仍为 `dedicated / needs_verification`。
|
||||
11. 若未运行真实 PostgreSQL / Flyway / New-API runtime / FileService 验证,必须在 `docs/memorys/YYYY-MM-DD-P1R3账户真实API规格计划.md` 或实现阶段留痕中记录残余 `needs_verification` 风险。
|
||||
@ -0,0 +1,564 @@
|
||||
# P1R-3:Account Real API 规格
|
||||
|
||||
- 版本:v1
|
||||
- 日期:2026-05-28
|
||||
- 状态:review 已通过;2026-05-29 实现阶段已收口到 `dedicated / needs_verification`
|
||||
- 上游规格:`docs/superpowers/specs/2026-05-25-P1R-muse-cloud-real-api-design.md`
|
||||
- 基线输入:`docs/superpowers/reports/p1r-api-coverage.json`
|
||||
- 范围:`muse-cloud/muse-module-member/**` 中 Account 专用实现、Account 相关追加迁移、P1R-3 覆盖门禁
|
||||
- 非范围:AI runtime / SSE、Knowledge / RAGFlow、Market 主流程、Events SSE、修改 `muse-cloud/scripts/**` 掩盖缺口、静默修改 OpenAPI、把 Account operation 标为 `completed`
|
||||
|
||||
## 1. 结论
|
||||
|
||||
P1R-3 的目标不是继续扩展 `MuseContractPersistenceService`,也不是把 Account 的通用持久化响应包装成 OpenAPI DTO。
|
||||
|
||||
本阶段要把 Account 域从“通用持久化可响应”推进到“真实账户业务 API 可验收”:
|
||||
|
||||
1. Account 33 个 operation 当前全部是 `generic_persistence / incomplete`,必须退出通用持久化完成口径。
|
||||
2. 仓库没有 `muse-module-account`,当前 Account 合同实际挂在 `muse-module-member`;P1R-3 的 owner 应落在 `muse-module-member` 的 Account 子域,而不是新增孤立模块。
|
||||
3. Account owner 只拥有用户资料、权益、配额、用量、New-API 绑定、调用归因读模型、安全事件、个人中心导出的账户事实。
|
||||
4. 购买、授权、发布记录只能读取 Market/Content/Knowledge/AI 已产生的事实或投影,不能在 Account 阶段实现 Market 主流程。
|
||||
5. New-API binding / recheck / quota request / integration call / call attribution 必须有 commandId 幂等、外部调用记录和失败补偿边界;其中 quota request 与 call attribution 按 OpenAPI 暴露 `correlationId`,binding / recheck 只在服务端 integration call 中关联 `bindingId` / `jobId`,不向响应偷加 OpenAPI 未定义字段。未接真实 New-API runtime 前只能保持 `needs_verification`。
|
||||
6. P1R-3 通过后的覆盖状态目标统一为 `dedicated / needs_verification`,不能写成 `completed`。外部 owner 未闭合时返回合同内 `CommonResult` 业务错误或 pending job,不使用 coverage 的 `blocked` 完成状态。
|
||||
|
||||
## 2. 已验证事实
|
||||
|
||||
### 2.1 执行工作面
|
||||
|
||||
用户给定主路径 `/Users/qingse/Sync/local-git/oh-my-muse` 当前不是本阶段真实工作面。只读核验结果显示:
|
||||
|
||||
- `/Users/qingse/Sync/local-git/oh-my-muse` 当前在 `feature/p1-muse-cloud-backend-20260524`,且有未跟踪文件。
|
||||
- `dev/1.0.0` 已被 worktree 占用:`/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0`。
|
||||
- 写入本规格和执行计划前,真实工作面 `dev/1.0.0` 的 `git status --short --branch` 输出为 `## dev/1.0.0...origin/dev/1.0.0`,无未提交改动。
|
||||
|
||||
本规格和执行计划落在真实 worktree:
|
||||
|
||||
```text
|
||||
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
|
||||
```
|
||||
|
||||
### 2.2 覆盖矩阵
|
||||
|
||||
来自 `docs/superpowers/reports/p1r-api-coverage.json`:
|
||||
|
||||
| 指标 | 数量 |
|
||||
|---|---:|
|
||||
| 全量 operation | 233 |
|
||||
| completed | 0 |
|
||||
| needs_verification | 67 |
|
||||
| incomplete | 166 |
|
||||
| generic_persistence | 164 |
|
||||
| sse_placeholder | 2 |
|
||||
| missing | 0 |
|
||||
| blocked | 0 |
|
||||
| Content `dedicated / needs_verification` | 51 |
|
||||
| Meta `dedicated / needs_verification` | 16 |
|
||||
| Account operation | 33 |
|
||||
| Account `generic_persistence / incomplete` | 33 |
|
||||
| Account `dedicated / needs_verification` | 0 |
|
||||
|
||||
Account 当前没有 `catch_all`、`sse_placeholder`、`missing` 或 `dedicated`。所有 Account operation 的 `notes` 均为:由 `MuseContractPersistenceService` 通用持久化处理,不是 P1R 完成证据。
|
||||
|
||||
### 2.3 当前代码事实
|
||||
|
||||
当前没有 `muse-cloud/muse-module-account/**`。Account 合同入口在 `muse-cloud/muse-module-member/**`:
|
||||
|
||||
- `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/AdminMuseAccountContractController.java`
|
||||
- `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/AppMuseAccountContractController.java`
|
||||
|
||||
这两个 Controller 使用宽泛路由接管:
|
||||
|
||||
- Admin:`/muse/account/**`
|
||||
- App:`/muse/me`、`/muse/profile`、`/muse/account/**`
|
||||
|
||||
并统一委托:
|
||||
|
||||
- `MuseContractPersistenceService.handle(...)`
|
||||
|
||||
当前缺失:
|
||||
|
||||
- Account 专用 Controller。
|
||||
- Account Application Service。
|
||||
- Account OpenAPI 对应 DTO / VO。
|
||||
- Account DO / Mapper。
|
||||
- Account commandId + requestHash 幂等服务。
|
||||
- Account 领域审计与 security event 写入。
|
||||
- App user owner guard 的统一后端强制。
|
||||
- Admin RBAC 权限点。
|
||||
- New-API binding / recheck 的真实外部调用边界。
|
||||
- integration call / correlation / call attribution 的专用事实表或投影。
|
||||
- balance snapshot、export task、download credential 的专用持久化。
|
||||
- purchase / license / publish record 的 Account 视角投影。
|
||||
|
||||
已有 Yudao 会员能力可复用但不是 OpenAPI 完成路径:
|
||||
|
||||
- `AppMemberUserController` 只覆盖 `/member/user/**`。
|
||||
- `MemberUserController` 只覆盖 `/member/user/**` 管理端会员用户。
|
||||
- `MemberUserService` / `MemberUserMapper` 可作为用户资料底层能力。
|
||||
|
||||
### 2.4 当前 DDL
|
||||
|
||||
`muse-cloud/sql/muse/V2__init_account_schema.sql` 已有 Account 基础表:
|
||||
|
||||
- `muse_member_entitlement`
|
||||
- `muse_member_entitlement_audit_log`
|
||||
- `muse_member_quota`
|
||||
- `muse_member_usage_record`
|
||||
- `muse_member_security_event`
|
||||
- `muse_member_new_api_binding`
|
||||
|
||||
`muse-cloud/sql/muse/V7__add_contract_operation_audit.sql` 已有通用操作记录:
|
||||
|
||||
- `muse_domain_operation_record`
|
||||
|
||||
`muse-cloud/sql/muse/V8__add_contract_workflow_and_market_interaction.sql` 已有通用工作流和市场购买:
|
||||
|
||||
- `muse_domain_workflow_task`
|
||||
- `muse_market_purchase`
|
||||
|
||||
`muse-cloud/sql/muse/V6__init_market_schema.sql` 已有 Market 侧可读来源:
|
||||
|
||||
- `muse_market_asset`
|
||||
- `muse_market_asset_version`
|
||||
- `muse_market_installation`
|
||||
- `muse_market_publish_request`
|
||||
- `muse_market_appeal`
|
||||
- `muse_market_handoff`
|
||||
|
||||
这些表不足以完成 P1R-3:
|
||||
|
||||
- 没有 Account 专用 command 表;`muse_domain_operation_record` 只有 domain 级 replay,没有 request hash 冲突判断。
|
||||
- 没有 balance snapshot 表。
|
||||
- 没有 integration call 表。
|
||||
- 没有 call attribution job 专用表和 per-call 归因结果。
|
||||
- 没有 quota request 专用状态表;当前只落 `muse_domain_workflow_task`。
|
||||
- 没有 account export task 表和 download credential 表。
|
||||
- `muse_member_security_event` 只有确认字段,缺 acknowledge action / note / riskSummary / append-only audit。
|
||||
- `muse_member_entitlement_audit_log` 缺 OpenAPI 所需 before/after 快照完整填充和审计事件关系。
|
||||
- purchase/license/publish records 没有 Account 视角读模型或明确 projection owner。
|
||||
|
||||
## 3. 目标
|
||||
|
||||
1. 为 33 个 Account operation 定义真实 API 落地边界。
|
||||
2. 用专用 Controller / Service / DTO / DAL / DDL 替代通用持久化完成口径。
|
||||
3. 建立当前用户、profile、权益、配额、余额、用量、安全事件、导出下载的账户事实模型。
|
||||
4. 建立 New-API binding / recheck / quota request / integration call / call attribution 的 correlation 边界。
|
||||
5. 建立 purchase / license / publish records 的 Account 视角投影,不接管 Market 主流程。
|
||||
6. 建立 commandId 幂等、requestHash 冲突校验、owner guard、admin RBAC、审计和错误响应。
|
||||
7. 建立 P1R-3 阶段门禁,防止 Account operation 继续被 `generic_persistence` 或 `completed` 混淆。
|
||||
|
||||
## 4. 非目标
|
||||
|
||||
1. 不修改 OpenAPI 来适配当前代码。若发现合同纠偏需求,必须单独列出原因、影响范围和是否属于合同纠偏。
|
||||
2. 不实现 AI task 真实 New-API 调用、AI runtime、Agent、Prompt、Quality、Suggestion、Job。
|
||||
3. 不实现 AI task SSE stream 或统一 Events SSE。
|
||||
4. 不实现 Knowledge / RAGFlow / projection 主流程。
|
||||
5. 不实现 Market 购买、安装、handoff、审核、召回、申诉主流程。
|
||||
6. 不把 `MuseContractPersistenceService`、`muse_domain_operation_record`、`muse_domain_workflow_task` 原始行、空列表、`status: accepted` 作为完成证据。
|
||||
7. 不修改 `muse-cloud/scripts/**` 来掩盖真实缺口。若扫描器无法识别 dedicated 实现,先说明扫描规则合同纠偏原因和影响范围。
|
||||
8. 不把前端按钮隐藏或页面权限当作后端权限。
|
||||
|
||||
## 5. Operation 清单与当前状态
|
||||
|
||||
| operationId | Method | Path | 当前状态 | 真实 owner | P1R-3 目标 |
|
||||
|---|---|---|---|---|---|
|
||||
| `adminListAccountUsers` | GET | `/admin-api/muse/account/users` | `generic_persistence / incomplete` | Account User Query | `dedicated / needs_verification` |
|
||||
| `adminGetUserEntitlements` | GET | `/admin-api/muse/account/users/{userId}/entitlements` | `generic_persistence / incomplete` | Account Entitlement Query | `dedicated / needs_verification` |
|
||||
| `adminCreateQuotaAdjustment` | POST | `/admin-api/muse/account/users/{userId}/quota-adjustments` | `generic_persistence / incomplete` | Account Quota Command | `dedicated / needs_verification` |
|
||||
| `adminListQuotaAdjustments` | GET | `/admin-api/muse/account/users/{userId}/quota-adjustments` | `generic_persistence / incomplete` | Account Quota Query | `dedicated / needs_verification` |
|
||||
| `adminListNewApiBindings` | GET | `/admin-api/muse/account/new-api-bindings` | `generic_persistence / incomplete` | Account New-API Query | `dedicated / needs_verification` |
|
||||
| `adminCreateNewApiBinding` | POST | `/admin-api/muse/account/users/{userId}/new-api-binding` | `generic_persistence / incomplete` | Account New-API Command | `dedicated / needs_verification` |
|
||||
| `adminCreateQuotaRequest` | POST | `/admin-api/muse/account/users/{userId}/quota-requests` | `generic_persistence / incomplete` | Account New-API Quota Command | `dedicated / needs_verification` |
|
||||
| `adminGetBalanceSnapshots` | GET | `/admin-api/muse/account/users/{userId}/balance-snapshots` | `generic_persistence / incomplete` | Account Balance Query | `dedicated / needs_verification` |
|
||||
| `adminCreateCallAttributionJob` | POST | `/admin-api/muse/account/call-attribution-jobs` | `generic_persistence / incomplete` | Account Attribution Command | `dedicated / needs_verification` |
|
||||
| `adminGetCallAttributionJob` | GET | `/admin-api/muse/account/call-attribution-jobs/{jobId}` | `generic_persistence / incomplete` | Account Attribution Query | `dedicated / needs_verification` |
|
||||
| `adminGetIntegrationCallByCorrelation` | GET | `/admin-api/muse/account/integration-calls/by-correlation/{correlationId}` | `generic_persistence / incomplete` | Account Integration Query | `dedicated / needs_verification` |
|
||||
| `adminListUsageRecords` | GET | `/admin-api/muse/account/usage-records` | `generic_persistence / incomplete` | Account Usage Query | `dedicated / needs_verification` |
|
||||
| `adminListPurchaseRecords` | GET | `/admin-api/muse/account/purchase-records` | `generic_persistence / incomplete` | Account Purchase Projection Query | `dedicated / needs_verification` |
|
||||
| `getCurrentUser` | GET | `/app-api/muse/me` | `generic_persistence / incomplete` | Account Current User Query | `dedicated / needs_verification` |
|
||||
| `getProfile` | GET | `/app-api/muse/profile` | `generic_persistence / incomplete` | Account Profile Query | `dedicated / needs_verification` |
|
||||
| `updateProfile` | PATCH | `/app-api/muse/profile` | `generic_persistence / incomplete` | Account Profile Command | `dedicated / needs_verification` |
|
||||
| `getAppEntitlements` | GET | `/app-api/muse/account/entitlements` | `generic_persistence / incomplete` | Account Entitlement Query | `dedicated / needs_verification` |
|
||||
| `getAppUsage` | GET | `/app-api/muse/account/usage` | `generic_persistence / incomplete` | Account Usage Query | `dedicated / needs_verification` |
|
||||
| `getAppNewApiBinding` | GET | `/app-api/muse/account/new-api-binding` | `generic_persistence / incomplete` | Account New-API Query | `dedicated / needs_verification` |
|
||||
| `appRecheckNewApiBinding` | POST | `/app-api/muse/account/new-api-binding/recheck` | `generic_persistence / incomplete` | Account New-API Command | `dedicated / needs_verification` |
|
||||
| `getAppBalanceSnapshots` | GET | `/app-api/muse/account/balance-snapshots` | `generic_persistence / incomplete` | Account Balance Query | `dedicated / needs_verification` |
|
||||
| `appCreateQuotaRequest` | POST | `/app-api/muse/account/quota-requests` | `generic_persistence / incomplete` | Account Quota Request Command | `dedicated / needs_verification` |
|
||||
| `appGetQuotaRequest` | GET | `/app-api/muse/account/quota-requests/{requestId}` | `generic_persistence / incomplete` | Account Quota Request Query | `dedicated / needs_verification` |
|
||||
| `appGetIntegrationCallByCorrelation` | GET | `/app-api/muse/account/integration-calls/by-correlation/{correlationId}` | `generic_persistence / incomplete` | Account Integration Query | `dedicated / needs_verification` |
|
||||
| `appListPurchases` | GET | `/app-api/muse/account/purchases` | `generic_persistence / incomplete` | Account Purchase Projection Query | `dedicated / needs_verification` |
|
||||
| `appListLicenses` | GET | `/app-api/muse/account/licenses` | `generic_persistence / incomplete` | Account License Projection Query | `dedicated / needs_verification` |
|
||||
| `appListPublishRecords` | GET | `/app-api/muse/account/publish-records` | `generic_persistence / incomplete` | Account Publish Projection Query | `dedicated / needs_verification` |
|
||||
| `appListSecurityEvents` | GET | `/app-api/muse/account/security-events` | `generic_persistence / incomplete` | Account Security Query | `dedicated / needs_verification` |
|
||||
| `appGetSecurityEvent` | GET | `/app-api/muse/account/security-events/{eventId}` | `generic_persistence / incomplete` | Account Security Query | `dedicated / needs_verification` |
|
||||
| `appAcknowledgeSecurityEvent` | POST | `/app-api/muse/account/security-events/{eventId}/acknowledge` | `generic_persistence / incomplete` | Account Security Command | `dedicated / needs_verification` |
|
||||
| `appCreateExportTask` | POST | `/app-api/muse/account/export-tasks` | `generic_persistence / incomplete` | Account Export Command | `dedicated / needs_verification` |
|
||||
| `appGetExportTask` | GET | `/app-api/muse/account/export-tasks/{taskId}` | `generic_persistence / incomplete` | Account Export Query | `dedicated / needs_verification` |
|
||||
| `appDownloadExport` | GET | `/app-api/muse/account/downloads/{credentialId}` | `generic_persistence / incomplete` | Account Export Download | `dedicated / needs_verification` |
|
||||
|
||||
## 6. 目标架构
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Admin Account Controllers] --> B[Account Application Services]
|
||||
C[App Account Controllers] --> B
|
||||
B --> D[Account Command Service]
|
||||
B --> E[Account Audit Service]
|
||||
B --> F[Account Owner Guards]
|
||||
B --> G[Account Query Assemblers]
|
||||
B --> H[Account Persistence]
|
||||
B --> I[External Facades]
|
||||
H --> J[(member_user)]
|
||||
H --> K[(muse_member_* tables)]
|
||||
H --> L[(muse_account_* extension tables)]
|
||||
I --> M[New-API Client Boundary]
|
||||
I --> N[Market Projection Boundary]
|
||||
I --> O[FileService Boundary]
|
||||
I --> P[Attribution Source Boundary]
|
||||
```
|
||||
|
||||
### 6.1 Controller
|
||||
|
||||
推荐拆分:
|
||||
|
||||
| Controller | 职责 |
|
||||
|---|---|
|
||||
| `AdminAccountUserController` | 用户摘要、用户权益、配额调整、余额快照 |
|
||||
| `AdminAccountNewApiController` | New-API binding 列表、创建/刷新、quota request |
|
||||
| `AdminAccountUsageController` | usage records、integration call、call attribution job |
|
||||
| `AdminAccountPurchaseController` | purchase records 管理端查询 |
|
||||
| `AppAccountProfileController` | `/app-api/muse/me`、`/app-api/muse/profile` |
|
||||
| `AppAccountEntitlementController` | 权益、用量、余额、quota request |
|
||||
| `AppAccountNewApiController` | binding 查询、recheck、integration call 查询 |
|
||||
| `AppAccountMarketRecordController` | purchases、licenses、publish records |
|
||||
| `AppAccountSecurityController` | security events、acknowledge |
|
||||
| `AppAccountExportController` | export task、download credential |
|
||||
|
||||
Controller 只负责:
|
||||
|
||||
- `@PreAuthorize` 或 app authenticated owner 入口。
|
||||
- `X-API-Version: 1` 校验。
|
||||
- path/query/body 参数校验。
|
||||
- DTO 进入 Application Service。
|
||||
- 默认用 `CommonResult<T>` 返回 `code/data/msg`。
|
||||
- `appDownloadExport` 是 OpenAPI 明确的例外:成功响应必须返回 `application/octet-stream` 文件流;失败响应仍沿用项目统一错误响应。
|
||||
|
||||
禁止:
|
||||
|
||||
- Controller 访问 Mapper。
|
||||
- Controller 拼接业务 JSON。
|
||||
- Controller 调用 `MuseContractPersistenceService` 作为完成路径。
|
||||
- Controller 静态返回 OpenAPI 样例。
|
||||
|
||||
### 6.2 Service
|
||||
|
||||
推荐服务:
|
||||
|
||||
| Service | 职责 |
|
||||
|---|---|
|
||||
| `AccountProfileService` | 当前用户、资料查询、资料更新、乐观锁 |
|
||||
| `AccountEntitlementService` | 权益、配额、余额快照查询与装配 |
|
||||
| `AccountQuotaService` | 配额调整、quota request 状态机 |
|
||||
| `AccountNewApiBindingService` | New-API binding、recheck、外部同步边界 |
|
||||
| `AccountUsageService` | usage records、usage summary、integration call 查询 |
|
||||
| `AccountAttributionService` | call attribution job 创建、状态、归因校验边界 |
|
||||
| `AccountMarketRecordService` | purchase/license/publish records Account 投影查询 |
|
||||
| `AccountSecurityService` | security event 查询、确认、append-only 审计 |
|
||||
| `AccountExportService` | export task、download credential、FileService 边界 |
|
||||
| `AccountCommandService` | commandId、requestHash、resultSnapshot 幂等 |
|
||||
| `AccountAuditService` | Account 领域审计和安全事件写入 |
|
||||
|
||||
### 6.3 DTO / Assembler
|
||||
|
||||
每个 OpenAPI schema 必须对应专用 VO/DTO,不能返回 `Map<String, Object>` 或 DO。
|
||||
|
||||
最小 DTO 覆盖:
|
||||
|
||||
- `AdminAccountUserSummaryRespVO`
|
||||
- `AdminUserEntitlementDetailRespVO`
|
||||
- `QuotaAdjustmentReqVO`
|
||||
- `QuotaAdjustmentResultRespVO`
|
||||
- `QuotaAdjustmentLedgerEntryRespVO`
|
||||
- `NewApiBindingSummaryRespVO`
|
||||
- `NewApiBindingCreateReqVO`
|
||||
- `NewApiBindingResultRespVO`
|
||||
- `AdminQuotaRequestCreateReqVO`
|
||||
- `AdminQuotaRequestResultRespVO`
|
||||
- `AppQuotaRequestResultRespVO`
|
||||
- `QuotaRequestStatusRespVO`
|
||||
- `AdminBalanceSnapshotEntryRespVO`
|
||||
- `AppBalanceSnapshotEntryRespVO`
|
||||
- `CallAttributionJobCreateReqVO`
|
||||
- `CallAttributionJobResultRespVO`
|
||||
- `CallAttributionJobDetailRespVO`
|
||||
- `AdminIntegrationCallDetailRespVO`
|
||||
- `AppIntegrationCallDetailRespVO`
|
||||
- `AdminUsageRecordRespVO`
|
||||
- `AdminPurchaseRecordRespVO`
|
||||
- `AppCurrentUserSummaryRespVO`
|
||||
- `AppProfileRespVO`
|
||||
- `AppProfileUpdateReqVO`
|
||||
- `AppEntitlementRespVO`
|
||||
- `AppUsageSummaryRespVO`
|
||||
- `AppNewApiBindingSummaryRespVO`
|
||||
- `AppNewApiBindingRecheckReqVO`
|
||||
- `AppNewApiBindingRecheckRespVO`
|
||||
- `AppQuotaRequestCreateReqVO`
|
||||
- `AppPurchaseRecordRespVO`
|
||||
- `AppLicenseRecordRespVO`
|
||||
- `AppPublishRecordRespVO`
|
||||
- `SecurityEventSummaryRespVO`
|
||||
- `SecurityEventDetailRespVO`
|
||||
- `SecurityEventAcknowledgeReqVO`
|
||||
- `SecurityEventAcknowledgeResultRespVO`
|
||||
- `AccountExportTaskCreateReqVO`
|
||||
- `AccountExportTaskResultRespVO`
|
||||
- `AccountExportTaskDetailRespVO`
|
||||
|
||||
Assembler 负责:
|
||||
|
||||
- ID 转字符串。
|
||||
- 时间字段统一为 OpenAPI date-time。
|
||||
- 手机、邮箱、外部订单、IP、设备信息脱敏。
|
||||
- `PageResult<T>` 与 OpenAPI `PaginatedResult.list` 对齐。
|
||||
- 不暴露 New-API token、provider authority、模型路由、Prompt/Response 原文、后台权限表。
|
||||
|
||||
## 7. 持久化设计
|
||||
|
||||
### 7.1 复用现有表
|
||||
|
||||
| 表 | P1R-3 用途 | 缺口 |
|
||||
|---|---|---|
|
||||
| `member_user` | 当前用户、用户摘要、账号基础状态 | 不直接承载 P1R-3 profile 乐观锁和公开笔名等扩展事实 |
|
||||
| `muse_account_profile` | profile 扩展、expectedVersion、公开资料 | P1R-3 新增轻量扩展表 |
|
||||
| `muse_member_entitlement` | plan、权益、额度摘要 | 需要 DTO 装配和来源语义 |
|
||||
| `muse_member_quota` | quota 明细、剩余和重置周期 | 需要资源类型映射和并发调整 |
|
||||
| `muse_member_entitlement_audit_log` | quota adjustment ledger | 需要 before/after 快照和 audit event 关联 |
|
||||
| `muse_member_usage_record` | usage records、app usage summary | 需要 correlation、归因状态、统计聚合 |
|
||||
| `muse_member_security_event` | security event 查询 | 需要 acknowledge action/note/audit |
|
||||
| `muse_member_new_api_binding` | New-API binding | 需要 recheck status、失败原因、外部同步时间 |
|
||||
| `muse_domain_workflow_task` | 可作为过渡读取旧任务 | 不能作为 Account dedicated 完成证据 |
|
||||
| `muse_market_purchase` | purchase projection 上游来源 | Account 只通过 `muse_account_record_projection` 读取 |
|
||||
| `muse_market_installation` | license projection 上游来源 | Account 只通过 `muse_account_record_projection` 读取 |
|
||||
| `muse_market_publish_request` | publish records 上游来源 | Account 只通过 `muse_account_record_projection` 读取 |
|
||||
|
||||
### 7.2 追加迁移
|
||||
|
||||
P1R-3 实现阶段建议新增 `V11__extend_account_real_api_schema.sql`。最小新增:
|
||||
|
||||
- `muse_account_command`
|
||||
- `muse_account_audit`
|
||||
- `muse_account_profile`
|
||||
- `muse_account_balance_snapshot`
|
||||
- `muse_account_quota_request`
|
||||
- `muse_account_integration_call`
|
||||
- `muse_account_call_attribution_job`
|
||||
- `muse_account_call_attribution_item`
|
||||
- `muse_account_export_task`
|
||||
- `muse_account_download_credential`
|
||||
- `muse_account_security_event_ack`
|
||||
- `muse_account_record_projection`
|
||||
|
||||
关键约束:
|
||||
|
||||
- `muse_account_command` 唯一键:`(tenant_id, command_id)`。
|
||||
- command 记录必须包含 `operation_id`、`actor_user_id`、`owner_user_id`、`target_type`、`target_id`、`request_hash`、`result_snapshot`。
|
||||
- 同一 `commandId` + 不同 `requestHash` 返回 409。
|
||||
- `muse_account_audit` 必须覆盖写操作、外部调用、导出下载和高敏安全动作,索引 `account_user_id`、`operation_id`、`correlation_id`。
|
||||
- `muse_account_profile` 必须以 `account_user_id` 唯一,包含 `profile_version` 支撑 `expectedVersion`。
|
||||
- `muse_account_record_projection` 必须包含 `record_type`,限定为 `purchase`、`license`、`publish`,并保存上游 `source_table` / `source_id` / `source_revision`。
|
||||
- app 可见表必须具备 `account_user_id` / `owner_user_id` 索引。
|
||||
- `correlation_id` 在 integration call 维度需要唯一或去重键。
|
||||
- download credential 必须具备 `credential_hash`、`account_user_id`、`task_id`、`expires_at`、`consumed_at`、`revoked_at`。
|
||||
|
||||
## 8. Owner Guard 与权限边界
|
||||
|
||||
### 8.1 App owner guard
|
||||
|
||||
App 入口所有读写必须以 `getLoginUserId()` 作为唯一账户 owner:
|
||||
|
||||
- 不接受请求体中的 `userId` 作为 owner。
|
||||
- `requestId`、`eventId`、`taskId`、`credentialId`、`correlationId` 都必须反查 owner。
|
||||
- 查不到或 owner 不匹配返回 403 或 404,不能返回跨用户空数据掩盖越权。
|
||||
- `appDownloadExport` 必须同时校验 credential owner、过期、撤销、source blocked 和 task 完成状态。
|
||||
|
||||
### 8.2 Admin 权限边界
|
||||
|
||||
Admin 入口必须使用后端 RBAC:
|
||||
|
||||
| 操作组 | 建议权限点 |
|
||||
|---|---|
|
||||
| 用户摘要/权益/余额/用量/购买记录查询 | `muse:account:query` |
|
||||
| quota adjustment | `muse:account:quota-adjust` |
|
||||
| quota request / New-API binding | `muse:account:new-api:manage` |
|
||||
| call attribution job | `muse:account:attribution:manage` |
|
||||
| security event 管理端查询若后续加入 | `muse:account:security:query` |
|
||||
|
||||
Admin 也必须校验目标用户存在。Admin 只能管理账户域事实,不能绕过 Market、AI、Knowledge 的 owner 状态机。
|
||||
|
||||
## 9. commandId 与幂等
|
||||
|
||||
所有写操作必须通过 `AccountCommandService`:
|
||||
|
||||
| operationId | 幂等目标 |
|
||||
|---|---|
|
||||
| `adminCreateQuotaAdjustment` | `quotaAdjustment:userId` |
|
||||
| `adminCreateNewApiBinding` | `newApiBinding:userId` |
|
||||
| `adminCreateQuotaRequest` | `quotaRequest:userId` |
|
||||
| `adminCreateCallAttributionJob` | `callAttribution:correlationId` |
|
||||
| `updateProfile` | `profile:actorUserId` |
|
||||
| `appRecheckNewApiBinding` | `newApiBindingRecheck:actorUserId` |
|
||||
| `appCreateQuotaRequest` | `quotaRequest:actorUserId` |
|
||||
| `appAcknowledgeSecurityEvent` | `securityEvent:eventId` |
|
||||
| `appCreateExportTask` | `exportTask:actorUserId` |
|
||||
|
||||
规则:
|
||||
|
||||
1. `commandId` 必填的 operation 必须从请求体读取,不依赖 `X-Command-Id`。
|
||||
2. 稳定 JSON 计算 `requestHash`。
|
||||
3. 相同 `commandId` + 相同 `requestHash` 返回旧 `resultSnapshot`,并在 DTO 中按合同表达 `idempotent_hit`。
|
||||
4. 相同 `commandId` + 不同 `requestHash` 返回 409,错误码为 Account 幂等冲突。
|
||||
5. command 预占与业务写入必须在同一事务内。
|
||||
6. 异步任务只保证“任务创建幂等”,不保证外部 runtime 已完成。
|
||||
|
||||
## 10. Audit 与 Security Event
|
||||
|
||||
Account 审计分两层:
|
||||
|
||||
1. `muse_account_command`:所有写命令的幂等和 result snapshot。
|
||||
2. `muse_account_audit`:业务可读审计,覆盖操作者、目标用户、operation、前后状态、correlationId、requestHash、风险摘要。
|
||||
|
||||
最小审计字段:
|
||||
|
||||
- `operationId`
|
||||
- `actorUserId`
|
||||
- `accountUserId`
|
||||
- `side`
|
||||
- `targetType`
|
||||
- `targetId`
|
||||
- `commandId`
|
||||
- `requestHash`
|
||||
- `correlationId`
|
||||
- `beforeSnapshot`
|
||||
- `afterSnapshot`
|
||||
- `status`
|
||||
- `errorCode`
|
||||
- `errorMessage`
|
||||
- `createdAt`
|
||||
|
||||
Security event:
|
||||
|
||||
- `appAcknowledgeSecurityEvent` 必须 append-only 记录 acknowledgement,不应覆盖历史处理动作。
|
||||
- `action=session_revoked` 不在 P1R-3 实现真实 session 失效;若 session owner 未接入,返回明确业务错误或 pending action,不伪造成功。
|
||||
- 账户导出高敏行为应生成 `sensitive_export` security event 或 audit event。
|
||||
|
||||
## 11. 错误响应
|
||||
|
||||
除 `appDownloadExport` 成功响应按 OpenAPI 返回 `application/octet-stream` 文件流外,其余接口使用项目现有 `CommonResult<T>` 成功封装。所有错误响应应保持 `code/data/msg` 的项目运行态一致性,不新增 OpenAPI 未定义字段。
|
||||
|
||||
Account 最小错误码:
|
||||
|
||||
| 场景 | HTTP/业务语义 | 建议业务错误 |
|
||||
|---|---|---|
|
||||
| X-API-Version 不支持 | 400 | `ACCOUNT_API_VERSION_UNSUPPORTED` |
|
||||
| 用户不存在 | 404 | `ACCOUNT_USER_NOT_EXISTS` |
|
||||
| app owner 不匹配 | 403 | `ACCOUNT_RESOURCE_FORBIDDEN` |
|
||||
| commandId 缺失 | 400 | `ACCOUNT_COMMAND_ID_REQUIRED` |
|
||||
| commandId 冲突 | 409 | `ACCOUNT_COMMAND_ID_CONFLICT` |
|
||||
| expectedVersion 冲突 | 409 | `ACCOUNT_VERSION_CONFLICT` |
|
||||
| New-API binding 不存在 | 404 | `ACCOUNT_NEW_API_BINDING_NOT_EXISTS` |
|
||||
| New-API runtime 不可用 | 503 或业务错误 | `ACCOUNT_NEW_API_UNAVAILABLE` |
|
||||
| correlationId 不存在 | 404 | `ACCOUNT_INTEGRATION_CALL_NOT_EXISTS` |
|
||||
| 余额/权益不足 | 409 | `ACCOUNT_QUOTA_EXHAUSTED` |
|
||||
| 下载凭证过期/撤销 | 403 | `ACCOUNT_DOWNLOAD_CREDENTIAL_INVALID` |
|
||||
| 导出来源 blocked | 403 | `ACCOUNT_EXPORT_SOURCE_BLOCKED` |
|
||||
|
||||
## 12. New-API / Correlation 边界
|
||||
|
||||
P1R-3 只定义 Account 与 New-API 的账户侧边界:
|
||||
|
||||
- `adminCreateNewApiBinding` / `appRecheckNewApiBinding` 只能创建 binding 或 recheck job。
|
||||
- binding / recheck 必须写入 `muse_account_integration_call`,并通过 `bindingId` / `jobId` 与内部 `correlationId` 关联;现有 OpenAPI 响应没有 `correlationId` 字段,P1R-3 不修改响应合同。
|
||||
- quota request 和 call attribution 已在 OpenAPI 中暴露 `correlationId`,必须用该值支持 `adminGetIntegrationCallByCorrelation` / `appGetIntegrationCallByCorrelation`。
|
||||
- 真实 New-API 用户创建、额度配置和余额查询若 runtime 未接入,必须以合同内业务错误或内部 pending/failed integration call 记录表达;不能为了“可追踪”向响应添加 OpenAPI 未定义字段,也不能返回 OpenAPI 未声明的状态值。
|
||||
- `muse_account_integration_call` 是外部调用去重、重试、错误和 attribution 的账户侧事实。
|
||||
- `adminGetIntegrationCallByCorrelation` 可看全局调用详情。
|
||||
- `appGetIntegrationCallByCorrelation` 只能查看当前用户 owner 的调用。
|
||||
|
||||
Call attribution:
|
||||
|
||||
- `adminCreateCallAttributionJob` 只能基于已存在的 integration call / New-API callIds。
|
||||
- 请求体不能直接指定可信 user/work/agent/asset/license 归因事实。
|
||||
- 服务端必须从调用审计记录、业务任务、作品、资产、授权关系校验后写 attribution item。
|
||||
- AI runtime 真实调用不在 P1R-3 实现;Account 只消费调用记录。
|
||||
|
||||
## 13. 数据来源
|
||||
|
||||
| 数据域 | P1R-3 数据来源 |
|
||||
|---|---|
|
||||
| user/profile/me | `member_user` + `muse_account_profile` + entitlement/security projection |
|
||||
| entitlements | `muse_member_entitlement` |
|
||||
| quota | `muse_member_quota` + `muse_member_entitlement_audit_log` |
|
||||
| quota requests | `muse_account_quota_request` + integration call |
|
||||
| balance snapshots | `muse_account_balance_snapshot` |
|
||||
| usage records/app usage | `muse_member_usage_record` + attribution fields |
|
||||
| purchase records | `muse_account_record_projection(record_type=purchase)`,上游来自 `muse_market_purchase` |
|
||||
| license records | `muse_account_record_projection(record_type=license)`,上游来自 `muse_market_installation` |
|
||||
| publish records | `muse_account_record_projection(record_type=publish)`,上游来自 `muse_market_publish_request` |
|
||||
| New-API binding | `muse_member_new_api_binding` + recheck job |
|
||||
| integration calls | `muse_account_integration_call` |
|
||||
| call attribution jobs | `muse_account_call_attribution_job` / item |
|
||||
| security events | `muse_member_security_event` + ack extension |
|
||||
| export tasks/downloads | `muse_account_export_task` + `muse_account_download_credential` + FileService boundary;下载成功响应为文件流 |
|
||||
|
||||
## 14. 外部阶段边界
|
||||
|
||||
| 边界 | P1R-3 处理方式 |
|
||||
|---|---|
|
||||
| AI task 真实 New-API 调用 | P1R-4;P1R-3 不创建 AI task、不调模型 |
|
||||
| AI runtime / agent / prompt / quality / suggestions / jobs | P1R-4;Account 只读已归因用量 |
|
||||
| AI task SSE stream | P1R-4;P1R-3 export/call attribution job 不实现 SSE |
|
||||
| Knowledge / RAGFlow / projection | P1R-5;Account 只读授权或用量投影 |
|
||||
| Market | P1R-6;Account 只读购买/授权/发布投影,不处理购买/安装/审核 |
|
||||
| Events SSE / 端到端验收 | P1R-7;P1R-3 不标 completed |
|
||||
| FileService | P1R-3 定义导出下载边界;真实存储未接入时保持 needs_verification |
|
||||
|
||||
## 15. 实现单元
|
||||
|
||||
P1R-3 实现阶段建议按以下单元推进:
|
||||
|
||||
1. Preflight 与覆盖基线冻结。
|
||||
2. Account 基础设施与追加 DDL。
|
||||
3. DTO / DAL / Mapper 骨架。
|
||||
4. App `me` / `profile`。
|
||||
5. 权益、配额、余额、用量。
|
||||
6. New-API binding、recheck、quota request、integration call。
|
||||
7. call attribution job。
|
||||
8. purchase / license / publish records 投影。
|
||||
9. security events。
|
||||
10. export task / download credential。
|
||||
11. Account catch-all 路由退役。
|
||||
12. P1R-3 覆盖门禁与报告对账。
|
||||
|
||||
## 16. 验收标准
|
||||
|
||||
P1R-3 spec + plan review 通过后,进入实现阶段。实现阶段完成必须满足:
|
||||
|
||||
1. Account 33 个 operation 有专用 Controller / Service / DTO。
|
||||
2. Account 33 个 operation 不再是 `generic_persistence`、`catch_all`、`sse_placeholder` 或 `missing`。
|
||||
3. Account operation 未经 P1R-7 真实端到端验收前,不允许标 `completed`。
|
||||
4. Account 全部保持 `dedicated / needs_verification`。
|
||||
5. Content 51 个 operation 保持 `dedicated / needs_verification`。
|
||||
6. Meta 16 个 operation 保持 `dedicated / needs_verification`。
|
||||
7. `completedOperations=0`。
|
||||
8. `muse-cloud/scripts/**` 未被用来掩盖缺口。
|
||||
9. Account 模块聚焦测试通过。
|
||||
10. `P1rAccountMigrationSqlTest` 通过,证明 V11 迁移包含 Account 审计、profile、projection、integration、export/download 等必要约束。
|
||||
11. P1R 门禁测试通过。
|
||||
12. 若未运行真实 PostgreSQL / Flyway / New-API runtime / FileService,必须在留痕中保留 `needs_verification` 风险。
|
||||
|
||||
## 17. 待确认项
|
||||
|
||||
1. P1R-3 是否允许在 `muse-module-member` 内新增 `account` 包作为长期 owner。默认推荐此方案,因为仓库没有 `muse-module-account`,且用户资料属于 member 模块。
|
||||
2. New-API runtime 在 P1R-3 是否有可用测试环境。若没有,binding/recheck/quota request 只能做到合同内业务错误或内部 pending/failed 可追踪,保持 `needs_verification`。
|
||||
3. FileService 是否有可用测试环境。若没有,export task / download credential 只能验证凭证与状态机,不能验证真实文件流交付。
|
||||
Loading…
x
Reference in New Issue
Block a user