Next.js 全栈实战:数据清洗、ORM 设计与 AI Prompt 工程最佳实践

本文基于一个真实的单词管理系统项目,深入讲解数据清洗、数据库设计、ORM 集成、AI Prompt 工程等核心知识点,附带面试高频考点。

一、项目背景

1.1 项目简介

构建一个单词后台管理系统,核心功能:

  • 单词书管理(CRUD)
  • 管理员权限系统
  • 数据清洗与导入
  • H5 单词学习应用

1.2 技术栈

技术 用途 面试亮点
Next.js 16 全栈框架 App Router、Server Components
Supabase BaaS 平台 云端 PostgreSQL、RLS
Drizzle ORM 数据库 ORM 类型安全、Schema 驱动
shadcn/ui UI 组件库 按需加载、AI 友好
TypeScript 类型系统 全链路类型推导

二、数据清洗:后端核心能力

2.1 什么是数据清洗?

数据清洗是将原始数据 转换为可用格式的过程,常见场景:

javascript 复制代码
原始数据(GitHub JSON)→ 清洗 → 标准格式(CSV/数据库)

2.2 为什么需要数据清洗?

问题 示例
格式不统一 JSON 嵌套层级不同
字段缺失 某些单词没有音标
数据冗余 包含不需要的字段
编码问题 中文编码不一致

2.3 传统方案 vs AI 方案

传统方案:手写脚本

javascript 复制代码
// scripts/json2csv.mjs
import { readFileSync, writeFileSync } from "fs";

const data = readFileSync("input.json", "utf-8");
const parsed = JSON.parse(data);

// 清洗逻辑
const cleaned = parsed.map(item => ({
  word: item.headWord,
  rank: item.wordRank,
  content: JSON.stringify(item.content),
}));

// 输出 CSV
writeFileSync("output.csv", cleaned.join("\n"));

优点 :确定性强、可调试 缺点:需要手写代码

AI 方案:生成脚本

给 AI 的 Prompt:

css 复制代码
写一个 Node.js 脚本,把 JSON 转成 CSV。
输入格式:[{ "wordRank": 1, "headWord": "ruler", "content": {...} }]
输出列:wordRank, headWord, content, bookId
要求:content 列保留原始 JSON 字符串

优点 :快速生成、1000 token 搞定 缺点:需要验证、可能有边界情况

2.4 面试考点

Q:数据清洗的流程是什么? A:数据采集 → 格式分析 → 清洗规则制定 → 脚本编写 → 验证输出
Q:如何处理大数据量的清洗? A:流式处理(Stream)、分批处理、并行处理


三、Supabase RLS(行级安全)

3.1 什么是 RLS?

RLS(Row Level Security) 是 PostgreSQL 的安全特性,控制用户只能访问特定行的数据。

sql 复制代码
-- 开启 RLS
ALTER TABLE words ENABLE ROW LEVEL SECURITY;

-- 创建策略:用户只能看到自己的数据
CREATE POLICY "Users can view own words" ON words
  FOR SELECT USING (auth.uid() = user_id);

3.2 什么时候需要 RLS?

场景 是否需要 RLS
单词表(公共数据) ❌ 不需要
用户背单词记录 ✅ 需要
管理员操作日志 ✅ 需要
单词书(公共) ❌ 不需要

3.3 为什么单词表不需要 RLS?

复制代码
单词数据是公共资源,所有用户共享
├── 单词表(words)→ 公开读取,无需 RLS
└── 用户记录(user_words)→ 私有数据,需要 RLS

3.4 面试考点

Q:RLS 和应用层权限控制的区别? A:RLS 在数据库层过滤,更安全;应用层在代码过滤,更灵活。推荐数据库层 + 应用层双重保障。
Q:如何设计 RLS 策略? A:最小权限原则,只授予必要的访问权限。


四、Prompt 工程:让 AI 高效工作

4.1 核心原则

原则一:给充足的上下文

vbnet 复制代码
❌ 错误:帮我写个接口
✅ 正确:用 Next.js App Router 写一个 GET 接口,查询 books 表,返回 JSON 格式

实践:把技术架构放在 AGENTS.md

markdown 复制代码
# AGENTS.md
## 技术栈
- Next.js 16 App Router
- Drizzle ORM + Supabase PostgreSQL
- shadcn/ui + Tailwind CSS

## 目录结构
- app/api/ - API 路由
- lib/db/ - 数据库配置
- components/ui/ - UI 组件

原则二:隐藏上下文开销

问题:178KB 的 JSON 文件,直接给 AI 读取会消耗 44,000+ tokens

解决方案:只给格式,不给数据

bash 复制代码
# 太大,不要读全文
# head -c 2000 input.json  → 只看前 2KB,了解结构

Prompt 示例

javascript 复制代码
写一个 JSON 转 CSV 脚本。
输入格式(每行一个 JSON):
{"wordRank":1,"headWord":"ruler","content":{...},"bookId":"PEP_1"}
输出列:wordRank, headWord, content, bookId

效果

方式 Token 消耗
读取完整文件 ~44,000 tokens
只看格式样本 ~500 tokens
节省 99%

4.2 Prompt 颗粒度

规则/规范类 Prompt

diff 复制代码
项目规范:
- 使用 Conventional Commits 格式
- API 返回统一用 NextResponse.json()
- 错误处理用 try-catch,返回 500

表单字段类 Prompt

diff 复制代码
创建单词书表单字段:
- title: 文本,必填
- wordCount: 数字,默认 0
- coverUrl: 文本,可选
- bookId: 文本,必填,唯一
- tags: 文本,逗号分隔

业务场景类 Prompt

markdown 复制代码
场景:管理员不能修改自己的角色
逻辑:
1. 编辑时判断 currentUser.id === editingUser.id
2. 如果是自己,禁用角色选择器
3. 后端也做校验,忽略传入的 role

4.3 让 AI 自己跑

复制代码
❌ 错误:帮我看看这段代码有没有 bug
✅ 正确:运行这个脚本,如果有错误就修复,直到成功

AI 擅长的事情

  • 生成代码
  • 运行脚本
  • 调试错误
  • 迭代优化

4.4 面试考点

Q:如何优化 AI 的 Token 消耗? A:1. 只给格式样本,不给完整数据;2. 使用 AGENTS.md 存储项目上下文;3. 明确 Prompt,减少猜测
Q:Prompt 工程的核心是什么? A:准确、清晰、完整。规则要明确,字段要完整,场景要具体。


五、Drizzle ORM:类型安全的数据库操作

5.1 Schema 设计

typescript 复制代码
// lib/db/schema.ts
import { pgTable, serial, text, timestamp, integer, uuid, jsonb } from "drizzle-orm/pg-core";

// 单词书表
export const books = pgTable("book", {
  id: uuid("id").defaultRandom().primaryKey(),
  title: text("title").notNull(),
  wordCount: integer("word_count").notNull().default(0),
  coverUrl: text("cover_url"),
  bookId: text("book_id").notNull().unique(),
  tags: text("tags"),
  createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
  updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
});

// 单词表(外键关联)
export const words = pgTable("words", {
  id: serial("id").primaryKey(),
  wordRank: integer("word_rank").notNull(),
  headWord: text("head_word").notNull(),
  content: jsonb("content").notNull(),
  bookId: text("book_id")
    .notNull()
    .references(() => books.bookId, { onDelete: "cascade" }),
});

5.2 级联删除(Cascade)

typescript 复制代码
bookId: text("book_id")
  .notNull()
  .references(() => books.bookId, { onDelete: "cascade" }),

效果:删除单词书时,自动删除关联的单词

面试考点

Q:级联删除的优缺点? A:优点是简化代码,自动清理关联数据;缺点是可能误删大量数据,需要谨慎使用。

5.3 CRUD 操作

typescript 复制代码
// 创建
const [book] = await db.insert(books).values({
  title: "CET-4 核心词汇",
  bookId: "cet4",
}).returning();

// 查询
const bookList = await db.select().from(books).orderBy(books.createdAt);

// 更新
await db.update(books)
  .set({ title: "新标题", updatedAt: new Date() })
  .where(eq(books.id, id));

// 删除(级联删除关联单词)
await db.delete(books).where(eq(books.id, id));

5.4 面试考点

Q:Drizzle ORM 和 Prisma 的区别? A:Drizzle 更轻量,Schema 就是代码,类型推导更直接;Prisma 功能更全,但需要生成客户端。
Q:什么是 Schema 驱动? A:数据库结构由代码定义,通过迁移同步到数据库,而不是手动建表。


六、权限系统设计

6.1 Session 认证流程

复制代码
登录 → 创建 Session → 写入 Cookie(7天有效期)
  ↓
后续请求 → 读取 Cookie → 验证 Session → 获取用户信息

6.2 角色权限控制

typescript 复制代码
// 前端:根据角色显示菜单
const navItems = [
  { title: "单词书", href: "/books", icon: BookOpen },
  ...(user?.role === "system_admin"
    ? [{ title: "管理员", href: "/admin-users", icon: Users }]
    : []),
];

// 后端:API 权限校验
if (currentUser.role !== "system_admin") {
  return NextResponse.json({ error: "权限不足" }, { status: 403 });
}

6.3 安全规则

规则 实现
不能删除自己 if (currentUser.id === userId) return error
不能修改自己的角色 后端忽略传入的 role
普通管理员不能访问管理接口 角色校验返回 403

6.4 面试考点

Q:Session 和 JWT 的区别? A:Session 存服务端,JWT 存客户端;Session 可主动失效,JWT 需等过期;JWT 无状态,适合分布式。


七、完整实现流程

7.1 数据库表创建

bash 复制代码
# 1. 定义 Schema
lib/db/schema.ts

# 2. 推送到数据库
pnpm db:push

# 3. 验证表结构
pnpm db:studio

7.2 API 路由设计

bash 复制代码
/api/auth/*
├── check-first-run  → 检查首次运行
├── signup           → 注册系统管理员
├── signin           → 登录
├── signout          → 退出
└── me               → 获取当前用户

/api/books/*
├── GET /            → 单词书列表
├── POST /           → 创建单词书
├── PUT /[id]        → 编辑单词书
└── DELETE /[id]     → 删除单词书

7.3 前端页面

bash 复制代码
app/
├── page.tsx              → 首页(跳转逻辑)
├── (auth)/
│   ├── signin/page.tsx   → 登录页
│   └── signup/page.tsx   → 注册页
└── (dashboard)/
    ├── layout.tsx        → 布局(认证检查)
    ├── books/page.tsx    → 单词书管理
    └── admin-users/      → 管理员管理

八、面试高频问题

8.1 技术选型

问题 答案要点
为什么选 Supabase? 免费、PostgreSQL、BaaS、RLS
为什么选 Drizzle? 类型安全、Schema 驱动、轻量
为什么选 shadcn/ui? 按需加载、可定制、AI 友好

8.2 数据库设计

问题 答案要点
外键怎么设计? references + onDelete cascade
什么时候用 JSONB? 结构不固定、查询少的字段
索引怎么加? 常用查询字段、唯一约束

8.3 安全相关

问题 答案要点
密码怎么存储? bcrypt 加密,10 轮 salt
Session 怎么管理? UUID + 数据库 + Cookie(7天)
权限怎么控制? 数据库层 RLS + 应用层角色校验

8.4 AI 工程

问题 答案要点
怎么优化 Token? 只给格式、AGENTS.md、明确 Prompt
Prompt 怎么写? 准确、清晰、完整、不让 LLM 猜
AI 适合做什么? 生成代码、运行脚本、调试错误

九、总结

9.1 核心知识点

  1. 数据清洗:后端常见任务,AI 生成脚本效率高
  2. RLS:数据库层安全,公共数据不需要开启
  3. Prompt 工程:上下文要准确,格式要清晰,隐藏数据开销
  4. ORM 设计:Schema 驱动,级联删除,类型安全
  5. 权限系统:Session 认证 + 角色控制 + 前后端双重校验

9.2 面试亮点

  • ✅ 全栈能力:前端 + 后端 + 数据库
  • ✅ 安全意识:密码加密、权限控制、RLS
  • ✅ AI 工程:Prompt 优化、Token 管理
  • ✅ 工程实践:ORM 设计、API 设计、错误处理

项目地址GitHub - danci1

技术交流:欢迎在评论区留言讨论!


📝 作者 :h206421 📅 发布时间 :2026 年 8 月 🏷️ 标签:Next.js, Supabase, Drizzle ORM, Prompt 工程, 数据清洗

相关推荐
雨夜之寂4 小时前
雨夜-现在有办法识别是不是ai文章么
后端·面试
峰向AI4 小时前
AI reads books:用 AI 逐页「啃」PDF 的知识提取器,一个脚本搞定一切
github
不正经学生5 小时前
C语言动态内存管理(上):堆上的自由与责任
c语言·开发语言·c++·算法·面试
Experience-摆渡6 小时前
GitHub 47万星免费公共API清单深度调研:收录规模、维护现状与实测
github
逛逛GitHub6 小时前
GitHub 上 2.5 万星星的开源 Skill 让 AI 画出漂亮图表。
github
ssshooter6 小时前
AI 时代你不能不知道的 git worktree
前端·后端·面试
CoderYanger6 小时前
A.每日一题:输入单词需要的最少按键次数 Ⅰ+Ⅱ
java·数据结构·算法·leetcode·面试
Cosolar6 小时前
一文弄懂 Agent Harness 与 Agent Runtime 的区别
java·后端·github
YH55269847 小时前
如何减少大模型的token消耗?日常使用,可以通过什么方式减少大模型 token 的消耗
gpt·chatgpt·github