跪拜 Guibai
← Back to the summary

Jeeflow: A 98KB Workflow Engine That Runs the Same Process in Java, Go, Python, and Node

If you've worked on Java business systems, you've probably encountered this scenario:

Approval flows, workflows — the moment the requirement comes in, it's "use Flowable / Activiti." Then you start wrestling with several MB of jars, hundreds of tables, and a pile of XML/JSON configurations. Bringing in an "enterprise engine" just for a "leave approval" is overkill, not to mention the learning costs, customization costs, and upgrade costs all fall on the business team.

This is the reality for many teams, and it was our real thinking back when we were building the mldong rapid development framework. Today's post is the first in the jeeflow series — I want to explain one thing clearly: how a workflow module embedded in a framework evolved step by step into an independent engine with "one set of process definitions, four language implementations."

This series continues from the mldong rapid development framework ecosystem, with synchronized updates on WeChat Official Accounts and Juejin. Welcome to follow along.

jeeflow evolution timeline


Starting Point: mldong's Built-in Custom Workflow Engine

The mldong rapid development framework (an open-source Java rapid development framework on Gitee) has a characteristic: if it can be built in-house, don't pile on dependencies. Workflow is one of those.

In an era where Flowable was everywhere, mldong chose to build its own lightweight approval engine based on LogicFlow process definitions:

Inside the framework, this engine ran very well: lightweight enough, stable enough, and business projects within the ecosystem could directly reuse it without reinventing the wheel.

Turning Point: Three Pain Points Forced It to "Go Independent"

As the ecosystem grew, three problems became increasingly acute:

Pain Point 1: Engine and framework coupling, high upgrade costs. The mldong framework itself underwent a "rewrite-style" evolution from boot2 to boot3 (different framework structures, business code rewritten according to logic). The engine followed the framework, meaning every major framework version upgrade forced a rewrite of the engine.

Pain Point 2: Other language teams couldn't use it. The ecosystem wasn't just Java — there was also Python (FastAPI), NestJS, and the frontend vben5. Workflow semantics are universal, but the engine was rooted in the Java framework, leaving other tech stacks "just watching."

Pain Point 3: Wanted to open it up, but couldn't carry the whole framework. Some people wanted to use this workflow engine standalone, but introducing an entire rapid development framework just for one engine was too heavy.

The conclusion was clear: The engine should have its own independent lifecycle. Its relationship with the framework should shift from "built-in module" to "upstream SDK" — the framework becomes its first consumer, not its sole host.

Independence: A 98KB Engine Core

Thus, jeeflow was born — the standalone version of the mldong workflow module. Several key design decisions:

Zero framework dependencies. The engine core (Java version) is only 98KB, with its sole dependency being slf4j-api (and that's provided). No touching Spring, no MyBatis, no Servlet.

SPI-ized. Repository, user info, JSON parsing, expression evaluation, ID generation, transaction template — 6 major SPIs. The engine makes no assumptions about your tech stack; the business side can integrate freely. Want to use MyBatis? Use MyBatis. Want an in-memory repository for unit tests? Go ahead. Want to plug in your own rule engine for expressions? That's fine too.

DDD Rich Domain Model. ProcessInstance (aggregate root) holds all state transition commands, while ProcessTask (sub-entity) is responsible for its own behavior. The state machine is explicit: Instance states are 10 In Progress / 20 Completed / 45 Rejected; Task states are 10 To Do / 20 Completed / 99 Discarded.

State Machine: Instance and Task Dual-Layer States

Contract alignment with mldong. This is the most critical part of going independent — the interface specification is completely consistent with the mldong framework: response code=0 for success, msg field, full enumeration of submitType (0 Initiate / 1 Agree / 2 Reject / 3 Return to Previous Step / 4 Jump / 5 Resubmit / 6 Return to Initiator / 20 Countersign Veto), endpoint list, VO structure, all aligned. This means: the mldong ecosystem frontend (vben5 + process designer) can directly connect to jeeflow with zero changes. Swapping the core without changing the shell, completely transparent to the consumer.

Spring Boot 2 / 3 / 4 triple starter. Comes with autoconfigure, runs from JDK 8 to 25.

Evolution: One Process Definition, Running in Four Languages

Independence wasn't the end. Back to Pain Point 2 — what about other language teams?

Our answer is a multi-language federation: not "one engine with multiple bindings," but four independent implementations + one unified specification:

The evolution discipline is strict: Specification first → Java reference implementation changes and tests first → Go/Python/Node align → Cross-validation. Any language change, four demos run the same batch of processes for verification, and results must be consistent.

Now, if you open the four demo sites (Java :8080 / Go :8081 / Python :8100 / Node :8082), log in with different accounts, and run the same expense report process — the flow results are exactly the same.

Now: A Six-Repository Ecosystem

jeeflow ecosystem topology

jeeflow-hub/
├── jeeflow-java    # Java reference implementation (core 98KB + repository + 3 starters + demo)
├── jeeflow-go      # Go implementation (GoFrame demo)
├── jeeflow-python  # Python implementation (FastAPI demo)
├── jeeflow-node    # Node.js implementation (Express demo)
├── jeeflow-ui      # Unified frontend (Vue3 + DingTalk process designer)
└── jeeflow-doc     # Specification and documentation site (jeeflow-doc.mldong.com)

Every change must pass three-scenario testing: Positive (core process runs through), Negative (boundary error codes match expectations), Regression (existing scenarios not broken). Test matrix: Java core 14 + jdbc 5, Python spec 10 + e2e 34, Node 10. Untested code is not allowed to be committed — this discipline runs through all languages.

What I'll Write in This Series

The jeeflow series has four seasons, synchronized on WeChat Official Accounts and Juejin:

Season Theme Articles
Prologue From mldong to jeeflow (this post) Part 0
Season 1 · Understanding Why build it yourself, what the 98KB looks like, state machine and submitType 3 articles
Season 2 · Core Design LogicFlow JSON, DDD aggregate root, applicant contract, 6 major SPIs, the three countersign brothers 5 articles
Season 3 · Multi-language Federation One definition running in four languages, cross-language alignment methodology, comparison of four implementations 3 articles
Season 4 · Ecosystem in Practice mldong contract alignment, Spring Boot 2/3/4 starter, jeeflow-ui, expense report process in practice, three-scenario testing 5 articles

Next post preview: 《Why Write a Lightweight Workflow Engine in the Flowable Era》 — a complete selection comparison between self-built vs mainstream open-source engines, thoroughly explaining "should you build it yourself."

Related Links

Comments

Top 1 from juejin.cn, machine-translated. The original thread is authoritative.

亚雷

The multi-language isomorphic approach is very clear.