supabase-validation

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
This skill is safe for use in any project. It never runs reset/break loops or destructive commands. Those exist only in the supabase-debug-playground teaching harness and are not part of this skill.

本技能可安全用于任何项目。 它绝不会执行重置/中断循环或破坏性命令。 这类命令仅存在于supabase-debug-playground教学工具中,不属于本技能的范畴。

Normative Principle

规范性原则

No Evidence. Not done.
Every action this skill governs — write, deploy, migrate, fix — is incomplete until observable, raw output confirms it. This is not a style preference; it is the contract this skill enforces.
Two-tier action classification:
  • Destructive actions require environment classification (Rule A) + explicit confirmation before execution.
  • High-sensitivity file edits (any file under
    supabase/
    ) require showing a diff + confirmation before applying — even if the operation is not destructive by the definition below.

无证据,不完成。
本技能管控的所有操作——编写、部署、迁移、修复——在得到可观察的原始输出确认前,都不算完成。这并非风格偏好,而是本技能强制执行的规则。
两级操作分类:
  • 破坏性操作:需要先进行环境分类(规则A),再获得明确确认后方可执行。
  • 高敏感度文件编辑
    supabase/
    目录下的任何文件):即使操作本身不属于下述定义的破坏性操作,也需先展示差异内容并获得确认,才能应用更改。

Destructive Operations — Definition

破坏性操作的定义

Destructive operations are defined here so the term is not interpreted loosely. Any rule that gates on "destructive" applies to all items in this list:
  • Dropping tables or columns
  • Resetting the database (
    supabase db reset
    )
  • Replaying migrations against any live project (local, staging, or production — even local, unless explicitly confirmed disposable)
  • Deleting rows or truncating tables
  • Overwriting a deployed edge function
  • Modifying or dropping RLS policies
  • Any write using
    service_role
    key
If an operation is not on this list, it is still subject to Rules B and A (evidence and environment classification) but does not require the full destructive-operation confirmation protocol.

此处明确定义破坏性操作,避免术语被随意解读。所有基于“破坏性”设置限制的规则,均适用于以下所有操作:
  • 删除表或列
  • 重置数据库(
    supabase db reset
  • 对任何线上项目(本地、预发布或生产环境——即使是本地环境,除非明确确认可随意处置)重放迁移
  • 删除行或截断表
  • 覆盖已部署的Edge Function
  • 修改或删除RLS策略
  • 使用
    service_role
    密钥执行的任何写入操作
如果操作不在此列表中,仍需遵守规则B和规则A(证据要求和环境分类),但无需遵循完整的破坏性操作确认流程。

Global Clause — Non-Interactive Mode

全局条款——非交互模式

Treat as non-interactive if any of the following are true:
  • No active chat session is available to receive a reply
  • Running inside a CI job, automated workflow, or scheduled script
  • Agent mode with
    autoApprove
    ,
    --yes
    , or equivalent flag set
  • The agent cannot determine whether a reply is possible
If uncertain, treat as non-interactive.
Rule: If user confirmation is required (by any rule below) but the agent is running in a non-interactive context, the agent must:
  1. Output the exact command, query, or SQL that would be executed
  2. Explain what it does and why confirmation is required
  3. Not execute it
A rule requiring confirmation does not become optional because the agent cannot ask. It becomes a manual handoff.

满足以下任一条件时,视为非交互模式:
  • 无可用的活跃聊天会话接收回复
  • 在CI任务、自动化工作流或定时脚本中运行
  • 启用
    autoApprove
    --yes
    或等效标志的Agent模式
  • Agent无法确定是否可发送回复
若存在不确定性,默认视为非交互模式。
规则: 如果任何规则要求用户确认,但Agent处于非交互环境中,则Agent必须:
  1. 输出将执行的具体命令、查询或SQL语句
  2. 说明该操作的作用以及需要确认的原因
  3. 不执行该操作
要求确认的规则不会因为Agent无法询问就变为可选,而是转为手动交接。

Global Clause — Never Disclose Secrets

全局条款——绝不泄露机密

Never print, paste, log, or include in a diff:
  • SUPABASE_ANON_KEY
  • SUPABASE_SERVICE_ROLE_KEY
    (or any
    service_role
    key)
  • JWTs or bearer tokens of any kind
  • Any value that begins with
    eyJ
    (base64-encoded JWT)
  • Any secret from
    .env
    ,
    .env.local
    , or equivalent files
If the agent needs to confirm a key is present: state "I can see a value is set for
SUPABASE_ANON_KEY
." If identity confirmation is needed, ask the user to confirm the last 4 characters — do not print them.
Showing
SUPABASE_URL
is permitted
— host portion only (e.g.,
https://xyz.supabase.co
). Do not include query strings or path segments that may carry tokens.
This rule applies even in local development.

绝打印、粘贴、记录或在差异对比中包含以下内容:
  • SUPABASE_ANON_KEY
  • SUPABASE_SERVICE_ROLE_KEY
    (或任何
    service_role
    密钥)
  • 任何类型的JWT或Bearer令牌
  • 任何以
    eyJ
    开头的值(Base64编码的JWT)
  • 来自
    .env
    .env.local
    或等效文件的任何机密信息
如果Agent需要确认密钥是否存在: 说明“我已确认
SUPABASE_ANON_KEY
已设置值。”若需要确认身份,请用户确认密钥的最后4位字符——不要打印完整密钥。
允许展示
SUPABASE_URL
——仅展示主机部分(例如
https://xyz.supabase.co
)。请勿包含可能携带令牌的查询字符串或路径段。
本规则即使在本地开发环境中也适用。

Rule A — Environment Classification Gate

规则A——环境分类校验

Before any write, migration, RLS change, or function deploy, the agent must classify the environment and surface evidence to the user. It must not proceed until the environment type is confirmed.
Classification levels:
  • local
    SUPABASE_URL
    is
    http://localhost:*
    , or
    supabase status
    shows local instance
  • staging
    — known non-production remote ref, explicitly confirmed by user
  • production
    — any
    *.supabase.co
    URL or unrecognised project ref
Evidence the agent must display before acting:
  • The value of
    SUPABASE_URL
    (host portion only — no keys)
  • Output of
    supabase status
    or
    supabase projects list
    showing the project ref
  • For production: the ref + any branch/context information available
Enforcement:
  • local
    — agent may proceed with non-destructive validation commands autonomously. Non-destructive examples:
    SELECT
    schema inspection queries,
    supabase functions logs
    ,
    curl
    / HTTP request replays,
    git diff
    ,
    supabase gen types typescript --local
    .
  • staging
    — agent must state the environment and confirm intent before writing
  • production
    — agent must surface the full command for user review and require explicit "yes, proceed" before executing anything that writes or modifies schema
  • If environment cannot be determined — treat as production; do not execute
No Environment Assumptions (see also Rule G): The agent must never infer environment type from file presence alone — the existence of
.env
,
supabase/config.toml
, or a
supabase/
directory does not confirm the environment is local. Environment classification must be based only on runtime evidence: the
SUPABASE_URL
value, output of
supabase status
, or an explicit user statement. Rule G extends this constraint to all tasks, including read-only inspection — not only pre-action gates.

在执行任何写入、迁移、RLS更改或函数部署操作前,Agent必须对环境进行分类,并向用户展示相关证据。在环境类型得到确认前,不得继续执行操作。
分类级别:
  • local
    ——
    SUPABASE_URL
    http://localhost:*
    ,或
    supabase status
    显示为本地实例
  • staging
    ——已知的非生产环境远程引用,且已得到用户明确确认
  • production
    ——任何
    *.supabase.co
    格式的URL,或无法识别的项目引用
Agent在执行操作前必须展示的证据:
  • SUPABASE_URL
    的值(仅主机部分——不含密钥)
  • supabase status
    supabase projects list
    的输出,展示项目引用
  • 生产环境:项目引用以及可用的分支/上下文信息
执行规则:
  • local
    ——Agent可自主执行非破坏性验证命令。非破坏性示例:
    SELECT
    架构查询、
    supabase functions logs
    curl
    /HTTP请求重放、
    git diff
    supabase gen types typescript --local
  • staging
    ——Agent必须说明环境类型,并在执行写入操作前确认用户意图
  • production
    ——Agent必须展示完整命令供用户审核,并在执行任何写入或修改架构的操作前,要求用户明确回复“yes, proceed”
  • 若无法确定环境类型——视为生产环境,不执行操作
不得假设环境(另见规则G): Agent不得仅根据文件存在情况推断环境类型——
.env
supabase/config.toml
supabase/
目录的存在,不能确认环境为本地。环境分类必须仅基于运行时证据:
SUPABASE_URL
的值、
supabase status
的输出,或用户的明确说明。规则G将此约束扩展至所有任务,包括只读检查——不仅是操作前的校验。

Rule B — No Silent Writes

规则B——禁止静默写入

An agent must never perform a write operation and report completion without returning observable evidence that the write succeeded.
Required evidence by operation type:
OperationRequired evidence
INSERT
Returned row with
id
from
.insert().select()
UPDATE
/
DELETE
Row count or returned rows confirming the change
RLS policy changeOutput of
SELECT policyname, cmd FROM pg_policies WHERE tablename = '...'
Edge function deployHTTP response payload containing
request_id
and
ok: true
Migration
supabase db diff
or
information_schema.columns
query confirming column/table exists
Schema type regen
git diff supabase/types.gen.ts
output (even if empty — show it)
If the operation produces no returnable evidence (e.g.,
Prefer: return=minimal
), re-run the operation with
.select()
chained, or run a follow-up read query.
Surface the raw output. Do not summarise before showing it. Return the actual payload — row object, JSON body, query result, diff — so the user can verify directly. You may summarise after showing raw output.
// Bad
"Insert successful."

// Good
{ id: 42, created_at: "2026-02-28T20:14:22Z" }
// (then) "Insert confirmed — row id 42 returned."

Agent执行写入操作后,若未返回可观察的成功证据,不得报告任务完成。
各操作类型所需的证据:
操作所需证据
INSERT
返回包含
id
的行(通过
.insert().select()
获取)
UPDATE
/
DELETE
确认更改的行数或返回的行
RLS策略更改
SELECT policyname, cmd FROM pg_policies WHERE tablename = '...'
的输出
Edge Function部署包含
request_id
ok: true
的HTTP响应体
迁移
supabase db diff
information_schema.columns
查询结果,确认列/表已存在
Schema类型重新生成
git diff supabase/types.gen.ts
的输出(即使为空,也需展示)
如果操作无法返回可验证的证据(例如使用
Prefer: return=minimal
),则需重新执行操作并链式调用
.select()
,或运行后续的读取查询。
展示原始输出,不得先总结。 返回实际的响应内容——行对象、JSON体、查询结果、差异对比——以便用户直接验证。可在展示原始输出后再进行总结。
// 错误示例
"插入成功。"

// 正确示例
{ id: 42, created_at: "2026-02-28T20:14:22Z" }
// (随后) "插入已确认——返回行id为42。"

Rule C —
service_role
Restricted Use

规则C——
service_role
的受限使用

service_role
bypasses all RLS policies. Its use must be explicitly bounded.
Permitted without user confirmation:
  • Read-only diagnostics only —
    SELECT
    queries to inspect schema, policies, or data for debugging purposes
Require explicit user confirmation before use:
  • Any write, insert, update, or delete using
    service_role
  • Any operation that modifies schema or policies using
    service_role
Confirmation protocol:
  1. State clearly: "This operation requires
    service_role
    which bypasses RLS."
  2. Display the environment classification (Rule A) as part of the request
  3. Show the exact command or query that will be run
  4. Wait for explicit "yes" — do not infer consent from prior approval of a related step
  5. If non-interactive: output the command for manual review, do not execute

service_role
会绕过所有RLS策略。其使用必须受到明确限制。
无需用户确认即可使用的场景:
  • 仅用于只读诊断——
    SELECT
    查询,用于检查架构、策略或数据以进行调试
使用前需获得用户明确确认的场景:
  • 使用
    service_role
    执行的任何写入、插入、更新或删除操作
  • 使用
    service_role
    修改架构或策略的任何操作
确认流程:
  1. 明确说明:“此操作需要使用
    service_role
    ,它会绕过RLS策略。”
  2. 将环境分类结果(规则A)作为请求的一部分展示
  3. 展示将执行的具体命令或查询
  4. 等待用户明确回复“yes”——不得从用户对相关步骤的先前批准中推断同意
  5. 若处于非交互模式:输出命令供手动审核,不执行操作

Rule D — Safe Fallback When Tooling Is Unavailable

规则D——工具不可用时的安全回退

The agent must not hallucinate access it doesn't have.
If a required tool is unavailable:
  1. State the missing capability explicitly
  2. Propose a non-destructive alternative:
    • Instead of CLI logs → capture
      error.code
      ,
      error.message
      ,
      error.hint
      from the client SDK response
    • Instead of
      supabase status
      → ask user to run it and paste the output
    • Instead of DB introspection → provide the exact SQL for the user to run in the dashboard SQL editor
  3. Never invent log output, query results, or command output
  4. Never report a validation as passed unless the agent itself received and parsed the response
Prohibited:
  • "I checked the logs and there are no errors" without having received log output
  • "The migration ran successfully" without confirmed evidence
  • "The policy is in place" without
    pg_policies
    output showing it

Agent不得虚构自身不具备的访问权限。
若所需工具不可用:
  1. 明确说明缺失的功能
  2. 提出非破坏性的替代方案:
    • 无法使用CLI日志时 → 从客户端SDK响应中捕获
      error.code
      error.message
      error.hint
    • 无法使用
      supabase status
      时 → 请用户运行该命令并粘贴输出结果
    • 无法进行数据库自省 → 提供精确的SQL语句,让用户在控制台的SQL编辑器中运行
  3. 不得编造日志输出、查询结果或命令输出
  4. 除非Agent自身已接收并解析响应,否则不得报告验证通过
禁止行为:
  • 未接收日志输出就声称“我检查了日志,无错误”
  • 无确认证据就声称“迁移已成功运行”
  • pg_policies
    输出就声称“策略已生效”

Rule E — Minimal File Mutations

规则E——最小化文件变更

Required behaviour:
  • Prefer the smallest diff that achieves the fix
  • Before applying any file change, show a diff or describe line-level changes
  • Never use a "replace entire file" pattern unless the user explicitly requests it
  • For Supabase-specific files (
    supabase/functions/**
    ,
    supabase/migrations/**
    ,
    supabase/types.gen.ts
    ): treat all changes as high-sensitivity and show the diff before applying
Why Supabase files are high-sensitivity:
  • Overwriting a migration file that has already run creates drift — it does not undo the migration
  • Overwriting
    types.gen.ts
    with stale content breaks TypeScript without a compile error
  • Overwriting an edge function's
    index.ts
    with an earlier version silently reverts a fix
Permitted without confirmation: adding new files where no existing file is displaced. Requires confirmation: modifying or deleting any existing file under
supabase/
.

必须遵守的行为:
  • 优先采用能修复问题的最小差异更改
  • 在应用任何文件更改前,展示差异内容或描述行级别的更改
  • 除非用户明确要求,否则不得使用“替换整个文件”的方式
  • 对于Supabase特定文件(
    supabase/functions/**
    supabase/migrations/**
    supabase/types.gen.ts
    ):所有更改均视为高敏感度操作,应用前需展示差异内容
为何Supabase文件属于高敏感度:
  • 覆盖已执行的迁移文件会导致数据漂移——无法撤销已执行的迁移
  • 用过期内容覆盖
    types.gen.ts
    会在无编译错误的情况下破坏TypeScript代码
  • 用旧版本覆盖Edge Function的
    index.ts
    会静默回滚修复内容
无需确认即可执行的操作: 添加新文件,且不替换现有文件。 需要确认的操作: 修改或删除
supabase/
目录下的任何现有文件。

Rule G — No Hidden Context Assumption

规则G——禁止假设隐藏上下文

The agent must not infer Supabase project configuration from local file presence alone. The existence of
.env
,
supabase/config.toml
, or a
supabase/
directory does not confirm which project is active, whether it is local or remote, or whether the configuration applies to the current task.
Environment classification must be based only on runtime evidence:
  • The resolved value of
    SUPABASE_URL
    (from the active shell environment — not a
    .env
    file the agent reads in isolation)
  • Output of
    supabase status
    or
    supabase projects list
  • An explicit user statement (e.g., "I'm working against our staging project")
What this prevents:
  • A skill applied inside a monorepo where a
    supabase/
    folder exists but belongs to a different sub-project
  • An agent assuming
    local
    because it sees
    http://localhost
    in a
    .env
    file that may be stale or inactive
  • Hallucinated project context: "this looks like a local project" based on file presence alone
Required agent phrasing: "I can see a
supabase/
directory and a
.env
file. To classify the environment I need to confirm the active
SUPABASE_URL
. Running
supabase status
…" — not "This looks like a local project."
Relationship to Rule A: Rule G governs what the agent may assume at any point, including read-only tasks. Rule A governs what the agent must confirm before acting. Rule G is the precondition; Rule A is the gate.

Agent不得仅根据本地文件存在情况推断Supabase项目配置。
.env
supabase/config.toml
supabase/
目录的存在,无法确认当前激活的项目、环境是本地还是远程,也无法确认配置是否适用于当前任务。
环境分类必须仅基于运行时证据:
  • SUPABASE_URL
    的解析值(来自活跃的Shell环境——而非Agent单独读取的
    .env
    文件)
  • supabase status
    supabase projects list
    的输出
  • 用户的明确说明(例如“我正在处理我们的预发布项目”)
此规则可避免的问题:
  • 在单体仓库中应用技能时,
    supabase/
    文件夹属于其他子项目
  • Agent因在
    .env
    文件中看到
    http://localhost
    就假设是本地环境,但该文件可能已过期或未激活
  • 基于文件存在情况就虚构项目上下文:“这看起来是一个本地项目”
Agent必须使用的表述: “我已检测到
supabase/
目录和
.env
文件。为了分类环境,我需要确认当前激活的
SUPABASE_URL
。正在运行
supabase status
……”——而非“这看起来是一个本地项目。”
与规则A的关系: 规则G管控Agent在任何时候可假设的内容,包括只读任务。规则A管控Agent在执行操作前必须确认的内容。规则G是前提条件,规则A是执行门槛。

Activation Rule — When This Skill Applies

激活规则——本技能的适用场景

This skill MUST activate automatically whenever any of the following signals appear in code, config, or commands:
  • supabase-js
    is imported or used
  • supabase.rpc()
    is called
  • .from(...).insert()
    ,
    .update()
    , or
    .delete()
    is used
  • CREATE FUNCTION
    ,
    CREATE POLICY
    , or
    ALTER TABLE
    appears in SQL
  • supabase functions deploy
    is run
  • supabase gen types
    is relevant to the task
  • Any migration touches schema or RLS
  • Any file under
    supabase/functions/
    is modified
  • Any file under
    supabase/migrations/
    or
    supabase/seed.sql
    is modified
  • Any
    supabase db *
    command is run (push/reset/diff)
When activated:
  • Add a validation step to the task plan before execution begins
  • Execute that validation step before reporting completion
  • Do not ask the user whether to validate — validate automatically
  • If execution is not possible, state that explicitly and provide the exact commands for the user to run

当代码、配置或命令中出现以下任一信号时,本技能必须自动激活:
  • 导入或使用
    supabase-js
  • 调用
    supabase.rpc()
  • 使用
    .from(...).insert()
    .update()
    .delete()
  • SQL中出现
    CREATE FUNCTION
    CREATE POLICY
    ALTER TABLE
  • 执行
    supabase functions deploy
    命令
  • supabase gen types
    与当前任务相关
  • 任何迁移操作涉及Schema或RLS
  • 修改
    supabase/functions/
    目录下的任何文件
  • 修改
    supabase/migrations/
    supabase/seed.sql
    目录下的任何文件
  • 执行任何
    supabase db *
    命令(push/reset/diff)
激活后的行为:
  • 在任务计划中添加验证步骤,再执行操作
  • 在报告完成前执行该验证步骤
  • 无需询问用户是否验证——自动执行验证
  • 若无法执行操作,需明确说明并提供用户可运行的具体命令

Validation Contract

验证契约

A Supabase task is not complete when code compiles or a command exits 0. It is complete only when the validation step passes.
Definition of done:
  1. Failure or baseline confirmed (run the current behaviour first)
  2. Fix applied
  3. Validation executed
  4. Validation produces a binary pass result
Required plan shape:
  1. Run current behaviour — confirm failure if fixing, baseline if building
  2. Diagnose — read the actual error (code, message, hint)
  3. Apply minimal fix
  4. Verify — binary pass/fail, not eyeballing
  5. Report completion
Hard gates — none of these are optional:
  • "Looks correct" is not a valid success signal
  • "Exit code 0" alone is not a valid success signal
  • Never skip verification because the code looks right — run the check
  • If a verify step fails, diagnose before retrying — do not loop without reading the error

Supabase任务的完成标准并非代码编译成功或命令退出码为0。只有当验证步骤通过时,任务才算完成。
完成定义:
  1. 确认失败或基准(先运行当前行为)
  2. 应用修复
  3. 执行验证
  4. 验证产生明确的通过/失败结果
必须遵循的计划流程:
  1. 运行当前行为——修复场景下确认失败,构建场景下确认基准
  2. 诊断——读取实际错误(错误码、消息、提示)
  3. 应用最小化修复
  4. 验证——明确的通过/失败,而非主观判断
  5. 报告完成
硬性要求——以下均为必选项:
  • “看起来正确”不是有效的成功信号
  • “退出码0”单独不能作为有效的成功信号
  • 绝不能因为代码看起来正确就跳过验证——必须运行检查
  • 若验证步骤失败,需先诊断再重试——不得在未读取错误的情况下循环重试

Pattern Index

模式索引

PatternTriggerPasses when
1 — Edge function (local)Change to a function running via
supabase functions serve
HTTP 200 +
body.ok === true
+
request_id
present
2 — Edge function (production)
supabase functions deploy <name>
to a real project
HTTP 200 +
body.ok === true
+
request_id
present
3 — RPC
CREATE OR REPLACE FUNCTION
or migration modifying an RPC
No error + response contains expected fields
4 — CRUD / InsertAny
.insert()
,
.update()
,
.delete()
via supabase-js
Non-null array with
id
present
5 — RLS
CREATE POLICY
,
DROP POLICY
,
ENABLE ROW LEVEL SECURITY
All 3 roles pass: unauthed blocked + authed allowed + service_role allowed
6 — Schema migrationMigration adding, removing, or renaming a column
types.gen.ts
reflects live schema + file committed

模式触发条件验证通过条件
1 — Edge Function(本地)修改通过
supabase functions serve
运行的函数
HTTP 200 +
body.ok === true
+ 存在
request_id
2 — Edge Function(生产)向真实项目执行
supabase functions deploy <name>
HTTP 200 +
body.ok === true
+ 存在
request_id
3 — RPC
CREATE OR REPLACE FUNCTION
或修改RPC的迁移
无错误 + 响应包含预期字段
4 — CRUD / 插入通过supabase-js执行的任何插入、更新或删除操作返回非空数组且包含带
id
的行
5 — RLS
CREATE POLICY
DROP POLICY
ALTER TABLE ... ENABLE ROW LEVEL SECURITY
或涉及RLS的迁移
三种角色验证均通过:未认证用户被拦截 + 已认证用户被允许 + service_role被允许
6 — Schema迁移添加、删除或重命名列的迁移
types.gen.ts
反映当前Schema + 文件已提交

Pattern 1 — Edge Function (Local)

模式1——Edge Function(本地)

Trigger: after any change to a Supabase edge function running locally via
supabase functions serve
.
Validation steps:
  1. POST to
    http://localhost:54321/functions/v1/<name>
  2. Assert HTTP 200
  3. Assert response body is valid JSON with
    ok: true
  4. Assert
    request_id
    is present in the response body
Fail signal: HTTP 500, empty body, no
request_id
, or
Deno.env.get(...)
returning
undefined
.
Diagnostic: errors stream to the
supabase functions serve
terminal — read them directly. There is no
supabase functions logs
command for local dev.
Docs:
Do not report done until: HTTP 200 +
ok: true
+
request_id
confirmed.

触发条件: 修改通过
supabase functions serve
在本地运行的Edge Function后。
验证步骤:
  1. http://localhost:54321/functions/v1/<name>
    发送POST请求
  2. 断言HTTP状态码为200
  3. 断言响应体为有效的JSON且包含
    ok: true
  4. 断言响应体中存在
    request_id
失败信号: HTTP 500、空响应体、无
request_id
,或
Deno.env.get(...)
返回
undefined
诊断方式: 错误会输出到
supabase functions serve
的终端——直接读取这些错误。本地开发环境无
supabase functions logs
命令。
文档:
在满足以下条件前,不得报告完成: 确认HTTP 200 +
ok: true
+
request_id
存在。

Pattern 2 — Edge Function (Production)

模式2——Edge Function(生产)

Trigger: after
supabase functions deploy <name>
to a real Supabase project.
Validation steps:
  1. POST to
    $SUPABASE_URL/functions/v1/<name>
    with
    Authorization: Bearer $SUPABASE_ANON_KEY
    (do not print the key value)
  2. Assert HTTP 200
  3. Assert response body is valid JSON with
    ok: true
  4. Assert
    request_id
    is present in the response body
Fail signal: HTTP 500 or unstructured body.
Diagnostic: dashboard function logs:
https://supabase.com/dashboard/project/<PROJECT_REF>/functions/<name>/logs
Docs:
Do not report done until: HTTP 200 +
ok: true
+
request_id
confirmed against the production URL.

触发条件: 向真实Supabase项目执行
supabase functions deploy <name>
后。
验证步骤:
  1. $SUPABASE_URL/functions/v1/<name>
    发送POST请求,携带
    Authorization: Bearer $SUPABASE_ANON_KEY
    (不要打印密钥值)
  2. 断言HTTP状态码为200
  3. 断言响应体为有效的JSON且包含
    ok: true
  4. 断言响应体中存在
    request_id
失败信号: HTTP 500或非结构化响应体。
诊断方式: 控制台函数日志:
https://supabase.com/dashboard/project/<PROJECT_REF>/functions/<name>/logs
文档:
在满足以下条件前,不得报告完成: 针对生产URL确认HTTP 200 +
ok: true
+
request_id
存在。

Pattern 3 — RPC

模式3——RPC

Trigger: after any
CREATE OR REPLACE FUNCTION
or migration that modifies an RPC.
Validation steps:
  1. Call via supabase-js:
    supabase.rpc('<function_name>', { ...args })
  2. Assert
    error
    is null
  3. Assert response data contains the expected fields
Fail signal:
error.code
is present — read
error.code
,
error.message
,
error.hint
as a unit.
Diagnostic: if error code is
42703
(undefined column), run:
sql
SELECT pg_get_functiondef('<schema>.<function_name>(<arg_types>)'::regprocedure);
Docs:
Do not report done until: RPC returns no error + response shape is correct.

触发条件: 执行任何
CREATE OR REPLACE FUNCTION
或修改RPC的迁移后。
验证步骤:
  1. 通过supabase-js调用:
    supabase.rpc('<function_name>', { ...args })
  2. 断言
    error
    为null
  3. 断言响应数据包含预期字段
失败信号: 存在
error.code
——需完整读取
error.code
error.message
error.hint
诊断方式: 若错误码为
42703
(未定义列),执行:
sql
SELECT pg_get_functiondef('<schema>.<function_name>(<arg_types>)'::regprocedure);
文档:
在满足以下条件前,不得报告完成: RPC调用无错误 + 响应结构正确。

Pattern 4 — CRUD / Insert

模式4——CRUD / 插入

Trigger: after any insert, update, or delete via supabase-js.
Validation steps:
  1. Always chain
    .select().throwOnError()
    onto the operation
  2. Assert returned
    data
    is a non-null array
  3. Assert the array contains a row with
    id
Why this matters:
.insert()
without
.select()
sends
Prefer: return=minimal
— PostgREST returns 204 with empty body. supabase-js translates this to
{ data: null, error: null }
. This is not confirmation the row was saved.
Correct pattern:
ts
const { data } = await supabase
  .from("table")
  .insert({ ...values })
  .select()
  .throwOnError();
// data is a non-null array if the insert succeeded
Docs:
Do not report done until: insert returns a non-null array containing a row with
id
.

触发条件: 通过supabase-js执行任何插入、更新或删除操作后。
验证步骤:
  1. 必须在操作后链式调用
    .select().throwOnError()
  2. 断言返回的
    data
    为非空数组
  3. 断言数组中包含带
    id
    的行
为何这很重要: 不带
.select()
.insert()
会发送
Prefer: return=minimal
——PostgREST会返回204状态码和空响应体。supabase-js会将其转换为
{ data: null, error: null }
,这无法确认行已保存。
正确模式:
ts
const { data } = await supabase
  .from("table")
  .insert({ ...values })
  .select()
  .throwOnError();
// 插入成功时,data为非空数组
文档:
在满足以下条件前,不得报告完成: 插入操作返回包含带
id
行的非空数组。

Pattern 5 — RLS

模式5——RLS

Trigger: after any
CREATE POLICY
,
DROP POLICY
,
ALTER TABLE ... ENABLE ROW LEVEL SECURITY
, or migration touching RLS.
Validation steps — all three must pass:
  1. Unauthenticated anon — attempt the restricted operation with a plain anon key and no auth session → assert blocked (error
    42501
    )
  2. Authenticated user — same operation with anon key + valid JWT → assert allowed
  3. service_role — same operation with service_role key → assert allowed (service_role always bypasses RLS)
Diagnostic commands:
sql
-- See all policies on a table
SELECT policyname, cmd, qual, with_check
FROM pg_policies WHERE tablename = '<table>';

-- Confirm RLS is enabled
SELECT relname, relrowsecurity FROM pg_class WHERE relname = '<table>';
Key insight: if something works from the Supabase dashboard but fails in the app, check whether an INSERT policy exists for the role your app uses.
service_role
has
BYPASSRLS
— it skips policy evaluation entirely.
Docs:
Do not report done until: all three scenarios produce the expected result.

触发条件: 执行任何
CREATE POLICY
DROP POLICY
ALTER TABLE ... ENABLE ROW LEVEL SECURITY
或涉及RLS的迁移后。
验证步骤——必须全部通过:
  1. 未认证匿名用户——使用普通anon密钥且无认证会话尝试受限操作 → 断言被拦截(错误码
    42501
  2. 已认证用户——使用anon密钥+有效JWT执行相同操作 → 断言被允许
  3. service_role——使用service_role密钥执行相同操作 → 断言被允许(service_role始终绕过RLS)
诊断命令:
sql
-- 查看表的所有策略
SELECT policyname, cmd, qual, with_check
FROM pg_policies WHERE tablename = '<table>';

-- 确认RLS已启用
SELECT relname, relrowsecurity FROM pg_class WHERE relname = '<table>';
关键提示: 如果在Supabase控制台中操作正常,但应用中失败,请检查应用使用的角色是否有对应的INSERT策略。
service_role
拥有
BYPASSRLS
权限——会完全跳过策略评估。
文档:
在满足以下条件前,不得报告完成: 三种场景均产生预期结果。

Pattern 6 — Schema Migration / Type Drift

模式6——Schema迁移 / 类型漂移

Trigger: after any migration that adds, removes, or renames a column.
Validation steps:
  1. Run:
    supabase gen types typescript --local > supabase/types.gen.ts
  2. Run:
    git diff supabase/types.gen.ts
  3. If diff is non-empty → expected (new column). Commit the updated file.
  4. If diff is empty and you added a column → migration may not have run — check.
Drift detection:
sql
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = '<table>'
ORDER BY ordinal_position;
Why this matters: TypeScript compiles cleanly against stale types. A column that exists in the DB but not in
types.gen.ts
is simply invisible to your code — no compile error, silent bugs.
CI: run
supabase gen types typescript --local > supabase/types.gen.ts && git diff --exit-code supabase/types.gen.ts
after any migration deploy. Fail the build if the diff is non-empty.
Docs:
Do not report done until:
types.gen.ts
reflects the current live schema and the file is committed.
触发条件: 执行任何添加、删除或重命名列的迁移后。
验证步骤:
  1. 执行:
    supabase gen types typescript --local > supabase/types.gen.ts
  2. 执行:
    git diff supabase/types.gen.ts
  3. 若差异非空 → 符合预期(新增列)。提交更新后的文件。
  4. 若差异为空但已添加列 → 迁移可能未运行——需检查。
漂移检测:
sql
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = '<table>'
ORDER BY ordinal_position;
为何这很重要: TypeScript会基于过期类型正常编译。数据库中存在但
types.gen.ts
中不存在的列,会在无编译错误的情况下导致代码出现静默错误。
CI流程: 迁移部署后执行
supabase gen types typescript --local > supabase/types.gen.ts && git diff --exit-code supabase/types.gen.ts
。若差异非空,构建失败。
文档:
在满足以下条件前,不得报告完成:
types.gen.ts
反映当前实时Schema且文件已提交。