Chuyển đến nội dung chính

第 14 課:Vibe 編碼全端應用程式 — 第 1 部分:後端

使用 Vibe Coding 建立完整的後端。設定 Node.js + Express + TypeScript。使用 AI 進行資料庫架構設計。 REST API、身份驗證、驗證。用於後端開發的代理模式工作流程。

💻 程式設計 — 第 14 課 第 14 課:Vibe 編碼全端應用 — 部分 1:後端

使用 GitHub Copilot 進行 Vibe 編碼:從基礎知識到高級

第 5 部分:Vibe 編碼實踐 — 建構真實項目

亞洲開發網

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 連線、響應式設計。