Forge Admin 是一套 Java / Spring Boot / Vue 的开源后台框架,自带流程(Flowable)、多租户、低代码与社区「按版本纯净版」初始化 SQL。开源仓库:Gitee ForgeLab/forge-admin(GitHub 镜像:yaomindong1996/forge-admin)。演示环境可参考文档站说明。
想给社区一份「干净、可空库导入、不含流程运行垃圾」的 SQL——听起来只是 mysqldump 多写几条 ignore。结果现场是这样的:
- 空库导入「纯净版」看起来成功了,一启动却炸:
Table 'flw_ru_batch' already exists; - 紧接着又是
FlowableWrongDbException: version mismatch … db version is null; - 手忙脚乱从 dump 里「删掉 flw_*」之后,发现 admin / 字典 / 参数的 INSERT 也没了。
这不是发版公告,是 Forge 在 2026-10-13~14 一串真实提交里,把「半套 Flowable 表」钉进 dump-safe-full.sh、skill 文档和 pitfalls 的过程。读完你能带走三条硬规则:引擎表两套前缀必须一起跳过;框架 *_version 不能用宽松正则误伤;事后手工剥 SQL 比改脚本更危险。
TL;DR(可先收藏)
- Flowable 不止
act_*:事件注册等还有flw_*(如flw_ru_batch、flw_event_*、flw_channel_definition)。 - 社区纯净版 不要导出 引擎表:由 Admin/Flow 首次启动自动建;半套表比「完全没有」更糟。
dump-safe-full.sh定稿规则:full_ignore_regex="^act_|^flw_"(commit1dcf6607)。- 只跳
^act_→ 留下flw_*→ 引擎再 CREATE →already exists,且常无act_ge_property.schema.version→db version is null。 - 不要用
(^|_)version$「顺便」忽略:会误伤ai_business_extension_version、ai_crud_config_version、sys_flow_model_version等。 - 事后从 SQL 文件剥
flw_*必须按表块删,不能从第一个flw_*一路 skip 到文件尾——mysqldump 按表名排序,后面往往是sys_*。
版本与提交矩阵(本稿场景)
| 组件 / 产物 | 说明 |
|---|---|
| 流程引擎 | Flowable(社区纯净版策略:不带引擎表;启动再建) |
| 导出脚本 | forge-server/scripts/db/dump-safe-full.sh |
| 导出规范 | .agents/skills/forge-project-init/references/pure-sql-export.md |
| 踩坑备忘 | code-copilot/memory/pitfalls/flow.md |
| 发布物 | forge-server/db/backup/ForgeAdmin-纯净版-V1.2.0.sql |
| 关键提交 | 88d17508 → fc753e11 → ad5da3d6 → 1dcf6607(2026-10-13~14,上海时区) |
下面按「现象 → 根因 → Forge 怎么改」拆三段,并把三次返工串成一条时间线。重点在框架落地,不在背 SQL 表名大全。
现象:想要「无流程表」,却导入后启动连环炸
按源码推演(发布前请作者用空库验证):运营侧从已跑过 Flyway 的测试库,经 clean-db.sh 清理再 dump-safe-full.sh,产出「ForgeAdmin-纯净版-Vx.y.z.sql」。目标在 skill 里写得很清楚——空库一次导入成功、有默认租户与超级管理员 admin、导入后启动前 information_schema 里 act_% / flw_% 应为 0 张。
但当 full_ignore_regex 还只写 ^act_ 时,flw_ru_batch、flw_event_*、flw_channel_definition 等会进 dump。空库导入后一启动,日志常常是两连击:
SQLSyntaxErrorException: Table 'flw_ru_batch' already exists
FlowableWrongDbException: version mismatch: library version is '7.0.1.1', db version is null
第一句好懂:引擎 schema 脚本还要执行 CREATE TABLE,库里却已经有同名表。第二句更阴:有一部分 flw_*,却读不到完整的 act_ge_property.schema.version——半套表把引擎推进「既不能当空库初始化、又不能当已升级库」的夹缝。排障同学若只搜 already exists,很容易去删表、改字符集、甚至怀疑 Flyway 历史,而漏掉「导出 ignore 规则写窄了」这一层。
根因一:Flowable 是两套表前缀,不是「只要 act_」
仓库 pitfalls(发现日期 2026-10-13,commit 88d17508)写得很直白:
社区纯净版从测试库 dump 时,
full_ignore_regex只写了^act_,把flw_ru_batch、flw_event_*、flw_channel_definition等带进 SQL。
根因:Flowable 表必须整套由启动创建。半套flw_*+ 无act_ge_property比「完全没有流程表」更糟。
同一次提交把脚本改成同时跳过 flw_*,并新增 pure-sql-export.md。文档还划了一条红线:禁止在导出后手工追加 INSERT INTO act_ge_property / act_id_property——有 INSERT、无建表,Navicat / mysql 会报 1146 Table '….act_ge_property' doesn't exist。
这里有一个容易混的语义差,必须分开记:
clean-db.sh库内清理:运行库里已经有流程表时,仍可保留ACT_GE_PROPERTY/ACT_ID_PROPERTY等属性行,再截断其它运行表——那是给「已存在引擎」的环境用的。- 社区纯净版导出:不要把引擎 DDL/DML 带进下载文件;官方「全量初始化 SQL」本身也不带完整
act_*/flw_*结构,靠应用首次启动创建。
旁支(commit fc753e11):同一测试库若先被 Flowable 8 写过再回退 7.x,只改 act_ge_property 版本号不够——Liquibase 托管的 flw_* / act_app_* / act_cmmn_* / act_dmn_* 等会再撞 already exists。与「纯净导出」是不同坑,但共享同一直觉:引擎主版本、库内 schema 标记、changelog 必须成套,半升级/半回退最伤。
调用链可以压成四行(便于贴到团队群):
dump 只 ignore ^act_
→ SQL 文件带半套 flw_*(无完整 act_ge_property 版本契约)
→ 启动时引擎再 CREATE / 读 schema.version
→ already exists + db version is null
根因二:错误的 version 忽略会误伤框架表
88d17508 一度写成:
full_ignore_regex="^act_|^flw_|(^|_)version$"
意图可能是「跳过无关 version 表」。commit 1dcf6607(2026-10-14)证明:该正则会匹配所有以 _version 结尾的框架表。导入纯净版后,低代码扩展一写版本、CRUD 一发版、流程模型一存历史,就会缺表。典型受害者包括:
ai_business_extension_versionai_business_application_versionai_crud_config_versionsys_flow_model_version/sys_flow_form_versionsys_print_template_version- …
定稿注释与规则变为(脚本约 L229–L231,commit 1dcf6607):
# Flowable 引擎表由应用首次启动创建;社区纯净版/安全全量导出不得带 act_*/flw_*
# 注意:不要用 (^|_)version$ —— 会误伤 ai_business_extension_version 等框架表
full_ignore_regex="^act_|^flw_"
pure-sql-export.md 与 forge-project-init SKILL 同步:Never 再加 (^|_)version$。V1.2.0 SQL 补回上述 *_version 的空结构 DDL(可无业务数据)——纯净版要的是「能跑起来的骨架」,不是「演示数据拉满」。
这是典型的「正则写宽了」事故:本想少导出一点噪音,结果把框架契约表当成噪音。和只跳 act_* 一样,都属于 ignore 规则的产品语义没钉死。
根因三:手工「删 flw_*」可能顺手删掉 admin
commit ad5da3d6 记录了另一次返工:旧 dump 仍含 flw_* 时,有人用编辑器/脚本从第一个 flw_* 数据段一路 skip 到文件尾。mysqldump 的 data 段按表名排序,flw_* 后面往往是 sys_*——于是 sys_user、sys_dict_data、sys_config、sys_resource 的 INSERT 全部消失。导入后「库能建起来,但登不进 admin、菜单字典全空」。
文档因此补了两条硬约束:
- 删除时必须按表一块一块删(每个
Table structure/Dumping data块各自结束); - 优先依赖已修复的
dump-safe-full.sh,避免事后剥离。
验收清单(导入空库后):
| 检查项 | 期望 |
|---|---|
| 导入 ERROR | 0 |
sys_user / sys_tenant / sys_role | 各 1 行,admin |
sys_dict_type / sys_dict_data / sys_config / sys_resource | 有数据 |
forge_schema_history | 有数据,版本与源库一致 |
act_% / flw_% 表数量(启动前) | 0 |
| 全文检索 | 无 AKID / LTAI / 真实库密码 / 云密钥 |
Forge 怎么落地:脚本 + skill + pitfalls 三件套
框架侧没有把规则只写在某次聊天记录里,而是收敛到三处,保证「下次再导纯净版」可重复:
1)导出流水线(必须在克隆库上操作)
# 1) 克隆测试库 → 临时库(禁止对共享库直接 --execute 清理)
mysqldump … forge_admin | mysql … forge_admin_vXXX_pure
# 2) 清理成模板库(forge-server 下)
MYSQL_PWD=*** bash scripts/db/clean-db.sh \
--host … --database forge_admin_vXXX_pure --user … --execute --yes
# 3) 安全导出(须跳过 act_* 与 flw_*)
MYSQL_PWD=*** bash scripts/db/dump-safe-full.sh \
--host … --database forge_admin_vXXX_pure --user … \
--output /tmp/forge-admin-pure-base.sql
# 4) 可选追加:forge_schema_history + 本地无密钥的 sys_file_storage_config
# 5) 清洗 installed_by(如 rdsroot→flyway);全文确认无 CREATE TABLE `flw_` / `act_`
# 且仍有 INSERT INTO `sys_user` / 字典 / 参数
文件名建议:ForgeAdmin-纯净版-V{版本}.sql。大 SQL 默认不要误提交进业务仓库,除非明确要求;文档站走运营后台「纯净版 SQL」上传即可。
2)已误导入带 flw_* 的库(急救)
按源码推演,可在该目标库按实际表名调整后删除残留 flw_*(示例见 pure-sql-export.md:flw_ru_batch、flw_event_*、flw_channel_definition、flw_ev_databasechangelog* 等),再重启 Admin/Flow 让引擎重建。更稳妥:空库重导已去掉全部 flw_/act_ 的纯净版文件——比在脏库上「外科手术」更少二次踩坑。
3)对照表(可收藏)
| 做法 | 典型结果 | Forge 定稿 |
|---|---|---|
只 ignore ^act_ | 半套 flw_* → already exists + version null | 不够 |
ignore ^act_|^flw_|(^|_)version$ | 引擎表对了,框架 *_version 缺表 | 禁止 version 段 |
ignore ^act_|^flw_ | 启动前 0 张引擎表;框架版本表保留 | 定稿 |
| 手工从 flw_* skip 到 EOF | 可能误删 sys_* INSERT | 按表块删或重导 |
导出后追加 act_ge_property INSERT | 1146 表不存在 | 禁止 |
| 8 污染库只改 version 回 7.x | Liquibase 表再 already exists | 另见版本混用 pitfalls |
三次返工时间线(方便对照 commit)
| 顺序 | SHA(短) | 做了什么 | ||
|---|---|---|---|---|
| 1 | fc753e11 | 记录 Flowable 8→7 版本混用;纳入纯净版 V1.2.0 SQL | ||
| 2 | 88d17508 | dump 增加跳过 flw_*;写 pure-sql-export;从 V1.2.0 去掉半套 flw_* | ||
| 3 | ad5da3d6 | 修复剥离时误删的 admin/字典/参数等基础数据 | ||
| 4 | 1dcf6607 | 去掉 `(^ | _)version$;补回框架 *versionDDL;定稿^act | ^flw_` |
叙事上这是一条「想做对 → 规则偏窄 → 规则又偏宽 → 手工返工误伤」的完整闭环。对开源后台框架来说,导出脚本的正则就是产品契约:写错一次,社区下载方全员踩坑。
可带走的自查清单
导出或审核「纯净版 SQL」前,建议按序过一遍:
- 全文检索:是否还有
CREATE TABLE \flw_/CREATE TABLE `act_`? - 是否误带
INSERT INTO act_ge_property/act_id_property? dump-safe-full.sh的full_ignore_regex是否仅为^act_|^flw_?- 是否没有
(^|_)version$?纯净版是否含CREATE TABLE \ai_business_extension_version`` 等? - 是否有
INSERT INTO \sys_user`` / 字典 / 参数 / 资源? - 空库导入后、启动前:
act_%/flw_%表数是否为 0? - 启动后:引擎表是否由应用创建?Flyway 是否显示已是最新?
admin/123456(默认)能否登录?本地上传配置是否仅 local、无云密钥?
做完这七步,再谈「要不要追加演示菜单、要不要带低代码样例表」——后者是产品选择,前者是能不能启动的底线。
框架视角:为什么规则要进脚本,而不是进 README 一句「注意」
若只在文档写「导出时请手动排除流程表」,每个运营同学、每个版本、每次克隆库都会重新发明一套 ignore 列表,最终一定有人只记得 act_*。Forge 的选择是:
- 脚本默认正确:
dump-safe-full.sh的full_ignore_regex就是契约; - skill 可执行:
forge-project-init的纯净导出步骤可被 agent / 人复跑; - pitfalls 可检索:现场报错关键词能搜回「半套 flw_*」「version 正则误伤」。
这和「业务模块里临时手改一份 SQL」是两种产品观。后者能糊过一次发布,前者才能让社区下载页长期可点。
和本系列其它文的差异
- 不是「Boot4 缺
applicationTaskExecutor+ Sa-Token 旧 Session」(10-13 已发); - 不是「MyBatis-Plus 分页 COUNT(*) 解析失败」(10-12);
- 不是「插件独立 Flyway / FeatureGate / 离线许可证」(10-11);
- 不是「单据打印两层校验 / 头像预签名」(更早);
- 本篇切口是 社区初始化 SQL 的表前缀契约:
act_*与flw_*必须成套跳过,框架*_version不能被正则误伤,手工剥离不能误删sys_*。
Forge Admin 把这些写进导出脚本、skill 与 pitfalls:业务侧下载纯净版时少踩「半套引擎表」的坑。源码检索关键字:dump-safe-full.sh、full_ignore_regex、pure-sql-export.md、commits 88d17508 / ad5da3d6 / 1dcf6607。