Storefront

Last updated on 2026-08-30

The storefront is the public-facing shopping experience. All pages are Server Components that query Supabase directly — no client-side data fetching for the initial render.

Pages Overview

Route Page Data Source
/ Homepage Featured products, categories, collections
/products Product Listing All products with filters
/products/[slug] Product Detail Single product with variants, images, reviews
/categories/[slug] Category Page Products filtered by category
/collections/[slug] Collection Page Products in a curated collection
/search Search Results Full-text search on products
/wishlist Wishlist User's saved products

Data Fetching Pattern

All storefront queries are in lib/queries.ts. Server Components call these directly:

// In a page.tsx Server Component
import { fetchProducts, fetchCategories } from "@/lib/queries"

export default async function ProductsPage() {
  const products = await fetchProducts()
  const categories = await fetchCategories()

  return <ProductsClient products={products} categories={categories} />
}

The client component receives server-fetched data as props and handles interactivity (filters, sort, pagination).

Homepage

The homepage queries four data sources:

  • Featured products — top 8 products by rating
  • Categories — all 4 categories with images
  • Collections — curated product groups
  • Deals — products with active sale_price

Product Listing (/products)

Server-side filtering with these parameters:

Filter Query Parameter Implementation
Category category .eq('category_id', id)
Price range minPrice, maxPrice .gte('price', min).lte('price', max)
Size size Join on product_variants
Color color Join on product_variants
Rating rating .gte('rating', value)
Search q .ilike('name', '%query%') or .textSearch()
Sort sort price-asc, price-desc, newest, rating

The client component (products-client.tsx) manages filter state and updates the URL search params.

Product Detail (/products/[slug])

Fetches a single product by slug with related data:

const product = await fetchProductBySlug(slug)
// Includes: variants, images, reviews, related products

The page renders:

  • Image gallery with thumbnail navigation
  • Variant selector (size, color) with stock status
  • Add to cart with quantity picker
  • Customer reviews from the database
  • "Frequently bought together" from product_bundles table
  • Related products from the same category

Full-text search queries the name, description, and tags fields:

const { data } = await supabase
  .from("products")
  .select("*")
  .or(`name.ilike.%${query}%, description.ilike.%${query}%`)
  .eq("status", "active")

Results render with the same product card grid used on the listing page.

Static Pages

These pages use data from data/static.ts (not the database):

  • /about, /contact, /faqs
  • /shipping-info, /returns, /size-guide
  • /privacy, /terms, /careers, /press
  • /blog, /blog/[slug]