Pinbox24 Process Engine — Reference Documentation
Last updated: 2026-07-02
Source: MongoDB inspection of w4_db on bms-2 (MongoDB rs0 PRIMARY) during live incident investigation
Audience: p24-infra ops/DevOps team — for debugging, fixing configs, and tracing record creation failures
Table of Contents
- Overview
- Storage —
process.configsCollection - Process Status Values
- Activity Types
- Transition Structure and Kinds
- Task Types
- Process Instances
- Register-to-Process Linkage
- Example: aiProcessingLog Process Flow
- Debugging: “No auto activity found” Error
- Collections Reference (w4_db)
1. Overview
Pinbox24 uses a process engine that executes configurable workflows on register records. A process is a directed graph of activities (nodes) connected by transitions (edges). When a record is created or a user action fires, the engine walks the graph: evaluating activity tasks, following transitions, and updating the running instance until it reaches a waiting state or terminates.
Processes are stored in MongoDB (w4_db on bms-2). All process definitions live in process.configs; running executions live in process.instances.
Key concepts:
- Activity — a node in the graph. Has a type, zero or more tasks, and optional roles.
- Transition — a directed edge between two activities. Has a kind that controls how it fires.
- Task — a unit of work within an activity (AI document processing, duplicate check, field update, etc.).
- Instance — one execution of a process for one record.
2. Storage — process.configs Collection
Each Pinbox24 process is one document in the process.configs collection inside w4_db.
Top-level fields
| Field | Type | Description |
|---|---|---|
_id | ObjectId | Unique process identifier |
name | string | Human-readable name, e.g. "aiProcessingLog" |
status | string | Lifecycle status — "launched" or "preparation" (see Section 3) |
regId | string | The register this process belongs to. May be empty "" (linkage mechanism not fully determined — see Section 8) |
officeId | (present) | Office/org scoping |
activities | array | All activities (nodes) in the process graph |
transitions | array | All edges between activities |
stepList | array | Ordered list of steps. Empty [] when status is "preparation" |
roles | array | Roles defined for this process |
isCustom | bool | Whether this is a custom (user-defined) process |
useCommit | bool | Whether record changes require explicit commit before persisting |
customSmtp | (present) | SMTP configuration override for process-triggered emails |
Example document shape (simplified)
{
"_id": "ObjectId(\"675abf9acb6b3800253342ae\")",
"name": "aiProcessingLog",
"status": "preparation",
"regId": "",
"stepList": [],
"activities": [ "/* 171 entries */" ],
"transitions": [ "/* 177 entries */" ]
}The live aiProcessingLog process had 171 activities and 177 transitions at time of investigation.
3. Process Status Values
| Status | Meaning | Runtime behavior |
|---|---|---|
"launched" | Published and active | Process executes on record creation; all transitions resolve normally |
"preparation" | Draft / being configured | Process is NOT ready for production use |
Critical behavior of "preparation" status
A process in "preparation" will be started when a record is created (if the register is configured to use it), but it will fail immediately with the error:
No auto activity found, while settings is to move to auto
The engine starts the process, reaches the start activity, attempts to auto-transition to the next activity, and cannot resolve a valid target. This happens because the engine handles preparation-status processes differently — it likely skips stepList resolution or transition lookup. The process hangs or errors out before any work is done.
Production rule: a process must have status: "launched" before any register is configured to use it.
4. Activity Types
Each entry in the activities array represents one node in the process graph.
Core activity fields
{
"id": 1,
"type": "start",
"label": "Start",
"kind": "interactive",
"actName": 1,
"sort": 50,
"roles": [],
"tasks": {
"init": [],
"pending": [],
"leaving": [],
"error": []
},
"slug": "some-slug",
"initStatusBehaviour": "useInstancesList",
"formType": "subForm",
"autoMove": true,
"autoMoveActivity": 5
}| Field | Description |
|---|---|
id | Integer, unique within the process |
type | Activity type (see table below) |
label | Human-readable name displayed in the UI |
kind | "interactive" or "automatic" |
actName | Mirrors id |
sort | Sort order for UI display |
roles | Array of role objects that can interact with this activity |
tasks.init | Tasks run when the engine enters this activity |
tasks.pending | Tasks run while the process is waiting in this activity |
tasks.leaving | Tasks run when the engine leaves this activity |
tasks.error | Tasks run on error |
slug | URL-friendly identifier used in API calls |
initStatusBehaviour | How instance status is initialized; observed value: "useInstancesList" |
formType | "subForm" or "main-form" — which form layout to show |
autoMove | If true, the engine moves automatically out of this activity without user input |
autoMoveActivity | Target activity ID for the automatic move |
Activity types
| Type | kind | Description |
|---|---|---|
start | interactive | Entry point of every process. Exactly one per process. Always auto-transitions to the first real activity. |
state | interactive | A waiting state. The process “sits” here until a user or cron manually triggers a transition out. Visible in the UI as the current step. Requires roles to define who can act. |
act | interactive | An action step. Involves user interaction or a cron task. Has roles and tasks. Auto-transitions out when tasks complete (success path) or on error (error path). |
trigger | interactive | A pass-through step that executes init tasks automatically and transitions out. No user interaction. No roles. Outgoing transition is typically kind: "auto". |
switch | automatic | A conditional branch. Evaluates a condition via tasks.init (typically an activate_trigger task) and fires a trigger-kind transition to one of N destinations. |
subgraph | (not inspected) | Presumably a nested sub-process. |
5. Transition Structure and Kinds
Each entry in the transitions array is a directed edge in the process graph.
Transition object structure
{
"id": 126,
"kind": "auto",
"transName": 126,
"source": {
"id": 1,
"type": "start",
"label": "Start",
"..."
},
"dest": {
"id": 102,
"type": "trigger",
"label": "created log entry",
"..."
}
}| Field | Description |
|---|---|
id | Integer, unique transition ID |
kind | How this transition fires (see table below) |
transName | Mirrors id |
source | Full copy of the source activity object, not just an ID |
dest | Full copy of the destination activity object, not just an ID |
Important: source and dest are full embedded copies of the activity objects. When filtering transitions programmatically, use transition.source.id and transition.dest.id — not top-level .source or .dest as strings.
Transition kinds
| Kind | Trigger mechanism | Description |
|---|---|---|
auto | Fires immediately when source completes | The engine moves automatically. No user input required. Used after trigger and act activities on the success path. |
manual | User clicks a button in the UI | A button labeled with the transition’s label appears in the interface. The process waits until a user with the correct role clicks it. |
trigger | Fired by a switch activity | Activated when a switch activity’s activate_trigger task evaluates a condition and matches this transition’s key. |
Terminology note: kind: "trigger" on a transition means it is activated by a switch condition. This is separate from type: "trigger" on an activity. A trigger-kind transition often leads to a trigger-type activity, but this is coincidental naming, not a requirement.
6. Task Types
Tasks are the units of work within an activity. They are defined in tasks.init, tasks.pending, tasks.leaving, or tasks.error arrays.
Task object structure
{
"id": 1733506788141,
"name": "doc process with ai",
"taskType": "open_ai_process_docs",
"formType": "main-form",
"open_ai_process_docs": {
"params": [],
"prompt": { "value": "...", "optionType": "defaultTextArea" },
"fileId": { "value": "recordMainDocument", "optionType": "formField" },
"apiKey": { "value": "...", "optionType": "defaultText" },
"successActId": { "value": "67", "optionType": "defaultText" },
"errorActId": { "value": "70", "optionType": "defaultText" }
}
}The configuration block is named after taskType (e.g. open_ai_process_docs). Field values inside this block use an optionType to indicate how the value should be resolved at runtime.
optionType values
| optionType | Resolution |
|---|---|
"formField" | Reads the value from the current record’s field named by value |
"defaultText" | Literal string value — used as-is |
"defaultTextArea" | Literal multi-line string — used for long prompts |
"select" | Value chosen from predefined options |
Observed task types
| taskType | Where used | Description |
|---|---|---|
open_ai_process_docs | act, trigger activities | Sends a document (PDF or image) to OpenAI with a configured prompt. Extracts structured fields from the response. successActId and errorActId specify which activity ID to jump to on success or failure. |
activate_trigger | switch activities | Evaluates the value of inputKey field and compares it against params[].key entries. Special values: ##isEmpty## (field is empty), ##isNotEmpty## (field has any value), or a literal match. Fires the transition associated with the matching key. |
filter_by_mq_filter_and_update | trigger activities | Queries a register using an mqFilter expression with field='##value##' substitution from the current record. Used for duplicate detection. Stores the result count in keyName. |
process_create_register_record | trigger activities | Creates a new record in a child register. Maps fields from the current record using mappingValue. childRegisterId identifies which register receives the new record. |
7. Process Instances
Running process executions are stored in related collections in w4_db:
| Collection | Content |
|---|---|
process.instances | One document per process execution per record. Tracks current activity, status, and execution metadata. |
process.instance.exts | Extended instance data — task results, field value snapshots captured during execution. |
instancehistories | Audit log of state changes for each instance. Useful for tracing which activities were visited and when. |
When debugging why a record is stuck or erroring, start by finding the instance document for that record in process.instances, then check instancehistories for the last successful state transition.
8. Register-to-Process Linkage
The mechanism that connects a register to its associated process was not fully determined during the 2026-07-02 investigation.
What was observed:
process.configsdocuments have aregIdfield, but this was empty""for theaiProcessingLogprocess.- The
registriescollection (27,838+ documents inw4_db) stores register definitions. - The AI-Logs register (
{_id: "67597cb44eefb1002c9847d4", name: "AI-Logs"}) exists inregistriesbut showed noprocessIdfield in the basic{name:1, processId:1}projection used during investigation.
Likely linkage mechanism (to be confirmed): the registries document probably contains a processes array (not visible under the limited projection used) that lists process IDs, or v42-prod maintains a separate in-memory configuration mapping registers to processes.
To confirm the linkage for a specific register, run this on bms-2 (no projection — full document):
db.registries.findOne({_id: ObjectId("67597cb44eefb1002c9847d4")})This will show all fields including any processes or processId field that controls which process fires on record creation.
9. Example: aiProcessingLog Process Flow
The aiProcessingLog process (_id: 675abf9acb6b3800253342ae) handles documents received via the Mailgun email integration for the AI-Logs register. It processes attached invoice/receipt documents using OpenAI and routes them by document type.
Partial flow (reconstructed from transitions)
start (id:1)
└─[auto, TR126]──> created log entry (trigger, id:102)
tasks.init: [] — pass-through, no tasks
├─[auto, TR405]──> avoidDupCheck (id:308)
├─[trigger, TR389]──> check duplicates (id:296)
│ task: filter_by_mq_filter_and_update
└─[trigger, TR127]──> not processable? (id:103)
Documents who are processing (state, id:2) [admin role — human review queue]
├─[manual, TR76]──> Success of processing secretary docs (act, id:67)
└─[manual, TR80]──> Error in processing (act, id:70)
└─[auto, TR82]──> Error to manage main documents (state, id:72)
File added go to AI processing (act, id:266) [cron-triggered, role: "Cron 2 minutes"]
└─[auto, TR105]──> have file or not (switch, id:267)
activate_trigger on file field:
isEmpty ──> (trigger, id:269)
isNotEmpty ──> (trigger, id:268)
check ai-email-address (switch, id:89)
activate_trigger on costCategory field:
isEmpty ──> ai-standard-doc (trigger, id:93)
"gutschrift" ──> gutschrift (trigger, id:91)
"rechnung" ──> rechnung (trigger, id:92)
"kassenbuch" ──> kassenbuch (trigger, id:90)
##isNotEmpty## ──> not defined category (trigger, id:94)
[Each category trigger runs open_ai_process_docs with successActId=67, errorActId=70]
Success of processing secretary docs (act, id:67)
└─[auto, TR75]──> create record in eigenhende (trigger, id:97)
task: process_create_register_record
childRegisterId: eigenhende register
Design intent
Records created by the Mailgun integration enter the process at start. The process logs the entry (created log entry), checks for duplicates, then waits for a cron job (runs every 2 minutes) to trigger AI processing of any attached document. The AI extracts cost category and routes the record to a specialist processing trigger. Results surface in the Documents who are processing state for human review. If processing fails, the error path routes to Error to manage main documents for human intervention.
10. Debugging: “No auto activity found” Error
Error message
No auto activity found, while settings is to move to auto
What it means
- A record was created in a register that has the process configured.
- The process started (engine entered the
startactivity). - The engine tried to auto-transition from
startto the next activity. - It could not find a valid next activity and threw this error.
Common causes
| Cause | Probability | Fix |
|---|---|---|
Process has status: "preparation" | High — confirmed in 2026-07-02 incident | Set status: "launched" in MongoDB (see fix below) |
Missing start → first_activity transition | Medium | Add the missing auto transition to the transitions array |
stepList empty on a launched process | Low — engine version dependent | Rebuild stepList from activity order |
Diagnostic query
Run on bms-2 using w4_app credentials:
const p = db.getSiblingDB('w4_db')['process.configs'].findOne(
{_id: ObjectId('PROCESS_ID')},
{name: 1, status: 1, stepList: 1, transitions: 1}
);
print('status:', p.status, '| stepList len:', p.stepList.length);
const fromStart = p.transitions.filter(t => t.source && t.source.id === 1);
print(
'transitions from start:',
JSON.stringify(fromStart.map(t => ({kind: t.kind, dest: t.dest.id, dest_label: t.dest.label})))
);Expected output for a healthy process:
status: launched | stepList len: N
transitions from start: [{"kind":"auto","dest":102,"dest_label":"created log entry"}]
Output for the broken state:
status: preparation | stepList len: 0
transitions from start: [{"kind":"auto","dest":102,"dest_label":"created log entry"}]
Note: even with transitions defined, preparation status causes the error.
Fix: set status to “launched”
Always take a backup before modifying a process config:
mongosh "mongodb://w4_app:PASSWORD@localhost:27017/w4_db" --quiet --eval \
"printjson(db.getCollection('process.configs').findOne({_id:ObjectId('PROCESS_ID')}))" \
> /tmp/process_backup_$(date +%Y%m%d_%H%M%S).jsonApply the fix:
db.getSiblingDB('w4_db')['process.configs'].updateOne(
{_id: ObjectId('PROCESS_ID')},
{$set: {status: 'launched'}}
)Verify:
db.getSiblingDB('w4_db')['process.configs'].findOne(
{_id: ObjectId('PROCESS_ID')},
{name: 1, status: 1}
)
// Expected: { name: "aiProcessingLog", status: "launched" }After applying the fix: trigger a new record creation in the register and confirm that the process instance advances past the start activity without error. Check instancehistories for the new record to confirm state progression.
11. Collections Reference (w4_db)
All collections relevant to process engine work live in the w4_db database on bms-2.
| Collection | Purpose | Notes |
|---|---|---|
process.configs | Process definitions: activities, transitions, task configs | One document per process |
process.instances | Running process instances | One document per record-process execution |
process.instance.exts | Extended instance data: task results, field value snapshots | Referenced by instance _id |
instancehistories | Audit log of all state changes per instance | First stop when tracing stuck/errored records |
registries | Register definitions | 27,838+ documents; see Section 8 for linkage notes |
regRecords | All register records across all registers | Scoped by registryId field |
forms | Form definitions used in the register UI | Referenced by activity formType |
process-templates | Reusable process template library | Used when creating new processes from templates |
tmp.processes | Temporary process state (scratch) | Engine working storage — not a source of truth |
Connection details
- Host: bms-2 (
145.239.133.104) — MongoDB rs0 PRIMARY - Database:
w4_db - Credentials:
w4_appuser (credentials insecrets/bms-servers.env.sops) - Port: 27017 (ufw-restricted — allowed only from rs0 members and jump hosts)
For ad-hoc investigation, SSH to bms-2 first, then connect locally:
ssh root@145.239.133.104
mongosh "mongodb://w4_app:PASSWORD@localhost:27017/w4_db"Document maintained by the p24-infra ops team. Update after any structural discovery about the process engine.