From 51317e9f43c66bfa6d64889c64fc135bfc5989af Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Mon, 27 Jul 2026 01:48:22 +0800 Subject: [PATCH] =?UTF-8?q?design(prototype):=20=E5=88=86=E6=B5=81?= =?UTF-8?q?=E8=A7=84=E5=88=99=E5=B1=8F=E7=94=A8=20v2=20=E7=9C=9F=20ui-kit?= =?UTF-8?q?=20=E9=87=8D=E5=BB=BA=20+=20=E6=90=AC=E5=85=A5=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=AF=B4=E6=98=8E=E6=96=87=E6=A1=A3(Task=203)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用 v2 设计系统真原子(.segswitch/.setting-row/.toggle/.card/.pill/.btn)建 screens/routing-rules.html(移动子屏 + 桌面设置窗口),替代独立 docs mockup。 配置说明文档搬入本分支 docs/。设计-first,待确认 4 取舍后出实现计划。 Co-Authored-By: Claude Opus 4.8 --- design/prototype/screens/routing-rules.html | 163 ++++++++++++++++++++ docs/configurable-proxy-spec.html | 156 +++++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100644 design/prototype/screens/routing-rules.html create mode 100644 docs/configurable-proxy-spec.html diff --git a/design/prototype/screens/routing-rules.html b/design/prototype/screens/routing-rules.html new file mode 100644 index 0000000..fa8990f --- /dev/null +++ b/design/prototype/screens/routing-rules.html @@ -0,0 +1,163 @@ + + + + + +分流规则 · 可配置代理原型(真 ui-kit) + + + + + + +
+

分流规则 · 可配置代理

+

Task 3 原型(用 v2 真实设计系统重建:全走 atoms.css / tokens.css / icons.js,非独立 mockup)。让用户像 Shadowrocket 那样自定义"直连 / 走隧道 / 拒绝"。规则模型与实现见 配置说明文档

+ +

移动端 · 分流规则子屏

+
+
+
9:415G ▮▮▮
+ +
+ +
代理模式
+
+ + + +
+ +
内置规则
+
+
国内直连
GeoIP / GeoSite CN
+
局域网 / 私网直连
强制,不可关
🔒
+
私有服务走隧道
服务端下发
🔒
+
+ +
我的规则 · 首命中生效
+
+
git.51yanmei.com
域名后缀
直连
+
aliyun.com
域名后缀
直连
+
github.com
域名后缀
走隧道
+
category-ads
GeoSite 规则集
拒绝
+
35.190.0.0/16
IP-CIDR
走隧道
+
+ + +
最终(未命中)
+
+
FINAL 兜底
走隧道
+
+
+
+ + +
+
9:415G ▮▮▮
+ +
+
类型
+
+ 域名域名后缀关键字 + IP-CIDRGeoIPGeoSite +
+
+
+
动作
+
+ 直连 DIRECT走隧道 PROXY拒绝 REJECT +
+
预览 · 翻译为 sing-box 规则
+
{ "domain_suffix":
+    ["git.51yanmei.com"],
+  "outbound": "direct" }
+
+
+
+ +

桌面端 · 设置窗口(表格 + 实时预览)

+
+
Pangolin — 设置 · 分流规则
+
+
+
通用
节点
分流规则
账户
统计
+
+
+
+
分流规则
+
+ +
+
+
+ + LAN 直连 🔒 + 私有服务走隧道 🔒 +
+ + + + + + + +
类型动作说明启用
域名后缀git.51yanmei.com直连CI 源
域名后缀aliyun.com直连镜像
域名后缀github.com走隧道
GeoSitecategory-ads拒绝广告
IP-CIDR35.190.0.0/16走隧道
+
+ + + + FINAL:走隧道 +
+
+
+
+ +
+

为什么用 v2 真 ui-kit

本屏所有组件(段选 .segswitch、设置行 .setting-row、开关 .toggle、卡片 .card、胶囊 .pill、按钮 .btn)都来自 v2 设计系统真原子,颜色全走 token,与线上 App 一致——不是独立 mockup。动作语义色(直连绿/走隧道橙/拒绝红)是原型内联,实现时收进 atoms。

+

待你确认(设计层)

①规则粒度够不够 ②要不要分应用代理(per-app,建议后置)③「从文本导入」Phase 1 还是 2 ④档案 per-user 还是 per-device。确认后出 Phase 1 实现计划。

+
+
+ + diff --git a/docs/configurable-proxy-spec.html b/docs/configurable-proxy-spec.html new file mode 100644 index 0000000..768518a --- /dev/null +++ b/docs/configurable-proxy-spec.html @@ -0,0 +1,156 @@ + + + + + +Pangolin 可配置分流 · 配置说明 + + + +
+

Pangolin 可配置分流 · 配置说明文档

+

Task 3 设计 · 让用户像 Shadowrocket 那样自定义路由规则(哪些直连 / 走隧道 / 拒绝)。

+

配套视觉原型:交互原型 → · 状态:设计待确认(未开发)

+ +

1. 目标与背景

+

当前 pangolin 客户端的分流是服务端固定渲染的:LAN 直连、DNS 劫持、可选国内分流(geoip/geosite-cn)、私有域名走隧道,用户无法自定义。实际需求(如 CI 编译源、公司内网、某些国内站要直连;某些站要强制走隧道;广告要拒绝)无处配置——这次暴露的「CI 流量被灌进隧道拖垮小节点」就是典型。

+

本设计给用户一套可配置路由规则,心智模型对齐 Shadowrocket 的 [Rule] 段:有序规则表,首命中生效,动作三选一(直连 / 走隧道 / 拒绝)。

+ +

2. 架构铁律:客户端不拼配置

+
ARCHITECTURE.md §3.1:Dart/Flutter 客户端不得自行拼装或修改 sing-box 配置——配置一律服务端渲染、原样下发。所以"客户端可配置"不能变成"客户端本地改 config"。
+

解法:用户在 App 编规则 → 存为服务端 per-user「路由档案(routing profile)」→ connect 时服务端把档案翻译进渲染的配置。客户端只负责编辑 UI + 存/取档案,永不碰 sing-box JSON。

+
App 规则编辑器  ──PUT /v1/routing-profile──▶  服务端存 per-user 档案(DB)
+                                                      │
+App 点连接  ──POST /v1/nodes/{id}/connect──▶  BuildClientConfig(读档案→翻译成 route.rules)
+                                                      │
+App  ◀────────── 完整 sing-box 配置(含用户规则)─────┘  原样喂内核
+ +

3. 规则模型

+

一条规则 = { type, value, action, note?, enabled }。整个档案:

+
{
+  "mode": "rule",            // global | rule | direct(对齐 shadowrocket 三模式)
+  "builtin": {
+    "china_direct": true,    // 国内分流(geoip-cn/geosite-cn → 直连)开关
+    "lan_direct": true,      // LAN/私网直连(强制,不可关)
+    "private_via_tunnel": true // 私有服务域名走隧道(服务端下发,不可关)
+  },
+  "rules": [                 // 用户自定义,有序,首命中生效
+    { "type": "domain_suffix", "value": "git.51yanmei.com", "action": "direct", "note": "CI 源", "enabled": true },
+    { "type": "geosite",       "value": "category-ads",     "action": "reject" },
+    { "type": "ip_cidr",       "value": "35.190.0.0/16",    "action": "proxy" }
+  ],
+  "final": "proxy"           // 兜底:未命中任何规则的动作
+}
+ +

类型 type

+ + + + + + + + +
type值示例sing-box 字段
domainexample.comdomain(精确)
domain_suffixaliyun.comdomain_suffix(含子域)
domain_keywordgoogledomain_keyword
ip_cidr35.190.0.0/16 · ::/0ip_cidr(v4/v6)
geoipCN · USrule_set(自托管 geoip-*.srs)
geositecn · netflix · category-adsrule_set(自托管 geosite-*.srs)
+

动作 action → sing-box outbound

+ + + + + +
actionoutbound说明
directdirect物理网卡直连(配合 route_exclude/reverse_mapping 真直连)
proxyauto经节点(REALITY/Hy2 urltest 择优)
rejectblock阻断
+ +

4. 优先级(渲染顺序)

+

服务端把规则按固定层级拼进 route.rules,自上而下首命中:

+
+
1DNS 劫持(port 53 → hijack-dns)· 系统强制
+
2LAN / 私网直连(10/8·192.168/16·127/8)· 系统强制
+
3私有服务域名 → 走隧道(PANGOLIN_PRIVATE_SPLIT_DOMAINS服务端
+
4用户规则(档案 rules[] 顺序展开)← 新增
+
5国内分流 geoip-cn/geosite-cn → 直连(china_direct 开时)
+
6FINAL 兜底(final:proxy / direct)
+
+
用户规则排在国内分流之前——这样"我要 github 走隧道""我要某国内站走隧道"能压过 geoip-cn 的直连默认。系统层(1-3)永远在用户规则之上,防止用户误配把 DNS/LAN/私有服务弄坏。
+ +

5. 直连是否真"不走 VPN"

+

direct outbound 让 sing-box 从物理网卡直接出连接。但 TUN strict_route 会把包重新捕回隧道——已有两个机制解决,用户规则复用:

+ +
这是关键实现难点:域名类直连规则要真生效,必须开 reverse_mapping 且用 local DNS 解析该域名;IP 类直连规则要真生效,值必须同时进 route_exclude_address。这两点在实现计划里逐条落。
+ +

6. 存储与传输(API)

+ + + + + +
端点作用
GET /v1/routing-profile拉当前用户档案(App 编辑器初始化;无则返回内置默认)
PUT /v1/routing-profile保存档案(服务端校验:CIDR 合法、type 合法、条数上限、去重)
POST …/connect(现有)渲染时读该用户档案,翻译进 route.rules
+

档案存 DB(routing_profiles 表:user_id · profile_json · updated_at),不走 connect body(与现有 split_cn 走 query 的约束一致——大规则集不塞 query/body)。客户端本地也缓存一份(离线可看/编,连接时以服务端为准)。

+ +

7. 校验与兜底(fail-safe)

+ + +

8. 与现有机制的关系

+ + + + + + +
现有本设计如何吸收
SplitCN(geoip/geosite-cn 直连,#5)降为档案里的 builtin.china_direct 开关(层级 5)
PrivateSplitDomains(走隧道)保留为系统层 3(服务端 env,用户不可动)
route_exclude_address(LAN)保留 + 扩展:用户 ip_cidr→direct 规则动态并入
reverse_mapping / local DNS复用:域名直连规则靠它命中
+

换句话说,本设计是把三个散落的分流机制统一收进一个用户可见、可配的规则模型,底层复用已验证的 sing-box 手法。

+ +

9. 待你确认的取舍

+
Q1 规则粒度:先做"域名/IP/GeoIP/GeoSite + 三动作"的规则表(本设计)?还是要更细(URL 正则、UA、进程名)?建议先前者,后者 shadowrocket 也少人用。
+
Q2 分应用代理(per-app):按 App 分流(仅 Android/桌面可行,iOS 系统扩展做不到)。较重,建议后置为独立任务。
+
Q3「从文本导入」:粘贴 Shadowrocket/Clash 规则批量建(原型第三屏)。锦上添花,可 Phase 2
+
Q4 档案作用域:per-user(跨设备同步,推荐)还是 per-device(每台独立)?推荐 per-user + 单档案起步。
+ +

10. 分期建议

+ +

确认这份设计后,我用 writing-plans 出 Phase 1 的实现计划(TDD、多端、服务端翻译逐条测),再开发。

+
+ +