Skip to content
Back to skills

2653 Database 2f5ea994

ASecurity

<!-- CUSTOMIZE: Update paths to match your project structure. -->

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
databasestypescriptsqldatabasesecurity

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 2653-database_2f5ea994 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2653 Database 2f5ea994?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2653 Database 2f5ea994
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2653-database-2f5ea994/badge)](https://www.skillsdirectory.com/skills/tools-only-2653-database-2f5ea994)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
---
paths:
  - "**/*.sql"
  - "**/migrations/**"
  - "**/supabase/**"
---

# Database Patterns — Supabase Postgres

## Schema Files & Migrations

<!-- CUSTOMIZE: Update paths to match your project structure. -->

- Create migrations: `npx supabase db diff --schema public -f <migration_name>`
- Apply migrations: `npx supabase db reset`
- Generate types: `npx supabase gen types typescript --local > types/database.ts`

## Type Inference

Use auto-generated types for compile-time safety. Manually duplicating row shapes creates drift that causes runtime errors when the schema changes:

```typescript
import { Database } from '@/types/database'; // Auto-generated

type Account = Database['public']['Tables']['accounts']['Row'];
type InsertAccount = Database['public']['Tables']['accounts']['Insert'];
```

## SQL Coding Style

- Tables: `snake_case`, plural nouns (`accounts`, `subscriptions`)
- Functions: `snake_case`, verb phrases (`create_team_account`, `verify_nonce`)
- Explicit schema references (`public.accounts` not `accounts`) — without them, `search_path` changes can silently resolve to wrong schemas
- `search_path = ''` on all function definitions — without this, functions can access unintended schemas, creating security vulnerabilities
- `security definer` bypasses the caller's RLS context — using it without justification could expose cross-tenant data. Warn if you use it.

## RLS Helper Functions

Create reusable helper functions for common auth checks to avoid duplicating access-control logic across RLS policies:

```sql
-- Example: Check if user is a member of an account
CREATE OR REPLACE FUNCTION public.has_role_on_account(target_account_id UUID)
RETURNS BOOLEAN
LANGUAGE sql
SECURITY DEFINER
SET search_path = ''
AS $$
  SELECT EXISTS (
    SELECT 1 FROM public.memberships
    WHERE user_id = (SELECT auth.uid())
    AND account_id = target_account_id
  );
$$;
```

<!-- CUSTOMIZE: Add your project's RLS helper functions here.
Common helpers include: membership check, role check, permission check, ownership check. -->

### RLS Policy Patterns

```sql
-- Team-level access
CREATE POLICY "team_read" ON public.my_table FOR SELECT
  TO authenticated USING (
    public.has_role_on_account(account_id)
  );

-- Personal account access
CREATE POLICY "personal_read" ON public.my_table FOR SELECT
  TO authenticated USING (
    account_id = (select auth.uid())
  );

-- Both personal + team
CREATE POLICY "mixed_read" ON public.my_table FOR SELECT
  TO authenticated USING (
    account_id = (select auth.uid()) OR
    public.has_role_on_account(account_id)
  );
```

## Views

Views without `security_invoker = true` use the view owner's permissions, bypassing the caller's RLS context. This defeats multi-tenant isolation:

```sql
CREATE OR REPLACE VIEW public.my_view
WITH (security_invoker = true) AS
SELECT ...;
```

## Common Patterns

| Pattern | Implementation |
|---------|---------------|
| Account association | `account_id UUID REFERENCES public.accounts(id) ON DELETE CASCADE NOT NULL` |
| Timestamps | `CREATE TRIGGER ... EXECUTE FUNCTION public.trigger_set_timestamps()` |
| User tracking | `CREATE TRIGGER ... EXECUTE FUNCTION public.trigger_set_user_tracking()` |
| Enums | `CREATE TYPE public.my_status AS ENUM('active', 'inactive', 'pending')` |
| Constraints | `CHECK (count >= 0)`, `CHECK (email ~* '^.+@.+\..+$')` |

## OTP / One-Time Tokens

For sensitive operations (account deletion, ownership transfer), use one-time tokens:

```sql
-- Functions: create_nonce(), verify_nonce(), revoke_nonce()
-- Pattern: Generate token → send to user → verify on submission → revoke after use
```

<!-- CUSTOMIZE: If your framework provides OTP components, reference them here. -->

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.