Files
ordo/README.md
T

154 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ordo
轻量审批流程引擎。宿主通过 `OrdoEngine` 注册流程定义、发起实例、审批/驳回/转派/撤回/取消,并查询任务、实例与审计历史。引擎不绑定业务表单、用户体系或设计器 UI,当前也不自带 REST;业务数据放在 `ProcessContext` 里。
要求 **Java 17+**。当前版本 `0.0.1-SNAPSHOT`。
## 模块
| 模块 | 作用 |
|---|---|
| `ordo-api` | 公共模型与 `OrdoEngine` 端口 |
| `ordo-core` | 运行时(`DefaultOrdoEngine` / `InMemoryOrdoEngine`) |
| `ordo-storage-jdbc` | JDBC 存储 + 按方言 Flyway 基线(PostgreSQL / MySQL) |
| `ordo-spring-boot-starter` | Spring Boot 自动装配(JDBC + Flyway) |
| `ordo-example` | 内存引擎示例 |
存储实现通过 dialect 层支持 **PostgreSQL** 与 **MySQL**(测试可用 H2 PostgreSQL 兼容模式)。Starter **不携带** JDBC 驱动,宿主自行加入 `postgresql`、`mysql-connector-j` 或 `h2`。Spring Boot 4 还需额外引入 `spring-boot-starter-flyway`,否则迁移不会跑。
## 能力
- 线性或多步图:`StepTransition` + 内置谓词 / 宿主 `RoutingCondition`
- 会签/或签:`ApprovalPolicy.ALL` / `ANY`(多候选人)
- 结构化并行:`kind: PARALLEL` 块(一层、join ALL)
- ACTION 步骤:事务提交后调用宿主 `ActionHandler`
- 发起人撤回:`WITHDRAWN`,待办任务 `SKIPPED`
- 管理员/系统取消:`cancel` → `CANCELLED`,待办任务 `SKIPPED`(引擎不鉴权角色)
- 任务转派:当前办理人 `reassign`,审计 `TASK_REASSIGNED`
- 到期升级:步骤 `due` + `processDue`,审计 `TASK_ESCALATED`
- 分页查询:任务 / 实例 / 流程定义
- 审计时间线:`ProcessEvent` + `queryHistory`
- 扩展点:`AssigneeResolver`、`RoutingCondition`、`ActionHandler`、`OrdoEventListener`
开发计划:可选 REST + 目录 SPI。设计器为独立产品(不进本仓库),待 REST 与目录之后。多租户 **暂不在计划中**。见 [docs/roadmap.md](docs/roadmap.md)。
详细用法(定义 JSON、扩展点、异常、查询、ACTION/审计语义)见 **[docs/usage.md](docs/usage.md)**。对外行为变更时同步更新该文档。
## 内存快速开始
```xml
<dependency>
<groupId>com.jetlumen</groupId>
<artifactId>ordo-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
```
```java
OrdoEngine ordo = new InMemoryOrdoEngine();
ordo.publish(ProcessDefinition.linear("leave-request", "Leave request", List.of(
ApprovalStep.single("manager", "Manager approval", "maria"),
ApprovalStep.single("hr", "HR approval", "henry")
)));
ProcessInstance instance = ordo.start("leave-request", "alice",
new ProcessContext(Map.of("requestId", "LEAVE-2026-001")));
ApprovalTask manager = ordo.findPendingTasksByInstanceId(instance.id()).get(0);
ordo.approve(manager.id(), "maria", "ok");
```
完整示例:`ordo-example` 的 `LeaveRequestExample`。
## JSON 流程定义
```json
{
"id": "leave-request-routed",
"name": "Leave request",
"steps": [
{ "id": "notify-submitted", "name": "Notify submitted", "kind": "ACTION", "action": "leave-submitted-mail" },
{ "id": "manager", "name": "Manager approval", "candidates": ["maria"], "policy": "ANY" },
{ "id": "hr", "name": "HR approval", "candidates": ["henry"], "policy": "ANY" },
{ "id": "notify-approved", "name": "Notify approved", "kind": "ACTION", "action": "leave-approved-mail" }
],
"transitions": [
{ "from": "notify-submitted", "to": "manager" },
{ "from": "manager", "to": "hr", "when": { "gt": ["days", 3] }, "priority": 0 },
{ "from": "manager", "to": "notify-approved", "priority": 1 },
{ "from": "hr", "to": "notify-approved" },
{ "from": "notify-approved", "to": null }
]
}
```
- `kind` 默认 `APPROVAL`;ACTION 用 `"action"` 作为 handler 查找键;`PARALLEL` 用 `branches`(结构化并行块,见 [docs/usage.md](docs/usage.md))。
- 带 `when` 的边先按 `priority` 匹配,都未命中再走无条件边;`to: null` 表示结束。
- 代码侧可用 `ProcessDefinitionParser.fromJson(...)`。
- `replace` 会整体替换同 id 定义;存在 `RUNNING` 实例时拒绝替换。
## Spring Boot
```xml
<dependency>
<groupId>com.jetlumen</groupId>
<artifactId>ordo-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
```
需要 `DataSource`。存在 `DataSource` 且 `ordo.enabled` 不为 `false` 时装配 JDBC 引擎。
```yaml
ordo:
enabled: true
jdbc:
dialect: # 可选 postgresql / mysql;空则按 DataSource 探测
definitions:
location: classpath*:ordo/*.json # 默认值;启动时 publish 加载
```
宿主提供 Bean 即可覆盖默认值:
| Bean | 默认 |
|---|---|
| `AssigneeResolver` | 候选人即办理人 |
| `RoutingCondition` | 始终匹配(`ref` 边;宿主可按 key+args 分发) |
| `ActionHandler` | 空操作 |
| `OrdoEventListener` | 可注册多个,提交后按顺序调用 |
## 运行时约定
**办理人** 必须等于任务 `assignee`,否则 `UnauthorizedTaskOperationException`(`approve` / `reject` / `reassign`)。
**转派** 只改 PENDING 任务的 `assignee`,不推进步骤。
**撤回** 仅发起人可操作,且实例须为 `RUNNING`。
**取消** `cancel` 任意非空 `actor`,实例须为 `RUNNING`;谁能调用由宿主决定。
实例状态:`RUNNING` / `APPROVED` / `REJECTED` / `WITHDRAWN` / `CANCELLED`。
任务状态:`PENDING` / `APPROVED` / `REJECTED` / `SKIPPED`。
**ACTION** 在审批事务提交之后执行。失败只记 `FAILED`、打日志、发 `ACTION_FAILED`,**不回滚已生效审批、不阻塞后续步骤**。可重试策略留给宿主(listener 或 `queryActionExecutions`)。
**历史** `queryHistory(instanceId, page)` 按时间升序。事件类型包括实例起止、任务创建/审批/跳过/转派、ACTION 成败。
`OrdoEventListener.onEvent` 在提交后派发;单个 listener 抛错不影响流程和其他 listener。
## 查询
```java
ordo.queryTasks(TaskQuery.any().withAssignee("maria").withStatus(TaskStatus.PENDING),
PageRequest.of(0, 20));
ordo.queryInstances(InstanceQuery.any().withInitiator("alice"), PageRequest.of(0, 20));
ordo.queryDefinitions(PageRequest.of(0, 20));
ordo.queryHistory(instanceId, PageRequest.of(0, 50));
ordo.queryActionExecutions(instanceId, PageRequest.of(0, 20));
```
任务/实例列表默认最新优先;历史与 ACTION 执行记录按发生时间升序。
## 构建
```bash
mvn -pl ordo-api,ordo-core,ordo-storage-jdbc,ordo-spring-boot-autoconfigure,ordo-spring-boot-starter install
```
先 `install` 再给外部工程(如宿主应用)引用。