Locker Module, Design Catalogue, SendGrid & Screenshot Renderer

Full locker (saved designs) CRUD with builder panel and dashboard, public design catalogue with category browsing, SendGrid mailer provider, lazy 3D screenshot renderer, and server actions body-size fix.

Overview

This release introduces the Locker module (save, manage, and share builder designs), a public design catalogue with category-driven browsing, SendGrid as a new mailer provider, a lazy 3D screenshot renderer for catalogue thumbnails, and several database/config improvements.

Locker Module — Saved Designs

Database

Migration 20260226120000_lockers.sql creates public.lockers:

ColumnTypePurpose
account_iduuid FKOwner (personal account)
sporttextSport category
product_slugtextProduct identifier
config_datajsonbFull BuilderData snapshot
nametextOptional user label
preview_front_urltextFront preview image
preview_back_urltextBack preview image

RLS policies restrict all operations to the owning account. Indexed on (account_id, updated_at DESC) for fast listing.

Builder Panel

LockerPanel slides into the builder's 1/3-width sidebar slot (same container as steps, brand templates, and quotes). Two views:

  • LockerPanelList — paginated list of saved designs with preview thumbnails, sport badge, and relative timestamps. Supports delete with confirmation.
  • LockerPanelDetail — inline drill-down showing full config preview, "Load into Builder" and "Get Share Link" actions.

Context is managed by LockerPanelContext (open/close state, selected locker, data fetching).

Server Actions

ActionPurpose
saveLockerActionInsert or update a locker. Receives config data + preview URLs.
fetchLockersPanelActionFetch current user's lockers for the panel (paginated, newest first).
deleteLockerActionSoft-delete a locker by ID (RLS-enforced ownership check).
getLockerShareLinkActionCreates a builder_shared_configs entry and returns a shareable builder URL.

Dashboard Pages

Full admin-style CRUD under /home/lockers:

  • Lockers list page — data table with search, sort, and bulk actions.
  • Locker detail page — read-only view with config inspector and action buttons.
  • Navigation entry added to personal-account-navigation.config.tsx.
  • Translation namespace: lockers.json (51 keys).

Design Catalogue — Public Browsing

Architecture

The catalogue lives under the (uniform-builder) route group and provides category-driven design discovery:

  • Landing page (page.tsx) — renders CategoryGrid showing all sport categories with product counts.
  • Category designs page ([category]/designs/page.tsx) — renders DesignGrid with product × design combinations for a category.

Server Loader

designs-catalogue.loader.ts exposes loadDesignCombinations(category):

  1. Fetches active, enabled products in the category.
  2. Fetches active, showable designs whose products array overlaps the product IDs.
  3. Builds the cross-product: one DesignCombo per (product, design) pair.

Components

ComponentPurpose
CategoryGridCard grid of sport categories with product counts and icons.
DesignCardIndividual product/design combo card with lazy 3D screenshot, sport badge, and "Customize" CTA.
DesignGridResponsive grid of DesignCard items with filtering support.
TeamNameSearchAutocomplete search for team names — filters catalogue results by team.

Lazy Screenshot Renderer

use-lazy-screenshot.ts generates 3D preview thumbnails on-demand:

  • Uses IntersectionObserver — only renders when the card scrolls into view.
  • Spins up an offscreen Three.js renderer, loads the GLB model, applies the SVG texture + color material, and captures a PNG frame.
  • Module-level LRU cache (100 entries max) prevents redundant renders across re-mounts.
  • Returns { ref, imageUrl, isLoading, error } for simple integration into any card component.

SendGrid Mailer Provider

New package @kit/mailers/sendgrid implements the Mailer interface using the Twilio SendGrid Web API v3 (@sendgrid/mail).

  • Registered in packages/mailers/core/src/registry.ts under the sendgrid provider enum.
  • Environment variable: SENDGRID_API_KEY (validated at startup via Zod).
  • Set MAILER_PROVIDER=sendgrid to activate.

Sales Rep Improvements

  • Sales Rep Grid (sales-rep-grid.tsx) — visual grid display of available sales reps with headshots, name, and territory info.
  • Sign-up with Sales Rep Preview — during sign-up, shows a preview card of the matched sales rep (geo-search or brand template) before account creation.
  • API Route (/api/salesreps/geo-search) — public-facing proxy to Game One geo-search endpoint, used by the sign-up flow for real-time rep matching.

Database Migrations

MigrationDescription
20260226120000_lockerslockers table with RLS, indexes, and grants
20260226140000_fix_products_update_rlsFixes restrictive UPDATE RLS policy on products
20260226150000_seed_designs_from_sourceSeeds design rows from source data for catalogue population

Server Actions Body Size Limit

Added serverActions.bodySizeLimit: '5mb' to next.config.mjs. The default 1 MB limit was causing 413 errors on the review step when base64 screenshot data + builder config exceeded the threshold.

Builder & Auth Tweaks

  • Text step — text assignment improvements for element placement.
  • Builder 3D scene — simplified render pipeline, removed unused material overrides in model-with-materials.tsx.
  • Auth provider — extended AuthProvider to propagate additional user metadata for downstream contexts.
  • Sentry config — updated client and server configs with refined sampling and environment settings.