Overview
Pipeline uses Supabase (PostgreSQL 15+) with a carefully designed schema featuring Row-Level Security (RLS), soft deletes, audit logging, and full-text search capabilities.Schema Version: 1.0.20 (13 migrations applied)All migrations are located in
/supabase/migrations/Core Tables
jobs
The main table storing all job applications and postings.Primary key - unique job identifier
Foreign key to
auth.users - job ownerCompany name (non-empty, max 200 chars)
Position title (non-empty, max 200 chars)
Full job description (max 50,000 chars)
HTTPS-only URL to original posting
One of:
brightermonday, fuzu, linkedin, manualOne of:
saved, applied, interview, offer, rejectedAI-calculated match percentage (0-100)
Structured data extracted by AI (skills, requirements)
AI explanation for the match score
Application submission date
Interview start date
Offer received date
Rejection date
User notes (max 10,000 chars)
Job tags (max 20 items, no empty strings)
Minimum salary (≥ 30,000)
Maximum salary (≤ 10,000,000)
Job location
Remote job flag
Creation timestamp
Last update timestamp (auto-updated)
Soft delete timestamp (NULL = active)
Weighted full-text search vector
Check Constraints
- AI match score between 0-100
- Salary min ≤ max, min ≥ 30k, max ≤ 10M
- Applied date before interview date
- HTTPS-only URLs
- Non-empty company name and job title
- Max 20 tags, no empty strings
events
Immutable activity log for audit trail (append-only).Primary key - unique event identifier
Foreign key to
auth.users - event ownerForeign key to
jobs - related job (if applicable)Event type enum (see Event Types below)
Event payload (must be valid JSON object)
Event timestamp
insights
AI-generated insights and recommendations with expiry management.Primary key - unique insight identifier
Foreign key to
auth.users - insight ownerOne of:
daily_digest, pattern_detection, recommendation, weekly_summary, market_analysisInsight title (non-empty)
Insight content (non-empty)
Additional structured data
Creation timestamp
Expiry timestamp (must be in the future)
scraper_runs
Scraper telemetry and statistics for monitoring.Primary key - unique run identifier
Foreign key to
auth.users - owner if manual runScraper source enum
One of:
running, completed, failed, cancelledRun start timestamp
Run completion timestamp
Total jobs found (≥ 0)
New jobs discovered (≥ 0)
Jobs imported (≥ 0)
Error details if failed
Additional run data
audit_log
Comprehensive audit trail for compliance and debugging (system-managed).Primary key
Affected table name
Affected record ID
One of:
INSERT, UPDATE, DELETEBefore snapshot
After snapshot
Acting user
Timestamp
Enums
job_status
saved→applied,rejectedapplied→interview,rejected,savedinterview→offer,rejected,applied,interviewoffer→rejected,applied,savedrejected→saved,applied
job_source
event_type
insight_type
scraper_status
Indexes
Performance Indexes
jobs table:idx_jobs_user_status- User’s jobs by statusidx_jobs_user_created- User’s jobs by date (DESC)idx_jobs_user_source- User’s jobs by sourceidx_jobs_user_company- User’s companiesidx_jobs_search_weighted- Full-text search (GIN)idx_jobs_ai_match_score- Top AI matches (DESC NULLS LAST)idx_jobs_deleted_at- Soft deleted jobs (partial index)
idx_events_user_created- User’s events by date (DESC)idx_events_job_id- Job’s eventsidx_events_user_type- User’s events by type
idx_insights_user_id- User’s insightsidx_insights_created_at- Recent insights (DESC)idx_insights_expires_at- Expiring insights (partial index)
idx_scraper_runs_started_at- Recent runs (DESC)idx_scraper_runs_user_started- User’s runs by date
Database Functions
Full-Text Search
- A (highest):
job_title,company_name - B (medium):
job_description - C (lowest):
tags
Soft Delete Utilities
Cleanup Functions
Triggers
Automated Triggers
trigger_update_updated_at
trigger_update_updated_at
Table:
jobsEvent: BEFORE UPDATEFunction: update_updated_at_column()Purpose: Automatically updates updated_at timestamp on every job updatetrigger_validate_status_transition
trigger_validate_status_transition
Table:
jobsEvent: BEFORE UPDATEFunction: validate_job_status_transition()Purpose: Validates status changes follow allowed transition rules. Raises exception for invalid transitions.trigger_log_job_changes
trigger_log_job_changes
Table:
jobsEvent: AFTER INSERT OR UPDATEFunction: log_job_changes()Purpose: Logs job changes to events table for audit trailtrigger_update_search_vector
trigger_update_search_vector
Table:
jobsEvent: BEFORE INSERT OR UPDATEFunction: update_search_vector()Purpose: Updates weighted full-text search vector for search functionalityEntity Relationship Diagram
Data Flow Examples
Job Creation Flow
Status Transition Flow
Migration History
Next Steps
RLS Policies
Learn about Row-Level Security implementation
Deployment
Deploy database to production