Examples/SaaS
Subscription SaaS (example)
A Next.js app with a Postgres database, Stripe subscriptions, a background job queue for emails and invoices, and file uploads to S3. Replace any part with how your own system works.
Scale: 2,000 paying teams; 30 req/s at peak
Select a component to see what it is responsible for and which state it owns.
- 1Next.js frontend → API routes: Sign up and upgrade plan
- 2API routes → Postgres: Read and write accounts
- 3API routes → Stripe: Create checkout session
- 4Stripe → API routes: Subscription webhooks
- 5API routes → Job queue: Enqueue welcome email and invoice
- 6Background worker → Job queue: Claim jobs
- 7Background worker → Email provider: Send email
- 8Background worker → S3: Store invoice PDF
- Request / response
- Asynchronous
- Bulk data
Select a part to trace its flows.
- Request / response
- Asynchronous
- Bulk data
Parts 8
Flows 8
- 1Next.js frontend → API routesSign up and upgrade planRequest / response
- 2API routes → PostgresRead and write accountsRequest / response
- 3API routes → StripeCreate checkout sessionRequest / response
- 4Stripe → API routesSubscription webhooksAsynchronous
- 5API routes → Job queueEnqueue welcome email and invoiceAsynchronous
- 6Background worker → Job queueClaim jobsRequest / response
- 7Background worker → Email providerSend emailRequest / response
- 8Background worker → S3Store invoice PDFBulk data
Invariants 3
A team has at most one active subscription
Partial unique index on subscriptions(team_id) WHERE status = 'active'; the webhook handler upserts by Stripe subscription id.
Kept by
A team is upgraded only after Stripe confirms payment
The plan changes only in the verified invoice.paid webhook handler; the checkout redirect shows a pending state.
Kept by
Each Stripe event changes state once
stripe_events(event_id) primary key inserted in the same transaction as the state change; a duplicate insert aborts the transaction.
Kept by