Skip to main content

Overview

The collections table allows users to organize prompts into named groups. A prompt can belong to multiple collections, and a collection can contain multiple prompts, implemented via the collection_prompts join table.

collections Table

Schema

id
UUID
required
Primary key. Auto-generated using gen_random_uuid().
user_id
UUID
required
Owner of the collection. References auth.users(id) with ON DELETE CASCADE.
name
TEXT
required
Collection name. Must be unique per user (enforced by collections_user_id_name_key constraint).
description
TEXT
Optional collection description.
created_at
TIMESTAMPTZ
required
Creation timestamp. Defaults to now().
updated_at
TIMESTAMPTZ
required
Last modification timestamp. Defaults to now(). (Note: No auto-update trigger defined in migration.)

Constraints

ALTER TABLE collections 
ADD CONSTRAINT collections_user_id_name_key 
UNIQUE (user_id, name);
Each user can have only one collection with a given name (e.g., “Favorites”, “Work Prompts”).

Row Level Security

CREATE POLICY "Users can view their own collections"
  ON collections FOR SELECT
  USING (auth.uid() = user_id);

CREATE POLICY "Users can insert their own collections"
  ON collections FOR INSERT
  WITH CHECK (auth.uid() = user_id);

CREATE POLICY "Users can update their own collections"
  ON collections FOR UPDATE
  USING (auth.uid() = user_id);

CREATE POLICY "Users can delete their own collections"
  ON collections FOR DELETE
  USING (auth.uid() = user_id);
All operations are restricted to the collection owner.

collection_prompts Join Table

Schema

collection_id
UUID
required
References collections(id) with ON DELETE CASCADE.
prompt_id
UUID
required
References prompts(id) with ON DELETE CASCADE.
added_at
TIMESTAMPTZ
required
Timestamp when the prompt was added to the collection. Defaults to now().

Constraints

ALTER TABLE collection_prompts 
ADD PRIMARY KEY (collection_id, prompt_id);
Composite primary key prevents duplicate entries. A prompt can be added to a collection only once.

Indexes

CREATE INDEX idx_collection_prompts_prompt_id 
  ON collection_prompts(prompt_id);

CREATE INDEX idx_collection_prompts_collection_id 
  ON collection_prompts(collection_id);
  • idx_collection_prompts_prompt_id: Fast lookup of all collections containing a prompt
  • idx_collection_prompts_collection_id: Fast lookup of all prompts in a collection

Row Level Security

CREATE POLICY "Users can view entries in their collections"
  ON collection_prompts FOR SELECT
  USING (
    EXISTS (
      SELECT 1 FROM collections c
      WHERE c.id = collection_id
      AND c.user_id = auth.uid()
    )
  );

CREATE POLICY "Users can add entries to their collections"
  ON collection_prompts FOR INSERT
  WITH CHECK (
    EXISTS (
      SELECT 1 FROM collections c
      WHERE c.id = collection_id
      AND c.user_id = auth.uid()
    )
  );

CREATE POLICY "Users can remove entries from their collections"
  ON collection_prompts FOR DELETE
  USING (
    EXISTS (
      SELECT 1 FROM collections c
      WHERE c.id = collection_id
      AND c.user_id = auth.uid()
    )
  );
All policies verify ownership via the parent collections table. No UPDATE policy (entries are immutable once added; remove and re-add to change added_at).

Relationships

  • Many-to-One with auth.users: Each collection belongs to one user
  • Many-to-Many with prompts: Collections can contain multiple prompts, and prompts can be in multiple collections

Cascade Behavior

  • Delete User: Deletes all their collections and associated collection_prompts entries
  • Delete Collection: Deletes all collection_prompts entries for that collection
  • Delete Prompt: Removes prompt from all collections (deletes collection_prompts rows)

Common Queries

Get All Collections for a User

SELECT * FROM collections
WHERE user_id = auth.uid()
ORDER BY name ASC;

Get All Prompts in a Collection

SELECT p.*, cp.added_at
FROM prompts p
JOIN collection_prompts cp ON p.id = cp.prompt_id
WHERE cp.collection_id = 'collection-uuid-here'
ORDER BY cp.added_at DESC;

Get All Collections for a Prompt

SELECT c.*, cp.added_at
FROM collections c
JOIN collection_prompts cp ON c.id = cp.collection_id
WHERE cp.prompt_id = 'prompt-uuid-here'
ORDER BY c.name ASC;

Add Prompt to Collection

INSERT INTO collection_prompts (collection_id, prompt_id)
VALUES ('collection-uuid', 'prompt-uuid');

Remove Prompt from Collection

DELETE FROM collection_prompts
WHERE collection_id = 'collection-uuid'
AND prompt_id = 'prompt-uuid';

Search Integration

The search_prompts() RPC function accepts a filter_collection_id parameter:
SELECT * FROM search_prompts(
  query_text := 'authentication',
  filter_user_id := auth.uid(),
  filter_collection_id := 'collection-uuid-here'
);
See supabase/migrations/20260208000002_search_index.sql:67 for implementation.

TypeScript Types

// src/features/collections/types.ts
export type Collection = {
  id: string;
  name: string;
  description: string | null;
};

// Note: Type does not include user_id, created_at, updated_at.
// These fields may be omitted in client-facing APIs.

Migration File

  • 20260208000003_collections.sql: Table creation, indexes, and RLS policies

Build docs developers (and LLMs) love