AI Decision Automation
A production platform where people query complex live data in plain English and build event-driven automations by connecting typed nodes—compiled to server-side code and run safely at scale.
- LLMs
- Compilers
- Distributed Systems
- PostgreSQL
- Ruby on Rails
- React
My role
Contract software engineer, through my own company, for a private client (2025–present). I designed and built core parts of a production platform that makes complex live data usable without requiring SQL or hand-written automation code: ingestion and indexing, plain-English querying, a metadata-driven visual language and compiler, and the event runtime that executes user-authored workflows.
Outcome
A production platform operating over 4+ TB of live data and processing 15M+ events per day. The client domain is intentionally omitted; the commerce walkthrough below is fictional, while the architecture, engineering work, and rounded scale are real.
Large operational databases contain useful answers, but usually only for the people who know the schema, can write complex queries, and understand which tables are safe to join. Acting on those answers creates another barrier: an engineer still has to turn the decision into software.
LLMs make complex operational data accessible through plain English. This platform carries that AI advantage from insight to action: users can turn an answer into a visual automation, test it against historical events, and activate it behind explicit controls.
About the example: The client and its domain are private. To make the product understandable without disguising that domain as something else, this case study uses a fictional multi-channel commerce scenario. The products, warehouses, results, and reconstructed interfaces are illustrative. The underlying capabilities, architecture, my contribution, and rounded production measurements are real.
Start with a question
Imagine a merchant selling the same products through several online stores and shipping from more than one warehouse. The data exists, but answering a question across sales, inventory, and incoming deliveries is still difficult:
Which products will run out before their next delivery arrives, even though another warehouse has more than it needs?
A representative answer might identify a 28-litre travel backpack that will run out in Reykjavík in six days. Its next delivery is twelve days away, while 180 units are moving slowly in Copenhagen. Moving 70 units now would likely prevent around 120 missed orders.
Representative interface reconstruction using fictional commerce data. The question-to-answer capability reflects the production system.
That answer is useful once. The next step makes it operational.
Turn the answer into a repeatable decision
Operational software is often good at showing what happened and poor at letting its users define what should happen next. Even a straightforward rule such as “when local stock will run out before the next delivery, check another warehouse and prepare a transfer” would normally become a ticket for a programmer. Someone has to connect the event, retrieve the relevant data, encode the checks, and call the right action.
Visual programming moves that work within reach of the people who understand the operation itself. Instead of writing code, a warehouse manager can connect typed event, data, decision, and action nodes:
A product starts selling faster than usual
→ local stock will not last until the next delivery
→ another warehouse has enough spare stock
→ moving it costs less than the likely missed orders
→ prepare a stock-transfer request
→ ask a manager to approve it
The graph is a real program, not a decorative flowchart. Connections are checked as the user builds it, so incompatible data cannot be joined and required inputs cannot be silently omitted.
The part I find most technically interesting is how the building blocks reach the editor. Backend methods deliberately approved for visual use carry metadata describing their names, inputs, outputs, types, and configuration. The editor consumes that catalog—roughly 200 operations—and constructs the corresponding nodes. Exposing an approved capability is therefore primarily a backend declaration, rather than a bespoke frontend feature for every new operation.
When the graph is saved, the platform validates it and compiles it into server-side Ruby source code. The compiler can call only methods registered for visual use, and it also derives the event subscriptions that determine when the automation should wake up. Before activation, the same compiled decision can be replayed against historical data to show when it would have run and what it would have proposed.
Representative historical-test reconstruction. Every commerce event and outcome shown here is synthetic; the testing workflow reflects the real platform capability.
A foundation for AI-authored automation
The longer-term goal was to let an LLM assemble the same vetted operations into a draft automation. Rather than emitting opaque, black-box code, the model would express its proposal as a typed node graph—a human-readable intermediate representation. This creates a human-in-the-loop layer of explainability: the model’s internal reasoning may remain opaque, but its proposed decision logic is visible, editable, and auditable before execution. Once approved, the existing validator and compiler could turn the graph into executable code. The AI generation layer remained future work, but the metadata-driven operation catalog, visual language, and compiler built the infrastructure required for it.
The production system behind the example
The figures below describe the real, generalized production platform—not a fictional commerce deployment:
- 4+ TB
- live operational data
- 15M+
- events processed daily
- ~200
- vetted operations
1. Asking the data safely
The natural-language layer does not send a question to a model without context. It assembles a focused description of the live database, operational notes about how it should be queried, and similar question-to-query examples that were previously reviewed and approved. Those examples are retrieved by meaning rather than exact wording, so the system gradually builds a useful vocabulary for its own data.
The model produces SQL—the database’s query language—but it does not control the execution boundary. The platform checks generated SQL with a short dry run before execution, caps the result set, applies a database timeout, and caches recent results. The model proposes the query; ordinary application code controls whether and how it runs.
This separation matters: the model proposes a way to answer the question; ordinary software constrains what happens next.
2. A visual language with a real compiler
The visual editor is a typed programming language presented as a node graph. Its operation catalog is generated from metadata on approved backend methods, and saving a graph runs required-input validation before compiling it into server-side Ruby. The compiler can emit calls only to methods deliberately registered for visual use; malformed graphs return structured errors to the editor instead of becoming broken runtime programs.
Each automation is versioned. Before queued work runs, the platform checks that it still targets the current version; if the automation changed in the meantime, that outdated execution is discarded.
3. Reacting to millions of events selectively
Live database changes enter a persisted event log through PostgreSQL notifications. Notification bursts are drained in batches: a burst becomes one bulk insert and one bulk enqueue operation rather than separate database round trips for every event.
The harder problem is deciding which user automations should wake up. Testing every active automation against every event would become increasingly expensive as either side grew. Instead, activating an automation compiles its interests into subscriptions and lookup indexes. An incoming event first finds the small set of automations that could care about its source and subject; only that candidate set receives the remaining checks.
This is the same idea as using an index at the back of a book: look up the relevant pages first instead of rereading the whole book for every question.
4. Keeping consequential actions controlled
Automations could lead to real actions, not only dashboards and notifications. The action path was therefore separated from the authoring runtime and designed around simulation, short-lived authorization, deduplication, and explicit approval where appropriate. The private domain’s credential and execution details are intentionally omitted here; the transferable principle is that a convenient visual rule should never bypass the controls expected of production software.
Why this project matters
The interesting part is not any single model call, node editor, or queue. It is the complete path from an inaccessible question to a user-authored decision that can survive live production data:
- Ask a nuanced question without knowing the schema.
- Inspect a guarded answer computed from current data.
- Encode the decision visually with typed building blocks.
- Test it against historical events.
- Activate it behind explicit controls.
- Dispatch only the live events that are relevant to it.
That path let non-specialists work with complex data without pretending the complexity had disappeared. The compiler, query boundaries, event indexes, and runtime checks carried the complexity so the user did not have to.
Want something built like this? I'm available for contract work.