53 KiB
KT Template Online API
本文是当前 API 的人工索引。字段细节、Swagger 示例和 DTO 以运行态 Swagger/Knife4j 为准:
- 全量 Swagger:
/api - OpenAPI JSON:
/api-json - Admin 分组:
/api/admin - QQBot 分组:
/api/qqbot - WordPress 分组:
/api/wordpress - 基础能力分组:
/api/basic
通用约定
后端固定监听 48085。根路径 GET / 重定向到 /api#/。
除文件下载、SSE、反向 WebSocket 等特殊接口外,业务接口统一返回:
{
"code": 200,
"msg": "操作成功",
"data": {}
}
错误响应统一把 err 输出为字符串:
{
"code": 400,
"msg": "操作失败",
"err": "错误原因"
}
认证
Admin、Component、Dict、MinIO、Blog 管理、WordPress 管理和 QQBot 管理接口默认需要后台登录态。
支持两种 access token 传递方式:
Authorization: Bearer <accessToken>- 登录接口写入的 httpOnly
admin_access_tokencookie
公开接口包括 /auth/login、/auth/refresh、/auth/logout、部分 Blog public 接口和根路径。具体以 Controller 上的 @Public() 为准。
ID 与时间
- 后台主键使用 Snowflake 数字 ID,接口按字符串返回,避免 JavaScript 长整型精度丢失。
- 后端格式化时间字段统一使用
KtDateTime extends Date:Entity 通过@KtDateTimeColumn(format)、@KtCreateDateColumn(format)、@KtUpdateDateColumn(format)在 TypeORM hydrate 边界转换;DTO/外部数据源通过@KtDateTimeField(format)+transformKtDateTimeFields()转换。默认输出YYYY-MM-DD HH:mm:ss,可在装饰器中传入格式字符串;响应包装不做递归遍历。 POST */save默认会删除请求体里的id,防止新增接口误用前端主键。
Runtime Health
| 方法 | 路径 | 认证 | 说明 |
|---|---|---|---|
GET |
/health/runtime |
否 | API 运行时健康和配置检查状态 |
该接口返回 plain JSON,不使用 Vben 响应包装,供本地 smoke、Jenkins/K8s 和 ktWorkflow 观测脚本直接读取。接口位于 Swagger 基础能力分组 /api/basic。
顶层字段:
| 字段 | 说明 |
|---|---|
service |
固定为 kt-template-online-api |
checkedAt |
ISO 时间字符串 |
status |
live、ready、degraded 或 blocked |
checks |
进程和配置检查列表 |
公开响应不返回数据库、WordPress、Loki、NapCat SSH 等运行拓扑配置快照;配置检查只暴露 key 级别、是否存在和缺失说明。
状态含义:
live:NestJS 进程能响应健康请求。ready:关键配置存在,当前检查未发现缺失项。degraded:可选运行时配置缺失,核心 API 可继续工作。blocked:关键运行时配置缺失,不能声明部署或运行态成功。
Admin Environment Dashboard
| 方法 | 路径 | 认证 | 说明 |
|---|---|---|---|
GET |
/system/environment/dashboard |
是 | 返回 local-dev、NAS 线上、腾讯云、r4se 环境快照 |
POST |
/system/environment/self-check |
是 | 触发只读自检并返回最新环境快照 |
GET |
/system/environment/events/stream |
是 | SSE 推送后端环境事件,支持 lastEventId 查询参数 |
环境总览接口使用 Site -> Node -> Service -> Signal 模型聚合状态,unwired 表示只读观测尚未配置,unknown 表示已知入口但缺少新鲜证据。Admin 首次加载通过 HTTP 获取快照,后续通过 API SSE 接收 local/MQTT 事件;前端不直接连接 MQTT,也不使用定时轮询。
当前版本只提供观测和只读自检。重启 Pod、触发 Jenkins 部署、执行迁移、重建 NapCat 容器、启停插件、立即执行插件任务、修改 Caddy/OpenClash/WireGuard/Tencent Cloud 等高风险能力只会以禁用动作展示,后端不提供通用写动作入口。
环境变量分组
| 分组 | 关键变量 |
|---|---|
| MySQL | DB_HOST、DB_PORT、DB_USERNAME、DB_PASSWORD、DB_DATABASE、DB_SYNC |
| MinIO | MINIO_ENDPOINT、MINIO_PORT、MINIO_ACCESS_KEY、MINIO_SECRET_KEY、MINIO_BUCKET |
| Admin | ADMIN_TOKEN_SECRET、ADMIN_COOKIE_SECURE、SNOWFLAKE_WORKER_ID、SNOWFLAKE_DATACENTER_ID |
| WordPress | WORDPRESS_BASE_URL、WORDPRESS_HOST_HEADER、WORDPRESS_ADMIN_USERNAME、WORDPRESS_ADMIN_PASSWORD |
| Loki | LOG_LEVEL、LOG_APP_NAME、LOKI_URL、LOKI_QUERY_HOST、LOKI_QUERY_SELECTOR |
| QQBot | QQBOT_ENABLED、QQBOT_ACCOUNT_SECRET_KEY、QQBOT_REVERSE_WS_PATH、QQBOT_REVERSE_WS_TOKEN、QQBOT_EVENT_BUS、QQBOT_SEND_*、QQBOT_PLUGIN_QUEUE_REDIS_*、QQBOT_PLUGIN_TASK_QUEUE_REDIS_*、QQBOT_PLUGIN_QUEUE_WAIT_TIMEOUT_MS、QQBOT_COMMAND_MIN_COOLDOWN_MS、QQBOT_RULE_MIN_COOLDOWN_MS、QQBOT_REPEATER_* |
| NapCat | NAPCAT_WEBUI_BASE_URL、NAPCAT_WEBUI_TOKEN、QQBOT_NAPCAT_* |
| MQTT | MQTT_URL、MQTT_USERNAME、MQTT_PASSWORD、MQTT_CLIENT_ID |
| Env Dashboard | ENV_DASHBOARD_CACHE_TTL_MS、ENV_DASHBOARD_SIGNAL_TIMEOUT_MS、ENV_DASHBOARD_EVENT_BUS、ENV_DASHBOARD_MQTT_*、ENV_DASHBOARD_SSE_*、ENV_DASHBOARD_JENKINS_*、ENV_DASHBOARD_K8S_*、ENV_DASHBOARD_TENCENT_*、ENV_DASHBOARD_CADDY_*、ENV_DASHBOARD_R4SE_* |
| BangDream | BANGDREAM_TSUGU_MAIN_SERVER、BANGDREAM_TSUGU_DISPLAYED_SERVERS、BANGDREAM_TSUGU_CACHE_ROOT |
| FF14 Market | FF14_XIVAPI_BASE_URL、FF14_UNIVERSALIS_BASE_URL、FF14_DEFAULT_WORLD |
| FFLogs | FFLOGS_GRAPHQL_URL、FFLOGS_TOKEN_URL、FFLOGS_CLIENT_ID、FFLOGS_CLIENT_SECRET |
真实密码、Token、OAuth secret 和生产 env 不提交到 Git。
Env Dashboard 的 ENV_DASHBOARD_ADMIN_LOCAL_URL / ENV_DASHBOARD_ADMIN_PUBLIC_URL 只作为 Admin 入口展示证据;Jenkins、K8s、Tencent Cloud、Caddy、WireGuard、Mihomo/OpenClash 仍通过对应 ENV_DASHBOARD_* 只读配置接入,缺失配置必须返回 unwired 证据。
QQBot 插件 worker 队列依赖 Redis。K8s 生产清单提供内部 Redis Service kt-qqbot-plugin-redis:6379,用于 QQBOT_PLUGIN_QUEUE_REDIS_HOST / QQBOT_PLUGIN_QUEUE_REDIS_PORT。QQBOT_PLUGIN_QUEUE_WAIT_TIMEOUT_MS 控制串行队列的排队等待窗口,避免排队时间挤占插件操作本身的 timeoutMs 执行预算。插件定时任务可通过 QQBOT_PLUGIN_TASK_QUEUE_REDIS_* 使用独立 BullMQ prefix;未配置 host 时复用插件 worker Redis 连接。
Admin 与基础后台
Auth / User
| 方法 | 路径 | 说明 |
|---|---|---|
POST |
/auth/login |
后台登录,返回 accessToken、用户信息和 WordPress 自动登录状态,并写入 httpOnly cookie |
POST |
/auth/refresh |
通过 refresh token cookie 刷新 accessToken |
POST |
/auth/logout |
清理 Admin 与 WordPress 登录 cookie |
GET |
/auth/codes |
获取当前用户按钮权限码 |
GET |
/user/info |
获取当前用户信息 |
/auth/login 会尝试用 env 中的 WordPress 管理员账号建立 WordPress 登录态。WordPress 不可用时,Admin 主登录仍成功,返回 wordpressAuth=null、wordpressAvailable=false,菜单和权限码会过滤 Blog 管理入口。
Menu / Role / Dept / User Manage
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/menu/all |
当前用户菜单 |
GET |
/system/menu/list |
系统菜单树 |
GET |
/system/menu/name-exists |
菜单 name 重名校验 |
GET |
/system/menu/path-exists |
菜单 path 重名校验 |
POST |
/system/menu |
新增菜单 |
PUT |
/system/menu/:id |
更新菜单 |
DELETE |
/system/menu/:id |
删除菜单及子菜单 |
GET |
/system/role/list |
角色分页 |
POST |
/system/role |
新增角色 |
PUT |
/system/role/:id |
更新角色 |
DELETE |
/system/role/:id |
删除角色 |
GET |
/system/dept/list |
部门树 |
POST |
/system/dept |
新增部门 |
PUT |
/system/dept/:id |
更新部门 |
DELETE |
/system/dept/:id |
删除部门 |
GET |
/system/user/list |
用户分页 |
POST |
/system/user |
新增用户 |
PUT |
/system/user/:id |
更新用户 |
DELETE |
/system/user/:id |
删除用户 |
Dict
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/dict/list |
字典项分页,支持 dictCode、keyword、label、value、childrenCode、status |
GET |
/dict/tree |
兼容树形字典视图 |
GET |
/dict/groups |
字典编码分组列表,适合左右表左侧分组 |
GET |
/dict/codes |
字典编码选项 |
GET |
/dict/getDictByKey |
按 dictKey 获取启用字典项 |
GET |
/dict/getComponentDictByType |
按组件一级类型查二级类型 |
POST |
/dict/save |
新增字典项 |
POST |
/dict/update |
更新字典项 |
DELETE |
/dict/:id |
物理删除字典项 |
POST |
/dict/toggle |
启停字典项 |
字典核心字段:
| 字段 | 说明 |
|---|---|
dictCode |
字典分组,例如 COMPONENT_TYPE、BANGDREAM_SERVER_ALIAS |
label |
展示文本 |
value |
字典值 |
childrenCode |
关联子分组编码 |
sort |
排序 |
status |
1 启用 |
Component
组件接口保持 /component/* 路径兼容,但数据表为 admin_component。
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/component/allList |
全量组件 |
GET |
/component/list |
组件分页,支持 pageNo、pageSize、name、type、componentType |
GET |
/component/detail?id= |
组件详情 |
POST |
/component/save |
新增组件 |
POST |
/component/update |
更新组件 |
POST |
/component/remove?id= |
逻辑删除组件 |
Timezone / Upload / Demo
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/timezone/getTimezoneOptions |
时区选项 |
GET |
/timezone/getTimezone |
当前用户时区 |
POST |
/timezone/setTimezone |
设置当前用户时区 |
POST |
/upload |
Vben 上传适配,实际写入 MinIO |
GET |
/table/list |
Vben 示例表格 |
GET |
/status |
状态码测试 |
GET |
/demo/bigint |
BigInt JSON 测试 |
GET |
/test |
GET 测试 |
POST |
/test |
POST 测试 |
系统日志
后端通过 nestjs-pino 输出结构化日志。配置 Loki 后,Admin 日志页面通过后端代理查询,不直连 Loki。
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/system/logs |
日志分页,支持 level、keyword、context、path、requestId、startTime、endTime、rangeMinutes |
GET |
/system/logs/summary |
按级别统计 |
GET |
/system/logs/levels |
日志级别选项 |
GET |
/system/logs/status |
Loki 查询配置状态 |
日志行包含 timestamp、level、message、method、path、statusCode、durationMs、requestId、raw 等字段。
系统站内信
站内信用于承接运行期事件,不再作为人工公告入口。后端在接口 5xx、QQBot OneBot 下线 notice、NapCat 容器日志检测到账户离线时自动生成或聚合一条通知,默认通知 super 角色;站内信接口在服务端也强制 super 角色访问。相同 dedupeKey 的事件通过 active_dedupe_key 唯一索引聚合,会累加 occurrenceCount,刷新 lastSeenAt,并把状态重新置为未处理。运行期通知会按表字段长度归一化 title、dedupeKey、source、eventType 和 notifyRoleCode,长 dedupeKey 会保留稳定 hash 后缀,避免长路径接口错误丢通知。
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/system/notice/list |
日志级站内信分页列表,支持 keyword、severity、source、eventType、status、isTop、notifyRoleCode、notifyUsers、pageNo、pageSize |
GET |
/system/notice/detail/:id |
查询站内信详情 |
DELETE |
/system/notice/:id |
删除站内信(逻辑删除) |
POST |
/system/notice/toggle |
标记处理或重新打开(id、status,1 未处理,0 已处理) |
POST |
/system/notice/top |
切换置顶(id、isTop) |
返回字段包含 severity、source、eventType、dedupeKey、occurrenceCount、notifyRoleCode、metadata、firstSeenAt、lastSeenAt。后端不暴露人工 save/update 入口。
Blog 本地内容
/blog/* 是本地博客内容能力,供 Vue/kt-blog-web 和 Admin 博客管理使用。
Blog Article
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/blog/article/public/list |
公开文章分页 |
GET |
/blog/article/public/detail |
公开文章详情,支持 id/slug |
GET |
/blog/article/list |
后台文章分页 |
GET |
/blog/article/detail |
后台文章详情 |
POST |
/blog/article/save |
新增文章 |
POST |
/blog/article/update |
更新文章 |
POST |
/blog/article/remove |
删除文章 |
GET |
/blog/article/category-options |
文章分类选项 |
GET |
/blog/article/tag-options |
文章标签选项 |
POST |
/blog/article/import-wordpress |
从 WordPress 导入文章 |
文章 body 常用字段:
{
"title": "文章标题",
"slug": "post-slug",
"status": "publish",
"content": "Markdown 或 HTML",
"contentFormat": "markdown",
"cover": "",
"categories": ["tech"],
"tags": ["kt"]
}
Blog Category / Tag / Theme
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/blog/category/list |
本地分类分页 |
GET |
/blog/category/detail |
本地分类详情 |
POST |
/blog/category/save |
新增分类 |
POST |
/blog/category/update |
更新分类 |
POST |
/blog/category/remove |
删除分类 |
GET |
/blog/tag/list |
本地标签分页 |
GET |
/blog/tag/detail |
本地标签详情 |
POST |
/blog/tag/save |
新增标签 |
POST |
/blog/tag/update |
更新标签 |
POST |
/blog/tag/remove |
删除标签 |
GET |
/blog/term/options |
分类/标签选项 |
GET |
/blog/theme/config |
获取 Argon 主题配置 |
POST |
/blog/theme/save |
保存本地主题配置 |
POST |
/blog/theme/import-wordpress |
从 WordPress 导入主题配置 |
WordPress 代理
/wordpress/* 需要 Admin 登录态和 WordPress 登录态。后端优先使用 kt_wordpress_auth httpOnly cookie,也支持显式透传 WordPress 认证 header。
| 方法 | 路径 | 说明 |
|---|---|---|
POST |
/wordpress/auth/login |
使用 env 管理员账号登录 WordPress 并写入 cookie |
POST |
/wordpress/auth/logout |
清理 WordPress cookie |
GET |
/wordpress/auth/check |
校验 WordPress 登录态 |
GET |
/wordpress/theme/config |
读取 WordPress Argon 主题配置 |
WordPress Article / Tag / Category
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/wordpress/article/public/list |
公开文章列表代理 |
GET |
/wordpress/article/public/detail |
公开文章详情代理 |
GET |
/wordpress/article/list |
WordPress 文章分页 |
GET |
/wordpress/article/detail |
WordPress 文章详情 |
POST |
/wordpress/article/save |
新增 WordPress 文章 |
POST |
/wordpress/article/update |
更新 WordPress 文章 |
POST |
/wordpress/article/remove |
删除 WordPress 文章 |
GET |
/wordpress/tag/list |
标签分页 |
GET |
/wordpress/tag/detail |
标签详情 |
POST |
/wordpress/tag/save |
新增标签 |
POST |
/wordpress/tag/update |
更新标签 |
POST |
/wordpress/tag/remove |
删除标签 |
GET |
/wordpress/category/list |
分类分页 |
GET |
/wordpress/category/detail |
分类详情 |
POST |
/wordpress/category/save |
新增分类 |
POST |
/wordpress/category/update |
更新分类 |
POST |
/wordpress/category/remove |
删除分类 |
WordPress rewrite 未开启导致 /wp-json/* 返回 404 时,后端会回退到 ?rest_route=/...。
MinIO
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/minio/check |
检查连接和 bucket |
POST |
/minio/bucket |
创建 bucket |
POST |
/minio/upload |
上传文件,multipart/form-data |
GET |
/minio/list |
文件列表 |
GET |
/minio/url |
临时访问 URL |
GET |
/minio/resource-proxy |
代理读取资源 |
GET |
/minio/download |
下载文件流 |
DELETE |
/minio/remove |
删除文件 |
bucketName 不传时使用 MINIO_BUCKET。
QQBot 管理
QQBot 运行态包括 NapCat 容器登录、OneBot v11 反向 WebSocket、MQTT 事件总线、账号能力绑定、在线命令、自动回复规则、权限名单、发送/接收日志和插件生态。
Account / Scan Login
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/qqbot/account/list |
QQBot 账号分页 |
GET |
/qqbot/account/enabled |
启用账号列表 |
POST |
/qqbot/account/save |
手动新增账号 |
POST |
/qqbot/account/update |
更新账号 |
POST |
/qqbot/account/scan/create |
扫码新增账号,创建登录会话 |
POST |
/qqbot/account/scan/refresh?id= |
对已有账号刷新登录态 |
GET |
/qqbot/account/scan/status?sessionId= |
查询扫码会话状态 |
GET |
/qqbot/account/scan/events?sessionId= |
SSE 订阅扫码进度 |
POST |
/qqbot/account/scan/qrcode/refresh?sessionId= |
刷新当前会话二维码 |
POST |
/qqbot/account/scan/captcha/submit |
提交密码登录安全验证码结果 |
POST |
/qqbot/account/scan/cancel?sessionId= |
取消扫码会话 |
POST |
/qqbot/account/delete?id= |
删除账号并断开 WS |
POST |
/qqbot/account/kick?selfId= |
断开反向 WS 会话 |
GET |
/qqbot/napcat/runtime/detail?accountId= |
读取账号 NapCat 运行态证据 |
POST |
/qqbot/account/bind/command |
绑定账号和在线命令 |
POST |
/qqbot/account/unbind/command |
解绑账号和在线命令 |
POST |
/qqbot/account/bind/rule |
绑定账号和自动回复规则 |
POST |
/qqbot/account/unbind/rule |
解绑账号和自动回复规则 |
账号保存支持可选 encryptedLoginPassword,用于 NapCat 密码登录。前端必须先通过 /auth/password-public-key 获取公钥并使用 RSA-OAEP 加密,不传明文 loginPassword;后端必须使用显式配置的 QQBOT_ACCOUNT_SECRET_KEY(或非默认 ADMIN_TOKEN_SECRET)二次加密落库,空值和公开默认值会被拒绝,不在列表/详情中返回。账号列表里的 connectStatus 只表示 OneBot 反向 WS;napcat.oneBotOnline、napcat.containerOnline、napcat.webuiOnline、napcat.qqLoginStatus、napcat.qqLoginMessage 分别表示 OneBot、容器、WebUI 和 QQ 登录态,webuiOnline=null 表示本次使用缓存且未重新探测 WebUI;qqLoginMessage 只承载真实 QQ 登录态消息,WebUI 配置缺失或请求异常只放在 lastError。
扫码链路返回 sessionId,前端应使用 SSE 查看步骤进度,而不是等待长 HTTP 请求完成;新增账号扫码会先预留容器和临时设备身份后立即返回 pending,会话后台再启动远端 Docker 和生成二维码。已有账号的更新登录不会通过 Docker 重建、重启或补 env 来刷新 QQ 登录态;如果目标容器仍在线,即使 QQ 账号已离线,也会保持同一容器并通过 NapCat WebUI 依次调用 SetQuickLogin、PasswordLogin、RefreshQRcode / GetQQLoginQrcode 推进原有弹窗流程。只有 Docker 容器离线或缺失时,容器准备阶段才会创建/重建容器,并在创建时一次性注入 ACCOUNT 和必要登录 env;已在线的源容器不补 env。快速登录失败后,如果账号保存了登录密码,后端使用解密后的密码计算 MD5 调用 /api/QQLogin/PasswordLogin,不会把密码写回运行态 env,也没有成功后的 env 清理步骤;密码登录结果按 QQBOT_NAPCAT_PASSWORD_LOGIN_WAIT_MS / QQBOT_NAPCAT_LOGIN_POLL_INTERVAL_MS 轮询。准备阶段的扫码会话会持续续期,避免后台登录未完成时前端先判过期。同一账号已有 pending 更新登录会话时,重复调用 /qqbot/account/scan/refresh 会返回原 sessionId,不会再次启动 quick/password/二维码准备。若 API Pod 在准备阶段重启,持久化的 preparingRelogin 超过 QQBOT_NAPCAT_RELOGIN_PREPARING_STALE_MS(留空使用密码等待窗口加缓冲)后,/qqbot/account/scan/status 会自动恢复普通登录态检测,不再永久停留在“正在尝试密码登录”;/qqbot/account/scan/events 在进程内事件缓存丢失时会先推送当前会话快照。密码登录触发 QQ 安全验证时,接口返回的 captchaUrl 只用于前端拉起腾讯验证码;前端必须把腾讯验证码返回的 ticket、randstr、sid 连同 sessionId 提交到 /qqbot/account/scan/captcha/submit,后端再代理到同一 NapCat 容器的 /api/QQLogin/CaptchaLogin 继续密码登录第二步。验证码和新设备验证这类真人交互态使用 NAPCAT_LOGIN_HUMAN_VERIFY_EXPIRE_MS(默认 15 分钟,且至少不短于普通二维码 TTL)续期;普通登录二维码仍使用 NAPCAT_LOGIN_QR_EXPIRE_MS。/qqbot/account/scan/status 遇到 NapCat 只返回“需要验证码/继续完成验证/安全验证”但不带 URL 时,会先从当前容器日志提取 proofWaterUrl,提取不到则保持验证码处理中而不切到二维码兜底;会话已有 captchaUrl 后,同类状态仍保持 pending 和原 captchaUrl。密码登录仍失败、验证码未完成、离线、账号不匹配或缺少 QQ 号时,直接通过 WebUI 二维码接口进入扫码兜底,不 reset 登录态。看门狗只做离线巡检、账号错误写入和 super 站内信告警,不会触发 quick/password 登录或扫码登录。
密码验证码通过后如果 NapCat 返回 needNewDevice,后端不会只把 jumpUrl 透给 Admin,而是在同一会话中继续调用 /api/QQLogin/GetNewDeviceQRCode 生成新设备验证二维码;/qqbot/account/scan/status 后续轮询会代理 /api/QQLogin/PollNewDeviceQR,状态映射为 newDeviceStatus=qr-pending|scanned|confirming|verified|expired|failed,进入确认态后再调用 /api/QQLogin/NewDeviceLogin 并回到密码登录完成检查。扫码会话结果新增 newDeviceQrcode、newDeviceStatus、deviceVerifyUrl 字段;captchaUrl 和 newDeviceQrcode 分别表示腾讯安全验证码和 QQ 新设备验证二维码,前端必须分开展示。SSE 进度文案包含快速登录、密码登录、验证码、新设备二维码、已扫码、确认中、二维码兜底、登录成功/失败。
同一 QQ 账号只保留一个有效 NapCat 主容器。扫码后如果已有账号绑定到新容器,后端会释放旧绑定和未共享的旧容器,避免同账号多实例互相挤下线。OneBot notice 只有机器人下线、登录失效、KickedOffLine 等账号级信号才会记录 QQ 登录态异常并生成 qqbot.account.offline 站内信,普通群成员 kick 不属于账号离线信号。下线原因写入 lastError 前按 last_error 500 字符列宽截断;后续无错误的普通断连只更新 OneBot 连接状态,不清空该原因。账号列表会按近期缓存检查绑定 NapCat 容器的最新登录状态日志,日志检测默认 5 秒超时;isOnline:false 属于 QQ 登录态离线信号;心跳只代表 OneBot/容器通信,不能推导 QQ 登录态;近期连接只用于避免重连瞬间被旧缓存误伤,后续仍必须以 NapCat WebUI/日志检查判断 QQ 登录态。托管容器必须显式配置 QQBOT_NAPCAT_IMAGE,不要依赖 latest 默认镜像。
托管 NapCat 容器按账号持久化设备身份,napcat_device_identity 保存账号对应的数据目录、hostname、machine-id 路径、MAC 地址、验证状态和最近登录证据。重建同一账号容器时会复用 pc-<8hex> hostname、实体 OUI 风格 MAC 和 machine-id,并明确排除 Docker 02:42、QEMU/KVM 52:54:00、VMware、Hyper-V 等虚拟化前缀;新增账号创建期在真实 QQ selfId 未知时使用预留容器 id 创建临时设备身份,第一次 Docker run 就注入完整拟真参数,扫码成功后再把该身份和 runtime/protocol profile 归属到真实账号。Docker run 会注入 --hostname、--mac-address 和只读 /etc/machine-id 挂载;后端还会同步写入 QQNT Linux machine-info,让 QQNT 计算 GUID 时使用的 MAC 与 Docker 网卡一致。当前策略名为 qqnt-visible-hostname-v1 / physical-oui-mac-v1,绑定关系会回填 napcat_account_binding.device_identity_id。
NapCat Runtime Profile
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/qqbot/napcat/runtime/detail?accountId= |
读取账号 NapCat runtime/protocol/session behavior profile、风险降载和历史登录事件兼容表状态 |
该接口只返回脱敏后的运行态证据,供 Admin 排查镜像、locale、shm、配置 hash、漂移状态、风险模式和 watchdog 巡检告警状态;不会返回 WebUI token、reverse WS token、QQ 登录密码、SSH 私钥或运行态密码环境。账号列表只挂载 napcat.profileStatus、napcat.runtimeProfile 等摘要字段,不触发登录、重建或修复动作。watchdog 不执行登录恢复:遇到 QQ 登录态离线只记录离线原因并通知 super,登录恢复统一由 Admin 手动「更新登录」触发;session behavior profile 只做冷启动、housekeeping、presence 和自动能力分阶段降载,不实现账号级每小时/每日累计发送预算。
NapCat Chinese Desktop Runtime v8 使用 KT NapCatQQ fork 源码构建出的 NapCat.Shell artifact,并在 QQ KickedOffLine 后重置 native login service 再请求二维码;同一次踢下线事件只消费一次 reset,且只有明确二维码过期或扫码确认窗口失效的 QR session failure 才自动换码,避免扫码确认期间被 ErrType=1/ErrCode=1 抢刷新打断。构建前必须运行 scripts/napcat-desktop-cn-stage-build.mjs 生成 Docker build context;生产 QQBOT_NAPCAT_IMAGE 应指向验证过的 kt-napcat-desktop-cn:desktop-cn-v8 digest。
napcat_login_event 实体和表仅作为历史 schema 兼容保留;watchdog 不再写入 quick/password 恢复事件,也不再依赖该表判断是否恢复登录。
外发消息不直接抢发:后端会按 QQBOT_SEND_GLOBAL_INTERVAL_MS、QQBOT_SEND_TARGET_INTERVAL_MS 和 QQBOT_SEND_JITTER_MS 预约发送窗口,默认全局 2500ms、同会话 8000ms、抖动 0-800ms;如果等待超过 QQBOT_SEND_MAX_QUEUE_WAIT_MS,本次发送会在下发前被拒绝。在线命令和自动回复规则会叠加运行时保底冷却,默认命令 5000ms、规则 30000ms;复读机默认连续 4 次相同普通文本才触发,同一会话默认 10 分钟内只复读一次,并限制普通文本长度,减少自动行为被风控识别的概率。
Command / Rule / Permission
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/qqbot/command/list |
在线命令分页,支持 pluginKey、operationKey、selfId、enabled |
POST |
/qqbot/command/save |
新增在线命令 |
POST |
/qqbot/command/update |
更新在线命令 |
POST |
/qqbot/command/delete?id= |
删除在线命令 |
POST |
/qqbot/command/toggle?id=&enabled= |
启停在线命令 |
POST |
/qqbot/command/test |
预览测试在线命令 |
GET |
/qqbot/rule/list |
自动回复规则分页 |
POST |
/qqbot/rule/save |
新增自动回复规则 |
POST |
/qqbot/rule/update |
更新自动回复规则 |
POST |
/qqbot/rule/delete?id= |
删除自动回复规则 |
POST |
/qqbot/rule/toggle?id=&enabled= |
启停自动回复规则 |
GET |
/qqbot/permission/config |
权限名单配置 |
POST |
/qqbot/permission/config |
保存权限名单配置 |
GET |
/qqbot/permission/allowlist |
白名单分页 |
POST |
/qqbot/permission/allowlist/save |
新增白名单 |
POST |
/qqbot/permission/allowlist/update |
更新白名单 |
POST |
/qqbot/permission/allowlist/delete?id= |
删除白名单 |
GET |
/qqbot/permission/blocklist |
黑名单分页 |
POST |
/qqbot/permission/blocklist/save |
新增黑名单 |
POST |
/qqbot/permission/blocklist/update |
更新黑名单 |
POST |
/qqbot/permission/blocklist/delete?id= |
删除黑名单 |
/qqbot/command/test 示例:
{
"commandId": "2041700000000000001",
"text": "/查曲 夏祭り",
"selfId": "10000",
"targetType": "group",
"targetId": "123456",
"userId": "2354598417"
}
线上 smoke 必须按 operationKey 查询启用命令 ID 后传入 commandId,避免默认 preview selfId 误报未匹配命令。
Plugin / Dashboard / Send / Message
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/qqbot/plugin/list |
插件列表,支持 triggerMode=command/event |
GET |
/qqbot/plugin/operation/list |
插件能力列表 |
GET |
/qqbot/plugin/health |
插件健康检查 |
GET |
/qqbot/plugin/event/list |
事件触发插件绑定状态 |
POST |
/qqbot/plugin/event/bind |
绑定事件触发插件 |
POST |
/qqbot/plugin/event/unbind |
解绑事件触发插件 |
GET |
/qqbot/dashboard/summary |
QQBot 工作台汇总 |
GET |
/qqbot/send/log/list |
发送日志分页 |
POST |
/qqbot/send/private |
发送私聊消息 |
POST |
/qqbot/send/group |
发送群聊消息 |
GET |
/qqbot/conversation/list |
会话列表 |
GET |
/qqbot/message/list |
消息列表 |
Plugin Platform
插件平台使用统一 plugin.json manifest 描述插件 key、版本、入口、操作、事件、定时任务、权限和运行预算;后端会校验路径必须留在插件包内,权限必须命中白名单,安装包 content hash 必须与 manifest 匹配。tasks 字段声明平台托管的定时任务:
| 字段 | 说明 |
|---|---|
key |
全局唯一任务 key,例如 bangdream.bestdori.sync-main-data |
name |
Admin 展示名称 |
handlerName |
插件入口暴露的任务处理器名称 |
defaultCron |
5 段 cron 表达式,不允许每分钟执行,并按 BullMQ/cron-parser 语义校验 |
timeoutMs |
单次任务执行预算 |
enabled |
安装/启用时是否默认调度 |
permissions |
任务需要的插件权限,例如 runtime.http、plugin.storage.write |
description |
可选说明 |
CLI 入口:
pnpm qqbot-plugin create <pluginKey>
pnpm qqbot-plugin validate <pluginDir>
pnpm qqbot-plugin pack <pluginDir>
pnpm qqbot-plugin install-local <packageFile>
平台管理接口:
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/qqbot/plugin-platform/installations |
插件安装记录,支持 key/status 过滤 |
POST |
/qqbot/plugin-platform/upload |
上传插件包并返回校验摘要 |
POST |
/qqbot/plugin-platform/validate |
校验 manifest JSON |
POST |
/qqbot/plugin-platform/install |
按上传包安装插件版本 |
POST |
/qqbot/plugin-platform/install-local |
按本地包路径安装插件版本 |
POST |
/qqbot/plugin-platform/enable |
启用插件安装 |
POST |
/qqbot/plugin-platform/disable |
禁用插件安装 |
POST |
/qqbot/plugin-platform/upgrade |
升级插件安装版本 |
POST |
/qqbot/plugin-platform/uninstall |
卸载插件安装 |
POST |
/qqbot/plugin-platform/config |
保存插件配置 |
GET |
/qqbot/plugin-platform/runtime-events |
查询插件运行事件 |
GET |
/qqbot/plugin-platform/account-bindings |
查询插件账号绑定 |
定时任务管理接口:
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/qqbot/plugin-platform/tasks/page |
插件定时任务分页,支持插件、状态过滤 |
GET |
/qqbot/plugin-platform/tasks/:id |
任务详情 |
POST |
/qqbot/plugin-platform/tasks/:id/enable |
启用任务并注册 BullMQ Job Scheduler |
POST |
/qqbot/plugin-platform/tasks/:id/disable |
停用任务并移除调度 |
POST |
/qqbot/plugin-platform/tasks/:id/cron |
修改 5 段 cron,校验通过后重建调度 |
POST |
/qqbot/plugin-platform/tasks/:id/run |
手动提交一次任务 |
GET |
/qqbot/plugin-platform/tasks/:id/runs |
任务运行记录分页 |
src/modules/qqbot/plugin-platform/runtime 当前提供 host-side driver 边界和超时/崩溃事件归档;实际 worker/child-process driver 可以在后续批次接入,但插件侧只能通过受控 SDK 访问发送队列、配置、存储、HTTP、资产和事件上下文。
Admin 入口为 /qqbot/plugin-task,用于分页查看任务、启停、修改 cron、手动运行和查看运行记录。BangDream 内置任务 bangdream.bestdori.sync-main-data 会定期同步 Bestdori 主数据到 BANGDREAM_TSUGU_CACHE_ROOT;生产容器内路径为 /data/qqbot/plugins/bangdream/cache,K8s hostPath 使用 k3d 节点可写目录 /var/lib/rancher/k3s/kt-template-online-api/qqbot-plugins。
OneBot Reverse WebSocket
QQBOT_REVERSE_WS_PATH 默认是 /qqbot/onebot/reverse。NapCat 通过反向 WS 连接 API,token 使用 QQBOT_REVERSE_WS_TOKEN。
QQBot 插件能力
Bilibili Card
插件 key:bilibili-card。这是事件型内置插件,不新增在线命令;启用后仍需通过账号事件绑定让指定 QQBot 账号接收 bilibili-card.message。
| event key | 触发来源 | 说明 |
|---|---|---|
bilibili-card.message |
message | 从 QQ/NapCat share/json/xml/lightapp 卡片和文本中提取 Bilibili 链接 |
插件会解析 www.bilibili.com、m.bilibili.com 和 b23.tv。短链通过插件平台受控 resolveRedirect host 能力限制跳转次数和超时;视频信息来自 Bilibili x/web-interface/view,回复为纯文本标题、UP 主、时长、播放/弹幕/点赞等摘要和标准视频链接。同一账号、同一会话、同一视频在 QQBOT_BILIBILI_CARD_DEDUPE_TTL_MS 内去重。
可配置键:
| 配置键 | 默认值 | 说明 |
|---|---|---|
QQBOT_BILIBILI_CARD_HTTP_TIMEOUT_MS |
6000 | HTTP 请求超时毫秒 |
QQBOT_BILIBILI_CARD_MAX_REDIRECTS |
5 | b23.tv 最大跳转数 |
QQBOT_BILIBILI_CARD_DEDUPE_TTL_MS |
600000 | 同视频去重毫秒 |
QQBOT_BILIBILI_CARD_DESC_MAX_LENGTH |
80 | 回复中简介最大字符数 |
BangDream
插件 key:bangdream。旧 bangDream 作为兼容别名仍可解析;当前源码根目录为 src/modules/qqbot/plugins/bangdream/src,按第三期插件结构拆分为 operations、domain/*、application、infrastructure/integration、infrastructure/storage、config、assets 和 theme,不再使用旧 tsugu 子目录、宿主 builtins 包装层或纯转接目录。
| operation key | 命令 | 说明 |
|---|---|---|
bangdream.song.search |
/查曲 |
查歌曲信息图片 |
bangdream.song.chart |
/查谱面 |
查谱面图片 |
bangdream.song.random |
/随机曲 |
随机歌曲 |
bangdream.song.meta |
/查询分数表 |
查歌曲分数榜 |
bangdream.card.search |
/查卡 |
查卡牌信息图片 |
bangdream.card.illustration |
/查卡面 |
查卡面插画 |
bangdream.character.search |
/查角色 |
查角色信息 |
bangdream.event.search |
/查活动 |
查活动信息 |
bangdream.event.stage |
/查试炼 |
查活动试炼,保持拆图输出 |
bangdream.player.search |
/查玩家 |
查玩家信息 |
bangdream.gacha.search |
/查卡池 |
查卡池 |
bangdream.gacha.simulate |
/抽卡模拟 |
模拟抽卡 |
bangdream.cutoff.detail |
/ycx |
单档位预测线 |
bangdream.cutoff.all |
/ycxall |
全档位预测线 |
bangdream.cutoff.recent |
/lsycx |
历史/近期档线 |
plugins/bangdream/plugin.json 是 BangDream operation、handlerName、别名、权限、超时和说明的单一来源。新增或调整命令必须同步在线命令 SQL,并跑 manifest/command-SQL 测试。
FF14 Market
插件 key:ff14-market。旧 ff14Market 作为兼容别名仍可解析;源码按第三期插件结构拆分为 operations、application、domain、infrastructure/integration 和 config。
| operation key | 说明 |
|---|---|
ff14.item.resolve |
按物品名称或 ID 解析 XIVAPI 物品 |
ff14.market.price |
查询指定服务器/大区的 Universalis 市场价格 |
市场查价支持 item、itemId、world、dataCenter、region、hq、language。
FFLogs
插件 key:fflogs。
源码按第三期插件结构拆分为 operations、application、domain、infrastructure/integration、infrastructure/storage 和 config。
| operation key | 说明 |
|---|---|
fflogs.character.summary |
查询 FFLogs 角色公开排名;传 encounter 时查询指定高难最近记录 |
常用输入:characterName、serverSlug、serverRegion、encounter、limit、metric、timeframe、zoneId。
初始化 SQL
| 文件 | 用途 |
|---|---|
sql/vben-admin-init.sql |
创建 Admin 基础表、用户、角色、菜单、部门、字典和空组件表 |
sql/blog-init.sql |
初始化本地 Blog 表 |
sql/blog-menu.sql |
初始化 Blog 管理菜单 |
sql/qqbot-init.sql |
初始化 QQBot 表、插件命令和字典 |
sql/system-log-menu.sql |
初始化系统日志菜单和权限 |
sql/system-notice-menu.sql |
初始化系统站内信表与菜单权限 |
sql/migrate-dict-to-admin-dict.sql |
旧 dict 迁移到 admin_dict |
sql/migrate-component-to-admin-component.sql |
旧 component 迁移到 admin_component |
sql/fix-admin-menu-meta.sql |
修复菜单 meta 被覆盖为空 |
sql/fix-admin-user-zero-id.sql |
修复旧版本 admin_user.id=0 脏数据 |
验证入口
常规文档/配置检查:
git diff --check
后端代码检查:
pnpm run typecheck
pnpm run lint
pnpm test
BangDream 图片 smoke:
.\scripts\bangdream-render-smoke.ps1 -OperationKey bangdream.song.search -Text "夏祭り" -OutFile ".kt-workspace/bangdream-smoke/song.jpg"
.\scripts\bangdream-render-smoke.ps1 -OperationKey bangdream.event.stage -Text "310" -OutFile ".kt-workspace/bangdream-smoke/stage.jpg" -ExpectedImageCount 5
Jenkins/K8s 发布后还需要观察 rollout、新 Pod 日志,并跑真实运行态 smoke;推送成功不等于发布完成。