Agent skill
supabase-skill
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/devops/supabase-skill
SKILL.md
Supabase Skill for Agritech Project
Core Principle
ALWAYS consolidate all database changes in project/supabase/migrations/00000000000000_schema.sql
This is a single-file migration approach where all schema changes (tables, functions, triggers, RLS policies, etc.) are maintained in one comprehensive migration file.
Project Structure
project/
├── supabase/
│ └── migrations/
│ └── 00000000000000_schema.sql # Single consolidated schema file
└── src/
└── ... (React frontend)
Migration Strategy
Single File Approach
- All database schema changes go into
00000000000000_schema.sql - This file contains the complete, idempotent database schema
- All CREATE statements use
IF NOT EXISTS,OR REPLACE, orDO $$ BEGIN ... EXCEPTION ... END $$patterns - The file is self-contained and can be run multiple times safely
Idempotency Requirements
- Tables: Use
CREATE TABLE IF NOT EXISTS - Functions: Use
CREATE OR REPLACE FUNCTION - Types/ENUMs: Use
DO $$ BEGIN ... EXCEPTION WHEN duplicate_object THEN null; END $$ - Indexes: Use
CREATE INDEX IF NOT EXISTS - Triggers: Use
DROP TRIGGER IF EXISTSbeforeCREATE TRIGGER - Policies: Use
DROP POLICY IF EXISTSbeforeCREATE POLICY
Schema Organization
The schema file is organized into sections:
- Extensions - PostGIS, UUID generation
- Helper Functions - Utility functions like
update_updated_at_column() - ENUM Types - All custom types (quote_status, invoice_status, etc.)
- Core Tables - Organizations, users, profiles
- Farm Management - Farms, parcels
- Billing Cycle - Quotes, sales orders, purchase orders
- Accounting - Accounts, journal entries, invoices, payments
- Workers & Tasks - Workers, tasks, work units
- Harvest & Delivery - Harvest records, deliveries
- Inventory & Stock - Items, warehouses, stock entries
- Satellite Data - Satellite indices, processing jobs
- Analyses & Reports - Soil analyses, reports
- RLS Policies - Row Level Security policies
- Triggers - Database triggers
- Data Seeding - Initial data setup
RLS (Row Level Security) Patterns
Helper Function
All RLS policies use the is_organization_member() helper function:
CREATE OR REPLACE FUNCTION is_organization_member(p_organization_id UUID)
RETURNS BOOLEAN
LANGUAGE sql
SECURITY DEFINER
STABLE
SET search_path = public
AS $$
SELECT EXISTS (
SELECT 1
FROM public.organization_users
WHERE user_id = auth.uid()
AND organization_id = p_organization_id
AND is_active = true
);
$$;
Policy Naming Convention
- Read:
org_read_{table_name} - Write/Insert:
org_write_{table_name} - Update:
org_update_{table_name} - Delete:
org_delete_{table_name} - All operations:
org_access_{table_name}(for child tables)
Policy Pattern
DROP POLICY IF EXISTS "org_read_{table}" ON {table};
CREATE POLICY "org_read_{table}" ON {table}
FOR SELECT USING (
is_organization_member(organization_id)
);
Common Patterns
Organization-Scoped Tables
All main tables include organization_id and RLS policies:
CREATE TABLE IF NOT EXISTS {table_name} (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
-- other columns
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
Updated_at Triggers
For tables with updated_at columns:
DROP TRIGGER IF EXISTS trg_{table}_updated_at ON {table};
CREATE TRIGGER trg_{table}_updated_at
BEFORE UPDATE ON {table}
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
Number Generation Functions
Use helper functions for generating sequential numbers:
generate_quote_number(p_organization_id UUID)generate_sales_order_number(p_organization_id UUID)generate_invoice_number(p_organization_id UUID, p_invoice_type invoice_type)
When Making Changes
Adding a New Table
- Add table definition in appropriate section
- Add indexes
- Enable RLS:
ALTER TABLE IF EXISTS {table} ENABLE ROW LEVEL SECURITY; - Add RLS policies (read, write, update, delete)
- Add
updated_attrigger if needed - Add to appropriate section comment
Modifying Existing Table
- Use
ALTER TABLE IF EXISTSfor schema changes - Ensure idempotency (check if column/index exists first)
- Update related RLS policies if needed
- Update triggers if needed
Adding Functions
- Use
CREATE OR REPLACE FUNCTION - Add
SECURITY DEFINERif it needs to bypass RLS - Set
SET search_path = publicfor security - Add
GRANT EXECUTEstatements - Add comments with
COMMENT ON FUNCTION
Adding RLS Policies
- Always
DROP POLICY IF EXISTSfirst - Use consistent naming:
org_{operation}_{table} - Use
is_organization_member()for organization-scoped tables - For child tables, check parent table membership
Data Seeding
Initial data setup is done in the same file:
- Default currencies
- Default roles
- User profile synchronization
- Organization setup
- Subscription setup
Use DO $$ ... END $$ blocks for conditional seeding.
Testing Changes
Before committing:
- Verify idempotency - run migration twice, should succeed both times
- Check RLS policies - ensure users can only access their organization's data
- Verify foreign keys - ensure all references are valid
- Test triggers - ensure they fire correctly
Important Notes
- Never create separate migration files - always update
00000000000000_schema.sql - Always use idempotent statements - migrations should be safe to run multiple times
- RLS is enabled on all tables - ensure policies are created for every table
- Use SECURITY DEFINER carefully - only for functions that need to bypass RLS
- Maintain section organization - keep related items together
- Add comments - document complex logic and important decisions
Common Commands
Apply Migration
cd project
npm run db:migrate
Generate TypeScript Types
npm run db:generate-types
Reset Database (Local)
npm run db:reset
File Location
All schema changes must be made in:
project/supabase/migrations/00000000000000_schema.sql
Remember: This is the single source of truth for the database schema.
Didn't find tool you were looking for?