ClearFlask 2.7.2 常用 CLI 命令与 API 详解
ClearFlask 2.7.2 运维 CLI 与 REST API 实操全解:systemd 启停与健康核查、Tomcat 自带脚本、MySQL/DynamoDB/S3 三层备份命令实测回显、超管登录双 Set-Cookie 破解、建项目/读写配置/建门户用户/提交反馈/投票/导出全链路 curl 实操与四大坑(connect-token、门户 403 强跳 HTTPS、voteValue 枚举、support.vote 前置)。
ClearFlask 2.7.2 常用 CLI 命令与 API 详解
目标:覆盖 ClearFlask 2.7.2 运维日常的两条线——服务侧 CLI(进程启停与健康核查、Tomcat 自带脚本、MySQL/DynamoDB/S3 三层备份、搜索索引 JMX 迁移)与 REST API 实操(超管登录、建项目、读写项目配置、建门户用户、提交反馈、投票、导出),全部命令与回显为 2026-11-01 本地实测照抄。
一、环境信息
| 项目 | 值 |
|---|---|
| 组件版本 | ClearFlask 2.7.2 |
| 对外入口 | http://127.0.0.1:8130(Node 前端服务,API 前缀 /api/v1) |
| Java 服务内部地址 | http://127.0.0.1:8080(仅服务网内可达,不对外发布) |
| Java 运行时 | Apache Tomcat 9.0.123 + JVM 17.0.20.1+1(Eclipse Adoptium) |
| 索引库 | MariaDB 10.5.29,库名 clearflask,root 密码 clearflask(内置弱口令,仅内网) |
| 源数据存储 | DynamoDB 兼容服务(端点 :4566,单表 clearflaskprimary;S3 桶 local-upload) |
| 实测账号 | 超管 admin@localhost / q1w2e3r4;门户用户 feedback@localhost / q1w2e3r4 |
⚠️ 宿主前置:本文启停/登录主机的命令按真机(systemd 或等价进程管理 + 可直接 SSH 到各服务主机)形态书写。本系列实测环境的各服务进程由部署编排拉起(见 《ClearFlask 2.7.2 Docker Compose 部署指南》),
aws/mysqldump/catalina.sh等命令均在对应服务所在主机上执行,回显与真机等价。
二、服务启停与健康核查
2.1 启停(真机形态)
systemctl restart clearflask-server # 改配置后重启 Java 服务
systemctl restart clearflask-connect # 改 connect.config.json 后重启 Node 服务
2.2 健康与进程核查(实测回显)
$ curl -s http://127.0.0.1:8130/api/health
ok
$ ss -ltn | grep ':8130\b'
LISTEN 0 4096 0.0.0.0:8130 0.0.0.0:*
$ ps -ef | grep 'catalina.base' | grep -v grep | head -1
root 792229 792202 15 19:32 ? 00:05:32 /opt/java/openjdk/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties ... -Xms256m -Xmx512m ... org.apache.catalina.startup.Bootstrap start
Java 服务就绪的日志标志(实测冷启动):
Server startup in 13309 ms
Node 服务启动标志:App on 9080 (selfhost);页面渲染成功会逐条打 Rendered http://demo.localhost/ in 2 pass(es)。
2.3 Tomcat 自带脚本
Java 服务安装目录 bin 实测清单(11 个):
catalina.sh ciphers.sh configtest.sh daemon.sh digest.sh
makebase.sh setclasspath.sh shutdown.sh startup.sh tool-wrapper.sh version.sh
版本核查实测回显:
$ catalina.sh version
Server version: Apache Tomcat/9.0.123
Server built: Oct 6 2026 18:59:20 UTC
Server number: 9.0.123.0
OS Name: Linux
OS Version: 7.0.0-38-generic
Architecture: amd64
JVM Version: 17.0.20.1+1
JVM Vendor: Eclipse Adoptium
日常最常用:configtest.sh(校验 Tomcat 层配置)、shutdown.sh/startup.sh(优雅停启,通常由进程管理器代管)、catalina.sh run(前台排障)。
三、备份与恢复(三层数据)
ClearFlask 数据分三层,备份缺一不可:源数据(DynamoDB 兼容层)、搜索索引(MySQL,可由源数据重建)、配置文件(含安装密钥)。
3.1 MySQL 索引库 mysqldump(实测)
$ mysqldump -h <索引库主机> -uroot -pclearflask clearflask > backup-mysql.sql
$ ls -l backup-mysql.sql
-rw-r--r-- 1 root root 9139 Nov 1 20:07 backup-mysql.sql
$ head -5 backup-mysql.sql
/*M!999999\- enable the sandbox mode */
-- MariaDB dump 10.19 Distrib 10.5.29-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: localhost Database: clearflask
库内 7 表实测:
$ mysql -h <索引库主机> -uroot -pclearflask -e "use clearflask; show tables;"
Tables_in_clearflask
account
comment
comment_parent_id
idea
idea_funders
idea_tags
user
💡 这 7 张表只是搜索镜像:
select count(*) from user实测为 0 而账号仍可登录——业务源数据在 DynamoDB 兼容层单表clearflaskprimary。恢复时 MySQL 层可整库重导,也可清空后靠启动参数createIndexesOnStartup=true+ JMXreindexProjects重建。
3.2 DynamoDB / S3(AWS CLI 指向兼容端点)
官方 README 调试节给出的标准用法——aws --endpoint-url=http://<兼容层>:4566(内置环境亦有 awslocal 快捷方式,实测回显):
$ aws --endpoint-url=http://127.0.0.1:4566 dynamodb list-tables
{
"TableNames": [
"clearflaskprimary"
]
}
$ aws --endpoint-url=http://127.0.0.1:4566 s3 ls
2026-11-01 11:02:14 local-upload
备份处置:源数据用 dynamodb export/逐项 scan 导出或直接持久化存储目录;附件桶 s3 sync local-upload ./backup/。
3.3 配置与整体导出
server/config-selfhost.cfg:含 VAPID/cursor/tokenSigner/SSO/webhook 五组安装密钥,chmod 600后随备份归档(参数含义见 《ClearFlask 2.7.2 配置参数详解》)。- 业务整体导出(超管 API,实测返回 ZIP):
$ curl -s -o project.zip -w '%{http_code}\n' \
-H "x-cf-connect-token: $CONNECT_TOKEN" -H "Cookie: cf_act_auth=$TOK; cf_sup_auth=$TOK" \
http://127.0.0.1:8080/api/v1/project/demo-9j4rx8vf/admin/export
200
$ file project.zip
project.zip: Zip archive data
四、REST API 实操(全链路实测)
API 定义即官方仓库 clearflask-api/src/main/openapi/api-*.yaml(OpenAPI,前端与后端共用),路径按域分组:/admin/account/*(超管账号)、/project/admin(建项目)、/project/{projectId}/admin/*(项目内管理)、/project/{projectId}/*(门户用户侧)。
4.1 认证机制(先读这节)
三层会话 Cookie + 一个内部头,实测结论:
| 凭据 | 获取方式 | 作用域 |
|---|---|---|
cf_act_auth | 超管登录 | 仪表盘账号会话 |
cf_sup_auth | 超管登录(同时下发) | 超级管理员标记 |
cf_usr_auth_<projectId> | 门户登录 POST /project/{pid}/login | 仅该项目门户,会话绑定 projectId,与路径不符直接 403(日志 Potential attack attempt) |
x-cf-connect-token | 部署时生成的共享令牌 | 直连 Java 服务 8080 时必须携带(AuthenticationFilter 的 Role.CONNECT 校验) |
两个实测坑:
- 登录响应的双 Set-Cookie:第二条带
Domain=... Expires=Thu, 01 Jan 1970是清除动作,curl -c jar会被抵消成空 jar。正确做法是手工提取 token 再以-H "Cookie: ..."传递:
$ TOK=$(curl -s -D- -X POST http://127.0.0.1:8130/api/v1/admin/account/login \
-H 'Content-Type: application/json' \
-d '{"email":"admin@localhost","password":"q1w2e3r4"}' \
| grep -oP 'cf_sup_auth=\K[^;]+' | head -1)
$ echo "$TOK"
5a2362d290a742088e7a... # 32 位小写十六进制会话 ID
- 门户子域写操作在纯 HTTP 环境被拒:经入口对
demo.localhost的 POST 返回403且带Location: https://demo.localhost/...(无证书形态下 Node 侧强制 HTTPS)。本地实操请直连 Java 服务内部地址并带x-cf-connect-token(下文示例均此形态)。
4.2 建项目(POST /project/admin)
先读当前状态(新建环境实测为空):
$ curl -s -H "Cookie: cf_act_auth=$TOK; cf_sup_auth=$TOK" \
http://127.0.0.1:8130/api/v1/project/config/admin
{"byProjectId":{}}
创建请求体是完整的项目 Config(必填链极深:layout.pages/menu、content.categories[].workflow/support/tagging、style.palette/typography/animation/whitelabel、users.onboarding.notificationMethods.email 等,逐项语义见官方 api-project.yaml)。实测可成功的最小完整体:
{
"test": false,
"projectId": "demo-project",
"name": "DemoBoard",
"slug": "demo",
"cookieConsent": {},
"layout": {
"pages": [{"pageId": "page1", "name": "Feedback", "slug": "feedback", "components": {}, "panels": []}],
"menu": [{"menuId": "menu1", "pageIds": ["page1"], "name": "Feedback"}]
},
"content": {
"categories": [{
"categoryId": "cat1", "name": "Ideas", "userCreatable": true, "visibility": "Public",
"workflow": {"statuses": [{"statusId": "st1", "name": "Started", "disableFunding": false,
"disableVoting": false, "disableExpressions": false, "disableIdeaEdits": false, "disableComments": false}]},
"support": {"fund": false, "comment": true},
"tagging": {"tags": [], "tagGroups": []}
}]
},
"style": {"palette": {"darkMode": false}, "typography": {}, "animation": {"enableTransitions": true},
"whitelabel": {"poweredBy": "Show"}},
"users": {"displayName": {}, "onboarding": {
"visibility": "Public", "accountFields": {"displayName": "Optional"},
"notificationMethods": {"browserPush": false, "oauth": [],
"email": {"mode": "SignupAndLogin", "verification": "None"}}}},
"integrations": {}
}
实测回显(节选)——注意 projectId 会被服务端重新分配(demo-project → demo-9j4rx8vf),且响应里附带超管在该项目的门户身份 admin-swt4n:
HTTP 200
{"projectId":"demo-9j4rx8vf","config":{"config":{...,"slug":"demo",...},"version":"new"},
"user":{"userId":"admin-swt4n","name":"Admin","isMod":true,"email":"admin@localhost",...}}
💡 缺字段的报错是逐层引导式的,实测样本:
500 NullPointerException(users.onboarding.notificationMethods.email 缺)→400 Json missing non null field verification in EmailSignup→400 Expected a boolean but was BEGIN_OBJECT at path $.users.onboarding.notificationMethods.browserPush→400 Json missing non null field menu in Layout。照上面的完整体抄即可一次通过;日常更推荐走仪表盘向导建项目,再用 API 读回改。
4.3 读 / 改项目配置
$ curl -s -H "x-cf-connect-token: $CONNECT_TOKEN" -H "Cookie: cf_act_auth=$TOK; cf_sup_auth=$TOK" \
http://127.0.0.1:8080/api/v1/project/demo-9j4rx8vf/admin/config # GET 读全量 Config
$ curl -s -X PUT -H 'Content-Type: application/json' \
-H "x-cf-connect-token: $CONNECT_TOKEN" -H "Cookie: cf_act_auth=$TOK; cf_sup_auth=$TOK" \
--data @config-updated.json \
http://127.0.0.1:8080/api/v1/project/demo-9j4rx8vf/admin/config # PUT 回写全量
PUT 是全量替换:先 GET、改目标字段、整体回写。类型校验严格,实测反例——给 support.vote.iWantThis(对象)塞了布尔:
HTTP 500
JsonSyntaxException: Expected BEGIN_OBJECT but was BOOLEAN at path $.content.categories[0].support.vote.iWantThis
本例把分类改为允许投票:"vote": {"enableDownvotes": false} 后 PUT 返回 200。
4.4 门户用户:创建与登录
$ curl -s -X POST -H 'Content-Type: application/json' \
-H "x-cf-connect-token: $CONNECT_TOKEN" -H "Cookie: cf_act_auth=$TOK; cf_sup_auth=$TOK" \
-d '{"name":"Feedback User","email":"feedback@localhost","password":"q1w2e3r4"}' \
http://127.0.0.1:8080/api/v1/project/demo-9j4rx8vf/admin/user
{"userId":"feedback-user-pjv4","name":"Feedback User","email":"feedback@localhost","hasPassword":true,"balance":0,...}
$ curl -s -D- -X POST -H 'Content-Type: application/json' \
-H "x-cf-connect-token: $CONNECT_TOKEN" \
-d '{"email":"feedback@localhost","password":"q1w2e3r4"}' \
http://127.0.0.1:8080/api/v1/project/demo-9j4rx8vf/login | grep -i 'set-cookie\|HTTP/'
HTTP/1.1 200
Set-Cookie: cf_usr_auth_demo-9j4rx8vf=ba2a6e08ea234ae88ede1e135c54f2ee; Path=/; HttpOnly; SameSite=Strict; Expires=Sat, 28 Aug 2027 12:25:27 GMT
Set-Cookie: cf_usr_auth_demo-9j4rx8vf=; Domain=localhost; Expires=Thu, 01 Jan 1970 00:00:00 GMT
门户会话 Cookie 名即 cf_usr_auth_<projectId>(取第一条有效值)。超管账号本身在门户的自动身份(admin-swt4n)无密码,/login 直登实测 401 Email or password incorrect——需要先用 4.4 的方式给用户设密码或用独立邮箱。
4.5 提交反馈与投票
# 管理侧建 idea(也可由门户用户经 /idea 端点创建,需门户会话)
$ curl -s -X POST -H 'Content-Type: application/json' \
-H "x-cf-connect-token: $CONNECT_TOKEN" -H "Cookie: cf_act_auth=$TOK; cf_sup_auth=$TOK" \
-d '{"authorUserId":"admin-swt4n","title":"支持导出反馈为CSV","description":"希望仪表盘能一键导出全部反馈数据为CSV。","categoryId":"cat1","tagIds":[],"statusId":"st1"}' \
http://127.0.0.1:8080/api/v1/project/demo-9j4rx8vf/admin/idea
{"ideaId":"csv-eowcvlnv","authorName":"Admin","title":"支持导出反馈为CSV","categoryId":"cat1","statusId":"st1","vote":{},...}
# 门户用户投票(vote 是枚举字符串,不是数字!)
$ curl -s -X PATCH -H 'Content-Type: application/json' \
-H "x-cf-connect-token: $CONNECT_TOKEN" \
-H "Cookie: cf_usr_auth_demo-9j4rx8vf=$USER_SESSION" \
-d '{"vote":"upvote"}' \
http://127.0.0.1:8080/api/v1/project/demo-9j4rx8vf/vote/idea/csv-eowcvlnv
{"vote":{"vote":"upvote"},"idea":{"ideaId":"csv-eowcvlnv",...,"voteValue":1,...}}
投票三连实测坑(照抄可避):
| 写法 | 实测结果 |
|---|---|
{"vote":"upvote"} | ✅ 200,voteValue:1(枚举:upvote/downvote/none) |
{"vote":1} | 200 但 vote:{}——非法类型被静默忽略,不报错 |
分类未开 support.vote 时投票 | 400 {"userFacingMessage":"Voting not allowed"}(先按 4.3 PUT 开启) |
用超管会话打 PATCH /project/{pid}/admin/vote/idea/{ideaId} | 恒 403——该端点要求 PROJECT_MODERATOR_ACTIVE(含订阅态检查),self-host 账号不满足;投票走门户会话 |
公开检索(门户读,无需登录态):
$ curl -s -X POST -H 'Content-Type: application/json' -H "x-cf-connect-token: $CONNECT_TOKEN" \
-d '{}' http://127.0.0.1:8080/api/v1/project/demo-9j4rx8vf/ideasearch
{"results":[{"ideaId":"csv-eowcvlnv",...,"vote":{}}],"hits":{"value":1,"isGte":true}}
4.6 其他常用端点速查
| 端点 | 方法 | 用途 |
|---|---|---|
/api/v1/admin/account/login | POST | 超管登录(body {email,password}) |
/api/v1/admin/account/logout | POST | 登出 |
/api/v1/project/config/admin | GET | 全部项目 Config 索引 |
/api/v1/project/{pid}/admin/export | GET | 项目整体 ZIP 导出 |
/api/v1/project/{pid}/admin/idea/{ideaId} | GET/PATCH/DELETE | 反馈读改删 |
/api/v1/project/{pid}/admin/idea/{ideaId}/merge/{parentId} | PATCH | 反馈合并 |
/api/v1/project/{pid}/admin/idea/{ideaId}/voters | GET | 投票人列表 |
/api/v1/project/{pid}/admin/usersearch | POST | 用户检索 |
/api/v1/project/{pid}/subscribe/category/{categoryId} | PATCH | 分类订阅 |
/api/v1/webhook/github | POST | GitHub App 回调(配置见 C1) |
五、搜索索引 JMX 运维(MySQL ↔ ES 迁移)
官方维护流程(README "Migration between Elasticsearch/MySQL"),前提:为 Java 服务开启 JMX 端口发布(9950/9951),连接无需凭据与 SSL:
service:jmx:rmi:///jndi/rmi://localhost:9950/jmxrmi
用 jconsole/VisualVM 调用 com.smotana.clearflask.web.resource.ProjectResource 的两个操作:
| 操作 | 参数 | 用途 |
|---|---|---|
createIndexes | MySQL 方向 (false, true);ES 方向 (true, false) | 在目标引擎建索引 |
reindexProjects | ES→MySQL (true, false, true);MySQL→ES (true, true, false) | 全量重灌索引 |
切换节奏:READWRITE_旧 → READ_旧_WRITE_BOTH →(reindex)→ READ_新_WRITE_BOTH → READWRITE_新 → 下线旧引擎;每步重启 Java 服务生效,期间盯日志告警,可用仪表盘"项目高级设置"对单项目强制覆盖引擎做灰度验证。
六、实测排障记录
| 症状 | 根因 | 处置 |
|---|---|---|
curl -c jar 登录后 jar 为空 | 双 Set-Cookie 一设一删 | 手工 grep token 传 -H Cookie(4.1) |
门户域 POST 恒 403 + Location: https | 无证书形态 Node 侧强跳 HTTPS | 直连 Java 内部 8080 + x-cf-connect-token,或配 TLS |
| 建项目 500/400 连环报错 | Config 必填链深、类型严格 | 照 4.2 完整体;错误信息逐字段指路 |
| 投票 200 但没票数 | vote 传了数字被静默忽略 | 用枚举字符串 upvote/downvote/none |
user 表 0 行但能登录 | MySQL 仅索引镜像 | 查源数据去 DynamoDB 兼容层 clearflaskprimary |
注册 admin@localhost 返回 409 | 账号已存在 | 直接登录;改白名单见 C1 |
七、相关文章
参考链接
- OpenAPI 定义(全部端点权威来源):https://github.com/clearflask/clearflask/tree/master/clearflask-api/src/main/openapi
- 官方 README(备份/迁移/JMX/调试):https://github.com/clearflask/clearflask
- AWS CLI 兼容端点用法:https://docs.aws.amazon.com/cli/latest/reference/