Files
sub2api-add/docs/PLUGIN_FRAMEWORK_V1_RFC.md
T
Qiufeng 5feae3ad41
Business Plugins CI / check (plugin-admin) (push) Successful in 3m13s
Business Plugins CI / check (subscription-admin) (push) Successful in 1m41s
chore: initialize standalone business plugin repository
2026-08-27 23:36:08 +08:00

24 KiB
Raw Blame History

Sub2API 独立业务插件框架 V1 RFC

状态:V1 通用插件控制面参考实现已落库;订阅业务插件只读适配与 Core Host Adapter/写操作仍为 Draft

本文规划一种不改动 Sub2API 核心代码、数据库和现有插件 ABI 的独立业务插件框架。当前 V1 控制面参考实现位于 plugins/plugin-admin,它负责插件清单、签名、安装、启停、升级、回滚、卸载、配置、审计和菜单注入;控制面本身不是订阅后台。每个业务插件(包括独立的 plugins/subscription-admin)作为可选的独立服务运行在自己的端口,通过控制面安装后再由部署层反向代理和现有“管理员可见自定义菜单”嵌入 Sub2API 页面。插件登录直接调用 Core 的现有鉴权,普通账号没有访问权限,也不复制 Core 用户表。

V1 已实现范围以 plugins/plugin-admin 控制面和本文“当前实现范围”章节为准;本文中的订阅业务插件只是首个适配样例。Core Host Adapter、短时 Plugin Access Token、无感 SSO 和余额写操作仍是后续版本设计,不代表当前 Core 已提供这些接口。

本文不是现有 .s2plugin 协议的直接改版。现有 .s2plugin 继续只负责 openai.oauth.outbound_transport.v1。本 RFC 的 V1 是部署级业务插件约定,不向当前 Core 增加新的路由、数据表或业务 RPC。

0. 约束与可行性边界

本版本必须同时满足以下约束:

  • 不修改 Sub2API 的 Go、Vue、数据库迁移和现有鉴权实现;
  • 不在插件内建立 Core 用户表,管理员身份以 Core 现有账号和角色为准;
  • 插件后端独立监听 PLUGIN_PORT,由 Nginx/Caddy/Traefik 等部署层转发;
  • 通过 Core 已有 custom_menu_items 配置添加 visibility=admin 的 iframe 菜单入口;
  • 插件只在服务端调用 Core 现有 API,浏览器不持有 x-api-key 或 Core JWT;
  • 第一阶段只搭框架、登录、权限、健康检查、嵌入和只读联调,不实现订阅购买写操作。

现有自定义菜单可以完成“把插件页面显示在 Sub2API 管理页面内”,但现有 iframe 使用 sandbox,且 Core 前端 JWT 保存在 localStorage,不会自动注入跨端口 iframe。因此在完全不改 Core 的前提下,V1 的登录方式是:插件登录页把凭据转交给插件后端,插件后端调用 Core 现有登录和二次验证接口,确认 role=admin 后只保留短时插件会话及服务端 Core token;这复用同一套 Core 用户和角色,不复制用户表,但不是无感知的当前页面会话共享。

如果以后要求“已登录 Core 后打开 iframe 立即无感登录”,需要一个很小的 Core 一次性登录交接接口或前端 postMessage 适配;这属于 V1.1,不应通过 URL 明文传递 JWT。反向代理只改变网络路径,不改变这一认证边界。

1. 决策摘要

1.1 推荐拓扑

管理员浏览器
      │ Core 页面中的 admin 自定义菜单
      ▼
Core `/custom/PLUGIN_ID`
      │ 现有 sandbox iframe;只加载插件 UI,不共享 Core 存储
      ▼
反向代理 `/extensions/PLUGIN_ID/*`
      │ 转发到独立服务 `127.0.0.1:PLUGIN_PORT`
      ▼
业务插件后台
  ├─ `/login` 接收管理员登录请求
  ├─ 服务端调用 Core `/api/v1/auth/login`(需要时调用 `/login/2fa`)
  ├─ 调用 Core `/api/v1/auth/me`,确认 `role=admin`
  ├─ 建立插件 HttpOnly 会话,Core access/refresh token 只在服务端保存
  └─ 通过 Bearer Core JWT 调用现有 Core Admin API
      ▼
Sub2API Core 现有认证、Admin API 和订阅/余额账本

插件后台是独立服务,不以高权限子进程形式嵌入核心,也不直接连接核心数据库。V1 通过部署层完成端口映射,通过 Core 现有登录/2FA、/auth/me 和 Admin API 完成功能联调;浏览器永远不接触 Admin Key,也不接触 Core JWT。插件后端不建立用户表,只维护短期会话(单实例可使用内存,多实例可使用插件自己的 Redis/会话存储)。这里的前提是插件属于受信任的内部服务:登录密码会在一次请求中经过插件后端再转交 Core,但不落库、不写日志;若要求插件进程也完全接触不到密码,需要另行引入 Core SSO/OIDC。

如果部署环境只允许服务到服务调用,也可以把 Core Admin API Key 放在插件后端 secret 中作为临时 BFF 凭据;这时所有命令都以该 Key 对应的管理员身份执行,属于单一服务身份模式,不等同于当前浏览器管理员的 SSO,也不替代 V1 的管理员登录方案。

1.2 V1 的默认范围

  • 插件拥有独立后台和独立发布版本。
  • 只允许管理员登录;普通用户访问插件后台一律拒绝。
  • 首版支持管理员登录、权限校验、健康检查、嵌入和只读订阅数据展示。
  • 余额购买命令暂不实现,待框架验收后再复用现有订阅逻辑设计原子入口。
  • 现有 .s2plugin 传输插件 ABI、路由和生命周期保持不变。
  • 不实现插件任意注册核心路由、任意执行 SQL、任意读取宿主 Cookie、任意注入 Vue 路由或任意修改 Core 菜单组件。

2. 为什么不复用现有 .s2plugin

现有插件协议的能力是 GetInfo、Health、配置读写、配置测试和 Forward HTTP 流。它的清单只接受 openai.oauth.outbound_transport.v1,UI 也只是无管理员 Token 的配置 iframe。

因此它不适合安全承载以下业务:

  • 管理员登录和角色授权;
  • 订阅商品、余额购买和订单审计;
  • 核心数据库事务或迁移;
  • 用户页面、菜单、任意 HTTP 路由和支付/订阅回调。

如果把这些能力硬塞入现有协议,就会同时改变进程 ABI、权限模型、数据库边界和前端路由,反而扩大与上游的冲突面。V1 采用“外部业务插件 + Core 现有 API 适配器”作为清晰的新边界;需要 Core 新增接口的部分另列为 V1.1。

3. 术语和边界

术语 定义
Core Sub2API 主服务,拥有用户、余额、Group、Key、订阅和用量账本。
Business Plugin 独立部署的后台服务,提供一个业务域的管理 UI 和 BFF。
Plugin UI 由 Business Plugin 提供的页面,只调用自己的后端。
Plugin Backend Business Plugin 的服务端,保存插件配置、会话和操作幂等记录。
Core API Adapter V1 插件后端对 Core 现有 REST API 的服务端客户端,只允许访问明确的认证、管理员和只读业务端点。
Future Host Adapter V1.1 以后、需要修改 Core 才能提供的版本化业务 API;不属于本次无 Core 改动的实现范围。
Plugin Session Credential 插件自己的 HttpOnly 会话标识,不等于 Core JWT 或全局 Admin Key。
Capability 插件声明的业务能力,例如 subscription.admin.v1。
Projection 插件保存的只读或可重建副本,不是核心账本的权威数据。

4. 认证与权限模型

4.1 管理员登录

V1 采用“插件会话 + Core 现有登录”的两层模型,不创建插件用户表:

  1. 浏览器打开插件 /login,只向插件后端提交 Core 管理员凭据和必要的 2FA 信息。
  2. 插件后端服务端调用 Core POST /api/v1/auth/login;需要二次验证时继续调用 POST /api/v1/auth/login/2fa。
  3. 插件后端用返回的 Core access token 调用 GET /api/v1/auth/me,确认用户状态正常且 role=admin。
  4. 插件后端建立自己的短时 HttpOnly 会话;Core access/refresh token 只保存在插件服务端的会话存储中,不回传浏览器。
  5. 插件业务请求只携带插件会话 Cookie,插件后端再用对应管理员的 Core Bearer token 调用允许的 Core API。
浏览器 -> Plugin /login(插件会话 Cookie 尚未建立)
Plugin -> Core /api/v1/auth/login
Plugin -> Core /api/v1/auth/login/2fa(按 Core 返回的要求)
Plugin -> Core /api/v1/auth/me(确认 role=admin)
Plugin <- 建立 HttpOnly 插件会话
浏览器 -> Plugin /admin/*(只带插件会话 Cookie)
Plugin -> Core /api/v1/admin/*(只在服务端带 Bearer Core JWT)

这不是独立账号,也不是把 Core 用户复制到插件;密码只用于一次 Core 登录请求,插件不落库。插件会话可使用内存存储;多实例部署时使用插件自己的 Redis/会话存储,不连接 Core 数据库。Core 继续负责密码、2FA、限流、TokenVersion、撤销和管理员角色校验。

当前 Core 没有给自定义 iframe 提供 token handoff,因此“Core 已登录后打开 iframe 自动登录”不属于 V1。V1 允许在 iframe 内显示插件登录页;由于 sandbox/第三方 Cookie 策略可能让嵌入会话在刷新后失效,插件必须提供“新窗口打开插件”入口作为稳定登录路径。以后如需真正无感 SSO,另行设计一次性 code + state 或 postMessage 交接机制,JWT 不应放在 URL。

4.2 权限判定

  • 默认拒绝所有普通用户、未登录用户和过期会话。
  • 插件会话只包含 plugin_id、admin_user_id、角色、权限版本、签发时间和过期时间。
  • V1 只定义 plugin_admin 角色;后续可增加 subscription_operator、subscription_readonly。
  • 插件后端每次命令都携带对应 Core 管理员的 Bearer token,不使用“系统管理员”固定身份代替实际操作者(仅使用临时 Admin Key 的过渡模式除外)。
  • Core 对每个现有 Admin API 操作再次做管理员角色、会话撤销和资源级授权,不把插件 UI 的按钮隐藏当作授权依据。
  • 所有写操作要求 CSRF 防护、审计记录和幂等键;敏感操作可要求 step-up。

4.3 会话要求

  • 会话 Cookie 必须 HttpOnly、Secure、SameSite=Lax 或更严格。
  • 生产环境只允许 HTTPS;反向代理必须正确传递原始 Host 和协议。
  • 登录使用短时一次性 state,绑定浏览器会话并防重放。
  • 默认会话有效期 30 分钟,滑动续期上限 8 小时;登出立即撤销服务端会话。
  • 独立 origin 嵌入时按浏览器策略使用 SameSite=None; Secure,同源反代优先使用 Lax;必须在目标浏览器验证刷新、退出和第三方 Cookie 行为。
  • 插件 UI 不把 Core JWT、Admin Key 或服务凭据写入 LocalStorage、URL、HTML、日志或错误提示。

5. Admin Key 与服务凭据安全

5.1 绝对禁止的做法

  • 不把全局 x-api-key 注入浏览器。
  • 不把 Admin Key 放进插件静态 JS、HTML、iframe、URL query、下载文件或前端 sourcemap。
  • 不让插件 UI 直接请求 Core Admin API。
  • 不把 Admin Key 写入普通业务日志、请求追踪、错误响应、数据库明文或备份导出。
  • 不让插件直接连接 Core PostgreSQL、Redis 或宿主文件目录。

5.2 V1 凭据分级

环境 凭据 用途 约束
开发 Core 管理员的临时登录凭据 调用 Core /auth/login 联调 只由开发者输入到插件登录页,不写入代码、配置和日志。
测试 Core 返回的 access/refresh token 建立插件服务端会话 只存插件服务端会话存储,短 TTL,测试 Core 与测试管理员专用。
生产 Core 返回的 access/refresh token 代表实际登录的 Core 管理员调用现有 Admin API 服务端加密保存或内存保存,按 Core TokenVersion/撤销结果失效;不回传浏览器。

V1 不要求新增 Plugin Access Token 服务,也不要求修改 Core。ADMIN_API_KEY 只作为服务到服务 BFF 的应急/测试凭据:它必须只存在插件后端 secret manager、受限环境变量或权限为 0600 的 secret 文件中,并由 Core Admin API 的 endpoint allowlist 限制。使用 Admin Key 时所有请求都以同一个管理员身份执行,审计粒度是服务身份级别,不得作为插件登录态下发给浏览器。

V1.1 如需在不保存 Core refresh token 的情况下运行,再设计 Core 签发的短时、限 scope Plugin Access Token;在 Core 提供该能力前,文档只把它视为未来接口。

5.3 凭据生命周期

  1. 插件后端接收管理员登录请求,但不保存密码。
  2. 插件后端调用 Core 登录/2FA,保存返回 token 到服务端会话,并绑定 admin_user_id。
  3. 每次 Core 请求都使用 TLS 和 Core Bearer token;Core 继续校验签名、TokenVersion、会话绑定和角色。
  4. access token 过期时只使用对应 refresh token 调用 Core /auth/refresh;刷新失败就销毁插件会话并要求重新登录。
  5. 登出、Core 管理员撤销会话、停用插件或发现泄露时,立即删除插件会话;Admin Key 过渡模式由运维轮换并撤销。

5.4 服务端防护

  • Core 现有 Admin API 由自身 adminAuth、JWT 会话和管理员角色保护;插件后端再使用出站 allowlist,只能访问事先批准的 Core API 路径。
  • 插件后端不接受任意 URL 转发,也不把 Core API 代理能力暴露给插件 UI。
  • 请求设置超时、重试上限和熔断;禁止在超时后盲目重放非幂等命令。
  • 日志对 Authorization、x-api-key、Cookie、session、余额和个人信息做结构化脱敏。
  • 记录 plugin_id、操作者、scope、资源 ID、幂等键和结果,不记录 secret 原文。
  • 生产插件运行在独立低权限账号或容器中,限制文件、网络、系统调用和环境变量。

6. Core API Adapter V1(使用现有接口)

本节描述在“不修改 Sub2API”前提下插件可以使用的最小集成面。它不是 Core 已注册的插件协议,而是插件后端对现有 HTTP API 的严格 allowlist;实现前应根据目标版本在插件配置中冻结路径和响应字段。

6.1 认证头

Authorization: Bearer CORE_ACCESS_TOKEN
X-Request-Id: UNIQUE_REQUEST_ID

CORE_ACCESS_TOKEN 只允许由插件后端的会话适配器发送。插件浏览器、静态资源和 iframe 消息中不得出现该 token。

6.2 V1 允许的接口类别

POST /api/v1/auth/login
POST /api/v1/auth/login/2fa
POST /api/v1/auth/refresh
POST /api/v1/auth/logout
GET  /api/v1/auth/me
GET  /api/v1/settings/public
GET  /api/v1/admin/payment/plans
GET  /api/v1/admin/subscriptions
GET  /api/v1/admin/subscriptions/{id}
GET  /api/v1/admin/users/{id}
GET  /api/v1/admin/users/{id}/subscriptions

实际插件先只开放只读管理员接口;不得把路径中的 <read-only-endpoint> 当作通配符,部署配置必须列出具体路径、方法和分页上限。现有 Core 没有 /api/v1/plugin-host/* 路由,V1 不调用或宣称该路径已存在。

6.3 V1 写操作边界

V1 框架和第一版订阅插件不实现余额扣款、订阅续期或撤销写操作。现有 Admin API 的多个调用不应拼成一笔购买,因为这样无法保证余额、订单、订阅和审计的单事务一致性。

未来要支持写操作,必须先在 Core 中增加版本化 Host Adapter 或等价的原子命令接口(需要 Core 代码、路由、审计和幂等存储变更),再由插件接入;这属于 V1.1,不是本轮“零 Core 改动”的交付物。

6.4 错误和重试

HTTP 含义 插件行为
401 凭据无效或已撤销 停止重试,提示重新注册/轮换。
403 管理员角色、会话或资源权限不足 不重试,记录操作者和资源。
409 幂等键冲突或业务状态冲突 查询 operation 状态后展示最终结果。
422 参数或余额业务校验失败 展示可读错误,不重试。
429 Core 限流 按 Retry-After 有上限地重试。
5xx Core 暂时故障 只对明确幂等命令重试,指数退避。

7. 插件注册、清单与生命周期

7.1 与 .s2plugin 分离

Business Plugin V1 不直接套用现有 manifest.schema.json。建议新增独立的业务插件清单,例如 business-plugin-manifest.v1.json:

{
  "schema_version": 1,
  "plugin_id": "example.subscription",
  "name": "Example Subscription Admin",
  "version": "0.1.0",
  "core_api_baseline": "sub2api-0.1.183",
  "capabilities": ["subscription.admin.v1"],
  "tested_core_versions": ["0.1.183"],
  "backend": { "health_path": "/healthz" },
  "ui": { "entrypoint": "/admin" },
  "publisher": { "key_id": "publisher-key-id" }
}

清单只声明能力和兼容范围,不授予数据库、路由或 secret 权限。V1 由部署脚本/反向代理保存清单、校验签名和允许的 Core API 路径;当前 Core 不会读取该清单,也没有业务插件注册表。插件发布包/容器镜像仍应签名,但签名验证属于部署门禁,不应写成现有 Core 能力。

7.2 状态机

registered -> disabled -> enabled -> draining -> disabled
     │           │          │
     └────── incompatible   └── error
  • registered:部署层已登记清单和发布者,但未启用。
  • disabled:服务存在但不接收业务请求。
  • enabled:健康检查通过,允许插件后端调用列入 allowlist 的 Core API。
  • draining:停止接收新命令,等待进行中的幂等命令完成。
  • error:健康检查或 Core API 合约校验失败,默认 fail-closed。
  • incompatible:插件清单或 Core API 版本不兼容,不允许启用。

7.3 升级和回滚

  • 插件版本独立于 backend/cmd/server/VERSION 和 frontend/package.json。
  • 升级前先执行健康检查、现有 Core API contract test 和插件自身数据备份检查。
  • 新版本不兼容时保持旧版本运行,不自动覆盖正在启用的实例。
  • 停用时等待进行中的命令完成;超过 drain 超时则拒绝新命令并标记待恢复。
  • 插件卸载不删除 Core 订阅、余额和审计数据。

8. 数据归属

8.1 Core 权威数据

  • 用户身份和管理员授权;
  • 余额账本;
  • 套餐价格、额度、覆盖 Group 和购买快照;
  • 用户订阅状态、期限、配额和 reserved;
  • 余额扣减、订阅创建/续期、撤销和审计;
  • 请求计费、额度预留、结算和幂等。

8.2 Plugin 可拥有的数据

  • 插件管理员会话和本地角色映射;
  • 插件 UI 偏好、筛选条件和缓存;
  • Core API operation 的本地查询索引;
  • 供应商或业务侧的非权威展示配置。

插件数据库中的订阅副本必须可删除、可重建、带来源版本和更新时间。它不作为网关放行请求的依据。

9. 前端和菜单集成

V1 通过现有的管理员自定义菜单嵌入,不修改 Core 前端路由:

Core 设置 -> custom_menu_items
  id: example.subscription
  visibility: admin
  url: https://PLUGIN_ORIGIN/extensions/example.subscription/

Core `/custom/example.subscription`
  └── sandbox iframe -> 反向代理 -> `127.0.0.1:PLUGIN_PORT`

visibility=admin 只负责隐藏普通账号的菜单入口,插件后端仍必须独立鉴权。现有 iframe 的 sandbox、跨端口 origin 和 Core JWT localStorage 使其不会自动共享 Core 登录态;因此 iframe 首屏显示插件登录页是 V1 的预期行为。插件也应提供“新窗口打开”,便于登录后保持自身会话。

生产部署建议把插件外部地址挂在与 Core 相同的 HTTPS 站点下,由 Nginx/Caddy 按路径反代到独立端口;这只减少浏览器跨域问题,不改变插件必须登录和服务端调用 Core 的事实。若使用独立 origin,必须在 Core CORS 中精确加入该 origin,禁止 *,并仅允许必要的 Authorization 请求头。

插件页面只调用自己的 /plugin-api/*,由插件后端调用 Core 现有认证和管理员 API。V1 不允许插件动态注入主应用 Vue 路由、修改核心菜单组件或覆盖全局 CSS;主应用只提供一个受权限控制的“业务插件”入口,插件内部菜单由插件自己管理。

10. 威胁模型与处置

威胁 V1 处置
XSS 窃取 Admin Key 浏览器永远没有 Admin Key;Cookie HttpOnly;CSP 和输出编码。
插件前端伪造管理员命令 插件后端重新验证插件会话;Core 重新验证 Bearer token、管理员角色、操作者和资源权限。
插件后端日志泄露 secret 统一日志脱敏,禁止记录 Authorization 和完整请求。
插件服务被攻破 限制 Token scope、TTL、出站地址和 Core API;立即撤销凭据。
重放余额购买 Idempotency-Key + Core 事务记录 + 请求时间/nonce。
CSRF SameSite Cookie、CSRF token、Origin/Referer 校验。
SSRF 插件出站 allowlist;Core 现有 API 不接受任意 URL。
普通用户进入后台 插件登录调用 Core /auth/me 并要求 role=admin;所有插件路由默认 deny。
多实例状态漂移 Core 是权威;插件状态通过健康检查和配置版本对齐。
插件卸载误删订阅 插件没有删除 Core 账本的权限,卸载只撤销凭据。

必须明确:独立插件进程不是操作系统级沙箱,签名只证明发布者和完整性,不证明代码无漏洞。生产部署仍需要低权限运行、网络隔离和可撤销凭据。

11. 测试门禁

11.1 Core API Adapter 合约测试

  • Core 登录、/login/2fa、/auth/me、access/refresh 过期和撤销;
  • 普通用户、停用用户、无效会话和跨插件会话均返回 403;
  • 只读 Admin API 的字段脱敏、分页上限和资源权限;
  • Core 超时、401/403/429/5xx、刷新 token 和重新登录;
  • V1 明确没有 /api/v1/plugin-host/*,测试不能把未来接口当成现有接口。

11.2 插件后端测试

  • Core 登录代理、2FA、会话过期、登出和 CSRF;
  • Core access/refresh token 不进入响应、页面、日志和异常堆栈;
  • Core 401/403/429/5xx 的处理和刷新失败后的重新登录;
  • 只允许配置中列出的 Core API endpoint;
  • 插件服务重启后会话失效或从插件自己的会话存储恢复,不能依赖 Core 用户表。

11.3 浏览器和部署测试

  • 管理员可登录,普通用户无法登录或访问任何后台 API;
  • 不同屏幕下页面无横向泄露和敏感字段;
  • 浏览器 DevTools 的请求、下载和页面源中没有 Admin Key;
  • HTTPS、反向代理、容器低权限、secret 文件权限和日志脱敏;
  • 停用、升级、回滚、凭据撤销后所有写操作按预期失败。

12. 分阶段实施计划(不含本次代码)

Phase 0:冻结部署契约

  • 选择外部服务部署方式(推荐同源反向代理 + 独立服务);
  • 冻结插件端口、反向代理路径、custom_menu_items 字段和健康检查;
  • 冻结允许调用的现有 Core API 路径、字段、分页和错误处理;
  • 明确插件登录通过 Core /auth/login//login/2fa,不创建用户表;
  • 建立 Core token 会话销毁、Admin Key 过渡和日志脱敏方案。

Phase 1:框架最小实现

  • 独立服务目录、清单、发布者签名和部署兼容性检查;
  • Plugin Backend 管理员登录和会话;
  • Core access/refresh token 服务端会话适配器;
  • 插件健康检查、启停、操作审计和同源入口;
  • Core API allowlist、contract test 与本地示例插件。

Phase 2:订阅插件试验

  • 只读套餐、用户余额和订阅列表;
  • 管理员操作页面、查询缓存和审计;
  • 使用测试 Core 和测试账户,不连接生产余额;
  • 余额购买、续费和撤销暂不实现,等待 Core 原子接口冻结。

Phase 3:生产准备

  • 未来 Core Host Adapter/短时 Plugin Access Token(若确认需要 Core 改动);
  • step-up、密钥轮换和撤销;
  • 多实例、备份恢复、升级回滚和故障演练;
  • 通过安全、契约、浏览器和并发门禁后再启用。

13. 待确认事项

以下事项在写代码前必须确定:

  1. V1 的订阅插件只允许管理员操作;普通用户购买页不纳入本框架首版。
  2. 管理员登录是否按本文通过 Core /auth/login 和 /login/2fa 完成;确认不创建插件用户表。
  3. 插件采用独立服务端口 + 同源反向代理,还是独立 origin;需确定生产网络拓扑。
  4. V1 是否允许测试环境使用服务端专用 Admin Key;生产默认不使用,除非接受单一管理员审计语义。
  5. 插件是否允许保存只读缓存;无论选择何种缓存,Core 必须始终是权威来源。
  6. V1.1 是否需要真正无感 SSO 和 Core Host Adapter;若需要,单独立项修改 Core。

在这些问题确认前,不应开始实现插件协议、数据库表或前端页面。