SuperAPI AI 工具集

supabase-fullstack-setup

编程与开发

查看项目

更新于 10-16 04:37

技能介绍

用途

该技能是一份完整指南,用于将 Supabase 与 Next.js 13+ 的 App Router 集成,涵盖认证、数据库设置、行级安全(RLS)以及生产应用中的常见模式。适用于启动带有 Supabase 的 Next.js 新项目、需要社交登录认证、构建用户专属数据应用(如笔记、收藏)、需要实时订阅、需要安全的服务端与客户端数据访问、或用数据库实现限流与审计日志、构建 SaaS 应用等场景。

核心设置

第 1 步:安装依赖

npm install @supabase/supabase-js @supabase/ssr
# 或
pnpm add @supabase/supabase-js @supabase/ssr

第 2 步:环境变量

创建 .env.local:

NEXT_PUBLIC_SUPABASE_URL=your-project-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key

获取位置:https://app.supabase.com/project/_/settings/api

第 3 步:创建 Supabase 客户端

服务端客户端(lib/supabase/server.ts)使用 createServerClient 与 next/headers 的 cookies,通过 getAll() 读取 cookie、setAll() 写入 cookie(写入放在 try/catch 中,注明从 Server Component 调用时由中间件处理)。浏览器客户端(lib/supabase/client.ts)使用 createBrowserClient。

第 4 步:认证设置

提供 Auth Context(contexts/auth-context.tsx),声明 user、loading、signIn、signUp、signOut,通过 supabase.auth.getSession() 获取初始会话,并用 onAuthStateChange 监听认证变化,在清理函数中调用 subscription.unsubscribe();signIn 使用 signInWithPassword,signUp 使用 signUp,signOut 使用 signOut。并导出 useAuth,在 Provider 外使用时抛出错误。

第 5 步:数据库表结构示例

给出四张表的建表与索引语句:video_analyses(视频分析,含 youtube_id、user_id、title、author、thumbnail_url、duration、transcript、topics、summary、suggested_questions 等,并对 youtube_id、user_id 建索引);notes(笔记,user_id 非空,video_id 外键带 ON DELETE CASCADE,含 source、source_id、text、metadata,对 user_id、video_id 建索引);user_favorites(收藏,user_id 与 video_analysis_id 组合主键,均级联删除);rate_limits(限流,含 key、identifier、timestamp,对 key+timestamp 与 timestamp 建索引)。

第 6 步:行级安全(RLS)

对 notes 和 user_favorites 启用 RLS,并创建策略:笔记的查看、创建、更新、删除均以 auth.uid() = user_id 为条件(SELECT/UPDATE/DELETE 用 USING,INSERT 用 WITH CHECK);收藏的查看、添加、删除同样以 auth.uid() = user_id 为条件。

使用示例

  • 示例 1:服务端数据获取:在 app/my-notes/page.tsx 中用服务端客户端取 getUser(),未登录则 redirect 到 /login,再查询 notes 表按 user_id 过滤并按 created_at 倒序。
  • 示例 2:客户端数据变更:在客户端组件中用 useAuth 获取用户,通过表单提交向 notes 表 insert(带 user_id、video_id、source、text),并检查 error。
  • 示例 3:带鉴权的 API 路由:app/api/notes/route.ts 中 GET 与 POST 均先 getUser(),未授权返回 401;GET 按 userId 与 videoId 查询,POST 解析 body 后 insert 并 .select().single(),出错返回 500。
  • 示例 4:实时订阅:客户端组件先取初始笔记,再用 supabase.channel('notes-changes').on('postgres_changes', ...) 订阅,按 user_id=eq.${user.id} 过滤,依据 INSERT/DELETE/UPDATE 事件更新本地 state,并在清理函数中 channel.unsubscribe()。
  • 示例 5:社交登录:使用 signInWithOAuth 支持 Google 与 GitHub,redirectTo 指向 /auth/callback;回调路由中读取 code 并调用 exchangeCodeForSession(code),随后重定向到根路径。

最佳实践

始终使用 RLS(绝不信任客户端安全);分离客户端(敏感操作用服务端客户端);为数据类型化;处理认证状态(用 context 管理用户状态);清理订阅(在 useEffect 清理中取消订阅);多表操作用事务;为外键建索引;注意常见陷阱:忘记 RLS 导致数据暴露、在浏览器代码中使用错误的客户端、不处理 error 对象、订阅泄漏、缺少索引导致大表查询慢、在 RLS 策略中硬编码 ID 而非使用 auth.uid()。

数据库模式

  • 软删除:为 notes 增加 deleted_at 列,并在 SELECT 策略中加入 deleted_at IS NULL。
  • 审计追踪:创建 audit_logs 表,含 user_id、action、table_name、record_id、old_data、new_data、created_at。
  • 自动时间戳:创建 update_updated_at() 触发器函数,更新时设置 NEW.updated_at = NOW(),并在 notes 的 BEFORE UPDATE 上挂载触发器。

类型生成

安装 Supabase CLI(npm install -g supabase),运行 supabase gen types typescript --project-id your-project-id > lib/database.types.ts 生成类型;随后可从 Database 中派生 Row、Insert、Update 类型。

后续步骤

设置数据库迁移、为文件配置存储桶、为认证添加邮件模板、为复杂逻辑设置 Edge Functions、配置自定义 SMTP、添加数据库备份。

相关技能

保护 Next.js API 路由、类型安全的表单验证、弹性异步操作。