Chapter 01 · Frontend

前端架构

原则:性能、稳定性、用户体验优先;不同平台允许不同技术栈,但视觉与交互必须 100% 还原 design/ 设计系统——以 ui_kits/ React 原型为像素验收标准,以 colors_and_type.css 为令牌唯一真相源。

§1分端技术栈选型

技术栈选型理由(性能 / 稳定 / UX)像素基准
移动 App
iOS / Android
Flutter + sing-box libbox(gomobile 桥接)
iOS NetworkExtension / Android VpnService
需要系统级隧道能力,Web 栈不可行;Flutter 自绘渲染保证两端像素一致,design/flutter/ 起步包(theme + widgets + main)拿来即跑。 ui_kits/mobile/
iPad 客户端 Flutter——与移动 App 同一工程,宽度 ≥900 自适应切换为侧栏分栏布局 不是第五套代码:复用移动端全部原子组件与内核层,仅布局开关;横屏 1180×820 基准,左侧栏导航(触控尺寸,行高 ≥48px),连接页双栏(左大连接键 / 右信息列),节点双列网格。 ui_kits/tablet/
桌面客户端
Windows / macOS
Flutter desktop + sing-box 子进程(TUN 模式) 与移动端共享 ~90% UI 代码(连接键、节点列表、统计、账户全复用),920×600 固定窗 + 侧栏布局照搬原型;避免 Electron 的内存与启动开销。 ui_kits/desktop/
官网 Astro(SSG)→ Cloudflare Pages 纯静态 = 极致加载性能 + 整站可秒级复制到任意备用域名(灾备关键,见 05 章);Astro 直接吃 JSX,ui_kits/website 组件近乎逐字迁移。 ui_kits/website/
Web 用户中心 Next.js(React,静态导出 + 客户端取数) ui_kits/usercenter 本身是 React——组件直接复用是保真上限;静态导出后同样可多镜像部署,动态数据全走 API。 ui_kits/usercenter/
为什么不强行统一一个栈 客户端离不开系统级隧道与开机自启,必须是原生壳;Web 端的两个原型本身就是 React,重写成 Flutter Web 反而损失保真与首屏性能。五个产品面、四套实现(iPad 归入移动端工程的自适应断点),通过同一套设计令牌(CSS 变量 ↔ pangolin_theme.dart 一一对应)保证视觉同源——栈不同,像素相同。

§2客户端分层架构(移动 + 桌面共享)

UI 层(共享 ~90%)flutter/widgets/:连接键三态 · 智能选择推荐卡 · 免费额度卡 · 节点列表 · 统计 · 账户;明暗双主题 + 中英单显;宽度 ≥900 自适应切侧栏分栏布局(iPad / 桌面同构)
状态层Riverpod:连接状态机(off / connecting / on)· 会话 · 节点目录(带 version)· 用量额度
服务层API client(域名池 + 重试退避 + 响应签名校验)· 节点目录缓存 · 订阅凭证存储(Keychain / Keystore)
内核层sing-box libbox(移动:gomobile AAR/XCFramework;桌面:子进程 + TUN)· URLTest 智能选线 · Kill-switch
平台壳iOS NetworkExtension · Android VpnService(前台服务)· macOS/Win TUN 设备 + 开机自启
UI 与内核之间仅通过状态层通信;内核崩溃不拖垮 UI,UI 重启不掉隧道

§3100% 还原策略

3.1 令牌同源

令牌载体同步方式
官网 / 用户中心colors_and_type.css 直接链入原样引用,不复制不改写
移动 / 桌面flutter/pangolin_theme.dart与 CSS 一一对应的 Dart 镜像;改令牌必须两处同改(design/CLAUDE.md §6)

3.2 像素基准与组件对照

每个界面动手前先打开对应 React 原型比对;以下关键组件逐一对照验收:

3.3 提交前验收清单(每个界面,引用 design/CLAUDE.md §9)

§4客户端断网弹性

设计目标:API 全灭、域名全被污染时,客户端仍能连上节点。详见 06 章断网应对矩阵,此处为客户端侧实现。

机制实现覆盖的故障
节点目录缓存每次成功拉取 /v1/nodes 后落盘(带 version 与时间戳);启动时先用缓存渲染并尝试连接,后台再刷新API 暂时不可达
API 端点池客户端内置:主域名 + 备用域名 N 个 + IP 直连兜底;按序故障转移,成功的端点置顶记忆单个域名被墙 / 被污染
DoH 解析域名解析优先走 DoH(多个提供方),绕开本地污染DNS 污染
签名端点更新定期从多镜像静态文件(Cloudflare Pages / GitHub 等)拉取 Ed25519 签名的端点列表,验签后合并进端点池内置端点全部失效
紧急逃生配置安装包内置 1–2 个应急节点参数(低速、仅够拉新目录),所有在线途径失效时启用极端封锁
应急公告客户端内公告位从签名静态 JSON 读取(多镜像),可引导用户更新或切换渠道需要人工广播时
注意所有兜底参数(IP、应急节点、签名公钥)属于敏感资产:随版本轮换、按渠道分包(不同分发渠道内置不同 IP 子集),泄露一个渠道不烧全部。