backend-dev
Guidance and patterns for backend logic implementation in Supabase-backed applications.
Install
mkdir -p .claude/skills/backend-dev && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/4909" && unzip -o skill.zip -d .claude/skills/backend-dev && rm skill.zipInstalls to .claude/skills/backend-dev
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Coding practices for backend development in Atomic CRM. Use when deciding whether backend logic is needed, or when creating/modifying database migrations, views, triggers, RLS policies, edge functions, or custom dataProvider methods that call Supabase APIs.Key capabilities
- →Create database views for read optimization
- →Implement Supabase edge functions for complex mutations
- →Manage RLS policies and database triggers
- →Enforce security via custom dataProvider methods
- →Synchronize views with table schema changes
How it works
The skill enforces a convention of using Supabase-native features like views, triggers, and edge functions, prioritizing frontend-only logic where possible.
Inputs & outputs
When to use backend-dev
- →Create database views for performance
- →Deploy Supabase edge functions
- →Manage RLS policies in migrations
- →Implement complex multi-table writes
About this skill
Backend Development
Reference for backend conventions. There is no custom backend server all server-side logic uses Supabase: PostgreSQL (tables, views, triggers, RLS), Auth API, Storage, and Edge Functions. Read the relevant section before writing backend code, then check the Red Flags and Verification list.
When to Use
- Deciding whether a change needs backend logic at all (default: prefer the frontend).
- Creating or modifying database views, triggers, or RLS policies.
- Writing or changing a Supabase edge function, or a custom dataProvider method that calls Supabase.
For the SQL migration mechanics themselves, see Skill({skill: "writing-migrations"}).
For the frontend side of a dataProvider method, see Skill({skill: "frontend-dev"}).
Deciding where logic belongs
Prefer frontend-only solutions via custom dataProvider methods calling the PostgREST API.
When backend logic is needed:
- Aggregation/read optimization: Create a database view (
CREATE OR REPLACE VIEWin a new migration). PostgREST exposes views like tables. When underlying table columns change, update thecontacts_summaryandcompanies_summaryviews too. - Complex mutations (multi-table writes): Create a Supabase edge function in Deno. Stored procedures via RPC are less preferred (code lives in migrations, harder to maintain). On the frontend, expose the edge function as a custom dataProvider method (using
httpClient(${supabaseUrl}/functions/v1/<name>)) and call it via react-query. (e.g.salesCreate()→/functions/v1/users,mergeContacts()→/functions/v1/merge_contacts)
Edge function conventions
- Shared utils in
supabase/functions/_shared/— reuseauthentication.ts,supabaseAdmin.ts,cors.ts,utils.ts - Follow the middleware chain pattern: CORS preflight →
authenticate()→ handler verify_jwt = falsein config.toml, so JWT validation is manual viaauthenticate()
Other conventions
- New tables need RLS policies and the auto-set
sales_idtrigger (see migration20260108160722)
RLS enforcement pitfalls (security-critical)
- A trigger/function that counts rows to enforce a limit (capacity, quota, balance, subscription depletion) must be
SECURITY DEFINERwith a fixedsearch_path, or delegate to one. ASECURITY INVOKERcount runs under the caller's RLS, sees only the rows that caller may read, under-counts, and the limit silently never fires (e.g.session_booked_countis DEFINER for exactly this reason). - A
WITH CHECKclause must constrain every column a non-admin may set, not just ownership.with check (contact_id = current_user_contact())alone lets the caller forge any other column (status,type, amounts, flags) via PostgREST — privilege escalation / payment bypass. Whitelist allowed values in the policy, a trigger, or aCHECKconstraint; never trust a client-chosenstatus/type.
Red Flags
- Reaching for an edge function or RPC where a custom dataProvider method against PostgREST would do.
- Adding a column to a table that feeds
contacts_summary/companies_summarywithout updating the view. - A new table without RLS policies or the
sales_idtrigger. - A row-counting limit enforced by a
SECURITY INVOKERfunction it under-counts and never fires. - A
WITH CHECKthat constrains only ownership while leavingstatus/type/amounts client-settable. - An edge function handler that runs before
authenticate()in the middleware chain.
Verification
- The logic genuinely needs the backend no frontend-only path was available.
- New/changed views keep
contacts_summaryandcompanies_summaryin sync. - New tables have RLS policies and the
sales_idtrigger. - Any limit-enforcing count runs
SECURITY DEFINERwith a fixedsearch_path. - Every column a non-admin can set is constrained by policy, trigger, or
CHECK. - Edge functions follow CORS →
authenticate()→ handler.
When not to use it
- →When frontend-only solutions are sufficient
- →When using custom backend servers outside Supabase
Limitations
- →Limited to Supabase-native backend logic
- →Requires strict adherence to middleware patterns
How it compares
It mandates specific security and performance patterns within the Supabase ecosystem rather than allowing arbitrary backend server implementations.
Compared to similar skills
backend-dev side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| backend-dev (this skill) | 1 | 6mo | No flags | Intermediate |
| drizzle-orm | 32 | 2mo | No flags | Intermediate |
| hiddenroom-supabase | 0 | 1mo | No flags | Intermediate |
| prisma-database | 0 | 6mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by marmelab
View all by marmelab →You might also like
drizzle-orm
EpicenterHQ
Drizzle ORM patterns for type branding and custom types. Use when working with Drizzle column definitions, branded types, or custom type conversions.
hiddenroom-supabase
cuvo1903-ctrl
Hidden Room Supabase backend skill for migrations, generated database types, Edge Functions, RLS policies, auth/profile sync, storage buckets, Stripe integration, cloud_jobs, and database documentation. Use when editing supabase/migrations, supabase/functions, database.types.ts, or Supabase-backed f
prisma-database
slashwhy
Prisma schema conventions, migrations, seeding, and query patterns. Use when modifying database schema, creating migrations, or writing complex queries.
Database Rules
taikiwt
Supabase、RLS、マイグレーション、およびデータ操作に関する絶対ルール
ck:databases
lengo0951
Design schemas, write queries for MongoDB and PostgreSQL. Use for database design, SQL/NoSQL queries, aggregation pipelines, indexes, migrations, replication, performance optimization, psql CLI.
event-store-design
wshobson
Design and implement event stores for event-sourced systems. Use when building event sourcing infrastructure, choosing event store technologies, or implementing event persistence patterns.