feat: complete unified plugin admin v1.1.0
This commit is contained in:
@@ -31,17 +31,69 @@ key). `PLUGIN_CONFIG_KEY` is required in every environment; use a randomly
|
||||
generated secret in production and keep it stable across restarts so encrypted
|
||||
plugin configuration remains decryptable.
|
||||
|
||||
When the optional subscription module is enabled, set `PLUGIN_PUBLIC_URL` to
|
||||
the externally reachable Plugin Admin base URL (without `/admin`), for example
|
||||
`https://CORE_ORIGIN/extensions/qiu.plugin-admin`. Menu apply then always emits
|
||||
`/admin/#/modules/subscription/overview`; a subscription service URL is never
|
||||
used as a browser entrypoint.
|
||||
|
||||
Open `/admin/` directly or expose the service through the reverse proxy in
|
||||
`deploy/`. The first login is the existing Core administrator login; no plugin
|
||||
user table is created. The control plane stores only a short-lived server-side
|
||||
session and encrypted plugin configuration.
|
||||
|
||||
The administrator UI is organized as separate hash-routed pages: overview,
|
||||
installed plugins, marketplace, and operations. Each plugin has its own detail
|
||||
route with secondary tabs for health, revisions, configuration, menu
|
||||
integration, and history. See
|
||||
[`../../docs/PLUGIN_ADMIN_UI_INFORMATION_ARCHITECTURE.md`](../../docs/PLUGIN_ADMIN_UI_INFORMATION_ARCHITECTURE.md)
|
||||
for the page responsibilities and responsive layout contract.
|
||||
|
||||
### TDesign UI build
|
||||
|
||||
The browser shell is a standalone Vue 3 application based on the Tencent
|
||||
TDesign Vue Next starter. It is built outside the Core repository and then
|
||||
embedded by this Go service:
|
||||
|
||||
```sh
|
||||
./build-ui.sh
|
||||
```
|
||||
|
||||
The command runs `npm ci`, type-checks the application, bundles TDesign Icons
|
||||
and ECharts locally (the service CSP does not allow a CDN), and copies the
|
||||
three runtime files into `ui/`. The generated shell keeps the existing
|
||||
`/login`, `/api/me`, CSRF and lifecycle contracts; no Core source or frontend
|
||||
build configuration is involved.
|
||||
|
||||
### 会话与令牌生命周期
|
||||
|
||||
插件进程是常驻服务,不会因为一次登录、一次请求或一次令牌刷新而重启。
|
||||
Core 的 access token 过期时,插件后端在当前请求链路中使用对应的 refresh
|
||||
token 刷新一次,并继续完成请求;刷新后的 token 仍只保存在插件服务端。
|
||||
浏览器始终只持有插件的 HttpOnly 会话 Cookie 和 CSRF token。
|
||||
|
||||
默认会话策略如下:
|
||||
|
||||
| 情况 | 行为 |
|
||||
| --- | --- |
|
||||
| 持续使用 | 每次请求滑动续期,通常无需重新登录 |
|
||||
| 空闲超过 30 分钟 | 插件会话失效,下一次访问回到登录页 |
|
||||
| 会话达到 8 小时 | 绝对过期,需要重新登录 |
|
||||
| Core access token 过期 | 后端透明 refresh,不重启插件 |
|
||||
| refresh token 被撤销/失效 | 清除插件会话并要求重新登录 |
|
||||
| 插件进程重启 | V1 内存会话清空,需要重新登录一次;已登记的插件由控制面按 registry 恢复 |
|
||||
|
||||
因此日常使用不需要“用完就重启”。生产多实例若需要跨实例或跨重启保留
|
||||
会话,应接入插件自己的加密 Redis/会话存储,并使用稳定的密钥;不要把
|
||||
Core token 写入浏览器、Core 数据库或 URL。
|
||||
|
||||
## Control-plane endpoints
|
||||
|
||||
```text
|
||||
GET /healthz
|
||||
GET /readyz
|
||||
POST /login POST /login/2fa POST /logout
|
||||
GET /api/captcha-config
|
||||
GET /api/marketplace POST /api/marketplace/install (JSON: plugin_id, version)
|
||||
GET /api/me GET /api/plugins GET /api/plugins/{id}
|
||||
POST /api/plugins/install (multipart field: package)
|
||||
@@ -53,6 +105,11 @@ GET|PUT /api/plugins/{id}/config
|
||||
POST /api/plugins/{id}/menu-preview|menu-apply
|
||||
POST /api/menu-items/preview|apply (JSON: {"plugin_id":"..."})
|
||||
GET /api/audit
|
||||
GET /api/subscription/status
|
||||
GET /api/subscription/audit
|
||||
GET /api/subscription/plans
|
||||
GET /api/subscription/subscriptions[/{id}]
|
||||
GET /api/subscription/users/{id}[/subscriptions]
|
||||
```
|
||||
|
||||
Every mutation requires the plugin CSRF token and an `Idempotency-Key`. A
|
||||
@@ -65,6 +122,13 @@ installs its runtime/menu. Failed installation and upgrade never replace the
|
||||
active revision. Delete/uninstall is allowed only after disable and removes
|
||||
plugin files, not Core data.
|
||||
|
||||
The login page reads only public CAPTCHA fields from `/api/captcha-config`.
|
||||
When Core enables Turnstile, Tencent Captcha, or Aliyun Captcha, the matching
|
||||
challenge is rendered in this page and its one-time proof is forwarded
|
||||
server-side to Core. Provider secrets are never returned. Keep the provider
|
||||
origins in the example CSP when CAPTCHA is enabled; changing the Core setting
|
||||
is picked up on the next login-page load and does not require a plugin restart.
|
||||
|
||||
## Marketplace catalog
|
||||
|
||||
The marketplace is server-side only. The browser receives metadata and sends a
|
||||
|
||||
Reference in New Issue
Block a user