Le Vanià

Overview
The online store of a Florentine maker of handmade luxury clogs, built as a fully headless e-commerce: a custom Next.js storefront on a WooCommerce back end, with Stripe payments.
Stack
Next.js 16 (App Router), TypeScript, WooCommerce REST API (headless), CoCart, Stripe (Payment Element, Express Checkout, webhooks), NextAuth, Twilio Verify, GSAP, Vercel, Cloudflare R2
What I built
- Headless architecture: server components with client islands, WooCommerce reached only through its REST API, product pages cached and revalidated every five minutes, and a server-side cart session through CoCart.
- Stripe checkout without the server SDK: the WooCommerce order is created first, then a PaymentIntent for WooCommerce's own total with an idempotency key. Cards, Apple Pay, Google Pay, Link, PayPal and Klarna run through Stripe Elements and Express Checkout, also straight from the product page.
- A Stripe webhook with a hand-written signature check (HMAC-SHA256, constant-time comparison, a replay window) that verifies the amount and the PaymentIntent against the order, skips duplicate events and never moves a paid order back.
- A deny-by-default API proxy in front of WooCommerce: only allowlisted routes, an ownership check on every customer and order, and request bodies rebuilt from allowed fields, so nobody can write a password, an email, a role or another user's data.
- A configurator for the modular clog: base, two uppers and size as one WooCommerce variable product, with the chosen configuration shareable by URL.
- Accounts with email and password through WordPress plus Google sign-in, order history behind ownership checks, guest checkout, and the online withdrawal flow required by EU law, recorded idempotently.
- Search engine work for a store: Product JSON-LD with shipping and return policies, breadcrumbs, a dynamic sitemap and 301 redirects from the old WordPress URLs.
Key decisions
- The amount charged always comes from WooCommerce's order total, recomputed on the server. A price from the browser is never trusted, and an invalid price throws instead of falling back to zero.
- The webhook owns the payment state. The confirmation from the browser can only complete an order that is still pending.
- A production incident solved from the logs: the host's anti-bot layer was blocking API calls (671 failures across 63 users). It became its own error type with exponential backoff and jitter, product fetches were batched into one request, and visitor headers stopped being forwarded.
- Cash on delivery was gated by an SMS code, proved by a signed, single-use cookie tied to the buyer. It shipped and was later switched off.
- It started on Vite and moved to Next.js, and from Cloudflare Pages to Vercel: 356 commits and about 23,000 lines of TypeScript.
Live Preview (opens in a new window)Source is private