chore: initialize standalone business plugin repository
Business Plugins CI / check (plugin-admin) (push) Successful in 3m13s
Business Plugins CI / check (subscription-admin) (push) Successful in 1m41s

This commit is contained in:
Qiufeng
2026-08-27 23:36:08 +08:00
commit 5feae3ad41
59 changed files with 8950 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
# Sub2API Subscription Admin Business Plugin V1
这是一个独立运行的管理员只读业务插件,不是现有 `.s2plugin` transport 插件,也不是插件管理后台。它不导入 Sub2API `internal` 包,不连接 Core 数据库,也不修改 Core Go/Vue、迁移、路由或 `.s2plugin` ABI。
生产/集成环境由通用 `plugins/plugin-admin` 控制面安装、启用和升级本插件;本插件不会预装,也不会成为控制面首页。只有健康检查通过并由管理员执行菜单预览/应用后,Core 管理员菜单才会出现“订阅管理”入口。直接运行本目录仅用于本地开发和契约测试。
## 本地启动
```sh
CORE_BASE_URL=http://127.0.0.1:8080 \
PLUGIN_HOST=127.0.0.1 \
PLUGIN_PORT=8091 \
go run .
```
打开 `http://127.0.0.1:8091/admin/`。生产环境应通过 HTTPS 反向代理,并设置 `PLUGIN_COOKIE_SECURE=true`。挂载到子路径时同时设置 `PLUGIN_PUBLIC_BASE_PATH` 和 `PLUGIN_COOKIE_PATH`,例如 `/extensions/qiu.subscription-admin`。
## V1 范围
- Core 管理员账号登录和 Core 2FA;普通账号统一拒绝。
- 插件 HttpOnly、SameSite 会话和写请求 CSRF 校验。
- Core token 只保存在插件服务端内存会话中,不进入浏览器、URL、HTML、LocalStorage、响应或日志。
- 只读套餐、订阅列表、订阅详情和插件操作记录。
- Core access token 失效时最多刷新一次;刷新失败会销毁插件会话。
- 页面刷新会从插件会话恢复,并重新取得短期 CSRF token;服务端不会把 Core token 返回浏览器。
- 登录会读取 Core 公开验证码配置并透传 Turnstile、腾讯、阿里云或 GeeTest 的验证结果;验证码本身仍由 Core 校验。
- 余额购买、续费、撤销、退款和外部支付不在 V1,页面不渲染提交按钮。
## Core API allowlist
插件服务端仅调用这些明确路径:
```text
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
```
列表请求只接受 `page`、`page_size`、`limit`、`user_id`、`group_id`、`status`、`platform`、`sort_by`、`sort_order` 参数。插件不会代理任意 URL,也不会调用尚不存在的 `/api/v1/plugin-host/*`。
## Core 菜单与反向代理
控制面会依据清单中的菜单声明生成下面的 `custom_menu_items` 项;部署时无需手工写入订阅菜单:
```json
{
"id": "qiu.subscription-admin",
"label": "订阅管理",
"url": "https://CORE_ORIGIN/extensions/qiu.subscription-admin/",
"visibility": "admin",
"sort_order": 200
}
```
Core 自定义页面的 sandbox iframe 不会继承 Core `localStorage` 登录态,因此 V1 首屏显示插件登录页是预期行为;同时提供新窗口入口。不要把 JWT 放进 URL。
## 测试
```sh
go test ./... -count=1
node --check ui/app.js
```
`main_test.go` 覆盖 Core 路径 allowlist、查询参数过滤、管理员角色拒绝、插件 Cookie、Core token 不泄露、会话过期、请求 ID、登录限流和 2FA pending 一次性消费。浏览器验收脚本位于 `test/browser-check.mjs`,可使用本地 Mock Core 验证直连、子路径反代和三种视口。
## 生成可安装包
```sh
./package.sh
```
脚本生成 `dist/qiu.subscription-admin.s2plugin`,包内根文件名为
`manifest.json`,并包含清单声明哈希的 UI 文件。该插件采用外部服务模式:
安装后先独立启动 `subscription-admin`,再在 `plugin-admin` 的配置中填写
`service_url`(插件 loopback 地址)和 `public_url`(反向代理地址),然后执行
启用、健康检查和菜单应用。生产环境必须把签名文件通过
`SIGNATURE_FILE=/path/to/signature.json ./package.sh` 放入包内,并将对应公钥
加入控制面受信发布者配置;未签名包仅限 development + loopback。
## 清单和发布
`business-plugin-manifest.v1.json` 是部署层清单,不由 Core 读取。生产发布应由独立 CI 签名并校验清单、版本、健康路径和兼容的 Core 版本;不要把发布私钥放入仓库或插件包。插件版本独立于 `backend/cmd/server/VERSION`。
## 已知限制
- V1 使用内存会话,服务重启会要求重新登录;多实例部署需将会话存储替换为插件自有 Redis/共享会话服务。
- 现有 Core 自定义 iframe 没有 token handoff,V1 不提供无感 SSO;真正 SSO 需要单独的 V1.1 Core 交接接口。
- Core 当前套餐响应中的 `features` 可能是 JSON 字符串,UI 会兼容字符串和数组。
- Core 开启验证码时,管理员必须先完成对应提供商的挑战并将结果填入登录表单;插件不保存验证码票据。