-- ============================================================================ -- Nxtgauge Database Complete Migration -- Version: 20260415000000 -- This migration performs a COMPLETE schema transformation -- NO FALLBACKS - This is a one-way migration -- ============================================================================ BEGIN; -- ============================================================================ -- PHASE 1: Create New Core Tables -- ============================================================================ -- 1.1 user_sessions (new) CREATE TABLE IF NOT EXISTS user_sessions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, session_token TEXT UNIQUE NOT NULL, ip_address TEXT, user_agent TEXT, expires_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_user_sessions_user_id ON user_sessions(user_id); CREATE INDEX IF NOT EXISTS idx_user_sessions_token ON user_sessions(session_token); CREATE INDEX IF NOT EXISTS idx_user_sessions_expires ON user_sessions(expires_at); -- 1.2 user_role_profiles (NEW ROOT - CRITICAL) CREATE TABLE IF NOT EXISTS user_role_profiles ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, role_key VARCHAR(50) NOT NULL, display_name TEXT, bio TEXT, location TEXT, avatar_url TEXT, phone TEXT, email TEXT, status VARCHAR(50) NOT NULL DEFAULT 'ACTIVE', verification_status VARCHAR(50) DEFAULT 'PENDING', approval_status VARCHAR(50) DEFAULT 'PENDING', rejection_reason TEXT, approved_at TIMESTAMPTZ, verified_at TIMESTAMPTZ, is_profile_public BOOLEAN DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(user_id, role_key) ); CREATE INDEX IF NOT EXISTS idx_user_role_profiles_user_id ON user_role_profiles(user_id); CREATE INDEX IF NOT EXISTS idx_user_role_profiles_role_key ON user_role_profiles(role_key); CREATE INDEX IF NOT EXISTS idx_user_role_profiles_status ON user_role_profiles(status); -- ============================================================================ -- PHASE 2: Skip backfill for fresh database -- ============================================================================ -- (No data to backfill from - profile tables use user_role_profile_id directly) -- ============================================================================ -- PHASE 3: Update Extension Tables to Use user_role_profile_id -- ============================================================================ -- Add user_role_profile_id column to ALL extension tables (already exist in fresh schema) -- ============================================================================ -- PHASE 5: Update Portfolio Tables -- ============================================================================ -- Add user_role_profile_id to portfolio_items ALTER TABLE portfolio_items ADD COLUMN IF NOT EXISTS user_role_profile_id UUID; ALTER TABLE portfolio_items ADD COLUMN IF NOT EXISTS display_order INTEGER DEFAULT 0; -- Backfill portfolio_items from professionals UPDATE portfolio_items pi SET user_role_profile_id = urp.id FROM user_role_profiles urp WHERE pi.professional_id IS NOT NULL AND urp.user_id = (SELECT user_id FROM professionals p WHERE p.id = pi.professional_id); -- Update remaining using user_id UPDATE portfolio_items pi SET user_role_profile_id = urp.id FROM user_role_profiles urp WHERE pi.user_id IS NOT NULL AND pi.user_role_profile_id IS NULL AND EXISTS (SELECT 1 FROM user_role_profiles urp2 WHERE urp2.user_id = pi.user_id AND urp2.role_key = pi.profession_key); -- Add user_role_profile_id to services ALTER TABLE services ADD COLUMN IF NOT EXISTS user_role_profile_id UUID; -- Backfill services UPDATE services s SET user_role_profile_id = urp.id FROM user_role_profiles urp WHERE s.professional_id IS NOT NULL AND urp.user_id = (SELECT user_id FROM professionals p WHERE p.id = s.professional_id); UPDATE services s SET user_role_profile_id = urp.id FROM user_role_profiles urp WHERE s.user_id IS NOT NULL AND s.user_role_profile_id IS NULL AND EXISTS (SELECT 1 FROM user_role_profiles urp2 WHERE urp2.user_id = s.user_id AND urp2.role_key = s.profession_key); -- ============================================================================ -- PHASE 6: Rename Tables -- ============================================================================ -- Rename applications -> job_applications ALTER TABLE applications RENAME TO job_applications; -- Rename requirements -> leads ALTER TABLE requirements RENAME TO leads; -- Rename coupon_uses -> coupon_redemptions ALTER TABLE coupon_uses RENAME TO coupon_redemptions; -- ============================================================================ -- PHASE 7: Create New Domain Tables -- ============================================================================ -- 7.1 verification_requests CREATE TABLE IF NOT EXISTS verification_requests ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_role_profile_id UUID REFERENCES user_role_profiles(id), verification_type VARCHAR(50) NOT NULL DEFAULT 'IDENTITY', status VARCHAR(50) NOT NULL DEFAULT 'PENDING', submitted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), reviewed_at TIMESTAMPTZ, reviewed_by_user_id UUID REFERENCES users(id), remarks TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.2 verification_documents CREATE TABLE IF NOT EXISTS verification_documents ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), verification_request_id UUID NOT NULL REFERENCES verification_requests(id) ON DELETE CASCADE, document_type VARCHAR(100) NOT NULL, file_url TEXT NOT NULL, file_name TEXT, mime_type TEXT, status VARCHAR(50) DEFAULT 'PENDING', uploaded_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), reviewed_at TIMESTAMPTZ, reviewed_by_user_id UUID REFERENCES users(id), remarks TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.3 verification_logs CREATE TABLE IF NOT EXISTS verification_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), verification_request_id UUID NOT NULL REFERENCES verification_requests(id), action VARCHAR(50) NOT NULL, old_status VARCHAR(50), new_status VARCHAR(50), acted_by_user_id UUID REFERENCES users(id), remarks TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.4 approval_requests CREATE TABLE IF NOT EXISTS approval_requests ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), entity_type VARCHAR(50) NOT NULL, entity_id UUID NOT NULL, approval_type VARCHAR(50), status VARCHAR(50) NOT NULL DEFAULT 'PENDING', submitted_by_user_id UUID REFERENCES users(id), reviewed_by_user_id UUID REFERENCES users(id), submitted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), reviewed_at TIMESTAMPTZ, remarks TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.5 approval_logs CREATE TABLE IF NOT EXISTS approval_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), approval_request_id UUID NOT NULL REFERENCES approval_requests(id), action VARCHAR(50) NOT NULL, old_status VARCHAR(50), new_status VARCHAR(50), acted_by_user_id UUID REFERENCES users(id), remarks TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.6 audit_logs CREATE TABLE IF NOT EXISTS audit_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), actor_user_id UUID REFERENCES users(id), actor_employee_id UUID, actor_type VARCHAR(50), action VARCHAR(100) NOT NULL, entity_type VARCHAR(100), entity_id UUID, entity_label TEXT, module_key VARCHAR(100), source_type VARCHAR(50), source_id UUID, request_id UUID, correlation_id UUID, ip_address TEXT, user_agent TEXT, status VARCHAR(50) NOT NULL DEFAULT 'SUCCESS', summary TEXT, metadata_json JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.7 audit_log_changes CREATE TABLE IF NOT EXISTS audit_log_changes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), audit_log_id UUID NOT NULL REFERENCES audit_logs(id) ON DELETE CASCADE, field_name TEXT NOT NULL, old_value_text TEXT, new_value_text TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_audit_logs_actor ON audit_logs(actor_user_id); CREATE INDEX IF NOT EXISTS idx_audit_logs_entity ON audit_logs(entity_type, entity_id); CREATE INDEX IF NOT EXISTS idx_audit_logs_module ON audit_logs(module_key); CREATE INDEX IF NOT EXISTS idx_audit_logs_created ON audit_logs(created_at); -- 7.8 orders CREATE TABLE IF NOT EXISTS orders ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id), order_type VARCHAR(50) NOT NULL DEFAULT 'PACKAGE', subtotal_inr INTEGER NOT NULL DEFAULT 0, discount_inr INTEGER NOT NULL DEFAULT 0, tax_inr INTEGER NOT NULL DEFAULT 0, total_inr INTEGER NOT NULL DEFAULT 0, status VARCHAR(50) NOT NULL DEFAULT 'PENDING', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.9 order_items CREATE TABLE IF NOT EXISTS order_items ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), order_id UUID NOT NULL REFERENCES orders(id) ON DELETE CASCADE, item_type VARCHAR(50) NOT NULL, item_id UUID, item_name TEXT NOT NULL, quantity INTEGER NOT NULL DEFAULT 1, unit_price_inr INTEGER NOT NULL, total_price_inr INTEGER NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.10 payment_gateway_configs CREATE TABLE IF NOT EXISTS payment_gateway_configs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), gateway_key VARCHAR(50) NOT NULL, display_name VARCHAR(255), config_json JSONB, is_active BOOLEAN DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.11 payment_transactions CREATE TABLE IF NOT EXISTS payment_transactions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), payment_id UUID NOT NULL REFERENCES payments(id), transaction_type VARCHAR(50) NOT NULL, provider_reference TEXT, request_payload_json JSONB, response_payload_json JSONB, status VARCHAR(50) NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.12 tax_rules CREATE TABLE IF NOT EXISTS tax_rules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, tax_type VARCHAR(50) NOT NULL, tax_rate DECIMAL(5,2) NOT NULL, applies_to VARCHAR(50), is_active BOOLEAN DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.13 kb_sections CREATE TABLE IF NOT EXISTS kb_sections ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), category_id UUID NOT NULL REFERENCES kb_categories(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, slug VARCHAR(255) NOT NULL, description TEXT, display_order INTEGER DEFAULT 0, is_active BOOLEAN DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.14 kb_article_feedback CREATE TABLE IF NOT EXISTS kb_article_feedback ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), article_id UUID NOT NULL REFERENCES kb_articles(id) ON DELETE CASCADE, user_id UUID REFERENCES users(id), is_helpful BOOLEAN, feedback_text TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.15 notification_templates CREATE TABLE IF NOT EXISTS notification_templates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), template_key VARCHAR(100) NOT NULL UNIQUE, channel VARCHAR(50) NOT NULL DEFAULT 'EMAIL', title_template TEXT, body_template TEXT, is_active BOOLEAN DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.16 smtp_configs CREATE TABLE IF NOT EXISTS smtp_configs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), provider_name VARCHAR(100), host VARCHAR(255), port INTEGER, username TEXT, encryption_mode VARCHAR(20), from_name VARCHAR(255), from_email VARCHAR(255), is_default BOOLEAN DEFAULT false, is_active BOOLEAN DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 7.17 dashboard_widgets CREATE TABLE IF NOT EXISTS dashboard_widgets ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), dashboard_config_id UUID NOT NULL REFERENCES dashboard_configs(id) ON DELETE CASCADE, widget_key VARCHAR(100) NOT NULL, widget_title VARCHAR(255), config_json JSONB, display_order INTEGER DEFAULT 0, width_units INTEGER DEFAULT 1, height_units INTEGER DEFAULT 1, is_visible BOOLEAN DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- ============================================================================ -- PHASE 8: Update Existing Tables -- ============================================================================ -- Update users table ALTER TABLE users ADD COLUMN IF NOT EXISTS account_type TEXT DEFAULT 'INDIVIDUAL'; ALTER TABLE users ADD COLUMN IF NOT EXISTS last_login_at TIMESTAMPTZ; ALTER TABLE users ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); UPDATE users SET updated_at = COALESCE(updated_at, created_at, NOW()) WHERE updated_at IS NULL; -- Update roles table ALTER TABLE roles ADD COLUMN IF NOT EXISTS description TEXT; ALTER TABLE roles ADD COLUMN IF NOT EXISTS can_approve_requests BOOLEAN DEFAULT false; ALTER TABLE roles ADD COLUMN IF NOT EXISTS can_manage_system_settings BOOLEAN DEFAULT false; -- Update departments table ALTER TABLE departments ADD COLUMN IF NOT EXISTS code VARCHAR(64); ALTER TABLE departments ADD COLUMN IF NOT EXISTS description TEXT; ALTER TABLE departments ADD COLUMN IF NOT EXISTS department_head VARCHAR(255); ALTER TABLE departments ADD COLUMN IF NOT EXISTS department_email VARCHAR(255); ALTER TABLE departments ADD COLUMN IF NOT EXISTS visibility VARCHAR(20) DEFAULT 'INTERNAL'; ALTER TABLE departments ADD COLUMN IF NOT EXISTS transfers_enabled BOOLEAN DEFAULT false; ALTER TABLE departments ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); UPDATE departments SET updated_at = COALESCE(updated_at, created_at, NOW()) WHERE updated_at IS NULL; -- Update designations table ALTER TABLE designations ADD COLUMN IF NOT EXISTS code VARCHAR(64); ALTER TABLE designations ADD COLUMN IF NOT EXISTS department_id UUID REFERENCES departments(id); ALTER TABLE designations ADD COLUMN IF NOT EXISTS description TEXT; ALTER TABLE designations ADD COLUMN IF NOT EXISTS level VARCHAR(100); ALTER TABLE designations ADD COLUMN IF NOT EXISTS can_manage_team BOOLEAN DEFAULT false; ALTER TABLE designations ADD COLUMN IF NOT EXISTS can_approve BOOLEAN DEFAULT false; ALTER TABLE designations ADD COLUMN IF NOT EXISTS is_active BOOLEAN DEFAULT true; ALTER TABLE designations ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); UPDATE designations SET updated_at = COALESCE(updated_at, created_at, NOW()) WHERE updated_at IS NULL; -- Update employees table ALTER TABLE employees ADD COLUMN IF NOT EXISTS joining_date DATE; ALTER TABLE employees ADD COLUMN IF NOT EXISTS employment_status VARCHAR(50) DEFAULT 'ACTIVE'; ALTER TABLE employees ADD COLUMN IF NOT EXISTS manager_employee_id UUID REFERENCES employees(id); ALTER TABLE employees ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); UPDATE employees SET updated_at = COALESCE(updated_at, created_at, NOW()) WHERE updated_at IS NULL; -- Update lead_requests table ALTER TABLE lead_requests ADD COLUMN IF NOT EXISTS user_role_profile_id UUID; UPDATE lead_requests lr SET user_role_profile_id = urp.id FROM user_role_profiles urp WHERE lr.professional_id IS NOT NULL AND urp.user_id = (SELECT user_id FROM professionals p WHERE p.id = lr.professional_id); ALTER TABLE lead_requests ADD COLUMN IF NOT EXISTS remarks TEXT; ALTER TABLE lead_requests ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); -- Update job_applications table ALTER TABLE job_applications ADD COLUMN IF NOT EXISTS applicant_user_id UUID; UPDATE job_applications ja SET applicant_user_id = ( SELECT user_id FROM job_seeker_profiles jsp WHERE jsp.id = ja.job_seeker_id ); ALTER TABLE job_applications ADD COLUMN IF NOT EXISTS cover_note TEXT; ALTER TABLE job_applications DROP COLUMN IF EXISTS job_seeker_id; ALTER TABLE job_applications DROP COLUMN IF EXISTS cover_letter; ALTER TABLE job_applications DROP COLUMN IF EXISTS resume_url; ALTER TABLE job_applications DROP COLUMN IF EXISTS contact_viewed; -- Update leads table (formerly requirements) ALTER TABLE leads ADD COLUMN IF NOT EXISTS created_by_user_id UUID; UPDATE leads l SET created_by_user_id = ( SELECT user_id FROM customer_profiles cp WHERE cp.id = l.customer_id ); ALTER TABLE leads ADD COLUMN IF NOT EXISTS required_date DATE; ALTER TABLE leads ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); ALTER TABLE leads DROP COLUMN IF EXISTS customer_id; -- Update jobs table ALTER TABLE jobs ADD COLUMN IF NOT EXISTS posted_by_user_id UUID; ALTER TABLE jobs ADD COLUMN IF NOT EXISTS mode_of_work VARCHAR(50); ALTER TABLE jobs ADD COLUMN IF NOT EXISTS budget_inr INTEGER; ALTER TABLE jobs ADD COLUMN IF NOT EXISTS salary_range_json JSONB; ALTER TABLE jobs ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); UPDATE jobs SET updated_at = COALESCE(updated_at, created_at, NOW()) WHERE updated_at IS NULL; -- Update tracecoin_wallets ALTER TABLE tracecoin_wallets RENAME COLUMN balance TO current_balance; ALTER TABLE tracecoin_wallets ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); -- Update tracecoin_ledger ALTER TABLE tracecoin_ledger ADD COLUMN IF NOT EXISTS balance_after INTEGER; ALTER TABLE tracecoin_ledger ADD COLUMN IF NOT EXISTS remarks TEXT; ALTER TABLE tracecoin_ledger RENAME COLUMN type TO transaction_type; ALTER TABLE tracecoin_ledger RENAME COLUMN reason TO reference_type; -- Update coupons ALTER TABLE coupons ADD COLUMN IF NOT EXISTS max_discount_inr INTEGER; ALTER TABLE coupons ADD COLUMN IF NOT EXISTS min_order_value_inr INTEGER DEFAULT 0; ALTER TABLE coupons ADD COLUMN IF NOT EXISTS valid_from TIMESTAMPTZ DEFAULT NOW(); ALTER TABLE coupons ADD COLUMN IF NOT EXISTS valid_to TIMESTAMPTZ; -- Update coupon_redemptions ALTER TABLE coupon_redemptions ADD COLUMN IF NOT EXISTS order_id UUID REFERENCES orders(id); ALTER TABLE coupon_redemptions ADD COLUMN IF NOT EXISTS discount_amount_inr INTEGER; ALTER TABLE coupon_redemptions RENAME COLUMN used_at TO redeemed_at; -- Update invoices ALTER TABLE invoices ADD COLUMN IF NOT EXISTS order_id UUID REFERENCES orders(id); ALTER TABLE invoices ADD COLUMN IF NOT EXISTS discount_inr INTEGER DEFAULT 0; ALTER TABLE invoices ADD COLUMN IF NOT EXISTS due_at TIMESTAMPTZ; ALTER TABLE invoices ADD COLUMN IF NOT EXISTS paid_at TIMESTAMPTZ; -- Update payments ALTER TABLE payments ADD COLUMN IF NOT EXISTS payment_gateway_config_id UUID REFERENCES payment_gateway_configs(id); ALTER TABLE payments ADD COLUMN IF NOT EXISTS payment_method VARCHAR(50); ALTER TABLE payments ADD COLUMN IF NOT EXISTS currency_code VARCHAR(10) DEFAULT 'INR'; ALTER TABLE payments ADD COLUMN IF NOT EXISTS initiated_at TIMESTAMPTZ DEFAULT NOW(); ALTER TABLE payments ADD COLUMN IF NOT EXISTS completed_at TIMESTAMPTZ; -- Update kb_articles ALTER TABLE kb_articles ADD COLUMN IF NOT EXISTS section_id UUID REFERENCES kb_sections(id); ALTER TABLE kb_articles ADD COLUMN IF NOT EXISTS article_type VARCHAR(50) DEFAULT 'HOW_TO'; ALTER TABLE kb_articles ADD COLUMN IF NOT EXISTS audience_type VARCHAR(50) DEFAULT 'ALL'; ALTER TABLE kb_articles RENAME COLUMN body TO content_markdown; ALTER TABLE kb_articles RENAME COLUMN created_by TO author_user_id; -- Update support_tickets ALTER TABLE support_tickets ADD COLUMN IF NOT EXISTS created_by_user_id UUID; UPDATE support_tickets SET created_by_user_id = user_id; ALTER TABLE support_tickets RENAME COLUMN assigned_to TO assigned_to_user_id; ALTER TABLE support_tickets ADD COLUMN IF NOT EXISTS related_entity_type VARCHAR(50); ALTER TABLE support_tickets ADD COLUMN IF NOT EXISTS related_entity_id UUID; ALTER TABLE support_tickets ADD COLUMN IF NOT EXISTS closed_at TIMESTAMPTZ; -- Update support_ticket_messages ALTER TABLE support_ticket_messages ADD COLUMN IF NOT EXISTS sender_user_id UUID; UPDATE support_ticket_messages SET sender_user_id = sender_id; ALTER TABLE support_ticket_messages RENAME COLUMN body TO message_body; ALTER TABLE support_ticket_messages ADD COLUMN IF NOT EXISTS attachment_url TEXT; -- Update notifications ALTER TABLE notifications ADD COLUMN IF NOT EXISTS channel VARCHAR(50) DEFAULT 'IN_APP'; ALTER TABLE notifications ADD COLUMN IF NOT EXISTS related_entity_type VARCHAR(50); ALTER TABLE notifications RENAME COLUMN reference_id TO related_entity_id; -- Update reviews ALTER TABLE reviews ADD COLUMN IF NOT EXISTS entity_type VARCHAR(50) DEFAULT 'professional'; ALTER TABLE reviews RENAME COLUMN customer_id TO reviewer_user_id; ALTER TABLE reviews ADD COLUMN IF NOT EXISTS status VARCHAR(50) DEFAULT 'PUBLISHED'; -- ============================================================================ -- PHASE 9: Drop Deprecated Tables -- ============================================================================ DROP TABLE IF EXISTS professionals CASCADE; DROP TABLE IF EXISTS onboarding_submissions CASCADE; DROP TABLE IF EXISTS onboarding_configs CASCADE; DROP TABLE IF EXISTS onboarding_states CASCADE; DROP TABLE IF EXISTS submission_documents CASCADE; -- ============================================================================ -- PHASE 10: Drop Deprecated Columns from Extension Tables -- ============================================================================ -- Drop old user_id columns from extension tables (AFTER backfilling user_role_profile_id) ALTER TABLE photographer_profiles DROP COLUMN IF EXISTS user_id; ALTER TABLE tutor_profiles DROP COLUMN IF EXISTS user_id; ALTER TABLE makeup_artist_profiles DROP COLUMN IF EXISTS user_id; ALTER TABLE developer_profiles DROP COLUMN IF EXISTS user_id; ALTER TABLE video_editor_profiles DROP COLUMN IF EXISTS user_id; ALTER TABLE graphic_designer_profiles DROP COLUMN IF EXISTS user_id; ALTER TABLE social_media_manager_profiles DROP COLUMN IF EXISTS user_id; ALTER TABLE fitness_trainer_profiles DROP COLUMN IF EXISTS user_id; ALTER TABLE catering_service_profiles DROP COLUMN IF EXISTS user_id; ALTER TABLE ugc_content_creator_profiles DROP COLUMN IF EXISTS user_id; -- Drop old columns from portfolio_items ALTER TABLE portfolio_items DROP COLUMN IF EXISTS professional_id; ALTER TABLE portfolio_items DROP COLUMN IF EXISTS user_id; ALTER TABLE portfolio_items DROP COLUMN IF EXISTS profession_key; -- Drop old columns from services ALTER TABLE services DROP COLUMN IF EXISTS professional_id; ALTER TABLE services DROP COLUMN IF EXISTS user_id; ALTER TABLE services DROP COLUMN IF EXISTS profession_key; -- Drop old columns from lead_requests ALTER TABLE lead_requests DROP COLUMN IF EXISTS professional_id; ALTER TABLE lead_requests DROP COLUMN IF EXISTS requirement_id; -- Drop old custom_data columns ALTER TABLE photographer_profiles DROP COLUMN IF EXISTS custom_data; ALTER TABLE tutor_profiles DROP COLUMN IF EXISTS custom_data; ALTER TABLE makeup_artist_profiles DROP COLUMN IF EXISTS custom_data; ALTER TABLE developer_profiles DROP COLUMN IF EXISTS custom_data; ALTER TABLE video_editor_profiles DROP COLUMN IF EXISTS custom_data; ALTER TABLE graphic_designer_profiles DROP COLUMN IF EXISTS custom_data; ALTER TABLE social_media_manager_profiles DROP COLUMN IF EXISTS custom_data; ALTER TABLE fitness_trainer_profiles DROP COLUMN IF EXISTS custom_data; ALTER TABLE catering_service_profiles DROP COLUMN IF EXISTS custom_data; ALTER TABLE ugc_content_creator_profiles DROP COLUMN IF EXISTS custom_data; -- Drop old profile columns that are now in user_role_profiles ALTER TABLE photographer_profiles DROP COLUMN IF EXISTS display_name; ALTER TABLE photographer_profiles DROP COLUMN IF EXISTS bio; ALTER TABLE photographer_profiles DROP COLUMN IF EXISTS location; ALTER TABLE photographer_profiles DROP COLUMN IF EXISTS status; ALTER TABLE photographer_profiles DROP COLUMN IF EXISTS rejection_reason; ALTER TABLE photographer_profiles DROP COLUMN IF EXISTS approved_at; ALTER TABLE tutor_profiles DROP COLUMN IF EXISTS display_name; ALTER TABLE tutor_profiles DROP COLUMN IF EXISTS bio; ALTER TABLE tutor_profiles DROP COLUMN IF EXISTS location; ALTER TABLE tutor_profiles DROP COLUMN IF EXISTS status; ALTER TABLE tutor_profiles DROP COLUMN IF EXISTS rejection_reason; ALTER TABLE tutor_profiles DROP COLUMN IF EXISTS approved_at; ALTER TABLE makeup_artist_profiles DROP COLUMN IF EXISTS display_name; ALTER TABLE makeup_artist_profiles DROP COLUMN IF EXISTS bio; ALTER TABLE makeup_artist_profiles DROP COLUMN IF EXISTS location; ALTER TABLE makeup_artist_profiles DROP COLUMN IF EXISTS status; ALTER TABLE makeup_artist_profiles DROP COLUMN IF EXISTS rejection_reason; ALTER TABLE makeup_artist_profiles DROP COLUMN IF EXISTS approved_at; ALTER TABLE developer_profiles DROP COLUMN IF EXISTS display_name; ALTER TABLE developer_profiles DROP COLUMN IF EXISTS bio; ALTER TABLE developer_profiles DROP COLUMN IF EXISTS location; ALTER TABLE developer_profiles DROP COLUMN IF EXISTS status; ALTER TABLE developer_profiles DROP COLUMN IF EXISTS rejection_reason; ALTER TABLE developer_profiles DROP COLUMN IF EXISTS approved_at; ALTER TABLE video_editor_profiles DROP COLUMN IF EXISTS display_name; ALTER TABLE video_editor_profiles DROP COLUMN IF EXISTS bio; ALTER TABLE video_editor_profiles DROP COLUMN IF EXISTS location; ALTER TABLE video_editor_profiles DROP COLUMN IF EXISTS status; ALTER TABLE video_editor_profiles DROP COLUMN IF EXISTS rejection_reason; ALTER TABLE video_editor_profiles DROP COLUMN IF EXISTS approved_at; ALTER TABLE graphic_designer_profiles DROP COLUMN IF EXISTS display_name; ALTER TABLE graphic_designer_profiles DROP COLUMN IF EXISTS bio; ALTER TABLE graphic_designer_profiles DROP COLUMN IF EXISTS location; ALTER TABLE graphic_designer_profiles DROP COLUMN IF EXISTS status; ALTER TABLE graphic_designer_profiles DROP COLUMN IF EXISTS rejection_reason; ALTER TABLE graphic_designer_profiles DROP COLUMN IF EXISTS approved_at; ALTER TABLE social_media_manager_profiles DROP COLUMN IF EXISTS display_name; ALTER TABLE social_media_manager_profiles DROP COLUMN IF EXISTS bio; ALTER TABLE social_media_manager_profiles DROP COLUMN IF EXISTS location; ALTER TABLE social_media_manager_profiles DROP COLUMN IF EXISTS status; ALTER TABLE social_media_manager_profiles DROP COLUMN IF EXISTS rejection_reason; ALTER TABLE social_media_manager_profiles DROP COLUMN IF EXISTS approved_at; ALTER TABLE fitness_trainer_profiles DROP COLUMN IF EXISTS display_name; ALTER TABLE fitness_trainer_profiles DROP COLUMN IF EXISTS bio; ALTER TABLE fitness_trainer_profiles DROP COLUMN IF EXISTS location; ALTER TABLE fitness_trainer_profiles DROP COLUMN IF EXISTS status; ALTER TABLE fitness_trainer_profiles DROP COLUMN IF EXISTS rejection_reason; ALTER TABLE fitness_trainer_profiles DROP COLUMN IF EXISTS approved_at; ALTER TABLE catering_service_profiles DROP COLUMN IF EXISTS bio; ALTER TABLE catering_service_profiles DROP COLUMN IF EXISTS location; ALTER TABLE catering_service_profiles DROP COLUMN IF EXISTS status; ALTER TABLE catering_service_profiles DROP COLUMN IF EXISTS rejection_reason; ALTER TABLE catering_service_profiles DROP COLUMN IF EXISTS approved_at; ALTER TABLE ugc_content_creator_profiles DROP COLUMN IF EXISTS display_name; ALTER TABLE ugc_content_creator_profiles DROP COLUMN IF EXISTS bio; ALTER TABLE ugc_content_creator_profiles DROP COLUMN IF EXISTS location; ALTER TABLE ugc_content_creator_profiles DROP COLUMN IF EXISTS status; ALTER TABLE ugc_content_creator_profiles DROP COLUMN IF EXISTS rejection_reason; ALTER TABLE ugc_content_creator_profiles DROP COLUMN IF EXISTS approved_at; COMMIT; -- ============================================================================ -- Migration Complete -- ============================================================================