Early access for Channel Partners and ISVs opening soon. Learn more →

Architecture

FSM as the spine of operations software

The status column starts simple and quietly becomes the load-bearing primitive of every operations app. Here's what changes when you treat it as one from the start.

The pattern every ops app converges on

Pick any operations-heavy application that's been in production for two years and you'll find some version of this:

  • A table that holds the records.
  • A status column on that table — a string, an enum, a foreign key into a "stages" lookup.
  • A pile of code that reads and writes that column.

That code starts small: when status moves from "Pending" to "Assigned," send a notification. Then it grows: only allow "Assigned → InProgress" if the assignee is qualified. Then: don't allow "Cancelled → Anything." Then: when "Pending" has been the status for more than two days, escalate. Then: log every status change with who, when, and why.

By the time the app is mature, that pile of code is a state machine pretending it isn't one. The transitions are scattered across handlers. The guards are re-implemented in three different places. The audit log is partial because two of the writes forgot to record themselves.

FastYoke makes the state machine the primary primitive of every workflow. Not a derived view of the data — the contract the data has to obey.

What changes when you start with an FSM

1. Transitions are checked, not hoped

Every transition has explicit from and to states. The engine refuses any write that doesn't match a declared transition. The "Cancelled → Anything" bug doesn't get caught in code review — it gets caught at the schema layer, because there's no transition declared and the write fails.

This isn't bureaucracy. It's the same lock that the type system gives you for function signatures, applied to the domain model.

2. Guards are first-class

A guard is a JSONLogic expression evaluated against the entity's payload before the transition fires. "Assigned → InProgress" is gated by {"==": [{"var": "qualified"}, true]}. The guard is part of the schema, not part of the handler. Every code path that fires the transition gets the guard for free.

When you need richer guard logic, the scripting tier runs QuickJS inside a wasmtime sandbox. You can write a real function, version it, test it. It still lives in the schema, not in a handler.

3. The audit log writes itself

Every successful transition appends a row to the event log. No UPDATE, no DELETE — append-only by construction. The auditor's question "what happened to this job between Tuesday and Friday?" has a literal answer in the database, ordered, with payloads and actors.

You don't have to remember to log it. The engine does.

4. Side effects fire on transitions, not on writes

A webhook to a partner, a notification, a payment capture — these are consequences of a transition, not consequences of a row write. Declaring them at the transition level means the webhook fires once when the transition fires once, even if two operators race to flip the status. The engine serializes the transition; the side effect inherits that guarantee.

This kills the "we fired the partner webhook twice" class of bug at the schema layer.

5. The visual builder is the schema

FSM Designer ships in the platform. Operators can see their workflow as a graph, drag a transition, ship a new state. The graph is the schema — there's no "the visual designer drifted from the code" failure mode because they share the same source of truth.

For workflows simple enough to author this way, the operator never touches code. For workflows that need code, the schema is still the authoritative document; the code is the implementation of one guard or one side effect.

What this lets you skip

The list of problems an FSM-first architecture doesn't have is long:

  • No "developer forgot the status check" bugs.
  • No "the audit log is missing entries for X" gaps.
  • No "the webhook fired three times" race conditions.
  • No "the bulk-update tool moved 4,000 records into an invalid state" outages.
  • No "rebuild the audit log from server logs because the app didn't record it" forensics.

These aren't theoretical wins. Every operations team that's been in production for three years has the scars from at least three of them.

What this costs

The honest tradeoffs:

  • You think about the workflow upfront. Schema-first design asks you to enumerate the states and transitions before you start writing handlers. That's upstream work the "add a status column and figure it out later" approach doesn't make you do.
  • One-off operations get heavier. Bulk-updating 10,000 records to a new state requires the bulk operation to declare itself as a transition. That's good for safety; it's slower than a UPDATE ... SET status = ? would be.
  • The mental model is graph-shaped, not list-shaped. Engineers used to thinking "records and statuses" have to rewire to "entities and transitions." The payoff is real, but there's a ramp.

If those costs are deal-breakers for your team's preferred shape, FastYoke is the wrong substrate. If they read as "yes, finally," you're the audience.

Where this shows up across FastYoke

  • Every marketplace app is built around one or more FSMs. Patient flow, warehouse management, AR invoicing, field service — same primitive, different workflow shape.
  • The admin "cancel override" sits outside the FSM on purpose, because cancellation is a privileged bypass — not a workflow transition. The schema says what the workflow is; the override says what an admin can do despite the workflow.
  • Self-loop transitions (where from == to) are a legitimate primitive for audit-only events, idempotent retries, and counter increments. The schema accommodates the cases the textbook doesn't.

The honest summary

FSMs aren't the right shape for every application. They are the right shape for operations software, because operations work is journeys through states with rules. Bolting a state machine onto an app that started without one is the most common refactor on the planet. Starting with one — and getting the audit log, the guards, the side effects, and the visual designer for free — is the unlock FastYoke is built around.

For the procurement-grade detail on how state changes become the contractual audit trail, see /security. For an architectural conversation with someone who'd be the engineer behind your tenant, request early access.