Files
pay/docs/pay-v2-p1-plan.html
T
wangjia 2383b9d593 docs: pay v2 P1 实现计划(核心数据模型+账户注册表)
4 TDD 任务:money(int64 最小单位+币种) / Order·Attempt·Account·Refund 模型+状态机
+:memory: 测试约定 / OrderStore(幂等标付/取消/列表) / 账户配置注册表(env 凭证)。
沿用 GORM AutoMigrate + glebarez sqlite。HTML 阅读版 + 登记 index + 与设计文档互链。
P2-P8 各自成计划。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 07:56:26 +08:00

79 lines
6.2 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>pay v2 · P1 核心数据模型(阅读版)</title>
<style>
:root{--bg:#0d1117;--card:#161b22;--card-2:#1c2330;--border:#283041;--fg:#e6edf3;--fg-soft:#aeb9c7;--muted:#7d8896;--accent:#58a6ff;--ok:#3fb950;--warn:#d29922;--radius:14px;--mono:"SF Mono",ui-monospace,Menlo,Consolas,monospace}
*{box-sizing:border-box}
body{margin:0;background:radial-gradient(1200px 600px at 80% -10%,rgba(88,166,255,.08),transparent 60%),var(--bg);color:var(--fg);font:15px/1.7 -apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif}
.wrap{max-width:960px;margin:0 auto;padding:44px 24px 96px}
.back{display:inline-block;margin-bottom:18px;font-size:13px}
a{color:var(--accent);text-decoration:none}
h1{font-size:27px;margin:6px 0 8px}
.lead{color:var(--fg-soft);margin:0 0 22px}
h2{font-size:18px;margin:34px 0 10px;color:var(--accent);border-bottom:1px solid var(--border);padding-bottom:8px}
code{font-family:var(--mono);font-size:.85em;background:var(--card-2);padding:1px 6px;border-radius:5px;color:#cdd9e5}
b{color:#fff}
table{width:100%;border-collapse:collapse;margin:14px 0;font-size:13.5px}
th,td{text-align:left;padding:9px 12px;border-bottom:1px solid var(--border);vertical-align:top}
th{color:var(--fg-soft);font-weight:600;font-size:13px}
table.fields td:first-child{font-family:var(--mono);font-size:12px;color:#cdd9e5;white-space:nowrap;width:1%}
.card{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:14px 18px;margin:12px 0}
.card h3{margin:0 0 6px;color:var(--accent);font-size:15px}
.lead-box{background:linear-gradient(180deg,rgba(88,166,255,.10),transparent);border:1px solid var(--border);border-radius:var(--radius);padding:16px 20px;margin:0 0 8px}
.tag{display:inline-block;font-size:12px;font-weight:600;padding:2px 9px;border-radius:999px}
.tag.ok{background:rgba(63,185,80,.16);color:var(--ok)}
.tag.info{background:rgba(88,166,255,.16);color:var(--accent)}
.path{color:var(--muted);font-size:12px;font-family:var(--mono);margin-top:6px}
</style>
</head>
<body>
<div class="wrap">
<a class="back" href="index.html">← 返回文档索引</a>
<h1>pay v2 · P1 核心数据模型 + 配置账户注册表<span style="font-size:14px"> (阅读版)</span></h1>
<p class="lead">执行真相源 <code>docs/superpowers/plans/2026-07-10-pay-v2-p1-core-model.md</code>(含 <code>- [ ]</code> checkbox)。设计见 <a href="pay-v2-unified-gateway-design.html">pay v2 统一支付网关设计</a></p>
<div class="lead-box">
<b>P1 目标</b>:建 pay v2 的<b>核心数据地基</b> —— Order + Attempt + Account + Refund 模型、金额 int64 最小单位 + 币种、状态机、<code>:memory:</code> 测试约定、配置驱动账户注册表。即"一单 N 渠道只一个成功 / 可取消 / 多账户路由"的数据层。不含 Provider/收款管线/渠道/退款执行(P2+)。
</div>
<h2>8 阶段路线图</h2>
<table>
<thead><tr><th>阶段</th><th>内容</th><th>状态</th></tr></thead>
<tbody>
<tr><td><b>P1</b></td><td>核心模型(Order/Attempt/Account/Refund)+ money + 状态机 + 测试约定 + 账户配置注册表</td><td><span class="tag ok">本页</span></td></tr>
<tr><td>P2</td><td>Provider 抽象 + 一次性收款管线 + webhook v2(event_type)+ 幂等/金额核对(fake provider 测)</td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P3</td><td>首批渠道 adapter:crypto 自托管 / 支付宝 / Stripe</td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P4</td><td>退款:POST /refunds + 三向(业务/crypto 人工/平台通知)+ refund 事件</td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P5</td><td>多账户路由策略(round_robin/weighted/limit_aware/crypto 地址池)</td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P6</td><td>对账 job(每 provider query,渠道流水 vs 本地订单)</td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P7</td><td>codes 共享库(A 嵌入各产品)</td><td><span class="tag info">待细化</span></td></tr>
<tr><td>P8</td><td>later:订阅/recurring(4 类 kind)、拒付 chargeback</td><td><span class="tag info">待细化</span></td></tr>
</tbody>
</table>
<h2>P1 任务(4 个,TDD bite-sized)</h2>
<div class="card"><h3>Task 1 · money 包</h3>金额 <b>int64 最小单位 + 币种码</b>(CNY/USD=分、USDT=micro);<code>Parse</code>/<code>Format</code> 往返,超精度报错。禁 float / string 元(v2 破坏性改动)。</div>
<div class="card"><h3>Task 2 · v2 模型 + 状态机 + 测试约定</h3>Order/Attempt/Account/Refund GORM 模型(内嵌 Base、金额 int64+币种、Attempt <code>UNIQUE(channel,provider_ref)</code>)、三套状态枚举、接进 AutoMigrate;建 <code>OpenTestDB</code><code>:memory:</code> sqlite 测试约定(pay 原无 DB 测试)。</div>
<div class="card"><h3>Task 3 · OrderStore</h3>建单/建尝试/<b>幂等标付</b>(条件 UPDATE + RowsAffected,守卫 order=pending → 一单只一个 attempt 成功)/取消(pending→canceled)/列表(全状态含 canceled)。沿用 pay 现有 applyPaid 幂等手法(sqlite 单写,无 FOR UPDATE)。</div>
<div class="card"><h3>Task 4 · 账户配置注册表</h3><code>config.accounts</code> 声明账户(channel/weight/enabled/limit/region/subject),<b>凭证只存 env 前缀、真值运行时从 env 取</b>;<code>EnabledFor(channel,region)</code> 筛选(路由策略在 P5)。</div>
<h2>关键约束</h2>
<table class="fields">
<thead><tr><th>约束</th><th>说明</th></tr></thead>
<tbody>
<tr><td>金额</td><td>int64 最小单位 + 币种码,禁 float / string 元</td></tr>
<tr><td>幂等</td><td>条件 UPDATE + RowsAffected(sqlite 单写,无 FOR UPDATE)</td></tr>
<tr><td>迁移</td><td>GORM AutoMigrate,无手写 migration;内嵌 Base</td></tr>
<tr><td>凭证</td><td>json:"-" + env 注入,不入库/配置明文</td></tr>
<tr><td>重设计</td><td>jiu 未上线、无生产数据,可重建表</td></tr>
</tbody>
</table>
<p class="path">相关:<a href="pay-v2-unified-gateway-design.html">pay v2 设计</a> · 真相源 docs/superpowers/plans/2026-07-10-pay-v2-p1-core-model.md</p>
</div>
</body>
</html>