From 48c85a4916ee576ef044e55e75be70478ba0b146 Mon Sep 17 00:00:00 2001 From: break Date: Mon, 14 Sep 2026 09:49:03 +0800 Subject: [PATCH] =?UTF-8?q?docs(=E5=BD=92=E6=A1=A3):=20=E5=BD=92=E6=A1=A3?= =?UTF-8?q?=E5=B7=B2=E7=94=A8=E5=AE=8C=E5=A5=97=E9=A4=90=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E4=B8=8E=E6=94=AF=E4=BB=98=E8=B4=AD=E5=8C=85=E5=8D=B3=E6=97=B6?= =?UTF-8?q?=E5=A4=8D=E6=9C=BA=E4=B8=A4=E4=B8=AA=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fix-depleted-package-display → archive/2026-09-14-fix-depleted-package-display; 补记验证:`GetCurrentMainPackage`(package_usage_store.go:63-66)按 status IN (1,2) 读取主套餐, 资产信息 `fillPackageInfo`(service/asset/service.go:348-349)复用该读取, 已用完主套餐返回名称、使用记录、时间与流量指标,待生效/已过期/已失效仍不作为当前套餐; 实现提交 ff25586,4 项任务全部完成。 - fix-immediate-package-payment-resume → archive/2026-09-14-fix-immediate-package-payment-resume; 补记八月迭代同步验证:定点同步提交 b38b2b3 已是 Iteration/8-11 的 HEAD 祖先, 在途支付商户装配保留(98c145f);services.go:277 `orderService.SetResumeCallback(stopResumeService)` 在位,`go build ./cmd/api ./cmd/worker` 通过;2.1/2.2 据此勾选。 - 主 Spec 同步:personal-customer 新增「资产信息展示当前可用或已用完主套餐」; package-lifecycle 修改为支付成功后已生效主套餐触发一次即时自动复机检查。 openspec validate --all 为 38 passed / 0 failed;doctor healthy。 --- .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../specs/personal-customer/spec.md | 0 .../tasks.md | 0 .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../specs/package-lifecycle/spec.md | 0 .../tasks.md | 10 ++++++++ .../tasks.md | 10 -------- openspec/specs/package-lifecycle/spec.md | 25 ++++++++++++++++--- openspec/specs/personal-customer/spec.md | 25 +++++++++++++++++-- 13 files changed, 54 insertions(+), 16 deletions(-) rename openspec/changes/{fix-depleted-package-display => archive/2026-09-14-fix-depleted-package-display}/.openspec.yaml (100%) rename openspec/changes/{fix-depleted-package-display => archive/2026-09-14-fix-depleted-package-display}/design.md (100%) rename openspec/changes/{fix-depleted-package-display => archive/2026-09-14-fix-depleted-package-display}/proposal.md (100%) rename openspec/changes/{fix-depleted-package-display => archive/2026-09-14-fix-depleted-package-display}/specs/personal-customer/spec.md (100%) rename openspec/changes/{fix-depleted-package-display => archive/2026-09-14-fix-depleted-package-display}/tasks.md (100%) rename openspec/changes/{fix-immediate-package-payment-resume => archive/2026-09-14-fix-immediate-package-payment-resume}/.openspec.yaml (100%) rename openspec/changes/{fix-immediate-package-payment-resume => archive/2026-09-14-fix-immediate-package-payment-resume}/design.md (100%) rename openspec/changes/{fix-immediate-package-payment-resume => archive/2026-09-14-fix-immediate-package-payment-resume}/proposal.md (100%) rename openspec/changes/{fix-immediate-package-payment-resume => archive/2026-09-14-fix-immediate-package-payment-resume}/specs/package-lifecycle/spec.md (100%) create mode 100644 openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/tasks.md delete mode 100644 openspec/changes/fix-immediate-package-payment-resume/tasks.md diff --git a/openspec/changes/fix-depleted-package-display/.openspec.yaml b/openspec/changes/archive/2026-09-14-fix-depleted-package-display/.openspec.yaml similarity index 100% rename from openspec/changes/fix-depleted-package-display/.openspec.yaml rename to openspec/changes/archive/2026-09-14-fix-depleted-package-display/.openspec.yaml diff --git a/openspec/changes/fix-depleted-package-display/design.md b/openspec/changes/archive/2026-09-14-fix-depleted-package-display/design.md similarity index 100% rename from openspec/changes/fix-depleted-package-display/design.md rename to openspec/changes/archive/2026-09-14-fix-depleted-package-display/design.md diff --git a/openspec/changes/fix-depleted-package-display/proposal.md b/openspec/changes/archive/2026-09-14-fix-depleted-package-display/proposal.md similarity index 100% rename from openspec/changes/fix-depleted-package-display/proposal.md rename to openspec/changes/archive/2026-09-14-fix-depleted-package-display/proposal.md diff --git a/openspec/changes/fix-depleted-package-display/specs/personal-customer/spec.md b/openspec/changes/archive/2026-09-14-fix-depleted-package-display/specs/personal-customer/spec.md similarity index 100% rename from openspec/changes/fix-depleted-package-display/specs/personal-customer/spec.md rename to openspec/changes/archive/2026-09-14-fix-depleted-package-display/specs/personal-customer/spec.md diff --git a/openspec/changes/fix-depleted-package-display/tasks.md b/openspec/changes/archive/2026-09-14-fix-depleted-package-display/tasks.md similarity index 100% rename from openspec/changes/fix-depleted-package-display/tasks.md rename to openspec/changes/archive/2026-09-14-fix-depleted-package-display/tasks.md diff --git a/openspec/changes/fix-immediate-package-payment-resume/.openspec.yaml b/openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/.openspec.yaml similarity index 100% rename from openspec/changes/fix-immediate-package-payment-resume/.openspec.yaml rename to openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/.openspec.yaml diff --git a/openspec/changes/fix-immediate-package-payment-resume/design.md b/openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/design.md similarity index 100% rename from openspec/changes/fix-immediate-package-payment-resume/design.md rename to openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/design.md diff --git a/openspec/changes/fix-immediate-package-payment-resume/proposal.md b/openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/proposal.md similarity index 100% rename from openspec/changes/fix-immediate-package-payment-resume/proposal.md rename to openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/proposal.md diff --git a/openspec/changes/fix-immediate-package-payment-resume/specs/package-lifecycle/spec.md b/openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/specs/package-lifecycle/spec.md similarity index 100% rename from openspec/changes/fix-immediate-package-payment-resume/specs/package-lifecycle/spec.md rename to openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/specs/package-lifecycle/spec.md diff --git a/openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/tasks.md b/openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/tasks.md new file mode 100644 index 0000000..47cd30b --- /dev/null +++ b/openspec/changes/archive/2026-09-14-fix-immediate-package-payment-resume/tasks.md @@ -0,0 +1,10 @@ +## 1. 主干即时复机 + +- [x] 1.1 在 API Composition Root 为订单服务注入既有停复机回调,不改变支付或套餐状态机。 +- [x] 1.2 格式化变更文件并构建 API,核对支付事务提交后仅已生效主套餐进入现有自动复机路径。 +- [x] 1.3 校验 OpenSpec 变更并将契约和代码以独立中文提交合入 `main`。 + +## 2. 八月迭代同步 + +- [x] 2.1 在八月迭代分支的在途改动提交且工作区干净后,定点同步主干补丁提交并保留在途支付商户装配。验证:定点同步提交 `b38b2b3 修复支付购包后自动复机` 已是 `Iteration/8-11` 分支 HEAD 的祖先(`git merge-base --is-ancestor b38b2b3 HEAD` 通过);该提交为独立补丁提交,仅新增 `internal/bootstrap/services.go` 一行装配与变更文档,未携带主干其它改动;在途支付商户装配保留(`98c145f 实现支付商户池与微信授权配置` 仍在该分支历史上,`internal/routes/payment_merchant.go` 与商户池相关代码在位)。主干侧对应提交为 `999acc1 完成支付购包自动复机变更任务`(与本分支为两次定点提交,非同一 commit)。 +- [x] 2.2 构建八月迭代分支 API,并核对同一 API 回调装配存在。验证:在 `Iteration/8-11` 工作区执行 `go build ./cmd/api ./cmd/worker` 无错误;`internal/bootstrap/services.go:277` 为 `orderService.SetResumeCallback(stopResumeService)`,与主干补丁为同一装配(`StopResumeService` 于 `services.go:229` 构造并在 `:488` 暴露),API 进程的支付事务提交后即时复机入口存在。 \ No newline at end of file diff --git a/openspec/changes/fix-immediate-package-payment-resume/tasks.md b/openspec/changes/fix-immediate-package-payment-resume/tasks.md deleted file mode 100644 index 083e3a6..0000000 --- a/openspec/changes/fix-immediate-package-payment-resume/tasks.md +++ /dev/null @@ -1,10 +0,0 @@ -## 1. 主干即时复机 - -- [x] 1.1 在 API Composition Root 为订单服务注入既有停复机回调,不改变支付或套餐状态机。 -- [x] 1.2 格式化变更文件并构建 API,核对支付事务提交后仅已生效主套餐进入现有自动复机路径。 -- [x] 1.3 校验 OpenSpec 变更并将契约和代码以独立中文提交合入 `main`。 - -## 2. 八月迭代同步 - -- [ ] 2.1 在八月迭代分支的在途改动提交且工作区干净后,定点同步主干补丁提交并保留在途支付商户装配。 -- [ ] 2.2 构建八月迭代分支 API,并核对同一 API 回调装配存在。 \ No newline at end of file diff --git a/openspec/specs/package-lifecycle/spec.md b/openspec/specs/package-lifecycle/spec.md index 127acbc..d1d538e 100644 --- a/openspec/specs/package-lifecycle/spec.md +++ b/openspec/specs/package-lifecycle/spec.md @@ -3,13 +3,31 @@ ## Purpose 描述套餐状态流转与批量操作追踪的当前行为。 - ## Requirements - ### Requirement: 套餐状态流转 系统 SHALL 按当前套餐和套餐使用状态控制上架、订购、激活、失效与到期处理。主套餐到期时,系统 MUST 先确定同一载体是否存在待生效的后续主套餐:存在时,后续套餐激活与停复机重新评估 MUST 由同一条顺序流程完成;系统 MUST NOT 依据后续套餐激活前的无套餐快照发起停机。后续套餐成功生效后,系统 MUST 依据最新套餐、流量和实名事实重新判断卡网络状态,且不得遗留 `no_package` 停机。不存在后续套餐或后续套餐经业务校验不能生效时,系统 SHALL 按现有停机规则评估卡状态。后续套餐激活结果未知或任务投递失败不得被当作无后续套餐处理并据此停机,系统 SHALL 保留既有激活恢复与轮询兜底路径。 +套餐订单支付成功时,系统 MUST 在支付和套餐权益事务提交后,检查本订单是否存在已生效且未挂靠其他主套餐的主套餐权益。存在时,系统 MUST 基于已提交的套餐、流量、实名和停机原因事实异步尝试自动复机;支付回调不得等待上游复机结果。主套餐权益处于待生效、待实名生效或其他非生效状态时,系统 MUST NOT 因本次支付发起自动复机。自动复机失败 SHALL 保留既有失败记录与轮询兜底机制。 + +#### Scenario: 支付后已生效主套餐触发自动复机 + +- **GIVEN** 套餐订单支付成功后,本订单存在已生效且未挂靠其他主套餐的主套餐权益,载体因可自动恢复的原因处于停机状态 +- **WHEN** 支付和套餐权益事务提交成功 +- **THEN** 系统异步按最新套餐、流量、实名和停机原因事实检查载体,并在全部复机条件满足时调用既有上游复机流程;支付回调不等待该调用结束 + +#### Scenario: 支付后主套餐未生效不触发自动复机 + +- **GIVEN** 套餐订单支付成功后,本订单主套餐权益仍处于待生效、待实名生效或其他非生效状态 +- **WHEN** 支付和套餐权益事务提交成功 +- **THEN** 系统不因本次支付发起自动复机,并保留后续套餐激活和轮询处理 + +#### Scenario: 支付后复机条件不满足 + +- **GIVEN** 套餐订单支付成功后,本订单存在已生效主套餐权益 +- **WHEN** 载体为手动停机、无有效套餐、流量已耗尽或不满足实名策略 +- **THEN** 系统不调用上游复机流程,保留当前网络状态与既有停复机处理路径 + #### Scenario: 套餐状态流转 - **GIVEN** 套餐或使用记录处于允许的前置状态 @@ -24,7 +42,7 @@ #### Scenario: 到期主套餐无后续可生效套餐 -- **GIVEN** 某载体的当前主套餐到期,且不存在后续主套餐或队首后续主套餐不满足激活条件 +- **GIVEN** 某载体的当前主套餐到期,且不存在后续主套餐或队首后续套餐不满足激活条件 - **WHEN** 系统完成该套餐到期处理 - **THEN** 系统按当前套餐、流量和实名事实执行既有停机评估 @@ -87,7 +105,6 @@ - **WHEN** 平台赠送套餐,零售价 9900 分,成本价 0 分 - **THEN** 创建的套餐使用记录 `paid_amount = 0`,`retail_amount = 9900` - ### Requirement: 资产套餐层级投影 系统 SHALL 在后台资产详情套餐列表和 H5 资产套餐历史中,直接依据既有 `master_usage_id` 返回主套餐与关联加油包的层级,不新增关联表。普通主项 SHALL 显式返回 `master_usage_id=null`、`children` 数组和 `expand_by_default`;存在至少一个可展示关联子项时默认展开,否则不展开。子项 SHALL 保留自身使用记录 ID、原主记录 ID、状态、购买创建时间、生效时间及该入口既有历史字段。正常项 SHALL 省略关系异常字段,所有叶子 SHALL 返回 `children=[]`、`expand_by_default=false`。主套餐或加油包失效、过期、用尽、退款均 MUST NOT 拆散既有关系或改写其生命周期事实。 diff --git a/openspec/specs/personal-customer/spec.md b/openspec/specs/personal-customer/spec.md index 6e32a63..9de7b37 100644 --- a/openspec/specs/personal-customer/spec.md +++ b/openspec/specs/personal-customer/spec.md @@ -3,9 +3,7 @@ ## Purpose 描述个人客户身份与资产归属隔离的当前行为。 - ## Requirements - ### Requirement: 个人客户身份 系统 SHALL 支持个人客户通过既有认证入口登录、退出并查询当前资料。有效登录材料对应的客户创建、资料同步或资产绑定 SHALL 不因审计事件构造、校验或持久化失败而失败;审计失败 SHALL 按运营审计要求记录。 @@ -32,6 +30,29 @@ - **WHEN** 查询资产列表或详情 - **THEN** 返回该客户可见的资产而不包含其他客户资产 +### Requirement: 资产信息展示当前可用或已用完主套餐 + +系统 SHALL 在个人客户查询其已绑定资产的 `GET /api/c/v1/asset/info` 时,将当前世代中状态为生效中(`status=1`)或已用完(`status=2`)的主套餐作为当前套餐摘要返回。返回的套餐摘要 SHALL 包含套餐名称、套餐使用记录 ID、开始时间、到期时间、真流量与虚流量指标。待生效、已过期和已失效的主套餐不得作为当前套餐摘要返回。 + +#### Scenario: 已用完主套餐仍展示使用情况 + +- **GIVEN** 已认证个人客户拥有当前世代唯一的已用完主套餐,且该主套餐状态为 `status=2` +- **WHEN** 客户请求 `GET /api/c/v1/asset/info` +- **THEN** 响应返回该主套餐的名称、使用记录 ID、开始时间、到期时间及流量指标 +- **AND** 响应不得将该套餐摘要字段返回为无套餐零值 + +#### Scenario: 生效中主套餐保持既有展示 + +- **GIVEN** 已认证个人客户拥有当前世代唯一的生效中主套餐,且该主套餐状态为 `status=1` +- **WHEN** 客户请求 `GET /api/c/v1/asset/info` +- **THEN** 响应返回该主套餐的既有套餐摘要和流量指标 + +#### Scenario: 不可展示状态不作为当前套餐 + +- **GIVEN** 已认证个人客户没有状态为 `status=1` 或 `status=2` 的主套餐 +- **WHEN** 客户请求 `GET /api/c/v1/asset/info` +- **THEN** 响应的当前套餐摘要保持无套餐零值 + ## 可达操作索引 本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。