Schema Version
40
Initialized
12/22/2025, 6:39:37 PM
Last Migration
10/14/2026, 2:14:42 PM
v1: 001_initial_schema
Applied: 12/22/2025, 6:39:38 PM
v2: 002_add_vendor_ratings
Applied: 1/15/2026, 1:16:53 PM
v3: 003_add_agile_projects
Applied: 10/14/2026, 2:00:42 PM
v4: 004_add_agile_releases
Applied: 10/14/2026, 2:00:52 PM
v5: 005_fix_profile_trigger
Applied: 10/14/2026, 2:01:04 PM
v6: 006_fix_audit_logs
Applied: 10/14/2026, 2:01:14 PM
v7: 007_add_feature_flags
Applied: 10/14/2026, 2:01:23 PM
v8: 008_add_target_location
Applied: 10/14/2026, 2:01:42 PM
v9: 009_meeting_reports_complete
Applied: 10/14/2026, 2:01:53 PM
v10: 010_add_vendor_management_columns
Applied: 10/14/2026, 2:02:04 PM
v11: 011_add_vendor_portal_columns
Applied: 10/14/2026, 2:02:18 PM
v12: 012_add_qa_feature_columns
Applied: 10/14/2026, 2:02:30 PM
v13: 013_add_qa_notification_columns
Applied: 10/14/2026, 2:02:42 PM
v14: 014_add_milestones
Applied: 10/14/2026, 2:02:58 PM
v15: 015_add_task_relations
Applied: 10/14/2026, 2:03:27 PM
v16: 016_add_qa_answer_approval
Applied: 10/14/2026, 2:03:38 PM
v17: 017_add_qa_consistency_check
Applied: 10/14/2026, 2:03:49 PM
v18: 018_add_meeting_report_hero_images
Applied: 10/14/2026, 2:08:14 PM
v19: 019_align_tenant_schema_with_app
Applied: 10/14/2026, 2:08:38 PM
v20: 020_full_align_with_reference
Applied: 10/14/2026, 2:08:53 PM
v21: 021_add_configurable_options
Applied: 10/14/2026, 2:09:06 PM
v22: 022_tender_parity_golf
Applied: 10/14/2026, 2:09:17 PM
v23: 023_tender_aggregation_trigger
Applied: 10/14/2026, 2:09:28 PM
v24: 024_add_design_v2_flag
Applied: 10/14/2026, 2:09:38 PM
v25: 025_add_rfq_quotation
Applied: 10/14/2026, 2:09:50 PM
v26: 026_add_rfq_tender_type
Applied: 10/14/2026, 2:10:01 PM
v27: 027_rfq_rev03_phase_a
Applied: 10/14/2026, 2:10:12 PM
v28: 028_rfq_plants
Applied: 10/14/2026, 2:10:24 PM
v29: 029_rfq_documents
Applied: 10/14/2026, 2:10:40 PM
v30: 030_rfq_suppliers
Applied: 10/14/2026, 2:10:50 PM
v31: 031_rfq_collaboration
Applied: 10/14/2026, 2:11:02 PM
v32: 032_rfq_activity
Applied: 10/14/2026, 2:11:13 PM
v33: 033_rfq_negotiation
Applied: 10/14/2026, 2:11:25 PM
v34: 034_rfq_awarding
Applied: 10/14/2026, 2:11:37 PM
v35: 035_rfq_realtime_quotes
Applied: 10/14/2026, 2:11:52 PM
v36: 036_allow_excluded_participation_status
Applied: 10/14/2026, 2:12:04 PM
v37: 037_project_html_documents
Applied: 10/14/2026, 2:12:26 PM
v38: 038_fix_report_translations
Applied: 10/14/2026, 2:14:11 PM
v39: 039_workshop_scorecard
Applied: 10/14/2026, 2:14:24 PM
v40: 040_security_hardening
Applied: 10/14/2026, 2:14:42 PM
-- INCISION Tenant Database Initial Schema
-- Version: 1
-- This script creates all required tables for a new tenant database
-- =====================================================
-- EXTENSIONS
-- =====================================================
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- =====================================================
-- ENUM TYPES
-- =====================================================
-- User role enum
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'user_role') THEN
CREATE TYPE user_role AS ENUM ('admin', 'manager', 'viewer', 'vendor');
END IF;
END $$;
-- Cost types
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'cost_type') THEN
CREATE TYPE cost_type AS ENUM ('one_time', 'recurring', 'variable');
END IF;
END $$;
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'cost_frequency') THEN
CREATE TYPE cost_frequency AS ENUM ('one_time', 'monthly', 'quarterly', 'annually');
END IF;
END $$;
-- RAID log enums
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'raid_category') THEN
CREATE TYPE raid_category AS ENUM ('technical', 'operational', 'financial', 'legal', 'resource', 'external', 'strategic');
END IF;
END $$;
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'risk_severity') THEN
CREATE TYPE risk_severity AS ENUM ('critical', 'high', 'medium', 'low');
END IF;
END $$;
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'risk_likelihood') THEN
CREATE TYPE risk_likelihood AS ENUM ('very_high', 'high', 'medium', 'low', 'very_low');
END IF;
END $$;
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'risk_impact') THEN
CREATE TYPE risk_impact AS ENUM ('critical', 'high', 'medium', 'low', 'minimal');
END IF;
END $$;
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'raid_status') THEN
CREATE TYPE raid_status AS ENUM ('open', 'in_progress', 'mitigated', 'resolved', 'closed', 'accepted');
END IF;
END $$;
-- Q&A enums
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'qa_question_status') THEN
CREATE TYPE qa_question_status AS ENUM ('pending', 'assigned', 'draft_answer', 'answered', 'published', 'rejected', 'deferred');
END IF;
END $$;
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'qa_question_category') THEN
CREATE TYPE qa_question_category AS ENUM ('technical', 'commercial', 'legal', 'compliance', 'general');
END IF;
END $$;
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'qa_question_priority') THEN
CREATE TYPE qa_question_priority AS ENUM ('low', 'normal', 'high', 'urgent');
END IF;
END $$;
-- =====================================================
-- CORE TABLES
-- =====================================================
-- Profiles table (extends auth.users)
CREATE TABLE IF NOT EXISTS public.profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
email TEXT NOT NULL,
full_name TEXT,
role user_role DEFAULT 'viewer',
bio TEXT,
permissions JSONB DEFAULT '{}',
avatar_url TEXT,
phone_number TEXT,
department TEXT,
job_title TEXT,
is_approved BOOLEAN DEFAULT false,
is_suspended BOOLEAN DEFAULT false,
is_archived BOOLEAN DEFAULT false,
must_change_password BOOLEAN DEFAULT false,
approved_by UUID REFERENCES auth.users(id),
approved_at TIMESTAMPTZ,
theme_preference TEXT DEFAULT 'light',
email_notifications JSONB DEFAULT '{"qa_new_question": true, "qa_answer_published": true, "qa_new_published": true}'::jsonb,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Feature flags table
CREATE TABLE IF NOT EXISTS public.feature_flags (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
feature_name TEXT NOT NULL UNIQUE,
is_enabled BOOLEAN DEFAULT false,
description TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Projects table
CREATE TABLE IF NOT EXISTS public.projects (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL,
description TEXT,
status TEXT DEFAULT 'active' CHECK (status IN ('active', 'on_hold', 'completed', 'archived')),
start_date DATE,
end_date DATE,
owner_id UUID REFERENCES public.profiles(id),
is_archived BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- TSA Services table
CREATE TABLE IF NOT EXISTS public.tsa_services (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
service_id TEXT UNIQUE NOT NULL,
service_code TEXT,
service_name TEXT NOT NULL,
description TEXT,
category TEXT,
provider TEXT,
recipient TEXT,
service_owner TEXT,
responsible_person TEXT,
contact_person TEXT,
contact_email TEXT,
service_level_agreement TEXT,
monthly_cost DECIMAL(12, 2) DEFAULT 0,
status
... (truncated)