LogicTrail
How does checkout work?
52 nodes · 56 edges · static analysis
/
CheckoutPage calls useCart()
CheckoutPage calls handleCheckout()
onClick
useCart() requests GET /api/cart
useEffect
handleCheckout() calls createOrder()
handleCheckout() calls Stripe.js: confirmCardPayment
handleCheckout() condition result.error
createOrder() requests POST /api/orders
result.error navigates navigate /checkout/failed
yes
result.error navigates navigate /orders/:param
no
POST /api/orders calls requireAuth()
middleware
POST /api/orders calls validateBody()
middleware
POST /api/orders calls OrdersController.create()
requireAuth() reads session.findUnique
requireAuth() condition !session || session.expiresAt < new Date()
validateBody() condition !result.success
OrdersController.create() calls getCart()
OrdersController.create() calls validateCart()
OrdersController.create() condition !validation.ok
!session || session.expiresAt < new Date() returns 401 Unauthorized
yes
!result.success returns 400 Bad Request
yes
getCart() reads cartItem.findMany
!validation.ok returns 400 Bad Request
yes
!validation.ok calls OrderService.createOrder()
no
!validation.ok calls createPaymentIntent()
no
OrderService.createOrder() calls cartTotal()
OrderService.createOrder() writes order.create
OrderService.createOrder() calls reserveInventory()
OrderService.createOrder() emits order.created
createPaymentIntent() calls Stripe: paymentIntents.create
reserveInventory() writes product.update
for each
reserveInventory() condition product.stock < 0
Stripe: paymentIntents.create triggers POST /api/webhooks/stripe (inferred, 60%)
webhook
product.stock < 0 returns throw OutOfStockError
yes
POST /api/webhooks/stripe calls handleStripeWebhook()
handleStripeWebhook() calls Stripe: webhooks.constructEvent
handleStripeWebhook() condition catch
on error
handleStripeWebhook() condition switch (event.type)
catch returns 400 Bad Request
switch (event.type) calls markOrderPaid()
payment_intent.succeeded
switch (event.type) calls markOrderFailed()
payment_intent.payment_fail…
markOrderPaid() writes order.update
markOrderPaid() emits emails queue
order-confirmation
markOrderFailed() writes order.update
markOrderFailed() calls releaseInventory()
markOrderFailed() emits order.paymentFailed
emails queue triggers worker emails handler
worker
releaseInventory() reads cartItem.findMany
releaseInventory() writes product.update
for each
order.paymentFailed triggers notifyPaymentFailed()
listener
worker emails handler condition job.name === "order-confirmation"
notifyPaymentFailed() calls sendPaymentFailedEmail()
job.name === "order-confirmation" calls sendOrderConfirmation()
yes
sendPaymentFailedEmail() reads order.findUnique
sendPaymentFailedEmail() calls Resend: emails.send
sendOrderConfirmation() reads order.findUnique
sendOrderConfirmation() calls Resend: emails.send
CheckoutPage React component rendered for /checkout.
CheckoutPage
pages/CheckoutPage.tsx:9
useCart() export function useCart()
useCart()
hooks/useCart.ts:4
handleCheckout() async function handleCheckout()
handleCheckout()
pages/CheckoutPage.tsx:14
GET /api/cart HTTP GET request to /cart.
GET /api/cart
hooks/useCart.ts:9
createOrder() export async function createOrder(shippingAddressId: string): Promise<CreatedOrder>
createOrder()
api/orders.ts:8
Stripe.js: confirmCardPayment Calls Stripe.js: confirmCardPayment.
Stripe.js: confirmCardPayment
pages/CheckoutPage.tsx:18
result.error handleCheckout() branches on `result.error`.
result.error
POST /api/orders express route POST /api/orders.
POST /api/orders
routes/orders.ts:8
navigate /checkout/failed Client-side navigation to /checkout/failed.
navigate /checkout/failed
pages/CheckoutPage.tsx:21
navigate /orders/:param Client-side navigation to /orders/:param.
navigate /orders/:param
pages/CheckoutPage.tsx:24
requireAuth() Rejects requests without a valid session cookie.
requireAuth()
middleware/requireAuth.ts:5
validateBody() Validates the request body against a zod schema.
validateBody()
middleware/validate.ts:5
OrdersController.create() Turns the user's cart into an order and starts a Stripe payment.
OrdersController.create()
controllers/ordersController.ts:10
session.findUnique Reads from session via prisma (findUnique).
session.findUnique
middleware/requireAuth.ts:8
!session || session.expiresAt < new Date() requireAuth() branches on `!session || session.expiresAt < new Date()`.
!session || session.expiresAt < new Dat…
!result.success validateBody() branches on `!result.success`.
!result.success
getCart() export async function getCart(userId: string): Promise<Cart>
getCart()
services/cart.ts:14
validateCart() Checks that the cart is not empty and every quantity is positive.
validateCart()
services/cart.ts:27
!validation.ok OrdersController.create() branches on `!validation.ok`.
!validation.ok
401 Unauthorized requireAuth() responds with HTTP 401.
401 Unauthorized
middleware/requireAuth.ts:11
400 Bad Request validateBody() responds with HTTP 400.
400 Bad Request
middleware/validate.ts:9
cartItem.findMany Reads from cartItem via prisma (findMany).
cartItem.findMany
services/cart.ts:15
400 Bad Request OrdersController.create() responds with HTTP 400.
400 Bad Request
controllers/ordersController.ts:14
OrderService.createOrder() Persists a pending order and reserves stock for its items.
OrderService.createOrder()
services/orderService.ts:9
createPaymentIntent() Creates a Stripe PaymentIntent for the order total.
createPaymentIntent()
payments/stripe.ts:8
cartTotal() export function cartTotal(cart: Cart): number
cartTotal()
services/cart.ts:36
order.create Writes to order via prisma (create).
order.create
services/orderService.ts:10
reserveInventory() Decrements stock for every cart line; fails if a product runs out.
reserveInventory()
services/inventory.ts:11
order.created Event "order.created".
order.created
services/orderService.ts:14
Stripe: paymentIntents.create Calls Stripe: paymentIntents.create.
Stripe: paymentIntents.create
payments/stripe.ts:9
product.update Writes to product via prisma (update).
product.update
services/inventory.ts:13
product.stock < 0 reserveInventory() branches on `product.stock < 0`.
product.stock < 0
POST /api/webhooks/stripe express route POST /api/webhooks/stripe.
POST /api/webhooks/stripe
routes/webhooks.ts:6
throw OutOfStockError reserveInventory() throws OutOfStockError.
throw OutOfStockError
services/inventory.ts:18
handleStripeWebhook() Verifies the Stripe signature and applies payment results to orders.
handleStripeWebhook()
payments/stripe.ts:17
Stripe: webhooks.constructEvent Calls Stripe: webhooks.constructEvent.
Stripe: webhooks.constructEvent
payments/stripe.ts:20
catch Error handling in handleStripeWebhook(): runs when the code above throws.
catch
switch (event.type) handleStripeWebhook() branches on `switch (event.type)`.
switch (event.type)
400 Bad Request handleStripeWebhook() responds with HTTP 400.
400 Bad Request
payments/stripe.ts:26
markOrderPaid() Marks an order as paid and queues the confirmation email.
markOrderPaid()
services/orderService.ts:24
markOrderFailed() Marks an order as failed, releases its stock and notifies listeners.
markOrderFailed()
services/orderService.ts:30
order.update Writes to order via prisma (update).
order.update
services/orderService.ts:25
emails queue Background job queue "emails".
emails queue
services/orderService.ts:26
releaseInventory() export async function releaseInventory(orderId: string)
releaseInventory()
services/inventory.ts:23
order.paymentFailed Event "order.paymentFailed".
order.paymentFailed
services/orderService.ts:33
worker emails handler async (job) =>
worker emails handler
jobs/emailWorker.ts:7
notifyPaymentFailed() async function notifyPaymentFailed({ orderId }: { orderId: string })
notifyPaymentFailed()
events/handlers.ts:11
job.name === "order-confirmation" worker emails handler branches on `job.name === "order-confirmation"`.
job.name === "order-confirmation"
sendPaymentFailedEmail() export async function sendPaymentFailedEmail(orderId: string)
sendPaymentFailedEmail()
email/send.ts:18
sendOrderConfirmation() Emails the customer a receipt for a paid order.
sendOrderConfirmation()
email/send.ts:7
order.findUnique Reads from order via prisma (findUnique).
order.findUnique
email/send.ts:8
Resend: emails.send Calls Resend: emails.send.
Resend: emails.send
email/send.ts:10
Component
Function
External service
Condition
Route
Database
Service
Error
Event / queue
Inferred
100%
Enable JavaScript to explore this LogicTrail flow interactively.