Project Design
We have now completed all the material for Phases 1-4. Charlie will now integrate all this knowledge to design a complete MegaShop e-commerce platform. From requirements analysis to architectural design, and from data models to API specifications, this is the first step in the hands-on project.
1. What You'll Learn
- Requirements Analysis: User Roles (Alice/Bob/Charlie) and Functional Module Breakdown
- Architecture: SSR + ISR hybrid rendering + Nitro API + Prisma + Redis
- Data Model: ER Diagram Design + Prisma Schema
- API Specifications: RESTful API Design + Version Management + Error Codes
- Technology Selection Decisions and Rationale
2. A True Story of an Architect
(1) Pain Point: Development Without Design
Charlie had previously instructed the team to start writing code right away without any design documentation. As a result, Alice's shopping cart data structure didn't match Bob's order data, API naming was chaotic, the database lacked indexes, queries were slow, and the cost of making changes later on was enormous.
(2) System Design Solutions
Design First, Then Develop—Use ER diagrams to define the data model, RESTful specifications to define the API, and architecture diagrams to define the system boundaries. Spend an extra week on the design phase, and save three weeks during development.
(3) Benefits: A Clear Roadmap
When every developer refers to the same design document—with consistent data structures, unified API specifications, and clear architectural boundaries—collaboration efficiency increases threefold.
3. Requirements Analysis
(1) User Roles and Core Needs
| Role | Identity | Core Needs | Key Metrics |
|---|---|---|---|
| Alice | Consumer | Browse/Search/Add to Cart/Checkout/Review | First Screen < 2s, Search < 500ms |
| Bob | Administrator | Product Management/Order Processing/User Management | CRUD response < 200 ms |
| Charlie | Architect | System Stability/High Performance/Scalability | 99.9% availability, supports 1 million products |
(2) Functional Module Division
| Module | Function | Priority | Affected Pages |
|---|---|---|---|
| Authentication | Sign Up/Sign In/OAuth2/JWT | P0 | /login, /register |
| Product | CRUD/Search/Categories/Filters | P0 | /products, /products/[id] |
| Shopping Cart | Add to Cart/Change Quantity/Remove/Clear | P0 | /cart |
| Order | Create/Pay/Check Status | P0 | /checkout, /orders |
| User | Personal Information/Address/Reviews | P1 | /profile |
| Administration | Backend CRUD/Statistics/Moderation | P1 | /admin/** |
| Internationalization | Chinese/English/Japanese + Multiple Currencies | P1 | Global |
| SEO | Dynamic meta/Sitemap/JSON-LD | P0 | Product Page |
4. Architecture Design
(1) Overview of the MegaShop System Architecture
graph TB
subgraph Client["Client Layer"]
Browser[Browser / Mobile]
Bot[Search Engine Bot]
end
subgraph CDN["CDN Layer"]
CF[Cloudflare / Vercel Edge]
end
subgraph Nuxt["Nuxt 3 Application"]
SSR[SSR Engine]
ISR[ISR Cache]
API[Nitro API Routes]
MW[Middleware / Auth]
end
subgraph Data["Data Layer"]
PG[(PostgreSQL)]
Redis[(Redis Cache)]
S3[Object Storage / Images]
end
subgraph External["External Services"]
Stripe[Stripe Payment]
Google[Google OAuth2]
Analytics[Analytics Service]
end
Browser --> CDN
Bot --> CDN
CDN --> SSR
CDN --> ISR
SSR --> API
API --> MW
API --> PG
API --> Redis
API --> S3
API --> Stripe
API --> Google
API --> Analytics
ISR --> Redis
(2) Rendering Strategy Design
| Page Type | Rendering Mode | swr | Reason |
|---|---|---|---|
| Home | SSG | - | Stable Content |
| Product List | ISR | 3600s | Updated hourly |
| Product Details | ISR | 86400s | Updated Daily |
| Search Results | SSR | - | Real-time Query |
| Cart/Checkout | CSR | - | For Members Only |
| Admin Dashboard | CSR | - | No SEO Required |
| API Routing | Dynamic | - | On-Demand Caching |
(3) Selecting a Technology Stack
(1) ▶ Example: nuxt.config.ts Technology Stack Integration
// nuxt.config.ts - Full tech stack integration
export default defineNuxtConfig({
ssr: true,
modules: [
'@pinia/nuxt',
'@nuxtjs/tailwindcss',
'@nuxtjs/i18n',
'@nuxtjs/sitemap',
'@nuxt/image',
'~/modules/analytics'
],
i18n: {
locales: [
{ code: 'en', name: 'English', file: 'en.json', currency: 'USD' },
{ code: 'zh', name: 'Chinese', file: 'zh.json', currency: 'CNY' },
{ code: 'ja', name: 'Japanese', file: 'ja.json', currency: 'JPY' }
],
defaultLocale: 'en',
lazy: true,
langDir: 'locales/'
},
image: { quality: 80, format: ['webp', 'avif'] }
})
Output:
// Execution Successful
(2) ▶ Example: Docker Compose Service Orchestration
# docker-compose.yml - Infrastructure definition
services:
web:
build: .
ports: ["3000:3000"]
depends_on: [db, redis]
db:
image: postgres:16-alpine
volumes: [postgres_data:/var/lib/postgresql/data]
redis:
image: redis:7-alpine
volumes: [redis_data:/data]
nginx:
image: nginx:alpine
ports: ["80:80", "443:443"]
depends_on: [web]
Output:
CONTAINER ID IMAGE STATUS PORTS
abc123 nginx:latest Up 2 hours 0.0.0.0:80->80/tcp
| Level | Technology | Reason for Selection |
|---|---|---|
| Framework | Nuxt 3 | SSR/ISR/CSR Hybrid Rendering |
| UI | Vue 3 + TailwindCSS | Reactive + Rapid Development |
| State Management | Pinia | Official Vue 3 Solution + SSR Support |
| Database | PostgreSQL + Prisma | Type-safe ORM + Millions of Queries |
| Caching | Redis + Nitro KV | API Caching + ISR Storage |
| Authentication | JWT + OAuth2 | Stateless + Social Login |
| Internationalization | @nuxtjs/i18n | Multilingual + SEO hreflang |
| Image | @nuxt/image | WebP/AVIF + Responsive |
| Testing | Vitest + Playwright | Unit + E2E |
| Deployment | Docker Compose | Full-Stack Service Orchestration |
| CI/CD | GitHub Actions | Automated Pipelines |
5. Data Model Design
(1) ER Diagram
erDiagram
User ||--o{ Order : "places"
User ||--o{ Review : "writes"
User ||--o{ CartItem : "has"
User ||--o{ Address : "owns"
Product ||--o{ OrderItem : "included in"
Product ||--o{ CartItem : "added to"
Product ||--o{ Review : "receives"
Product ||--o{ ProductImage : "has"
Product }o--|| Category : "belongs to"
Category ||--o{ Category : "parent-child"
Order ||--o{ OrderItem : "contains"
Order }o--|| Address : "ships to"
(2) Core Table Design
(1) ▶ Example: Core Prisma Schema
// Key models from prisma/schema.prisma
model Product {
id Int @id @default(autoincrement())
name String
slug String @unique
price Decimal @db.Decimal(10, 2)
inStock Boolean @default(true)
categoryId Int
category Category @relation(fields: [categoryId], references: [id])
orderItems OrderItem[]
cartItems CartItem[]
@@index([categoryId])
@@index([price])
}
model Order {
id Int @id @default(autoincrement())
userId Int
user User @relation(fields: [userId], references: [id])
total Decimal @db.Decimal(10, 2)
status OrderStatus @default(PENDING)
items OrderItem[]
@@index([userId])
@@index([status])
}
Output:
// Execution Successful
(2) ▶ Example: API Error Code Definitions
// server/utils/errors.ts
export const ErrorCodes = {
VALIDATION_ERROR: { statusCode: 400, message: 'Validation error' },
AUTH_REQUIRED: { statusCode: 401, message: 'Authentication required' },
TOKEN_EXPIRED: { statusCode: 401, message: 'Token expired' },
FORBIDDEN: { statusCode: 403, message: 'Insufficient permissions' },
NOT_FOUND: { statusCode: 404, message: 'Resource not found' },
CONFLICT: { statusCode: 409, message: 'Resource conflict' },
RATE_LIMITED: { statusCode: 429, message: 'Too many requests' }
} as const
export function throwError(code: keyof typeof ErrorCodes, details?: any) {
const err = ErrorCodes[code]
throw createError({ statusCode: err.statusCode, message: err.message, data: { errorCode: code, details } })
}
Output:
// Execution Successful
(3) ▶ Example: Standard API Response Format
// server/utils/response.ts
export function successResponse(data: any, message = 'Success') {
return { data, message, timestamp: Date.now() }
}
export function listResponse(items: any[], total: number, page: number, limit: number) {
return { items, total, page, limit, timestamp: Date.now() }
}
export function errorResponse(statusCode: number, errorCode: string, message: string, details?: any) {
return { statusCode, errorCode, message, details, timestamp: Date.now() }
}
Output:
// Execution Successful
(4) ▶ Example: routeRules rendering strategy configuration
// nuxt.config.ts - Route-level rendering strategy
routeRules: {
'/': { prerender: true },
'/products': { swr: 3600 },
'/products/**': { swr: 86400 },
'/admin/**': { ssr: false },
'/cart': { ssr: false },
'/api/**': { cors: true },
'/_nuxt/**': { headers: { 'cache-control': 'public, max-age=31536000, immutable' } }
}
Output:
// Execution Successful
(5) ▶ Example: CI/CD Pipeline Structure
# .github/workflows/ci.yml - Core pipeline
name: CI
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps: [{ uses: actions/checkout@v4 }, { run: npm ci }, { run: npm run lint }]
test:
needs: lint
steps: [{ run: npm run test:coverage }]
build:
needs: test
steps: [{ run: npm run build }]
Output:
CI/CD pipeline loaded
Pipeline status: passed
Tests: 12 passed, 0 failed
| Table | Number of Fields | Primary Index | Estimated Data Volume |
|---|---|---|---|
| Product | 12 | slug, categoryId, price | 1 million |
| Category | 6 | slug, parentId | 500 |
| User | 10 | email, role | 500,000 |
| Order | 8 | userId, status, createdAt | 1 million |
| OrderItem | 6 | orderId, productId | 5 million |
| CartItem | 5 | userId+productId (unique) | 100,000 |
| Review | 7 | productId, userId | 2 million |
| Address | 8 | userId | 500 thousand |
6. API Specifications
(1) RESTful API Design
| Method | Path | Description | Authentication |
|---|---|---|---|
| GET | /api/products | Product List (Pagination/Filtering) | None |
| GET | /api/products/:id | Product Details | None |
| POST | /api/products | Create Product | Admin |
| PUT | /api/products/:id | Update Product | Admin |
| DELETE | /api/products/:id | Delete Product | Admin |
| GET | /api/categories | Category List | None |
| POST | /api/auth/register | Register | None |
| POST | /api/auth/login | Login | None |
| POST | /api/auth/refresh | Refresh Token | Cookie |
| GET | /api/cart | Shopping Cart | User |
| POST | /api/cart/add | Add to Cart | User |
| DELETE | /api/cart/remove | Remove | User |
| POST | /api/orders | Create Order | User |
| GET | /api/orders | Order List | User |
| GET | /api/orders/:id | Order Details | User |
(2) Error Code Specifications
| Status Code | Error Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Request parameter validation failed |
| 401 | AUTH_REQUIRED | Not logged in |
| 401 | TOKEN_EXPIRED | Token expired |
| 403 | FORBIDDEN | Insufficient permissions |
| 404 | NOT_FOUND | Resource does not exist |
| 409 | CONFLICT | Resource conflict (e.g., email address already registered) |
| 429 | RATE_LIMITED | Request rate exceeded |
| 500 | INTERNAL_ERROR | Internal server error |
(3) Response Format
// Success response
{
"data": { ... },
"message": "Operation successful"
}
// List response
{
"items": [...],
"total": 1000000,
"page": 1,
"limit": 20
}
// Error response
{
"statusCode": 400,
"message": "Validation error",
"errorCode": "VALIDATION_ERROR",
"details": { "field": "email", "reason": "Invalid format" }
}
7. Comprehensive Example: MegaShop Project Structure
megashop/
├── nuxt.config.ts
├── prisma/
│ ├── schema.prisma
│ ├── seed.ts
│ └── migrations/
├── pages/
│ ├── index.vue
│ ├── products/
│ │ ├── index.vue
│ │ └── [id].vue
│ ├── categories/
│ │ └── [slug].vue
│ ├── cart.vue
│ ├── checkout.vue
│ ├── login.vue
│ ├── register.vue
│ ├── profile/
│ │ ├── index.vue
│ │ └── orders.vue
│ └── admin/
│ ├── index.vue
│ ├── products/
│ └── orders/
├── components/
│ ├── AppHeader.vue
│ ├── AppFooter.vue
│ ├── product/
│ │ ├── ProductCard.vue
│ │ ├── ProductGrid.vue
│ │ └── ProductReview.vue
│ ├── cart/
│ │ └── CartItem.vue
│ └── common/
│ ├── LanguageSwitcher.vue
│ └── SearchBar.vue
├── composables/
│ ├── useCart.ts
│ ├── useAnalytics.ts
│ ├── useLocalizedPrice.ts
│ └── useProductSearch.ts
├── stores/
│ ├── cart.ts
│ └── user.ts
├── server/
│ ├── utils/
│ │ ├── prisma.ts
│ │ └── jwt.ts
│ ├── middleware/
│ │ └── auth.ts
│ ├── api/
│ │ ├── auth/
│ │ ├── products/
│ │ ├── categories/
│ │ ├── cart/
│ │ └── orders/
│ └── plugins/
│ └── stock.ts
├── middleware/
│ ├── 01-auth.global.ts
│ └── admin.ts
├── plugins/
│ ├── 01-config.ts
│ ├── 02-logger.ts
│ └── 03-stripe.client.ts
├── layouts/
│ ├── default.vue
│ └── sidebar.vue
├── locales/
│ ├── en.json
│ ├── zh.json
│ └── ja.json
├── modules/
│ └── analytics/
├── tests/
│ ├── composables/
│ ├── stores/
│ ├── components/
│ └── api/
├── e2e/
│ ├── cart-flow.spec.ts
│ ├── auth-flow.spec.ts
│ └── admin-flow.spec.ts
├── Dockerfile
├── docker-compose.yml
├── .github/workflows/
│ ├── ci.yml
│ ├── deploy-staging.yml
│ └── deploy-production.yml
└── public/
├── favicon.ico
└── robots.txt
❓ FAQ
📖 Summary
- Requirements Analysis: Core Requirements and Key Metrics for the Three Roles (Alice, Bob, and Charlie)
- Architecture: CDN → Nuxt (SSR/ISR/CSR) → Nitro API → PostgreSQL/Redis
- Data model: 8 core tables; 1 million rows in the "Product" table; query optimization using indexes
- API Specifications: RESTful style + uniform error codes + standard response format
- Technology Stack: Nuxt 3 + Pinia + Prisma + Redis + Docker Compose
📝 Exercises
- Basic Question (Difficulty: ⭐): Draw a diagram showing the user roles and functional modules for your project.
- Advanced Problem (Difficulty ⭐⭐): Design a complete Prisma schema (with at least 5 models), taking into account indexes and foreign keys.
- Challenge (Difficulty: ⭐⭐⭐): Design a complete API specification document, including all endpoints, request/response formats, and error codes.
---|



