# geng-dev **Repository Path**: freehacker/geng-dev ## Basic Information - **Project Name**: geng-dev - **Description**: Geng Dev(庚·开发)是面向企业级应用建设的开源流程编排与低代码开发平台,融合可视化流程、AMIS 页面、动态数据模型、Query DSL、脚本扩展、权限治理和应用发布能力,让流程与应用一起生长。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-22 - **Last Updated**: 2026-08-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # DevFlow DevFlow 是一个面向企业后台应用的流程编排与低代码开发平台。项目将可视化流程设计、流程运行与调试、动态代码节点、低代码数据模型、AMIS 页面运行时、Query DSL、多租户和 RBAC 权限管理整合在同一套前后端工程中。 当前仓库已经形成两条可以协同工作的主线: - **流程自动化**:使用可视化画布编排条件、循环、HTTP、数据库、代码和大模型节点,并提供实时调试、运行日志、实例追踪及开放接口。 - **低代码应用**:通过应用、模型、选项集、页面、动作、导航、修订和发布构建独立后台应用,运行端使用 AMIS 动态渲染。 低代码动作可以调用 DevFlow 流程,流程代码节点又可以通过受控 Query DSL 查询已发布低代码模型,因此两套能力不是相互独立的功能集合,而是可以组成完整业务应用的统一平台。 > 项目仍处于持续开发阶段。README 中“已实现”的内容均以当前仓库代码为准;尚未完成的企业级能力会在“当前边界”中单独说明。 ## 目录 - [核心能力概览](#核心能力概览) - [系统架构](#系统架构) - [流程编排与执行](#流程编排与执行) - [低代码应用平台](#低代码应用平台) - [Query DSL](#query-dsl) - [系统管理与安全](#系统管理与安全) - [技术栈](#技术栈) - [项目结构](#项目结构) - [快速开始](#快速开始) - [配置说明](#配置说明) - [常用接口](#常用接口) - [构建与测试](#构建与测试) - [数据存储与版本迁移](#数据存储与版本迁移) - [生产部署提示](#生产部署提示) - [当前边界](#当前边界) - [相关文档](#相关文档) ## 核心能力概览 | 领域 | 已实现能力 | | --- | --- | | 流程设计 | Flowgram 自由布局画布、节点拖拽、连线、分组、注释、复制粘贴、缩放、导入导出、流程定义保存与复制 | | 流程节点 | 开始、结束、条件、多条件、变量、循环、HTTP、数据库、代码、LLM,以及循环内部的控制节点 | | 流程运行 | 草稿试运行、正式执行、SSE 实时事件、节点状态、输入输出日志、实例记录、取消执行 | | 动态代码 | JavaScript、Java、Groovy,Monaco 编辑器,默认沙箱,`params`、`vars`、`select`、`spring` 运行时对象 | | 外部集成 | HTTP 请求、命名/默认/直连数据源、AI 模型调用、带应用凭据和流程授权的开放 API | | 低代码设计 | 应用、数据模型、公共选项集、生成式页面、自由 AMIS 页面、流程动作、导航、修订和发布 | | 低代码运行 | 独立 AMIS 运行端、应用品牌、明暗主题、树形菜单、面包屑、多窗口页签、Hash 地址 | | 数据管理 | 每模型独立物理表、CRUD、分页、搜索、乐观锁、软删除、变更历史、CSV 导入导出、聚合与图表 | | 查询内核 | JSON Query DSL、Java Fluent DSL、参数绑定、递归条件、排序、分页、聚合、分组、受治理 JOIN、执行引擎 SPI | | 平台治理 | 登录认证、租户上下文、用户、角色、资源、组织、岗位、字典、操作日志和权限快照 | | 数据库演进 | Flyway 固定 Schema 迁移、旧库兼容迁移、低代码动态表演进、一次性运行时数据迁移登记 | ## 系统架构 ```text ┌────────────────────────────────────────────────────────────────────┐ │ Web 前端 │ │ │ │ Portal 管理端 Flow Builder AMIS Runtime │ │ 用户/权限/流程/Studio 可视化流程设计器 已发布应用运行端 │ └──────────┬───────────────────────┬──────────────────────┬──────────┘ │ │ │ └───────────────────────┴──────────────────────┘ │ HTTP / SSE ▼ ┌────────────────────────────────────────────────────────────────────┐ │ Spring Boot 应用 │ │ │ │ 身份与权限 流程定义/实例/日志 低代码设计态 低代码运行态 │ │ │ │ │ │ │ │ │ Solon Flow 执行内核 │ Query DSL │ │ │ 节点处理器与脚本门面 │ │ │ │ └────────────────┴─────────────────┴───────────────┘ │ │ Application / Domain │ │ │ │ │ Repository / Engine / Target SPI │ └──────────────────────────────────────┬─────────────────────────────┘ │ ┌──────────────────┴──────────────────┐ ▼ ▼ PostgreSQL / MyBatis-Flex Redis 平台表、发布快照、lc_biz_* 业务表 登录态与 Sa-Token ``` 后端按 `interfaces`、`application`、`domain`、`infrastructure` 分层,并保留正在收敛的 `legacy` 兼容实现。低代码查询层通过 `Engine`、`TargetProvider` 和 `TargetResolver` 抽象逻辑查询与物理存储,平台代码不直接向流程脚本暴露 MyBatis-Flex、连接对象或物理表名。 ## 流程编排与执行 ### 可视化设计器 流程设计器基于 Flowgram Free Layout Editor,当前支持: - 自由布局画布、节点拖拽和端口连线。 - 节点面板、连线快捷添加、节点复制、粘贴、删除和全选。 - 画布缩放、折叠、分组、注释及小地图等设计辅助能力。 - 节点表单配置、输入输出定义和变量引用。 - JSON/YAML 流程文档导入导出。 - 新建、更新、复制、查询和删除流程定义。 - 按流程标识、名称、分组和启用状态分页检索。 - 在设计器中直接发起草稿试运行,无需先覆盖正式流程定义。 Portal 使用 Hash Router,流程设计地址示例: ```text http://localhost:8899/#/flow/designer?key=demo_flow ``` ### 节点类型 | 节点 | 标识 | 主要用途 | 典型输出 | | --- | --- | --- | --- | | 开始 | `start` | 定义流程入口和输入参数 | 配置的流程入参 | | 结束 | `end` | 汇总并定义流程返回值 | 最终业务结果 | | 条件 | `condition` | 真/假二分支 | 命中的分支 | | 多条件 | `multi-condition` | 多个条件分支和兜底分支 | 命中的分支 | | 变量 | `variable` | 声明、覆盖或计算流程变量 | 新变量值 | | 循环 | `loop` | 迭代集合并执行子画布 | 每次迭代和聚合结果 | | HTTP | `http` | 调用远程 HTTP 服务 | `body`、`statusCode`、`headers` | | 数据库 | `db` | 执行参数化查询或更新 | `rows`、`affectedRows`、`rowCount` | | 大模型 | `llm` | 调用配置的 AI Chat 模型 | 模型响应内容 | | 代码 | `code` | 执行 JavaScript、Java 或 Groovy | 脚本返回对象 | 循环画布还包含 `block-start`、`block-end`、`break` 和 `continue` 等内部控制节点。 ### 值解析与变量 节点字段支持四类值来源: | 类型 | 用途 | 示例 | | --- | --- | --- | | `constant` | 直接使用字面量 | `"VIP"`、`100` | | `ref` | 引用节点输出或流程全局变量 | `["customerNode", "name"]` | | `expression` | 使用表达式动态计算 | 条件判断、数值计算 | | `template` | 在文本中插入上下文变量 | `客户 ${name} 审批通过` | 运行上下文会记录流程入参、全局变量和各节点输出。节点可以按节点 ID 或配置的节点代码引用前序结果,结束节点负责将内部上下文转换为明确的流程输出。 ### 运行、调试与追踪 - `run` 和 `test-run` 统一启动异步调试执行。 - 通过 SSE 持续推送流程开始、节点开始、节点完成、节点失败和流程结束等事件。 - 设计器实时显示节点状态和格式化后的运行日志。 - 支持在流程执行期间发起取消。 - 流程实例保存当前节点、流程数据和运行状态。 - 流程日志支持按流程、实例、节点、动作、状态、关键词和时间范围检索。 - 支持查看日志详情、按实例读取日志、单条删除和批量删除。 ### HTTP 节点 HTTP 节点用于对接外部服务,可配置请求地址、方法、请求头、查询参数和请求体。请求配置可以引用流程变量,执行结果会统一整理为响应体、状态码和响应头供后续节点使用。 ### 数据库节点 数据库节点支持查询、新增、修改、删除和自定义 SQL,并提供三种连接方式: - `default`:使用平台默认数据源。 - `named`:引用 `application.yml` 中 `flow.db.datasources` 配置的命名数据源。 - `direct`:在节点中提供直连配置,适合受控环境下的临时集成。 SQL 推荐使用命名参数,例如: ```sql SELECT * FROM customer WHERE organization_id = :organizationId LIMIT :limit ``` 平台根据查询或更新类型返回 `rows`、`affectedRows`、`rowCount`、`sqlType` 和 `datasourceMode`。数据库节点用于通用外部数据库集成;低代码模型数据查询应优先使用 Query DSL,以获得模型校验、租户隔离和可替换执行引擎。 ### LLM 节点与 AI 调用 LLM 节点通过 Solon AI Flow 及配置的模型地址执行对话,可在节点提示词中组合流程变量。后端同时提供普通 Prompt 和 System Prompt 两种 AI Chat 接口。默认配置指向本地 Ollama 兼容地址,可在 `application.yml` 中修改模型 URL、API Key 和模型名称。 ### 代码节点 代码节点支持: - JavaScript:GraalVM JavaScript ScriptEngine。 - Java:Liquor 动态编译执行。 - Groovy:GroovyShell。 - Monaco 代码编辑器、语法高亮和基础代码提示。 - 默认开启脚本沙箱;JavaScript 和 Groovy 对文件、网络、线程、反射、进程等危险能力进行限制。 脚本运行时对象如下: | 对象 | 说明 | | --- | --- | | `params` | 当前代码节点解析后的输入参数 | | `vars` | 流程实例全局变量 | | `select` | 查询已发布低代码应用数据的受控门面 | | `spring` | 调用显式标注为流程可调用的 Spring Service | JavaScript 示例: ```javascript function main({ params, select, spring }) { const page = select.from("crm", "crm_customer") .contains("name", params.keyword) .eq("level", "VIP") .orderByDesc("updatedTime") .page(1, 20) .fetch(); const summary = spring.call("customerStatistics", "summarize", { customerIds: page.items.map(item => item.bizId) }); return { customers: page.items, total: page.total, summary }; } ``` 普通 Spring Bean 不会自动暴露给脚本。业务服务必须显式使用 `@FlowCallable`: ```java import dev.daoyou.flow.application.flow.script.FlowCallable; @FlowCallable("customerStatistics") public class CustomerStatisticsService { public Statistics summarize(StatisticsCommand command) { return calculate(command); } } ``` 这样可以保留 Spring Service 的领域边界,同时避免脚本任意获取 `ApplicationContext` 或平台内部 Bean。更完整的脚本规范参见 [流程代码节点文档](docs/flow-code-node.md)。 ### 流程开放 API 平台提供两级开放能力: - 开放应用:维护应用标识、密钥、签名算法、时钟偏差和启停状态。 - 流程授权:按流程或流程分组授予开放应用执行权限。 开放调用统一进入 `/api/open/flow/execute`,服务端负责身份校验、签名校验、授权校验和执行。密钥支持重置,敏感配置使用平台主密钥加密保存。 ## 低代码应用平台 ### 设计原则 低代码内核采用“元数据 + 不可变修订 + 发布快照 + AMIS 运行时”的方式: ```text Studio 草稿 │ 保存修订 ▼ lc_artifact / lc_artifact_revision │ 发布并编译 ▼ lc_release / lc_release_item │ 当前发布版本 ├──────────► AMIS 页面与导航 ├──────────► Query DSL 模型查询 └──────────► lc_biz_{modelKey} 业务表 ``` Studio 编辑的是草稿,独立运行端读取的是应用当前发布快照。草稿变更不会直接影响正在使用的应用,重新发布后运行端才切换到新版本。 ### 应用管理 应用中心支持创建、修改和删除应用,并提供进入应用及进入 Studio 的入口。应用级设置包括: - 稳定且租户内唯一的 `appKey`。 - 应用名称和说明。 - 应用图标。 - `LIGHT` 白天主题和 `DARK` 暗色主题。 - `COLLAPSIBLE` 展开收缩菜单和 `SECTION` 分组小字菜单。 - 应用状态和当前发布版本。 `appKey` 创建后不可修改,用于运行地址、发布快照和逻辑 API 定位。 ### 制品、修订与发布 | 制品 | 当前用途 | | --- | --- | | `MODEL` | 数据模型、字段、类型、必填、只读、可查询和选项集引用 | | `OPTION_SET` | 多模型复用的公共选项数据 | | `PAGE` | 生成式 CRUD 页面或自由 AMIS Schema | | `ACTION` | 调用一个已启用的 DevFlow 流程 | | `NAVIGATION` | 默认页、菜单分组、菜单项和图标 | | `VIEW` | 已预留枚举,尚未形成完整设计与运行能力 | | `THEME` | 已预留枚举;当前主题保存在应用设置 | 同一制品每次保存都会生成新的不可变修订,不覆盖历史 JSON。发布时平台会: 1. 读取各制品最新修订。 2. 重新校验模型、页面、选项集和导航引用。 3. 将生成式页面编译成 AMIS Schema。 4. 生成包含 SHA-256 校验值的不可变 manifest。 5. 记录发布版本与各制品修订的对应关系。 6. 演进模型对应的独立物理表。 7. 将应用当前版本切换到新发布版本。 ### 数据模型 模型支持以下字段类型: | 类型 | 说明 | 常见 AMIS 控件 | | --- | --- | --- | | `string` | 短文本 | `input-text` | | `text` | 长文本 | `textarea` | | `integer` | 整数 | `input-number` | | `decimal` | 小数 | `input-number` | | `boolean` | 布尔值 | `switch` | | `date` | 日期 | `input-date` | | `datetime` | 日期时间 | `input-datetime` | | `select` | 公共选项 | `select` | 字段可以配置: - 字段标识、显示名称和数据类型。 - 是否必填。 - 是否允许作为查询条件。 - 是否只读(后端和编译器已支持;Studio 当前尚未提供对应勾选项)。 - `select` 字段引用的公共选项集。 模型标识全局唯一,发布后会创建 `lc_biz_{modelKey}` 业务表。例如: ```text 模型 crm_customer -> 表 lc_biz_crm_customer 模型 service_order -> 表 lc_biz_service_order ``` 每个模型独立表避免所有应用数据集中在一个 JSONB 大表中。业务字段使用真实 PostgreSQL 列,平台统一维护: - `tenant_id`:租户隔离。 - `biz_id`:UUID 业务主键。 - `revision`:乐观锁版本。 - `deleted`:软删除标识。 - 创建、修改等审计时间。 模型发布只执行安全的增量演进,例如创建表、新增字段和索引;不会自动删除旧列或执行高风险字段类型收缩。 ### 公共选项集 公共选项集用于集中维护多个模型共享的下拉值,避免在每个模型和页面中重复配置: ```json { "name": "客户等级", "options": [ { "label": "普通", "value": "NORMAL", "enabled": true }, { "label": "重点", "value": "VIP", "enabled": true } ] } ``` 已实现的规则: - `select` 字段引用公共选项集。 - 运行表单通过 `lc://options/{optionSetKey}` 加载启用选项。 - 列表自动将存储值映射为显示名称。 - 新增、修改和导入会拒绝不存在或已停用的选项值。 - 被模型引用的选项集不能删除。 - 选项修改后需要重新发布应用。 ### 生成式 CRUD 页面 生成式页面只需要选择模型并配置页面信息,发布时由服务端编译出 AMIS CRUD。当前包含: - 模型字段列表。 - 服务端分页。 - 勾选为可查询字段的搜索表单。 - 查询和重置按钮。 - 新增、编辑、删除。 - 操作完成后自动刷新。 - 手动刷新和列显示切换。 - CSV 导入和导出。 - 底部统计、每页条数切换、页码和跳转分页工具栏。 - 公共选项动态加载和列表值映射。 - 新增/编辑表单 1~4 列动态布局。 页面定义示例: ```json { "type": "GENERATED", "title": "客户档案维护", "modelKey": "crm_customer", "formColumns": 3 } ``` CSV 导入最大 5 MB、单次最多 5000 条;任一行校验失败会回滚整批导入。CSV 导出沿用当前查询条件,最多导出 10000 条。 ### 自由 AMIS 页面 `CUSTOM_AMIS` 页面可以直接保存完整 AMIS Schema,用于构建看板、图表、复杂表单、详情页和组合工作台。页面中的 API 推荐使用逻辑协议: ```text lc://model/{modelKey}/records lc://model/{modelKey}/records/{bizId} lc://model/{modelKey}/records/import lc://model/{modelKey}/records/export lc://model/{modelKey}/query lc://model/{modelKey}/query/validate lc://model/{modelKey}/aggregate lc://options/{optionSetKey} lc://action/{actionKey} ``` 公共 fetcher 会把 `lc://` 转换为当前应用的后端地址,Schema 不需要写死主机、端口或应用标识。服务端递归检查 Schema 中的 API,目前只接受 `lc://...` 和同源 `/api/...`。 ### 聚合与图表 模型聚合接口支持: - `count`、`sum`、`avg`、`min`、`max`。 - 按模型字段分组。 - 日期按时间桶聚合。 - 公共选项值自动转换为显示名称。 - 直接生成 `pie`、`bar`、`line` ECharts 配置供 AMIS `chart.api` 使用。 示例: ```text lc://model/crm_customer/aggregate?metric=count&groupBy=level&chart=pie lc://model/service_order/aggregate?metric=sum&field=amount&groupBy=createdTime&bucket=month&chart=line ``` ### 动作 当前动作类型为 `FLOW`,用于把页面操作连接到流程: ```json { "type": "FLOW", "flowKey": "customer_approval" } ``` Studio 使用流程下拉框选择已启用流程。调用 `lc://action/{actionKey}` 时,后端同步执行流程,并返回实例标识、状态和输出。每次执行都会写入 `lc_action_execution`,保存输入、输出、成功或失败状态及错误信息。 ### 导航与独立运行端 应用运行端使用 AMIS `app`、`nav`、`tabs` 和 `breadcrumb` 等原生组件,支持: - 应用图标和名称。 - 菜单分组和菜单项图标。 - 展开收缩或分组小字两种导航模式。 - 白天和暗色主题。 - 面包屑。 - 多窗口页签、切换和关闭。 - 默认首页保护。 - 使用浏览器 `localStorage` 恢复已打开页签。 运行端读取 `NAVIGATION/main`。应用地址使用 Hash 参数,适合 Nginx 静态文件部署: ```text http://localhost:5176/#/?appKey=test&pageKey=crm_dashboard ``` 旧格式 `/?appKey=...` 仍可读取,运行端会规范为 Hash 地址。 ### 运行时数据接口 运行端提供: - 页面和导航读取。 - 模型记录分页查询、单条读取、新增、修改和删除。 - Query DSL 执行和仅校验。 - CSV 导入导出。 - 聚合和图表数据。 - 公共选项读取。 - 低代码动作执行。 新增和修改统一执行字段白名单、数据类型、必填、只读和选项值校验。修改时提交 `_revision` 会进行乐观锁检查,删除使用软删除,变更历史写入 `lc_model_record_history`。 ## Query DSL Query DSL 是低代码模型与具体存储实现之间的稳定查询协议。调用者只使用应用、模型和逻辑字段,不允许提交物理表名、物理列名、原生 SQL 或 `QueryWrapper`。 ### 执行链 ```text JSON Query DSL ──► Parser ─┐ ├─► Statement ─► Planner ─► Plan Java Fluent DSL ───────────┘ │ ▼ TargetResolver / Registry │ ▼ Engine SPI │ relational / MyBatis-Flex │ ▼ Db + Row ``` ### 已支持能力 - 单模型字段投影和结果别名。 - 递归 `AND` / `OR` 条件。 - 字面量和命名参数。 - `EQ`、`NE`、比较、区间、集合、模糊匹配、空值判断等操作符。 - 多字段升序和降序排序。 - 分页和总数。 - `COUNT`、`SUM`、`AVG`、`MIN`、`MAX` 聚合。 - `GROUP BY`。 - 基于已发布模型关系的 `INNER JOIN` 和 `LEFT JOIN`。 - 模型字段、类型、`searchable` 权限和复杂度校验。 - 自动附加当前租户和软删除条件。 - 查询引擎能力声明、注册和路由。 默认分页从 1 开始,每页 20 条,服务端单页最多 200 条。当前关系型引擎使用 MyBatis-Flex `QueryWrapper` 编译逻辑计划,并通过 `Db + Row` 执行。 Query DSL 2.0 使用模型中预定义的 `relations` 进行 JOIN,不允许客户端提交物理表名或 自由 `ON`。当前支持同一应用发布快照、同一查询引擎内的 `ONE_TO_ONE` 和 `MANY_TO_ONE` 关系,最多关联 5 个模型。流程代码节点可使用 `.as(...).leftJoin(...)` 或 `.innerJoin(...)`。 ### Java Fluent DSL 平台 Java 服务和编译期扩展可以直接注入 `Select`: ```java List customers = select .from("crm", "crm_customer") .fields("name", "phone", "amount") .contains("name", keyword) .ge("amount", minimumAmount) .when(level != null, source -> source.eq("level", level)) .orderByDesc("updatedTime") .page(1, 20) .list(); ``` 需要分页元数据时: ```java Page page = select .from("crm", "crm_customer") .eq("level", "VIP") .page(1, 20) .fetch(); ``` 复杂嵌套条件、聚合和需要保存查询定义的场景可以使用 `Selects` 构造 `Statement`,再交给 `Operations` 执行。 ### JSON DSL ```json { "query": { "version": "1.0", "source": { "model": "crm_customer", "alias": "customer" }, "select": [ { "field": "customer.name", "as": "name" }, { "field": "customer.level", "as": "level" } ], "where": { "logic": "AND", "items": [ { "field": "customer.name", "operator": "CONTAINS", "value": { "type": "PARAM", "name": "keyword" } } ] }, "orderBy": [ { "field": "customer.updatedTime", "direction": "DESC" } ], "pagination": { "page": 1, "perPage": 20 } }, "params": { "keyword": "科技" } } ``` HTTP 接口: ```text POST /api/lowcode/runtime/apps/{appKey}/models/{modelKey}/records/query POST /api/lowcode/runtime/apps/{appKey}/models/{modelKey}/records/query/validate ``` 查询内核已经预留 Elasticsearch 引擎标识和 SPI,但当前仓库只实现了 `relational` 引擎;ES 客户端、索引生命周期、数据同步和执行适配器尚未实现。完整协议参见 [Query DSL 文档](docs/lowcode-query-dsl.md)。 ## 系统管理与安全 ### 身份认证 - 用户登录、注册、退出和当前用户信息。 - Sa-Token 登录态。 - Redis 会话存储。 - Token 使用 UUID 风格,默认 Header 名为 `satoken`。 - 前端请求自动携带 Token 和 `X-Tenant-Id`。 - 密码使用 BCrypt;升级代码兼容旧 MD5 密码并执行迁移。 ### RBAC 权限 - 用户管理和用户角色分配。 - 角色管理和角色资源分配。 - 资源/菜单管理。 - 用户、角色、权限关系查询。 - 登录后返回资源、菜单、角色、租户和超级管理员快照。 - Portal 根据菜单和能力控制页面访问。 - 流程执行校验 `button:flow:execute` 权限。 ### 组织、岗位与字典 - 组织增删改查、分页和树形结构。 - 岗位增删改查和分页。 - 字典及字典项维护。 - 按字典编码获取下拉选项。 - 用户与主组织关系。 ### 多租户 平台表和低代码业务数据使用 `tenant_id` 隔离。MyBatis-Flex 租户配置、请求租户上下文和低代码查询计划共同约束数据范围。Query DSL 强制追加租户与软删除条件,用户顶层 `OR` 也不能绕过平台条件。 ### 操作日志 写操作通过 `@Log` 和拦截器记录操作日志,包含请求信息、操作说明、用户、租户和执行结果。管理端支持分页、详情、单条删除和批量删除。 ## 技术栈 ### 后端 | 技术 | 当前版本/用途 | | --- | --- | | Java | 开发环境使用 JDK 25,Maven 编译目标为 Java 21 | | Spring Boot | 4.0.6 | | PostgreSQL | 默认平台数据库 | | MyBatis-Flex | 1.11.6,固定表持久化及低代码动态表 `Db + Row` | | Flyway | 固定 Schema 和兼容升级 | | Sa-Token | 1.45.0,认证和会话 | | Redis | Sa-Token 会话存储 | | Solon Flow / Solon AI Flow | 3.10.3,流程与 AI 流程执行 | | Liquor | 1.6.3,Java 动态代码及表达式 | | GraalVM JavaScript | 24.1.2 | | Groovy | 动态 Groovy 脚本 | | AgentScope / OpenAI Java | AI 集成基础能力 | ### 前端 | 技术 | 用途 | | --- | --- | | React 18 + TypeScript | Portal、流程设计器和运行端 | | pnpm workspace | 前端 Monorepo | | Vite / Rsbuild | 应用开发和构建 | | Flowgram 1.0.11 | 可视化流程设计器 | | AMIS 6.10 | 低代码页面和独立应用运行壳 | | AMIS Editor 6.13 | Studio 自由页面编辑 | | Ant Design / Semi UI | Portal 和流程设计器组件 | | Monaco Editor | 代码节点编辑 | | TanStack Query / Axios | 请求与客户端状态 | | Zustand / CASL / AJV | 状态、权限能力和 Schema 校验 | ## 项目结构 ```text dev-flow/ ├── backend/ │ └── process-orchestration/ │ ├── pom.xml │ └── src/ │ ├── main/java/ │ │ ├── db/migration/ # Java Flyway 迁移 │ │ └── dev/daoyou/flow/ │ │ ├── interfaces/ # HTTP Controller、DTO │ │ ├── application/ # 用例编排、Query DSL、脚本门面 │ │ ├── domain/ # 领域实体、规则和抽象 │ │ ├── infrastructure/ # 持久化、执行器、配置和适配器 │ │ └── legacy/ # 正在逐步收敛的兼容服务 │ ├── main/resources/ │ │ ├── application.yml │ │ ├── db/init.sql │ │ ├── db/migration/ # SQL Flyway 迁移 │ │ └── flow/ # 示例流程 │ └── test/java/ # 单元及 Controller 测试 ├── frontend/ │ ├── apps/ │ │ ├── portal/ # 统一管理端与低代码 Studio │ │ ├── flow-builder/ # Flowgram 流程设计器 │ │ └── runtime/ # 独立 AMIS 应用运行端 │ ├── packages/ │ │ ├── api-client/ # API、鉴权和 lc:// fetcher │ │ ├── auth/ # 登录状态 │ │ ├── flow-engine/ # 流程客户端能力 │ │ ├── permission/ # CASL 权限 │ │ ├── schema-engine/ # 低代码 Schema 和路由工具 │ │ ├── tenant/ # 租户状态 │ │ └── ui-components/ # 公共组件 │ ├── package.json │ └── pnpm-workspace.yaml ├── docs/ # 实现说明与第三方参考文档 ├── restart-dev.sh # 本地一键重启 └── README.md ``` `frontend/apps/app-builder` 当前仅保留历史构建产物,不属于 pnpm workspace 中的活动应用;低代码 Studio 已集成到 `portal`。 ## 快速开始 ### 环境要求 | 依赖 | 建议版本 | | --- | --- | | JDK | 25 | | Maven | 3.9+ | | Node.js | 24 | | pnpm | 10.5.2(仓库 `packageManager` 声明版本) | | PostgreSQL | 14+ | | Redis | 6+ | 检查环境: ```bash java -version mvn -v node -v pnpm -v psql --version redis-cli --version ``` ### 初始化 PostgreSQL 默认开发配置: ```text 数据库:dev_flow 地址:localhost:5432 用户:postgres 密码:123456 ``` 创建数据库: ```bash createdb -h localhost -U postgres dev_flow ``` 不需要手工执行 `init.sql`。后端第一次启动时,Flyway 会自动创建和升级固定表结构。 ### 启动 Redis 默认连接: ```text 地址:127.0.0.1:6379 密码:123456 数据库:0 ``` 如本机 Redis 配置不同,请先修改后端 `application.yml`。 ### 安装前端依赖 首次运行: ```bash cd frontend corepack enable pnpm install cd .. ``` ### 一键启动 ```bash bash restart-dev.sh ``` 脚本会停止占用开发端口的旧进程,启动后端和全部 pnpm workspace 开发应用,并持续输出后端日志。 默认地址: | 服务 | 地址 | | --- | --- | | Portal 管理端 | `http://localhost:8899/` | | 后端 API | `http://localhost:9696/` | | 流程设计器独立开发服务 | `http://localhost:5175/` | | 低代码应用运行端 | `http://localhost:5176/` | 默认账号: ```text 用户名:admin 密码:123456 ``` 该账号仅用于本地开发,生产部署必须立即修改默认密码和示例密钥。 ### 分别启动 后端: ```bash cd backend/process-orchestration mvn -Dmaven.test.skip=true spring-boot:run ``` 全部前端应用: ```bash cd frontend pnpm dev ``` 只启动某个前端应用: ```bash cd frontend pnpm --filter @devflow/portal dev pnpm --filter @devflow/flow-builder dev pnpm --filter @devflow/runtime dev ``` ### 日志 一键启动日志位于: ```text .devflow/logs/backend.log .devflow/logs/frontend.log ``` 实时查看: ```bash tail -f .devflow/logs/backend.log tail -f .devflow/logs/frontend.log ``` ### 第一个流程 1. 登录 Portal。 2. 进入“流程管理 / 流程定义”。 3. 新建流程并设置唯一流程标识。 4. 从开始节点连接业务节点,再连接结束节点。 5. 保存后点击试运行,填写开始节点入参。 6. 在运行面板观察 SSE 节点状态和日志。 7. 启用流程后,可以从低代码动作或开放 API 调用。 ### 第一个低代码应用 1. 进入“低代码 / 应用中心”并创建应用;`appKey` 创建后不可修改。 2. 进入 Studio,在“应用设置”配置名称、图标、主题和菜单模式。 3. 创建公共选项集。 4. 创建数据模型,配置字段、必填、可查询和选项集。 5. 创建生成式页面,选择模型并设置表单列数。 6. 如需业务编排,创建动作并选择一个已启用流程。 7. 创建标识为 `main` 的导航,设置默认页、分组和菜单项。 8. 新建发布版本。 9. 从应用中心进入应用,或访问: ```text http://localhost:5176/#/?appKey={appKey}&pageKey={pageKey} ``` ## 配置说明 主要配置文件为 `backend/process-orchestration/src/main/resources/application.yml`。 | 配置 | 默认值 | 说明 | | --- | --- | --- | | `server.port` | `9696` | 后端端口 | | `spring.datasource.url` | `jdbc:postgresql://localhost:5432/dev_flow` | 平台数据库 | | `spring.datasource.username` | `postgres` | 数据库用户 | | `spring.datasource.password` | `123456` | 数据库密码 | | `spring.flyway.enabled` | `true` | 启用版本迁移 | | `spring.flyway.clean-disabled` | `true` | 禁止 Flyway clean | | `spring.data.redis.host` | `127.0.0.1` | Redis 地址 | | `spring.data.redis.port` | `6379` | Redis 端口 | | `spring.data.redis.password` | `123456` | Redis 密码 | | `flow.definition-path` | `/data/flow-definitions` | 流程定义文件路径 | | `flow.db.datasources` | `{}` | DB 节点命名数据源 | | `flow.open-api.crypto.master-key` | 开发默认值 | 开放接口密钥加密主密钥 | | `flow.ai-flow.model-url` | `http://localhost:11434/api/chat` | AI 模型地址 | | `flow.ai-flow.api-key` | `default-api-key` | AI 模型密钥 | | `flow.ai-flow.model-name` | `qwen2.5` | 默认模型名 | 命名数据源示例: ```yaml flow: db: datasources: analytics: engine: postgresql url: jdbc:postgresql://localhost:5432/analytics username: postgres password: change-me ``` Portal 打开独立低代码运行端时使用 `VITE_LOWCODE_RUNTIME_URL`;未配置时默认 `http://localhost:5176`。 > 当前 `@devflow/api-client` 的后端基址默认写为 `http://localhost:9696`。生产构建前应根据部署拓扑改为统一域名下的相对 `/api`,或接入环境变量配置,不能直接沿用开发默认值。 ## 常用接口 ### 认证与权限 | 方法 | 地址 | 用途 | | --- | --- | --- | | POST | `/api/auth/login` | 登录 | | POST | `/api/auth/register` | 注册 | | POST | `/api/auth/logout` | 退出 | | GET | `/api/auth/info` | 当前用户 | | GET | `/api/auth/permission-snapshot` | 权限快照 | | GET/POST/PUT/DELETE | `/api/system/users` | 用户管理 | | GET/POST/PUT/DELETE | `/api/system/roles` | 角色管理 | | GET/POST/PUT/DELETE | `/api/system/resources` | 资源管理 | ### 流程 | 方法 | 地址 | 用途 | | --- | --- | --- | | POST | `/api/flow/definition` | 新建流程定义 | | PUT | `/api/flow/definition` | 更新流程定义 | | POST | `/api/flow/definition/copy` | 复制流程 | | GET | `/api/flow/definition/page` | 分页查询流程 | | GET | `/api/flow/definition/key/{flowKey}` | 按标识读取 | | DELETE | `/api/flow/definition/{id}` | 删除流程 | | POST | `/api/flow/engine/execute/{flowKey}` | 执行已保存流程 | | POST | `/api/flow/engine/run` | 启动调试执行 | | GET | `/api/flow/engine/run/{instanceId}/events` | SSE 运行事件 | | POST | `/api/flow/engine/run/{instanceId}/cancel` | 取消运行 | | GET | `/api/flow/instance/page` | 流程实例 | | GET | `/api/flow/log/page` | 流程日志 | | POST | `/api/open/flow/execute` | 开放 API 执行 | ### 低代码设计态 基础路径:`/api/lowcode/design` | 方法 | 地址 | 用途 | | --- | --- | --- | | GET/POST | `/apps` | 查询或创建应用 | | PUT/DELETE | `/apps/{appId}` | 修改或删除应用 | | GET | `/apps/{appId}/artifacts` | 查询制品 | | GET | `/apps/{appId}/artifacts/{type}/{key}` | 读取制品详情 | | POST | `/apps/{appId}/artifacts/{type}/{key}/revisions` | 保存新修订 | | GET | `/apps/{appId}/model-keys/{modelKey}/availability` | 验证模型标识 | | GET | `/apps/{appId}/models/{modelKey}/storage` | 查看物理存储状态 | | GET/POST | `/apps/{appId}/releases` | 查询或发布版本 | ### 低代码运行态 基础路径:`/api/lowcode/runtime/apps/{appKey}` | 方法 | 相对地址 | 用途 | | --- | --- | --- | | GET | `/navigation` | 已发布导航 | | GET | `/pages/{pageKey}` | 已发布页面 Schema | | GET/POST | `/models/{modelKey}/records` | 分页查询或新增 | | GET/PUT/DELETE | `/models/{modelKey}/records/{bizId}` | 单条 CRUD | | POST | `/models/{modelKey}/records/query` | Query DSL 查询 | | POST | `/models/{modelKey}/records/query/validate` | 校验 DSL | | POST | `/models/{modelKey}/records/import` | CSV 导入 | | GET | `/models/{modelKey}/records/export` | CSV 导出 | | GET | `/models/{modelKey}/aggregate` | 聚合和图表 | | GET | `/options/{optionSetKey}` | 公共选项 | | POST | `/actions/{actionKey}` | 执行动作 | ## 构建与测试 ### 后端 ```bash cd backend/process-orchestration # 编译 mvn -Dmaven.test.skip=true compile # 执行全部测试 mvn test # 执行指定测试 mvn -Dtest=FlowRunCodeServiceTest test mvn -Dtest=FlowRunDbServiceTest test mvn -Dtest=ParserTest,SelectTest,SelectsTest test mvn -Dtest=AmisPageCompilerTest test # 打包 mvn package ``` ### 前端 ```bash cd frontend # 所有 workspace 包构建 pnpm build # 流程设计器测试 pnpm --filter @devflow/flow-builder test # 单独构建 pnpm --filter @devflow/portal build pnpm --filter @devflow/flow-builder build pnpm --filter @devflow/runtime build ``` Portal 和 Runtime 的 `build` 脚本会先执行 TypeScript `--noEmit` 检查;Flow Builder 使用 Vitest 执行组件、节点注册、文档导入和运行时客户端测试。 ## 数据存储与版本迁移 ### Flyway 后端启动时自动执行 Flyway: - `V1__Baseline`:全新数据库基线,复用完整 `db/init.sql`。 - `V2__lowcode_kernel_schema.sql`:低代码元数据、修订、发布、动作及相关约束。 - `V3__Legacy_schema_compatibility`:旧用户权限、租户、组织、字典、开放接口和日志结构兼容。 - `V4__runtime_migration_registry.sql`:一次性运行时迁移登记。 固定平台 Schema 必须通过新的 Flyway 版本调整。原启动期 `SchemaCompatibilityInitializer` 已迁移为版本化的 V3,不再在每次启动时扫描并修改固定表。 ### 低代码表 | 表 | 用途 | | --- | --- | | `lc_app` | 应用和当前发布版本 | | `lc_artifact` | 制品身份和最新修订号 | | `lc_artifact_revision` | 不可变制品修订 | | `lc_release` | 发布 manifest | | `lc_release_item` | 发布与制品修订关系 | | `lc_model_record_history` | 模型记录变更历史 | | `lc_action_execution` | 动作执行记录 | | `lc_runtime_migration` | 一次性运行迁移状态 | | `lc_biz_{modelKey}` | 每个模型自己的业务数据表 | JSONB 仍用于制品定义、发布清单、动作输入输出和历史快照,因为这些内容本质上属于文档和审计数据;普通模型业务记录已经迁移到独立物理表,不再集中写入共享 JSONB 记录表。 旧共享业务表到独立模型表的迁移需要读取发布清单并执行领域校验,因此由 `LowcodeStorageMigrationInitializer` 执行一次,成功后写入 `lc_runtime_migration`,后续启动不会重复扫描。 ## 生产部署提示 Portal 和 Runtime 都使用 Hash 地址,并设置相对静态资源基址,可以部署到 Nginx 根目录或子目录,不要求 Nginx 识别前端业务路由。 单域名推荐拓扑: ```text https://example.com/ -> Portal 静态文件 https://example.com/runtime/ -> Runtime 静态文件 https://example.com/api/ -> 反向代理 Spring Boot :9696 ``` 示例访问地址: ```text Portal:https://example.com/#/dashboard 应用:https://example.com/runtime/#/?appKey=crm&pageKey=dashboard ``` 上线前至少完成: - 将 API Client 改为同源 `/api` 或注入生产 API 地址。 - 设置 `VITE_LOWCODE_RUNTIME_URL=/runtime/`。 - 修改数据库、Redis、默认管理员密码和所有示例密钥。 - 通过环境变量或外部配置文件管理密钥,不提交生产凭据。 - 配置 HTTPS、反向代理超时和 SSE 禁用缓冲。 - 限制数据库直连节点和关闭脚本沙箱的使用权限。 - 备份 PostgreSQL 并在发布前验证 Flyway。 - 为 `/api/open/flow/execute` 配置网关限流、审计和来源控制。 ## 当前边界 以下内容尚未完整实现,使用时应明确边界: 1. **低代码权限**:已有租户和登录态隔离,但应用级、页面级、动作级、字段级和行级权限模型尚未完成。 2. **发布治理**:已有不可变修订和发布快照,但缺少发布审批、版本差异、环境晋级和一键回滚界面。 3. **Query DSL**:2.0 已支持受模型关系治理的同引擎 `INNER/LEFT JOIN`,尚不支持多跳关系、一对多、多对多、自由 ON、HAVING、窗口函数和跨引擎查询。 4. **多查询引擎**:SPI 已具备,当前只有 MyBatis-Flex 关系型实现;Elasticsearch 仍是预留扩展点。 5. **低代码动作**:当前仅支持同步流程动作,尚无异步动作、HTTP 动作、重试、超时、幂等和补偿配置。 6. **自由页面安全**:已经拒绝外部 URL,但同源 `/api/...` 范围仍较宽,后续需要接口白名单和组件能力授权。 7. **制品完整度**:`VIEW`、`THEME` 已预留但未形成完整 Studio 和运行能力;主题当前属于应用设置。 8. **模型演进**:自动新增表、字段和索引,不自动执行删除列、重命名或高风险类型收缩。 9. **脚本安全**:沙箱降低风险但不能替代权限、资源限额和进程级隔离;不应向不受信任用户开放关闭沙箱的能力。 10. **生产配置**:前端 API 默认值仍面向本地开发,正式部署必须外部化。 当前版本更适合受信任团队构建企业内部后台应用和自动化流程。在面向不受信任租户或高合规场景前,应优先补齐细粒度授权、发布审批、资源配额和安全审计。 ## 相关文档 - [低代码内核实现](docs/lowcode-kernel.md) - [Query DSL 1.0 / 2.0](docs/lowcode-query-dsl.md) - [流程代码节点](docs/flow-code-node.md) - [Solon Flow 参考资料](docs/solon-flow-docs/) - [Solon AI Flow 参考资料](docs/solon-ai-flow-docs/) - [Flowgram 参考资料](docs/flowgram-docs/) - [Liquor 参考资料](docs/liquor-docs/) - [MyBatis-Flex 参考资料](docs/mybatis-flex-docs/) ## 常见问题 ### 后端启动提示数据库连接失败 确认 PostgreSQL 已启动、`dev_flow` 已创建,并检查 `application.yml` 中的 URL、用户名和密码。不要手工重复执行 Flyway 已管理的迁移脚本。 ### 登录后仍然返回 401 检查 Redis 是否可用、密码和数据库编号是否与配置一致。前端会在请求头携带 `satoken` 和 `X-Tenant-Id`。 ### 代码节点找不到 `select` 代码节点中直接使用运行时全局对象 `select`,不要把它写成未声明的成员变量。Java 脚本如需在局部类中使用,应将 `select` 作为参数传入局部类方法。具体示例参见 [流程代码节点文档](docs/flow-code-node.md)。 ### 代码节点无法调用某个 Spring Service 只有标注 `@FlowCallable("逻辑名称")` 的 Bean 才会被注册到脚本门面。脚本使用 `spring.call("逻辑名称", "方法名", 参数)` 调用,Service 自身仍应执行领域权限和数据权限校验。 ### 修改低代码草稿后运行端没有变化 运行端只读取当前发布快照。保存新修订后必须重新发布应用。 ### 新增数据成功但列表没有刷新 生成式页面已配置新增、编辑和删除后的 CRUD 刷新。如果是自由 AMIS 页面,需要在动作成功后配置目标组件刷新,并确保列表 API 返回 AMIS 兼容的 `items`、`total`、`page` 和 `perPage`。 ### 新发布的模型为什么生成新表 每个模型使用 `lc_biz_{modelKey}` 独立物理表,以避免所有应用数据集中在共享 JSONB 表中,并为索引、查询计划和容量治理保留空间。 ### 为什么低代码查询不直接暴露 MyBatis-Flex `Db` 流程和页面使用的是运行时模型,必须在查询前执行模型字段、查询权限、参数类型、租户、软删除和复杂度校验。Query DSL 将这些平台规则统一放在 Planner 和 Engine 之前,同时保留未来接入其他存储实现的可能。 ### 静态部署后刷新页面是否会 404 Portal 和 Runtime 使用 Hash Router,`#/...` 后面的部分不会发送给 Nginx,因此不依赖服务端路由回退。仍需正确配置静态资源目录和 `/api/` 反向代理。