> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/ai-vibe-coding/zh/integration/ji-cheng-supabase.md).

# 集成 Supabase

这里介绍如何在 App in Toss（迷你应用）WebView 环境中接入 Supabase。Supabase JS 客户端可与框架无关地运行。代码示例基于 **基于 Vite（React + TypeScript）** 编写。

***

### 概述

Supabase 是一个提供认证、数据库（PostgreSQL）、文件存储、实时订阅等功能的开源后端服务。在 App in Toss WebView 环境中也可以同样使用，不过， **安全设置和环境变量管理**很重要。

***

### 1. 准备工作

* Supabase 账户（[supabase.com](https://supabase.com))
* 使用 Vite（React + TypeScript）制作的项目
* Node.js、npm（或 yarn、pnpm）

### 2. 创建 Supabase 项目

1. 在 Supabase 仪表板中 **New project**点击它来创建新项目。
2. 设置项目名称、数据库密码和区域后完成创建。
3. 项目准备好后，可以在仪表板中查看以下信息。

```
Project URL     : https://<project-id>.supabase.co
Publishable key : sb_publishable_xxxxxxxxxxxx
```

### 3. 设置环境变量

出于安全考虑，建议将 Supabase 连接信息作为环境变量管理。在项目根目录下 `.env` 创建文件，并按如下方式编写。

```bash
VITE_SUPABASE_URL=https://<project-id>.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=sb_publishable_xxxxxxxxxxxx
```

### 4. 安装并初始化 Supabase

`src/supabase/client.ts` 创建文件，并像下面这样初始化 Supabase 客户端。

```bash
npm install @supabase/supabase-js
```

```ts
import { createClient } from '@supabase/supabase-js';

const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabasePublishableKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY;

export const supabase = createClient(supabaseUrl, supabasePublishableKey);
```

{% hint style="info" %}
**参考**

Publishable key 就像 Stripe 的 `pk_live_...`、Firebase 的 `apiKey`一样，是可以暴露给客户端的公开密钥。不过， **必须设置 RLS（行级安全）策略** 。没有 RLS 的情况下，只要有 publishable key，任何人都可以读写整张表。

`secret` 密钥是可以完全绕过 RLS 的秘密密钥。仅在服务器端使用，绝不要暴露给客户端。
{% endhint %}

### 5. 数据库使用示例

如果已经初始化了 Supabase 客户端，就可以在 React 组件中读写数据。下面是 `App.tsx`中读取并保存单行数据的最简单示例。

Supabase 仪表板中的 **Table Editor**中 `users` 创建表， `id`（int8，主键）以及 `name`（text）列。

```tsx
import { useState, useEffect } from 'react';
import { supabase } from './supabase/client';

function App() {
  const [name, setName] = useState('');
  const [savedName, setSavedName] = useState('');

  // 从 Supabase 读取数据
  useEffect(() => {
    const fetchData = async () => {
      const { data } = await supabase.from('users').select('name').eq('id', 1).single();
      if (data) {
        setSavedName(data.name);
      }
    };
    fetchData();
  }, []);

  // 向 Supabase 写入数据
  const handleSave = async () => {
    await supabase.from('users').upsert({ id: 1, name });
    setSavedName(name);
    setName('');
  };

  return (
    <div style={{ padding: 24 }}>
      <h1>Supabase 简单示例</h1>
      <input value={name} onChange={(e) => setName(e.target.value)} placeholder="输入姓名" />
      <button onClick={handleSave}>保存</button>
      <p>已保存的姓名：{savedName || '(无)'}</p>

  );
}

export default App;
```

#### 工作方式

* 读取数据（`.select()`)
  * `users` 在表中 `id`只读取 id 为 1 的行一次。
  * 如果该行存在， `name` 将值显示在界面上。
* 写入数据（`.upsert()`)
  * 将输入的姓名 `users` 保存到表中。
  * 如果没有该行则新建，有则覆盖。

{% hint style="info" %}
**Supabase 其他功能**

* 实时订阅： `.channel()`, `.on()`使用它们后，数据变化时 UI 会自动更新。
* 文件存储： `supabase.storage`可以上传图片或文件。
* 认证集成： `supabase.auth`配合使用后，可以实现按用户保存数据。
  {% endhint %}

### 6. 安全检查清单

* 将敏感信息作为环境变量管理
  * Supabase URL、publishable key 等不要直接写在代码中，而是 `.env`来管理。
* 不要把环境文件上传到 Git 等仓库
  * `.env` 文件必须添加到 `.gitignore`中。
  * 如果密钥泄露，请立即在 Supabase 仪表板中重新生成密钥。
* **务必设置行级安全（RLS）**
  * Supabase 的所有表默认都处于 RLS 关闭状态。
  * 在 RLS 关闭的情况下，只要有 publishable key，任何人都可以访问整张表。
  * 部署前务必启用 RLS，并设置策略（Policy），仅允许已认证用户访问。
  * Supabase 仪表板 **Table Editor → 选择表 → RLS** 可在该标签页中设置。
* 确认来源（Origin）限制
  * Supabase 仪表板中的 **Authentication → URL Configuration**中限制允许的域名。
  * 只允许迷你应用（WebView）域名，可以防止未授权访问。

{% hint style="info" %}
**允许的目标域名**

根据 SDK 版本不同而不同。\
\
SDK 3.x\
`https://<appName>.web.tossmini.com` — 实际服务环境 \
`https://<appName>.private-web.tossmini.com` — 控制台 QR 测试环境\
\
SDK 1.x \~ 2.x\
`https://<appName>.apps.tossmini.com` — 实际服务环境 \
`https://<appName>.private-apps.tossmini.com` — 控制台 QR 测试环境
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers-apps-in-toss.toss.im/ai-vibe-coding/zh/integration/ji-cheng-supabase.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
