Vibe Modeling a Payment System: A 15-Minute Walkthrough
“Build me a payment system.” That’s the prompt. And if you type it into Claude Code right now, you’ll get something that works — until it doesn’t. Payment systems are where vibe coding breaks down hardest, because the domain is full of state transitions, edge cases, and boundaries that aren’t obvious until they bite you.
Vibe modeling is the practice of visually exploring domain events, system boundaries, and user flows with AI before writing code. It gives developers structured context and shared understanding, so vibe coding starts from a clear model instead of a vague prompt.
Here’s what fifteen minutes of vibe modeling looks like for a payment system, step by step.
Minutes 0-3: Place the obvious events
Open the board and start placing domain events. Don’t think too hard. Just write what happens in a payment system:
- CustomerRegistered
- PlanSelected
- PaymentMethodAdded
- SubscriptionStarted
- InvoiceGenerated
- PaymentProcessed
- PaymentFailed
- SubscriptionRenewed
- SubscriptionCancelled
- RefundRequested
- RefundProcessed
Eleven events in three minutes. These are the facts — things that happen in the system. Don’t worry about order yet. Don’t worry about completeness. Just get the obvious ones on the board.
Minutes 3-6: Arrange the timeline
Now drag the events into a rough timeline. Left to right, what happens first?
CustomerRegistered → PlanSelected → PaymentMethodAdded → SubscriptionStarted → InvoiceGenerated → PaymentProcessed → SubscriptionRenewed → …
This already reveals something: there’s a happy path (customer signs up, pays, renews) and there are branches. PaymentFailed is a branch off PaymentProcessed. RefundRequested branches off somewhere after a successful payment. SubscriptionCancelled could happen at almost any point.
The AI consultant on the board notices the timeline and asks: “What happens between PaymentFailed and the next retry? Is there a grace period?” Good question. You add:
- GracePeriodStarted
- PaymentRetried
- GracePeriodExpired
- AccountSuspended
Four more events you wouldn’t have thought about if you’d gone straight to code.
Minutes 6-10: Find the boundaries
Look at the events on the board. Some cluster naturally:
Cluster 1 — Customer identity: CustomerRegistered, PaymentMethodAdded, AccountSuspended. These are about who the customer is and their account state.
Cluster 2 — Subscription lifecycle: PlanSelected, SubscriptionStarted, SubscriptionRenewed, SubscriptionCancelled. These are about what the customer has.
Cluster 3 — Billing: InvoiceGenerated, PaymentProcessed, PaymentFailed, PaymentRetried, GracePeriodStarted, GracePeriodExpired. These are about money moving.
Cluster 4 — Refunds: RefundRequested, RefundProcessed. A small but distinct flow with its own rules.
Draw boundaries around these clusters. You’ve just discovered four bounded contexts — not because someone told you about Domain-Driven Design, but because the events themselves showed you where the natural divisions are.
The AI asks: “Should the Subscription context know about payment failures directly, or should it react to events from Billing?” This is the architectural question that determines whether your system is coupled or clean. On the board, it’s a conversation. In generated code, it’s a buried assumption.
Minutes 10-13: Surface the edge cases
This is where the real value lives. With your events and boundaries visible, start asking questions the AI helps you surface:
What if a refund is requested during a grace period? The billing context is already in a retry loop. Does the refund cancel the retry? Does it cancel the subscription? You add: RefundDuringGracePeriod as an event and mark it as an open question.
What if the customer upgrades their plan mid-cycle? PlanSelected happens again, but now there’s proration to calculate. You add: PlanUpgraded, ProratedInvoiceGenerated.
What if payment succeeds after the account is suspended? AccountSuspended is in the Customer context, but the payment success event comes from Billing. These contexts need to communicate. You draw an arrow: PaymentProcessed triggers AccountReactivated.
Every edge case you discover on the board is a bug you won’t ship in code. The fifteen minutes you spend here saves days of debugging later.
In five minutes of questioning, you’ve found three edge cases that would have become production incidents. They’re now visible on the board, documented as events, with clear context boundaries showing which part of the system handles each one.
Minutes 13-15: Export as context
Your board now has roughly twenty events across four bounded contexts, with arrows showing how events flow between them. Translate this into structured context for your coding tool:
Payment System — Domain Model
Bounded contexts:
1. Customer (identity, account state)
2. Subscription (plan lifecycle)
3. Billing (invoices, payments, retries)
4. Refunds (refund processing)
Key cross-context events:
- Billing.PaymentFailed → Subscription.GracePeriodStarted
- Billing.GracePeriodExpired → Customer.AccountSuspended
- Billing.PaymentProcessed → Customer.AccountReactivated
- Subscription.PlanUpgraded → Billing.ProratedInvoiceGenerated
Open questions:
- Refund during grace period: cancel retry loop?
- Payment success after suspension: auto-reactivate?
Hand that to Claude Code or Cursor along with “implement the Billing bounded context.” The generated code will have event-driven communication, clear module boundaries, and explicit handling for the edge cases you identified. Compare that to what you’d get from “build me a payment system.”
What fifteen minutes buys you
You started with a vague idea — “payment system” — and finished with a structured domain model showing four bounded contexts, twenty events, cross-context communication patterns, and three documented edge cases. The model isn’t perfect. It doesn’t need to be. It needs to be good enough that your AI coding tool generates architecture instead of assumptions.
This is what vibe modeling looks like in practice. Not a two-day workshop. Not a formal architecture review. Fifteen minutes of placing events, finding boundaries, and asking the uncomfortable questions — before the first line of code.
Try it yourself
Map your domain events. Explore bounded contexts with AI. Walk away confident.
Open the Board