PolarDB Supabase是PolarDB PostgreSQL版推出全托管的Supabase服务,以PolarDB PostgreSQL版为核心,整合了Realtime实时数据库、RESTful API、GoTrue身份认证、文件存储、日志采集等关键功能,并在此基础上进行了优化与增强,为您省去Supabase复杂的参数管理和应用运维等操作,并提供了兼具灵活性与高性能的后端解决方案。您可以基于PolarDB Supabase快速搭建Web、SaaS平台、AI集成应用等现代化应用。
接下来,将为您展示如何使用PolarDB Supabase快速搭建一个会议笔记系统。
效果展示
交互体验如下,打开两个浏览器,进入同一个会议,可以观察到两侧的信息是实时同步的。会议笔记系统的核心功能包括实时协作编辑、用户在线状态管理、文件上传与管理、任务追踪、活动日志以及标签系统。
核心功能
功能 | 说明 |
完整数据库功能 | Supabase基于PolarDB PostgreSQL版数据库构建,提供完整的数据库功能:
|
实时订阅(Realtime) | 基于PostgreSQL的逻辑复制,实现实时数据同步:
|
身份认证(Auth) | 内置完善的身份认证和授权系统:
|
行级安全(RLS) | 基于PostgreSQL的行级安全策略:
|
存储服务(PolarFS) | 基于PolarDB文件系统(Polar File System,简称PolarFS)进行文件存储与管理:
|
边缘函数(Edge Functions) | 基于Deno的服务器端函数:
|
API(REST & GraphQL) | 自动生成的API接口:
|
搭建会议笔记系统
在会议笔记系统中,将主要应用以下功能:
功能 | 说明 |
数据存储,主要记录会议、笔记、任务、用户状态等表信息。 | |
协作功能,用于实时同步笔记编辑、用户在线状态。 | |
数据安全,用于控制用户访问权限。 | |
文件管理,用于会议资料上传和下载。 | |
用户管理,用于管理用户登录和会话管理。 |
应用技术栈
前端:Next.js 15 + React 18 + TypeScript。
后端:PolarDB Supabase (PostgreSQL + 鉴权 + 实时订阅 + 存储)。
UI:Tailwind CSS + Radix UI。
状态管理:React Hooks + 本地状态。
数据库设计
为会议笔记系统的核心功能设计会议表、笔记表、用户在线状态表、标签表及任务表等系统表,并通过外键约束以确保数据的一致性。
实时订阅配置
启用实时功能
-- 启用实时订阅功能
ALTER PUBLICATION supabase_realtime ADD TABLE meetings;
ALTER PUBLICATION supabase_realtime ADD TABLE notes;
ALTER PUBLICATION supabase_realtime ADD TABLE user_presence;
ALTER PUBLICATION supabase_realtime ADD TABLE tags;
ALTER PUBLICATION supabase_realtime ADD TABLE tasks;
ALTER PUBLICATION supabase_realtime ADD TABLE meeting_activities;
ALTER PUBLICATION supabase_realtime ADD TABLE meeting_files;
客户端实时订阅
// 创建自定义Hook管理实时订阅
export function useRealtime(meetingId: string, callbacks: RealtimeCallbacks) {
const channelsRef = useRef<any[ ]>([ ])
const cleanup = useCallback(() => {
channelsRef.current.forEach((channel) => {
supabase.removeChannel(channel)
})
channelsRef.current = []
}, [])
useEffect(() => {
if (!meetingId) return
// 清理之前的连接
cleanup()
// 创建多个专用频道
const presenceChannel = supabase
.channel(`presence:${meetingId}`)
.on(
"postgres_changes",
{
event: "*",
schema: "public",
table: "user_presence",
filter: `meeting_id=eq.${meetingId}`,
},
(payload) => {
console.log("User presence change:", payload)
if (callbacks.onUserPresenceChange) {
loadOnlineUsers()
}
},
)
.subscribe()
// 保存频道引用用于清理
channelsRef.current = [presenceChannel, /* 其他频道 */]
}, [meetingId, callbacks])
return { cleanup }
}
实时订阅设计指南
功能隔离:按业务场景划分独立频道(如在线状态、文档协作、任务通知),避免逻辑耦合。
事件过滤:通过
filter
参数限定事件范围(如指定会议ID),减少冗余数据传输。资源回收:在组件卸载或页面跳转时,主动调用
removeChannel
清理所有频道连接,释放资源。错误处理:监听订阅通道的状态,对断连、超时等异常进行重试或降级处理。
安全性
行级安全(RLS)
-- 启用RLS
ALTER TABLE meetings ENABLE ROW LEVEL SECURITY;
-- 创建安全策略
CREATE POLICY "Users can view all meetings" ON meetings
FOR SELECT USING (true);
CREATE POLICY "Users can create meetings" ON meetings
FOR INSERT WITH CHECK (true);
CREATE POLICY "Users can update their own meetings" ON meetings
FOR UPDATE USING (auth.uid() = created_by);
用户认证
const login = useCallback(async (email: string, password: string) => {
try {
const { data, error } = await supabase.auth.signInWithPassword({ email, password })
if (error) throw error
if (data.user) {
const userData = transformSupabaseUser(data.user)
setUser(userData)
localStorage.setItem("meeting_user", JSON.stringify(userData))
return { success: true, user: userData }
}
return { success: false, error: '登录失败' }
} catch (error: any) {
return { success: false, error: error.message || '登录失败' }
}
}, [])
const transformSupabaseUser = (supabaseUser: SupabaseUser): User => ({
id: supabaseUser.id,
email: supabaseUser.email || null,
name: supabaseUser.user_metadata?.name || supabaseUser.email?.split('@')[0] || '用户',
avatar_url: supabaseUser.user_metadata?.avatar_url || null,
created_at: supabaseUser.created_at,
is_anonymous: supabaseUser.user_metadata?.is_anonymous || false,
})
客户端集成
客户端配置
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
// 类型定义
export interface Meeting {
id: string
created_at: string
title: string
description: string | null
}
环境变量管理
# 生产环境变量
NEXT_PUBLIC_SUPABASE_URL=<YOUR_SUPABASE_PUBLIC_URL>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<YOUR_SUPABASE_ANON_KEY>
快速搭建
下载项目示例代码:PolarDB-Supabase-App-Demo。
准备运行环境:项目示例代码需要在您的本地环境中安装
Node.js
和pnpm
。说明Node.js
:请前往Node.js
官方网站进行下载和安装。pnpm
:在安装Node.js
后,可通过npm
进行全局安装,命令为npm install -g pnpm
。
环境配置:在项目根目录创建
.env.local
文件,并将以下值替换为您PolarDB Supabase的配置。说明您可在集群的
列表页面,单击您的应用ID进入应用详情页,在拓扑图与配置页签中查看相关配置信息。<YOUR_SUPABASE_PUBLIC_URL>
为应用的公网地址。<YOUR_SUPABASE_ANON_KEY>
为应用参数secret.jwt.anonKey
的值。
# 生产环境变量 NEXT_PUBLIC_SUPABASE_URL=<YOUR_SUPABASE_PUBLIC_URL> NEXT_PUBLIC_SUPABASE_ANON_KEY=<YOUR_SUPABASE_ANON_KEY>
数据库初始化:在项目根目录的
scripts
文件夹下找到01-create-tables.sql
文件,并在Supabase Dashboard上面的右侧导航栏SQL Editor中执行SQL。运行项目:请在项目根目录下执行以下命令以安装依赖并启动项目。启动后,默认的本地访问地址为
http://localhost:3000
,您可以直接在浏览器中访问该系统。pnpm install pnpm dev
经验总结
基于上述会议笔记系统项目的实战经验,PolarDB Supabase最佳实践包括:
遵循这些最佳实践可以构建稳定、安全、高性能的PolarDB Supabase应用。