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_bundlestable - Related products from the same category
Search
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]