← 文档索引

方案 A · 自建发卡网(独角数卡)落地细化

2026-07-08 · 实现计划 · 门面自建 + USDT 收款 + 激活码自动发货 · 基于已就绪server/internal/codes

关键前提(好消息):激活码后端基本已就绪——发卡店回调 POST /webhook/store/codes(HMAC + 时间戳 + nonce 防重放)、用户兑换 POST /v1/redeem(JWT)、批次生成/导出/作废都在 server/internal/codes。所以方案 A 的工作量集中在门面(独角数卡)+ 一小段发货胶水 + 运维不是重写后端

已就绪的后端契约(照这个对接,别新造)

已实现 · 发卡店回调 POST /webhook/store/codes

发卡店卖出一个码后调它,把该码登记为 pangolin 的有效激活码。挂在 /v1 之外、无需 JWT,靠三重校验。

POST /webhook/store/codes            # 无 JWT
Headers:
  X-Pangolin-Signature: sha256=<hex>    # HMAC-SHA256(raw body, secret)
  X-Pangolin-Timestamp: <unix>           # ±5 分钟窗口
  X-Pangolin-Nonce: <唯一串>              # Redis 去重,防重放
Body:
  { "code": "<明文激活码>",               # 必须是 pangolin 格式合法码(见下)
    "plan": "pro",                        # free | pro | team
    "duration_days": 365,
    "note": "dujiaoka #订单号" }           # 可选备注
→ 201 {"status":"created"}
→ 200 {"status":"already_exists"}         # code_hash 已存在,幂等
→ 200 {"status":"duplicate_ignored"}      # nonce 重复,幂等
→ 400 / 401                                # 校验失败

仅存 hash(明文不落库)。secret 走 Bitwarden,配到 server.env

已实现 · 用户兑换 POST /v1/redeem

POST /v1/redeem   (JWT)
Body:  { "code": "PGL-XXXX-..." }
→ 200 { "idempotent":false, "plan":"pro", "duration_days":365,
        "expires_at":"2027-07-08T00:00:00Z" }
错误码: CODE_NOT_FOUND / CODE_REDEEMED / CODE_VOID / INVALID_CODE / RATE_LIMITED / ACCOUNT_LOCKED

已含幂等(同用户同码重放返回 idempotent=true)+ 限频 + 账户锁。用户中心/客户端只要有"输码兑换"入口即可。

已实现 · 批次生成 / 导出 / 作废

server/cmd/codegen 生成一批合法码(Crockford Base32、75-bit、带校验位、可 Canonicalize 纠错),export.go 导出明文,VoidBatch 批量作废未使用码。码格式带校验位——第三方要产出合法码不能乱编(见下模型 B 的待补点)。

整体拓扑

用户 浏览器 / TG 独角数卡(独立 VPS) 门面 · 商品/SKU · 卡密库存 USDT 支付插件 → 收款 PHP + MySQL + Redis 发货 hook → 回调 pangolin USDT 钱包 / 网关 TRC20 · 你 US LLC 自托管 Pangolin 控制面 POST /webhook/store/codes codes:登记/作废/批次 POST /v1/redeem(兑换) → 订阅/时长生效 客户端 / 用户中心 输码兑换 → /v1/redeem ①下单付款 ②USDT 收款 ③发货 hook 登记码 ④用户拿码 → 输码兑换
钱流 码流 自托管资产

部署选址 · 风险隔离

独角数卡必须独立部署,别放 pangolin1。 两个理由:① pangolin1 只有 ~1GB 内存,跑控制面+agent+sing-box 已经紧,再塞 PHP+MySQL+Redis 会 OOM;② 风险隔离——发卡/收款站点和 VPN 控制面绑一起,一处被盯上会牵连另一处。放独立小 VPS(海外,2C/2G 起),与控制面只经 HTTPS webhook 通信。

两种发货模型(映射到已有能力)

模型 A · 预充卡密库存 最快 MVP模型 B · webhook JIT 登记 更安全
怎么做codegen 生成一批 → 导出明文 → 充进独角数卡卡密库 → 发货直接给码独角数卡发货后调 /webhook/store/codes 才把码登记为有效
码何时有效生成即有效(在 codes 表 status=unused)付款+发货后才有效
泄漏风险独角数卡库被脱 → 码可被无票兑换未售出的码无效,脱库也没用
要写的胶水几乎零(导入卡密即可)发货 hook 签 HMAC 调 webhook + 解决"码由谁生成"
webhook不用/webhook/store/codes
建议:MVP 先用模型 A(零胶水、当天能卖),跑通量后升级模型 B 拿安全性。
模型 B 的待补点:webhook 要求发卡店发送pangolin 格式合法码(带校验位)。独角数卡自己产不出合法码,两条路二选一:(1) 在独角数卡侧复刻 GenerateCode 生成算法;(2) 给 pangolin 加一个受保护的 POST /internal/codes/mint(HMAC 同款)让发卡网"先领一个合法码再发货登记"。推荐 (2),格式单源、不重复实现。

商品 / SKU 映射

独角数卡里每个商品 = 一个套餐档,映射到 webhook 的 plan + duration_days

独角数卡商品planduration_days
Pro · 月pro30
Pro · 年pro365
Team · 月 / 年team30 / 365

档位/定价对齐 design/CLAUDE.md §7 与官网 Pricing;SKU 表落进配置,别散在代码里。

USDT 收款接入

要建的胶水(很小)

  1. 发货 hook → pangolin webhook(仅模型 B):独角数卡发货成功后,组 body + 签 X-Pangolin-Signature(HMAC)+时间戳+nonce,POST /webhook/store/codes。独角数卡支持"自动发货 API 商品/webhook",写个小中间脚本或插件即可。
  2. HMAC secret:生成一把,存 Bitwarden;配 pangolin server.env 与独角数卡侧。
  3. (模型 B 推荐)POST /internal/codes/mint:受 HMAC 保护,返回一个合法码给发卡网。需新增
  4. 兑换入口自检:确认客户端/用户中心已有"输码兑换 → /v1/redeem"的 UI(后端已就绪)。

落地步骤

第 1 步 · 门面起来(半天)
第 2 步 · 收款接上(USDT)
第 3 步 · 发货接 pangolin
第 4 步 · 闭环验证

密钥 · 备份 · 风险边界

待你拍板 / 下一步

相关:支付渠道选型总览 · 发卡/Reseller 收款 + 激活码自动发货架构