Skip to the content.

使用文档 · 开发文档 · 配置文档

MagicPanel 开发文档

给要改这份代码的人(人或 Agent)。看完能回答三个问题:要改的东西在哪个文件、改完怎么验证、怎么发到线上。

配置数据本身的结构与改法见 配置文档;给使用者的说明见 使用文档。


目录


一句话认识这个项目

一个自托管的代理订阅配置管理服务。用户维护「节点来源 / 规则来源 / 策略组 / 分流策略 / 引擎平台 / 拓展模块 / 基础配置」,面板把它们编译成 Stash 和 Mihomo 能直接用的 YAML,构建成不可变快照,发布出去,设备按固定订阅地址拉取。

它不碰流量:不开发代理内核,不做中转,只负责”把配置编对并分发”。


跑起来

本地开发

python3 -m venv .venv && .venv/bin/pip install -r server/requirements.txt
npm install
npm run dev

环境变量

变量 作用
MAGICPANEL_DATA_DIR 数据目录,默认 server/../data
MAGICPANEL_SCHEDULER=0 关闭内置定时任务(测试用)
MAGICPANEL_SCHEDULER_TICK 调度器心跳间隔秒数,默认 30

数据目录里有什么

data/
  magicpanel.db     SQLite(主库,WAL 模式)
  secret.key        Fernet 主密钥,丢了备份就解不开
  builds/           构建产物
  bin/mihomo        测速核心
  geoip.dat / geosite.dat / country.mmdb
  avatars/          头像

环境与内网地址

仓库和脚本里出现的内网地址都出自 环境与地址速查。一句话版:

改网络环境(换 IP、换机器)时,先改那份速查文档,再改引用它的地方。


代码地图

server/app/
  main.py           应用装配:路由挂载、静态托管、调度器启动
  config.py         路径、常量、白名单(引擎标签、规则类型、策略组类型…)
  db.py             表结构(SCHEMA)、迁移(_migrate_*)、事务与查询助手
  deps.py           依赖注入:当前用户、CSRF 校验
  security.py       口令散列、令牌、Fernet 加解密、审计写入
  routers/          HTTP 接口,一个业务一个文件
    auth.py         登录、登出、改密、头像
    policy.py       策略组、分流规则
    targets_devices.py  引擎平台、设备
    sources.py      节点来源
    rule_providers.py    规则来源
    local_nodes.py  本地单节点
    snippets.py     拓展模块
    base_config.py  基础配置(三层)
    builds.py       构建、发布、回滚
    feed.py         订阅分发
    automation.py   自动构建发布与运行记录
    portal.py       门户页
    deps.py         自主维护(依赖文件库的浏览、编辑、提交、同步)
    misc.py         概览、审计、设置、备份、测速核心
  services/
    base_config.py  三层合并、差异计算、默认配置、参数 schema
    fetcher.py      订阅抓取
    repo_manager.py 依赖文件库的 Git 操作层(只做 Git,不做业务判断)
    repo_sync.py    仓库内容同步:rule/*.yaml → 规则来源
    tester.py       Mihomo 核心拨测
    scheduler.py    定时任务
    releases.py     发布与回滚
    updater.py      核心安装
    webdav.py       远程备份
    local_nodes.py  本地节点参数与渲染
    direct.py       直连域名、Fake-IP 过滤等伪键
    refs.py         引用检查(谁引用了这个)
    retention.py    保留策略
  compiler/
    render.py       产物渲染(合并、渲染目标、设备叠加)
    validate.py     产物校验
src/
  views/            一个页面对应一个 .vue
  components/       通用组件(StatusDot、EmptyState、ErrorState…)
  api.js            后端接口封装
  router.js         路由表
  store.js          登录态与全局状态
  core.js           通用逻辑
  format.js         时间、数字、枚举文案
  confirm.js        二次确认
  theme.js          主题变量
  mobile.js         useMobile() 断点判断
  useRowSortable.js 拖动排序
  scopeOptions.js   「包含所有」哨兵(与后端 config.ALL_SCOPE 对齐)
  snippetPresets.js 拓展模块预设
scripts/
  deploy.sh         一键发布到 NAS
  package.sh        打出可部署的 tar.gz
  release.sh        打标签推送、发 GitHub Release
  check_secrets.py 凭据扫描(CI + 部署前)
  check_engine_defaults.py 引擎默认配置与官方文档对账
  check_data_consistency.py 线上数据自检(部署后)

数据怎么流动

节点来源(订阅) ──┐
本地节点        ──┤
规则来源(规则集) ──┤
策略组          ──┼──►  collect_snapshot()  ──►  编译 ──►  校验  ──►  构建快照
分流规则        ──┤         (builds.py)          (compiler/)    (compiler/validate)
拓展模块        ──┤
基础配置三层    ──┤
平台扩展        ──┘
                                   │
                                   ├──► 平台产物   builds/<id>/<平台>.yaml
                                   └──► 设备产物   builds/<id>/<设备名>.yaml
                                                │
                                    发布 ───────┤
                                                ▼
                              /feed/<令牌>/config.yaml   (分发时叠加设备独立配置)

关键点:三层配置的作用域不同。


改动落点速查

想改什么 改哪里
页面上的一个字段、一个按钮 src/views/<页面>.vue
新增一个页面 src/views/Xxx.vue + src/router.js 加路由 + src/App.vue 加菜单
接口地址与参数 src/api.js
增删改接口 server/app/routers/<业务>.py
策略组 / 规则的校验规则 server/app/routers/policy.py + server/app/config.py 的白名单
产物顶层键(端口、模式、DNS…) server/app/services/base_config.py 的 SCHEMA 与 PRESETS
引擎默认配置 server/app/services/base_config.py 的 _COMMON_DEFAULTS / STASH_* / MIHOMO_*
基础配置页的本层改动标记 src/views/ArtifactConfig.vue(蓝色 = 本层新增,橙色 = 本层覆盖)
产物合并、渲染 server/app/compiler/render.py
产物校验规则 server/app/compiler/validate.py
定时任务 server/app/services/scheduler.py
依赖仓库的 Git 操作 server/app/services/repo_manager.py(命令封装、排除清单、冲突三方)
仓库内容 → 规则来源 server/app/services/repo_sync.py
发布与回滚 server/app/services/releases.py、server/app/routers/builds.py
订阅分发 server/app/routers/feed.py
订阅内容解析(Clash YAML / base64 URI 列表) server/app/services/source_nodes.py
删除前的引用检查(含当前生产产物是否还引用它) server/app/services/refs.py
数据库表结构 server/app/db.py 的 SCHEMA + init_db() 里加迁移
适用范围(引擎平台 / 设备 / 节点来源) 哨兵 config.ALL_SCOPE("*")= 多选里的「包含所有」;空数组 = 不适用任何
引擎名、平台名、规则类型白名单 server/app/config.py(RULE_TYPES 管创建,ENGINE_RULE_TYPES 管构建校验)
基础配置预设 server/app/services/base_config.py 的 PRESETS(经 /api/v1/base-config/schema 下发)
拓展模块预设 src/snippetPresets.js 的 SNIPPET_PRESETS(纯前端常量,服务端无预设接口)
部署流程 scripts/deploy.sh、docker-compose.yml、Dockerfile
文档 docs/,本文件与配置文档优先更新
文档站 scripts/build_docs_site.py 生成站点源码,.github/workflows/pages.yml 自动发布

数据库

SQLite,WAL 模式,单文件 data/magicpanel.db。

表 存什么 关键点
users 维护者账号 口令散列、门户 PIN 散列、头像 MIME
sessions 登录会话 默认 7 天过期
sources 节点来源 URL 加密存储;抓取快照、测速结果、自动抓取/测速开关
rule_providers 规则来源 URL 加密存储;远程/内联;行为类型
local_nodes 本地单节点 参数加密;协议不同字段不同
proxy_groups 策略组 targets / devices 是 JSON 数组,["*"] = 全部(哨兵 config.ALL_SCOPE),[] = 不适用任何平台 / 设备
rules 分流规则 同上;no_resolve 标记;sort 决定顺序
targets 引擎平台 (engine, platform) 唯一
devices 设备 令牌哈希 + 加密副本;target_id 指向引擎平台
base_configs 基础配置三层 主键 (engine, platform, device_id);device_id=0 是引擎平台配置层,platform='' 是引擎默认配置层
snippets 拓展模块 YAML 片段,标引擎
builds 构建快照 产物、校验结果、策略摘要
releases 发布记录 testing / production 各至多一条生效
audit 审计日志 谁在何时改了什么
automation_runs 自动任务运行记录 最近 20 条
settings 键值设置 见 config.SETTINGS_DEFAULTS

加字段的固定做法

不要手改线上库,也不要改历史数据。加列 + 写迁移:

# server/app/db.py
def _ensure_column(conn, table, column, decl) -> bool:
    ...  # 已有

# 在 init_db() 里
_ensure_column(conn, "sources", "new_flag", "new_flag INTEGER NOT NULL DEFAULT 0")

# 需要搬历史数据时,再写一个 _migrate_xxx(conn),在 init_db() 末尾调用
def _migrate_xxx(conn) -> None:
    conn.execute("UPDATE ... WHERE ...")

迁移必须幂等(重复执行不报错、不重复改数据),因为每次启动都会跑。


后端约定

基础配置的比较基线

三层各自只存”相对基线的差异”,基线怎么算决定了差异怎么算:


前端约定

语义 写法
新建 / 保存 type="primary"(实心蓝)
触发一次动作 type="primary" plain
检测 / 校验 type="success" plain
发布 type="success"
查看 type="info" plain
撤销 / 警告 type="warning" plain
删除 type="danger" plain
中性(编辑、排序、取消、批量修改) 不写 type

改完怎么验证

cd server && ../.venv/bin/python -m pytest tests -q    # 后端测试,应全绿
npm run build                                          # 前端能构建
.venv/bin/python scripts/check_secrets.py              # 凭据扫描
.venv/bin/python scripts/check_engine_defaults.py      # 引擎默认配置与官方文档对账

线上数据的自检在部署脚本里自动跑(scripts/check_data_consistency.py),也可以手动对线上库跑:

scp scripts/check_data_consistency.py archon@10.0.1.2:/tmp/check_data.py
ssh archon@10.0.1.2 "docker cp /tmp/check_data.py magicpanel:/tmp/check_data.py && \
  docker exec magicpanel python3 /tmp/check_data.py /app/data/magicpanel.db"

改了配置层或引擎默认配置,要重新构建发布才生效;只改代码(页面、接口、逻辑)则部署后立刻可见。


怎么发到线上

DEPLOY_PROXY=http://10.0.1.8:7890 bash scripts/deploy.sh          # 带测试
DEPLOY_PROXY=http://10.0.1.8:7890 bash scripts/deploy.sh --fast   # 只改前端时跳过测试

DEPLOY_PROXY 指向 Mac mini 上的 Stash 混合端口(见环境与地址速查)。 它是通过 ssh 注入到 NAS 端 docker compose build 的(构建时要拉 npm/pip 包), 所以必须写 Mac mini 的内网地址 10.0.1.8——写 127.0.0.1 会让 NAS 连自己、拉包失败。

脚本依次做:跑后端测试 → 同步工作区到 NAS → 重建容器 → 等健康检查 → 跑数据自检 → 验域名。任何一步不过就停。

发完还要发一版订阅:

# 后台「构建发布 → 创建构建 → 发布至测试 → 发布至生产」
# 或用接口
curl -X POST https://magichub.top:8443/api/v1/builds -H 'Content-Type: application/json' \
  -H "Cookie: mp_session=..." -H "X-CSRF-Token: ..." \
  -d '{"note":"说明这次改了什么"}'

验证线上:

curl -s https://magichub.top:8443/api/v1/setup/status      # 面板活着
ssh archon@10.0.1.2 "docker logs magicpanel --tail 50"      # 看日志

回滚:面板「构建发布」里「回滚至生产」;代码问题用 git revert + 重新部署。

打包与发布版本

./scripts/package.sh              # dist/magicpanel-<时间戳>.tar.gz
./scripts/release.sh 1.2.0        # 打标签推送 + GitHub Release

硬性约束

这几条是设计决定,破坏它们会直接让客户端加载失败。完整清单见仓库根目录的 AGENTS.md,最关键的四条:

  1. 结构化内容不能被配置层覆盖。 proxies / proxy-providers / proxy-groups / rule-providers / rules 这五个键,引擎默认配置 / 引擎平台配置 / 设备独立配置、平台扩展、拓展模块都不许写。服务端硬校验,不是提示。
  2. 兜底规则(MATCH / FINAL)永远在最后。 规则按 sort 排序,兜底之后不能有规则。
  3. 列表的合并语义分两种:引擎默认配置 / 引擎平台配置 = 整体替换;设备独立配置 = 追加。差异计算、层级合并、分发叠加三处必须一致。
  4. 设备独立配置的键跟着设备的引擎平台走。 设备换平台、平台改引擎时要自动换键,否则配置静默失效。

常见改动配方

加一个新的产物顶层键

  1. server/app/services/base_config.py 的 SCHEMA 里加字段(类型、说明、分组、默认值)。
  2. 需要默认开启的,加进 _COMMON_DEFAULTS 或引擎专属的 STASH_* / MIHOMO_*。
  3. 跑 scripts/check_engine_defaults.py——每个默认键都要能在 official-example/ 里找到出处。
  4. 界面自动出现该参数(表单是 schema 驱动的)。

加一个拓展模块预设

  1. src/snippetPresets.js 的 SNIPPET_PRESETS 里加一条(key / name / category / engine / note / content)。
  2. 预设内容不许出现结构化内容键。

基础配置的预设是另一套,在 server/app/services/base_config.py 的 PRESETS,不要混。

加一条数据自检规则

scripts/check_data_consistency.py 里加一段:查出问题写 problems(阻断部署),只是提示写 notes(不阻断)。规则集合、策略组、规则、设备的引用完整性、命名、冗余覆盖都从这里管。

加一个页面

  1. src/views/Xxx.vue。
  2. src/router.js 加路由,src/App.vue 加菜单项。
  3. 后端接口放 server/app/routers/ 下合适的文件。
  4. 窄屏用 useMobile() 处理表格与操作列。

改产物结构(合并顺序、渲染逻辑)

server/app/compiler/render.py。改完必须跑构建并逐个目标比对产物,Mihomo 目标还会跑 mihomo -t 校验。


遇到问题先看哪里

现象 先看
客户端加载失败 构建详情里的校验错误;server/app/compiler/validate.py
产物内容不对 构建详情的「预览产物」;render.py 的合并顺序
订阅 404 令牌被轮换或设备被删;server/app/routers/feed.py
测速结果不准 系统状态页的「测速链路」;容器代理变量
端口占用 / 启动失败 docker logs magicpanel --tail 50
定时任务没跑 自动构建发布页的开关与运行记录;scheduler.py