Back to blog
EngineeringDate unavailable· min read

Wiring Strug City Sports Into the Sanity Product Catalog

The fourth product page (Strug City Sports) forced us to solve a real problem: how do you maintain a canonical product catalog when Sanity is the source of truth but bespoke page routes don't match CMS slugs?

We shipped the Strug City Sports product page two weeks ago. Full seven-section landing page with demo videos, competitive thesis, Aurora gradients, zero client-side JavaScript. Beautiful. But there was a disconnect.

The page existed at /products/strugcity-sports. The product appeared in the Sanity catalog as "Strug City Sports" with a slug of strug-city-sports. But the /products page — the main product grid — wasn't wired to route to it. You could visit the page directly, but the discoverability layer was missing.

The deeper issue: we had deprecated product names floating around (BanditsTracker, Strug AI Platform), the canonical catalog wasn't enforced, and the relationship between Sanity slugs and Next.js routes was implicit. You had to grep the codebase to figure out what mapped where.

The Fix: Canonical Catalog + Explicit Routing

We did three things:

  • Created a patch-products.ts script that deletes stale product documents (BanditsTracker, Strug AI Platform) and upserts the canonical five-product catalog: Sabine Super Agent, Strug Works Virtual Engineering, Strug City Sports, Anti-Strug, and Strug Enterprise Site.
  • Added a SLUG_TO_PAGE_ROUTE constant in src/app/products/utils.ts that explicitly maps Sanity slugs to bespoke Next.js routes. No more guessing. If a product has a custom page, the mapping lives here.
  • Created filterDisplayedProducts() utility that filters the raw Sanity product list for public display — excluding the enterprise site itself and guarding against null slugs from draft documents.

The SLUG_TO_PAGE_ROUTE map solves a real architectural tension. Sanity slugs follow CMS naming conventions (kebab-case, descriptive). Next.js routes follow URL conventions (short, memorable, sometimes different). The Sports page is at /products/strugcity-sports but the Sanity slug is strug-city-sports. The map is the contract.

Why This Matters

We committed to Sanity as the source of truth for product metadata. That means the /products grid, OG images, RSS feeds, sitemaps — everything that depends on the product catalog — should pull from Sanity. But we also wanted bespoke product pages with custom routes and visual identity.

The tension is real: CMS flexibility vs. developer control. The solution is to make the contract explicit. SLUG_TO_PAGE_ROUTE is 12 lines of TypeScript. Everyone knows where to look.

What's Next

Two more product pages are coming: Feedtumi (nutrition coaching) and Poppin (personal finance). Both already have placeholder routes and Sanity schema slots. When we ship them, the patch script will add them to the canonical catalog and SLUG_TO_PAGE_ROUTE will wire the routes.

The pattern is established. The product grid is Sanity-powered. The routes are explicit. The catalog is maintained. What started as a one-off fix for Sports is now the repeatable infrastructure for every product we ship.