A resume-scale e-commerce storefront built as a multi-page site: HTML, CSS, TypeScript, Vite as the bundler (not a UI framework), Supabase for the backend (Postgres, Auth, Row Level Security), and Cloudinary for product media.
Cloudinary is the image CDN, not the product database. Product records, users, carts, and orders live in Supabase. Each product stores a Cloudinary public_id.
We will complete this project phase by phase. Session progress is recorded in activeContext.md so the next session can continue without re-scanning the whole tree.
| Layer | Choice |
|---|---|
| Pages | Multi-page HTML (index.html + pages/) |
| Language | TypeScript modules, compiled by Vite |
| Style | Plain CSS with design tokens |
| Bundler | Vite (aliases, multi-page build) |
| Backend | Supabase (Postgres + Auth + RLS) |
| Media | Cloudinary delivery URLs + unsigned upload later |
| Data now | Mock catalog in TS, then Supabase |
Libraries are added only when a phase needs them (@supabase/supabase-js is the first).
npm install
copy .env.example .env.local
npm run devOpen the URL Vite prints (usually http://localhost:5173). Home is /, shop is /pages/shop.html.
npm run build
npm run preview.env.local is gitignored. Copy .env.example and fill VITE_* keys. The Cloudinary API secret must never use a VITE_ prefix.
The catalog still uses mock products until supabase/migrations/001_init.sql is applied in the Supabase SQL editor. Cart and wishlist stay in localStorage until auth lands.
Optional later: npm run seed:cloudinary uploads placeholder photos to Cloudinary folder velora/ (uses the server-only API secret locally).
This mix is the right default for a vanilla multi-page shop: HTML by route, TypeScript by feature, shared UI and tokens in one place.
Html-Css-Landing-Page/
├── index.html Home
├── pages/ One HTML file per storefront / admin route
│ ├── shop.html
│ ├── product.html
│ ├── cart.html
│ ├── checkout.html
│ ├── login.html
│ ├── register.html
│ ├── account.html
│ ├── orders.html
│ ├── order-detail.html
│ ├── wishlist.html
│ ├── search.html
│ ├── about.html
│ ├── contact.html
│ ├── faq.html
│ ├── blog.html
│ ├── blog-post.html
│ ├── privacy.html
│ ├── terms.html
│ ├── shipping.html
│ ├── returns.html
│ ├── 404.html
│ └── admin/
│ ├── index.html
│ ├── products.html
│ ├── product-edit.html
│ ├── orders.html
│ ├── customers.html
│ └── media.html
├── public/ Static files copied as-is
├── supabase/
│ ├── migrations/ SQL schema
│ └── seed.sql
├── src/
│ ├── app.ts Boot: CSS + header/footer
│ ├── vite-env.d.ts
│ ├── assets/ Local images, icons, fonts (later)
│ ├── styles/ Tokens, reset, base, layout, page CSS
│ ├── lib/ Third-party clients
│ │ ├── supabase/ Client + auth helpers
│ │ └── cloudinary/ Delivery URL builder
│ ├── shared/
│ │ ├── components/ Header/footer, product card
│ │ ├── types/
│ │ └── utils/
│ ├── features/ Domain modules (feature-based)
│ │ ├── auth/
│ │ ├── catalog/
│ │ ├── product/
│ │ ├── cart/
│ │ ├── checkout/
│ │ ├── orders/
│ │ ├── account/
│ │ ├── wishlist/
│ │ ├── reviews/
│ │ ├── search/
│ │ ├── newsletter/
│ │ ├── blog/
│ │ ├── contact/
│ │ ├── media/
│ │ └── admin/
│ └── pages/ Page entry scripts (import features)
├── vite.config.ts Aliases + multi-page inputs
├── tsconfig.json
├── package.json
├── .env.example
├── README.md This roadmap
└── activeContext.md What is already done
A product page needs catalog data, cart actions, wishlist, and later reviews. Those should live in features/*, not inside one giant pages/product.ts. Page files stay thin: query the DOM, call feature APIs.
- New page → HTML in
pages/+ entry insrc/pages/<name>/+ add the HTML path tovite.config.ts. - New domain behavior →
src/features/<name>/. - Shared chrome (header, money format, types) →
src/shared/. - After finishing a slice, update both this README (phase checkboxes) and
activeContext.md.
- Vite + TypeScript multi-page setup
- Feature-based
src/tree and storefront HTML routes - Design tokens and base layout (header/footer)
- Mock catalog, localStorage cart and wishlist
- Supabase client stub + draft SQL schema
- Cloudinary URL helper
- README +
activeContext.md -
.env.localwired (Supabase URL + publishable key, Cloudinary cloud name)
- Mobile navigation (drawer)
- Button, field, badge, empty-state components
- Product cards and PDP use Cloudinary delivery URLs
- Skip link, focus styles, color contrast pass
- 404 wired in Vite preview / host
- Apply
supabase/migrations/001_init.sqlon a project - Map DB rows to
Producttypes (used whenproductsexists; otherwise mock) - Shop filters (category, price, availability)
- Sort (newest, price)
- Pagination or “load more”
- Featured collection on home from Supabase
- Gallery (Cloudinary transforms)
- Size / color pickers that affect cart line identity
- Related products
- Stock messaging
- JSON-LD product schema
- Copy
.env.localkeys - Sign up, sign in, sign out
-
profilesrow on signup (trigger) - Protected account / orders routes
- RLS policies for profiles
- Sync cart to
cart_itemswhen logged in; keep guest cart in localStorage - Merge guest cart on login
- Checkout validation and order insert
- Mock payment first (no real charges), optional Stripe later
- Order list + order detail
- Email confirmation via Supabase (optional)
- Addresses
- Wishlist synced to Supabase
- Reviews (create + list on product)
- Newsletter signup table
- Debounced search
- Postgres
ilike/ full-text - Collection landing pages
- Promo banners
-
role = admingate - Product CRUD
- Order status updates
- Customer list
- Cloudinary unsigned upload from media page
- Basic dashboard counts
- Cloud name in client env; API secret only for local seed script
- Unsigned upload preset for admin
- Upload widget or
fetchto Cloudinary API from admin - Store
public_idonproducts.image_public_idin Supabase - Responsive
w_/c_fillURLs in cards and PDP
- Real about, FAQ, shipping, returns copy
- Journal list from a
poststable - Contact form → Supabase table or Edge Function
- Privacy / terms review
- Lighthouse (performance, a11y, SEO)
- Empty, loading, and error states everywhere
- Seed script with realistic catalog
- Deploy (Netlify / Cloudflare Pages / GitHub Pages + Supabase)
- Short architecture note in this README for recruiters
- Phase 1 mobile nav + product imagery
- Phase 4 env + Auth (unlocks everything else)
- Phase 2 catalog from Supabase
- Phase 5 checkout
- Phase 8 admin + Phase 9 uploads
- Multi-page vanilla architecture with TypeScript, not a SPA framework
- Feature modules instead of a single script file
- Auth and RLS on Postgres
- Media pipeline split from relational data
- Real commerce flows: catalog, bag, checkout, orders, admin