17 KiB
下面这份你可以直接丢给 Codex。 我把我们刚刚聊出来的最终拍板结论和完整实现方案都整理进去了。
sub-provider 重构方案(最终版,完整 YAML 路线)
1. 最终结论
本项目后续重构,采用以下最终选择:
对外输出
-
统一输出单个完整 YAML
-
不强依赖客户端支持
rule-providers/proxy-providers -
目标是优先保证:
- 兼容性
- 可调试性
- 易分发
- 易维护
对内实现
-
内部仍然采用模块化设计
-
在 sub-provider 内部完成:
- 源拉取与缓存
- 节点解析与标准化
- 节点筛选、重命名、去重
- 规则模块组合
- 策略组装配
- DNS / TUN / 通用配置拼装
- 最终完整 YAML 渲染
规则存储方式
-
规则正文继续放项目文件
-
采用类似 ACL4SSR 的维护方式:
- 一个类别的规则放一个文件
- 规则文件便于 Git 管理、diff、回滚、手工维护
-
不把 ACL4SSR 大量规则逐条入库
规则组合与面板配置
-
规则的组合关系、启用状态、绑定的策略组、顺序、参数等放 SQLite
-
面板配置的是:
- 选哪些规则模块
- 每个模块绑定哪个策略组
- 模块顺序
- 模块参数
- profile 配置
- 源配置
- 少量 prepend / append 自定义规则
数据库选择
-
默认数据库:SQLite
-
原因:
- 当前项目是单服务、轻量配置中心、生成器型应用
- SQLite 部署和迁移成本最低
- 最适合当前阶段快速落地
-
代码层要保留未来切 PostgreSQL 的能力:
- 使用 SQLAlchemy
- 使用 Alembic
- 用
DATABASE_URL配置数据库连接
-
当前不推荐 Mongo 作为主库
-
当前不优先推荐 MySQL
2. 目标
将现有 Python sub-provider 项目重构为一个:
- 可面板管理
- 配置解耦
- 规则模块化
- 输出完整 YAML
- 可缓存
- 可预览
- 可追踪生成结果
的配置生成系统。
3. 项目边界
本阶段要做
- 面板化管理订阅源
- 规则模块化
- 规则组合关系数据库化
- 支持多个输出 Profile
- 服务端拼装生成完整 YAML
- 做缓存和快照
- 支持预览和下载
本阶段不做
- 不强制对外输出 provider 模式
- 不做“在线全文编辑 ACL4SSR 大规则文件”为主交互方式
- 不做复杂多用户权限系统
- 不做重型前后端分离
- 不把所有规则全文放 SQLite
- 不引入 Mongo 做主存储
4. 架构原则
原则 1:外部简单,内部灵活
客户端只拿一个完整 YAML。 服务端内部怎么拆、怎么缓存、怎么组合,都由 sub-provider 负责。
原则 2:规则内容文件化,组合关系数据库化
规则正文属于“资产”,继续放文件。 面板管理的是“配置和组合关系”,放 SQLite。
原则 3:90% 的配置修改通过“选模块 + 改参数”完成
不要把面板做成“大文本框配置编辑器”。
原则 4:优先可维护,而不是一开始就追求炫技
先把结构跑顺,再考虑高级模式。
5. 总体架构
输入源
-> 拉取缓存
-> 原始内容缓存
-> 解析节点
-> 节点标准化
-> 节点处理(过滤/去重/重命名/分类)
-> 策略组生成
-> 规则模块加载
-> 规则模块参数渲染
-> 规则按顺序拼接
-> 插入 prepend/append 自定义规则
-> 渲染完整 YAML
-> 结果缓存 / 生成快照
-> 提供下载 / 预览 / HEAD 信息
6. 推荐技术栈
后端
- FastAPI
数据库
- SQLite(默认)
- SQLAlchemy ORM
- Alembic migration
模板
- Jinja2
前端
- 优先服务端渲染
- 可用 Jinja2 + HTMX 或简单模板页
- 先不要求 React/Vue 前后端分离
缓存
-
轻量场景下可先用:
- SQLite 表
- 本地文件缓存
-
不必一上来引入 Redis
7. 目录结构建议
app/
api/
routes_sources.py
routes_profiles.py
routes_rules.py
routes_preview.py
core/
config.py
database.py
cache.py
db/
base.py
session.py
models/
source.py
profile.py
rule_module.py
policy_group.py
artifact.py
schemas/
source.py
profile.py
rule_module.py
services/
source_fetcher.py
source_parser.py
proxy_normalizer.py
proxy_processor.py
policy_group_builder.py
rule_loader.py
rule_renderer.py
profile_renderer.py
artifact_service.py
templates/
base.html
sources.html
profiles.html
rules.html
preview.html
main.py
rules/
modules/
lan.list
private.list
cn_domain.list
cn_ip.list
apple.list
microsoft.list
github.list
telegram.list
openai.list
streaming.list
ads.list
final_proxy.list
final_direct.list
presets/
minimal.yaml
daily.yaml
router.yaml
group_templates/
basic.yaml
ai.yaml
streaming.yaml
data/
app.db
cache/
raw_sources/
parsed_sources/
generated/
artifacts/
migrations/
tests/
8. 规则系统设计
8.1 规则正文:继续放文件
规则正文文件继续按 ACL4SSR 风格维护。
例如:
rules/modules/apple.listrules/modules/openai.listrules/modules/telegram.listrules/modules/cn_domain.listrules/modules/final_proxy.list
推荐格式
规则文件使用模板变量,不直接写死策略组:
DOMAIN-SUFFIX,openai.com,{{ target_group }}
DOMAIN-SUFFIX,chatgpt.com,{{ target_group }}
DOMAIN-SUFFIX,oaistatic.com,{{ target_group }}
DOMAIN-SUFFIX,auth0.openai.com,{{ target_group }}
这样同一个规则模块可复用到不同策略组。
8.2 规则模块:放 SQLite
SQLite 里存规则模块元数据,而不是规则全文。
表:rule_modules
字段建议:
idkeynamedescriptionfile_pathcategorydefault_enableddefault_orderdefault_target_policyparams_schema_jsoncreated_atupdated_at
示例
{
"key": "openai",
"name": "OpenAI",
"file_path": "rules/modules/openai.list",
"category": "service",
"default_enabled": true,
"default_order": 80,
"default_target_policy": "🤖 AI",
"params_schema_json": {
"target_group": {
"type": "string",
"default": "🤖 AI"
}
}
}
8.3 Profile 中的规则组合:放 SQLite
表:profile_rule_modules
字段建议:
idprofile_idmodule_idenabledorder_indextarget_policyparams_json
含义:
- 这个 profile 是否启用这个模块
- 顺序是什么
- 最终绑定到哪个策略组
- 参数是什么
8.4 规则预设
可选支持“预设”。
例如:
minimaldailyrouter
但预设只作为初始化模板,最终仍落到具体 profile 配置里。
不要求上线初期就把预设做得很复杂。
9. 策略组系统设计
策略组不要硬编码死在一个大 YAML 模板里。 也要做成可配置对象。
表:policy_groups
字段建议:
idprofile_idnametypeorder_indexconfig_json
config_json 示例
{
"proxies": ["DIRECT", "REJECT", "香港节点", "日本节点"],
"include_all_nodes": false,
"filter": "HK|Hong Kong"
}
支持的策略组类型
selecturl-testfallbackload-balance
建议的默认组
🚀 节点选择🤖 AI📺 流媒体🍎 苹果服务📲 Telegram🌍 国外网站🇨🇳 国内网站
10. 源管理设计
表:sources
字段建议:
-
id -
name -
type值可为:base64urllinkstatic
-
content -
headers_json -
enabled -
priority -
update_interval_sec -
rename_rules_json -
filter_rules_json -
dedupe_policy -
last_sync_at -
last_sync_status -
last_error -
created_at -
updated_at
说明
这里的源是原始输入源,不是给客户端的 provider。
11. Profile 设计
Profile 是最终对外输出的配置单元。
例如:
- iPhone 配置
- Windows 配置
- OpenWrt 配置
- Apple TV 配置
- 精简版配置
- 完整版配置
表:profiles
字段建议:
idnamedescriptionsource_ids_jsondns_templatetun_enabledudp_enabledappend_subscription_infoexpose_head_infoenabledcreated_atupdated_at
12. 自定义覆盖设计
为了兼容高级用户需求,支持少量覆盖,但不做全文编辑器。
表:profile_overrides
字段建议:
idprofile_idcustom_rules_prependcustom_rules_appendcustom_proxy_groupscustom_dns_patchcustom_yaml_patch
原则
只提供:
- prepend rules
- append rules
- 少量 patch
不鼓励直接在面板里手写全部 YAML。
13. 缓存设计
13.1 原始源缓存
缓存拉回来的原始内容。
目的:
- 避免频繁请求订阅源
- 降低上游压力
- 出问题可复现
13.2 解析结果缓存
把原始内容解析为统一节点模型后缓存。
目的:
- 多 profile 复用解析结果
- 避免重复解析
13.3 最终 YAML 缓存
同一个 profile 在以下内容不变时,直接返回缓存:
- 订阅源内容未变
- profile 配置未变
- 规则模块未变
- 策略组未变
缓存键建议基于 hash:
- 源快照 hash
- 规则快照 hash
- profile 配置 hash
14. 生成快照设计
表:generated_artifacts
字段建议:
idprofile_idversioncontentcontent_hashsource_snapshot_jsonrule_snapshot_jsongenerated_at
用途
- 预览
- diff
- 回滚
- 调试
- 追踪“为什么这次生成结果变了”
15. 内部统一节点模型
建议在解析层统一成一个内部对象。
Python 草案
from pydantic import BaseModel
from typing import Any
class ProxyNode(BaseModel):
name: str
type: str
server: str
port: int
udp: bool = True
tags: list[str] = []
raw: dict[str, Any] = {}
对不同类型协议(ss、vmess、vless、trojan、hysteria 等)额外字段可放在 raw 里。
16. 生成流水线
第 1 步:拉取源
- 读取启用的 sources
- 获取原始订阅内容
- 更新缓存
- 记录同步状态
第 2 步:解析源
- 解析 base64
- 解析单链接
- 解析远程订阅
- 标准化成统一节点模型
第 3 步:节点处理
- 去重
- 重命名
- 按国家/协议/标签分类
- 过滤无效节点
- 应用 profile 的筛选逻辑
第 4 步:生成策略组
- 读取 profile 绑定的 policy groups
- 根据节点分类与过滤规则生成
proxy-groups
第 5 步:加载规则模块
- 读取 profile 启用的规则模块
- 按顺序加载规则文件
- 渲染模板变量(如
target_group)
第 6 步:组装规则
- 拼接所有规则模块
- 插入 prepend rules
- 插入 append rules
- 保证
MATCH规则最后输出
第 7 步:生成完整 YAML
输出包含:
- mixed-port / socks-port / redir-port / tproxy-port(按需)
- mode
- log-level
- dns
- tun
- proxies
- proxy-groups
- rules
第 8 步:缓存与快照
- 计算 hash
- 命中缓存则复用
- 否则生成新 artifact
17. 输出设计
对外输出接口
/profiles/{id}/clash.yaml/profiles/{id}/download/profiles/{id}/preview/profiles/{id}/head
输出原则
- 默认返回完整 YAML
- 对客户端透明
- 客户端无需理解内部模块化结构
可选响应头
支持将源站订阅信息透传到最终响应头,例如:
subscription-userinfo- 其他流量额度相关头
如果多个源混合:
- 默认只透传第一个主源的额度信息
- 或后续设计聚合策略,但不是当前必做
18. API 草案
源管理
GET /api/sourcesPOST /api/sourcesPUT /api/sources/{id}DELETE /api/sources/{id}POST /api/sources/{id}/testPOST /api/sources/{id}/sync
规则模块
GET /api/rule-modulesGET /api/rule-modules/{id}PUT /api/rule-modules/{id}
Profile
GET /api/profilesPOST /api/profilesPUT /api/profiles/{id}DELETE /api/profiles/{id}
Profile 规则配置
GET /api/profiles/{id}/rulesPUT /api/profiles/{id}/rules
Profile 策略组配置
GET /api/profiles/{id}/policy-groupsPUT /api/profiles/{id}/policy-groups
预览与生成
POST /api/profiles/{id}/previewPOST /api/profiles/{id}/generateGET /api/profiles/{id}/artifactsGET /api/artifacts/{id}
19. 面板设计原则
普通模式
允许:
- 配源
- 选 profile
- 勾选规则模块
- 选择规则模块绑定的策略组
- 调模块顺序
- 加 prepend / append 规则
- 预览生成结果
高级模式
允许:
- 编辑少量覆盖配置
- 自定义组模板
- 导入自定义规则模块
不建议
- 直接在线编辑整份 ACL4SSR 规则大文件作为主要操作方式
20. 示例规则模块
rules/modules/openai.list
DOMAIN-SUFFIX,openai.com,{{ target_group }}
DOMAIN-SUFFIX,chatgpt.com,{{ target_group }}
DOMAIN-SUFFIX,oaistatic.com,{{ target_group }}
DOMAIN-SUFFIX,auth0.openai.com,{{ target_group }}
rules/modules/apple.list
DOMAIN-SUFFIX,apple.com,{{ target_group }}
DOMAIN-SUFFIX,icloud.com,{{ target_group }}
DOMAIN-SUFFIX,itunes.apple.com,{{ target_group }}
DOMAIN-SUFFIX,apps.apple.com,{{ target_group }}
21. 示例最终输出 YAML 骨架
mixed-port: 7890
allow-lan: true
mode: rule
log-level: info
dns:
enable: true
ipv6: false
nameserver:
- 223.5.5.5
- 119.29.29.29
proxies:
- name: 香港节点 01
type: ss
server: 1.2.3.4
port: 443
cipher: aes-128-gcm
password: xxxx
proxy-groups:
- name: 🚀 节点选择
type: select
proxies:
- 香港节点 01
- 日本节点 01
- DIRECT
- name: 🤖 AI
type: select
proxies:
- 🚀 节点选择
- 香港节点 01
- 日本节点 01
rules:
- DOMAIN-SUFFIX,openai.com,🤖 AI
- DOMAIN-SUFFIX,chatgpt.com,🤖 AI
- DOMAIN-SUFFIX,apple.com,🍎 苹果服务
- GEOIP,CN,DIRECT
- MATCH,🚀 节点选择
22. 数据库配置要求
默认
DATABASE_URL=sqlite:///./data/app.db
未来切 PostgreSQL
DATABASE_URL=postgresql+psycopg://user:pass@postgres:5432/subprovider
要求
- 所有数据库访问都走 SQLAlchemy
- migration 走 Alembic
- 不写死 SQLite 特性到业务逻辑中
23. 开发阶段建议
第一阶段:解耦与最小可用
目标:
- 先跑通结构
任务:
- 引入 SQLAlchemy + Alembic
- 建 sources / profiles / rule_modules / profile_rule_modules / policy_groups / artifacts 表
- 将现有规则整理为
rules/modules/*.list - 将现有单体生成逻辑拆成 service
- 支持生成一个完整 YAML
- 提供最简预览页面
第二阶段:面板化
目标:
- 基础可用
任务:
- 源管理页面
- Profile 管理页面
- 规则模块勾选和排序页面
- 策略组配置页面
- 预览和下载页面
第三阶段:增强能力
目标:
- 更稳定、更可追踪
任务:
- 快照与 diff
- 生成缓存优化
- 同步日志和错误展示
- 自定义规则导入
- 自定义组模板
24. 明确不推荐的方向
- 不推荐把 ACL4SSR 规则逐条入 SQLite
- 不推荐面板主交互是“编辑一万条规则文本”
- 不推荐一开始就做 rule-provider / proxy-provider 对外发布
- 不推荐 Mongo 作为主配置库
- 不推荐先做复杂权限系统
- 不推荐先做重前端再补业务逻辑
25. 给 Codex 的明确执行要求
请按以下要求重构项目:
-
保留对外输出为单个完整 YAML
-
将内部生成逻辑改为模块化流水线
-
规则正文继续使用文件存储
-
使用 SQLite 存储:
- 源配置
- profile 配置
- 规则模块元数据
- profile 与规则模块的绑定关系
- 策略组配置
- 生成快照
-
使用 SQLAlchemy + Alembic,数据库 URL 可配置
-
代码结构按 service 分层,避免单文件堆逻辑
-
首先实现最小可运行版本:
- 能配置 source
- 能配置 profile
- 能选择规则模块
- 能选择目标策略组
- 能生成并预览完整 YAML
-
不要实现对外 provider 模式作为默认路线
-
不要将规则正文全文入库
-
不要将面板设计成规则全文编辑器
26. 最终一句话总结
本项目的最终路线是:
内部模块化、缓存化、可配置化 对外输出完整单文件 YAML 规则正文继续文件维护 规则组合关系和面板配置放 SQLite
这条路线最符合当前项目阶段,也最稳。
如果你要,我下一条可以继续给你一份更像任务单的 Codex 执行拆分版,我会按“先改哪些文件、再改哪些文件、每步验收什么”来写。