web

SDB WEAR — Premium Motorcycle Protection & Leather Gear (Pakistan)

SDB WEAR is a production-ready, 100% free-to-host e-commerce platform: a statically exported Next.js storefront on GitHub Pages (https://www.sdbbuy.com), backed entirely by Supabase (Postgres, Auth, Row Level Security, Edge Functions). There is no traditional application server anywhere in this stack.

The brand (roots in 2017, Pakistan) sells premium motorcycle protection and leather gear — moto suits, moto gloves, moto shoes, leather jackets and handcrafted stitched gloves — with secure card checkout internationally.

Architecture

Browser (GitHub Pages, static HTML/JS)
   │
   ├── Supabase Postgres (via supabase-js, anon key, RLS-protected reads)
   │       - public product/category catalog reads
   │       - authenticated users' own orders
   │
   └── Supabase Edge Functions (Deno, service-role key, the ONLY place
       that computes prices and writes orders/order_items)
           - create-checkout        → Stripe Checkout Session (USD, international)
           - local-gateway-checkout  → JazzCash / Safepay mock template (PKR)
           - stripe-webhook          → verifies Stripe signature, marks orders paid

Why this is safe with no backend server: every price the customer is charged is recomputed from the products / product_variants tables inside an Edge Function running with the Supabase service role key. The browser never sends a price — only product_id, variant_id, and quantity. RLS policies additionally stop a signed-in user from inserting an order that’s already marked paid, or an order_items row priced differently from the live catalog.

Repository layout

.
├── .github/workflows/
│   ├── ci.yml        # Quality gate: typecheck + lint + tests + build (push/PR)
│   └── deploy.yml    # CI/CD: build+deploy frontend, deploy Supabase backend
├── frontend/         # Next.js 14 App Router, output: 'export'
├── supabase/
│   ├── migrations/   # SQL schema, RLS policies, seed catalogs
│   ├── functions/    # Deno Edge Functions (create-checkout, local-gateway-checkout, …)
│   └── config.toml
└── README.md

Catalog

Three product families (the storefront nav, homepage cards, and shop filters are driven entirely by the categories table — parent_id enables subcategories):

Family Subcategories Products
Motorbike Gear Moto Suits, Moto Gloves, Moto Shoes 13
Leather Jackets & Biker Fashion Biker, Casual, Heritage, Racing-Inspired jackets, Biker Fashion (vests) 12
Handcrafted Gloves Leather, Riding, Driving, Work, Fashion, Mechanic, Tactical, Custom 12

Products support rich merchandising fields: brand, multi-image galleries (images JSONB, shown with thumbnail navigation on the product page), rating / review_count (not seeded — review numbers come from real customers), optional compare_at_price_* sale pricing, SEO metadata (seo_title, seo_description, seo_keywords), and size/option variants with unique SKUs. All previous catalogs (legacy demo, the 2026 SDBBUY leather/boxing/gym catalog, and the motorbike marketplace) are deactivated; rows referenced by historical orders are preserved (inactive) so order history is never lost, while every customer-facing page shows only the new SDB WEAR catalog. Product imagery is elegant branded SVG placeholders — no fake product photography.

Storefront features

Prerequisites

1. Local setup

git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git
cd YOUR_REPO

# --- Frontend ---
cd frontend
npm install
cp .env.local.example .env.local
# edit .env.local with:
#   NEXT_PUBLIC_SUPABASE_URL=https://YOUR_PROJECT_REF.supabase.co
#   NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-public-key
#   NEXT_PUBLIC_SUPABASE_FUNCTIONS_URL=https://YOUR_PROJECT_REF.supabase.co/functions/v1
npm run dev   # http://localhost:3000

Quality checks (mirrors the CI gate):

npm run typecheck   # tsc --noEmit
npm run lint        # next lint
npm test            # vitest (lib unit tests)
# from the repository root
supabase login
supabase init            # only if supabase/ wasn't already scaffolded (it is, in this repo)
supabase link --project-ref YOUR_PROJECT_REF

Find YOUR_PROJECT_REF in your Supabase project’s dashboard URL: https://supabase.com/dashboard/project/<THIS_IS_YOUR_REF>.

3. Push the database schema

supabase db push

Migrations (in supabase/migrations/, applied in order):

  1. Initial schemaprofiles, categories, products, product_variants, orders, order_items, RLS policies, stock-decrement RPCs, Stripe event dedupe table.
  2. Seller Centralprofiles.role, seller RLS policies, seller_notifications, inventory_log, promotions, seller_settings, product-images storage bucket, is_seller() authorization gate, categories.parent_id + is_active.
  3. Seller notification preferences — preference-aware order/payment/stock triggers and low/out-of-stock alerts.
  4. SDBBUY catalog — professional seed catalog (leather, boxing, gym, accessories) replacing demo products.
  5. Motorbike category — removes the Apparel categories, adds Motorbikes with 10 subcategories and 30 gallery products, plus optional merchandising columns (brand, images, rating, review_count, compare_at_*).
  6. SDB WEAR redesign — adds product SEO columns, retires every previous customer-facing catalog (legacy demo, SDBBUY leather/boxing/gym, motorbike marketplace), preserves order-referenced rows as inactive, and seeds the new three-family SDB WEAR catalog (Motorbike Gear, Leather Jackets & Biker Fashion, Handcrafted Gloves — 37 products, ~200 variants, branded SVG placeholders, no fabricated ratings).

4. Configure secrets (used by the Edge Functions)

supabase secrets set \
  STRIPE_SECRET_KEY=sk_test_xxx \
  STRIPE_WEBHOOK_SIGNING_SECRET=whsec_xxx \
  SITE_URL=https://www.sdbbuy.com

SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY are injected automatically into every hosted Edge Function — you do not set them yourself.

For local testing, also add SUPABASE_ANON_KEY to supabase/functions/.env (the CLI reads this file for supabase functions serve); in production it is likewise auto-injected.

5. Deploy the Edge Functions manually (first time / local testing)

supabase functions deploy create-checkout
supabase functions deploy local-gateway-checkout
supabase functions deploy stripe-webhook --no-verify-jwt

stripe-webhook must be deployed with --no-verify-jwt because Stripe, not a signed-in Supabase user, calls it — Stripe cannot supply a Supabase JWT. Signature verification inside the function itself is what secures this endpoint instead.

6. Point Stripe at your webhook

In the Stripe Dashboard → Developers → Webhooks, add an endpoint:

https://YOUR_PROJECT_REF.supabase.co/functions/v1/stripe-webhook

Subscribe to: checkout.session.completed, checkout.session.expired, payment_intent.payment_failed. Copy the signing secret into STRIPE_WEBHOOK_SIGNING_SECRET above.

7. Configure GitHub Actions secrets

In your repo → Settings → Secrets and variables → Actions, add:

Secret Value
NEXT_PUBLIC_SUPABASE_URL https://YOUR_PROJECT_REF.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY Supabase → Settings → API → anon public key
NEXT_PUBLIC_SUPABASE_FUNCTIONS_URL https://YOUR_PROJECT_REF.supabase.co/functions/v1
SUPABASE_ACCESS_TOKEN Supabase → Account → Access Tokens
SUPABASE_PROJECT_REF Your project ref
SUPABASE_DB_PASSWORD Your project’s database password
STRIPE_SECRET_KEY Stripe → Developers → API keys
STRIPE_WEBHOOK_SIGNING_SECRET From step 6
SITE_URL https://www.sdbbuy.com

In Settings → Pages, set Source to GitHub Actions.

8. Push to GitHub

git add .
git commit -m "Initial commit: Jamstack storefront on GitHub Pages + Supabase"
git branch -M main
git remote add origin https://github.com/YOUR_USERNAME/YOUR_REPO.git
git push -u origin main

Pushing to main triggers:

Your storefront is live at https://www.sdbbuy.com/.

Rebuilding after a catalog change

Because product data is fetched at build time (generateStaticParams + server-component fetches, since there’s no server to hit at request time), adding or editing a product (or applying a new Supabase migration) requires a rebuild. Trigger one from the Actions tab (workflow_dispatch) or push any commit — no code change is required.

Local currency notes