1. 現實項目介紹
在接下來的 3 節課中,我們將構建 工作管理應用程式 配有 Vibe 編碼。目標是體驗人工智慧的端到端開發過程。
項目概況:
| 圖層 | 科技 | 課程 |
|---|---|---|
| 後端 | Node.js + Express + TypeScript | 第14課(本課) |
| 前端 | React + Next.js + TailwindCSS | 第15課 |
| 智慧型手機 | 反應本機/顫振 | 第16課 |
| 資料庫 | PostgreSQL + Prisma ORM | 第14課 |
| 授權 | JWT + bcrypt | 第14課 |
2. 使用 Vibe Coding 创建项目
第一步:使用Agent模式搭建鷹架
// Prompt cho Agent Mode:
Create a new Node.js backend project with:
- TypeScript configuration
- Express.js server
- Prisma ORM with PostgreSQL
- JWT authentication
- Project structure following clean architecture
- ESLint + Prettier configuration
- Docker Compose for PostgreSQL
代理模式將自動:
- 運行
npm 初始化,安裝依賴項 - 創建
tsconfig.json,.eslintrc,.prettierrc - 建立資料夾結構
- 設定 Docker Compose
第2步:创建项目结构
task-api/
├── src/
│ ├── controllers/
│ │ ├── auth.controller.ts
│ │ └── task.controller.ts
│ ├── middleware/
│ │ ├── auth.middleware.ts
│ │ └── validate.middleware.ts
│ ├── routes/
│ │ ├── auth.routes.ts
│ │ └── task.routes.ts
│ ├── services/
│ │ ├── auth.service.ts
│ │ └── task.service.ts
│ ├── types/
│ │ └── index.ts
│ └── app.ts
├── prisma/
│ └── schema.prisma
├── docker-compose.yml
├── tsconfig.json
└── package.json
3. AI 数据库架构设计
// Prompt:
Design a Prisma schema for a task management app with:
- Users (email, password hash, name, avatar)
- Projects (name, description, owner)
- Tasks (title, description, status, priority, assignee, due date)
- Comments on tasks
- Project memberships with roles
Copilot 将生成架构:
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
email String @unique
password String
name String
avatar String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ownedProjects Project[]
memberships ProjectMember[]
assignedTasks Task[] @relation("AssignedTasks")
createdTasks Task[] @relation("CreatedTasks")
comments Comment[]
}
model Project {
id String @id @default(uuid())
name String
description String?
ownerId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
owner User @relation(fields: [ownerId], references: [id])
members ProjectMember[]
tasks Task[]
}
model ProjectMember {
id String @id @default(uuid())
role Role @default(MEMBER)
userId String
projectId String
user User @relation(fields: [userId], references: [id])
project Project @relation(fields: [projectId], references: [id])
@@unique([userId, projectId])
}
enum Role {
OWNER
ADMIN
MEMBER
}
model Task {
id String @id @default(uuid())
title String
description String?
status TaskStatus @default(TODO)
priority Priority @default(MEDIUM)
dueDate DateTime?
projectId String
assigneeId String?
creatorId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
project Project @relation(fields: [projectId], references: [id])
assignee User? @relation("AssignedTasks", fields: [assigneeId], references: [id])
creator User @relation("CreatedTasks", fields: [creatorId], references: [id])
comments Comment[]
}
enum TaskStatus {
TODO
IN_PROGRESS
IN_REVIEW
DONE
}
enum Priority {
LOW
MEDIUM
HIGH
URGENT
}
model Comment {
id String @id @default(uuid())
content String
taskId String
authorId String
createdAt DateTime @default(now())
task Task @relation(fields: [taskId], references: [id])
author User @relation(fields: [authorId], references: [id])
}
4. 身份驗證-JWT 流程
// Prompt:
Implement JWT authentication with:
- Register endpoint with email validation and password hashing
- Login endpoint returning access + refresh tokens
- Auth middleware that validates JWT
- Refresh token rotation
- Use bcrypt for password hashing
Copilot 生成身份验证服务:
// src/services/auth.service.ts
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { prisma } from '../lib/prisma';
export class AuthService {
async register(email: string, password: string, name: string) {
const existingUser = await prisma.user.findUnique({ where: { email } });
if (existingUser) {
throw new Error('Email already registered');
}
const hashedPassword = await bcrypt.hash(password, 12);
const user = await prisma.user.create({
data: { email, password: hashedPassword, name },
});
return this.generateTokens(user.id);
}
async login(email: string, password: string) {
const user = await prisma.user.findUnique({ where: { email } });
if (!user || !(await bcrypt.compare(password, user.password))) {
throw new Error('Invalid credentials');
}
return this.generateTokens(user.id);
}
private generateTokens(userId: string) {
const accessToken = jwt.sign(
{ userId },
process.env.JWT_SECRET!,
{ expiresIn: '15m' }
);
const refreshToken = jwt.sign(
{ userId },
process.env.JWT_REFRESH_SECRET!,
{ expiresIn: '7d' }
);
return { accessToken, refreshToken };
}
}
5. REST API——增删改查操作
// Prompt:
Create CRUD endpoints for tasks with:
- GET /api/tasks — list tasks with filtering and pagination
- POST /api/tasks — create new task
- PUT /api/tasks/:id — update task
- DELETE /api/tasks/:id — delete task
- Include authorization checks
- Validate request body with Zod
副驾驶生成控制器:
// src/controllers/task.controller.ts
import { Request, Response } from 'express';
import { z } from 'zod';
import { prisma } from '../lib/prisma';
const createTaskSchema = z.object({
title: z.string().min(1).max(255),
description: z.string().optional(),
priority: z.enum(['LOW', 'MEDIUM', 'HIGH', 'URGENT']).default('MEDIUM'),
dueDate: z.string().datetime().optional(),
projectId: z.string().uuid(),
assigneeId: z.string().uuid().optional(),
});
export class TaskController {
async list(req: Request, res: Response) {
const { projectId, status, priority, page = '1', limit = '20' } = req.query;
const tasks = await prisma.task.findMany({
where: {
projectId: projectId as string,
status: status as any,
priority: priority as any,
},
include: {
assignee: { select: { id: true, name: true, avatar: true } },
_count: { select: { comments: true } },
},
skip: (Number(page) - 1) * Number(limit),
take: Number(limit),
orderBy: { createdAt: 'desc' },
});
res.json({ data: tasks });
}
async create(req: Request, res: Response) {
const data = createTaskSchema.parse(req.body);
const task = await prisma.task.create({
data: {
...data,
dueDate: data.dueDate ? new Date(data.dueDate) : null,
creatorId: req.userId!, // from auth middleware
},
});
res.status(201).json({ data: task });
}
}
6. 后端 Vibe 编码工作流程
最佳工藝:
┌──────────────────────────────────────────────────┐
│ BACKEND VIBE CODING WORKFLOW │
├──────────────────────────────────────────────────┤
│ │
│ 1. Mô tả feature bằng ngôn ngữ tự nhiên │
│ ↓ │
│ 2. Agent Mode scaffold files │
│ ↓ │
│ 3. Review generated code │
│ ↓ │
│ 4. Prompt: "Write tests for this" │
│ ↓ │
│ 5. Agent chạy tests, fix lỗi │
│ ↓ │
│ 6. Prompt: "Add error handling and validation" │
│ ↓ │
│ 7. Review final code → Commit │
│ │
└──────────────────────────────────────────────────┘
Vibe Coding 後端時的提示:
- 清晰描述業務邏輯: AI 不知道你的域名
- 同時請求測試:“创建服务及其单元测试”
- 審查安全性:始終檢查輸入驗證、身份驗證檢查
- 資料庫遷移:使用
Prisma 遷移開發AI改變模式後 - 使用副駕駛指令.md:定义项目的编码标准
7. 人工智慧測試
// Prompt:
Write comprehensive tests for AuthService including:
- Successful registration
- Duplicate email registration
- Successful login
- Invalid credentials
- Token generation and verification
Use Jest with supertest for integration tests.
// src/services/__tests__/auth.service.test.ts
import { AuthService } from '../auth.service';
import { prisma } from '../../lib/prisma';
import bcrypt from 'bcrypt';
describe('AuthService', () => {
const authService = new AuthService();
beforeEach(async () => {
await prisma.user.deleteMany();
});
describe('register', () => {
it('should create user and return tokens', async () => {
const result = await authService.register(
'[email protected]', 'Password123!', 'Test User'
);
expect(result.accessToken).toBeDefined();
expect(result.refreshToken).toBeDefined();
const user = await prisma.user.findUnique({
where: { email: '[email protected]' },
});
expect(user).toBeDefined();
expect(user!.name).toBe('Test User');
});
it('should hash password correctly', async () => {
await authService.register(
'[email protected]', 'Password123!', 'Test User'
);
const user = await prisma.user.findUnique({
where: { email: '[email protected]' },
});
expect(user!.password).not.toBe('Password123!');
expect(await bcrypt.compare('Password123!', user!.password)).toBe(true);
});
it('should reject duplicate email', async () => {
await authService.register(
'[email protected]', 'Password123!', 'Test User'
);
await expect(
authService.register('[email protected]', 'Other456!', 'Other User')
).rejects.toThrow('Email already registered');
});
});
});
8. 錯誤處理模式
// Prompt:
Add global error handling middleware with:
- Custom AppError class with status codes
- Async error wrapper for controllers
- Prisma error handling (unique constraint, not found)
- Request validation errors (Zod)
- Structured error response format
9. 總結
| 步驟 | 振動編碼法 | 節省時間 |
|---|---|---|
| 項目設定 | 代理模式鷹架 | ~2 小時 → 5 分鐘 |
| 資料庫結構定義 | 描述实体 → Prisma 模式 | ~1 小時 → 10 分鐘 |
| 授權 | 描述流程 → 全面实施 | ~4 小時 → 20 分鐘 |
| 增刪改查API | 描述端点→控制器+服务 | ~3 小時 → 15 分鐘 |
| 測試 | 「為 X 編寫測試」→ 綜合套件 | ~3 小時 → 10 分鐘 |
重要提示:上述時間節省是理想的。其實你還是需要的 審查、調試和完善 AI代碼誕生。 Vibe Coding 減少了編碼時間,但 不減少審稿時間。
下一篇:施工 前端 應用程式 — React + Next.js + TailwindCSS、API 連線、響應式設計。