database-design

Database design rules for Supabase, a service that provides hosted databases and user accounts. They define naming, data types, relationships, required fields, and row-level security, which controls who can read or change each row.

In plain words
What is it for?
Use them when designing Supabase tables, adding relationships, choosing timestamp and identifier types, and writing policies that restrict user data.
Why use it?
They help keep database structures consistent and reduce common access-control and data-integrity mistakes.

Cursor rule for Cursor

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add rules/vibestackdev/vibe-stack/database-design
Clone the repo
git clone --depth 1 https://github.com/vibestackdev/vibe-stack

Made for: Cursor.

Per session 0 Nothing until a file matches its globs; then the whole rule loads.
When invoked 556 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00000 $0.00556
Opus 5 $0.00000 $0.00278
Sonnet 5 $0.00000 $0.00111
Haiku 4.5 $0.00000 $0.00056

Measured yesterday against content hash 519a4b26b26b, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

database-design scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured yesterday.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

.cursor/rules/database-design.mdc · 66 lines

How it starts

The opening of the file, as written. The whole thing — 66 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Database Design Patterns

Table Naming

  • Use snake_case for tables and columns: user_profiles, created_at
  • NEVER use camelCase in SQL: userId → WRONG, user_id → CORRECT
  • Use plural table names: profiles, posts, comments

Required Columns (Every Table)

CREATE TABLE public.example (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  -- your columns here
  created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
  updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);

ALWAYS include id, created_at, and updated_at. ALWAYS use UUID for primary keys (not serial/integer). ALWAYS use TIMESTAMPTZ (not TIMESTAMP) for timezone safety.

Foreign Key Pattern

-- Always reference auth.users for user ownership
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL

Use ON DELETE CASCADE for user-owned data. Use ON DELETE SET NULL for optional relationships.

RLS Template (Copy This Every Time)

ALTER TABLE public.example ENABLE ROW LEVEL SECURITY;

-- Users can only see their own data
CREATE POLICY "Users own data" ON public.example
  FOR ALL USING (auth.uid() = user_id);

-- Or for public read + owner write:
CREATE POLICY "Public read" ON public.example
  FOR SELECT USING (true);
CREATE POLICY "Owner write" ON public.example
  FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Owner update" ON public.example
  FOR UPDATE USING (auth.uid() = user_id);
CREATE POLICY "Owner delete" ON public.example
  FOR DELETE USING (auth.uid() = user_id);

Type Generation

After schema changes, regenerate types:

npx supabase gen types typescript --project-id YOUR_PROJECT_REF > src/types/database.ts

ALWAYS use generated types — NEVER manually type database schemas.

Anti-Patterns

  • NEVER use TEXT for fields that should be enums — use PostgreSQL enums or CHECK constraints
  • NEVER store JSON blobs when structured columns work — use JSONB only for truly dynamic data
  • NEVER create tables without RLS — see supabase-rls.mdc
  • NEVER use SERIAL for IDs — use UUID for security (prevents enumeration attacks)

Read the full file on GitHub · 66 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. yesterday First seen · 66 lines · 0 tokens per session scan A 519a4b26b26b

Subscribe to this mod's changes

database-design is a cursor rule published in the GitHub repository vibestackdev/vibe-stack (7 stars, last pushed 2d ago), licensed MIT. It costs nothing until one of its globs matches a file; then it loads 556 tokens. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.