English  · Tiếng Việt  · 日本語
Full-stack milk tea e-commerce — Next.js 14 · TypeScript · Prisma · Docker
MilkTea Iku is a production-shaped e-commerce storefront for a premium milk tea brand. It covers the full customer journey — browsing, customising drinks, checkout, and order tracking — plus an admin dashboard for order and coupon management.
📚 Learning project — This is a personal learning portfolio by Nguyễn Sơn. The codebase is intentionally production-shaped (real auth, real validation, real CI/CD, real docs) so it can serve as a reference for full-stack patterns, but it is not a commercial deployment. See
docs/HONEST_SCOPE.mdfor what is and isn't covered.
| Live URL | milktea-iku.vercel.app |
| Status | Deployed on Vercel · portfolio / reference implementation |
| Stack | Next.js 14 App Router, TypeScript, Prisma, SQLite (dev) / Postgres (prod) |
| Tests | 35 Playwright spec files — e2e, API, accessibility, visual, performance, SEO |
| CI/CD | 6 GitHub Actions workflows (ci, deploy, docker-publish, codeql, security, release) |
Live tour of the homepage — hero, featured products, and store locator.
Homepage · Light mode |
Homepage · Dark mode |
Menu · Product browsing with filters |
Stores · 6 locations across HCM and Hà Nội |
Checkout · Order placement and payment |
Menu · Dark mode browsing |
Light mode |
Dark mode |
Interaction demo |
Menu browsing · Filters, hover states, product cards |
Theme toggle · Smooth dark mode transition |
Customer
- Menu browsing with category filter, full-text search, and sort
- Drink customiser — size, sugar level, ice level, multi-topping selection
- Cart with persistent state (Zustand + localStorage)
- Multi-step checkout with Zod validation and server-side price recompute
- Coupon application with rate-limited validation
- Order tracking by phone number and order ID
- Loyalty tiers and rewards programme
- Wishlist
Platform
- Admin dashboard — order management, status transitions, coupon CRUD, aggregate stats
- Light / dark theme via
next-themes(WCAG AA contrast) - Fully responsive, mobile-first design
- Multi-language support (English · Tiếng Việt · 日本語)
- OpenAPI 3.0 spec at
/api/docs - PWA manifest and service-worker scaffold
| Layer | Choice |
|---|---|
| Framework | Next.js 14.2 (App Router, Server Components, streaming) |
| Language | TypeScript 5.4 |
| Styling | Tailwind CSS 3.4 + shadcn/ui |
| Animations | Framer Motion 11 |
| Theming | next-themes |
| Validation | Zod 3.23 |
| State | Zustand 4.5 |
| ORM / DB | Prisma 5.14 — SQLite (dev) · Postgres (prod) |
| Auth | HTTP Basic + Bearer token, scrypt-hashed passwords |
| Rate limiting | Per-IP sliding window (in-memory) |
| Icons | lucide-react |
| Testing | Playwright 1.60 |
| CI/CD | GitHub Actions |
| Hosting | Vercel (primary) · Docker Hub |
git clone https://github.com/JasonTM17/MilkTea_Iku.git
cd MilkTea_Iku
npm install --legacy-peer-deps
cp .env.example .env.local
# Edit .env.local — see Environment Variables below
npx prisma generate --schema=backend/prisma/schema.prisma
npm run db:push
npm run db:seed
npm run dev
# → http://localhost:3000cp .env.example .env.local
# Edit .env.local with your values
docker compose up -d
# → http://localhost:3000| Command | Purpose |
|---|---|
npm run dev |
Start dev server |
npm run build |
Production build |
npm run lint |
ESLint + Next lint |
npx tsc --noEmit |
Type check |
npx playwright test |
Full test suite |
npm run db:push |
Push schema to SQLite |
npm run db:seed |
Seed reference data |
npm run db:studio |
Open Prisma Studio |
node scripts/generate-admin-hash.mjs |
Generate ADMIN_PASSWORD_HASH |
Copy .env.example to .env.local and fill in the values.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | SQLite path for dev; Postgres URL for prod |
ADMIN_USERNAME |
Yes | Username for /admin HTTP Basic Auth |
ADMIN_PASSWORD |
Dev only | Plaintext password (ignored when hash is set) |
ADMIN_PASSWORD_HASH |
Prod | scrypt hash — generate with generate-admin-hash.mjs |
ADMIN_API_TOKEN |
Yes | Bearer token for programmatic admin access |
N8N_WEBHOOK_URL |
Optional | n8n chatbot webhook URL |
N8N_HOSTNAMES |
Optional | SSRF allowlist for n8n hostnames |
N8N_USER |
Optional | n8n basic auth user (docker-compose only) |
N8N_PASSWORD |
Optional | n8n basic auth password (docker-compose only) |
E2E_BASE_URL |
CI only | Base URL for Playwright (default: http://localhost:3000) |
Full architecture overview, project layout, and data-flow diagrams: docs/ARCHITECTURE.md.
Additional documentation:
| Document | Link |
|---|---|
| API reference | docs/api.md |
| Deployment guide | docs/DEPLOYMENT.md |
| Testing strategy | docs/TESTING.md |
| UI/UX guidelines | docs/UI_UX_GUIDELINES.md |
| Security posture | SECURITY.md |
| Honest scope | docs/HONEST_SCOPE.md |
Push to main — the deploy.yml workflow builds and deploys automatically.
For production, set all environment variables in the Vercel dashboard and switch DATABASE_URL to a Postgres connection string.
docker compose up -d # start backend + frontend + n8n
docker compose down # stop
docker compose logs -f # stream logsTagged releases publish images to Docker Hub via docker-publish.yml.
Full reference: docs/DEPLOYMENT.md.
Nguyễn Sơn — github.com/JasonTM17 · [email protected]
MIT © 2026 Nguyễn Sơn
Made with ☕ in Saigon










