Project

Workflow Visualizer

Submit a job below and watch it move through a real AWS Step Functions state machine — Validating, Processing, then Complete — with every status change written straight to DynamoDB by the state machine itself. No Lambda sits in that loop at all.

Demo

Submit a Job

This button sends a real request to API Gateway, which starts a Step Functions execution. The timeline below polls a status endpoint and lights up live as the state machine advances.

Privacy notice: nothing personal is collected — each job is just a random id, a status, and two timestamps.

Your job's live status will appear here once you submit one.

Recent jobs

No jobs submitted yet this session.
Submitted Job ID Status

Architecture

How It Works

This is a real AWS project, not a mockup. Here's what actually happens between clicking the button above and the timeline reaching Complete — click any step to jump to it, or let it play through on its own.

Visitor
Website
API Gateway
Lambda
Step Functions
DynamoDB
  1. 1

    Visitor clicks Submit a job

    This static page — including this button — is served from S3, the same way as the rest of the site. Clicking it sends a POST /jobs request with an empty body; nothing personal is sent.

  2. 2

    Browser calls API Gateway

    API Gateway receives the request and proxies it to a Lambda function — the only Lambda involved in the whole submit-and-run path.

  3. 3

    Lambda creates the job and starts the workflow

    Lambda writes a new DynamoDB item with status SUBMITTED, then calls Step Functions' StartExecution API and immediately returns the new job's id to the browser — it doesn't wait for the workflow to finish.

  4. 4

    Step Functions runs the state machine

    A Standard state machine advances the job through VALIDATING, a short wait, PROCESSING, another short wait, then COMPLETE — around 13 seconds end to end.

  5. 5

    Step Functions writes status directly to DynamoDB

    Every one of those three transitions is a native dynamodb:UpdateItem task built into the state machine definition — there's no Lambda in this part of the path at all. Meanwhile, the browser polls a separate GET /jobs/{id} endpoint every couple seconds and lights up the timeline above to match whatever DynamoDB currently says.

Use Cases

Where This Pattern Fits

Step Functions shows up anywhere a request kicks off work that takes longer than a single API call should reasonably wait for.

Multi-step processing pipelines

Video transcoding, report generation, image processing — any job that moves through distinct stages benefits from a state machine that tracks exactly where each one is.

Order and fulfillment workflows

An order moving through payment, inventory, and shipping steps is a natural fit — each stage's status is queryable at any point, not hidden inside a single opaque function.

Approval and review chains

Anything with a human-in-the-loop wait — a moderation queue, an approval step — pairs naturally with a state machine's ability to sit idle for a long time at no cost.

Pricing

What This Actually Costs

Pay-per-use the whole way through — an unclicked demo costs nothing. These are estimates based on public AWS list pricing, not a guarantee.

Low volume

~$0/mo

A few hundred job submissions a month — comfortably inside Step Functions' free tier of 4,000 state transitions (each job uses 3), plus Lambda and DynamoDB's free tiers.

Jobs submitted per month

What drives the cost

  • Step Functions — Standard workflows are billed per state transition; this workflow uses 3 (Validating, Processing, Complete) per job, after a 4,000/month free tier.
  • Lambda — one small function on the create-job path, billed per request and per millisecond.
  • DynamoDB — on-demand billing for the job table and its recency index; no idle capacity to pay for.
  • API Gateway — billed per request across the create/read/list routes.

Design Decisions

Why I Built It This Way

A few choices here aren't the only way to build this — here's the reasoning behind them.

No Lambda inside the state machine

It would have been simpler in one sense to route every transition through a single generic "update status" Lambda. Step Functions' native DynamoDB integration — a task state that calls dynamodb:UpdateItem directly — skips that extra hop entirely: no Lambda cold start on the path, no separate function to deploy and grant permissions to, and the state machine's own execution role only ever needs exactly one IAM action against exactly one table.

The trigger Lambda writes SUBMITTED, not VALIDATING

Having the API Lambda create the job with status VALIDATING directly would let two different pieces of code each claim to be the source of a status change. Splitting SUBMITTED (written by the API Lambda) from VALIDATING (the state machine's own first transition) means every real status change has exactly one origin.

Standard workflow, not Express

Express workflows are built for high-volume, sub-5-minute, fire-and-forget executions where you don't need to look back at run history. This project is the opposite of that use case — the whole point is watching one execution's history unfold, and Standard workflows keep that execution history queryable in the console long after it finishes.

A GSI instead of a Scan for "recent jobs"

A Scan can't reliably answer "the N most recent rows" once a table holds more than a handful of items, since it reads items in whatever order they sit in on disk. A GSI with a constant partition key and createdAt as the sort key turns that into an actual sorted Query.

Polling instead of a WebSocket

This project reaches for a simple tool — the browser polling a REST endpoint every couple seconds is plenty responsive for a 13-second workflow, without the extra infrastructure a persistent connection would need.

Architecture Diagram

Full Architecture Diagram

The complete AWS architecture diagram for this project, built with draw.io. Click it to expand full screen.