Nuxt: 项目设计
最后更新:2026-08-26
Phase 1-4 的知识已经全部学完。现在 Charlie 要把所有知识融会贯通,设计一个完整的 MegaShop 电商平台。从需求分析到架构设计、从数据模型到 API 规范,这是实战项目的第一步。
1. 你将学到
- 需求分析:用户角色(Alice/Bob/Charlie)与功能模块划分
- 架构设计:SSR + ISR 混合渲染 + Nitro API + Prisma + Redis
- 数据模型:ER 图设计 + Prisma Schema
- API 规范:RESTful 接口设计 + 版本管理 + 错误码
- 技术选型决策与理由
2. 一个架构师的真实故事
(1) 痛点:没有设计直接开发
Charlie 之前让团队直接写代码,没有设计文档。结果:Alice 的购物车数据结构和 Bob 的订单数据不一致,API 命名混乱,数据库缺少索引查询慢,后期改动代价巨大。
(2) 系统设计的解法
先设计再开发——用 ER 图定义数据模型,用 RESTful 规范定义 API,用架构图定义系统边界。设计阶段多花 1 周,开发阶段省 3 周。
(3) 收益:清晰的蓝图
每个开发者看同一份设计文档,数据结构一致、API 规范统一、架构边界清晰,协作效率提升 3 倍。
3. 需求分析
(1) 用户角色与核心需求
| 角色 | 身份 | 核心需求 | 关键指标 |
|---|---|---|---|
| Alice | 消费者 | 浏览/搜索/加购/结算/评价 | 首屏 < 2s,搜索 < 500ms |
| Bob | 管理员 | 商品管理/订单处理/用户管理 | CRUD 响应 < 200ms |
| Charlie | 架构师 | 系统稳定/高性能/可扩展 | 可用性 99.9%,支持 1M 商品 |
(2) 功能模块划分
| 模块 | 功能 | 优先级 | 涉及页面 |
|---|---|---|---|
| 认证 | 注册/登录/OAuth2/JWT | P0 | /login, /register |
| 商品 | CRUD/搜索/分类/筛选 | P0 | /products, /products/[id] |
| 购物车 | 加购/改量/删除/清空 | P0 | /cart |
| 订单 | 创建/支付/状态查询 | P0 | /checkout, /orders |
| 用户 | 个人信息/地址/评价 | P1 | /profile |
| 管理 | 后台CRUD/统计/审核 | P1 | /admin/** |
| 国际化 | 中/英/日 + 多货币 | P1 | 全局 |
| SEO | 动态meta/Sitemap/JSON-LD | P0 | 商品页 |
4. 架构设计
(1) MegaShop 系统架构全景
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) 渲染策略设计
| 页面类型 | 渲染模式 | swr | 理由 |
|---|---|---|---|
| 首页 | SSG | - | 内容稳定 |
| 商品列表 | ISR | 3600s | 每小时更新 |
| 商品详情 | ISR | 86400s | 每日更新 |
| 搜索结果 | SSR | - | 实时查询 |
| 购物车/结算 | CSR | - | 用户专属 |
| 管理后台 | CSR | - | 无需 SEO |
| API 路由 | 动态 | - | 按需缓存 |
(3) 技术栈选型
▶ 示例:nuxt.config.ts 技术栈集成
TYPESCRIPT
// 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: '中文', file: 'zh.json', currency: 'CNY' },
{ code: 'ja', name: '日本語', file: 'ja.json', currency: 'JPY' }
],
defaultLocale: 'en',
lazy: true,
langDir: 'locales/'
},
image: { quality: 80, format: ['webp', 'avif'] }
})
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:Docker Compose 服务编排
YAML
# 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]
输出:
TEXT
📖 仅展示
CONTAINER ID IMAGE STATUS PORTS
abc123 nginx:latest Up 2 hours 0.0.0.0:80->80/tcp
| 层级 | 技术 | 选择理由 |
|---|---|---|
| 框架 | Nuxt 3 | SSR/ISR/CSR 混合渲染 |
| UI | Vue 3 + TailwindCSS | 响应式 + 快速开发 |
| 状态管理 | Pinia | Vue 3 官方方案 + SSR 支持 |
| 数据库 | PostgreSQL + Prisma | 类型安全 ORM + 百万级查询 |
| 缓存 | Redis + Nitro KV | API 缓存 + ISR 存储 |
| 认证 | JWT + OAuth2 | 无状态 + 社交登录 |
| 国际化 | @nuxtjs/i18n | 多语言 + SEO hreflang |
| 图片 | @nuxt/image | WebP/AVIF + 响应式 |
| 测试 | Vitest + Playwright | 单元 + E2E |
| 部署 | Docker Compose | 全套服务编排 |
| CI/CD | GitHub Actions | 自动化流水线 |
5. 数据模型设计
(1) ER 图
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) 核心表设计
▶ 示例:核心 Prisma Schema
PRISMA
// 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])
}
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:API 错误码定义
TYPESCRIPT
// 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 } })
}
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:标准 API 响应格式
TYPESCRIPT
// 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() }
}
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:routeRules 渲染策略配置
TYPESCRIPT
// 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' } }
}
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:CI/CD 流水线结构
YAML
# .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 }]
输出:
TEXT
📖 仅展示
CI/CD pipeline loaded
Pipeline status: passed
Tests: 12 passed, 0 failed
| 表 | 字段数 | 核心索引 | 预估数据量 |
|---|---|---|---|
| Product | 12 | slug, categoryId, price | 1 million |
| Category | 6 | slug, parentId | 500 |
| User | 10 | email, role | 500 thousand |
| Order | 8 | userId, status, createdAt | 1 million |
| OrderItem | 6 | orderId, productId | 5 million |
| CartItem | 5 | userId+productId(unique) | 100 thousand |
| Review | 7 | productId, userId | 2 million |
| Address | 8 | userId | 500 thousand |
6. API 规范
(1) RESTful API 设计
| 方法 | 路径 | 说明 | 鉴权 |
|---|---|---|---|
| GET | /api/products | 商品列表(分页/筛选) | 无 |
| GET | /api/products/:id | 商品详情 | 无 |
| POST | /api/products | 创建商品 | Admin |
| PUT | /api/products/:id | 更新商品 | Admin |
| DELETE | /api/products/:id | 删除商品 | Admin |
| GET | /api/categories | 分类列表 | 无 |
| POST | /api/auth/register | 注册 | 无 |
| POST | /api/auth/login | 登录 | 无 |
| POST | /api/auth/refresh | 刷新令牌 | Cookie |
| GET | /api/cart | 购物车 | User |
| POST | /api/cart/add | 加购 | User |
| DELETE | /api/cart/remove | 移除 | User |
| POST | /api/orders | 创建订单 | User |
| GET | /api/orders | 订单列表 | User |
| GET | /api/orders/:id | 订单详情 | User |
(2) 错误码规范
| 状态码 | 错误码 | 说明 |
|---|---|---|
| 400 | VALIDATION_ERROR | 请求参数校验失败 |
| 401 | AUTH_REQUIRED | 未登录 |
| 401 | TOKEN_EXPIRED | Token 过期 |
| 403 | FORBIDDEN | 权限不足 |
| 404 | NOT_FOUND | 资源不存在 |
| 409 | CONFLICT | 资源冲突(如邮箱已注册) |
| 429 | RATE_LIMITED | 请求频率超限 |
| 500 | INTERNAL_ERROR | 服务器内部错误 |
(3) 响应格式
TYPESCRIPT
// 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. 综合示例:MegaShop 项目结构
TEXT
📖 仅展示
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
❓ 常见问题
Q 设计阶段要花多少时间?
A 一般 1-2 周。需求分析 2 天、架构设计 2 天、数据模型 2 天、API 规范 2 天、技术选型 1 天。设计越细致,开发越顺畅。
Q PostgreSQL 和 MySQL 怎么选?
A PostgreSQL 更适合 MegaShop——支持 JSON 字段(商品属性)、全文搜索(商品搜索)、丰富的索引类型。Prisma 对 PostgreSQL 支持最好。
Q Redis 必须吗?
A 百万级商品页推荐使用。Redis 做商品缓存和 ISR 存储,响应 5ms vs 数据库 200ms。小流量可先不用。
Q API 版本管理怎么做?
A 在 URL 中加版本前缀 /api/v1/products,重大变更时升级版本。小版本变更用向后兼容的方式扩展字段。
Q 模块划分的粒度怎么定?
A 按业务领域划分——认证、商品、购物车、订单各一个模块。每个模块有独立的 API/Store/Composable/页面。不要按技术层划分。
Q 怎么保证设计文档和代码一致?
A 用 Prisma Schema 作为数据模型的 Single Source of Truth,API 规范用 TypeScript 接口定义。设计变更先改 Schema 和接口,再改代码。
📖 小节
- 需求分析:三个角色(Alice/Bob/Charlie)的核心需求和关键指标
- 架构设计:CDN → Nuxt(SSR/ISR/CSR) → Nitro API → PostgreSQL/Redis
- 数据模型:8 张核心表,Product 1 million 行,索引优化查询
- API 规范:RESTful 风格 + 统一错误码 + 标准响应格式
- 技术选型:Nuxt 3 + Pinia + Prisma + Redis + Docker Compose
📝 作业
- 基础题(难度⭐):画出你的项目用户角色和功能模块划分图
- 进阶题(难度⭐⭐):设计完整的 Prisma Schema(至少 5 个模型),考虑索引和外键
- 挑战题(难度⭐⭐⭐):设计完整的 API 规范文档,包括所有端点、请求/响应格式、错误码
---|