Client work
Sarah Mozer Studio
An artist’s shop, with an editing workflow she can own.

The work comes first
A painting fills the opening view. The navigation leads directly to the kinds of work a visitor can buy or commission.
View full sizeSarah needed a place to sell her artwork, prints and cards, and a manageable way to look after it. I built the shop, catalogue, checkout and inventory controls together with the editing workflow.
She can change customer-facing words and photographs while technical fields remain protected. An owner guide and support using annotated screenshots help her make routine changes. My work included discovery, implementation, deployment and ongoing support.
Delivered client system. Availability and product details are maintained by the studio.
More views (1)

A place for each collection
The landscape collection has its own introduction and visual identity. Captured September 2026; stock and availability change.
View full sizeTechnical detail
Architecture checked against the catalogue configuration, checkout and webhook implementation. This is a code account, not a fresh live-payment test.
Catalogue and ownership
One catalogue row represents one sellable format. An artwork grouping ID connects an original, print and card derived from the same painting. Product IDs, Stripe price IDs and inventory policy have technical ownership; the CMS describes that boundary separately from editable words and images.
Checkout and finite stock
The server resolves submitted product IDs to canonical catalogue entries and Stripe prices. Originals are restricted to quantity one. Finite-stock lines require an enabled inventory path and a reservation; unavailable stock, cart conflicts or database failures stop checkout. A fingerprint binds the attempt to its cart, and the attempt ID becomes the Stripe idempotency key.
Payment events and recovery
Webhook construction verifies the raw body with the Stripe signature. The handler distinguishes paid, pending asynchronous, expired and failed sessions, filters application ownership, and passes event and reservation IDs to the inventory repository before persisting a paid order. A definitive checkout-creation failure may release a new reservation; an uncertain failure retains it rather than assuming no payment session exists.
Stack / components
Next.js, TypeScript, TinaCMS, Stripe, Neon