前端直接 Supabase 访问
本页面记录了前端代码中直接使用 Supabase SDK(不通过后端 API)的所有场景。 这是项目架构设计中允许的访问模式,但需要了解其影响和边界。
架构说明
前端的 Service 层允许直接访问 Supabase SDK,这是架构设计中认可的模式。数据通过 Supabase 的 RLS(Row Level Security)策略保护,确保用户只能访问自己有权限的数据。
层级规则:
- Services 层:允许直接使用 Supabase SDK(
.from()、.rpc()、.auth、.channel()、.storage) - Composables 层:允许使用 Supabase Realtime(
.channel()),用于实时订阅 - Stores 层:应通过 Services 层间接访问,但存在少量直接调用
- Views 层:应通过 Services/Stores 间接访问,越层调用需要注意
Services 层
billingService.ts
计费相关的数据直接通过 Supabase 查询,订阅管理操作则走后端 API。
| 方法 | 操作 | 表/RPC | 说明 |
|---|---|---|---|
getSubscription | from().select() | subscriptions | 读取团队订阅信息 |
getCreditBalance | from().select() | credit_balances | 读取积分余额 |
updateAutoTopup | from().update() | credit_balances | 更新自动充值配置 |
listTransactions | from().select() | credit_transactions | 查询积分流水 |
getUsageHeatmap | rpc() | get_usage_heatmap | 获取用量热力图 |
listPricingRules | from().select() | billing_rules | 查询定价规则 |
createBillingRule | from().insert() | billing_rules | 创建定价规则 |
updateBillingRule | from().update() | billing_rules | 更新定价规则 |
deleteBillingRule | from().update() | billing_rules | 软删除定价规则 |
listProviderCosts | from().select() | model_provider_costs | 查询供应商成本 |
upsertProviderCosts | from().upsert() | model_provider_costs | 批量更新供应商成本 |
deleteProviderCosts | from().delete() | model_provider_costs | 删除供应商成本 |
cancelRenewal | fetch() | 后端 API | 取消续订(走后端) |
resumeRenewal | fetch() | 后端 API | 恢复续订(走后端) |
changePlan | fetch() | 后端 API | 变更套餐(走后端) |
permissionService.ts
权限查询和审计日志直接操作 Supabase。
| 方法 | 操作 | 表/RPC | 说明 |
|---|---|---|---|
getSitePermissions | from().select() | grants | 查询当前用户站点权限 |
hasSitePermission | from().select() | grants | 检查是否有指定权限 |
logAudit | from().insert() | audit_logs | 记录审计日志 |
listAuditLogs | from().select() | audit_logs_with_names | 查询审计日志列表(视图) |
apiKeyService.ts
API Key 列表和更新直接操作 Supabase,创建走后端 API。
| 方法 | 操作 | 表/RPC | 说明 |
|---|---|---|---|
listByTeam | from().select() | api_keys | 获取团队 API Key 列表 |
create | fetch() | 后端 API | 创建 API Key(走后端,密钥安全) |
update | from().update() | api_keys | 更新 API Key 设置 |
delete | rpc() | delete_api_key | 软删除 API Key(数据库 RPC) |
siteSettingsService.ts
站点配置完全通过 Supabase 直接操作。
| 方法 | 操作 | 表/RPC | 说明 |
|---|---|---|---|
get | from().select() | site_settings | 获取单个配置项 |
getMany | from().select() | site_settings | 批量获取配置项 |
getAll | from().select() | site_settings | 获取所有配置项 |
set | from().upsert() | site_settings | 设置配置项(upsert) |
setMany | from().upsert() | site_settings | 批量设置配置项 |
delete | from().delete() | site_settings | 删除配置项 |
realtimeService.ts
Supabase Realtime 订阅封装,所有实时数据同步通过此服务。
| 方法 | 操作 | 订阅表 | 说明 |
|---|---|---|---|
subscribeToTable | channel().on() | 任意表 | 通用单表订阅 |
subscribeToMultipleTables | channel().on() | 多表 | 通用多表共享 channel 订阅 |
subscribeToBillingTables | 多表订阅 | credit_balances, credit_transactions, subscriptions | 计费数据实时同步 |
subscribeToAiModelTables | 多表订阅 | billing_rules, model_provider_costs | AI 模型数据变更 |
subscribeToDocument | 单表订阅 | documents | 文档变更监听 |
subscribeToPaymentOrder | 单表订阅 | payment_orders | 支付订单状态监听 |
subscribeToRuns | channel().on() | runs | 执行记录变更(按 deployment) |
subscribeToProjectRuns | channel().on() | runs | 执行记录变更(按 project) |
subscribeToRompMessages | 多表订阅 | romp_messages | ROMP 消息实时推送 |
subscribeToTypingIndicator | Broadcast | — | ROMP 输入状态指示器 |
subscribeToProjectData | 多表订阅 | projects, documents, deployments, project_schedules | 项目级数据同步 |
subscribeToTeamData | 多表订阅 | projects, deployments, team_members | 团队级数据同步 |
createCollaborationChannel | Presence + Broadcast | — | Yjs 协同编辑通道 |
Composables 层
useAssetsRealtime.ts
资产状态实时订阅。
| 操作 | 订阅表 | 说明 |
|---|---|---|
channel().on() | assets_items | 监听资产 UPDATE 事件,更新 Store 状态 |
channel().on() | assets_sessions | 监听会话 UPDATE 事件,检测控制权转移 |
useStorageRealtime.ts
存储文件实时订阅。
| 操作 | 订阅表 | 说明 |
|---|---|---|
channel().on() | files | 监听文件 INSERT/UPDATE/DELETE,刷新文件列表 |
Stores 层
romp.ts
ROMP 聊天 Store 中直接调用 Supabase Auth 获取 Session Token,用于 WebSocket 连接鉴权。
| 操作 | API | 说明 |
|---|---|---|
supabase.auth.getSession() | Auth | 获取 access_token 用于 WS 连接 |
Views 层(越层调用)
警告
以下为 Views 层直接调用 Supabase SDK 的场景,属于越层调用,理想情况应迁移到 Services 层。
DashboardMainBody.vue
| 操作 | API | 说明 |
|---|---|---|
supabase.storage.from().getPublicUrl() | Storage | 获取横幅图片公开 URL |
BannersConfigTab.vue(Admin)
| 操作 | API | 说明 |
|---|---|---|
supabase.storage.from().getPublicUrl() | Storage | 获取横幅图片公开 URL |
supabase.storage.from().upload() | Storage | 上传横幅封面图片 |
supabase.storage.from().remove() | Storage | 删除旧封面图片 |
注意事项
RLS 保护:所有直接 Supabase 访问都受 RLS 策略保护。前端使用
anonkey + JWT 认证,不会泄露service_rolekey。数据一致性:对于需要跨表事务或复杂业务逻辑的操作(如创建 API Key、订阅变更),统一走后端 API 处理。
Realtime 订阅:Supabase Realtime 的 postgres_changes 事件受 RLS 策略约束,用户只能收到自己有权访问的行变更。
Storage 访问:
getPublicUrl()仅生成 URL 不做鉴权检查,实际访问权限由 Storage 的 Bucket Policy 控制。upload()和remove()需要有效 JWT。越层调用治理:Views 层的直接 Supabase 调用(DashboardMainBody、BannersConfigTab)应逐步迁移到 Services 层,以保持架构分层清晰。