3ae96ef229
覆盖前端五端/后端/MySQL/弹性节点拓扑/Web安全/安全总纲,遵循 design/ 设计系统视觉呈现。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
175 lines
11 KiB
HTML
175 lines
11 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>02 后端设计 · 穿山甲架构设计</title>
|
||
<link rel="stylesheet" href="assets/style.css">
|
||
</head>
|
||
<body>
|
||
|
||
<header class="site-header"><div class="inner">
|
||
<a class="brand" href="index.html"><img src="assets/logo-mark.svg" alt="Pangolin"><span><span class="zh">穿山甲 · 架构设计</span><br><span class="en">Pangolin Architecture</span></span></a>
|
||
<nav class="site-nav">
|
||
<a href="index.html">总览</a>
|
||
<a href="01-frontend.html">01 前端</a>
|
||
<a href="02-backend.html" class="active">02 后端</a>
|
||
<a href="03-database.html">03 数据库</a>
|
||
<a href="04-infra.html">04 网络拓扑</a>
|
||
<a href="05-web-security.html">05 Web 安全</a>
|
||
<a href="06-security.html">06 安全总纲</a>
|
||
</nav>
|
||
<button class="theme-btn" id="themeBtn" title="切换深浅主题"><i data-lucide="moon"></i></button>
|
||
</div></header>
|
||
|
||
<main class="doc">
|
||
|
||
<div class="doc-hero">
|
||
<div class="overline">Chapter 02 · Backend</div>
|
||
<h1>后端设计</h1>
|
||
<p class="lede">Go 模块化单体,满足前端全部功能即可、不做过度设计。API 契约完整继承 <code>design/server/ARCHITECTURE.md</code> §3 蓝本,唯一语义修订:数据面从 WireGuard 换为 sing-box(REALITY / Hysteria2),<code>connect</code> 改为下发用户凭证 + 节点连接参数。</p>
|
||
</div>
|
||
|
||
<section id="modules">
|
||
<h2><span class="num">§1</span>服务形态与模块划分</h2>
|
||
<p>单体起步、按模块分包(实现顺序即蓝本 §7):</p>
|
||
<div class="diagram">
|
||
<div class="flow">
|
||
<div class="fbox accent"><b>HTTP API</b><span>chi · /v1</span></div>
|
||
<div class="farr">→</div>
|
||
<div class="fbox"><b>auth</b><span>验证码/注册/JWT</span></div>
|
||
<div class="fbox"><b>codes</b><span>激活码/兑换/webhook</span></div>
|
||
<div class="fbox"><b>devices</b><span>设备/订阅校验</span></div>
|
||
<div class="fbox"><b>nodes</b><span>目录/connect/调度</span></div>
|
||
<div class="fbox"><b>usage</b><span>用量/额度</span></div>
|
||
<div class="fbox"><b>admin</b><span>管理端(独立监听)</span></div>
|
||
</div>
|
||
<div class="flow">
|
||
<div class="fbox ghost"><b>gRPC server(mTLS)</b><span>节点 agent:注册 / 心跳 / 凭证下发与回收 / 用量上报</span></div>
|
||
<div class="fbox ghost"><b>scheduler</b><span>探针汇聚 · 判封 · 节点生命周期驱动(见 04 章)</span></div>
|
||
<div class="farr">→</div>
|
||
<div class="fbox"><b>MySQL</b><span>主数据</span></div>
|
||
<div class="fbox"><b>Redis</b><span>验证码/限流/实时负载</span></div>
|
||
</div>
|
||
<div class="cap">一个二进制三个监听:公网 API(CDN 后)· agent gRPC(mTLS 双向认证)· 管理端(内网/白名单)</div>
|
||
</div>
|
||
<ul>
|
||
<li>每模块完成定义(蓝本约定):单测 + OpenAPI 同步 + 错误文案双语(<code>{code, message_zh, message_en}</code>)+ 符合脱敏口径。</li>
|
||
<li>管理端绝不与公网 API 共用监听端口;部署时仅绑内网地址,前置白名单 + 2FA(见 06 章)。</li>
|
||
</ul>
|
||
</section>
|
||
|
||
<section id="api">
|
||
<h2><span class="num">§2</span>API 契约 v1(继承蓝本 §3,正式版用 OpenAPI 定义)</h2>
|
||
<pre><code><span class="c"># 认证(无需 JWT)</span>
|
||
POST /v1/auth/code {email} <span class="c"># 发 6 位验证码(Redis 10min,限 1/min)</span>
|
||
POST /v1/auth/register {email, code, password} <span class="c"># 建号 + 7 天试用 + JWT</span>
|
||
POST /v1/auth/login {email, password} <span class="c"># JWT(access 15min + refresh 30d)</span>
|
||
POST /v1/auth/refresh {refresh_token}
|
||
|
||
<span class="c"># 账户</span>
|
||
GET /v1/me <span class="c"># 账户 + 订阅 + 用量摘要</span>
|
||
GET /v1/me/devices
|
||
DELETE /v1/me/devices/:id <span class="c"># 移除设备(同步回收节点侧凭证)</span>
|
||
|
||
<span class="c"># 商业闭环(App 内无支付,只有兑换)</span>
|
||
POST /v1/redeem {code} <span class="c"># 兑换激活码(幂等 + 审计)</span>
|
||
POST /v1/ads/unlock {device_id, ad_token} <span class="c"># 免费版激励视频解锁当日时长(验 SDK 回执)</span>
|
||
GET /v1/plans <span class="c"># 套餐目录(数字与 design/CLAUDE.md §7 一致)</span>
|
||
|
||
<span class="c"># 节点(数据面入口)</span>
|
||
GET /v1/nodes ?if_version=N <span class="c"># 节点目录(按套餐过滤,304 支持)</span>
|
||
POST /v1/nodes/:id/connect {device_id} <span class="c"># 下发连接凭证(见 §3,语义已适配 sing-box)</span>
|
||
POST /v1/nodes/:id/disconnect {device_id}
|
||
|
||
GET /v1/usage ?days=7 <span class="c"># 用量曲线(统计页)</span>
|
||
GET /v1/notices <span class="c"># 公告(亦发布为多镜像签名静态 JSON)</span></code></pre>
|
||
<ul>
|
||
<li>除 auth 外全部接口要求 JWT;限流用 Redis 滑动窗口(按 IP + 用户双维度)。</li>
|
||
<li>错误体统一 <code>{code, message_zh, message_en}</code>;文案遵守铁律 13 脱敏口径。</li>
|
||
<li>节点目录响应带 <code>version</code>;客户端 <code>if_version</code> 命中返回 304——这是节点秒级灰度的基础(见 04 章)。</li>
|
||
</ul>
|
||
</section>
|
||
|
||
<section id="connect">
|
||
<h2><span class="num">§3</span>connect 语义适配(相对蓝本 v0.1 的唯一修订)</h2>
|
||
<div class="callout"><b>修订理由</b>蓝本 v0.1 的数据面是 WireGuard(connect = 下发 WG peer)。WG 协议特征明显,在目标网络环境会被快速识别阻断;plan/ phase-0~3 已选定 REALITY 主线 + Hysteria2 备线。API 形状不变,仅返回体语义调整。</div>
|
||
<h3>3.1 连接流程</h3>
|
||
<div class="diagram">
|
||
<div class="flow">
|
||
<div class="fbox accent"><b>客户端</b><span>POST /nodes/:id/connect</span></div>
|
||
<div class="farr">→</div>
|
||
<div class="fbox"><b>API 校验</b><span>订阅有效 · 设备数 ≤ 上限 · 免费版校验 ad_unlocked_at + 剩余分钟</span></div>
|
||
<div class="farr">→</div>
|
||
<div class="fbox"><b>gRPC → agent</b><span>确保该用户 UUID 已在节点 sing-box 用户表</span></div>
|
||
<div class="farr">→</div>
|
||
<div class="fbox ok"><b>返回连接参数</b><span>server, port, uuid, flow, reality pbk/sid/sni · hy2 备用</span></div>
|
||
</div>
|
||
<div class="cap">免费版凭证带 TTL = 当日剩余分钟,到时 agent 自动从用户表移除;付费版 TTL 24h 在线自动续期</div>
|
||
</div>
|
||
<h3>3.2 凭证模型</h3>
|
||
<ul>
|
||
<li><strong>每用户一个数据面 UUID</strong>(与账号 ID 解耦,可轮换):节点侧只见 UUID,零账号信息——单节点被抄不泄露用户库。</li>
|
||
<li>凭证轮换:用户改密 / 管理端封禁 / 定期轮换时生成新 UUID,gRPC 广播到所有在册节点替换;旧 UUID 给 5 分钟宽限期平滑重连。</li>
|
||
<li>订阅过期、设备被移除、套餐降级 → scheduler 驱动 agent 即时回收对应 UUID。</li>
|
||
<li>Hysteria2 凭证同源派生(同一 UUID 作 auth password),客户端按网络状况自动选协议。</li>
|
||
</ul>
|
||
</section>
|
||
|
||
<section id="flows">
|
||
<h2><span class="num">§4</span>关键业务流程</h2>
|
||
<h3>4.1 注册与试用(对齐客户端 UI:邮箱 → 验证码 → 设密码)</h3>
|
||
<ul>
|
||
<li><code>POST /auth/code</code>:风控(IP + 邮箱限频、一次性邮箱域黑名单)→ 发码(Redis 10min)。</li>
|
||
<li><code>POST /auth/register</code>:验码 → 建号 → <strong>自动写入 7 天 PRO 试用</strong>(<code>subscriptions(plan=pro, expires_at=now()+7d, source='trial')</code>,一邮箱仅一次)→ 返回 JWT。</li>
|
||
<li>试用到期回落 free:仅 tier=free 节点、每日 10 分钟、每日首连前需激励视频解锁。</li>
|
||
</ul>
|
||
<h3>4.2 激活码生命周期</h3>
|
||
<div class="diagram">
|
||
<div class="flow">
|
||
<div class="fbox"><b>发卡店售出</b><span>webhook(HMAC 签名)</span></div>
|
||
<div class="fbox"><b>人工渠道</b><span>TG/LINE/邮箱 · 管理端批量生成 batch</span></div>
|
||
<div class="farr">→</div>
|
||
<div class="fbox"><b>codes 入库</b><span>status=unused · 库存 hash</span></div>
|
||
<div class="farr">→</div>
|
||
<div class="fbox accent"><b>POST /redeem</b><span>事务:redeemed + 订阅顺延(叠加非覆盖)</span></div>
|
||
<div class="farr">→</div>
|
||
<div class="fbox"><b>audit_log</b><span>必记</span></div>
|
||
</div>
|
||
</div>
|
||
<ul>
|
||
<li>码格式:Crockford Base32,16 位含校验位;明文只出现一次(生成响应 / 发卡店),库内存 hash。</li>
|
||
<li>兑换幂等:同一用户重复提交同一码返回首次结果;风控:单用户失败 5 次/小时锁 1 小时。</li>
|
||
</ul>
|
||
<h3>4.3 免费版广告解锁</h3>
|
||
<ul>
|
||
<li>客户端播完激励视频 → <code>POST /v1/ads/unlock</code> 携带广告 SDK 回执 → 服务端向 AdMob/Unity 校验回执真伪 → 记 <code>usage_daily.ad_unlocked_at</code>。</li>
|
||
<li><code>connect</code> 对 free 用户强制校验当日 <code>ad_unlocked_at</code> 与剩余分钟;分钟数由 agent 上报的会话时长累计,服务端为权威。</li>
|
||
</ul>
|
||
</section>
|
||
|
||
<section id="hardening">
|
||
<h2><span class="num">§5</span>后端安全要点(详见 06 章总纲)</h2>
|
||
<ul>
|
||
<li>密码 argon2id;JWT RS256,签名密钥定期轮换;全站 TLS 1.3。</li>
|
||
<li>验证码 / 兑换 / 登录接口限流 + 防一次性邮箱 + 失败锁定;所有敏感操作进 <code>audit_log</code>。</li>
|
||
<li><strong>无日志口径</strong>(写进隐私政策并据实执行):不记录目的地址 / DNS 查询 / 流量内容;仅 <code>usage_daily</code> 字节数与分钟数。</li>
|
||
<li>agent gRPC 双向 mTLS:节点证书由内部 CA 签发、与节点 ID 绑定,节点被回收即吊销。</li>
|
||
<li>CI:lint + 单测 + OpenAPI 校验 + 镜像构建;OpenAPI 即 API 文档与客户端 SDK 生成源。</li>
|
||
</ul>
|
||
</section>
|
||
|
||
</main>
|
||
|
||
<nav class="pager">
|
||
<a href="01-frontend.html"><span>上一章</span><b>← 01 前端架构</b></a>
|
||
<a class="next" href="03-database.html"><span>下一章</span><b>03 数据库 →</b></a>
|
||
</nav>
|
||
|
||
<footer class="colophon">穿山甲 · Pangolin — 内部架构设计文档 · 遵循 design/ 设计系统 · 2026-06</footer>
|
||
|
||
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
|
||
<script src="assets/doc.js"></script>
|
||
</body>
|
||
</html>
|