Database Schema

Last updated on 2026-09-02

The kit uses 19 Supabase tables organized into five domains: people, deals, productivity, communication, and system. All tables have row-level security (RLS) enabled with a shared workspace model.

Schema Overview

People:         profiles, companies, contacts, tags, contact_tags, company_tags

Deals:          pipelines, pipeline_stages, deals, deal_products, deal_tags

Productivity:   tasks, activities

Communication:  emails, email_templates, email_sequences, email_sequence_steps

System:         notifications, crm_settings

Tables

profiles

Auto-created on user signup via database trigger. Stores team member information.

Column Type Notes
id uuid (PK, FK) References auth.users.id
full_name text Display name
avatar_url text Profile image URL
email text User email
phone text Phone number
role text member or admin
job_title text Role in the organization
quota numeric Sales quota amount
created_at timestamptz Auto-set
updated_at timestamptz Auto-updated by trigger

companies

Organizations tracked in the CRM.

Column Type Notes
id uuid (PK) Auto-generated
name text Company name
industry text Industry category
website text Company URL
phone text Company phone
email text General contact email
description text Company description
logo_url text Logo from crm-assets bucket
employee_count integer Number of employees
annual_revenue numeric Annual revenue
founded_year integer Year founded
address jsonb {street, city, state, zip, country}
social jsonb {linkedin, twitter}
owner_id uuid (FK) References profiles.id
search_vector tsvector Full-text search index
created_at timestamptz Auto-set
updated_at timestamptz Auto-updated by trigger

contacts

Individual people associated with companies.

Column Type Notes
id uuid (PK) Auto-generated
first_name text First name
last_name text Last name
email text Contact email
phone text Phone number
job_title text Job title
company_id uuid (FK) References companies.id
owner_id uuid (FK) References profiles.id
lead_source text website, referral, linkedin, cold_call, event, other
address jsonb {street, city, state, zip, country}
social jsonb {linkedin, twitter, website}
notes text Freeform notes
avatar_url text Contact photo
last_contacted timestamptz Auto-updated by trigger
search_vector tsvector Full-text search index
created_at timestamptz Auto-set
updated_at timestamptz Auto-updated by trigger

tags

Reusable labels for contacts, companies, and deals.

Column Type Notes
id uuid (PK) Auto-generated
name text (unique) Tag label
color text Display color

contact_tags / company_tags / deal_tags

Junction tables linking tags to entities.

Column Type Notes
entity_id uuid (FK) References the entity table
tag_id uuid (FK) References tags.id
Primary key composite (entity_id, tag_id)

pipelines

Named sales pipelines (e.g., "Sales Pipeline", "Enterprise Pipeline").

Column Type Notes
id uuid (PK) Auto-generated
name text Pipeline name
description text Pipeline description
is_default boolean Default pipeline for new deals
created_at timestamptz Auto-set

pipeline_stages

Ordered stages within each pipeline.

Column Type Notes
id uuid (PK) Auto-generated
pipeline_id uuid (FK) References pipelines.id
name text Stage name (e.g., "Lead", "Qualified")
color text Stage color for Kanban column
position integer Display order
default_probability integer 0-100 probability when deal enters stage
description text Stage description

deals

Individual deals tracked through pipeline stages.

Column Type Notes
id uuid (PK) Auto-generated
name text Deal name
description text Deal description
value numeric Deal monetary value
probability integer Win probability (0-100)
company_id uuid (FK) References companies.id
contact_id uuid (FK) References contacts.id
pipeline_id uuid (FK) References pipelines.id
stage_id uuid (FK) References pipeline_stages.id
owner_id uuid (FK) References profiles.id
priority text high, medium, or low
close_date date Expected close date
source text Lead source
created_at timestamptz Auto-set
updated_at timestamptz Auto-updated by trigger

deal_products

Line items / products associated with a deal.

Column Type Notes
id uuid (PK) Auto-generated
deal_id uuid (FK) References deals.id
name text Product/service name
quantity integer Quantity
unit_price numeric Price per unit

tasks

To-do items linked to contacts, deals, or standalone.

Column Type Notes
id uuid (PK) Auto-generated
title text Task title
description text Task details
priority text high, medium, or low
status text pending, in_progress, or completed
due_date date Due date
assignee_id uuid (FK) References profiles.id
contact_id uuid (FK) References contacts.id (nullable)
deal_id uuid (FK) References deals.id (nullable)
created_at timestamptz Auto-set
updated_at timestamptz Auto-updated by trigger

activities

Chronological log of CRM actions (calls, emails, meetings, notes, stage changes).

Column Type Notes
id uuid (PK) Auto-generated
type text call, email, meeting, note, stage_change
description text Activity description
user_id uuid (FK) References profiles.id
contact_id uuid (FK) References contacts.id (nullable)
deal_id uuid (FK) References deals.id (nullable)
company_id uuid (FK) References companies.id (nullable)
metadata jsonb Extra data (e.g., old/new stage for stage_change)
created_at timestamptz Auto-set

emails

Email messages sent and received within the CRM.

Column Type Notes
id uuid (PK) Auto-generated
subject text Email subject
body text Email body content
from_email text Sender email
to_email text Recipient email
folder text inbox, sent, or drafts
is_read boolean Read status
is_starred boolean Starred flag
contact_id uuid (FK) Linked CRM contact (nullable)
deal_id uuid (FK) Linked deal (nullable)
created_at timestamptz Auto-set

email_templates

Reusable email templates with merge field support.

Column Type Notes
id uuid (PK) Auto-generated
name text Template name
subject text Subject line with merge fields
body text Body with merge fields
category text Sales, Follow-up, Onboarding, Support
usage_count integer Times used
created_by uuid (FK) References profiles.id
created_at timestamptz Auto-set
updated_at timestamptz Auto-updated by trigger

email_sequences

Automated multi-step email campaigns.

Column Type Notes
id uuid (PK) Auto-generated
name text Sequence name
status text active, paused, or draft
enrolled_count integer Contacts enrolled
open_rate numeric Aggregate open rate
reply_rate numeric Aggregate reply rate
created_by uuid (FK) References profiles.id
created_at timestamptz Auto-set
updated_at timestamptz Auto-updated by trigger

email_sequence_steps

Individual steps within an email sequence.

Column Type Notes
id uuid (PK) Auto-generated
sequence_id uuid (FK) References email_sequences.id
step_type text email, wait, or condition
position integer Step order
template_id uuid (FK) References email_templates.id (nullable)
delay_days integer Wait duration for wait steps
condition_type text For condition steps: opened, clicked, replied
content text Custom email content if no template

notifications

In-app notifications for team members.

Column Type Notes
id uuid (PK) Auto-generated
user_id uuid (FK) References profiles.id
title text Notification title
message text Notification body
type text deal, task, contact, system
is_read boolean Read status
link text URL to navigate to
created_at timestamptz Auto-set

crm_settings

Global CRM configuration (single row).

Column Type Notes
id uuid (PK) Auto-generated
company_name text Organization name
company_logo text Logo URL
default_currency text Currency code (e.g., "USD")
fiscal_year_start integer Month number (1-12)
date_format text e.g., "MM/DD/YYYY"
timezone text e.g., "America/New_York"
updated_at timestamptz Auto-updated by trigger

Row-Level Security

RLS is enabled on every table. The kit uses a shared workspace model -- all authenticated team members can read all CRM data, while write operations are scoped based on role.

Helper Functions

-- Check if the current user is a team member (has a profile)
CREATE OR REPLACE FUNCTION is_team_member()
RETURNS boolean AS $$
  SELECT EXISTS (
    SELECT 1 FROM public.profiles
    WHERE id = auth.uid()
  );
$$ LANGUAGE sql SECURITY DEFINER;

-- Check if the current user is a CRM admin
CREATE OR REPLACE FUNCTION is_crm_admin()
RETURNS boolean AS $$
  SELECT EXISTS (
    SELECT 1 FROM public.profiles
    WHERE id = auth.uid() AND role = 'admin'
  );
$$ LANGUAGE sql SECURITY DEFINER;

Policy Summary

Table Team Read Team Write Admin-Only Write
profiles All profiles Own profile Manage all profiles
companies All All (insert, update) Delete
contacts All All (insert, update) Delete
deals All All (insert, update) Delete
tasks All All (insert, update) Delete
activities All Insert own Delete
emails All All (insert, update) Delete
email_templates All All (insert, update) Delete
email_sequences All All (insert, update) Delete
notifications Own only Own (update read) -
crm_settings All - Update
tags All All (insert) Delete
pipelines All - All (admin only)
pipeline_stages All - All (admin only)

Triggers

Profile Auto-Creation

When a new user signs up, a trigger automatically creates their profile:

CREATE OR REPLACE FUNCTION handle_new_user()
RETURNS trigger AS $$
BEGIN
  INSERT INTO public.profiles (id, full_name, avatar_url, email, role)
  VALUES (
    new.id,
    coalesce(new.raw_user_meta_data ->> 'full_name', ''),
    coalesce(new.raw_user_meta_data ->> 'avatar_url', ''),
    new.email,
    'member'
  );
  RETURN new;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

Auto-Update updated_at

All tables with an updated_at column have a trigger that sets it to now() on every update.

Deal Stage Change Activity

When a deal's stage_id changes, a trigger automatically logs an activity:

-- Inserts into activities with type = 'stage_change'
-- Stores old and new stage names in metadata

Contact Last Contacted

When a new activity is created with a contact_id, a trigger updates that contact's last_contacted timestamp.

Seed Data

The supabase/seed.sql file includes:

Entity Count Notes
Team members (profiles) 6 Including 1 admin: admin@example.com / password123
Companies 10 Various industries, sizes, and revenues
Contacts 20 Distributed across companies
Tags 8 Sales, Enterprise, Partner, etc.
Pipelines 2 Sales Pipeline (6 stages), Enterprise Pipeline (6 stages)
Deals 16 Various stages, values, and priorities
Tasks 12 Mix of pending, in-progress, and completed
Activities 20 Calls, emails, meetings, notes
Emails 12 Inbox, sent, and draft messages
Email templates 6 Sales, follow-up, and onboarding
Email sequences 3 Active, paused, and draft
Notifications 10 Various types
CRM settings 1 Default configuration

Regenerating Types

After modifying the schema, regenerate TypeScript types:

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

This updates the typed Supabase client used throughout the application.