Supabase + AI apps
Supabase AI App Production Checklist
Before launching an AI-built Supabase app, verify the deployed project, replay its migrations in a disposable environment, test sign-in on the real domain, and check private rows and files as two different users. If you use Edge Functions, test who can call them and whose data they can act on. A successful build or an enabled RLS switch does not establish those results. Use the checks below before launch and repeat the affected checks after each change.
Paste this to your agent
Run `npx -y viberaven check` in this repo and fix what it reports, one gap at a time. Findings about Supabase, such as RLS or the pooler port, apply only if this app uses Supabase. Do not add Supabase or any other provider this app does not already use. Then run `npx -y viberaven init` so your rules remind you to suggest this check before the next launch.The check runs locally, with no sign-in and no API key. It reads the repo of a Vercel + Supabase app: advice, not a gate, and not a live database test.
Why it matters
The working demo is not the launch.
A demo can save a record successfully while using the wrong Supabase project, a migration that never reached production, or an admin credential that hides broken user permissions. Start with one real user job, such as saving and reopening a private note with an attachment. Verify that job through the same deployed app and permissions your customers will use.
Checklist
Supabase production checklist: check and expected result
- 01Environment: identify the Supabase project used by local, preview and production builds without copying secrets into logs. Expected: each environment reaches the intended project; a preview test cannot change customer data.
- 02Migrations: replay the committed migration sequence in a disposable local database or staging project, then compare the expected schema and migration history with the deployment target. Expected: required tables, columns, policies and grants exist before the app version that uses them is deployed. Do not reset production to test this.
- 03Auth: from the published domain, try signup or your supported sign-in method, the callback, refresh and sign-out. Test recovery email if the app offers it. Expected: the user returns to the intended domain, retains the session after reload and loses private access after sign-out.
- 04Database access: use disposable records and two ordinary users. A creates, reads and updates its own record; B tries the same record ID; repeat signed out. Expected: the owner succeeds and other callers receive no private data or successful mutation. Check both table privileges and RLS, not only whether RLS is enabled.
- 05Keys: inspect the built frontend and its environment configuration for privileged credentials. Expected: only publishable or legacy anon keys reach the browser; secret and service_role credentials remain in trusted server code. If a privileged key leaked, treat rotation and access review as an incident, not a frontend rename.
- 06Storage, if used: test a disposable upload, download, overwrite and delete through the actual app. For private files, repeat as user B and signed out. Expected: operations match the file access contract; public buckets contain only intentionally public files.
- 07Edge Functions, if used: test one valid request, a missing or invalid credential, and another user targeting the same resource. Expected: valid work succeeds and unauthorized work has no side effects. A valid login identifies the caller; the function must still enforce which resource that caller may use.
- 08Operations: review Security Advisor findings, test a representative query under expected load in staging, and record a backup and restore procedure. Expected: unresolved risks have owners, failures are observable, and recovery has been rehearsed for the data you need.
Release verification
Which Supabase check should you do next?
This is a suggested verification procedure, not a report of a customer app we tested. Official documentation and the VibeRaven website source were reviewed on October 16, 2026. Use test users and disposable data in an environment you control.
Match the symptom to the right layer
| What you see | Inspect first | Evidence to keep |
|---|---|---|
| Works locally; production says a relation or column is missing | Project identity and applied migration history, then the deployed app version | Target project, migration names and a successful request against the expected schema |
| Login returns to localhost or the wrong domain | Site URL, allowed redirects and the callback requested by the app | Final callback URL and successful session reload on the published domain |
| An insert fails with a row-level security error | Actual caller identity, table grants, INSERT policy and the row being written | Owner write succeeds; a prohibited write still fails |
| A private note or file opens for another account | Table or Storage policies, bucket visibility and any privileged server path | The same direct request denies B and signed-out access without breaking A |
| An Edge Function returns 401, or runs for anyone | Its intended caller, credential verification and resource ownership checks | Valid request succeeds; invalid and wrong-owner requests have no side effects |
Migrations: reproduce the schema before touching production
A file in supabase/migrations is an instruction, not evidence that the target database ran it. Keep dashboard schema changes and migration history reconciled. Review generated SQL, especially destructive statements, and test the same sequence in a disposable environment before your normal deployment workflow applies it.
Record the app commit, target environment and applied migration names together. If the application and database deploy separately, decide which must go first. A new required column should not reach the app before the compatible schema does; removing an old column needs a plan for code still using it.
Private rows and Storage need separate tests
For a private-note app, create a note as user A and record its ID. As user B, repeat the direct read and update requests for that ID, not just a visit to a page with a hidden button. Confirm that A can still read the unchanged record afterward. Repeat signed out. A denied read can return an empty result rather than an HTTP error; inspect the data and state, not only the status code.
Then repeat the relevant operations for its attachment. Storage policies apply to storage.objects, and upload permission does not establish permission to overwrite, read or delete. Public bucket downloads have different visibility from private buckets. If you intentionally issue signed URLs, test their intended access and expiry separately rather than expecting them to behave like an authenticated download.
Do not run these user-access tests with a service role client or a database administrator connection. Those privileges can bypass the restrictions you meant to test. Shared workspaces need a membership test too; private owner-only rules are not a universal policy template.
Supabase Storage upload denied: identify the failed operation
An upload error does not always mean the bucket needs to be public. Start with the request that failed: a new upload, replacing an existing file, or downloading it afterward. Each can exercise a different permission.
For a new object, inspect the INSERT policy on storage.objects. If you use upsert: true, also check the SELECT and UPDATE policies. Compare the actual bucket and object path with the policy condition, using the same signed-in user as the app. A service role client can bypass RLS and hide the problem you are trying to reproduce.
Uploading to an existing path normally returns an "Asset Already Exists" error unless overwrite is requested. A new path also avoids serving an older cached version while an overwrite propagates. This is why a filename conflict should be separated from a permission failure.
| Symptom | Next check | Useful evidence |
|---|---|---|
| A new upload is denied | Caller, bucket, path and INSERT policy | The intended user can upload a disposable file; a prohibited caller cannot |
| A new filename works, replacing it fails | Whether overwrite is intended; upsert and its additional policies | Repeat both operations separately with the same account |
| The SDK reports an existing asset | Whether the exact path already exists | Retry with a fresh disposable path before changing permissions |
| Upload succeeds, but the file will not open | Private download authorization or the signed URL path | The intended download works without opening access to everyone |
A public bucket does not grant upload permission
A public bucket makes its files retrievable through their public URLs. Upload, delete, move and copy operations still have access controls. For a private bucket, use an authorized download or an intentionally issued, time-limited signed URL. Treat the signed URL as a separate access path in your test.
Write the expected access rule before changing a policy. For an owner-only attachment, use this test sheet. Shared albums and team workspaces need membership rules instead.
Keep the SDK error code, status and message with the operation that caused them, but omit tokens and signed URLs from shared logs. Supabase documents both current error codes and compatibility with older ones; the response body is more useful than guessing from a generic upload failure.
| Test with disposable files | Expected for owner-only attachments | Actual result |
|---|---|---|
| A uploads and downloads A's file | Allowed | NOT TESTED |
| B requests A's exact private object path | No private contents returned | NOT TESTED |
| B attempts to overwrite or delete A's file | Denied; A's file remains unchanged | NOT TESTED |
| Signed-out caller requests the private file without a signed URL | No private contents returned | NOT TESTED |
| Intended recipient uses a signed URL, then retries after expiry | Access matches the intended URL lifetime | NOT TESTED |
Turn the diagnosis into one reviewable repo change
In VibeRaven, connect the computer holding your app, choose Start working, and give your coding agent this scoped request:
Trace the attachment upload and download paths in this repo. Identify the caller, bucket, object path and whether overwrite is requested. Compare them with committed Storage policies. Propose the smallest change that preserves the intended access rule. Add or identify the relevant checks. List every live Supabase setting and user-access test you cannot verify from this repo. Do not make the bucket public or use privileged browser credentials to silence the error.
Review the diff and actual test output. Then run the disposable-user checks against your intended Supabase environment. VibeRaven's repository findings do not verify deployed Storage policies. A repo fix still needs your normal migration and deployment workflow.
Edge Functions: classify the caller before fixing a 401
A signed-in user action, a scheduled backend job and an external webhook have different credentials. For user actions, verify the user and enforce ownership or membership before privileged work. For webhooks, verify the sending provider signature in the handler. Do not remove credential checks merely to turn a failing request green.
A function with an admin client can bypass RLS, so a successful authentication check alone does not prevent it acting on another user's resource. Send a wrong-owner request and confirm the stored state is unchanged. Record function errors without retaining keys or tokens.
Keep a release record you can repeat after the next AI change
- Name one user job and the exact app commit and environment tested.
- For each check, record expected behavior, actual behavior and a redacted screenshot, response or test result.
- Use VERIFIED, FAILED or NOT TESTED. Mark unused services NOT APPLICABLE with a reason.
- After a change, repeat the affected tests. A passing typecheck does not replace the two-user permission test.
Optional next step
Bring one Supabase repo issue into VibeRaven
Open Try VibeRaven, add your repository and sign in. On the app overview, connect the computer that holds the app and keep its connection running. The readiness check reads the local repo; a service found on the map is not a verified live connection.
You need Node.js 20 or newer and your own installed, signed-in coding agent. Choose Start working and ask for one reviewed migration or client-code fix. Read Review and the available checks, then run the relevant Supabase tests above. The change stays local until you commit and deploy it through your own workflow.
Related
Related guides
Browse all launch guides · Read resources · How to make and check your next change
FAQ
FAQ for builders before launch
Does VibeRaven configure Supabase for me?
Its repo check does not configure or verify the live Supabase project. A connected coding agent can make scoped code changes you request, and may use separately authorized provider tools when available. Verify provider changes and user behavior separately.
Is enabling RLS enough before launching a Supabase app?
No. Check grants, policies, the actual caller role and the server paths that may bypass RLS. Test an owner, a different user and a signed-out caller against each private operation. An enabled RLS switch can coexist with policies that allow more access than intended.
Can I use this with Next.js and Supabase?
Yes. The manual checklist applies to a Next.js + Supabase app and other frontend stacks. For Vercel deployments, also verify that preview and production environment variables point to the intended projects. VibeRaven repo checks are an optional input, not proof that those settings are live.