feat: shipping methods, announcement banners, legal compliance#1
Merged
Lutherwaves merged 132 commits intomainfrom Mar 13, 2026
Merged
Conversation
Full architecture decision record covering monorepo restructure, tRPC+Drizzle+Supabase stack, bidding system, product catalog with JSONB variants, guest checkout, admin panel, i18n, and Netlify deploy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
22-task plan covering monorepo restructure, tRPC+Drizzle+Supabase stack, bidding system, Stripe checkout, admin panel, i18n, and Netlify deploy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Publishes from apps/website/.next with turbo filter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8 tables: artworks, products, product_variants, orders, auctions, bids, inquiries, newsletter_subscribers. Migration applied to Supabase. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Includes context, router factory, inquiries (Resend emails) and newsletter (Buttondown sync) routers. Tests passing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
validateBid is a pure function — 5 unit tests covering deadline, min bid, and increment enforcement. All 7 tests passing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds @vamy/db exports for ./trpc and ./trpc/context. Stripe initialized lazily to avoid module-load errors in tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- App Router: /api/trpc/[trpc] + /api/webhooks/stripe - src/lib/trpc.ts client - Lazy DB + Resend init to avoid build-time throws - next.config.js: ignoreBuildErrors (type-check via tsc --noEmit in CI) - tsconfig paths for @vamy/* workspace packages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tests/ workspace: Vitest for API, Playwright for UI - API tests: inquiries.create + newsletter.subscribe (6/6 pass) - E2E tests: page smoke tests + inquiry form prefill (6/6 pass) - tRPC v11 wire format: raw JSON body (no superjson wrapper) - apps/website/.env.example: documents all required env vars - pnpm-workspace.yaml: includes tests/ package Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Blocks direct anon-key access to every table. Server-side tRPC uses DATABASE_URL (postgres superuser) so it bypasses RLS unaffected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove HubSpot integration from FormBlock, replace with trpc.inquiries.create - Add tRPC + React Query provider to _app.tsx (replaced _app.js) - Add NewsletterSignup component to Footer via trpc.newsletter.subscribe Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tripe - BidWidget: live bid display with Supabase Realtime + 30s polling fallback, countdown timer, bid modal - ProductSelector: variant picker with Stripe Checkout redirect - Install @supabase/supabase-js in website package Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cher - Install next-intl, configure withNextIntl plugin in next.config.js - Add i18n Pages Router config (locales: en/de/bg, default: en) - Create src/i18n/routing.ts and request.ts for App Router integration - Add LocaleSwitcher dropdown to Header (uses next/router locale switching) - Inline locale names in Header to avoid webpack bundling TS workspace source Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task 15 — Bootstrap: - Next.js 15 App Router, TypeScript strict mode, Tailwind, autoprefixer - Route group (dashboard)/ for protected pages, login/ for public auth - tRPC API route at /api/trpc (reuses appRouter from @vamy/db) - Providers client component (tRPC + React Query) - Netlify config, .gitignore, .env.example Task 16 — Auth: - @supabase/ssr (recommended package for App Router, not deprecated auth-helpers) - lib/supabase/server.ts + client.ts (server/browser split) - middleware.ts: redirects unauthenticated users, refreshes session cookies - Login page with email/password form Tasks 17-20 — Dashboard views: - /auctions: open/close auctions, bid history table - /orders: fulfillment table with tracking number input + mark shipped - /artworks: product list with inline variant management (stock, price) - /inquiries: table with mailto: reply link, mark-handled action Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The withNextIntl plugin is App Router only. Using it alongside the Pages Router i18n config caused a routing conflict that 404'd the root URL. Removed the plugin wrapper; Pages Router handles locale routing natively via the i18n config in next.config.js. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…for locale pref The Pages Router i18n config conflicts with Stackbit's getStaticPaths URL string format, causing GET / to 404. Removed i18n config; locale switcher now stores preference in localStorage. URL-based locale routing requires a deeper content architecture change and is deferred. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ield names
- Add Vamy logo to admin sidebar header
- Seed 3 artworks (Whispers, First Contact, On the Horizon) as available
- Seed original painting product (€2,500 placeholder, 1 of 1) per artwork
- Seed fine art print product per artwork with 4 giclée variants:
A4 21×30cm €75 (ed. 50), A3 30×42cm €120 (ed. 50),
50×70cm €200 (ed. 30), 70×100cm €350 (ed. 20)
Industry standard: 300gsm archival cotton, signed & numbered limited edition
- Fix orders page: productVariant.name, amountPaid (not totalAmount/variantId)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without relations defined, all db.query calls using `with: {}` returned 500.
Added relations for artworks, products, productVariants, orders, auctions, bids.
Fixed inquiries page: inq.handled → inq.handledAt (actual column name).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ess page - PostLayout: dynamically imports ProductSelector + BidWidget (ssr:false), extracts artwork slug from URL path, renders commerce widgets after content - /order/success: confirmation page shown after Stripe checkout completes - Gallery markdown: rename CTA from "PREORDER A PRINT" to "INQUIRE ABOUT THE ORIGINAL" — disambiguates from the new print purchase selector Purchase flow is now end-to-end: artwork page → ProductSelector → Stripe Checkout → webhook → order in DB → confirmation email to buyer + notification to artist → /order/success Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New /get-a-piece page (bypasses catch-all, owns its own route)
- Two-column layout: artwork context + 4-step process guide on left,
form on right
- When arrived from artwork page (?piece=), shows artwork thumbnail,
medium, dimensions, and pre-fills + locks the piece field with
an escape hatch to change it
- Labelled fields (not just placeholders), optional message with
contextual placeholder examples
- Personalised success state ("Thank you, {name}")
- Micro-copy: "Maeve will reply personally — no bots, no templates"
- Exclude /get-a-piece from [[...slug]] to avoid path conflict
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds optional userId field (default null) to the tRPC context, laying the groundwork for protectedProcedure auth checks. Updates inquiry test mocks to satisfy the updated context shape. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…mplementation details Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds ISR to the Pages Router catch-all: new paths render on demand (fallback:blocking) and cached pages revalidate every hour. Also adds tRPC v11 server caller (appRouter.createCaller) for use in getStaticProps in upcoming data-fetching tasks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET (query) responses are cached for 1 hour at the CDN edge with stale-while-revalidate of 24 hours. POST (mutation) responses are passed through unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Accepts POST with x-revalidate-secret header and a comma-separated paths query param. Calls res.revalidate() for each path in parallel. REVALIDATION_SECRET and NEXT_PUBLIC_WEBSITE_URL added to .env.local (gitignored). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vamy/db imports postgres (Node.js-only) which webpack tries to bundle for the browser when pages import from @vamy/db/trpc. Adding webpack externals for postgres/resend/stripe in browser builds prevents the 'can't resolve fs/perf_hooks' errors while keeping transpilePackages intact for TypeScript compilation. Also adds server-only to @vamy/db devDependencies for future use. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n homepage Replaces the client-side tRPC hook in AnnouncementBanner with a prop-driven component fed from getStaticProps. Banner and featured artwork image are now embedded in the static HTML at build/revalidation time. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes client-side ArtworkCardInfo dynamic import. Gallery index now fetches product data per artwork in getStaticProps and passes it via props. ArtworkCardInfoStatic renders medium, dimensions, price, and availability without any client-side JS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes client-side ArtworkDetails dynamic import. Detail pages now receive artworkProduct via getStaticProps and render medium, dimensions, price, and availability through ArtworkDetailsStatic with no client-side data fetching. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ce post mutation Extract shared variant-derivation logic from ArtworkCardInfoStatic and ArtworkDetailsStatic into apps/website/src/utils/artwork-product.ts. Replace in-place post.artworkProduct mutation in [[...slug]].js with a non-mutating map that returns new post objects. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ro components Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…policies Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The release workflow was using npm (causing lock file errors) and triggering on PRs where semantic-release has nothing to do. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
_app.tsx./privacy), legal notice in footer (company EIK, address), Privacy link in footer, copyright year auto-increments, Terms corrected (Stripe-only payments, VAT language, company details added).What's New
packages/db:shipping_methods+bannerstables, tRPC routers for both,products.shippingMethodIdFKapps/admin: Shipping Methods page, Banners page, shipping dropdown on Artworks page, nav itemsapps/website:AnnouncementBannercomponent, shipping display inProductSelector, privacy page, footer updatesTest Plan
gallery, verify it shows only on/gallery/privacypage loadspnpm test)🤖 Generated with Claude Code