A production-grade, security-first luxury watch e-commerce platform β React 18 Β· TypeScript Β· Vite Β· MUI 6 Β· Zustand Β· TanStack Query β that runs fully in demo mode with zero configuration and can switch to real Firebase auth + Firestore by adding credentials.
- Project Overview
- Key Features
- Product Capabilities
- Technology Stack
- System Architecture
- Project Structure
- Prerequisites
- Installation
- Environment Variables
- Local Development
- Available Scripts
- Database Setup / Migration
- Testing
- Code Quality
- Security
- CI/CD
- Build & Production
- Deployment
- Git Workflow
- Troubleshooting
- Contributing
- License
- Project Status
Classic Watch Pro is a full-featured luxury watch e-commerce application demonstrating modern React engineering, defense-in-depth security, and outstanding performance & accessibility. It ships a complete storefront, secure authentication (including TOTP 2FA and WebAuthn passkeys), a full admin/analytics console, and an architecture that runs on an in-memory demo database out of the box β with production Firebase integration available by supplying credentials.
The project was designed to be a portfolio-quality reference implementation of production React patterns: typed state management, server-state caching, schema-versioned persistence with live migrations, route-level code splitting, and a hardened security posture.
- Catalog & discovery β responsive product grid with category / brand / price / rating filters, sorting, live search, featured & latest rails, and rich product detail pages with real watch photography.
- Reviews & ratings β rating-distribution summaries, verified-purchase badges, helpful votes, and a write-review flow whose aggregates stay coherent with the catalog.
- Discovery extras β a persisted recently-viewed rail and the side-by-side compare drawer (up to four watches: specs, price, availability) that both stay in sync across open browser tabs via
BroadcastChannel, plus quick-view on every card. - Cart & checkout β persisted cart, Zod + react-hook-form validation, multiple payment methods, promo codes (percent/fixed, min-order & usage caps β seeded codes like
WELCOME10), and order confirmation with a full order-history view. - Cross-tab cart sync β the cart contents stay synchronized across open tabs via
BroadcastChannel(most-recent-writer-wins, echo-loop protected). - Account area β customer dashboard, order tracking & per-order activity timelines, wishlist, an in-app notification center (order status, refunds, stock alerts), and profile/security management.
- Full auth cycle β register, login, Google sign-in, forgot-password, email verification with a route-level "verify your email" gate, anti-enumeration error copy.
- Two-factor authentication (TOTP) β enroll with a live secret +
otpauth://URI, verify-and-enable, disable. Real Firebase MFA path included; a deterministic demo path works offline. - Passkeys (WebAuthn) β genuine WebAuthn ceremonies via
@simplewebauthn(registration + authentication), cryptographically verified client-side in demo mode, counter-based replay protection, and a clearly-labelled legacy fallback for browsers without WebAuthn. - Authorization β
ProtectedRoute/AdminRouteguards enforce sign-in, role, and email-verification; the admin surface is invisible to non-admins (verified by tests + live scans). - Audit history β immutable, timestamped activity trails on orders (placement, status changes, cancellations) and users (role changes), surfaced in Admin Orders, Admin Users, and the customer order page.
- Dashboard β revenue / order / customer KPIs, dependency-free SVG charts (monthly revenue bars + order-status donut), inventory health, most-reviewed products, and top customers by lifetime spend.
- Sales reports β export analytics to CSV or a print-to-PDF report; every export is HTML-escaped so report content can never inject markup.
- Management β products CRUD, orders (status workflow + tracking notes + one-click refunds that append an immutable audit event), users (roles, 2FA/passkey badges, activity dialogs), a review moderation queue, and a Backup / Restore / Reset console for the demo database.
| Area | Capability |
|---|---|
| Storefront | Browse, search, filter, sort, quick-view, compare, recently-viewed |
| Purchasing | Cart, promo codes, multi-step checkout (shipping / payment / review) |
| Orders | Track status, activity timeline, refunds, order history |
| Reviews | Rate products, write reviews, moderation queue for admins |
| Accounts | Register, login (email/Google), email verification, profile, wishlist |
| Security | TOTP 2FA, WebAuthn passkeys, role-based guards, audit trails |
| Admin | Dashboard KPIs, charts, exports, full CRUD, backup/restore |
| Notifications | In-app notification center (order status, refunds, stock alerts) |
| PWA | Installable, offline-capable with service-worker caching |
| Area | Choice |
|---|---|
| Language / runtime | TypeScript 5.6 Β· Node β₯ 18 |
| Build / dev server | Vite 7 (SWC React plugin) Β· PWA plugin |
| UI | React 18 Β· MUI 6 |
| Routing | React Router 7 |
| Client state | Zustand 5 (+ persist middleware) |
| Server state | TanStack Query 5 |
| Forms / validation | React Hook Form (pinned 7.53.x) + Zod |
| Auth | Firebase Auth (lazy-loaded) Β· @simplewebauthn/browser + @simplewebauthn/server |
| HTTP | Axios with interceptors + an in-app mock adapter |
| Tests | Vitest 3 Β· React Testing Library Β· jsdom Β· axe-core Β· Playwright E2E |
| Error tracking | Sentry (@sentry/react) β lazily loaded when VITE_SENTRY_DSN is set |
| Quality | ESLint (incl. eslint-plugin-security) Β· Prettier Β· tsc --noEmit |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β React Application β
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββββ β
β β Pages β β Components β β API layer β β
β β (routes) β β (MUI) β β (React Query) β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ βββββββββ¬βββββββββ β
β β β β β
β ββββββββΌβββββββββββββββββββΌβββββββββββββββββββββΌββββββββ β
β β Zustand stores (client state) β β
β β (auth Β· cart Β· wishlist Β· theme Β· features) β β
β ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββ β
β β Service abstraction β β
β β Axios client + interceptors + mock adapter β β
β βββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββ β
ββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββ
β β
ββββββββββββΌβββββββββββ ββββββββββββΌβββββββββββ
β Real backend β β Demo mode β
β (Firebase/Firestoreβ β (in-memory mock DBβ
β + HTTP API, β β persisted to β
β optional) β β localStorage, β
β β β schema-versioned) β
βββββββββββββββββββββββ βββββββββββββββββββββββ
The UI operates against a service abstraction (Axios client with interceptors + an in-app mock adapter). In demo mode, an in-memory mock database with realistic seed data (16 watches, 6 users, 6 orders) serves all requests behind the same API shape as the real backend. Every mutation persists across reloads to localStorage inside a schema-versioned envelope with a migration registry β old snapshots upgrade in place, never silently discarded.
src/
βββ api/ # Typed API hooks (React Query) for products/orders/users/wishlist
βββ components/ # Layout (Header/Footer/MainLayout), common UI, guards, skeletons
βββ config/ # Env-driven app config + demo user
βββ features/ # Feature modules: auth, products, cart, orders, admin, dashboard, home
β βββ admin/ # Dashboard, charts, exports, CRUD, backup/restore controls
β βββ auth/ # Pages, MFA dialog, layouts
β βββ β¦
βββ lib/ # Firebase bootstrap (lazy), axios client, WebAuthn ceremony helpers
βββ mocks/ # Mock DB: seeds, schema-versioned storage, adapter, auth helpers
βββ store/ # Zustand stores: auth, cart, wishlist, theme
βββ styles/ # Global styles + MUI theme (light & dark, AA+ tuned)
βββ test/ # Test setup + factories
βββ types/ # Shared domain types
βββ utils/ # Helpers, CSV/print export
Cross-tab broadcast utilities live in src/lib/broadcastChannel.ts, and feature-specific sync hooks are colocated with their features (e.g. src/features/cart/hooks/useCrossTabCartSync.ts).
See docs/FILE_STRUCTURE.md for the full tree and docs/PROJECT_OVERVIEW.md for an architecture deep-dive.
- Node.js β₯ 18 (Node 22 recommended for CI parity)
- npm β₯ 9
- Git
# 1. Clone the repository
git clone git@github.com:SadManFahIm/Watching-.git
cd Watching-
# 2. Install dependencies
npm install
# 3. (Optional) Create your local environment file
cp .env.example .env.localAll configuration is provided via environment variables (Vite reads them from .env.local). Copy .env.example β .env.local and fill in values. Without Firebase credentials the app auto-signs in the demo admin on load.
| Variable | Required | Purpose |
|---|---|---|
VITE_API_BASE_URL |
No | Backend API URL (demo mode ignores this) |
VITE_FIREBASE_API_KEY |
No | Firebase API key (enables real auth) |
VITE_FIREBASE_AUTH_DOMAIN |
No | Firebase auth domain |
VITE_FIREBASE_PROJECT_ID |
No | Firebase project ID |
VITE_FIREBASE_STORAGE_BUCKET |
No | Firebase storage bucket |
VITE_FIREBASE_MESSAGING_SENDER_ID |
No | Firebase messaging sender ID |
VITE_FIREBASE_APP_ID |
No | Firebase app ID |
VITE_CLOUDINARY_CLOUD_NAME |
No | Cloudinary media integration |
VITE_STRIPE_PUBLISHABLE_KEY |
No | Stripe payment key |
VITE_SENTRY_DSN |
No | Sentry error-tracking DSN (lazy-loaded) |
VITE_ENABLE_ANALYTICS |
No | Feature flag: analytics |
VITE_ENABLE_PWA |
No | Feature flag: PWA support |
VITE_ENABLE_NOTIFICATIONS |
No | Feature flag: notification center |
All variables are optional. The app runs in demo mode without any configuration.
npm install
npm run dev
# β http://localhost:5173In demo mode, sign in with demo@classicwatch.local and any password of 4+ characters (admin). Additional seeded users appear in Admin β Manage users. Explore the 2FA and passkey flows from Profile β Security.
Without Firebase credentials the app auto-signs in the demo admin on load and persists mutations to
localStorageunder a versioned mock-DB key. Use the Reset demo data control on the admin dashboard to reseed.
| Command | Purpose |
|---|---|
npm run dev |
Start the Vite dev server |
npm run build |
Type-check + production build to dist/ |
npm run preview |
Serve the production build locally |
npm run type-check |
tsc --noEmit |
npm run lint |
ESLint (zero-warning policy) |
npm run lint:fix |
ESLint with auto-fix |
npm run format |
Prettier across src/ |
npm test |
Full Vitest suite once |
npm run test:watch |
Watch mode |
npm run test:ui |
Interactive UI mode |
npm run test:coverage |
Coverage report |
npm run test:e2e |
Build + Playwright E2E smoke suite |
npm run generate:icons |
Regenerate PWA icon set |
The app has no separate database setup requirement β the demo database is fully in-memory and self-seeding. However, the persistence layer is schema-versioned with a migration registry:
- The mock DB persists to
localStorageunder a versioned envelope key. - On load, the snapshot is validated against the expected schema version; if older, registered migrations upgrade it in place.
- Admins can export the DB as versioned JSON, validate & import it back, or reseed.
- The DB schema is versioned and migration-tested.
To enable the real backend (Firebase Firestore), provide VITE_FIREBASE_* variables and restart β the same UI talks to Firestore instead. Swap, don't rewrite.
Run the full suite:
npm testTest coverage includes:
- Accessibility regression suite (
src/features/__tests__/a11y.test.tsx) β full-page axe-core scans (WCAG 2.1 AA) on 18 routes: storefront, auth, dashboard, checkout and admin surfaces. This suite catches structural defects jsdom renders even when a narrow viewport hides them. - Store-level behavior β cart promo-code discount math, notifications feed, recently-viewed dedupe & cap, compare toggle limits.
- Cross-tab sync β cart, compare, and recently-viewed BroadcastChannel synchronization (message shape filtering, echo-loop protection, broadcast on mutation).
- Mock-adapter integration β reviews, promo validation & redemption, refund eligibility + audit, persistence across reloads.
- Auth-store state machines β MFA enrollment/verify/disable, email verification, passkeys incl. legacy fallback.
- Route guards β protected / admin / email-verification, header navigation.
- Storage round-trips + schema migrations + adapter integration.
- WebAuthn verification helpers, CSV/print export escaping, chart rendering.
npm run test:e2eThe E2E smoke suite runs against the production build in demo mode and covers: the complete buy flow (discover β detail β cart β checkout β confirmation), auth & admin guards, and admin order/review moderation.
npm run lint && npm run type-check && npm test && npm run build- Strict TypeScript β
strict,noUnusedLocals,noUnusedParameters,noFallthroughCasesInSwitch. - ESLint with
@typescript-eslint/recommended,react-hooks/recommended, andeslint-plugin-security(eval, unsafe-regex, non-literal-regexp as errors). - Prettier formatting enforced across
src/. - Zero-warning policy β
npm run lintfails on any warning. - Modular feature folders with clear boundaries; shared utilities extracted to
lib/,utils/. - Consistent, typed tests for all core logic and UI flows.
- No secrets in the repo β Firebase keys live in
.env.local(git-ignored); missing config is detected and the app falls back to demo mode. - Supply chain β
npm audit --omit=dev --audit-level=highruns in CI; the production-only scope keeps the check fast and meaningful. Unused dependencies are removed rather than tolerated. - Input & output hardening β Zod-validated forms, XSS-safe rendering, HTML-escaped export/print views, security-focused ESLint rules.
- Auth hardening β anti-enumeration error copy, email-verification gate on protected routes, role-based route guards, TOTP second factor, WebAuthn passkeys with counter replay protection, and immutable audit trails for privileged actions.
- Cryptographically secure randomness β challenge generation for WebAuthn uses
crypto.getRandomValuesand fails closed when unavailable. - Dependency pinning β
react-hook-formis pinned to the known-good 7.53.x line because 7.86.0 shipped a regression that silently dropsformState.errorsafter failed validation.
.env* (except .env.example), node_modules/, dist/, test-results/, coverage, and other local artifacts are all excluded.
CI runs on GitHub Actions (.github/workflows/ci.yml) with three parallel jobs:
| Job | Checks |
|---|---|
| Quality gates | lint β type-check β unit tests β production build β production-dependency audit |
| E2E smoke | Playwright against the production build (buy flow, auth + admin guard, moderation) |
| Lighthouse budget | Lighthouse CI against the built app enforcing performance / a11y / best-practices / SEO floors |
Concurrency cancels stale runs so PRs iterate fast. All jobs use Node 22 and npm caching.
Lighthouse budget (.lighthouserc.json) enforces explicit floors on every PR: perf β₯ 0.80 (warn), a11y / best-practices / SEO β₯ 0.90 (error), CLS β€ 0.10, LCP β€ 5.5 s, TBT β€ 1200 ms on throttled mobile. Measured locally: Home 99 Β· /products 86 Β· A11y / Best-practices / SEO 100.
npm run buildProduces a fully optimized production build in dist/:
- Route-level code splitting with granular vendor chunks (react, mui, firebase, query, form).
- Lazy Firebase β the Firebase SDK is dynamically imported; demo-mode builds ship zero Firebase bytes on the critical path.
- Lazy WebAuthn β
@simplewebauthn/browserand/serverare code-split and loaded only when a passkey ceremony actually runs. - Terser minification with console/debugger stripping.
- PWA with auto-update registration, inline SW registration, and Workbox caching for fonts, images, and API responses.
- Inlined critical CSS + app-shell hero for fast first paint.
Serve locally with:
npm run previewSee docs/DEPLOYMENT.md for the full deployment checklist. In summary:
- Build:
npm run build - Serve the
dist/directory as a static site (any static host: Vercel, Netlify, Cloudflare Pages, GitHub Pages, etc.). - Sentry: set
VITE_SENTRY_DSNat build time to enable error tracking. - Firebase: set
VITE_FIREBASE_*variables to enable real auth + Firestore. - PWA: the service worker and manifest are generated at build time; ensure the host serves them correctly.
This repository follows a trunk-based workflow with feature branches:
main (protected)
βββ feat/<feature> β create PR β CI green β merge to main
- Create a feature branch from
main. - Keep changes small and covered by tests.
- Run the full quality gate locally before pushing.
- Push and open a PR with a clear description of the change and verification performed.
- CI runs lint, type-check, tests, build, audit, E2E and Lighthouse on every PR.
- Merge only when CI is green.
| Symptom | Fix |
|---|---|
| Dev server doesn't open browser | The dev server listens on port 3000 (server.port); visit http://localhost:3000 |
| Firebase config warning on startup | Expected in demo mode β either add VITE_FIREBASE_* variables or ignore (the app falls back gracefully) |
react-hook-form field errors silently dropped |
Ensure react-hook-form stays pinned to 7.53.2 (a 7.86.0 regression was the reason for the pin) |
Test failures in jsdom around BroadcastChannel |
jsdom lacks BroadcastChannel; the sync hooks fall back to a no-op via openBroadcastChannel |
| Lighthouse perf fails in CI but passes locally | Cold shared runners vary; the config uses explicit metric floors and warns (not errors) on perf score |
- Fork the repository and create a feature branch.
- Keep changes small and covered by tests β run the quality gate before pushing.
- Open a pull request describing the change and the verification performed.
MIT β free to use for learning or commercial purposes.
v3.1.0 β Production-ready. Actively maintained. See docs/ROADMAP_V3.md for the product roadmap.
| Document | Contents |
|---|---|
README.md |
You are here |
docs/PROJECT_OVERVIEW.md |
Package contents & architecture |
docs/QUICK_START.md |
Fast setup walkthrough |
docs/DEPLOYMENT.md |
Deployment checklist & guide |
docs/FILE_STRUCTURE.md |
Complete file tree |
docs/ROADMAP_V3.md |
Product roadmap (living document) |
docs/UPGRADE_SUMMARY.md |
Migration/upgrade report |
Classic Watch Pro Β· v3.1.0 β a demonstration of production-grade React engineering.