Hidden Demo — Full-Stack E-commerce Portfolio Project
A production-grade flower & gift shop built with Next.js 15 (App Router), TypeScript, MongoDB, Stripe, and Cloudinary. This repository is a portfolio demonstration — the codebase powers a real storefront, stripped of sensitive business data so it can be run and explored locally by anyone.
| Area | What's demonstrated |
|---|---|
| Full-stack TypeScript | Next.js App Router, server components, API routes, Mongoose models — all typed end-to-end |
| RESTful API design | Resource-based routes (/api/products, /api/orders, /api/admin/*), proper HTTP methods & status codes, input validation via Zod on every endpoint |
| Authentication & security | HMAC-signed session cookies, bcrypt password hashing, CSP headers, per-IP rate limiting, httpOnly/secure/SameSite cookie flags |
| MongoDB | Mongoose schemas with indexes, lean queries, aggregation via admin analytics, audit trail on every state change |
| Stripe integration | Checkout Sessions, webhook signature verification, idempotent order creation, delivery fee line items |
| Accessibility | Skip-to-content link, focus trap in cart drawer, ARIA roles/labels (role="dialog", aria-modal, aria-labelledby, aria-describedby), keyboard navigation, semantic landmarks |
| Performance | Lighthouse CI asserting ≥ 85 performance / ≥ 95 accessibility on mobile, next/image optimisation, font subsetting, lazy-reveal components |
| Unit testing | Jest + React Testing Library — 19 tests across pure utility functions (lib/geo.ts, lib/validation.ts) with spies for side-effect isolation |
| End-to-end testing | Playwright smoke suite covering page load, cart interactions, and a full mocked checkout flow |
| CI | GitHub Actions workflow running lint and unit tests on every push/PR |
| Docker | Multi-stage Dockerfile (deps → build → slim runner) with docker-compose.yml for local MongoDB |
| UX polish | Optimistic loading states, inline error feedback, toast notifications, animated cart drawer, skeleton-free instant paint via blurred poster frame |
| Validation | Zod schemas shared between client forms and server API routes; delivery time window enforced on both sides |
| Deployment | Vercel with environment variable validation at startup — missing secrets throw a clear error rather than silently misbehaving |
- Product catalogue with collections (Flowers, Gifts, Plants, New Arrivals, Occasions)
- Cart with animated drawer, quantity controls & persistent state via React context
- Stripe Checkout integration (test-mode friendly)
- Delivery radius checker — geo-validates customer ZIP at checkout against MongoDB config
- Post-order confirmation page with toast notification
- Newsletter sign-up
- Responsive design, SEO meta/OG tags, sitemap & robots.txt
- Announcement bar, promo banners, Instagram widget
- Secure login with HMAC session cookies (bcrypt password hashing)
- Product management (create, edit, archive, image upload via Cloudinary)
- Category & promotion management
- Order management with status updates & audit trail
- Discount codes
- Delivery zone & radius configuration
- Media library, subscriber list, analytics dashboard, full audit log
| Layer | Technology |
|---|---|
| Framework | Next.js 15 App Router (TypeScript) |
| Database | MongoDB + Mongoose |
| Payments | Stripe (Checkout Sessions + Webhooks) |
| Media | Cloudinary |
| Nodemailer (SMTP) | |
| Styling | Tailwind CSS |
| Validation | Zod |
| Unit testing | Jest + React Testing Library |
| E2E testing | Playwright + Lighthouse CI |
| CI | GitHub Actions |
| Containerisation | Docker + Docker Compose |
| Monitoring | Sentry (optional) |
| Deployment | Vercel |
git clone https://github.com/webdevdano/hiddendemo.git
cd hiddendemo
pnpm installcp .env.example .env.localOpen .env.local and fill in your values. Minimum required to run locally:
MONGODB_URI=mongodb+srv://...
STRIPE_SECRET=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
ADMIN_SECRET=any-long-random-string
SMTP_HOST=... SMTP_PORT=587 SMTP_USER=... SMTP_PASS=... SMTP_FROM=...All variables are validated at startup via Zod in
lib/env.ts. Missing required secrets throw a clear error.
pnpm dev
# In a second terminal:
curl "http://localhost:3000/api/seed"stripe listen --forward-to localhost:3000/api/stripe/webhookCopy the printed whsec_... into STRIPE_WEBHOOK_SECRET in .env.local.
- Storefront: http://localhost:3000
- Admin panel: http://localhost:3000/admin/login
app/
(admin)/admin/ — Admin panel pages & layout
api/ — All API routes (RESTful, Zod-validated)
collections/ — Storefront collection pages
components/ — Shared UI components
data/ — Static seed/fallback data
lib/ — Shared utilities (auth, db, env, geo, mail, rate limiter…)
models/ — Mongoose models (Product, Order, Category, AuditLog…)
public/ — Static assets
scripts/ — One-off DB migration scripts
__tests__/ — Jest unit tests (lib/geo, lib/validation)
tests/ — Playwright E2E smoke tests
.github/workflows/ — GitHub Actions CI
| Route | Method | Description |
|---|---|---|
/api/products |
GET | List products. Query: ?featured=true&limit=4&q=search |
/api/categories |
GET | List categories |
/api/checkout |
POST | Create a Stripe Checkout session |
/api/stripe/webhook |
POST | Handle Stripe payment events (signature-verified) |
/api/delivery/check |
GET | Validate delivery address/ZIP/coords against configured radius |
/api/subscribe |
POST | Add email to subscriber list |
/api/seed |
GET | Seed demo data (guarded by SEED_SECRET in production) |
/api/admin/* |
Various | Admin CRUD endpoints (session-protected) |
# Unit tests (Jest + React Testing Library) — no external services needed
pnpm test:unit
# E2E tests (Playwright — starts dev server automatically)
pnpm test:e2e
# Lighthouse CI against a production build
pnpm build && pnpm exec lhci autorunLighthouse is configured to assert ≥ 85 performance and ≥ 95 accessibility scores on mobile (lighthouserc.json).
The CI pipeline (.github/workflows/ci.yml) runs lint and unit tests on every push and pull request.
# Build and run with docker-compose (includes a local MongoDB)
docker compose up --buildThe app will be available at http://localhost:3000. Create a .env.local with your secrets before running — docker-compose.yml loads it automatically via env_file.
The multi-stage Dockerfile keeps the final image slim: a deps stage installs packages, a builder stage compiles the Next.js app, and the runner stage copies only the build output and runs as a non-root user.
- Push to GitHub.
- Import the repo in Vercel.
- Add all variables from
.env.examplein Vercel Environment Variables. - Deploy — Vercel auto-detects Next.js and builds automatically.
pnpm dev # development server
pnpm build # production build
pnpm start # run production build locally
pnpm lint # ESLint
pnpm test:unit # Jest unit tests
pnpm test:e2e # Playwright E2E tests| Symptom | Likely cause | Fix |
|---|---|---|
| Server throws on startup | Missing env var | Check terminal — lib/env.ts lists the exact missing variable |
| Webhook signature error | Wrong STRIPE_WEBHOOK_SECRET |
Re-copy from stripe listen output |
| Admin login fails | Wrong password or ADMIN_SECRET not set |
Re-check .env.local and restart dev server |
| MongoDB errors | Invalid MONGODB_URI |
Verify connection string and Atlas network access |
| Images not showing | Wrong public path | Ensure assets exist under public/ and paths start with / |
Built by Dano