Supabase 2026 深度解析:开源 Firebase 的极限进化——从数据库到 AI 应用全家桶
前言
2026年,Supabase 已经不再只是"Firebase 的开源替代品"了。
它进化为一套完整的后端即服务(Backend as a Service)平台,构建在 PostgreSQL 之上,提供实时数据库、身份认证、文件存储、边缘函数、向量检索等全套能力。更重要的是,Supabase 将 PostgreSQL 的强大 SQL 能力与 AI 时代的需求深度结合——pgvector 向量存储、RAG 管道支持、实时数据订阅,让开发者无需搭建复杂的后端基础设施,就能快速构建现代 AI 应用。
本文将从 Supabase 的核心架构出发,深入解析 2026 年的关键新特性:模板系统、熔断器模式、向量存储、RAG 集成、以及构建 AI 应用后端的实战指南。
一、Supabase 是什么?不止是 Firebase 替代品
1.1 架构全景
# Supabase 全家桶
#
# Firebase: 专有云、NoSQL (Firestore)、闭源生态
# Supabase: 开源可自托管、PostgreSQL、SQL 原生、开放生态
Supabase 核心组件:
├── PostgreSQL 17 # 关系型数据库 (核心)
├── pgvector # 向量存储与检索 (AI 支持)
├── GoTrue # 身份认证 (JWT)
├── PostgREST # REST API 自动生成
├── PostgRPC # gRPC API (高性能)
├── Realtime # WebSocket 实时订阅
├── Storage # 文件存储 (S3 兼容)
├── Edge Functions # 边缘函数 (Deno)
├── Edge Analytics # 边缘分析
└── Studio # 管理界面
1.2 为什么选择 PostgreSQL?
-- PostgreSQL 的优势:既可以做传统关系型数据库
-- 也可以做向量数据库、时间序列数据库、全文搜索...
-- 1. 关系型数据
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT UNIQUE NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
-- 2. 向量数据 (pgvector)
CREATE TABLE document_embeddings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
content TEXT NOT NULL,
embedding vector(1536), -- OpenAI embeddings 维度
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT now()
);
-- 3. 时序数据
CREATE TABLE sensor_readings (
device_id UUID REFERENCES devices(id),
recorded_at TIMESTAMPTZ DEFAULT now(),
temperature FLOAT,
humidity FLOAT
) PARTITION BY RANGE (recorded_at);
-- 4. 全文搜索
CREATE TABLE articles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT,
body TEXT,
search_vector TSVECTOR -- 全文搜索向量
);
-- 5. 行级安全 (RLS) - Supabase 认证的核心
CREATE POLICY "Users can view own data"
ON users
FOR SELECT
USING (auth.uid() = id); -- 自动化与 GoTrue 认证集成
二、模板系统:开发效率提升 300%
2.1 模板系统设计
// Supabase 模板系统
// 核心思想:将常见应用模式封装为可复用的模板
// 模板类型
type Template =
| "saas-starter" // SaaS 应用基础架构
| "social-app" // 社交应用
| "e-commerce" // 电商
| "ai-chatbot" // AI 聊天机器人
| "real-time-collab" // 实时协作
| "rag-pipeline" // RAG 管道
// 模板包含
interface Template {
id: string
name: string
description: string
// 数据库 Schema
schemas: {
tables: Table[]
functions: Function[]
triggers: Trigger[]
policies: Policy[] // RLS 策略
}[]
// API 配置
apis: {
rest: Route[] // PostgREST 自动生成
rpc: Procedure[] // RPC 函数
}[]
// 前端示例
frontend?: {
framework: "react" | "vue" | "svelte"
code: string
}
// 边缘函数
edgeFunctions: EdgeFunction[]
}
// 使用模板创建项目
const { data, error } = await supabase.cli.projects.create({
template: "saas-starter",
name: "my-saas-app",
organization: "my-org",
})
console.log("Project created with:")
console.log("- 8 tables (users, teams, subscriptions, ...)")
console.log("- 15 RLS policies")
console.log("- 5 RPC functions")
console.log("- React starter code")
2.2 SaaS 模板实战
-- Supabase SaaS Starter 模板的核心表结构
-- 1. 组织/团队
CREATE TABLE organizations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
plan TEXT DEFAULT 'free' CHECK (plan IN ('free', 'pro', 'enterprise')),
created_at TIMESTAMPTZ DEFAULT now()
);
-- 2. 用户-组织关联 (多租户)
CREATE TABLE organization_members (
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
role TEXT DEFAULT 'member' CHECK (role IN ('owner', 'admin', 'member')),
joined_at TIMESTAMPTZ DEFAULT now(),
PRIMARY KEY (organization_id, user_id)
);
-- 3. 订阅管理
CREATE TABLE subscriptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
stripe_customer_id TEXT,
stripe_subscription_id TEXT,
status TEXT DEFAULT 'active' CHECK (status IN ('active', 'past_due', 'canceled')),
current_period_end TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT now()
);
-- 4. 审计日志
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
actor_id UUID REFERENCES auth.users(id),
action TEXT NOT NULL,
resource_type TEXT NOT NULL,
resource_id UUID,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT now()
);
-- RLS 策略:组织隔离
ALTER TABLE organizations ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view own organizations"
ON organizations FOR SELECT
USING (
id IN (
SELECT organization_id FROM organization_members
WHERE user_id = auth.uid()
)
);
CREATE POLICY "Only owners can delete organizations"
ON organizations FOR DELETE
USING (
EXISTS (
SELECT 1 FROM organization_members
WHERE organization_id = organizations.id
AND user_id = auth.uid()
AND role = 'owner'
)
);
2.3 实时协作模板
// Supabase 实时协作模板
// 支持: 多人同时编辑、实时聊天、协同白板
import { createClient } from "@supabase/supabase-js"
import type { RealtimeChannel } from "@supabase/supabase-js"
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!
)
// 1. Presence:追踪谁在线
interface PresenceState {
user_id: string
user_name: string
cursor?: { x: number; y: number }
selection?: string[]
}
const channel: RealtimeChannel = supabase.channel("room-123", {
config: {
presence: {
key: supabase.auth.currentUser?.id || "anonymous",
},
},
})
// 加入房间
channel.on("presence", { event: "sync" }, () => {
const state = channel.presenceState()
console.log("Online users:", Object.keys(state))
})
// 监听他人加入/离开
channel.on("presence", { event: "join" }, ({ key, newPresences }) => {
console.log(`${key} joined with:`, newPresences)
})
channel.on("presence", { event: "leave" }, ({ key, leftPresences }) => {
console.log(`${key} left`)
})
// 广播光标位置
document.addEventListener("mousemove", (e) => {
channel.presenceTrack({
cursor: { x: e.clientX, y: e.clientY },
timestamp: Date.now(),
})
})
await channel.subscribe(async (status) => {
if (status === "SUBSCRIBED") {
await channel.presenceTrack({ name: "Alice" })
}
})
// 2. Broadcast:实时消息
channel.on("broadcast", { event: "chat-message" }, ({ payload }) => {
console.log("Received:", payload)
appendMessage(payload)
})
// 发送消息
const sendMessage = (content: string) => {
channel.send({
type: "broadcast",
event: "chat-message",
payload: {
user_id: supabase.auth.currentUser?.id,
content,
sent_at: new Date().toISOString(),
},
})
}
// 3. Postgres Changes:监听数据库变更
channel.on(
"postgres_changes",
{
event: "UPDATE",
schema: "public",
table: "documents",
filter: "room_id=eq.123",
},
(payload) => {
console.log("Document updated:", payload.new)
// 实时同步文档内容
syncDocument(payload.new)
}
)
三、熔断器模式:高可用保障
3.1 为什么需要熔断器?
// 分布式系统的级联失败
//
// 问题场景:
// - 外部支付 API 响应慢 (500ms → 30s)
// - 支付服务占满连接池
// - 其他依赖数据库的服务开始超时
// - 最终整个系统崩溃
// 解决方案: 熔断器
// 1. 正常状态: 请求直接通过
// 2. 失败率超过阈值: 熔断器打开 (快速失败,不调用外部服务)
// 3. 半开状态: 允许少量请求试探
// 4. 恢复: 逐步恢复调用
import { CircuitBreaker, CircuitBreakerState } from "./circuit-breaker"
// Supabase 内置熔断器
const breaker = new CircuitBreaker({
name: "stripe-api",
// 失败率阈值
threshold: 0.5, // 50% 失败率触发熔断
// 最小请求数
minimumRequests: 10,
// 熔断持续时间
duration: 30_000, // 30 秒
// 半开状态探测比例
probeRatio: 0.3, // 30% 请求允许通过探测
onStateChange: (state: CircuitBreakerState) => {
console.log(`Circuit ${state}`)
// 通知监控
metrics.track("circuit_breaker", { name: "stripe-api", state })
},
})
// 在边缘函数中使用
Deno.serve(async (req) => {
const result = await breaker.execute(async () => {
// 调用外部服务
const response = await fetch("https://api.stripe.com/v1/charges", {
method: "POST",
headers: { Authorization: `Bearer ${Deno.env.get("STRIPE_SECRET_KEY")}` },
body: new URLSearchParams({ amount: 1000, currency: "usd" }),
})
if (!response.ok) throw new Error(`Stripe error: ${response.status}`)
return response.json()
})
// 熔断状态下的降级处理
if (result.err instanceof CircuitBreakerOpenError) {
return Response.json(
{ error: "Payment service temporarily unavailable", code: "SERVICE_DEGRADED" },
{ status: 503 }
)
}
return Response.json(result.value)
})
3.2 Supabase 边缘函数熔断配置
// supabase/functions/payment/index.ts
// 支付边缘函数,内置熔断与降级
const CONFIG = {
// Stripe 调用超时
stripeTimeout: 5000,
// 熔断器配置
circuitBreaker: {
enabled: true,
errorThreshold: 0.3, // 30% 错误率
resetTimeout: 30000, // 30 秒后重试
halfOpenMaxCalls: 3, // 半开状态最多 3 个请求
},
// 降级策略
fallback: {
enabled: true,
queuePayments: true, // 队列延迟处理
emailNotification: true, // 通知管理员
},
}
// 支付队列 (用于降级)
const paymentQueue: Array<{
amount: number
currency: string
customerId: string
timestamp: number
}> = []
// 熔断器状态检查
async function processPayment(amount: number, currency: string, customerId: string) {
try {
const response = await fetch("https://api.stripe.com/v1/charges", {
method: "POST",
headers: {
Authorization: `Bearer ${Deno.env.get("STRIPE_SECRET_KEY")}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({ amount, currency, customer: customerId }),
signal: AbortSignal.timeout(CONFIG.stripeTimeout),
})
if (!response.ok) {
throw new Error(`Stripe API error: ${response.status}`)
}
return await response.json()
} catch (error) {
// 触发熔断器
return handleCircuitBreakerError(error, amount, currency, customerId)
}
}
async function handleCircuitBreakerError(error: Error, amount: number, currency: string, customerId: string) {
// 记录错误
await supabase.from("payment_errors").insert({
error_type: error.name,
error_message: error.message,
amount,
currency,
customer_id: customerId,
circuit_state: "open",
})
// 降级:队列支付,稍后重试
if (CONFIG.fallback.queuePayments) {
paymentQueue.push({ amount, currency, customerId, timestamp: Date.now() })
// 触发通知
if (CONFIG.fallback.emailNotification) {
await sendAlertEmail(`Payment queued: ${amount} ${currency}`)
}
return {
status: "queued",
queue_id: crypto.randomUUID(),
message: "Payment queued for processing",
}
}
throw error
}
// 定时处理队列中的支付 (边缘函数定时器)
Deno.serve(async (req) => {
if (req.url.includes("/process-queue")) {
return await processPaymentQueue()
}
// 主支付处理
const { amount, currency, customerId } = await req.json()
return await processPayment(amount, currency, customerId)
})
四、向量存储:RAG 的新基础设施
4.1 pgvector 架构
-- Supabase 向量存储配置
-- 1. 启用 pgvector 扩展
CREATE EXTENSION IF NOT EXISTS vector;
-- 2. 创建文档表
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
content TEXT NOT NULL,
metadata JSONB DEFAULT '{}',
-- 向量字段 (支持 1536 维 OpenAI, 1024 维 Cohere, 768 维 BERT)
embedding vector(1536),
-- 元数据: 来源、分区、标签等
source TEXT,
category TEXT,
tags TEXT[],
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
-- 3. 创建向量索引 (HNSW 算法,性能最佳)
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- 4. 相似度搜索
-- 余弦相似度 (Cosine Similarity): 适用于 OpenAI embeddings
-- 欧氏距离 (L2): 适用于图片向量
-- 内积 (IP): 适用于归一化向量
-- 查询最近似文档
SELECT
id,
content,
metadata,
-- 计算相似度分数 (1 - 余弦距离 = 相似度)
1 - (embedding <=> $1::vector) AS similarity,
source
FROM documents
WHERE category = $2 -- 元数据过滤
ORDER BY embedding <=> $1::vector -- HNSW 索引排序
LIMIT $3;
-- 5. 混合搜索 (向量 + 全文)
SELECT
id,
content,
1 - (embedding <=> $1::vector) AS vector_score,
ts_rank(search_vector, plainto_tsquery('english', $2)) AS text_score,
-- 综合评分
(1 - (embedding <=> $1::vector)) * 0.7 +
ts_rank(search_vector, plainto_tsquery('english', $2)) * 0.3 AS combined_score
FROM documents
WHERE
search_vector @@ plainto_tsquery('english', $2) -- 全文过滤
AND category = $3 -- 分类过滤
ORDER BY combined_score DESC
LIMIT $4;
4.2 完整 RAG 管道实现
// supabase/functions/rag-chat/index.ts
// RAG 对话管道
import { createClient } from "@supabase/supabase-js"
import OpenAI from "openai"
const supabase = createClient(
Deno.env.get("SUPABASE_URL")!,
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
)
const openai = new OpenAI({
apiKey: Deno.env.get("OPENAI_API_KEY"),
})
interface RAGRequest {
query: string
systemPrompt?: string
maxContextDocuments?: number
temperature?: number
}
Deno.serve(async (req: Request) => {
const { query, systemPrompt, maxContextDocuments = 5, temperature = 0.7 } = await req.json() as RAGRequest
// 1. 将用户问题转为向量
const queryEmbeddingResponse = await openai.embeddings.create({
model: "text-embedding-3-small",
input: query,
})
const queryEmbedding = queryEmbeddingResponse.data[0].embedding
// 2. 向量相似度检索
const { data: contextDocuments, error } = await supabase.rpc("match_documents", {
query_embedding: queryEmbedding,
match_threshold: 0.7, // 相似度阈值
match_count: maxContextDocuments,
filter_category: null, // 可选:按分类过滤
})
if (error) {
return Response.json({ error: error.message }, { status: 500 })
}
// 3. 构建上下文
const context = contextDocuments
.map((doc: { content: string; source: string }, i: number) =>
`[${i + 1}] ${doc.content}\n来源: ${doc.source}`
)
.join("\n\n")
// 4. 构建 RAG prompt
const system = systemPrompt ||
`你是一个有帮助的AI助手。请根据以下上下文信息回答用户的问题。
如果上下文中没有相关信息,请如实说明,不要编造答案。
---
上下文信息:
${context}
---`
// 5. 调用 LLM
const completion = await openai.chat.completions.create({
model: "gpt-4-turbo",
messages: [
{ role: "system", content: system },
{ role: "user", content: query },
],
temperature,
stream: false,
})
const answer = completion.choices[0].message.content!
// 6. 记录对话历史 (可选)
await supabase.from("rag_conversations").insert({
query,
answer,
context_doc_ids: contextDocuments.map((d: { id: string }) => d.id),
model: "gpt-4-turbo",
})
return Response.json({
answer,
context_used: contextDocuments.length,
sources: contextDocuments.map((d: { source: string }) => d.source),
})
})
// 数据库函数: 向量检索
// 需要在 Supabase SQL Editor 中创建
/*
CREATE OR REPLACE FUNCTION match_documents(
query_embedding vector(1536),
match_threshold float DEFAULT 0.7,
match_count int DEFAULT 5,
filter_category text DEFAULT NULL
)
RETURNS TABLE (
id uuid,
content text,
metadata jsonb,
source text,
category text,
similarity float
)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT
documents.id,
documents.content,
documents.metadata,
documents.source,
documents.category,
1 - (documents.embedding <=> query_embedding) AS similarity
FROM documents
WHERE
(filter_category IS NULL OR documents.category = filter_category)
AND 1 - (documents.embedding <=> query_embedding) > match_threshold
ORDER BY documents.embedding <=> query_embedding
LIMIT match_count;
END;
$$
*/
4.3 性能优化
-- pgvector 性能调优
-- 1. 索引选择
-- HNSW: 更高召回率,更高构建时间,适合读取密集型
-- IVFFlat: 更低内存,更快构建,适合更新频繁型
-- HNSW 参数调优
CREATE INDEX documents_embedding_hnsw ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 128); -- 更高召回
-- 2. 分区策略 (大规模向量)
CREATE TABLE documents_partitioned (
id UUID DEFAULT gen_random_uuid(),
embedding vector(1536),
content TEXT,
created_at TIMESTAMPTZ DEFAULT now()
) PARTITION BY RANGE (created_at);
-- 按月分区
CREATE TABLE documents_2026_01 PARTITION OF documents_partitioned
FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
-- 3. 量化压缩 (降低内存)
-- int8 量化: 精度损失约 5-10%,内存减少 4x
ALTER TABLE documents ALTER COLUMN embedding TYPE vector(1536);
-- 4. 监控查询性能
SELECT
query,
calls,
total_exec_time / 1000 AS total_seconds,
mean_exec_time AS avg_ms,
stddev_exec_time
FROM pg_stat_statements
WHERE query LIKE '%<=%'
ORDER BY total_exec_time DESC
LIMIT 10;
五、实时数据订阅:<100ms 延迟
5.1 实时架构
// Supabase Realtime 工作原理
//
// 架构: Postgres WAL → Decoder → Broadcast → WebSocket
// ┌─────────────────────────────────────────────────────────┐
// │ PostgreSQL │
// │ ┌──────────┐ ┌───────────┐ ┌───────────────────┐ │
// │ │ WAL Log │→ │ pg_logical│→ │ Supabase Realtime │ │
// │ │ Write-Ahead│ │ Decoder │ │ Broadcast │ │
// │ │ Log │ └───────────┘ │ │ │
// │ └──────────┘ │ ┌─────────────┐ │ │
// └────────────────────────────────│ │ WebSocket │ │ │
// │ │ Server │ │ │
// │ └──────┬──────┘ │ │
// └─────────│──────────┘ │
// │ │
// ┌─────────▼──────────┐ │
// │ Client SDK │ │
// │ (JavaScript/...) │ │
// └───────────────────┘ │
//
// 延迟分析:
// - WAL 写入: ~1ms
// - Decoder 解析: ~5ms
// - Broadcast 广播: ~10ms
// - 网络传输: 取决于地理距离 (边缘节点 <10ms)
//
// 端到端延迟: 15-100ms (远优于轮询的 1000-5000ms)
5.2 完整实时聊天实现
// 实时聊天应用
interface Message {
id: string
room_id: string
sender_id: string
content: string
created_at: string
}
interface Reaction {
message_id: string
emoji: string
user_ids: string[]
}
// 1. 订阅新消息
const channel = supabase
.channel(`room:${roomId}`)
.on(
"postgres_changes",
{
event: "INSERT",
schema: "public",
table: "messages",
filter: `room_id=eq.${roomId}`,
},
(payload) => {
const message: Message = payload.new
appendMessage(message)
// 通知
if (message.sender_id !== currentUserId) {
showNotification(`${message.sender_name}: ${message.content}`)
}
}
)
.on(
"postgres_changes",
{
event: "UPDATE",
schema: "public",
table: "reactions",
},
(payload) => {
updateReactions(payload.new as Reaction)
}
)
.subscribe((status) => {
console.log("Channel status:", status)
})
// 2. 发送消息
async function sendMessage(content: string) {
const { data, error } = await supabase
.from("messages")
.insert({
room_id: roomId,
sender_id: currentUserId,
content,
})
.select()
.single()
if (error) {
console.error("Failed to send:", error)
showRetryOption()
}
return data
}
// 3. 表情反应
async function addReaction(messageId: string, emoji: string) {
const { data, error } = await supabase.rpc("toggle_reaction", {
p_message_id: messageId,
p_emoji: emoji,
p_user_id: currentUserId,
})
}
// 4. Typing 指示器
const typingChannel = supabase.channel(`typing:${roomId}`)
typingChannel.on("broadcast", { event: "typing" }, ({ payload }) => {
if (payload.user_id !== currentUserId) {
showTypingIndicator(payload.user_name)
}
})
// 广播 typing 状态
let typingTimeout: ReturnType<typeof setTimeout>
input.addEventListener("input", () => {
typingChannel.send({
type: "broadcast",
event: "typing",
payload: { user_id: currentUserId, user_name: currentUserName },
})
clearTimeout(typingTimeout)
typingTimeout = setTimeout(() => {
// 用户停止输入
}, 2000)
})
六、身份认证:GoTrue 深度整合
6.1 多方式认证
// Supabase Auth 配置
// 1. 邮箱密码认证
const { data, error } = await supabase.auth.signUp({
email: "user@example.com",
password: "secure-password",
options: {
data: { name: "Alice" },
emailRedirectTo: "https://myapp.com/confirm",
},
})
// 2. 魔法链接 (无密码登录)
const { error } = await supabase.auth.signInWithOtp({
email: "user@example.com",
options: {
emailRedirectTo: "https://myapp.com/confirm",
},
})
// 3. 社交登录
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "github", // 支持: github, google, apple, discord, twitter...
options: {
redirectTo: "https://myapp.com/auth/callback",
scopes: "read:user user:email", // 请求权限
},
})
// 4. 验证邮箱
const { data, error } = await supabase.auth.verifyOtp({
email: "user@example.com",
token: "123456",
type: "email",
})
// 5. JWT 会话管理
const { data: { session }, error } = await supabase.auth.getSession()
// 访问令牌 (用于 API 调用)
const accessToken = session.access_token
// 刷新令牌 (自动续期)
const refreshToken = session.refresh_token
// 监听会话变化
supabase.auth.onAuthStateChange((event, session) => {
if (event === "SIGNED_IN") {
console.log("User signed in:", session.user)
} else if (event === "SIGNED_OUT") {
console.log("User signed out")
redirectToLogin()
} else if (event === "TOKEN_REFRESHED") {
console.log("Token refreshed")
}
})
6.2 RLS 与认证深度整合
-- Row Level Security (行级安全) 策略
-- 1. 基础: 用户只能访问自己的数据
CREATE POLICY "Users can read own profile"
ON profiles FOR SELECT
USING (auth.uid() = user_id);
-- 2. 中级: 用户可以读取团队成员的数据
CREATE POLICY "Team members can read project data"
ON projects FOR SELECT
USING (
team_id IN (
SELECT team_id FROM team_members
WHERE user_id = auth.uid()
)
);
-- 3. 高级: 基于角色的细粒度访问
CREATE POLICY "Admins can manage all users"
ON users FOR ALL
USING (
EXISTS (
SELECT 1 FROM organization_members
WHERE organization_id = users.organization_id
AND user_id = auth.uid()
AND role IN ('admin', 'owner')
)
);
-- 4. 公开数据 (无需认证)
CREATE POLICY "Public profiles are visible to everyone"
ON profiles FOR SELECT
USING (is_public = true);
-- 5. 条件更新 (只能修改自己的数据)
CREATE POLICY "Users can update own posts"
ON posts FOR UPDATE
USING (author_id = auth.uid())
WITH CHECK (author_id = auth.uid());
-- 6. 订阅系统: 根据订阅状态限制访问
CREATE POLICY "Pro users can access pro features"
ON features FOR SELECT
USING (
organization_id IN (
SELECT o.id FROM organizations o
JOIN subscriptions s ON s.organization_id = o.id
WHERE s.status = 'active' AND o.plan IN ('pro', 'enterprise')
)
OR
-- 公开特性对所有人可见
is_public = true
);
七、生产环境部署
7.1 自托管 vs 云服务
# docker-compose.yml (自托管 Supabase)
version: "3.8"
services:
postgres:
image: supabase/postgres:15.6.0
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: postgres
POSTGRES_USER: supabase_admin
volumes:
- pgdata:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
kong:
image: kong:3.4
environment:
KONG_DATABASE: "off"
KONG_DECLARATIVE_CONFIG: /usr/local/kong.yml
KONG_PLUGINS: bundled,cors,acl
volumes:
- ./kong.yml:/usr/local/kong.yml
depends_on:
- auth
- rest
auth:
image: supabase/gotrue:v2.151.0
environment:
GOTRUE_SITE_URL: ${SITE_URL}
GOTRUE_URI_ALLOWLIST: ${ALLOWED_ORIGINS}
GOTRUE_DISABLE_SIGNUP: "false"
DATABASE_URL: postgres://supabase_admin:${POSTGRES_PASSWORD}@postgres:5432/postgres?sslmode=disable
JWT_SECRET: ${JWT_SECRET}
SMTP_ADMIN_EMAIL: ${SMTP_ADMIN_EMAIL}
SMTP_HOST: ${SMTP_HOST}
SMTP_PORT: ${SMTP_PORT}
storage:
image: supabase/storage-api:v1.16.0
environment:
ANON_KEY: ${SUPABASE_ANON_KEY}
SERVICE_KEY: ${SUPABASE_SERVICE_KEY}
DATABASE_URL: postgres://supabase_admin:${POSTGRES_PASSWORD}@postgres:5432/postgres?sslmode=disable
volumes:
- storage:/var/lib/storage
realtime:
image: supabase/realtime:v2.28.0
environment:
DB_HOST: postgres
DB_PORT: 5432
DB_USER: supabase_admin
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_NAME: postgres
PORT: 4000
functions:
image: supabase/edge-runtime:v1.55.0
environment:
SUPABASE_URL: http://kong:8000
SUPABASE_ANON_KEY: ${SUPABASE_ANON_KEY}
SUPABASE_SERVICE_KEY: ${SUPABASE_SERVICE_KEY}
volumes:
pgdata:
storage:
7.2 性能监控
// Supabase 性能监控
// 1. 数据库查询分析
const { data, error } = await supabase.rpc("explain_query", {
sql: "SELECT * FROM messages WHERE room_id = $1 ORDER BY created_at DESC LIMIT 20",
params: [roomId],
})
// 2. 实时性能指标
interface PerformanceMetrics {
queryTime: number // 查询执行时间
connectionPoolUsage: number // 连接池使用率
replicationLag: number // 复制延迟
cacheHitRate: number // 缓存命中率
}
// 3. 边缘函数监控
Deno.serve(async (req) => {
const start = performance.now()
// 处理请求
const result = await processRequest(req)
const duration = performance.now() - start
// 发送到监控
await supabase.from("function_metrics").insert({
function_name: "rag-chat",
duration_ms: duration,
status: result.success ? "success" : "error",
error_message: result.error,
timestamp: new Date().toISOString(),
})
return Response.json(result)
})
八、总结
Supabase 在 2026 年已经进化为一套完整的企业级后端平台:
- PostgreSQL 核心: 关系型数据、向量存储、时序数据、全文搜索,全部基于 SQL
- AI 时代支持: pgvector、RAG 管道、流式推理,与 LLM 深度整合
- 实时能力: <100ms 延迟的 WebSocket 订阅,覆盖聊天、协作、实时数据
- 模板系统: SaaS、社交、RAG 等场景开箱即用,开发效率提升 300%
- 高可用保障: 熔断器模式、服务降级、边缘函数容错
- 安全可靠: RLS 行级安全、GoTrue 认证、审计日志
对于创业团队和独立开发者来说,Supabase 提供了一条从原型到生产的最快路径——用一个开源平台替代过去需要 10+ 个服务才能实现的全部功能。
参考资料: