Files
pangolin/docs/pay-orchestration-p1-plan.html
T
wangjia cc47f16190 docs(pay): P1 实现计划(数据层+开通重构)+ 哪吒密钥入库标记已定
P1 计划(4 TDD 任务:迁移 000022 双引擎 / subscription.Grant 抽取 / codes 委托 /
payorders 数据访问)+ HTML 阅读版 + 登记 index。设计文档哪吒行更新为已定
(Bitwarden nzzf)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 23:17:47 +08:00

103 lines
7.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>统一支付编排层 · P1 数据层 + 开通重构(阅读版)</title>
<style>
:root{
--bg:#0f1117; --panel:#171a22; --panel2:#1d2129; --fg:#e6e8ee; --fg2:#a8afbd;
--accent:#e0884f; --accent2:#5fb0c9; --ok:#5ec27a; --bad:#e06a6a; --warn:#e0b84f;
--border:#272c36; --mono:"SF Mono",ui-monospace,Menlo,Consolas,monospace;
--sans:-apple-system,"PingFang SC","Helvetica Neue",Arial,sans-serif;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--sans);line-height:1.7;font-size:15px}
.wrap{max-width:960px;margin:0 auto;padding:48px 24px 96px}
h1{font-size:28px;line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
.sub{color:var(--fg2);font-size:15px;margin:0 0 24px}
h2{font-size:20px;margin:40px 0 12px;padding-bottom:8px;border-bottom:1px solid var(--border)}
h3{font-size:15px;margin:20px 0 8px;color:var(--accent2)}
p{margin:10px 0}
code{font-family:var(--mono);font-size:.86em;background:var(--panel2);padding:1px 6px;border-radius:5px;color:#f0d9c4}
pre{background:#0a0c11;border:1px solid var(--border);border-radius:10px;padding:14px 16px;overflow-x:auto;font-family:var(--mono);font-size:12.5px;line-height:1.55;color:#cdd3df}
.tag{display:inline-block;font-size:12px;font-weight:600;padding:2px 9px;border-radius:999px}
.tag.ok{background:rgba(94,194,122,.16);color:var(--ok)}
.tag.info{background:rgba(95,176,201,.16);color:var(--accent2)}
.tag.warn{background:rgba(224,184,79,.16);color:var(--warn)}
.card{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:16px 20px;margin:14px 0}
.card h3{margin-top:0}
table{width:100%;border-collapse:collapse;margin:14px 0;font-size:13.5px}
th,td{text-align:left;padding:8px 12px;border-bottom:1px solid var(--border);vertical-align:top}
th{color:var(--fg2);font-weight:600;font-size:13px}
ul,ol{padding-left:22px;margin:8px 0}
li{margin:5px 0}
.lead{background:linear-gradient(180deg,rgba(224,136,79,.10),transparent);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin:0 0 8px}
a{color:var(--accent2)}
.back{display:inline-block;margin-bottom:24px;font-size:13px}
b{color:#fff}
.path{color:var(--fg2);font-size:12px;font-family:var(--mono)}
</style>
</head>
<body>
<div class="wrap">
<a class="back" href="index.html">← 返回文档索引</a>
<h1>统一支付编排层 · P1 数据层 + 开通重构<span style="font-size:14px"> (阅读版)</span></h1>
<p class="sub">执行真相源 <code>docs/superpowers/plans/2026-07-09-pay-orchestration-p1-schema-grant.md</code>(含 <code>- [ ]</code> checkbox,勿改)。设计见 <a href="pay-orchestration-design.html">统一支付编排层设计</a></p>
<div class="lead">
<b>P1 目标</b>:给控制面加支付订单数据层(<code>pay_orders</code> 业务订单 + <code>pay_attempts</code> 支付尝试),并把「开通订阅」从 codes 抽成可复用、可传 <code>source</code><code>subscription</code> 包,<code>subscriptions.source</code> 枚举加 <code>'pay'</code><b>只覆盖数据层 + 开通原语</b>HTTP/adapter/客户端在 P2+。
</div>
<h2>7 阶段路线图</h2>
<table>
<thead><tr><th>阶段</th><th>内容</th><th>本计划</th></tr></thead>
<tbody>
<tr><td><b>P1</b></td><td>schemapay_orders/pay_attempts+ subscription 开通重构(source=pay migration+ payorders 数据访问</td><td><span class="tag ok">本页</span></td></tr>
<tr><td>P2</td><td>Provider 抽象/注册表 + Order/Attempt service + 客户端 RESTmethods/orders/get/list/retry+ 统一开通管线 + Query 轮询 workerfake provider 测)</td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P3</td><td>crypto adapter(包裹 pangolin-pay+ pay-server 出站 webhook + <code>/v1/webhooks/pay/crypto</code></td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P4</td><td>哪吒 adapterRSA 签/验、GET 回调、查单;密钥 Bitwarden <code>nzzf</code>+ <code>/v1/webhooks/pay/nazha</code></td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P5</td><td>四端 Flutter 支付页(方法选择器 + render_type 分发 + 轮询)+ 接购买入口</td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P6</td><td>用户中心订单历史页(读 <code>GET /v1/pay/orders</code>return_url 跳此)</td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P7</td><td>端到端联调(两轨小额真链/真单)</td><td><span class="tag info">待细化</span></td></tr>
</tbody>
</table>
<p class="path">各阶段落地前逐一细化成独立计划,让接口以真代码为准、不臆测。</p>
<h2>P1 任务(4 个,TDD bite-sized</h2>
<div class="card">
<h3>Task 1 · 迁移 000022(双引擎)</h3>
<p><code>pay_orders</code> + <code>pay_attempts</code>,并给 <code>subscriptions.source</code><code>'pay'</code>。SQLite 列级 CHECK 不能 ALTER → <b>重建表</b>(rename→建新→复制→drop→重建索引);MySQL <code>ALTER TABLE subscriptions MODIFY source ENUM('trial','code','pay')</code>。up/down 各 4 文件,临时 sqlite 库跑 up/down 验证。</p>
</div>
<div class="card">
<h3>Task 2 · <code>subscription</code> 包抽出开通原语</h3>
<p>新包 <code>server/internal/subscription</code><code>Grant(ctx, tx, userID, planID, days, source) → (subID, expiresAt)</code> 复刻现规则(同 plan 有活跃订阅→延长;否则→新建),<code>source</code> 写进新行。SQLite 内存实库测「新建→续期叠加、只 1 行、source=pay」。</p>
</div>
<div class="card">
<h3>Task 3 · codes 委托 subscription.Grant(行为不变)</h3>
<p><code>codes.Service.applySubscription</code> 改为调 <code>subscription.Grant(..., "code")</code>,跑通现有 codes 全套测试证明零行为变化。删除 <code>codes.Store</code> 里迁走的重复方法(若无其他调用者)。</p>
</div>
<div class="card">
<h3>Task 4 · <code>payorders</code> 数据访问</h3>
<p>新包 <code>server/internal/payorders</code><code>Order</code>/<code>Attempt</code> 结构 + <code>CreateOrder/GetOrder/ListOrders/CreateAttempt/AttemptByProviderRef</code> + 幂等 <code>MarkOrderPaid</code>(仅 <code>status='pending'</code> 才置 paid + 回填 subscription_id + attempt 置 paid;已 paid 返回 false)。SQLite 内存实库测「建单→查单→标付→再标付幂等」。</p>
</div>
<h2>两张新表</h2>
<pre>pay_orders 业务订单/购买账本:order_no(唯一幂等) · user_id/user_uuid · sku · plan_code
· duration_days · amount_minor(int64) · currency · status
(created|pending|paid|expired|canceled) · subscription_id(开通回填)
· created_at/paid_at/expires_at
pay_attempts 支付尝试/收款账本:order_no · method · provider · provider_ref
· render_type · amount_minor · currency · status
(created|pending|paid|failed|expired) · UNIQUE(provider,provider_ref) 幂等命门</pre>
<p style="margin-top:28px" class="path">相关:<a href="pay-orchestration-design.html">编排层设计</a> · 真相源 docs/superpowers/plans/2026-07-09-pay-orchestration-p1-schema-grant.md</p>
</div>
</body>
</html>