Build and execute gamified business processes with a visual editor, role-based task routing, and a database-driven process engine.
ProcessFlow lets teams model, deploy, and run structured workflows with full gamification built in. Process designs are created visually in a node-based editor — activities, gateways, parallel flows, and role assignments — and executed by a PostgreSQL-driven engine that advances instances automatically as tasks are completed.
Completing tasks earns XP, coins, and badges configured directly in the editor. A plugin architecture lets anyone extend the platform with custom activity types hosted on external servers, rendered inside iframes.
Team Dashboard![]() |
Workflow Editor![]() |
Task Worklist![]() |
Monitoring Dashboard![]() |
Activity Shop![]() |
User Statistics![]() |
Design business processes with a drag-and-drop node graph. Connect activity nodes, exclusive gateways, and parallel AND-split/join nodes. Each node type is configurable via a side panel — including gamification rewards, role assignments, and output variables.
Team members are assigned roles that control both page access and which process activities appear in their worklist. Tasks are automatically pushed to the right users as the process engine advances.
Every activity node can award XP, coins, or badges upon completion. Rewards are rule-based — conditions (comparisons against process variables), application methods (increment, decrement, set), and badge types are all configured in the editor.
The engine runs inside PostgreSQL. Completing a task triggers a database function that stores output data, evaluates the next path (including gateway conditions and AND-join synchronisation), and creates the next flow element instance — all in one transaction. No dedicated backend process required.
Activity nodes with executionMode: Automatic are dispatched via HTTP to an external server when created. The server processes the task and posts results back to /api/instance/complete. This enables fully automated steps within otherwise manual workflows.
Activity nodes are not hardcoded — they are node definitions that describe a reusable task type: its name, icon, UI structure (what inputs to show the user), and how it executes.
- Manual nodes render a custom task form in an iframe, served by an external server. The user fills it in and submits; the result is posted back to the process engine.
- Automatic nodes trigger an HTTP call to an external server when reached. The server does its work and calls back when done — no user interaction needed.
The shop lists all available node definitions. Teams browse it, install the types they want, and those types appear in the node palette inside the editor. Anyone can publish their own node type to the shop.
Real-time overview of all process instances — running, completed, or errored — with per-process charts and task breakdown stats.
Also uses: better-auth · ReactFlow · Zustand · Radix UI · Recharts · Fumadocs · next-intl · Zod
Each completed task triggers a chain of PostgreSQL functions that advance the process automatically:
| Step | What happens |
|---|---|
complete_flow_element_instance() |
Stores output data in data_object_instance, marks instance as Completed |
create_next_flow_element_instance trigger |
Evaluates gateway conditions, resolves variable placeholders, creates next instance(s) |
execute_created_flow_element_instance trigger |
Sets Manual tasks to Todo; sets Automatic tasks to In Progress |
App layer (dispatchAutomaticActivities) |
Makes HTTP POST to external server for Automatic tasks |
Parallel branches (AND-split) and synchronisation (AND-join) are handled natively in the trigger functions.
Requires Node 20+ and a running PostgreSQL instance.
# 1. Clone & install
git clone https://github.com/MertenD/process-flow.git
cd process-flow
npm install
# 2. Configure environment
cp .env.example .env
# Fill in DATABASE_URL, BETTER_AUTH_SECRET, APP_URL
# 3. Apply migrations (tables + engine functions)
npm run db:migrate
# 4. Start dev server
npm run devStarts the app and a PostgreSQL container. Migrations run automatically on first start.
# 1. Configure environment
cp .env.example .env
# Set DB_PASSWORD and BETTER_AUTH_SECRET
# 2. Start stack (builds the image automatically on first run)
docker compose -f docker-compose.local.yaml up -dApp available at http://localhost:3000.
# Stop
docker compose -f docker-compose.local.yaml down
# Reset database
docker compose -f docker-compose.local.yaml down -vdocker compose up -dRequires an external web Docker network with Traefik and a le-merten TLS resolver configured on the host.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
✅ | PostgreSQL connection string |
BETTER_AUTH_SECRET |
✅ | Random secret for session signing |
BETTER_AUTH_URL |
✅ | App base URL (e.g. http://localhost:3000) |
NEXT_PUBLIC_APP_URL |
✅ | Public app URL (used client-side) |
APP_URL |
✅ | App URL used by the process engine for callbacks |
DB_PASSWORD |
Docker | PostgreSQL password for the Docker Compose DB service |
ACTIVITY_OPENROUTER_URL |
Endpoint of the OpenRouter activity service (see below) |
Copy .env.example to .env and fill in the values before running.
Bundled automatic activity services live in custom-activities/<name>/. Each is an independent Node.js service (Express, POST /call, port 3000) that is built and deployed alongside the main app.
| Service | Folder | Description |
|---|---|---|
| OpenRouter Call | custom-activities/openrouter/ |
Calls any LLM via OpenRouter |
URL routing per environment
| Environment | How the app reaches an activity |
|---|---|
Local dev (npm run dev) |
http://localhost:<port>/call — run the service separately |
| Local Docker Compose | http://activity-<name>:3000/call — started automatically |
| Production | https://processflow.merten.tech/activities/<name>/call — routed by Traefik |
Adding a new activity
- Create
custom-activities/<name>/withserver.js(POST /call),package.json, and aDockerfile - Add an
activity-<name>service to both compose files (copy the openrouter block as a template) - Add
ACTIVITY_<NAME>_URLto.env,.env.example, and both compose files - Add the node definition to
prisma/seed.tsand include the name in thealwaysUpdateset so URL changes are applied on re-seed
erDiagram
user ||--o{ team : "creates"
user ||--o{ profile_team : "member of"
user ||--o{ profile_role_team : "assigned"
user ||--o{ statistics : "tracks"
team ||--o{ role : "has"
team ||--o{ process_model : "owns"
team ||--o{ profile_team : ""
team ||--o{ profile_role_team : ""
team ||--o{ invitation : "sends"
team ||--o{ statistics : ""
role ||--o{ profile_role_team : ""
process_model ||--o{ flow_element : "contains"
process_model ||--o{ process_instance : "instantiated as"
flow_element ||--o| activity_element : ""
flow_element ||--o| start_element : ""
flow_element ||--o| end_element : ""
flow_element ||--o| gateway_element : ""
flow_element ||--o| and_split_element : ""
flow_element ||--o| and_join_element : ""
flow_element ||--o{ flow_element_instance : "instance of"
process_instance ||--o{ flow_element_instance : "contains"
process_instance ||--o{ data_object_instance : "stores"
node_definition ||--o{ teams_node_definitions : ""
team ||--o{ teams_node_definitions : ""
Special thanks to Emilija for designing the app logo!






