Smart Order Capture
Core concepts

How it works

The mental model in five terms: workflows, triggers, actions, runs, and devices.

smartordercapture has five concepts. Once you have them down, the rest of the product is navigation.

Workflow

A directed graph of one trigger and one or more actions, expressed as a versioned JSON document. You build them in the visual editor; we serialize them to the workflow DSL (see DSL reference) and sync them to your phone.

Workflows have a current version and a history. Saving a change creates a new version; older versions are kept so you can roll back without rebuilding from scratch.

Trigger

The node that starts a workflow. Every workflow has exactly one. The trigger decides what wakes the engine — a time of day, an SMS, an NFC tap, a homescreen shortcut, a push from the cloud, etc. Full list: triggers reference.

Action

The node that does something. Tap a button, swipe, type text, wait, open an app, make an HTTP call, log to a sheet, send an SMS. Actions form the body of the workflow and execute in the order you connect them. There are two special action kinds — action.branch for conditionals and action.loop for repetition — that change the flow. Full list: actions reference.

Run

One execution of a workflow. Each run records a status (queued, running, success, failed, cancelled), start and end timestamps, an error message if it failed, and a trace — a step-by-step log of which nodes executed, with which outcome, and how long each one took.

Note
Traces are produced by both the on-device Kotlin interpreter and the in-builder simulator. They're byte-identical for any given workflow (we golden-test this in CI), so the preview log you see in the builder matches what your phone will actually do.

Device

An Android phone paired with your account. Workflows are assigned per device — a workflow on your primary phone doesn't silently run on your spare. Each device has a label, an install source (Play or direct), and a last-seen heartbeat the dashboard updates in real time via SSE.

The execution loop, end to end

  1. You save a workflow in the builder. The API validates it against the DSL schema, extracts the targeted Android package names, checks them against the denylist, and stores a new workflow_version row.
  2. The API fires NOTIFY workflow_synced over Postgres LISTEN/NOTIFY and pushes a Firebase Cloud Messaging payload to every paired device.
  3. The Android client receives the FCM push, pulls the new workflow definition over HTTPS, and stores it locally in Room.
  4. The trigger registry registers any new WorkManager jobs / broadcast receivers / geofences required by the new triggers.
  5. When a trigger fires, the executor loads the workflow from Room and runs it through the Kotlin interpreter. Every node is checked against the on-device denylist before any UI action is dispatched.
  6. When the run finishes, the client posts the trace back to /v1/trpc/runs.report. The cloud surfaces it via SSE on the dashboard.

Local-first vs. cloud-first

The cloud is the source of truth for which workflows belong to you. Execution is fully local. Your phone can run armed workflows for days without network — sync resumes when connectivity returns. Run results queue locally and upload when reachable.