CASE STUDY

SupaTags

Take the money. Print the label. Never lose the order.

§ PROBLEM

A UK school name-label brand needed two things that are usually two products and three vendors: a shop where a parent designs a sheet of labels in under a minute, and the fulfilment operation that turns that order into a booked Royal Mail parcel. Between them sits the part nobody demos — money that has already moved, and a warehouse that has to agree with the ledger.

§ THE BUILD

One system, front to back. The design studio runs in the browser: text, fonts, colours, icons, photo upload, and generated sticker art. Photo cutout runs on the customer's own device — background removal in a Web Worker over WASM or WebGPU, with a custom alpha-matte refinement pass, a main-thread fallback, and a kill switch — so personalising a photo costs nothing per image and no picture of a child leaves the browser to be processed. Payment is Stripe hosted Checkout over a two-phase order: written pending_payment, promoted to paid only by a signature-verified webhook, with idempotency enforced by conditional update and a reconciliation endpoint that recovers the order if the webhook never lands. Refunds share one code path for full and partial, with a cumulative ratchet so a replayed webhook collapses to nothing. Shipping talks to Royal Mail Pro Shipping v4 — token caching, label PDFs, pre-manifest cancellation, end-of-day manifesting — and scopes every allocation to its own container so a second platform sharing the same Royal Mail account cannot claim our shipments. Behind it all, an admin floor: orders, staged fulfilment, label booking, manifests, refunds, catalogue, promo codes, and a switch that closes the shop.

§ OUTCOME

A shop and a warehouse that hold the same truth, live and taking money. Around 26,400 lines of TypeScript on Next.js 15, React 19 and Supabase, with row-level security as the boundary and isolated production and development environments that fail closed. Designed, built and shipped by one engineer in under two months.

STILLS FROM THE DEVELOPMENT DEPLOYMENT · PICK A STEP TO JUMP TO IT

FEATURE SET

01

The design studio

A parent opens a product and lays out a sheet of labels in the browser: text, fonts, colours, icons, uploaded photos and generated sticker art. No plugin, no upload-and-wait, no proof cycle. What they arrange on the sheet is what the printer receives.

IN-BROWSER CANVAS · CLIENT-SIDE RENDER · PRINT-READY OUTPUT

02

On-device photo cutout

Background removal runs on the customer's own machine — a Web Worker over WASM or WebGPU, a custom alpha-matte refinement pass, a main-thread fallback and a kill switch. Personalising a photo costs nothing per image, and no picture of a child leaves the browser to be processed.

ONNX IN A WEB WORKER · WASM OR WEBGPU · ZERO PER-IMAGE COST

03

The two-phase order

An order is written pending_payment before the customer ever reaches Stripe, and promoted to paid only by a signature-verified webhook. Idempotency is enforced by conditional update, so a replayed event changes nothing, and a reconciliation endpoint recovers the order when the webhook never arrives.

PENDING_PAYMENT → PAID · WEBHOOK-DRIVEN · CONDITIONAL UPDATE

04

The refund ratchet

Full and partial refunds share one code path, and the refunded total only ever moves up. A duplicated or out-of-order webhook collapses to nothing instead of paying a customer twice.

ONE CODE PATH · CUMULATIVE · REPLAY-SAFE

05

Container-scoped allocation

Shipping speaks Royal Mail Pro Shipping v4: cached tokens, label PDFs, pre-manifest cancellation, end-of-day manifesting. Every allocation is scoped to its own container, so a second platform sharing the same Royal Mail account cannot claim our shipments.

ROYAL MAIL PRO SHIPPING v4 · SCOPED CONTAINERS

06

The admin floor

One place to run the business: orders, staged fulfilment, label booking, manifests, refunds, catalogue and promo codes, and a switch that closes the shop. Reach is enforced by row-level security rather than by an unlisted route.

ROW-LEVEL SECURITY · STAGED FULFILMENT · SHOP KILL SWITCH

07

Guest order tracking

Most parents buy once, in a hurry, and will not open an account to do it. An order can be found and followed to the parcel without one.

NO ACCOUNT REQUIRED

SURFACES

SYSTEM ANATOMY

THE STACK — AS BUILT

CLIENT
Next.js 15 · React 19 · TypeScript front to back
DATA
Supabase Postgres · row-level security as the boundary
PAYMENTS
Stripe hosted Checkout · signature-verified webhooks
SHIPPING
Royal Mail Pro Shipping v4 · cached tokens, label PDFs, manifests
IMAGING
On-device ONNX in a Web Worker · WASM or WebGPU, main-thread fallback
EMAIL
Resend · order, dispatch and refund mail
HOSTING
Vercel · isolated production and development, failing closed

BUILD RECORD

  1. PHASE 01

    The studio

    The surface a parent actually touches, built first: text, fonts, colours, icons, photo upload and generated sticker art, all in the browser. Photo cutout was on-device from the start — a Web Worker over WASM or WebGPU, a custom alpha-matte refinement pass, a main-thread fallback and a kill switch.

  2. PHASE 02

    Money

    Stripe hosted Checkout over a two-phase order. Written pending_payment, promoted to paid only by a signature-verified webhook, idempotent by conditional update, with a reconciliation endpoint for the day the webhook never lands.

  3. PHASE 03

    Parcels

    Royal Mail Pro Shipping v4 — token caching, label PDFs, pre-manifest cancellation, end-of-day manifesting. Every allocation scoped to its own container, so a second platform on the same Royal Mail account cannot claim our shipments.

  4. PHASE 04

    The admin floor

    Orders, staged fulfilment, label booking, manifests, refunds, catalogue and promo codes, plus a switch that closes the shop. The point at which the storefront and the warehouse started reading the same record.

< 2 MONTHS

EMPTY REPO TO TAKING REAL MONEY

LINES OF TYPESCRIPT, ONE AUTHOR

ON-DEVICE

PHOTO CUTOUT, ZERO PER-IMAGE COST

IDEMPOTENT

WEBHOOK-DRIVEN ORDER STATE

NEXT SYSTEM

WINGS