From d1fd0abd736d180d586ed93c818ed4517c5faa40 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Fri, 10 Jul 2026 09:52:14 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20P2=20=E8=AE=A1=E5=88=92=20HTML=20?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E7=89=88=20+=20index=20=E6=94=B9=E6=8C=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- docs/index.html | 2 +- docs/pay-v2-p2-plan.html | 107 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 docs/pay-v2-p2-plan.html diff --git a/docs/index.html b/docs/index.html index cfbae9d..86ac6b6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -57,7 +57,7 @@
阅读版;执行真相源 docs/superpowers/plans/2026-07-10-pay-v2-p1-core-model.md(含 checkbox)。pay v2 设计的首个落地阶段(8 阶段之 P1)。4 个 TDD 任务:money 包(int64 最小单位+币种)→ Order/Attempt/Account/Refund 模型+状态机+:memory: 测试约定 → OrderStore(幂等标付/取消/列表,条件UPDATE+RowsAffected)→ 账户配置注册表(凭证走 env)。沿用 GORM AutoMigrate/glebarez sqlite 惯例;金额从 string 元改 int64。P2-P8(Provider/收款管线/渠道 adapter/退款/路由/对账/codes 库/订阅)各自成计划、落地前细化。
P1 · 2026-07-10 · Go(Gin+GORM+sqlite) · 待执行
- +
pay v2 · P2 收款管线 + Provider 抽象 + webhook v2(计划)
7 个 TDD 任务:Provider 接口(create/verify_callback/query)+6 render_type+PaidEvent+注册表 → fake provider → OrderStore 扩展 → 一次性收款管线 gateway → 统一入账/开通(复用 P1 MarkAttemptPaid 幂等)→ webhook v2 outbox+Notifier(event_type+HMAC)→ HTTP /v1 接线。复用 P1 全部类型、免 docker。/v1 与 v1 /api/v1 并存。
P2 · 2026-07-10 · 待执行 · 真相源 .md
diff --git a/docs/pay-v2-p2-plan.html b/docs/pay-v2-p2-plan.html new file mode 100644 index 0000000..9ca8d11 --- /dev/null +++ b/docs/pay-v2-p2-plan.html @@ -0,0 +1,107 @@ + + + + + +pay v2 · P2 收款管线 + Provider 抽象(阅读版) + + + +
+← 返回文档索引 +

pay v2 · P2 收款管线 + Provider 抽象 + webhook v2 (阅读版)

+

执行真相源 docs/superpowers/plans/2026-07-10-pay-v2-p2-pipeline.md(含 checkbox + 每步完整代码/测试)。设计见 pay v2 设计,DAG 见 依赖图

+ +
+P2 目标:在 P1 数据地基上搭起一次性收款的完整管线 —— Provider 渠道抽象(6 render_type)+ 建单/查单/重试/取消 + 统一入账/开通(webhook 与 query 都归一成 PaidEvent,复用 P1 的幂等标付)+ pay→业务方 webhook v2(带 event_type)。用一个 fake provider 端到端验证管线,真渠道在 P3。全程复用 P1、免 docker。 +
+ +

7 个 TDD 任务

+ +
+

Task 1 · Provider 抽象接口 + render_type + PaidEvent + 注册表

+

文件 internal/provider/provider.go。核心契约,P3 所有渠道 adapter 依赖它:

+
type Provider interface {
+  Method() string
+  Capabilities() Capabilities
+  Create(ctx, CreateRequest) (*Session, error)
+  VerifyCallback(ctx, CallbackInput) (*PaidEvent, error)
+  Query(ctx, providerRef string) (*PaidEvent, error)
+}
+// 可选子接口:RefundingProvider(P4)、RecurringProvider(P8)
+type Session   struct { ProviderRef string; RenderType string; Payload map[string]any; ExpiresAt *time.Time }
+type PaidEvent struct { ProviderRef string; Status PaidStatus; PaidAmountMinor int64; PaidCurrency, Raw string }
+

6 个 render_type 常量 + PaidPending/Succeeded/Failed;Registry(Register/Get/Methods + ErrUnknownMethod)。

+
+ +
+

Task 2 · fake provider(测试用)

+internal/provider/fake/fake.go —— 实现 Provider,Method()=="fake"、render=crypto_address;带 SetQueryResult 测试 seam。P2 用它端到端验管线,不接真渠道。 +
+ +
+

Task 3 · OrderStore 扩展(查询)

+internal/store/order_query.go:GetOrder / AttemptByProviderRef / ListAttemptsByStatus / ExpirePendingAttempts + 哨兵错误。为管线定位订单/尝试用。 +
+ +
+

Task 4 · 一次性收款管线 gateway

+internal/gateway/gateway.go:CreateOrder(选 provider→create→落 Order+Attempt→返回 {order_no, session:{render_type,payload}})/ GetOrder / RetryOrder / CancelOrder。接口 ProductResolver.Resolve(sku)(取权威价/币种/subject/bizCode)、WebhookEnqueuer.Enqueue(...)。 +
+ +
+

Task 5 · 统一入账/开通管线 settle

+internal/gateway/settle.go:Settle(ctx, *PaidEvent) = 归一 → 定位(provider_ref→attempt→order)→ 币种/金额核对 → 复用 P1 MarkAttemptPaid 幂等 → 仅翻转时入队 payment.succeededHandleCallback(webhook 入口)、SyncPendingAttempts(query 兜底)都汇入这条。SettleResult:ignored/not_found/amount_mismatch/duplicate/processed。 +
+ +
+

Task 6 · webhook v2 outbox + Notifier

+model.WebhookDelivery(uniqueIndex(out_trade_no,event_type) 幂等)+ store.WebhookStore(Enqueue/ListUndelivered/MarkDelivered/MarkFailed)+ webhook.Notifier(DeliverPending/Start,HMAC 头 X-Pay-System/Event/Timestamp/Nonce/Sign,失败重试)。event_type 从 payment.succeeded。 +
+ +
+

Task 7 · HTTP /v1 接线

+router.SetupV2POST /v1/ordersGET /v1/orders/:no.../retry.../cancelPOST /v1/callback/:method;main.go 装配 provider 注册表 + gateway + notifier,AutoMigrate 加 WebhookDelivery。 +
+ +

关键设计取舍(计划 Self-Review 已记)

+ + + + + + + + + +
取舍说明
fake provider_ref需纳秒唯一化——P1 Attempt 有 uniqueIndex(channel,provider_ref),retry 同 method 会撞键(真渠道天然不同 ref)
webhook 无 biz_codeP1 OrderV2 无 biz_code 列,不改已落地 schema;业务方暂用 biz_ref 映射,P3 补
路由取首个账户P2 取"首个 enabled 账户",完整路由策略在 P5
币种走部署默认多币种在 P3+
/v1 与 /api/v1 并存v2 新端点与 v1 旧端点并存,收口在 pay 定稿后
+ +
审阅重点:① Provider 接口是否够覆盖后续渠道(Task1);② settle 的归一/幂等/金额核对链路(Task5,资金命脉);③ webhook outbox 幂等键 (out_trade_no,event_type) 是否合理(Task6);④ 上面 5 条取舍是否认可(尤其"路由取首个账户""币种默认"延后)。
+ +

相关:pay v2 设计 · 真相源 docs/superpowers/plans/2026-07-10-pay-v2-p2-pipeline.md

+
+ +