Durable workflow execution for Spring Boot — no server to run, just the PostgreSQL you already have.
Workflows are ordinary Java code; the engine handles persistence, replay, retries, timeouts, signals, human approvals, durable timers, cron schedules, and recovery after restarts. Ships as a Spring Boot starter plus a web console.
public final class RefundWorkflow implements Workflow<RefundRequest, RefundResult> {
public String type() { return "refund"; }
public RefundResult execute(RefundRequest request, WorkflowContext ctx) {
Customer customer = ctx.activity("load-customer", Customer.class,
() -> customerService.find(request.customerId()));
RefundDecision decision = ctx.activity("evaluate", RefundDecision.class,
() -> refundPolicy.evaluate(customer));
if (decision.requiresApproval()) {
ctx.requestApproval(new ApprovalRequestDetails(
"refund-approval", "Approve refund", null, decision));
ReviewApproval approval = ctx.awaitSignal("refund-approval", ReviewApproval.class);
if (!approval.approved()) {
return RefundResult.denied(approval.comment());
}
}
return ctx.activity("issue-refund", RefundResult.class,
() -> refundService.issue(decision));
}
}Kill the process anywhere in that flow — on restart it resumes exactly where it left off, without re-running completed steps.
Licensed under Apache 2.0. See PRD.md for the full product specification and CONTRIBUTING.md to get involved.
backend/
flowforge-core/ Framework-free domain model + public interfaces
flowforge-runtime/ Execution engine (replay, retries, signals, recovery)
flowforge-storage-postgres/ PostgreSQL persistence (jOOQ, Flyway migrations)
flowforge-spring-boot-starter/ Spring Boot auto-configuration
flowforge-api/ REST controllers + DTOs
flowforge-demo/ Runnable app + reference requirement-review workflow
frontend/
flowforge-console/ Next.js web console
infrastructure/
docker-compose.yml Local PostgreSQL
docs/
adr/ Architecture decision records
- Docker (for PostgreSQL and integration tests)
- Java is auto-provisioned by the Gradle toolchain (JDK 25); nothing to install
- Node.js 20+ (web console only)
# 1. Start PostgreSQL (host port 5433; override with FLOWFORGE_DB_PORT)
docker compose -f infrastructure/docker-compose.yml up -d postgres
# 2. Run the backend (applies Flyway migrations on startup)
./gradlew :backend:flowforge-demo:bootRun
# 3. Web console
cd frontend/flowforge-console && npm install && npm run dev # http://localhost:3000
# 4. Health
curl -s http://localhost:8080/actuator/healthThen start the reference workflow and approve it — see docs/development.md for the full walkthrough and docs/api.md for the API.
./gradlew build # everything + unit tests
./gradlew :backend:flowforge-runtime:test # engine tests (in-memory store)
./gradlew :backend:flowforge-storage-postgres:test # PostgreSQL integration (Testcontainers)
./gradlew :backend:flowforge-demo:test # end-to-end vertical sliceIntegration and E2E tests use Testcontainers and require Docker.
- Durable replay execution: sequential + parallel activities (virtual threads), persisted results never re-executed, nondeterminism detected.
- Retries with backoff, activity timeouts, structured errors — all durable (they survive restarts as scheduled wakeups).
- Buffered signals, durable timers (
context.sleep), human approvals bridged to signals, cancellation, manual retry of failed workflows. - Restart recovery: leases with per-claim fencing tokens, heartbeats, stale-execution requeue.
- REST API (PRD 15), web console (PRD 16), health + metrics, append-only event history.
- Cron-scheduled workflow starts (guarded, never double-fires), live console updates over SSE, a read-only execution graph per instance, free-text workflow search, and one-click history export.
- Console extras: schema-generated input forms with a JSON escape hatch, dark mode, start-workflow and send-signal UIs.
Design decisions live in docs/adr; architecture overview in docs/architecture.md.