BUILD: PRODUCTION WHITE-LABEL ECOMMERCE (HTML/CSS/Vanilla JS + Supabase + Razorpay + Vercel)

Build a complete, secure, resellable white-label store + admin. Generate COMPLETE code for every file. No placeholders, no TODOs, no skipped files. Vanilla JS only — NO React/Vue/Angular/jQuery, no bundler for UI.

HARD INVARIANTS (must hold — these are the build's spine)

  1. Secrets never in the browser. Only PUBLIC_* env vars reach the client, written at build time by scripts/generate-env.jsjs/env.js (window.__ENV). The service-role key, Razorpay secret, and webhook secret live ONLY in /api serverless (process.env). Zero credentials in source.
  2. Payments verified server-side. Client makes a pending order (RLS: own only) → POST /api/create-order re-reads the order from DB (NEVER trusts client amounts), creates the Razorpay order with the secret, stores razorpay_order_id → Checkout opens with the PUBLIC key id → POST /api/verify-payment recomputes HMAC_SHA256(razorpay_order_id| payment_id, secret), compares timing-safe, and ONLY then sets payment_status='paid' via the service role → POST /api/razorpay-webhook verifies X-Razorpay-Signature against the RAW body (bodyParser off) for captured/failed/refunded.
  3. No client can self-mark an order paid. No RLS policy may permit a client to write payment_status='paid'. Only the service role (inside verify-payment/webhook) can.
  4. RLS on every table, default deny. Users touch only their own cart/wishlist/addresses/ orders/order_items/payments/reviews. Public read = active products/categories + the single store_settings row. Admin writes gated by SQL is_admin() (profiles.role + admin_users).
  5. White-label = data only. The whole site rebrands by editing .env + the store_settings row — never code. settings.js loads the singleton row, caches it, and applies brand colors (CSS vars -brand-primary/secondary/accent), logo, favicon, title, meta/OG, navbar, footer, and data-store="<field>" bindings — into navbar, footer, SEO/OG, emails, invoices, admin, checkout, contact.
  6. XSS-safe + parameterized. Escape all DB/user strings (esc() for & < > " ') before HTML; never innerHTML raw input. Supabase client/RPC only — no string-built SQL.

SETUP WIZARD

If store_settings is empty → auto-redirect to a branded multi-step wizard (setup.html + js/setup.js): website name, company, logo, favicon, primary/secondary/accent colors, currency, support email, phone, address, socials, AND create the first admin account. The FIRST registered user auto-becomes admin via a SQL trigger. Upload logo/favicon to Storage, write the singleton row, site goes live. Include maintenance_mode + a "not configured" banner.

DATABASE — 4 files, run in order

CUSTOMER

Homepage (hero, featured, trending, categories, best sellers, testimonials, newsletter, FAQ). Shop (DEBOUNCED search, category/brand/price filters, sort, pagination). Product (gallery + zoom, variants, reviews/ratings, related, recently-viewed via localStorage). Wishlist. Cart (guest=localStorage + user=DB, auto-merge on login). Checkout. Profile. Order tracking. Auth: email/password, register, forgot/reset, Google OAuth, magic link, email verification.