Ecommerce Template
Next.js·React 등으로 만든 최신 전자상거래 템플릿
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기AdamDakdouk/nova-streetwear-fashion-shop
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A mini e-commerce platform built for the Full Stack Engineer take-home assessment: browse a 15-product streetwear catalog with color/size variants, manage a cart and wishlist, and complete a mocked checkout — end to end, fully responsive.
• Backend: Node.js, Express, TypeScript, Mongoose (MongoDB), JWT auth, zod validation, Jest
• Frontend: React, TypeScript, Vite, Tailwind CSS, TanStack Query, Zustand, React Router, Vitest
• Node.js 20+ (built with v24)
• A running local MongoDB instance on mongodb://127.0.0.1:27017 (or update MONGODB_URI)README 전문 보기 ↗A mini e-commerce platform built for the Full Stack Engineer take-home assessment: browse a 15-product streetwear catalog with color/size variants, manage a cart and wishlist, and complete a mocked checkout — end to end, fully responsive.
mongodb://127.0.0.1:27017 (or update MONGODB_URI)# 1. Install all workspace dependencies (root, server, client)
npm install
# 2. Configure the backend
cp server/.env.example server/.env
# edit server/.env: set a real JWT_SECRET; a RESEND_API_KEY (resend.com) for
# OTP emails; MONGODB_URI pointed at a real cluster if not running Mongo
# locally; and the 5 R2_* vars (dash.cloudflare.com) for admin image uploads
# — see notes below, all of these are required at boot
# 3. Seed the database (creates the 15 products + copies product images into
# client/public/products/, creates a demo user, and inserts the default
# homepage hero)
npm run seed
# 4. Run both apps
npm run dev
GET /api/health for a liveness check)Admin dashboard: /admin/login — [email protected] / AdminPass123! (not linked from the storefront UI; add/edit/delete products including image upload, and edit the homepage hero banner — copy, button label, and 1–4 images, with a live preview). See NOTES_BACKEND.md / NOTES_FRONTEND.md for how the role gating works.
Email/OTP: registration, email verification, and password reset send real email via Resend. EMAIL_FROM must be an address on a domain verified in Resend — with a verified domain, anyone can register and receive their own verification code. Resend's shared sandbox sender ([email protected]) needs no DNS setup but only ever delivers to the address the Resend account was registered with, so it works for local testing and not for anyone else. RESEND_API_KEY is required at boot (the server won't start without it).
Admin image uploads: stored on Cloudflare R2 (S3-compatible object storage), not the app's own server — a local-disk approach was tried first and dropped once it was clear it wouldn't survive an actual deploy (see NOTES_BACKEND.md). Needs a bucket with public access enabled and an API token; all 5 R2_* vars are required at boot.
Deployed as a single Vercel project — the React app and the API share one domain, so there is no CORS to configure and no pair of URLs to keep in sync.
| Path | Served by |
|---|---|
/ | the built React app (client/dist) |
/api/* | the Express app, as one serverless function |
vercel.json sets the build command (npm run build -w client), the output directory, the SPA rewrite that stops /products/:id 404ing on refresh, and bakes VITE_API_URL=/api into the build so it can't be forgotten.api/index.ts is a single function that awaits a database connection and hands the request to the unchanged Express app — Express still does all the routing, exactly as it does locally. Every /api/* path is rewritten to it, carrying the original path as a query parameter that the handler puts back on req.url. A catch-all filename (api/[...path].ts) is the tidier way to express that, but Vercel registered it as a single dynamic segment, so /api/products worked while /api/products/:id was rejected at the edge.connectDB memoises its connection on globalThis. A long-running server connects once at boot; a serverless one would otherwise open a fresh pool per request and exhaust the cluster's connection limit.tsconfig.json exists purely so api/ is type-checked. Vercel bundles that file with esbuild and never type-checks it, which would otherwise leave the deployment's most important file the only one nothing verifies.Setting it up:
vercel.json handles the rest.MONGODB_URI, JWT_SECRET, RESEND_API_KEY, R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET_NAME, R2_PUBLIC_URL.
Optional: JWT_EXPIRES_IN, EMAIL_FROM.0.0.0.0/0. Vercel's outbound IPs are not fixed, so an allowlist of specific addresses will fail intermittently./api/health returns {"status":"ok"} before testing the storefront.| Command | Description |
|---|---|
npm run dev | Runs backend + frontend together |
npm run seed | Re-seeds the database and copies product images |
npm run test | Runs backend (Jest) and frontend (Vitest) test suites |
npm run build | Type-checks and builds both workspaces |
npm run optimize-images | Re-encodes product photography in place (see below) |
Product images: the source photography is saved at near-lossless quality, which put roughly 9MB of images on a first page load. npm run optimize-images re-encodes media/ and client/public/products/ in place at quality 80 — about 91% smaller with no visible difference at the sizes this UI renders. Both trees get identical treatment on purpose: compressing only the served copy would work until the next npm run seed restored the heavy originals. It is a one-off to run after adding photography, not part of the build, since it is lossy and rewrites files in place.
server/ Express + TypeScript API (models, services, controllers, routes)
client/ React + TypeScript SPA (pages, components, hooks, api clients)
media/ Source product photography (copied into client/public/products by the seed script)
docs/ Architecture reference notes (see below)
localStorage via a persisted Zustand store, not an httpOnly cookie — a known XSS-surface tradeoff accepted for this scope.server/ + client/) rather than split repos — appropriate for this project's scale (one small API, one small SPA, shared review context).