Skip to content
← portfolio·
case study

Joyce Art Studio

live2025

Full-stack artist portfolio and custom-order e-commerce shop for Joyce Rasfeld — gallery, cart, Stripe checkout, and a webhook- driven order state machine.

Customers can browse a filterable gallery, then place custom orders for miniature houses, animal magnets, or framed pieces. The cart lives in localStorage so no account is needed — Stripe Checkout handles payment and a webhook flips the order to PAID, then triggers a Resend confirmation email.

WebStripe-poweredLive at joyceartstudio.comOpen source
Joyce Art Studio screenshot
architecture

How It Works

The cart is intentionally stateless — React Context backed by localStorage, no auth, no accounts. On checkout, the server creates a Stripe session and returns a hosted checkout URL. Stripe's checkout.session.completed webhook advances the order state machine to PAID and triggers a Resend confirmation email. Customer photos for custom pieces upload directly to Cloudinary via signed uploads.

// order state machine
client
Cart
localStorage\nReact Context
Checkout form
react-hook-form · Zod
↓ create Stripe session
order lifecycle
DRAFT
PENDING_PAYMENT
PAID
↑ checkout.session.completed
Stripe webhook
advances state
Resend
confirmation email
stack

Tech Stack

Frontend
Next.js 16 App Router · React 19 · TypeScript
Styling
Tailwind CSS v4 (oklch tokens) · shadcn/ui · Radix
Forms
react-hook-form · Zod validation
Database
Prisma · PostgreSQL
Models
Artwork · Order · OrderItem
Payments
Stripe Checkout + webhook handler
Media
Cloudinary (signed uploads, transforms)
Email
Resend (transactional)
Analytics
@vercel/analytics
Deploy
Vercel + Docker (local Postgres)
features

Key Features

Filterable artwork gallery sourced from a Cloudinary-backed Postgres table
Three product lines — miniature houses, animal magnets, framed houses
Per-item photo uploads for custom commissions
localStorage cart, multi-item, multi-session, no account required
Stripe Checkout session creation with success / cancel return URLs
Webhook-driven order finalization on checkout.session.completed
Resend confirmation and shipping emails
Feature flag NEXT_PUBLIC_SHOP_ENABLED toggles the shop
SEO — Organization + Product JSON-LD and generated OG images