Files
craft2prints/HANDOFF.md
T

6.6 KiB

Craft2Prints — Handoff Brief

This project was built in a series of conversations with Claude (chat interface, zip-file delivery). The person is moving to Claude Code to work on it directly. This doc summarizes where things stand so nothing gets lost in the switch.

What this is

An e-commerce site with two parallel catalogs:

  • Personalised (/made-to-order) — customers design their own version of a product using an in-browser design tool (drag text/images onto the product).
  • Products (/products) — same underlying products, but a plain "pick a color/size, buy as-is" page, no design tool.

A single product can be flagged to appear on either catalog, or both, via showOnPersonalised / showOnProducts booleans — same photos either way, nothing duplicated.

Business context: UK-based, GBP is the base/canonical currency, sources some products from a supplier called Firelabel.

Tech stack

  • Next.js 14 (App Router), TypeScript, Tailwind CSS
  • Prisma + SQLite (prisma/dev.db) — easy to swap to Postgres later by changing provider in prisma/schema.prisma and DATABASE_URL
  • Zustand for cart state, persisted to IndexedDB (not localStorage — see Gotchas below for why)
  • Konva / react-konva for the design tool canvas
  • Stripe for checkout
  • Nodemailer for design-approval emails (optional, SMTP-based)

Person's environment (important context)

  • Windows, project lives at D:\Craft2Prints
  • Dev server has repeatedly ended up on port 3001 instead of 3000 because a stale node.exe process keeps holding port 3000 / locking Prisma's engine binary. Recurring fix: Task Manager → kill all node.exe → re-run npx prisma generate. If that keeps happening, it may be worth just settling on 3001 as the working port rather than fighting it every time.
  • Was previously working inside OneDrive, which caused .next build errors (EINVAL: invalid argument, readlink) — project was moved out of OneDrive to fix this. If it ever moves again, keep it outside any cloud-sync folder.
  • Has hit Watchpack Error noise on Windows a few times — next.config.mjs is already configured to fall back to polling-based file watching, which resolved it.
  • Not deeply technical with the terminal — needs exact copy-pasteable commands, not assumed familiarity with npm/Prisma/Stripe CLI workflows.

What's built and working

  • Full product management: add/edit/delete, admin-managed categories (each scopable to either catalog), admin-managed sizes, colors as swatches (not hex text), real photo upload with a drag-to-mark print-area box, optional back photo (own print area), photo-per-color (front AND back), and an optional black/white photo "tint" recolor mode as a fallback when there's no per-color photo.
  • The design tool: front/back personalization, drag/resize/rotate text and uploaded images, 11 font choices, color swatches, size picker. Exports two images per side: a clean transparent print-ready PNG, and a "placement reference" image (design composited onto the actual product photo, for print placement — only generated for photo-based products, not illustration-only ones).
  • Cart (/cart), real Stripe Checkout, webhook-confirmed order persistence, admin order management (/admin/orders) with print files downloadable per order, and order archiving (manual button + auto-archive after 30 days).
  • Custom design-approval flow for one-off jobs: admin uploads a finished design for a specific customer (/admin/proofs/new), customer reviews/approves via a link, with an in-page chat thread and optional email notification.
  • Currency selector (GBP/USD/EUR) — display only, fixed approximate rates, not live; actual checkout always charges in GBP regardless of what's displayed.
  • Dark mode, admin area behind HTTP Basic Auth (ADMIN_USER/ADMIN_PASSWORD in .env).

Known gaps / explicitly not built yet

  • Order confirmation emails — customer only sees the on-screen success page; no automated email receipt yet.
  • "Buy it now" — everything currently goes through the cart, no skip-to-checkout for a single item.
  • /products catalog has no illustration fallback for placement references — only real uploaded photos get a placement-reference image.
  • Checkout's shipping_address_collection allowed countries is a short hardcoded list in src/app/api/checkout/route.ts — worth revisiting for the actual shipping footprint.
  • No multi-currency charging — only display formatting. Stripe currently always charges GBP.

Gotchas specific to this codebase

  • Environment/session resets happened at least once during the build — a chunk of work (categories, sizes, product editing) briefly vanished from the working copy and had to be reconstructed from conversation history. It was fully recovered, but if anything ever seems to have "reverted" unexpectedly, grep for the feature in question before assuming it was never built — it may just need re-syncing rather than rebuilding from scratch.
  • prisma/seed.ts is idempotent and safe to re-run — it only touches the 6 starter products (matched by slug) and 3 starter categories, never anything added through the admin panel. Useful for resetting demo data without wiping real work.
  • Cart storage: moved from localStorage to IndexedDB after a real QuotaExceededError crash — each cart item can carry up to 4 full-size images (print files + placement refs), which blew past localStorage's ~5-10MB cap with just 2-3 items. Don't move this back to localStorage.
  • The image-node-ready race condition: uploaded images in the design tool load asynchronously, unlike text. There's a nodeReadyTick mechanism in DesignCanvas.tsx specifically to re-sync the resize-handle Transformer once an image's Konva node actually mounts. If resize handles ever stop appearing on images again, this is the first place to check — and watch out for calling a state setter unconditionally inside an inline Konva ref callback, since that callback re-fires on every render (this caused an infinite-loop bug once already; the fix was guarding on whether the node reference actually changed).

Setup (for a fresh Claude Code session to verify environment)

npm install
cp .env.example .env    # fill in Stripe keys, admin password, etc. — see README
npx prisma generate
npm run db:push
npm run db:seed
npm run dev

Full details, including Stripe test-mode setup with the Stripe CLI, are in README.md at the project root — it's been kept up to date throughout the build and is the more detailed reference; treat this file as the high-level orientation and README.md as the how-to.