Production-like demo store for showing how Inngest runs, retries, fails, and recovers durable commerce workflows.
Target demo domain: swag.demo.inngest.com.
This repo starts from the real Inngest swag store, then diverges into a controlled demo environment for sales, developer relations, talks, and meetups.
The demo store should let a presenter:
Stripe test checkout -> POST /api/webhooks/stripe -> inngest.send("store/order.placed")
|
v
fulfill-order Inngest function
- capture payment
- reserve inventory
- send confirmation
- record fulfillment
|
v
Railway Postgres demo data store
Realtime publishes:
- order:{orderId} -> customer order status page
- admin -> presenter/admin live tracker
The demo data layer now uses Railway/Postgres when DATABASE_URL is present. The original Google Sheets path remains as a local compatibility fallback until the demo deployment is fully cut over.
Railway should own resettable demo state:
The reset endpoint should restore all demo state in one shot:
POST /api/demo/reset
Expected reset behavior:
Inngest run history should remain in Inngest. The app should instead tag every demo order/event with a demoSessionId so presenters can clearly separate the current run from older ones.
The demo will use Railway because it is fast, resettable, and predictable. The real swag store may eventually integrate with a supplier instead.
Keep that future path clean by treating inventory and fulfillment as ports:
The Inngest workflow should call domain-level operations like reserveInventory, recordFulfillment, and releaseInventory, not know whether the backend is Postgres, Google Sheets, or a supplier.
You need:
brew install stripe/stripe-cli/stripe)npm install
cp .env.local.example .env.local
npm run dev
In separate terminals:
npx inngest-cli@latest dev
stripe listen --forward-to localhost:3000/api/webhooks/stripe
Visit:
/demo.| Path | Purpose |
|---|---|
src/app/api/checkout/route.ts |
Creates Stripe Checkout Sessions |
src/app/api/webhooks/stripe/route.ts |
Validates Stripe signatures, fires store/order.placed |
src/app/api/inngest/route.ts |
Inngest serve handler |
src/inngest/client.ts |
Inngest client + encryption middleware |
src/inngest/channels.ts |
Realtime channels (order:{id}, admin) |
src/inngest/functions/fulfill-order.ts |
Durable fulfillment workflow |
src/lib/demo-store.ts |
Railway/Postgres demo store, reset logic, scenario failures |
src/lib/sheets.ts |
Legacy Google Sheets fallback |
src/app/api/demo/reset/route.ts |
Resets demo orders, inventory, and scenario state |
src/app/api/demo/scenario/route.ts |
Reads or changes the active demo scenario |
src/app/demo/page.tsx |
Presenter demo console |
src/lib/catalog.ts |
Static product catalog |
src/components/OrderStatusClient.tsx |
Customer-facing order page |
src/components/AdminClient.tsx |
Public live order tracker |
/orders/[id]) defaults to masked PII.event.data.encrypted.MIT. This is a demo-focused fork of the Inngest swag store.