前端转全栈 14:综合实战——从 0 到 1 做一个带用户系统的全栈应用
前端全栈tutorial实战项目nextjssupabasecapstone
系列目录:本文是「前端转全栈:Next.js + Supabase 实战」系列的第 14 篇,也是综合实战篇。前面每篇是零件,这一篇把它们组装成一辆能上路的车。
学了很多概念,但「真要我独立做一个,从哪下手?」——这篇给你一条可复制的做事流水线。我们以一个「带登录的留言板」为例子,它覆盖了全栈应用的全部核心要素。
一、需求拆解(先做减法)
MVP(最小可行产品)只保留:
- 游客能看留言列表
- 登录用户能发留言、删自己的留言
- 数据持久化
不做的(留作扩展):富文本、点赞、通知、管理后台。全栈新手最容易死在「想一次做全」,先交付核心闭环。
二、数据建模(第 3 篇)
一张表就够:
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
content TEXT NOT NULL CHECK (char_length(content) <= 500),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_messages_created_at ON messages (created_at DESC);
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
CREATE POLICY "公开可读" ON messages FOR SELECT USING (true);
CREATE POLICY "登录可写" ON messages FOR INSERT
WITH CHECK (auth.role() = 'authenticated');
CREATE POLICY "删自己的" ON messages FOR DELETE
USING (auth.uid() = user_id);
注意 CHECK (char_length <= 500) 在数据库层就限制了长度——防御纵深。
三、页面与数据获取(第 4、5 篇)
列表用 Server Component 直连库,无需 API 中转:
// app/page.tsx(Server Component)
import { createClient } from "@/lib/supabase/server"
export default async function Home() {
const supabase = await createClient()
const { data: messages } = await supabase
.from("messages").select("content, created_at, user_id").order("created_at", { ascending: false })
return <MessageList initial={messages} />
}
四、写操作:Server Action(第 8 篇)
// app/actions.ts
"use server"
import { createClient } from "@/lib/supabase/server"
import { z } from "zod"
import { revalidatePath } from "next/cache"
const Schema = z.object({ content: z.string().min(1).max(500) })
export async function addMessage(prev: any, formData: FormData) {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) return { error: "请先登录" }
const parsed = Schema.safeParse({ content: String(formData.get("content")) })
if (!parsed.success) return { error: "内容不合法" }
const { error } = await supabase.from("messages")
.insert({ content: parsed.data.content, user_id: user.id })
if (error) return { error: error.message }
revalidatePath("/")
return { ok: true }
}
这里同时用到了:认证校验(第 7 篇)+ zod 校验(第 6 篇)+ 渐进增强表单(第 8 篇)。
五、认证入口(第 7 篇)
登录按钮调 GitHub OAuth,回调用本站 auth/callback/route.ts(第 7 篇原样复用)。删自己的留言:
await supabase.from("messages").delete().eq("id", id).eq("user_id", user.id)
// 加 user_id 条件 = 对象级鉴权(第 9 篇),RLS 再兜底
六、上线(第 13 篇)
- 推 GitHub → Vercel 导入 → 配环境变量。
- Supabase 执行上面的
schema.sql。 - 配 GitHub OAuth + 域名 HTTPS。
- 打开手机访问,发一条留言,刷新看到它——你独立完成了第一个全栈应用 🎉
七、可复制的全栈工作流(记住这条线)
需求拆解(做 MVP)
→ 数据建模(建表 + RLS + 索引)
→ 页面(Server Component 读)
→ 写操作(Server Action + zod + 鉴权)
→ 安全自查(第 9 篇清单)
→ 测试(第 12 篇)
→ 部署监控(第 13 篇)
这套流程适用于绝大多数全栈项目:待办、博客、小电商、内部工具……换汤不换药。
总结
- 综合实战 = 把 1-13 篇的零件按「需求→建模→页面→写→安全→部署」流水线组装。
- 数据库层就做防御(CHECK / RLS / 索引),不把希望全押在接口。
- Server Action 同时承载认证、校验、鉴权,是全栈写操作的核心形态。
- 跑通留言板,你就证明了「能独立交付全栈应用」。
最后一篇,我们谈上线之后:维护、迭代,以及如何把这份能力变成作品集、接单与求职的资本。
练习:照这篇的七步,把「留言板」真正做出来并部署上线。做完它,你简历上就能写「独立全栈开发」——这是下一篇要聊的。
Comments
Sign in to leave a comment.