From 031a875ec12fbdfcf8bf1ed3cf9306dc462c2e01 Mon Sep 17 00:00:00 2001 From: break Date: Wed, 22 Jul 2026 17:25:05 +0900 Subject: [PATCH] ur36issues --- .../01-batch-unique-asset-resolution.md | 19 +++++++++++++ .../02-controlled-upload-object-ownership.md | 19 +++++++++++++ .../03-real-dependency-integration-harness.md | 19 +++++++++++++ ...04-unified-admin-package-purchasability.md | 19 +++++++++++++ ...5-single-asset-package-purchase-command.md | 23 +++++++++++++++ .../06-idempotent-bulk-purchase-creation.md | 28 +++++++++++++++++++ .../issues/07-validate-csv-persist-items.md | 25 +++++++++++++++++ .../issues/08-offline-bulk-row-purchase.md | 24 ++++++++++++++++ .../09-wallet-bulk-row-purchase-recovery.md | 23 +++++++++++++++ .../issues/10-bulk-purchase-task-queries.md | 22 +++++++++++++++ .../issues/11-real-chain-release-gate.md | 24 ++++++++++++++++ 11 files changed, 245 insertions(+) create mode 100644 .scratch/ur36-bulk-package-purchase/issues/01-batch-unique-asset-resolution.md create mode 100644 .scratch/ur36-bulk-package-purchase/issues/02-controlled-upload-object-ownership.md create mode 100644 .scratch/ur36-bulk-package-purchase/issues/03-real-dependency-integration-harness.md create mode 100644 .scratch/ur36-bulk-package-purchase/issues/04-unified-admin-package-purchasability.md create mode 100644 .scratch/ur36-bulk-package-purchase/issues/05-single-asset-package-purchase-command.md create mode 100644 .scratch/ur36-bulk-package-purchase/issues/06-idempotent-bulk-purchase-creation.md create mode 100644 .scratch/ur36-bulk-package-purchase/issues/07-validate-csv-persist-items.md create mode 100644 .scratch/ur36-bulk-package-purchase/issues/08-offline-bulk-row-purchase.md create mode 100644 .scratch/ur36-bulk-package-purchase/issues/09-wallet-bulk-row-purchase-recovery.md create mode 100644 .scratch/ur36-bulk-package-purchase/issues/10-bulk-purchase-task-queries.md create mode 100644 .scratch/ur36-bulk-package-purchase/issues/11-real-chain-release-gate.md diff --git a/.scratch/ur36-bulk-package-purchase/issues/01-batch-unique-asset-resolution.md b/.scratch/ur36-bulk-package-purchase/issues/01-batch-unique-asset-resolution.md new file mode 100644 index 0000000..e97d7e1 --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/01-batch-unique-asset-resolution.md @@ -0,0 +1,19 @@ +# 01 — 统一资产标识的批量唯一解析 + +**What to build:** 批量订购可以通过系统唯一的资产解析能力,一次解析一组用户输入的资产标识,并稳定得到资产类型、资产 ID 和规范标识。ICCID、卡虚拟号、MSISDN、设备虚拟号、IMEI 和 SN 使用与其他业务相同的注册规则;未命中或历史脏数据导致多命中时明确失败,不能任取一条。 + +**Blocked by:** None — can start immediately + +**Status:** ready-for-agent + +**架构通道:** Application + Port/Adapter。 + +**完整业务边界:** 本票深化公共 Asset 解析接缝,使单个和批量调用共享唯一匹配语义与规范标识选择规则。明确不实现批量订购任务、不迁移资产列表或生命周期逻辑、不在批量模块维护第二套标识白名单。 + +- [ ] 公共解析结果包含原始输入对应的资产类型、资产 ID、规范标识和稳定失败分类,并能区分未命中与多命中。 +- [ ] ICCID、卡虚拟号、唯一 MSISDN、设备虚拟号、IMEI 和 SN 均通过现有全局标识注册规则解析;新增调用方无需复制识别分支。 +- [ ] 同一资产使用不同受支持标识时得到相同资产类型与 ID,规范标识由公共能力统一决定。 +- [ ] 历史脏数据造成多条候选时返回明确歧义,单个和批量调用均不得使用 `First` 或其他任取逻辑。 +- [ ] 批量接口以集合查询或等价批处理方式完成解析,避免按行跨卡表、设备表和标识表形成 N+1。 +- [ ] 测试覆盖全部支持标识、首尾空白、未命中、多命中、不同标识指向同一资产及批量查询次数边界。 + diff --git a/.scratch/ur36-bulk-package-purchase/issues/02-controlled-upload-object-ownership.md b/.scratch/ur36-bulk-package-purchase/issues/02-controlled-upload-object-ownership.md new file mode 100644 index 0000000..9e75d82 --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/02-controlled-upload-object-ownership.md @@ -0,0 +1,19 @@ +# 02 — 交付受控直传与对象归属证明 + +**What to build:** 操作员可以为批量订购 CSV 和线下凭证申请受控上传地址并直传真实私有 S3,业务接口随后能够证明对象由当前账号按声明用途申请、已经真实上传且元数据符合约束。上传授权可原子绑定业务任务,已绑定 Key 不能被其他账号或其他批次复用。 + +**Blocked by:** None — can start immediately + +**Status:** ready-for-agent + +**架构通道:** 主通道为 Infrastructure,辅助通道为简单写 Application。 + +**完整业务边界:** 本票收口预签名上传授权、对象 Head 元数据和业务绑定能力,并增加 `bulk_purchase` 受控用途。明确不解析 CSV、不创建批量任务、不改变其他对象存储消费者的业务语义、不实现内存 Provider。 + +- [ ] `bulk_purchase` 用途只签发批量订购目录下的 `.csv` Key,并限制为允许的 CSV Content-Type;附件继续复用现有 `attachment` 用途和文件类型规则。 +- [ ] 上传授权稳定保存对象 Key、用途、申请账号、声明文件名、声明 Content-Type 和签发时间,不以目录前缀推断上传主体。 +- [ ] 存储 Provider 可以查询对象是否存在、实际大小和实际 Content-Type,并以统一安全错误区分不存在、类型不符、过大和基础设施失败。 +- [ ] 授权绑定使用业务类型、业务 ID 和绑定时间形成持久事实;同一 Key 的并发绑定最终由数据库约束裁决。 +- [ ] 相同业务幂等重试可以识别原绑定,其他账号、其他用途或其他批次复用同一 Key 时明确冲突。 +- [ ] 真实 S3 集成测试覆盖预签名上传、Head、下载、精确删除、10MB 边界、伪造类型、对象不存在、跨账号、跨用途和重复绑定。 + diff --git a/.scratch/ur36-bulk-package-purchase/issues/03-real-dependency-integration-harness.md b/.scratch/ur36-bulk-package-purchase/issues/03-real-dependency-integration-harness.md new file mode 100644 index 0000000..6d2faf7 --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/03-real-dependency-integration-harness.md @@ -0,0 +1,19 @@ +# 03 — 建立批量任务真实依赖的集成测试 Harness + +**What to build:** Agent 和开发者可以通过一个可复用的 Go 集成测试 Harness,安全驱动真实 PostgreSQL、Redis DB 7、真实 S3、Fiber 后台认证和公开 Worker Handler。每次运行只创建、记录和清理带唯一运行标识的资源,测试失败也不会清空或污染共享环境。 + +**Blocked by:** `.scratch/ur36-bulk-package-purchase/issues/02-controlled-upload-object-ownership.md` — 02 — 交付受控直传与对象归属证明 + +**Status:** ready-for-agent + +**架构通道:** Infrastructure。 + +**完整业务边界:** 本票收口本需求及后续同类批量任务需要的安全集成测试基础设施。明确不替换全仓测试框架、不创建新 PostgreSQL 数据库、不使用 S3 内存替身、不通过等待真实后台 Worker 抢任务完成断言。 + +- [ ] Harness 启动时读取最终生效配置,并确认普通 Redis Client、Asynq Client 和 Worker Server 均使用 DB 7;任一不符时在写入前失败。 +- [ ] Harness 支持唯一 `run_id`、测试账号与真实认证、Fiber 请求、统一响应解码、真实 S3 上传及公开 Worker Handler 驱动。 +- [ ] 待投递任务可在应用公开注入点被受控捕获,并以结构化 `task_id` 调用 Handler,不依赖 `sleep` 或私有处理函数。 +- [ ] PostgreSQL、Redis 和 S3 资源进入精确清理台账;成功和失败清理只操作本次创建的主键、Key 和对象,不执行 TRUNCATE、FLUSHDB、前缀扫描或 Bucket 清理。 +- [ ] 清理失败输出安全诊断和未清理资源标识,不输出数据库密码、Token、对象存储密钥、预签名 URL 或完整敏感数据。 +- [ ] 固定 `testdata` 覆盖 UTF-8、BOM、非法表头、重复资产、多代理、钱包不足和线下凭证,并至少提供一个穿过公开 HTTP 与 Worker 边界的示例。 + diff --git a/.scratch/ur36-bulk-package-purchase/issues/04-unified-admin-package-purchasability.md b/.scratch/ur36-bulk-package-purchase/issues/04-unified-admin-package-purchasability.md new file mode 100644 index 0000000..c692dc7 --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/04-unified-admin-package-purchasability.md @@ -0,0 +1,19 @@ +# 04 — 统一后台与批量入口的套餐可售策略 + +**What to build:** 后台单笔订购和批量单行订购可以调用同一套餐可售策略,按写入时的资产、结算代理、套餐授权、渠道状态、价格和操作场景得到一致结论。批量或后台主体不能进入个人历史用户的下架续费例外,也不能绕过禁用、未授权或组合限制。 + +**Blocked by:** None — can start immediately + +**Status:** ready-for-agent + +**架构通道:** 复杂写前置 Domain Policy。 + +**完整业务边界:** 本票收口 UR#36 实际触碰的后台套餐购买策略接缝,并与 UR#40 的统一策略语义兼容。明确不实现 C 端下架续费页面、不迁移套餐管理、不迁移未触碰的订单流程、不在 Query 快照上做最终写入判断。 + +- [ ] 策略输入显式包含操作主体、资产及当前世代、结算代理、套餐、销售渠道和操作场景,不依赖可被遗漏的隐式布尔开关。 +- [ ] 套餐全局禁用、渠道下架、授权缺失或失效、价格异常、赠送及既有套餐组合限制均返回稳定业务失败。 +- [ ] 后台单笔和批量场景遇到下架套餐固定拒绝,不能使用个人客户的 `renew_only` 历史资格。 +- [ ] 结算金额来自结算代理当前有效授权成本和现有定价规则,前端或 CSV 无法提交价格覆盖策略结果。 +- [ ] 写命令在事务前后按最新事实重新校验必要不变量,不能把查询接口先前返回的资格当作授权凭证。 +- [ ] 测试覆盖平台及代理渠道、启用与禁用、上架与下架、授权删除或失效、价格低于成本、组合限制,以及后台与批量结果一致性。 + diff --git a/.scratch/ur36-bulk-package-purchase/issues/05-single-asset-package-purchase-command.md b/.scratch/ur36-bulk-package-purchase/issues/05-single-asset-package-purchase-command.md new file mode 100644 index 0000000..f96072a --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/05-single-asset-package-purchase-command.md @@ -0,0 +1,23 @@ +# 05 — 提供统一的单资产套餐订购命令 + +**What to build:** 现有后台单笔入口和批量任务中的一个业务行可以调用同一个单资产套餐订购命令,按资产当前归属确定结算代理,完成套餐可售校验、定价、订单及套餐激活编排。钱包支付通过统一 Wallet Application/Port 接缝完成,线下支付生成符合现有后台语义的已支付订单。 + +**Blocked by:** + +- `.scratch/ur36-bulk-package-purchase/issues/04-unified-admin-package-purchasability.md` — 04 — 统一后台与批量入口的套餐可售策略 +- `.scratch/ur38-agent-main-wallet-credit/issues/05-unified-agent-wallet-debit.md` — 05 — 统一代理订单、代购与钱包支付扣款 + +**Status:** ready-for-agent + +**架构通道:** 主通道为复杂写,Application UseCase → Order/Package Domain → Repository/Infrastructure;Wallet Application/Port 为辅助通道。 + +**完整业务边界:** 本票迁移后台单资产套餐订购这一最小完整用例,收口资产归属、套餐可售与定价、订单、订单明细、套餐使用及激活编排。钱包领域只通过 UR#38 的稳定接缝协作。明确不迁移其他订单创建、支付、退款、佣金或资产钱包流程。 + +- [ ] 命令只接收规范资产、套餐、支付方式、凭证快照、操作者和稳定业务幂等标识,不接受可信 `shop_id`、结算价格或套餐可售结论。 +- [ ] 每次执行按资产当前归属解析结算代理,并调用统一套餐可售策略重新校验授权、状态、定价及现有订单不变量。 +- [ ] `offline` 创建已支付订单、订单明细和套餐使用并完成现有激活语义,不扣代理钱包;凭证关联作为业务快照保留。 +- [ ] `wallet` 只调用 UR#38 提供的 Wallet Application/Port 接缝;UR#36 不复制信用公式、不直接更新代理钱包模型、不调用旧钱包 Store 扣款条件、不重新实现钱包流水或信用并发规则。 +- [ ] 单次成功订购中的订单、套餐使用与激活、结算代理和价格快照、明细关联、审计及可靠事件原子提交;任何失败不留下部分事实。 +- [ ] 现有后台单笔 HTTP 契约保持不变并迁移为调用该命令;旧订单 Service 如保留,只能作为本用例的内部迁移门面。 +- [ ] 测试覆盖钱包与线下、不同代理归属、未授权、下架、价格异常、资产状态与组合规则、幂等重试及事务回滚。 + diff --git a/.scratch/ur36-bulk-package-purchase/issues/06-idempotent-bulk-purchase-creation.md b/.scratch/ur36-bulk-package-purchase/issues/06-idempotent-bulk-purchase-creation.md new file mode 100644 index 0000000..3fc8576 --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/06-idempotent-bulk-purchase-creation.md @@ -0,0 +1,28 @@ +# 06 — 幂等创建批量订购任务 + +**What to build:** 通过现有后台认证的操作员可以提交唯一 `request_id`、单个套餐、统一支付方式、CSV Key 和凭证 Key 创建批量订购任务。接口在返回已接收任务前验证对象归属和真实元数据,并在同一事务保存套餐与操作者快照、上传绑定、请求指纹、任务事实、创建审计和可靠投递事件。 + +**Blocked by:** + +- `.scratch/ur36-bulk-package-purchase/issues/02-controlled-upload-object-ownership.md` — 02 — 交付受控直传与对象归属证明 +- `.scratch/tech-public-foundation/issues/02-transactional-public-outbox-write.md` — 02 — 在业务事务中可靠写入公共 Outbox +- `.scratch/tech-public-foundation/issues/03-outbox-at-least-once-delivery.md` — 03 — 完成 Outbox 到 Asynq 的至少一次投递闭环 +- `.scratch/tech-public-foundation/issues/05-command-idempotency-contract.md` — 05 — 提供创建命令幂等与并发职责契约 +- `.scratch/tech-public-foundation/issues/06-unified-async-task-contract.md` — 06 — 冻结统一异步任务五态和查询契约 +- `.scratch/tech-global-audit/issues/01-audit-event-write-loop.md` — 01 — 交付不可变 Audit Event 写入闭环 + +**Status:** ready-for-agent + +**架构通道:** 复杂写 Application + Port/Adapter。 + +**完整业务边界:** 本票收口批量订购任务的可靠接收、幂等、上传绑定和投递事实。明确不下载或解析 CSV、不创建逐行明细、不执行订单、不增加批量权限码或任务创建人隔离。 + +- [ ] 请求只接受 `request_id`、`package_id`、`payment_method`、`file_key` 和 `voucher_keys`;显式提交 `shop_id` 返回统一参数错误,其他未知字段不参与业务决策。 +- [ ] `wallet` 要求凭证为空;`offline` 要求 1 至 5 个有效附件;套餐存在性和 ID、编码、名称快照在创建时确定。 +- [ ] CSV 与凭证必须由当前账号按正确用途申请、真实存在且元数据合法;CSV 实际大小不超过 10MB,所有 Key 在任务事务内完成绑定。 +- [ ] 相同 `request_id`、操作者和规范化请求指纹返回原任务;改变套餐、支付方式、文件、凭证或操作者时返回冲突。 +- [ ] 并发首写最终只产生一个任务、一次上传绑定和一个可靠事件;Asynq 暂不可用不丢失已提交任务。 +- [ ] 任务使用全局五态并返回中文状态名;队列载荷只包含结构化 `task_id`,不传 `[]byte`、文件内容、临时路径或认证上下文。 +- [ ] 创建成功写公共审计,记录任务号、支付方式、文件安全摘要和凭证数量,不记录预签名 URL、Token 或环境密钥。 +- [ ] 新 Handler 同步注册后台路由并更新两个 OpenAPI 文档生成入口,所有响应使用统一包装和中文错误码语义。 + diff --git a/.scratch/ur36-bulk-package-purchase/issues/07-validate-csv-persist-items.md b/.scratch/ur36-bulk-package-purchase/issues/07-validate-csv-persist-items.md new file mode 100644 index 0000000..b68edc5 --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/07-validate-csv-persist-items.md @@ -0,0 +1,25 @@ +# 07 — 完整校验 CSV 并固化逐行明细 + +**What to build:** Worker 可以领取待处理批量任务,下载完整 CSV 后先完成全部文件结构和行数校验,再批量解析资产并一次性持久化所有数据行。文件级错误使任务失败且不产生订单;文件有效时每个原始数据行都有稳定行号、解析结果、失败信息和幂等键,可供后续恢复处理。 + +**Blocked by:** + +- `.scratch/ur36-bulk-package-purchase/issues/01-batch-unique-asset-resolution.md` — 01 — 统一资产标识的批量唯一解析 +- `.scratch/ur36-bulk-package-purchase/issues/03-real-dependency-integration-harness.md` — 03 — 建立批量任务真实依赖的集成测试 Harness +- `.scratch/ur36-bulk-package-purchase/issues/06-idempotent-bulk-purchase-creation.md` — 06 — 幂等创建批量订购任务 + +**Status:** ready-for-agent + +**架构通道:** 主通道为 Application,辅助通道为 Infrastructure。 + +**完整业务边界:** 本票收口任务领取、CSV 文件级校验、公共资产批量解析、文件内判重和明细初始化。明确不执行套餐订购、不扣钱包、不创建订单、不支持 Excel 或单行重试。 + +- [ ] Worker 仅领取待处理或租约已过期的处理中任务,终态任务不会重新解析;源对象下载失败按安全任务错误进入失败终态。 +- [ ] CSV 仅接受 UTF-8 或 UTF-8 BOM、LF 或 CRLF、唯一单列表头 `资产标识`;空文件、只有表头、非法编码、引号语法错误、缺列、多列、重复或未知列均为文件级错误。 +- [ ] 实际文件不得超过 10MB,数据行不得超过 1000;Worker 在任何订单写入前读完整文件并确认第 1001 行不存在。 +- [ ] 文件有效后每个数据行都持久化并保留原始行号和原始标识;空值、控制字符、未命中及多命中作为行级失败计数,不被省略。 +- [ ] 文件内重复在公共解析成功后按 `资产类型 + 资产ID` 判断;首次出现行继续处理,后续行失败并指出首次 CSV 行号,不同标识指向同一资产也能识别。 +- [ ] 明细具有 `(任务, 行号)` 和稳定 `bulk_purchase:{task_id}:{row_no}` 幂等约束,并保存公共行处理状态、租约和安全失败码。 +- [ ] 文件验证与明细初始化完成后,Worker 重启直接读取已有明细,不重新生成行号或幂等键;汇总从明细事实聚合。 +- [ ] 真实 S3 和 PostgreSQL 测试覆盖编码、换行、表头、10MB、1000/1001 行、伪装 Excel、空字段、控制字符、资产歧义和跨标识重复。 + diff --git a/.scratch/ur36-bulk-package-purchase/issues/08-offline-bulk-row-purchase.md b/.scratch/ur36-bulk-package-purchase/issues/08-offline-bulk-row-purchase.md new file mode 100644 index 0000000..69c1259 --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/08-offline-bulk-row-purchase.md @@ -0,0 +1,24 @@ +# 08 — 逐行完成线下支付批量订购 + +**What to build:** 文件校验通过的线下支付任务可以严格按 CSV 行号逐行订购套餐。每行按资产当前归属确定结算代理,调用统一单资产订购命令创建已支付订单并激活套餐;一行业务失败只记录该行中文原因并继续,成功订单都能追溯批次及整批凭证。 + +**Blocked by:** + +- `.scratch/ur36-bulk-package-purchase/issues/05-single-asset-package-purchase-command.md` — 05 — 提供统一的单资产套餐订购命令 +- `.scratch/ur36-bulk-package-purchase/issues/07-validate-csv-persist-items.md` — 07 — 完整校验 CSV 并固化逐行明细 + +**Status:** ready-for-agent + +**架构通道:** 复杂写,Application → Order/Package Domain。 + +**完整业务边界:** 本票收口批量任务的 `offline` 逐行执行、结果记录和任务终态。明确不建设凭证金额核销、跨批唯一、自动财务对账、单行重试或钱包扣款。 + +- [ ] Worker 仅按 `row_no ASC` 串行领取待处理或过期处理中明细,不并发改变业务顺序,已有成功或失败终态不可被覆盖。 +- [ ] 每行重新读取资产当前归属并解析结算代理,任务创建时不存在单一代理快照,也不接受前端提供的 `shop_id`。 +- [ ] 有效行调用统一单资产套餐订购命令,按结算代理当前授权、价格和套餐规则创建已支付订单并激活套餐,不扣任何代理钱包。 +- [ ] 整批凭证 Key 快照关联到每个成功订单和批次审计;凭证可以被其他批次使用,不建立内容或金额唯一性。 +- [ ] 资产、归属、授权、下架、价格、组合及订单业务错误写稳定失败码和中文原因后继续下一行,底层错误不原样返回。 +- [ ] 成功行的订单、套餐使用与激活、明细成功状态、逐行关联、Audit Event 和 Outbox 原子提交;事务失败不会留下可重复执行的部分事实。 +- [ ] 所有业务行处理完后任务进入已完成;全部成功、部分成功或全部业务失败只通过计数表达,`processed_count = success_count + fail_count = total_count`。 +- [ ] 测试覆盖多代理、凭证 1 个和 5 个、未授权、下架、全部失败、部分成功、重复 Worker 领取和单行事务回滚。 + diff --git a/.scratch/ur36-bulk-package-purchase/issues/09-wallet-bulk-row-purchase-recovery.md b/.scratch/ur36-bulk-package-purchase/issues/09-wallet-bulk-row-purchase-recovery.md new file mode 100644 index 0000000..94817e7 --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/09-wallet-bulk-row-purchase-recovery.md @@ -0,0 +1,23 @@ +# 09 — 逐行完成钱包批量订购与崩溃恢复 + +**What to build:** 钱包支付任务可以严格按 CSV 行号,分别使用每个资产结算代理的主钱包完成订购。同一代理资金不足只失败当前行,后续更便宜的行仍按当时可用金额判断;重复消息、并发 Worker 和进程中断恢复不会重复创建订单、扣款、写流水或激活套餐。 + +**Blocked by:** + +- `.scratch/ur36-bulk-package-purchase/issues/05-single-asset-package-purchase-command.md` — 05 — 提供统一的单资产套餐订购命令 +- `.scratch/ur36-bulk-package-purchase/issues/08-offline-bulk-row-purchase.md` — 08 — 逐行完成线下支付批量订购 + +**Status:** ready-for-agent + +**架构通道:** 复杂写,Application → Order/Package Domain,辅助调用 Wallet Application/Port。 + +**完整业务边界:** 本票在已经验证的逐行任务闭环上增加 `wallet` 支付和故障恢复。它通过 UR#36 Ticket 05 间接消费 UR#38 的钱包能力,不直接依赖或重新实现 Wallet Domain。明确不预占整批资金、不并行结算、不迁移其他钱包用例。 + +- [ ] 每行按当前资产归属定位结算代理,并通过统一单资产订购命令调用 Wallet Application/Port;批量代码不读取信用字段计算可用金额,不直接更新钱包或创建钱包流水。 +- [ ] 严格行序决定同一代理的资金使用优先级,不按代理汇总预占;当前行余额不足只失败该行,后续金额较小且资金足够时可以成功。 +- [ ] 任务和明细使用状态条件、处理租约及稳定幂等键领取;只有租约所有者可以提交处理中状态,终态不可重复执行。 +- [ ] 两个 Worker 同时领取、重复 Asynq 消息、任务租约过期和行租约过期时,订单、钱包扣款、真实金额流水、套餐激活及成功审计各最多一次。 +- [ ] 单行事务提交前崩溃可安全重试;提交后但确认前崩溃可从订单、明细和幂等事实恢复,不得再次扣款。 +- [ ] 钱包不足、无有效主钱包、信用关闭或额度不足等稳定业务失败记录中文安全原因;数据库、Redis 或底层钱包错误不泄露给前端。 +- [ ] 任务终态汇总从明细重新聚合并记录涉及代理数、成功金额、成功数和失败数,同时写任务终态公共审计。 +- [ ] 并发与故障测试覆盖多代理各扣主钱包、现金与信用、无钱包、前贵后便宜、普通订单并发、双 Worker、重复消息及事务提交前后故障。 diff --git a/.scratch/ur36-bulk-package-purchase/issues/10-bulk-purchase-task-queries.md b/.scratch/ur36-bulk-package-purchase/issues/10-bulk-purchase-task-queries.md new file mode 100644 index 0000000..3af524e --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/10-bulk-purchase-task-queries.md @@ -0,0 +1,22 @@ +# 10 — 提供任务汇总与逐行明细查询 + +**What to build:** 通过现有后台认证的调用方可以查询批量订购任务汇总及逐行结果,在刷新或重新打开页面后恢复进度。接口按固定行号顺序分页,支持状态和资产标识精确筛选,并返回套餐、结算代理、金额、订单及中文失败信息,不暴露存储凭证、钱包余额或底层错误。 + +**Blocked by:** `.scratch/ur36-bulk-package-purchase/issues/09-wallet-bulk-row-purchase-recovery.md` — 09 — 逐行完成钱包批量订购与崩溃恢复 + +**Status:** ready-for-agent + +**架构通道:** Query。 + +**完整业务边界:** 本票收口批量订购任务详情和明细读取模型、DTO 与后台路由。明确不建立通用任务中心、不修改任务状态、不增加任务创建人隔离或新的 RBAC、不迁移其他任务查询。 + +- [ ] 任务详情返回任务号、请求 ID、套餐快照、支付方式、状态与中文名称、源文件摘要、凭证引用、操作者、计数、涉及代理数、成功金额、安全错误和起止时间。 +- [ ] 明细查询默认第 1 页、每页 20 条且最大 100,始终按 `row_no ASC`;前端不能改变业务处理顺序。 +- [ ] `status` 只接受公共行处理状态,`asset_identifier` 去除首尾空白后仅在当前任务内对原始或规范标识精确匹配;多个筛选使用 AND。 +- [ ] 每行返回行号、资产类型、原始标识、资产 ID、规范标识、结算代理快照、金额、状态与中文名称、订单、失败码、中文原因和处理时间。 +- [ ] 汇总从明细事实计算或校准,始终满足 `processed_count = success_count + fail_count`;解析阶段允许总数为 0,部分成功不增加私有状态。 +- [ ] 查询只复用现有后台认证与公共数据范围,不新增批量权限码、账号类型拦截或按创建人隔离;无权与不存在遵循项目统一安全语义。 +- [ ] 响应不包含 SQL、底层错误、永久对象访问凭证、Redis Key、预签名 URL、其他代理钱包余额或环境秘密。 +- [ ] 新 Handler 同步后台路由及两个 OpenAPI 文档生成入口;DTO 枚举说明从公共常量原文复制并包含所有 `status_name`。 +- [ ] HTTP 测试覆盖默认与最大分页、固定排序、状态与标识 AND 筛选、任务汇总、认证失效、跨创建人查询语义和安全字段边界。 + diff --git a/.scratch/ur36-bulk-package-purchase/issues/11-real-chain-release-gate.md b/.scratch/ur36-bulk-package-purchase/issues/11-real-chain-release-gate.md new file mode 100644 index 0000000..f4c12ed --- /dev/null +++ b/.scratch/ur36-bulk-package-purchase/issues/11-real-chain-release-gate.md @@ -0,0 +1,24 @@ +# 11 — 完成真实链路验收、文档与发布门禁 + +**What to build:** 发布负责人可以通过自动化测试、OpenAPI、静态 CSV 模板和中文联调契约,验证从后台认证、真实 S3 直传、任务创建、可靠投递、Worker 执行到任务查询的完整链路。发布和回滚步骤明确保护已经产生的订单、钱包流水、套餐使用、任务和审计事实。 + +**Blocked by:** + +- `.scratch/ur36-bulk-package-purchase/issues/03-real-dependency-integration-harness.md` — 03 — 建立批量任务真实依赖的集成测试 Harness +- `.scratch/ur36-bulk-package-purchase/issues/10-bulk-purchase-task-queries.md` — 10 — 提供任务汇总与逐行明细查询 + +**Status:** ready-for-agent + +**架构通道:** 主通道为 Infrastructure,辅助通道为 Application 与 Query 验收。 + +**完整业务边界:** 本票收口 UR#36 的真实依赖验收、接口文档、静态模板、中文功能总结、发布与回滚门禁。本仓库不实现前端页面;只提供前端交互所需的 API、OpenAPI、静态 CSV 模板和联调验收契约,不扩展为全仓测试治理。 + +- [ ] 完整示例穿过真实后台认证、预签名 URL、真实 S3 PUT 与 Head、创建 API、可靠任务投递、公开 Worker Handler、PostgreSQL 事实和查询 API。 +- [ ] 自动化覆盖文件级零订单失败、行业务部分成功、全部行业务失败、多代理线下与钱包、信用与余额不足、严格行序、幂等 HTTP、双 Worker 和崩溃恢复。 +- [ ] 审计验证任务创建、任务终态、成功订单和钱包事实可串联,且响应、日志、审计和测试输出不包含密钥、Token、预签名 URL 或底层错误。 +- [ ] 提供只有 `资产标识` 一列的 UTF-8 静态 CSV 模板,并明确支持的标识、1000 行、10MB、不接受 Excel及长数字保护提示。 +- [ ] OpenAPI 完整包含上传用途、创建任务、任务详情和明细查询契约;两个文档生成入口一致,生成校验无漂移。 +- [ ] 前端交互联调契约覆盖单套餐、钱包或线下支付、1 至 5 个凭证、四阶段页面、重复点击复用 `request_id`、刷新恢复、解析中空进度、部分成功计数、失败默认筛选和精确搜索。 +- [ ] 中文功能总结和 README 说明领域边界、接口、失败闭环、真实依赖测试、部署顺序、监控、停用入口及回滚限制。 +- [ ] 发布门禁包含目标及相关包测试、全量 Go 测试、并发或竞态专项、静态检查、OpenAPI 生成、迁移升降级验证,以及 PostgreSQL、Redis/Asynq 和真实 S3 配置核验。 +- [ ] 回滚先关闭创建入口并处置待处理或处理中任务;已经形成的标准订单、钱包流水、套餐使用、批量任务和审计作为业务事实保留,不执行反向删除。