{"views":[{"name":"admin_action_logs","schema":"public","definition":" SELECT id,\n    user_id AS admin_user_id,\n    event_action AS action_type,\n        CASE\n            WHEN resource_type = 'user'::text AND resource_id ~ '^[0-9a-f-]{36}$'::text THEN resource_id::uuid\n            ELSE NULL::uuid\n        END AS target_user_id,\n    tenant_id AS target_tenant_id,\n    metadata,\n    ip_address,\n    user_agent,\n    \"timestamp\",\n    created_at\n   FROM comprehensive_audit_logs\n  WHERE event_category = 'admin'::text;"},{"name":"audit_logs","schema":"public","definition":" SELECT id,\n    \"timestamp\",\n    user_id,\n    tenant_id,\n    event_action AS action,\n    COALESCE(resource_type, 'unknown'::text) AS resource_type,\n    resource_id,\n    old_value,\n    new_value,\n    ip_address,\n    user_agent,\n    session_id,\n    metadata,\n    severity,\n    created_at\n   FROM comprehensive_audit_logs;"},{"name":"business_activity_ledger","schema":"public","definition":" SELECT a.id,\n    a.tenant_org_id,\n    t.name AS tenant_name,\n    a.contact_id,\n    a.user_id,\n    a.actor_role,\n    a.event_domain,\n    a.activity_type,\n    a.title,\n    a.description,\n    a.related_entity_type,\n    a.related_entity_id,\n    a.correlation_key,\n    a.source_channel,\n    a.touch_channel,\n    a.source_detail,\n    a.source_campaign,\n    a.source_referrer,\n    a.source_system,\n    a.source_record_type,\n    a.source_record_id,\n    a.previous_state,\n    a.new_state,\n    a.reason_code,\n    a.monetary_value,\n    a.currency,\n    a.outcome,\n    a.corrects_event_id,\n    a.dedupe_key,\n    a.importance,\n    a.is_system_generated,\n    a.metadata,\n    a.created_at AS occurred_at,\n    a.recorded_at\n   FROM activity_timeline a\n     JOIN tenants t ON t.id = a.tenant_org_id;"},{"name":"business_attention_feed","schema":"public","definition":" SELECT a.id,\n    a.tenant_id,\n    a.opportunity_id,\n    a.kind,\n    a.priority,\n    a.state,\n    a.title,\n    a.summary,\n    a.due_at,\n    a.due_at IS NOT NULL AND a.due_at < now() AS is_overdue,\n    a.action_route,\n    a.source_state,\n    a.acknowledged_at,\n    a.created_at,\n    a.updated_at,\n    o.contact_id,\n    o.category,\n    o.lifecycle_state,\n    o.proposal_state,\n    o.payment_state,\n    o.fulfillment_state,\n    o.estimated_value,\n    o.quoted_amount,\n    o.balance_amount\n   FROM business_attention_items a\n     JOIN business_opportunities o ON o.id = a.opportunity_id AND o.tenant_id = a.tenant_id\n  WHERE a.state = ANY (ARRAY['open'::text, 'acknowledged'::text]);"},{"name":"business_contact_attribution","schema":"public","definition":" WITH first_source AS (\n         SELECT DISTINCT ON (activity_timeline.tenant_org_id, activity_timeline.contact_id) activity_timeline.tenant_org_id,\n            activity_timeline.contact_id,\n            activity_timeline.source_channel AS first_touch_source,\n            activity_timeline.source_detail AS first_touch_detail,\n            activity_timeline.source_campaign AS first_campaign,\n            activity_timeline.source_referrer AS first_referrer,\n            activity_timeline.created_at AS first_touch_at\n           FROM activity_timeline\n          WHERE activity_timeline.contact_id IS NOT NULL AND activity_timeline.source_channel IS NOT NULL AND activity_timeline.source_channel <> 'Unknown'::text\n          ORDER BY activity_timeline.tenant_org_id, activity_timeline.contact_id, activity_timeline.created_at, activity_timeline.id\n        ), latest_source AS (\n         SELECT DISTINCT ON (activity_timeline.tenant_org_id, activity_timeline.contact_id) activity_timeline.tenant_org_id,\n            activity_timeline.contact_id,\n            activity_timeline.source_channel AS latest_touch_source,\n            activity_timeline.source_detail AS latest_touch_detail,\n            activity_timeline.source_campaign AS latest_campaign,\n            activity_timeline.source_referrer AS latest_referrer,\n            activity_timeline.created_at AS latest_source_at\n           FROM activity_timeline\n          WHERE activity_timeline.contact_id IS NOT NULL AND activity_timeline.source_channel IS NOT NULL AND activity_timeline.source_channel <> 'Unknown'::text\n          ORDER BY activity_timeline.tenant_org_id, activity_timeline.contact_id, activity_timeline.created_at DESC, activity_timeline.id DESC\n        ), latest_touch AS (\n         SELECT DISTINCT ON (activity_timeline.tenant_org_id, activity_timeline.contact_id) activity_timeline.tenant_org_id,\n            activity_timeline.contact_id,\n            activity_timeline.touch_channel AS latest_touch_channel,\n            activity_timeline.created_at AS latest_touch_at\n           FROM activity_timeline\n          WHERE activity_timeline.contact_id IS NOT NULL AND activity_timeline.touch_channel IS NOT NULL\n          ORDER BY activity_timeline.tenant_org_id, activity_timeline.contact_id, activity_timeline.created_at DESC, activity_timeline.id DESC\n        ), activity AS (\n         SELECT activity_timeline.tenant_org_id,\n            activity_timeline.contact_id,\n            count(*) AS activity_count,\n            max(activity_timeline.created_at) AS last_activity_at,\n            COALESCE(sum(activity_timeline.monetary_value) FILTER (WHERE activity_timeline.event_domain = 'revenue'::text AND (lower(COALESCE(activity_timeline.outcome, ''::text)) = ANY (ARRAY['paid'::text, 'collected'::text]))), 0::numeric)::numeric(14,2) AS collected_revenue\n           FROM activity_timeline\n          WHERE activity_timeline.contact_id IS NOT NULL\n          GROUP BY activity_timeline.tenant_org_id, activity_timeline.contact_id\n        )\n SELECT c.tenant_org_id::uuid AS tenant_org_id,\n    c.id AS contact_id,\n    COALESCE(f.first_touch_source, normalize_business_source(COALESCE(c.raw_data #>> '{acquisition,source}'::text[], c.source, c.lead_origin, c.referral_source, c.import_source), c.raw_data)) AS first_touch_source,\n    f.first_touch_detail,\n    f.first_campaign,\n    f.first_referrer,\n    COALESCE(f.first_touch_at, c.source_created_date, c.created_at) AS first_touch_at,\n    COALESCE(l.latest_touch_source, f.first_touch_source, normalize_business_source(COALESCE(c.raw_data #>> '{acquisition,source}'::text[], c.source, c.lead_origin, c.referral_source, c.import_source), c.raw_data)) AS latest_touch_source,\n    l.latest_touch_detail,\n    l.latest_campaign,\n    l.latest_referrer,\n    COALESCE(l.latest_source_at, f.first_touch_at, c.source_created_date, c.created_at) AS latest_source_at,\n    x.latest_touch_channel,\n    x.latest_touch_at,\n    COALESCE(a.activity_count, 0::bigint) AS activity_count,\n    COALESCE(a.last_activity_at, c.updated_at, c.created_at) AS last_activity_at,\n    COALESCE(a.collected_revenue, 0::numeric)::numeric(14,2) AS collected_revenue\n   FROM unified_contacts c\n     JOIN tenants t ON t.id::text = c.tenant_org_id\n     LEFT JOIN first_source f ON f.tenant_org_id = t.id AND f.contact_id = c.id\n     LEFT JOIN latest_source l ON l.tenant_org_id = t.id AND l.contact_id = c.id\n     LEFT JOIN latest_touch x ON x.tenant_org_id = t.id AND x.contact_id = c.id\n     LEFT JOIN activity a ON a.tenant_org_id = t.id AND a.contact_id = c.id;"},{"name":"business_tenant_activity_summary","schema":"public","definition":" SELECT t.id AS tenant_id,\n    t.name AS tenant_name,\n    count(a.id) AS activity_count,\n    count(DISTINCT a.contact_id) FILTER (WHERE a.contact_id IS NOT NULL) AS tracked_contacts,\n    count(DISTINCT a.contact_id) FILTER (WHERE a.contact_id IS NOT NULL AND a.source_channel IS NOT NULL AND a.source_channel <> 'Unknown'::text) AS attributed_contacts,\n    max(a.created_at) AS last_activity_at,\n    COALESCE(sum(a.monetary_value) FILTER (WHERE a.event_domain = 'revenue'::text AND (lower(COALESCE(a.outcome, ''::text)) = ANY (ARRAY['paid'::text, 'collected'::text]))), 0::numeric)::numeric(14,2) AS collected_revenue\n   FROM tenants t\n     LEFT JOIN activity_timeline a ON a.tenant_org_id = t.id\n  GROUP BY t.id, t.name;"},{"name":"card_grading_population_report","schema":"public","definition":" SELECT tenant_id,\n    category,\n    year,\n    manufacturer,\n    set_name,\n    brand_set,\n    subset,\n    player_character,\n    card_number,\n    variation,\n    serial_number,\n    autograph_present,\n    relic_present,\n    final_grade,\n    grade_label,\n    count(*) AS pop_count\n   FROM card_grading_certificates c\n  WHERE (tenant_id <> '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid OR cert_number ~ '^[0-9]{5}$'::text) AND published_at IS NOT NULL AND (card_id IS NULL OR (EXISTS ( SELECT 1\n           FROM card_grading_cards k\n          WHERE k.id = c.card_id AND k.tenant_id = c.tenant_id AND k.deleted_at IS NULL))) AND NOT (EXISTS ( SELECT 1\n           FROM pcg_card_publication_revocations r\n          WHERE r.tenant_id = c.tenant_id AND (r.card_id = c.card_id OR r.cert_number IS NOT NULL AND r.cert_number = c.cert_number)))\n  GROUP BY tenant_id, category, year, manufacturer, set_name, brand_set, subset, player_character, card_number, variation, serial_number, autograph_present, relic_present, final_grade, grade_label;"},{"name":"card_grading_public_certificates","schema":"public","definition":" SELECT tenant_id,\n    cert_number,\n    category,\n    year,\n    manufacturer,\n    set_name,\n    brand_set,\n    subset,\n    player_character,\n    card_number,\n    variation,\n    serial_number,\n    autograph_present,\n    relic_present,\n    final_grade,\n    grade_label,\n    final_image_url,\n    finalized_at,\n    published_at\n   FROM ( SELECT c.tenant_id,\n            c.cert_number,\n            c.category,\n            c.year,\n            c.manufacturer,\n            c.set_name,\n            c.brand_set,\n            c.subset,\n            c.player_character,\n            c.card_number,\n            c.variation,\n            c.serial_number,\n            c.autograph_present,\n            c.relic_present,\n            c.final_grade,\n            c.grade_label,\n            c.final_image_url,\n            c.finalized_at,\n            c.published_at\n           FROM card_grading_certificates c\n          WHERE c.published_at IS NOT NULL AND (c.card_id IS NULL OR (EXISTS ( SELECT 1\n                   FROM card_grading_cards k\n                  WHERE k.id = c.card_id AND k.tenant_id = c.tenant_id AND k.deleted_at IS NULL))) AND NOT (EXISTS ( SELECT 1\n                   FROM pcg_card_publication_revocations r\n                  WHERE r.tenant_id = c.tenant_id AND (r.card_id = c.card_id OR r.cert_number IS NOT NULL AND r.cert_number = c.cert_number)))) public_safe\n  WHERE tenant_id <> '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid OR cert_number ~ '^[0-9]{5}$'::text;"},{"name":"contacts_with_tenants","schema":"public","definition":" SELECT uc.id,\n    uc.name,\n    uc.first_name,\n    uc.last_name,\n    uc.phone,\n    uc.email,\n    uc.second_email,\n    uc.address,\n    uc.address2,\n    uc.address3,\n    uc.address4,\n    uc.city,\n    uc.state,\n    uc.zip,\n    uc.lat,\n    uc.lng,\n    uc.geocoded_at,\n    uc.carrier,\n    uc.carrier_name,\n    uc.policy_number,\n    uc.policy_number2,\n    uc.policy_number3,\n    uc.policy_number4,\n    uc.claim_number,\n    uc.claim_number2,\n    uc.claim_number3,\n    uc.claim_number4,\n    uc.dol,\n    uc.claim_notes,\n    uc.adjuster_name,\n    uc.adjuster_phone,\n    uc.adjuster_email,\n    uc.assigned_estimator,\n    uc.estimator_phone,\n    uc.roof_type,\n    uc.roof_age,\n    uc.property_data,\n    uc.property_square_feet,\n    uc.property_parcel_id,\n    uc.property_data_fetched_at,\n    uc.property_owner_name,\n    uc.property_assessed_value,\n    uc.property_bedrooms,\n    uc.property_bathrooms,\n    uc.property_year_built,\n    uc.property_lot_size,\n    uc.property_data_jurisdiction,\n    uc.property_data_source,\n    uc.property_zoning,\n    uc.property_land_use,\n    uc.property_market_value,\n    uc.property_tax_amount,\n    uc.property_last_sale_date,\n    uc.property_last_sale_price,\n    uc.normalized_phone,\n    uc.normalized_email,\n    uc.normalized_address,\n    uc.permit_data,\n    uc.permit_scanned_at,\n    uc.has_recent_roof_permit,\n    uc.roof_permit_finaled_date,\n    uc.raw_data,\n    uc.link_group_id,\n    ctm.tenant_id::text AS tenant_org_id,\n    ctm.assigned_to,\n    ctm.assigned_rep,\n    ctm.assigned_user,\n    ctm.status,\n    ctm.contact_status,\n    ctm.service_status,\n    ctm.lead_stage,\n    ctm.jobs_stage,\n    ctm.claim_stage,\n    ctm.graduated_at,\n    ctm.appt_date,\n    ctm.appt_time,\n    ctm.notes,\n    ctm.notes2,\n    ctm.notes3,\n    ctm.notes4,\n    ctm.additional_notes,\n    ctm.source,\n    ctm.priority,\n    ctm.quality_score,\n    ctm.lead_score,\n    ctm.lead_tags,\n    ctm.claim_status,\n    ctm.insurance_claim_status,\n    ctm.estimate_status,\n    ctm.job_value,\n    ctm.work_classification,\n    ctm.salesperson_number,\n    ctm.contact_role,\n    ctm.lead_id,\n    ctm.contact_ref,\n    ctm.last_touched_at,\n    ctm.last_contact,\n    ctm.deleted_at,\n    ctm.deleted_by,\n    ctm.deletion_reason,\n    ctm.created_at AS membership_created_at,\n    ctm.updated_at AS membership_updated_at\n   FROM unified_contacts uc\n     JOIN contact_tenant_memberships ctm ON ctm.contact_id = uc.id;"},{"name":"dnc_compliance_summary","schema":"public","definition":" SELECT (( SELECT count(*) AS count\n           FROM lead_deck\n          WHERE lead_deck.phone IS NOT NULL AND lead_deck.phone <> ''::text)) + (( SELECT count(*) AS count\n           FROM unified_contacts\n          WHERE unified_contacts.phone IS NOT NULL AND unified_contacts.phone <> ''::text)) AS total_leads_with_phone,\n    (( SELECT count(*) AS count\n           FROM lead_deck\n          WHERE lead_deck.dnc_checked_at >= (now() - '31 days'::interval))) + (( SELECT count(*) AS count\n           FROM unified_contacts\n          WHERE unified_contacts.dnc_checked_at >= (now() - '31 days'::interval))) AS leads_scanned_recently,\n    ( SELECT count(*) AS count\n           FROM dnc_leads_due_for_rescan) AS leads_due_for_rescan,\n    (( SELECT count(*) AS count\n           FROM lead_deck\n          WHERE lead_deck.is_dnc = true)) + (( SELECT count(*) AS count\n           FROM unified_contacts\n          WHERE unified_contacts.is_dnc = true)) AS total_dnc_quarantined,\n    ( SELECT max(dnc_audit_runs.completed_at) AS max\n           FROM dnc_audit_runs\n          WHERE dnc_audit_runs.status = 'completed'::text) AS last_successful_scan,\n    ( SELECT min(dnc_audit_runs.started_at) AS min\n           FROM dnc_audit_runs\n          WHERE dnc_audit_runs.status = 'running'::text) AS oldest_running_scan;"},{"name":"dnc_leads_due_for_rescan","schema":"public","definition":" SELECT ld.id AS lead_id,\n    'lead_deck'::text AS lead_table,\n    ld.phone,\n    ld.dnc_checked_at,\n    ld.is_dnc,\n    ld.tenant_org_id,\n    EXTRACT(epoch FROM now() - COALESCE(ld.dnc_checked_at, ld.created_at)) / 86400::numeric AS days_since_check\n   FROM lead_deck ld\n  WHERE ld.phone IS NOT NULL AND ld.phone <> ''::text AND (ld.dnc_checked_at IS NULL OR ld.dnc_checked_at < (now() - '31 days'::interval))\nUNION ALL\n SELECT uc.id AS lead_id,\n    'unified_contacts'::text AS lead_table,\n    uc.phone,\n    uc.dnc_checked_at,\n    uc.is_dnc,\n    uc.tenant_org_id,\n    EXTRACT(epoch FROM now() - COALESCE(uc.dnc_checked_at, uc.created_at)) / 86400::numeric AS days_since_check\n   FROM unified_contacts uc\n  WHERE uc.phone IS NOT NULL AND uc.phone <> ''::text AND (uc.dnc_checked_at IS NULL OR uc.dnc_checked_at < (now() - '31 days'::interval));"},{"name":"entitlements_view","schema":"public","definition":" SELECT ts.tenant_id,\n    ts.plan_id,\n    p.slug AS plan_slug,\n    p.name AS plan_name,\n    p.tier AS plan_tier,\n    ts.status AS subscription_status,\n    ts.trial_ends_at,\n    ts.seat_count,\n    p.included_seats,\n    ts.billing_cycle,\n    pf.feature_key,\n    pf.limit_value,\n    pf.is_boolean\n   FROM tenant_subscriptions ts\n     JOIN plans p ON p.id = ts.plan_id\n     LEFT JOIN plan_features pf ON pf.plan_id = p.id;"},{"name":"incoming_users","schema":"public","definition":" SELECT ui.id,\n    ui.email,\n    ui.name,\n    ui.tenant_id,\n    ui.role,\n    ui.status,\n    ui.created_at,\n    ui.expires_at,\n    'invitation'::text AS source,\n    ui.invited_by AS source_user_id\n   FROM user_invitations ui\n  WHERE ui.status = 'pending'::text\nUNION ALL\n SELECT ps.id,\n    ps.email,\n    ps.full_name AS name,\n    NULL::uuid AS tenant_id,\n    ps.role,\n    ps.status,\n    ps.created_at,\n    ps.expires_at,\n    'self_signup'::text AS source,\n    ps.created_by AS source_user_id\n   FROM pending_signups ps\n  WHERE ps.status = ANY (ARRAY['pending'::text, 'pending_agreement'::text, 'pending_approval'::text]);"},{"name":"invoice_payment_reconciliation","schema":"public","definition":" SELECT i.id AS invoice_id,\n    i.tenant_org_id,\n    i.status,\n    i.amount AS invoice_total,\n    COALESCE(sum(\n        CASE\n            WHEN a.entry_kind = 'allocation'::text THEN a.amount\n            WHEN a.entry_kind = 'reversal'::text THEN - a.amount\n            ELSE 0::numeric\n        END), 0::numeric)::numeric(14,2) AS allocated_amount,\n        CASE\n            WHEN lower(COALESCE(i.status, ''::text)) = 'paid'::text THEN 0::numeric\n            WHEN lower(COALESCE(i.status, ''::text)) = ANY (ARRAY['void'::text, 'cancelled'::text]) THEN 0::numeric\n            WHEN lower(COALESCE(i.status, ''::text)) = 'partially_paid'::text AND count(a.id) = 0 THEN NULL::numeric\n            ELSE GREATEST(0::numeric, i.amount - COALESCE(sum(\n            CASE\n                WHEN a.entry_kind = 'allocation'::text THEN a.amount\n                WHEN a.entry_kind = 'reversal'::text THEN - a.amount\n                ELSE 0::numeric\n            END), 0::numeric))::numeric(14,2)\n        END AS balance_due,\n        CASE\n            WHEN lower(COALESCE(i.status, ''::text)) = 'paid'::text AND COALESCE(sum(\n            CASE\n                WHEN a.entry_kind = 'allocation'::text THEN a.amount\n                WHEN a.entry_kind = 'reversal'::text THEN - a.amount\n                ELSE 0::numeric\n            END), 0::numeric) < i.amount THEN 'historical_paid_unmatched'::text\n            WHEN lower(COALESCE(i.status, ''::text)) = 'partially_paid'::text AND count(a.id) = 0 THEN 'partial_needs_reconciliation'::text\n            WHEN COALESCE(sum(\n            CASE\n                WHEN a.entry_kind = 'allocation'::text THEN a.amount\n                WHEN a.entry_kind = 'reversal'::text THEN - a.amount\n                ELSE 0::numeric\n            END), 0::numeric) > 0::numeric THEN 'allocation_recorded'::text\n            ELSE 'unallocated'::text\n        END AS reconciliation_state\n   FROM invoices i\n     LEFT JOIN invoice_payment_allocations a ON a.invoice_id = i.id AND a.tenant_id::text = i.tenant_org_id\n  WHERE i.document_kind = 'invoice'::text\n  GROUP BY i.id, i.tenant_org_id, i.status, i.amount;"},{"name":"jobs_crew_view","schema":"public","definition":" SELECT id,\n    tenant_id,\n    job_number,\n    job_type,\n    priority,\n    status,\n    assigned_crew_id,\n    assigned_pm_id,\n    scheduled_date,\n    scheduled_time,\n    appointment_date,\n    started_at,\n    completed_at,\n    property_address,\n    city,\n    state,\n    zip,\n    latitude,\n    longitude,\n    split_part(COALESCE(customer_name, ''::text), ' '::text, 1) AS customer_first_name,\n    special_instructions,\n    crew_notes,\n    work_auth_signed,\n    tarp_installed,\n    photos_uploaded,\n    docs_complete,\n    created_at,\n    updated_at\n   FROM jobs j\n  WHERE (EXISTS ( SELECT 1\n           FROM user_tenant_memberships m\n          WHERE m.user_id = uid() AND m.tenant_id = j.tenant_id AND m.status = 'active'::text)) AND (is_manager_or_higher_strict(uid(), tenant_id) OR has_acting_pm_grant(uid(), tenant_id) OR assigned_pm_id = uid() OR assigned_crew_id = uid());"},{"name":"jobs_package_readiness","schema":"public","definition":" SELECT id AS job_id,\n    tenant_id,\n    job_number,\n    status AS job_status,\n    verified_at,\n    contact_claim_id,\n    work_auth_signed,\n    photos_uploaded,\n    docs_complete,\n    verified_at IS NOT NULL AS pm_verified,\n    tarping_invoice_id IS NOT NULL AS invoice_present,\n    COALESCE(carrier_name, ''::text) <> ''::text AS carrier_present,\n    COALESCE(policy_number, ''::text) <> ''::text AS policy_present,\n    COALESCE(claim_number, ''::text) <> ''::text AS claim_present,\n    COALESCE(property_address, ''::text) <> ''::text AND COALESCE(customer_name, ''::text) <> ''::text AS contact_present,\n    work_auth_signed AND photos_uploaded AND docs_complete AND verified_at IS NOT NULL AND tarping_invoice_id IS NOT NULL AND COALESCE(carrier_name, ''::text) <> ''::text AND COALESCE(policy_number, ''::text) <> ''::text AND COALESCE(claim_number, ''::text) <> ''::text AS package_ready\n   FROM jobs j;"},{"name":"lead_deck_compat","schema":"public","definition":" SELECT id,\n    lead_id,\n    name,\n    phone,\n    email,\n    address,\n    city,\n    state,\n    zip,\n    status,\n    priority,\n    source,\n    assigned_to,\n    tenant_org_id,\n    notes,\n    created_at,\n    updated_at,\n    deleted_at,\n    deleted_by,\n    deletion_reason,\n    property_data,\n    property_square_feet,\n    property_parcel_id,\n    property_data_fetched_at,\n    property_owner_name,\n    property_assessed_value,\n    property_bedrooms,\n    property_bathrooms,\n    property_year_built,\n    property_lot_size,\n    COALESCE(property_data ->> 'property_data_jurisdiction'::text, NULL::text)::character varying AS property_data_jurisdiction,\n    lead_stage,\n    graduated_at,\n    lat,\n    lng,\n    geocoded_at,\n    geocode_confidence,\n    archived_at,\n    lost_at,\n    dnc_at\n   FROM unified_contacts\n  WHERE graduated_at IS NULL AND assigned_to IS NULL AND deleted_at IS NULL;"},{"name":"lead_timeline","schema":"public","definition":" SELECT 'call:'::text || cl.id AS event_id,\n    cl.tenant_id AS tenant_org_id,\n    COALESCE(cl.contact_id::text, cl.lead_id) AS lead_id,\n    'call'::text AS kind,\n    cl.outcome::text AS subkind,\n    cl.created_at AS occurred_at,\n    cl.user_id AS actor_user_id,\n    COALESCE(NULLIF(cl.notes, ''::text), 'Call '::text || COALESCE(cl.outcome::text, 'logged'::text)) AS title,\n    cl.transcript AS body,\n    jsonb_build_object('direction', cl.direction, 'duration_seconds', cl.duration_seconds, 'recording_url', cl.recording_url, 'twilio_status', cl.twilio_status, 'phone', cl.phone_called) AS metadata\n   FROM call_logs cl\nUNION ALL\n SELECT 'sms:'::text || sh.id AS event_id,\n    sh.tenant_id AS tenant_org_id,\n    sh.contact_id::text AS lead_id,\n    'sms'::text AS kind,\n    sh.direction AS subkind,\n    sh.created_at AS occurred_at,\n    sh.user_id AS actor_user_id,\n        CASE\n            WHEN sh.direction = 'outbound'::text THEN 'SMS sent'::text\n            ELSE 'SMS received'::text\n        END AS title,\n    sh.body,\n    jsonb_build_object('from', sh.from_number, 'to', sh.to_number, 'status', sh.status, 'twilio_sid', sh.twilio_sid) AS metadata\n   FROM sms_history sh\nUNION ALL\n SELECT 'lane:'::text || la.id AS event_id,\n    la.tenant_org_id,\n    la.lead_id::text AS lead_id,\n    'lane'::text AS kind,\n    la.to_state::text AS subkind,\n    la.created_at AS occurred_at,\n    la.actor_user_id,\n    'Lane → '::text || la.to_state::text AS title,\n    COALESCE(la.notes, la.disclosure_text) AS body,\n    jsonb_build_object('from_state', la.from_state, 'to_state', la.to_state, 'disclosure', la.disclosure_text) AS metadata\n   FROM lead_lane_audit la\nUNION ALL\n SELECT 'compliance:'::text || ce.id AS event_id,\n        CASE\n            WHEN ce.tenant_org_id ~* '^[0-9a-f-]{36}$'::text THEN ce.tenant_org_id::uuid\n            ELSE NULL::uuid\n        END AS tenant_org_id,\n    ce.lead_id,\n    'compliance'::text AS kind,\n    ce.check_type AS subkind,\n    ce.checked_at AS occurred_at,\n    ce.checked_by AS actor_user_id,\n    (ce.check_type || ' → '::text) || COALESCE(ce.decision, ce.result, 'logged'::text) AS title,\n    ce.reason AS body,\n    jsonb_build_object('provider', ce.provider, 'result', ce.result, 'decision', ce.decision, 'phone', ce.phone_number) AS metadata\n   FROM communication_compliance_events ce\nUNION ALL\n SELECT 'note:'::text || cn.id AS event_id,\n    cn.tenant_org_id,\n    cn.contact_id::text AS lead_id,\n    'note'::text AS kind,\n    COALESCE(cn.note_type, 'note'::text) AS subkind,\n    cn.created_at AS occurred_at,\n    cn.user_id AS actor_user_id,\n    COALESCE(cn.user_name, cn.user_email, 'Note'::text) AS title,\n    cn.content AS body,\n    jsonb_build_object('claim_id', cn.claim_id) AS metadata\n   FROM contact_notes cn\nUNION ALL\n SELECT 'activity:'::text || al.id AS event_id,\n        CASE\n            WHEN al.tenant_id ~* '^[0-9a-f-]{36}$'::text THEN al.tenant_id::uuid\n            ELSE NULL::uuid\n        END AS tenant_org_id,\n    al.contact_id AS lead_id,\n    'activity'::text AS kind,\n    al.activity_type AS subkind,\n    al.created_at AS occurred_at,\n    al.user_id AS actor_user_id,\n    al.title,\n    al.description AS body,\n    al.metadata\n   FROM activity_log al;"},{"name":"pcg_public_canonical_cards","schema":"public","definition":" SELECT id,\n    tenant_id,\n    submission_id,\n    cert_number,\n    sequence_number,\n    category,\n    year,\n    brand_set,\n    player_character,\n    card_number,\n    variation,\n    declared_value,\n    grade,\n    grade_label,\n    status,\n    front_image_url,\n    back_image_url,\n    slab_image_url,\n    grader_notes,\n    population_count,\n    created_at,\n    updated_at,\n    import_key,\n    metadata,\n    is_demo,\n    card_description,\n    autograph_present,\n    manufacturer,\n    set_name,\n    subset,\n    serial_number,\n    relic_present,\n    identified_at,\n    identified_by,\n    finalized_at,\n    slab_back_image_url,\n    pcg_submission_number,\n    pcg_submission_year,\n    publish_to_website,\n    publish_to_ebay,\n    sale_price,\n    publish_intent_updated_at,\n    internal_notes,\n    front_notes,\n    back_notes,\n    deleted_at,\n    deleted_by,\n    deletion_reason,\n    restored_at,\n    restored_by,\n    restore_reason\n   FROM ( SELECT c.id,\n            c.tenant_id,\n            c.submission_id,\n            c.cert_number,\n            c.sequence_number,\n            c.category,\n            c.year,\n            c.brand_set,\n            c.player_character,\n            c.card_number,\n            c.variation,\n            c.declared_value,\n            c.grade,\n            c.grade_label,\n            c.status,\n            c.front_image_url,\n            c.back_image_url,\n            c.slab_image_url,\n            c.grader_notes,\n            c.population_count,\n            c.created_at,\n            c.updated_at,\n            c.import_key,\n            c.metadata,\n            c.is_demo,\n            c.card_description,\n            c.autograph_present,\n            c.manufacturer,\n            c.set_name,\n            c.subset,\n            c.serial_number,\n            c.relic_present,\n            c.identified_at,\n            c.identified_by,\n            c.finalized_at,\n            c.slab_back_image_url,\n            c.pcg_submission_number,\n            c.pcg_submission_year,\n            c.publish_to_website,\n            c.publish_to_ebay,\n            c.sale_price,\n            c.publish_intent_updated_at,\n            c.internal_notes,\n            c.front_notes,\n            c.back_notes,\n            c.deleted_at,\n            c.deleted_by,\n            c.deletion_reason,\n            c.restored_at,\n            c.restored_by,\n            c.restore_reason\n           FROM card_grading_cards c\n          WHERE c.deleted_at IS NULL AND NOT (EXISTS ( SELECT 1\n                   FROM pcg_card_publication_revocations r\n                  WHERE r.tenant_id = c.tenant_id AND r.card_id = c.id))) public_safe\n  WHERE tenant_id <> '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid OR cert_number ~ '^[0-9]{5}$'::text;"},{"name":"pcg_public_legacy_rows","schema":"public","definition":" SELECT id,\n    batch_id,\n    tenant_id,\n    row_number,\n    external_key,\n    import_key,\n    source_url,\n    raw_payload,\n    normalized_payload,\n    validation_status,\n    planned_action,\n    canonical_submission_id,\n    canonical_card_id,\n    error_text,\n    created_at,\n    updated_at\n   FROM pcg_import_rows r\n  WHERE NOT (EXISTS ( SELECT 1\n           FROM pcg_card_publication_revocations tombstone\n          WHERE tombstone.tenant_id = r.tenant_id AND (tombstone.card_id = r.canonical_card_id OR tombstone.cert_number IS NOT NULL AND tombstone.cert_number =\n                CASE\n                    WHEN COALESCE(r.normalized_payload ->> 'cert_number'::text, ''::text) ~ '^[0-9]{4}$'::text THEN lpad(r.normalized_payload ->> 'cert_number'::text, 5, '0'::text)\n                    ELSE r.normalized_payload ->> 'cert_number'::text\n                END))) AND (canonical_card_id IS NULL OR (EXISTS ( SELECT 1\n           FROM card_grading_cards card\n          WHERE card.id = r.canonical_card_id AND card.tenant_id = r.tenant_id AND card.deleted_at IS NULL))) AND (tenant_id <> '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid OR COALESCE(normalized_payload ->> 'cert_number'::text, ''::text) ~ '^[0-9]{5}$'::text AND (EXISTS ( SELECT 1\n           FROM card_grading_public_certificates published\n          WHERE published.tenant_id = r.tenant_id AND published.cert_number = (r.normalized_payload ->> 'cert_number'::text))));"},{"name":"platform_storage_catalog","schema":"public","definition":" SELECT bucket_id,\n    namespace,\n    domain,\n    purpose,\n    owner_tenant_id,\n    owner_tenant_slug,\n    canonical_path_contract,\n    visibility,\n    lifecycle,\n    retention_class,\n    managed_by,\n    status,\n    architecture_version,\n    object_count,\n    bytes,\n    last_audited_at,\n    namespace = 'legacy_pending'::text OR (status <> ALL (ARRAY['active'::text, 'planned'::text])) AS architecture_attention_required\n   FROM platform_storage_registry;"},{"name":"profiles_safe","schema":"public","definition":" SELECT id,\n    email,\n    name,\n    phone,\n    role,\n    active,\n    company,\n    tenant_org_id,\n    last_login,\n    last_login_at,\n    created_at,\n    updated_at,\n    user_drive_folder_id,\n    drive_provisioned_at,\n    drive_provisioning_status,\n    leaddeck_sheet_id,\n    license_number,\n    tcpa_certified_at\n   FROM profiles;"},{"name":"qr_code_analytics","schema":"public","definition":" SELECT qc.id AS qr_id,\n    qc.tenant_id,\n    qc.campaign_id,\n    qc.short_code,\n    qc.title,\n    qc.type,\n    qc.active,\n    qc.destination_mode,\n    qc.destination_value,\n    count(qe.id) FILTER (WHERE qe.event_type = 'scan'::text) AS scans,\n    count(qe.id) FILTER (WHERE qe.event_type = 'redirect'::text) AS redirects,\n    count(qe.id) FILTER (WHERE qe.event_type = 'conversion'::text) AS conversions,\n    max(qe.created_at) AS last_event_at,\n    qc.created_at\n   FROM qr_codes qc\n     LEFT JOIN qr_events qe ON qe.qr_id = qc.id\n  GROUP BY qc.id;"},{"name":"security_active_user_tenant_memberships","schema":"public","definition":" SELECT id,\n    user_id,\n    tenant_id,\n    status,\n    invited_by,\n    joined_at,\n    last_accessed_at,\n    is_owner\n   FROM user_tenant_memberships\n  WHERE status = 'active'::text;"},{"name":"settlement_invoices","schema":"public","definition":" SELECT id,\n    tenant_org_id,\n    contact_id,\n        CASE\n            WHEN created_by ~* '^[0-9a-f-]{36}$'::text THEN created_by::uuid\n            ELSE NULL::uuid\n        END AS created_by_user_id,\n    invoice_id AS invoice_number,\n    invoice_date,\n    due_date,\n    document_metadata ->> 'template_tone'::text AS template_tone,\n    COALESCE(document_metadata ->> 'homeowner_name'::text, customer_name) AS homeowner_name,\n    document_metadata ->> 'property_address'::text AS property_address,\n    insurance_carrier,\n    claim_number,\n    policy_number,\n    COALESCE((document_metadata ->> 'settlement_amount'::text)::numeric, amount) AS settlement_amount,\n    (document_metadata ->> 'deposit_amount'::text)::numeric AS deposit_amount,\n    (document_metadata ->> 'remaining_balance'::text)::numeric AS remaining_balance,\n    payment_terms,\n    document_metadata ->> 'invoice_html'::text AS invoice_html,\n    notes,\n    document_metadata ->> 'rep_name'::text AS rep_name,\n    document_metadata ->> 'rep_phone'::text AS rep_phone,\n    document_metadata ->> 'rep_email'::text AS rep_email,\n    status,\n    sent_at,\n    paid_at,\n    created_at,\n    updated_at,\n    document_metadata ->> 'city'::text AS city,\n    document_metadata ->> 'state'::text AS state,\n    document_metadata ->> 'zip'::text AS zip,\n    (document_metadata ->> 'original_total'::text)::numeric AS original_total,\n    (document_metadata ->> 'insurance_payment'::text)::numeric AS insurance_payment,\n    (document_metadata ->> 'settlement_discount'::text)::numeric AS settlement_discount\n   FROM invoices i\n  WHERE document_kind = 'invoice'::text AND document_subtype = 'settlement'::text;"},{"name":"tarping_invoices","schema":"public","definition":" SELECT id,\n    tenant_org_id,\n    contact_id,\n        CASE\n            WHEN created_by ~* '^[0-9a-f-]{36}$'::text THEN created_by::uuid\n            ELSE NULL::uuid\n        END AS created_by,\n    invoice_id AS invoice_number,\n    invoice_date,\n    payment_terms AS terms,\n    status,\n    COALESCE(document_metadata ->> 'insured_name'::text, customer_name) AS insured_name,\n    document_metadata ->> 'insured_poa'::text AS insured_poa,\n    document_metadata ->> 'property_address'::text AS property_address,\n    insurance_carrier,\n    claim_number,\n    COALESCE(document_metadata -> 'materials_items'::text, '[]'::jsonb) AS materials_items,\n    COALESCE(document_metadata -> 'labor_items'::text, '[]'::jsonb) AS labor_items,\n    (document_metadata ->> 'materials_subtotal'::text)::numeric AS materials_subtotal,\n    (document_metadata ->> 'labor_subtotal'::text)::numeric AS labor_subtotal,\n    COALESCE((document_metadata ->> 'grand_total'::text)::numeric, amount) AS grand_total,\n    document_metadata ->> 'service_description'::text AS service_description,\n    document_metadata ->> 'important_notice'::text AS important_notice,\n    COALESCE(document_metadata -> 'photo_urls'::text, '[]'::jsonb) AS photo_urls,\n    pdf_file_path AS pdf_file_id,\n    pdf_url,\n    created_at,\n    updated_at,\n    sent_at,\n    paid_at,\n    document_metadata ->> 'city'::text AS city,\n    document_metadata ->> 'state'::text AS state,\n    document_metadata ->> 'zip'::text AS zip,\n    document_metadata ->> 'job_number'::text AS job_number,\n    NULLIF(document_metadata ->> 'service_date'::text, ''::text)::date AS service_date,\n    document_metadata ->> 'crew_size'::text AS crew_size,\n    document_metadata ->> 'anchor_method'::text AS anchor_method,\n    document_metadata ->> 'distance_note'::text AS distance_note,\n    document_metadata ->> 'special_conditions'::text AS special_conditions,\n    (document_metadata ->> 'trip_miles'::text)::numeric AS trip_miles,\n    (document_metadata ->> 'trip_hours'::text)::numeric AS trip_hours,\n    document_metadata ->> 'customer_phone'::text AS customer_phone,\n    customer_email,\n    policy_number,\n    document_metadata ->> 'date_of_loss'::text AS date_of_loss,\n    document_metadata ->> 'adjuster_name'::text AS adjuster_name,\n    document_metadata ->> 'adjuster_phone'::text AS adjuster_phone\n   FROM invoices i\n  WHERE document_kind = 'invoice'::text AND document_subtype = 'emergency_tarping'::text;"},{"name":"tenant_organizations","schema":"public","definition":" SELECT id,\n    name AS company_name,\n    name,\n    tenant_type,\n    owner_id,\n    status,\n    created_at,\n    updated_at,\n    settings,\n    company_slug,\n    company_legal_name,\n    company_dba_name,\n    company_address,\n    company_city,\n    company_state,\n    company_zip,\n    company_phone,\n    company_email,\n    company_logo_url AS logo_url,\n    company_logo_url,\n    letterhead_config,\n    is_active,\n    company_descriptor,\n    customer_facing_title,\n    branded_sender_email,\n    company_website,\n    company_mailing_address\n   FROM tenants;"},{"name":"user_tenant_access","schema":"public","definition":" SELECT COALESCE(r.user_id, m.user_id) AS user_id,\n    COALESCE(r.tenant_id, m.tenant_id) AS tenant_id,\n    r.role::text AS role,\n    COALESCE(m.is_owner, false) AS is_owner,\n    COALESCE(m.status, 'active'::text) AS membership_status,\n    r.role IS NOT NULL AS has_role,\n    m.user_id IS NOT NULL AS has_membership,\n    COALESCE(r.role::text,\n        CASE\n            WHEN m.is_owner THEN 'Tenant Owner'::text\n            ELSE 'Rep'::text\n        END) AS effective_role,\n    COALESCE(r.assigned_at, m.joined_at) AS granted_at\n   FROM user_roles r\n     FULL JOIN user_tenant_memberships m ON r.user_id = m.user_id AND r.tenant_id = m.tenant_id\n  WHERE COALESCE(r.user_id, m.user_id) = (( SELECT uid() AS uid)) OR ( SELECT is_system_admin(uid()) AS is_system_admin) OR (( SELECT role() AS role)) = 'service_role'::text;"},{"name":"v_active_tenant_users","schema":"public","definition":" SELECT p.id AS user_id,\n    p.email AS user_email,\n    p.name AS user_name,\n    p.phone AS user_phone,\n    p.active AS profile_active,\n    m.tenant_id,\n    m.status AS membership_status,\n    m.is_owner,\n    m.joined_at,\n    m.last_accessed_at\n   FROM profiles p\n     JOIN user_tenant_memberships m ON m.user_id = p.id\n  WHERE COALESCE(p.active, true) = true AND COALESCE(m.status, 'active'::text) = 'active'::text;"},{"name":"v_cached_parcel_roof_age_intel","schema":"public","definition":" SELECT id,\n    parcel_id,\n    lat,\n    lng,\n    year_built,\n    year_built_source,\n    roof_age_score,\n    roof_permit_year,\n    permit_count,\n    permit_source,\n    sqft_heated,\n    land_use,\n    zip,\n    notes,\n    viewport_key,\n    fetched_at,\n    created_at,\n    owner_name,\n    address,\n    assessed_value,\n    sale_price,\n    sale_date,\n    parcel_geometry,\n    geometry_source,\n    geometry_fetched_at\n   FROM cached_parcel_roof_ages;"},{"name":"v_canonical_stages","schema":"public","definition":" SELECT id,\n    tenant_org_id,\n    tenant_type,\n    tenancy_type,\n    pipeline_kind,\n    name,\n    order_index,\n    color,\n    is_active,\n    is_closed,\n    is_won,\n    is_template,\n    template_stage_key,\n    is_using_master_template,\n    derived_from_template_id,\n    adopted_admin_version,\n    created_at,\n    updated_at,\n    'pipeline_stages'::text AS source\n   FROM pipeline_stages ps\n  WHERE is_active = true;"},{"name":"v_command_center_events_safe","schema":"public","definition":" SELECT id,\n    tenant_id,\n    event_type,\n    priority,\n    status,\n    source_module,\n    created_by_role,\n    actor_display_name,\n    title,\n    cc_scrub_text(message) AS message,\n    requires_response,\n    requires_approval,\n    approval_status,\n    related_lead_id,\n    related_job_id,\n    related_claim_id,\n    created_at,\n    updated_at,\n    resolved_at\n   FROM command_center_events;"},{"name":"v_lead_intelligence_with_contact","schema":"public","definition":" SELECT s.id AS score_row_id,\n    s.tenant_org_id,\n    s.score_type,\n    s.subject_id,\n    s.score,\n    s.bucket,\n    s.label,\n    s.confidence,\n    s.reasons,\n    s.factors,\n    s.recommended_action,\n    s.stale,\n    s.dismissed,\n    s.last_calculated_at,\n    c.id AS contact_id,\n    c.name,\n    c.address,\n    c.city,\n    c.state,\n    c.zip,\n    c.phone,\n    c.lat,\n    c.lng,\n    c.assigned_to,\n    c.contact_status,\n    c.lead_stage,\n    c.graduated_at,\n    c.is_dnc,\n    c.carrier,\n    c.lead_score\n   FROM lead_intelligence_scores s\n     JOIN unified_contacts c ON c.id = s.subject_id AND c.deleted_at IS NULL\n  WHERE s.subject_type = 'contact'::text;"},{"name":"v_live_tenant_calls","schema":"public","definition":" SELECT acs.id AS session_id,\n    acs.tenant_org_id,\n    acs.rep_id,\n    acs.lead_id,\n    acs.phone_number,\n    acs.parent_call_sid,\n    acs.rep_call_sid,\n    acs.homeowner_call_sid,\n    acs.status,\n    acs.started_at,\n    acs.metadata,\n    ap.status AS rep_status,\n    p.name AS rep_name,\n    p.email AS rep_email\n   FROM active_call_sessions acs\n     LEFT JOIN agent_presence ap ON ap.user_id = acs.rep_id\n     LEFT JOIN profiles p ON p.id = acs.rep_id\n  WHERE acs.status <> ALL (ARRAY['ended'::text, 'failed'::text]);"},{"name":"v_ops_rollup_events_safe","schema":"public","definition":" SELECT id,\n    tenant_id,\n    event_type,\n    priority,\n    status,\n    source_module,\n    created_by_role,\n    actor_display_name,\n    title,\n    message,\n    requires_response,\n    requires_approval,\n    approval_status,\n    related_lead_id,\n    related_job_id,\n    related_claim_id,\n    created_at,\n    updated_at,\n    resolved_at\n   FROM v_command_center_events_safe\n  WHERE event_type = 'ops_anomaly_rollup'::text AND created_by_role = 'system:scetarping_ops_sentinel_rollup'::text;"},{"name":"v_ops_sentinel_events_safe","schema":"public","definition":" SELECT id,\n    tenant_id,\n    event_type,\n    priority,\n    status,\n    source_module,\n    created_by_role,\n    actor_display_name,\n    title,\n    message,\n    requires_response,\n    requires_approval,\n    approval_status,\n    related_lead_id,\n    related_job_id,\n    related_claim_id,\n    created_at,\n    updated_at,\n    resolved_at\n   FROM v_command_center_events_safe\n  WHERE event_type = 'ops_anomaly'::text AND created_by_role = 'system:scetarping_ops_sentinel'::text;"},{"name":"v_pa_settlement_kpis","schema":"public","definition":" SELECT tenant_org_id,\n    count(*) FILTER (WHERE (claim_status <> ALL (ARRAY['Settled'::text, 'Paid'::text, 'Closed'::text, 'Denied'::text, 'Withdrawn'::text])) OR claim_status IS NULL) AS open_cases,\n    count(*) FILTER (WHERE claim_status = 'Negotiating'::text) AS negotiating_cases,\n    count(*) FILTER (WHERE claim_status = 'Settled'::text) AS settled_cases,\n    count(*) FILTER (WHERE claim_status = ANY (ARRAY['Paid'::text, 'Closed'::text])) AS paid_closed_cases,\n    COALESCE(sum(pa_demand_amount) FILTER (WHERE claim_status <> ALL (ARRAY['Paid'::text, 'Closed'::text, 'Denied'::text, 'Withdrawn'::text])), 0::numeric) AS open_demand_total,\n    COALESCE(sum(carrier_offer_amount), 0::numeric) AS total_carrier_offers,\n    COALESCE(sum(settlement_amount), 0::numeric) AS total_settlement,\n    COALESCE(sum(expected_fee_amount), 0::numeric) AS total_expected_fees,\n    COALESCE(sum(fee_amount) FILTER (WHERE fee_status = 'Paid'::text), 0::numeric) AS total_collected_fees,\n    round(avg(settlement_amount) FILTER (WHERE settlement_amount IS NOT NULL), 2) AS avg_settlement,\n    round(avg((settlement_date - claim_filed_date)::numeric) FILTER (WHERE settlement_date IS NOT NULL AND claim_filed_date IS NOT NULL), 1) AS avg_days_to_settlement,\n    count(*) FILTER (WHERE claim_filed_date IS NOT NULL AND settlement_date IS NULL AND claim_filed_date <= (CURRENT_DATE - '30 days'::interval) AND claim_filed_date > (CURRENT_DATE - '60 days'::interval)) AS aging_30_60,\n    count(*) FILTER (WHERE claim_filed_date IS NOT NULL AND settlement_date IS NULL AND claim_filed_date <= (CURRENT_DATE - '60 days'::interval) AND claim_filed_date > (CURRENT_DATE - '90 days'::interval)) AS aging_60_90,\n    count(*) FILTER (WHERE claim_filed_date IS NOT NULL AND settlement_date IS NULL AND claim_filed_date <= (CURRENT_DATE - '90 days'::interval)) AS aging_over_90\n   FROM contact_claims cc\n  GROUP BY tenant_org_id;"},{"name":"v_priority_queue","schema":"public","definition":" SELECT lis.id AS score_id,\n    lis.tenant_org_id,\n    lis.score_type,\n    lis.subject_type,\n    lis.subject_id,\n    lis.score,\n    lis.label,\n    lis.bucket,\n    lis.confidence,\n    lis.rank,\n    lis.reasons,\n    lis.factors,\n    lis.recommended_action,\n    lis.recommended_method,\n    lis.recommended_script,\n    lis.dismissed,\n    lis.manually_boosted,\n    lis.manual_priority_override,\n    lis.stale,\n    lis.last_calculated_at,\n    lis.model_version,\n    uc.id AS contact_id,\n    uc.first_name,\n    uc.last_name,\n    COALESCE((uc.first_name || ' '::text) || uc.last_name, uc.first_name, uc.last_name) AS contact_name,\n    uc.address,\n    uc.city,\n    uc.state,\n    uc.zip,\n    uc.phone,\n    uc.email,\n    uc.assigned_to,\n    uc.status AS contact_status,\n    uc.lead_stage,\n    uc.jobs_stage,\n    uc.claim_stage,\n    uc.last_touched_at,\n    uc.roof_age,\n    uc.roof_permit_finaled_date,\n    uc.has_recent_roof_permit,\n    uc.property_year_built,\n    uc.property_assessed_value\n   FROM lead_intelligence_scores lis\n     LEFT JOIN unified_contacts uc ON (lis.subject_type = ANY (ARRAY['contact'::text, 'lead'::text, 'client'::text])) AND lis.subject_id = uc.id;"},{"name":"v_user_call_readiness","schema":"public","definition":" SELECT p.id AS user_id,\n    p.tenant_org_id::uuid AS tenant_id,\n    au.email,\n    p.name,\n    p.active,\n    p.phone AS profile_phone,\n    vc.phone_number AS verified_caller_id_number,\n    vc.forward_to_phone,\n    vc.verified_at,\n    ( SELECT tpn.phone_number\n           FROM tenant_phone_numbers tpn\n          WHERE tpn.tenant_org_id = p.tenant_org_id::uuid AND regexp_replace(tpn.phone_number, '\\D'::text, ''::text, 'g'::text) = regexp_replace(COALESCE(vc.phone_number, ''::text), '\\D'::text, ''::text, 'g'::text)\n         LIMIT 1) AS assigned_tenant_did,\n        CASE\n            WHEN p.phone IS NULL OR p.phone = ''::text THEN 'MissingProfilePhone'::text\n            WHEN vc.user_id IS NULL THEN 'MissingVerifiedCallerId'::text\n            WHEN vc.forward_to_phone IS NULL OR vc.forward_to_phone = ''::text THEN 'MissingForwarding'::text\n            WHEN vc.verified_at IS NULL THEN 'SetupIncomplete'::text\n            WHEN regexp_replace(p.phone, '\\D'::text, ''::text, 'g'::text) <> regexp_replace(vc.forward_to_phone, '\\D'::text, ''::text, 'g'::text) THEN 'ProfileHubMismatch'::text\n            ELSE 'Ready'::text\n        END AS readiness_status\n   FROM profiles p\n     JOIN users au ON au.id = p.id\n     LEFT JOIN LATERAL ( SELECT r.id,\n            r.user_id,\n            r.tenant_org_id,\n            r.phone_number,\n            r.friendly_name,\n            r.twilio_validation_sid,\n            r.twilio_caller_sid,\n            r.status,\n            r.is_default,\n            r.verified_at,\n            r.created_at,\n            r.updated_at,\n            r.forward_to_phone,\n            r.voice_url,\n            r.sms_url,\n            r.status_callback_url,\n            r.voice_recording_enabled,\n            r.voicemail_enabled,\n            r.voicemail_greeting,\n            r.forward_sms_enabled\n           FROM rep_verified_caller_ids r\n          WHERE r.user_id = p.id\n          ORDER BY r.verified_at DESC NULLS LAST\n         LIMIT 1) vc ON true\n  WHERE p.tenant_org_id IS NOT NULL;"},{"name":"v_voicemail_automation_health","schema":"public","definition":" SELECT tenant_org_id,\n    date_trunc('day'::text, started_at) AS day,\n    count(*) FILTER (WHERE voicemail_armed_template_id IS NOT NULL) AS armed,\n    count(*) FILTER (WHERE terminal_outcome = 'voicemail_left_auto'::text) AS auto_dropped,\n    count(*) FILTER (WHERE voicemail_armed_template_id IS NOT NULL AND terminal_outcome IS DISTINCT FROM 'voicemail_left_auto'::text) AS missed,\n        CASE\n            WHEN count(*) FILTER (WHERE voicemail_armed_template_id IS NOT NULL) = 0 THEN NULL::numeric\n            ELSE round(100.0 * count(*) FILTER (WHERE terminal_outcome = 'voicemail_left_auto'::text)::numeric / NULLIF(count(*) FILTER (WHERE voicemail_armed_template_id IS NOT NULL), 0)::numeric, 1)\n        END AS auto_drop_pct\n   FROM active_call_sessions acs\n  WHERE started_at >= (now() - '30 days'::interval)\n  GROUP BY tenant_org_id, (date_trunc('day'::text, started_at));"}],"format":"knocklaunch-database-catalog-v1","tables":[{"table":"audit_log_entries","schema":"auth","columns":[{"name":"instance_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"payload","type":"json","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_address","type":"character varying(64)","default":"''::character varying","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"audit_log_entries_pkey","definition":"CREATE UNIQUE INDEX audit_log_entries_pkey ON auth.audit_log_entries USING btree (id)"},{"name":"audit_logs_instance_id_idx","definition":"CREATE INDEX audit_logs_instance_id_idx ON auth.audit_log_entries USING btree (instance_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"audit_log_entries_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"custom_oauth_providers","schema":"auth","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"provider_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"identifier","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"client_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"client_secret","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"acceptable_client_ids","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"scopes","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"pkce_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"attribute_mapping","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"authorization_params","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"email_optional","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"issuer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"discovery_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"skip_nonce_check","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"cached_discovery","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"discovery_cached_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"authorization_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"token_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"userinfo_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"jwks_uri","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"custom_claims_allowlist","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"custom_oauth_providers_created_at_idx","definition":"CREATE INDEX custom_oauth_providers_created_at_idx ON auth.custom_oauth_providers USING btree (created_at)"},{"name":"custom_oauth_providers_enabled_idx","definition":"CREATE INDEX custom_oauth_providers_enabled_idx ON auth.custom_oauth_providers USING btree (enabled)"},{"name":"custom_oauth_providers_identifier_idx","definition":"CREATE INDEX custom_oauth_providers_identifier_idx ON auth.custom_oauth_providers USING btree (identifier)"},{"name":"custom_oauth_providers_identifier_key","definition":"CREATE UNIQUE INDEX custom_oauth_providers_identifier_key ON auth.custom_oauth_providers USING btree (identifier)"},{"name":"custom_oauth_providers_pkey","definition":"CREATE UNIQUE INDEX custom_oauth_providers_pkey ON auth.custom_oauth_providers USING btree (id)"},{"name":"custom_oauth_providers_provider_type_idx","definition":"CREATE INDEX custom_oauth_providers_provider_type_idx ON auth.custom_oauth_providers USING btree (provider_type)"}],"policies":[],"triggers":[],"constraints":[{"name":"custom_oauth_providers_authorization_url_https","definition":"CHECK (authorization_url IS NULL OR authorization_url ~~ 'https://%'::text)"},{"name":"custom_oauth_providers_authorization_url_length","definition":"CHECK (authorization_url IS NULL OR char_length(authorization_url) <= 2048)"},{"name":"custom_oauth_providers_client_id_length","definition":"CHECK (char_length(client_id) >= 1 AND char_length(client_id) <= 512)"},{"name":"custom_oauth_providers_discovery_url_length","definition":"CHECK (discovery_url IS NULL OR char_length(discovery_url) <= 2048)"},{"name":"custom_oauth_providers_identifier_format","definition":"CHECK (identifier ~ '^[a-z0-9][a-z0-9:-]{0,48}[a-z0-9]$'::text)"},{"name":"custom_oauth_providers_identifier_key","definition":"UNIQUE (identifier)"},{"name":"custom_oauth_providers_issuer_length","definition":"CHECK (issuer IS NULL OR char_length(issuer) >= 1 AND char_length(issuer) <= 2048)"},{"name":"custom_oauth_providers_jwks_uri_https","definition":"CHECK (jwks_uri IS NULL OR jwks_uri ~~ 'https://%'::text)"},{"name":"custom_oauth_providers_jwks_uri_length","definition":"CHECK (jwks_uri IS NULL OR char_length(jwks_uri) <= 2048)"},{"name":"custom_oauth_providers_name_length","definition":"CHECK (char_length(name) >= 1 AND char_length(name) <= 100)"},{"name":"custom_oauth_providers_oauth2_requires_endpoints","definition":"CHECK (provider_type <> 'oauth2'::text OR authorization_url IS NOT NULL AND token_url IS NOT NULL AND userinfo_url IS NOT NULL)"},{"name":"custom_oauth_providers_oidc_discovery_url_https","definition":"CHECK (provider_type <> 'oidc'::text OR discovery_url IS NULL OR discovery_url ~~ 'https://%'::text)"},{"name":"custom_oauth_providers_oidc_issuer_https","definition":"CHECK (provider_type <> 'oidc'::text OR issuer IS NULL OR issuer ~~ 'https://%'::text)"},{"name":"custom_oauth_providers_oidc_requires_issuer","definition":"CHECK (provider_type <> 'oidc'::text OR issuer IS NOT NULL)"},{"name":"custom_oauth_providers_pkey","definition":"PRIMARY KEY (id)"},{"name":"custom_oauth_providers_provider_type_check","definition":"CHECK (provider_type = ANY (ARRAY['oauth2'::text, 'oidc'::text]))"},{"name":"custom_oauth_providers_token_url_https","definition":"CHECK (token_url IS NULL OR token_url ~~ 'https://%'::text)"},{"name":"custom_oauth_providers_token_url_length","definition":"CHECK (token_url IS NULL OR char_length(token_url) <= 2048)"},{"name":"custom_oauth_providers_userinfo_url_https","definition":"CHECK (userinfo_url IS NULL OR userinfo_url ~~ 'https://%'::text)"},{"name":"custom_oauth_providers_userinfo_url_length","definition":"CHECK (userinfo_url IS NULL OR char_length(userinfo_url) <= 2048)"}]},{"table":"flow_state","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"auth_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"code_challenge_method","type":"code_challenge_method","default":null,"identity":"","not_null":false,"generated":""},{"name":"code_challenge","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_access_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_refresh_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"authentication_method","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"auth_code_issued_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"invite_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"referrer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"oauth_client_state_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"linking_target_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"email_optional","type":"boolean","default":"false","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"flow_state_created_at_idx","definition":"CREATE INDEX flow_state_created_at_idx ON auth.flow_state USING btree (created_at DESC)"},{"name":"flow_state_pkey","definition":"CREATE UNIQUE INDEX flow_state_pkey ON auth.flow_state USING btree (id)"},{"name":"idx_auth_code","definition":"CREATE INDEX idx_auth_code ON auth.flow_state USING btree (auth_code)"},{"name":"idx_user_id_auth_method","definition":"CREATE INDEX idx_user_id_auth_method ON auth.flow_state USING btree (user_id, authentication_method)"}],"policies":[],"triggers":[],"constraints":[{"name":"flow_state_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"identities","schema":"auth","columns":[{"name":"provider_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"identity_data","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"last_sign_in_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":"lower((identity_data ->> 'email'::text))","identity":"","not_null":false,"generated":"s"},{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"identities_email_idx","definition":"CREATE INDEX identities_email_idx ON auth.identities USING btree (email text_pattern_ops)"},{"name":"identities_pkey","definition":"CREATE UNIQUE INDEX identities_pkey ON auth.identities USING btree (id)"},{"name":"identities_provider_id_provider_unique","definition":"CREATE UNIQUE INDEX identities_provider_id_provider_unique ON auth.identities USING btree (provider_id, provider)"},{"name":"identities_user_id_idx","definition":"CREATE INDEX identities_user_id_idx ON auth.identities USING btree (user_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"identities_pkey","definition":"PRIMARY KEY (id)"},{"name":"identities_provider_id_provider_unique","definition":"UNIQUE (provider_id, provider)"},{"name":"identities_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"instances","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"uuid","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_base_config","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"instances_pkey","definition":"CREATE UNIQUE INDEX instances_pkey ON auth.instances USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"instances_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"mfa_amr_claims","schema":"auth","columns":[{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"authentication_method","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""}],"indexes":[{"name":"amr_id_pk","definition":"CREATE UNIQUE INDEX amr_id_pk ON auth.mfa_amr_claims USING btree (id)"},{"name":"mfa_amr_claims_session_id_authentication_method_pkey","definition":"CREATE UNIQUE INDEX mfa_amr_claims_session_id_authentication_method_pkey ON auth.mfa_amr_claims USING btree (session_id, authentication_method)"}],"policies":[],"triggers":[],"constraints":[{"name":"amr_id_pk","definition":"PRIMARY KEY (id)"},{"name":"mfa_amr_claims_session_id_authentication_method_pkey","definition":"UNIQUE (session_id, authentication_method)"},{"name":"mfa_amr_claims_session_id_fkey","definition":"FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE"}]},{"table":"mfa_challenges","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"factor_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_address","type":"inet","default":null,"identity":"","not_null":true,"generated":""},{"name":"otp_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"web_authn_session_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"mfa_challenge_created_at_idx","definition":"CREATE INDEX mfa_challenge_created_at_idx ON auth.mfa_challenges USING btree (created_at DESC)"},{"name":"mfa_challenges_pkey","definition":"CREATE UNIQUE INDEX mfa_challenges_pkey ON auth.mfa_challenges USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"mfa_challenges_auth_factor_id_fkey","definition":"FOREIGN KEY (factor_id) REFERENCES mfa_factors(id) ON DELETE CASCADE"},{"name":"mfa_challenges_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"mfa_factors","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"friendly_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"factor_type","type":"factor_type","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"factor_status","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"secret","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_challenged_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"web_authn_credential","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"web_authn_aaguid","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_webauthn_challenge_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"factor_id_created_at_idx","definition":"CREATE INDEX factor_id_created_at_idx ON auth.mfa_factors USING btree (user_id, created_at)"},{"name":"mfa_factors_last_challenged_at_key","definition":"CREATE UNIQUE INDEX mfa_factors_last_challenged_at_key ON auth.mfa_factors USING btree (last_challenged_at)"},{"name":"mfa_factors_pkey","definition":"CREATE UNIQUE INDEX mfa_factors_pkey ON auth.mfa_factors USING btree (id)"},{"name":"mfa_factors_user_friendly_name_unique","definition":"CREATE UNIQUE INDEX mfa_factors_user_friendly_name_unique ON auth.mfa_factors USING btree (friendly_name, user_id) WHERE (TRIM(BOTH FROM friendly_name) <> ''::text)"},{"name":"mfa_factors_user_id_idx","definition":"CREATE INDEX mfa_factors_user_id_idx ON auth.mfa_factors USING btree (user_id)"},{"name":"unique_phone_factor_per_user","definition":"CREATE UNIQUE INDEX unique_phone_factor_per_user ON auth.mfa_factors USING btree (user_id, phone)"}],"policies":[],"triggers":[],"constraints":[{"name":"mfa_factors_last_challenged_at_key","definition":"UNIQUE (last_challenged_at)"},{"name":"mfa_factors_pkey","definition":"PRIMARY KEY (id)"},{"name":"mfa_factors_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"mfa_recovery_code_sets","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"mfa_factor_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"failed_verification_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"verification_locked_until","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mfa_recovery_code_sets_mfa_factor_id_key","definition":"CREATE UNIQUE INDEX mfa_recovery_code_sets_mfa_factor_id_key ON auth.mfa_recovery_code_sets USING btree (mfa_factor_id)"},{"name":"mfa_recovery_code_sets_pkey","definition":"CREATE UNIQUE INDEX mfa_recovery_code_sets_pkey ON auth.mfa_recovery_code_sets USING btree (id)"},{"name":"mfa_recovery_code_sets_user_id_key","definition":"CREATE UNIQUE INDEX mfa_recovery_code_sets_user_id_key ON auth.mfa_recovery_code_sets USING btree (user_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"mfa_recovery_code_sets_failed_verification_count_check","definition":"CHECK (failed_verification_count >= 0)"},{"name":"mfa_recovery_code_sets_mfa_factor_id_fkey","definition":"FOREIGN KEY (mfa_factor_id) REFERENCES mfa_factors(id) ON DELETE CASCADE"},{"name":"mfa_recovery_code_sets_mfa_factor_id_key","definition":"UNIQUE (mfa_factor_id)"},{"name":"mfa_recovery_code_sets_pkey","definition":"PRIMARY KEY (id)"},{"name":"mfa_recovery_code_sets_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"},{"name":"mfa_recovery_code_sets_user_id_key","definition":"UNIQUE (user_id)"}]},{"table":"mfa_recovery_codes","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"mfa_recovery_code_set_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"code_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"consumed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mfa_recovery_codes_pkey","definition":"CREATE UNIQUE INDEX mfa_recovery_codes_pkey ON auth.mfa_recovery_codes USING btree (id)"},{"name":"mfa_recovery_codes_set_id_idx","definition":"CREATE INDEX mfa_recovery_codes_set_id_idx ON auth.mfa_recovery_codes USING btree (mfa_recovery_code_set_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"mfa_recovery_codes_mfa_recovery_code_set_id_fkey","definition":"FOREIGN KEY (mfa_recovery_code_set_id) REFERENCES mfa_recovery_code_sets(id) ON DELETE CASCADE"},{"name":"mfa_recovery_codes_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"oauth_authorizations","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"authorization_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"client_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"redirect_uri","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scope","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"resource","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"code_challenge","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"code_challenge_method","type":"code_challenge_method","default":null,"identity":"","not_null":false,"generated":""},{"name":"response_type","type":"oauth_response_type","default":"'code'::oauth_response_type","identity":"","not_null":true,"generated":""},{"name":"status","type":"oauth_authorization_status","default":"'pending'::oauth_authorization_status","identity":"","not_null":true,"generated":""},{"name":"authorization_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":"(now() + '00:03:00'::interval)","identity":"","not_null":true,"generated":""},{"name":"approved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"nonce","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"oauth_auth_pending_exp_idx","definition":"CREATE INDEX oauth_auth_pending_exp_idx ON auth.oauth_authorizations USING btree (expires_at) WHERE (status = 'pending'::oauth_authorization_status)"},{"name":"oauth_authorizations_authorization_code_key","definition":"CREATE UNIQUE INDEX oauth_authorizations_authorization_code_key ON auth.oauth_authorizations USING btree (authorization_code)"},{"name":"oauth_authorizations_authorization_id_key","definition":"CREATE UNIQUE INDEX oauth_authorizations_authorization_id_key ON auth.oauth_authorizations USING btree (authorization_id)"},{"name":"oauth_authorizations_pkey","definition":"CREATE UNIQUE INDEX oauth_authorizations_pkey ON auth.oauth_authorizations USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"oauth_authorizations_authorization_code_key","definition":"UNIQUE (authorization_code)"},{"name":"oauth_authorizations_authorization_code_length","definition":"CHECK (char_length(authorization_code) <= 255)"},{"name":"oauth_authorizations_authorization_id_key","definition":"UNIQUE (authorization_id)"},{"name":"oauth_authorizations_client_id_fkey","definition":"FOREIGN KEY (client_id) REFERENCES oauth_clients(id) ON DELETE CASCADE"},{"name":"oauth_authorizations_code_challenge_length","definition":"CHECK (char_length(code_challenge) <= 128)"},{"name":"oauth_authorizations_expires_at_future","definition":"CHECK (expires_at > created_at)"},{"name":"oauth_authorizations_nonce_length","definition":"CHECK (char_length(nonce) <= 255)"},{"name":"oauth_authorizations_pkey","definition":"PRIMARY KEY (id)"},{"name":"oauth_authorizations_redirect_uri_length","definition":"CHECK (char_length(redirect_uri) <= 2048)"},{"name":"oauth_authorizations_resource_length","definition":"CHECK (char_length(resource) <= 2048)"},{"name":"oauth_authorizations_scope_length","definition":"CHECK (char_length(scope) <= 4096)"},{"name":"oauth_authorizations_state_length","definition":"CHECK (char_length(state) <= 4096)"},{"name":"oauth_authorizations_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"oauth_client_states","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"code_verifier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_oauth_client_states_created_at","definition":"CREATE INDEX idx_oauth_client_states_created_at ON auth.oauth_client_states USING btree (created_at)"},{"name":"oauth_client_states_pkey","definition":"CREATE UNIQUE INDEX oauth_client_states_pkey ON auth.oauth_client_states USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"oauth_client_states_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"oauth_clients","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"client_secret_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"registration_type","type":"oauth_registration_type","default":null,"identity":"","not_null":true,"generated":""},{"name":"redirect_uris","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"grant_types","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"client_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"client_uri","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"logo_uri","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"client_type","type":"oauth_client_type","default":"'confidential'::oauth_client_type","identity":"","not_null":true,"generated":""},{"name":"token_endpoint_auth_method","type":"text","default":null,"identity":"","not_null":true,"generated":""}],"indexes":[{"name":"oauth_clients_deleted_at_idx","definition":"CREATE INDEX oauth_clients_deleted_at_idx ON auth.oauth_clients USING btree (deleted_at)"},{"name":"oauth_clients_pkey","definition":"CREATE UNIQUE INDEX oauth_clients_pkey ON auth.oauth_clients USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"oauth_clients_client_name_length","definition":"CHECK (char_length(client_name) <= 1024)"},{"name":"oauth_clients_client_uri_length","definition":"CHECK (char_length(client_uri) <= 2048)"},{"name":"oauth_clients_logo_uri_length","definition":"CHECK (char_length(logo_uri) <= 2048)"},{"name":"oauth_clients_pkey","definition":"PRIMARY KEY (id)"},{"name":"oauth_clients_token_endpoint_auth_method_check","definition":"CHECK (token_endpoint_auth_method = ANY (ARRAY['client_secret_basic'::text, 'client_secret_post'::text, 'none'::text]))"}]},{"table":"oauth_consents","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"client_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"scopes","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"granted_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"revoked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"oauth_consents_active_client_idx","definition":"CREATE INDEX oauth_consents_active_client_idx ON auth.oauth_consents USING btree (client_id) WHERE (revoked_at IS NULL)"},{"name":"oauth_consents_active_user_client_idx","definition":"CREATE INDEX oauth_consents_active_user_client_idx ON auth.oauth_consents USING btree (user_id, client_id) WHERE (revoked_at IS NULL)"},{"name":"oauth_consents_pkey","definition":"CREATE UNIQUE INDEX oauth_consents_pkey ON auth.oauth_consents USING btree (id)"},{"name":"oauth_consents_user_client_unique","definition":"CREATE UNIQUE INDEX oauth_consents_user_client_unique ON auth.oauth_consents USING btree (user_id, client_id)"},{"name":"oauth_consents_user_order_idx","definition":"CREATE INDEX oauth_consents_user_order_idx ON auth.oauth_consents USING btree (user_id, granted_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"oauth_consents_client_id_fkey","definition":"FOREIGN KEY (client_id) REFERENCES oauth_clients(id) ON DELETE CASCADE"},{"name":"oauth_consents_pkey","definition":"PRIMARY KEY (id)"},{"name":"oauth_consents_revoked_after_granted","definition":"CHECK (revoked_at IS NULL OR revoked_at >= granted_at)"},{"name":"oauth_consents_scopes_length","definition":"CHECK (char_length(scopes) <= 2048)"},{"name":"oauth_consents_scopes_not_empty","definition":"CHECK (char_length(TRIM(BOTH FROM scopes)) > 0)"},{"name":"oauth_consents_user_client_unique","definition":"UNIQUE (user_id, client_id)"},{"name":"oauth_consents_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"one_time_tokens","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"token_type","type":"one_time_token_type","default":null,"identity":"","not_null":true,"generated":""},{"name":"token_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"relates_to","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp without time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp without time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"one_time_tokens_pkey","definition":"CREATE UNIQUE INDEX one_time_tokens_pkey ON auth.one_time_tokens USING btree (id)"},{"name":"one_time_tokens_relates_to_hash_idx","definition":"CREATE INDEX one_time_tokens_relates_to_hash_idx ON auth.one_time_tokens USING hash (relates_to)"},{"name":"one_time_tokens_token_hash_hash_idx","definition":"CREATE INDEX one_time_tokens_token_hash_hash_idx ON auth.one_time_tokens USING hash (token_hash)"},{"name":"one_time_tokens_user_id_token_type_key","definition":"CREATE UNIQUE INDEX one_time_tokens_user_id_token_type_key ON auth.one_time_tokens USING btree (user_id, token_type)"}],"policies":[],"triggers":[],"constraints":[{"name":"one_time_tokens_pkey","definition":"PRIMARY KEY (id)"},{"name":"one_time_tokens_token_hash_check","definition":"CHECK (char_length(token_hash) > 0)"},{"name":"one_time_tokens_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"refresh_tokens","schema":"auth","columns":[{"name":"instance_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"id","type":"bigint","default":"nextval('refresh_tokens_id_seq'::regclass)","identity":"","not_null":true,"generated":""},{"name":"token","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"parent","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"refresh_tokens_instance_id_idx","definition":"CREATE INDEX refresh_tokens_instance_id_idx ON auth.refresh_tokens USING btree (instance_id)"},{"name":"refresh_tokens_instance_id_user_id_idx","definition":"CREATE INDEX refresh_tokens_instance_id_user_id_idx ON auth.refresh_tokens USING btree (instance_id, user_id)"},{"name":"refresh_tokens_parent_idx","definition":"CREATE INDEX refresh_tokens_parent_idx ON auth.refresh_tokens USING btree (parent)"},{"name":"refresh_tokens_pkey","definition":"CREATE UNIQUE INDEX refresh_tokens_pkey ON auth.refresh_tokens USING btree (id)"},{"name":"refresh_tokens_session_id_revoked_idx","definition":"CREATE INDEX refresh_tokens_session_id_revoked_idx ON auth.refresh_tokens USING btree (session_id, revoked)"},{"name":"refresh_tokens_token_unique","definition":"CREATE UNIQUE INDEX refresh_tokens_token_unique ON auth.refresh_tokens USING btree (token)"},{"name":"refresh_tokens_updated_at_idx","definition":"CREATE INDEX refresh_tokens_updated_at_idx ON auth.refresh_tokens USING btree (updated_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"refresh_tokens_pkey","definition":"PRIMARY KEY (id)"},{"name":"refresh_tokens_session_id_fkey","definition":"FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE"},{"name":"refresh_tokens_token_unique","definition":"UNIQUE (token)"}]},{"table":"saml_providers","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"sso_provider_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata_xml","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"attribute_mapping","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"name_id_format","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"saml_providers_entity_id_key","definition":"CREATE UNIQUE INDEX saml_providers_entity_id_key ON auth.saml_providers USING btree (entity_id)"},{"name":"saml_providers_pkey","definition":"CREATE UNIQUE INDEX saml_providers_pkey ON auth.saml_providers USING btree (id)"},{"name":"saml_providers_sso_provider_id_idx","definition":"CREATE INDEX saml_providers_sso_provider_id_idx ON auth.saml_providers USING btree (sso_provider_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"entity_id not empty","definition":"CHECK (char_length(entity_id) > 0)"},{"name":"metadata_url not empty","definition":"CHECK (metadata_url = NULL::text OR char_length(metadata_url) > 0)"},{"name":"metadata_xml not empty","definition":"CHECK (char_length(metadata_xml) > 0)"},{"name":"saml_providers_entity_id_key","definition":"UNIQUE (entity_id)"},{"name":"saml_providers_pkey","definition":"PRIMARY KEY (id)"},{"name":"saml_providers_sso_provider_id_fkey","definition":"FOREIGN KEY (sso_provider_id) REFERENCES sso_providers(id) ON DELETE CASCADE"}]},{"table":"saml_relay_states","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"sso_provider_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"request_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"for_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"redirect_to","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"flow_state_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"saml_relay_states_created_at_idx","definition":"CREATE INDEX saml_relay_states_created_at_idx ON auth.saml_relay_states USING btree (created_at DESC)"},{"name":"saml_relay_states_for_email_idx","definition":"CREATE INDEX saml_relay_states_for_email_idx ON auth.saml_relay_states USING btree (for_email)"},{"name":"saml_relay_states_pkey","definition":"CREATE UNIQUE INDEX saml_relay_states_pkey ON auth.saml_relay_states USING btree (id)"},{"name":"saml_relay_states_sso_provider_id_idx","definition":"CREATE INDEX saml_relay_states_sso_provider_id_idx ON auth.saml_relay_states USING btree (sso_provider_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"request_id not empty","definition":"CHECK (char_length(request_id) > 0)"},{"name":"saml_relay_states_flow_state_id_fkey","definition":"FOREIGN KEY (flow_state_id) REFERENCES flow_state(id) ON DELETE CASCADE"},{"name":"saml_relay_states_pkey","definition":"PRIMARY KEY (id)"},{"name":"saml_relay_states_sso_provider_id_fkey","definition":"FOREIGN KEY (sso_provider_id) REFERENCES sso_providers(id) ON DELETE CASCADE"}]},{"table":"schema_migrations","schema":"auth","columns":[{"name":"version","type":"character varying(255)","default":null,"identity":"","not_null":true,"generated":""}],"indexes":[{"name":"schema_migrations_pkey","definition":"CREATE UNIQUE INDEX schema_migrations_pkey ON auth.schema_migrations USING btree (version)"}],"policies":[],"triggers":[],"constraints":[{"name":"schema_migrations_pkey","definition":"PRIMARY KEY (version)"}]},{"table":"scim_tokens","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"sso_provider_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"token_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"prefix","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_used_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"scim_tokens_expires_at_idx","definition":"CREATE INDEX scim_tokens_expires_at_idx ON auth.scim_tokens USING btree (expires_at)"},{"name":"scim_tokens_pkey","definition":"CREATE UNIQUE INDEX scim_tokens_pkey ON auth.scim_tokens USING btree (id)"},{"name":"scim_tokens_revoked_at_idx","definition":"CREATE INDEX scim_tokens_revoked_at_idx ON auth.scim_tokens USING btree (revoked_at)"},{"name":"scim_tokens_sso_provider_id_idx","definition":"CREATE INDEX scim_tokens_sso_provider_id_idx ON auth.scim_tokens USING btree (sso_provider_id)"},{"name":"scim_tokens_token_hash_key","definition":"CREATE UNIQUE INDEX scim_tokens_token_hash_key ON auth.scim_tokens USING btree (token_hash)"}],"policies":[],"triggers":[],"constraints":[{"name":"scim_tokens_expires_at_future","definition":"CHECK (expires_at IS NULL OR expires_at > created_at)"},{"name":"scim_tokens_pkey","definition":"PRIMARY KEY (id)"},{"name":"scim_tokens_revoked_after_created","definition":"CHECK (revoked_at IS NULL OR revoked_at >= created_at)"},{"name":"scim_tokens_sso_provider_id_fkey","definition":"FOREIGN KEY (sso_provider_id) REFERENCES sso_providers(id) ON DELETE CASCADE"},{"name":"scim_tokens_token_hash_check","definition":"CHECK (token_hash ~ '^[0-9a-f]{64}$'::text)"}]},{"table":"scim_users","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"sso_provider_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"resource","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_name","type":"text","default":"lower((resource ->> 'userName'::text))","identity":"","not_null":true,"generated":"s"},{"name":"external_id","type":"text","default":"(resource ->> 'externalId'::text)","identity":"","not_null":false,"generated":"s"},{"name":"active","type":"boolean","default":"COALESCE(((resource ->> 'active'::text))::boolean, true)","identity":"","not_null":true,"generated":"s"},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"scim_users_created_at_idx","definition":"CREATE INDEX scim_users_created_at_idx ON auth.scim_users USING btree (sso_provider_id, created_at, id) WHERE (deleted_at IS NULL)"},{"name":"scim_users_deleted_at_idx","definition":"CREATE INDEX scim_users_deleted_at_idx ON auth.scim_users USING btree (deleted_at)"},{"name":"scim_users_external_id_key","definition":"CREATE UNIQUE INDEX scim_users_external_id_key ON auth.scim_users USING btree (sso_provider_id, external_id) WHERE ((external_id IS NOT NULL) AND (deleted_at IS NULL))"},{"name":"scim_users_id_idx","definition":"CREATE INDEX scim_users_id_idx ON auth.scim_users USING btree (sso_provider_id, id) WHERE (deleted_at IS NULL)"},{"name":"scim_users_pkey","definition":"CREATE UNIQUE INDEX scim_users_pkey ON auth.scim_users USING btree (id)"},{"name":"scim_users_sso_provider_id_idx","definition":"CREATE INDEX scim_users_sso_provider_id_idx ON auth.scim_users USING btree (sso_provider_id)"},{"name":"scim_users_updated_at_idx","definition":"CREATE INDEX scim_users_updated_at_idx ON auth.scim_users USING btree (sso_provider_id, updated_at, id) WHERE (deleted_at IS NULL)"},{"name":"scim_users_user_id_idx","definition":"CREATE INDEX scim_users_user_id_idx ON auth.scim_users USING btree (user_id)"},{"name":"scim_users_user_name_idx","definition":"CREATE INDEX scim_users_user_name_idx ON auth.scim_users USING btree (sso_provider_id, user_name COLLATE \"C\", id) WHERE (deleted_at IS NULL)"},{"name":"scim_users_user_name_key","definition":"CREATE UNIQUE INDEX scim_users_user_name_key ON auth.scim_users USING btree (sso_provider_id, user_name) WHERE (deleted_at IS NULL)"}],"policies":[],"triggers":[],"constraints":[{"name":"scim_users_pkey","definition":"PRIMARY KEY (id)"},{"name":"scim_users_sso_provider_id_fkey","definition":"FOREIGN KEY (sso_provider_id) REFERENCES sso_providers(id) ON DELETE CASCADE"},{"name":"scim_users_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL"}]},{"table":"sessions","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"factor_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"aal","type":"aal_level","default":null,"identity":"","not_null":false,"generated":""},{"name":"not_after","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"refreshed_at","type":"timestamp without time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip","type":"inet","default":null,"identity":"","not_null":false,"generated":""},{"name":"tag","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"oauth_client_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"refresh_token_hmac_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"refresh_token_counter","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"scopes","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"sessions_not_after_idx","definition":"CREATE INDEX sessions_not_after_idx ON auth.sessions USING btree (not_after DESC)"},{"name":"sessions_oauth_client_id_idx","definition":"CREATE INDEX sessions_oauth_client_id_idx ON auth.sessions USING btree (oauth_client_id)"},{"name":"sessions_pkey","definition":"CREATE UNIQUE INDEX sessions_pkey ON auth.sessions USING btree (id)"},{"name":"sessions_user_id_idx","definition":"CREATE INDEX sessions_user_id_idx ON auth.sessions USING btree (user_id)"},{"name":"user_id_created_at_idx","definition":"CREATE INDEX user_id_created_at_idx ON auth.sessions USING btree (user_id, created_at)"}],"policies":[],"triggers":[],"constraints":[{"name":"sessions_oauth_client_id_fkey","definition":"FOREIGN KEY (oauth_client_id) REFERENCES oauth_clients(id) ON DELETE CASCADE"},{"name":"sessions_pkey","definition":"PRIMARY KEY (id)"},{"name":"sessions_scopes_length","definition":"CHECK (char_length(scopes) <= 4096)"},{"name":"sessions_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"sso_domains","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"sso_provider_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"domain","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"sso_domains_domain_idx","definition":"CREATE UNIQUE INDEX sso_domains_domain_idx ON auth.sso_domains USING btree (lower(domain))"},{"name":"sso_domains_pkey","definition":"CREATE UNIQUE INDEX sso_domains_pkey ON auth.sso_domains USING btree (id)"},{"name":"sso_domains_sso_provider_id_idx","definition":"CREATE INDEX sso_domains_sso_provider_id_idx ON auth.sso_domains USING btree (sso_provider_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"domain not empty","definition":"CHECK (char_length(domain) > 0)"},{"name":"sso_domains_pkey","definition":"PRIMARY KEY (id)"},{"name":"sso_domains_sso_provider_id_fkey","definition":"FOREIGN KEY (sso_provider_id) REFERENCES sso_providers(id) ON DELETE CASCADE"}]},{"table":"sso_providers","schema":"auth","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"resource_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"disabled","type":"boolean","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"sso_providers_pkey","definition":"CREATE UNIQUE INDEX sso_providers_pkey ON auth.sso_providers USING btree (id)"},{"name":"sso_providers_resource_id_idx","definition":"CREATE UNIQUE INDEX sso_providers_resource_id_idx ON auth.sso_providers USING btree (lower(resource_id))"},{"name":"sso_providers_resource_id_pattern_idx","definition":"CREATE INDEX sso_providers_resource_id_pattern_idx ON auth.sso_providers USING btree (resource_id text_pattern_ops)"}],"policies":[],"triggers":[],"constraints":[{"name":"resource_id not empty","definition":"CHECK (resource_id = NULL::text OR char_length(resource_id) > 0)"},{"name":"sso_providers_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"users","schema":"auth","columns":[{"name":"instance_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"aud","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"role","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"encrypted_password","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"email_confirmed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"invited_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"confirmation_token","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"confirmation_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"recovery_token","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"recovery_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"email_change_token_new","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"email_change","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"email_change_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_sign_in_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_app_meta_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_user_meta_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_super_admin","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":"NULL::character varying","identity":"","not_null":false,"generated":""},{"name":"phone_confirmed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_change","type":"text","default":"''::character varying","identity":"","not_null":false,"generated":""},{"name":"phone_change_token","type":"character varying(255)","default":"''::character varying","identity":"","not_null":false,"generated":""},{"name":"phone_change_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"confirmed_at","type":"timestamp with time zone","default":"LEAST(email_confirmed_at, phone_confirmed_at)","identity":"","not_null":false,"generated":"s"},{"name":"email_change_token_current","type":"character varying(255)","default":"''::character varying","identity":"","not_null":false,"generated":""},{"name":"email_change_confirm_status","type":"smallint","default":"0","identity":"","not_null":false,"generated":""},{"name":"banned_until","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"reauthentication_token","type":"character varying(255)","default":"''::character varying","identity":"","not_null":false,"generated":""},{"name":"reauthentication_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_sso_user","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_anonymous","type":"boolean","default":"false","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"confirmation_token_idx","definition":"CREATE UNIQUE INDEX confirmation_token_idx ON auth.users USING btree (confirmation_token) WHERE ((confirmation_token)::text !~ '^[0-9 ]*$'::text)"},{"name":"email_change_token_current_idx","definition":"CREATE UNIQUE INDEX email_change_token_current_idx ON auth.users USING btree (email_change_token_current) WHERE ((email_change_token_current)::text !~ '^[0-9 ]*$'::text)"},{"name":"email_change_token_new_idx","definition":"CREATE UNIQUE INDEX email_change_token_new_idx ON auth.users USING btree (email_change_token_new) WHERE ((email_change_token_new)::text !~ '^[0-9 ]*$'::text)"},{"name":"idx_users_created_at_desc","definition":"CREATE INDEX idx_users_created_at_desc ON auth.users USING btree (created_at DESC)"},{"name":"idx_users_email","definition":"CREATE INDEX idx_users_email ON auth.users USING btree (email)"},{"name":"idx_users_last_sign_in_at_desc","definition":"CREATE INDEX idx_users_last_sign_in_at_desc ON auth.users USING btree (last_sign_in_at DESC)"},{"name":"idx_users_name","definition":"CREATE INDEX idx_users_name ON auth.users USING btree (((raw_user_meta_data ->> 'name'::text))) WHERE ((raw_user_meta_data ->> 'name'::text) IS NOT NULL)"},{"name":"reauthentication_token_idx","definition":"CREATE UNIQUE INDEX reauthentication_token_idx ON auth.users USING btree (reauthentication_token) WHERE ((reauthentication_token)::text !~ '^[0-9 ]*$'::text)"},{"name":"recovery_token_idx","definition":"CREATE UNIQUE INDEX recovery_token_idx ON auth.users USING btree (recovery_token) WHERE ((recovery_token)::text !~ '^[0-9 ]*$'::text)"},{"name":"users_email_partial_key","definition":"CREATE UNIQUE INDEX users_email_partial_key ON auth.users USING btree (email) WHERE (is_sso_user = false)"},{"name":"users_instance_id_email_idx","definition":"CREATE INDEX users_instance_id_email_idx ON auth.users USING btree (instance_id, lower((email)::text))"},{"name":"users_instance_id_idx","definition":"CREATE INDEX users_instance_id_idx ON auth.users USING btree (instance_id)"},{"name":"users_is_anonymous_idx","definition":"CREATE INDEX users_is_anonymous_idx ON auth.users USING btree (is_anonymous)"},{"name":"users_phone_key","definition":"CREATE UNIQUE INDEX users_phone_key ON auth.users USING btree (phone)"},{"name":"users_pkey","definition":"CREATE UNIQUE INDEX users_pkey ON auth.users USING btree (id)"}],"policies":[],"triggers":[{"name":"trg_knocklaunch_auth_delete_to_profile","definition":"CREATE TRIGGER trg_knocklaunch_auth_delete_to_profile AFTER DELETE ON users FOR EACH ROW EXECUTE FUNCTION knocklaunch_sync_auth_delete_to_profile()"}],"constraints":[{"name":"users_email_change_confirm_status_check","definition":"CHECK (email_change_confirm_status >= 0 AND email_change_confirm_status <= 2)"},{"name":"users_phone_key","definition":"UNIQUE (phone)"},{"name":"users_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"webauthn_challenges","schema":"auth","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"challenge_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"session_data","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""}],"indexes":[{"name":"webauthn_challenges_expires_at_idx","definition":"CREATE INDEX webauthn_challenges_expires_at_idx ON auth.webauthn_challenges USING btree (expires_at)"},{"name":"webauthn_challenges_pkey","definition":"CREATE UNIQUE INDEX webauthn_challenges_pkey ON auth.webauthn_challenges USING btree (id)"},{"name":"webauthn_challenges_user_id_idx","definition":"CREATE INDEX webauthn_challenges_user_id_idx ON auth.webauthn_challenges USING btree (user_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"webauthn_challenges_challenge_type_check","definition":"CHECK (challenge_type = ANY (ARRAY['signup'::text, 'registration'::text, 'authentication'::text]))"},{"name":"webauthn_challenges_pkey","definition":"PRIMARY KEY (id)"},{"name":"webauthn_challenges_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"webauthn_credentials","schema":"auth","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"credential_id","type":"bytea","default":null,"identity":"","not_null":true,"generated":""},{"name":"public_key","type":"bytea","default":null,"identity":"","not_null":true,"generated":""},{"name":"attestation_type","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"aaguid","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"sign_count","type":"bigint","default":"0","identity":"","not_null":true,"generated":""},{"name":"transports","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"backup_eligible","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"backed_up","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"friendly_name","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_used_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"webauthn_credentials_credential_id_key","definition":"CREATE UNIQUE INDEX webauthn_credentials_credential_id_key ON auth.webauthn_credentials USING btree (credential_id)"},{"name":"webauthn_credentials_pkey","definition":"CREATE UNIQUE INDEX webauthn_credentials_pkey ON auth.webauthn_credentials USING btree (id)"},{"name":"webauthn_credentials_user_id_idx","definition":"CREATE INDEX webauthn_credentials_user_id_idx ON auth.webauthn_credentials USING btree (user_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"webauthn_credentials_pkey","definition":"PRIMARY KEY (id)"},{"name":"webauthn_credentials_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"card_grading_cert_counters","schema":"private","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"cert_prefix","type":"smallint","default":null,"identity":"","not_null":true,"generated":""},{"name":"next_suffix","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"card_grading_cert_counters_pkey","definition":"CREATE UNIQUE INDEX card_grading_cert_counters_pkey ON private.card_grading_cert_counters USING btree (tenant_id, cert_prefix)"}],"policies":[],"triggers":[],"constraints":[{"name":"card_grading_cert_counters_cert_prefix_check","definition":"CHECK (cert_prefix = ANY (ARRAY[7, 8, 9]))"},{"name":"card_grading_cert_counters_next_suffix_check","definition":"CHECK (next_suffix >= 1 AND next_suffix <= 10000)"},{"name":"card_grading_cert_counters_pkey","definition":"PRIMARY KEY (tenant_id, cert_prefix)"}]},{"table":"mail_continuity_machine_auth","schema":"private","columns":[{"name":"key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"secret_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mail_continuity_machine_auth_pkey","definition":"CREATE UNIQUE INDEX mail_continuity_machine_auth_pkey ON private.mail_continuity_machine_auth USING btree (key)"}],"policies":[],"triggers":[],"constraints":[{"name":"mail_continuity_machine_auth_pkey","definition":"PRIMARY KEY (key)"}]},{"table":"modes_storage_reconcile_guard","schema":"private","columns":[{"name":"scope_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"last_dispatched_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_blocked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"blocked_notice_count","type":"bigint","default":"0","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"modes_storage_reconcile_guard_pkey","definition":"CREATE UNIQUE INDEX modes_storage_reconcile_guard_pkey ON private.modes_storage_reconcile_guard USING btree (scope_key)"}],"policies":[],"triggers":[],"constraints":[{"name":"modes_storage_reconcile_guard_pkey","definition":"PRIMARY KEY (scope_key)"}]},{"table":"opportunity_radar_lifecycle_secret","schema":"private","columns":[{"name":"singleton","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"token","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"opportunity_radar_lifecycle_secret_pkey","definition":"CREATE UNIQUE INDEX opportunity_radar_lifecycle_secret_pkey ON private.opportunity_radar_lifecycle_secret USING btree (singleton)"}],"policies":[],"triggers":[],"constraints":[{"name":"opportunity_radar_lifecycle_secret_pkey","definition":"PRIMARY KEY (singleton)"},{"name":"opportunity_radar_lifecycle_secret_singleton_check","definition":"CHECK (singleton)"}]},{"table":"academy_ai_eval_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"suite","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"runtime_version","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_sha","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"heldout_case_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"overall_score","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"dimensions","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"failures","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"read_only","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_ai_eval_runs_pkey","definition":"CREATE UNIQUE INDEX academy_ai_eval_runs_pkey ON public.academy_ai_eval_runs USING btree (id)"},{"name":"academy_ai_eval_tenant_created_idx","definition":"CREATE INDEX academy_ai_eval_tenant_created_idx ON public.academy_ai_eval_runs USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = academy_ai_eval_runs.tenant_org_id))))","roles":["authenticated"],"tablename":"academy_ai_eval_runs","permissive":"PERMISSIVE","policyname":"academy_ai_eval_membership","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = academy_ai_eval_runs.tenant_org_id))))"}],"triggers":[],"constraints":[{"name":"academy_ai_eval_runs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_ai_learning_candidates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_utterance","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"interpreted_intent","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"canonical_outcome","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"correction_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"verification_status","type":"text","default":"'candidate'::text","identity":"","not_null":true,"generated":""},{"name":"provenance","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"dedupe_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"promoted_lesson_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"promoted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_ai_learning_candidates_pkey","definition":"CREATE UNIQUE INDEX academy_ai_learning_candidates_pkey ON public.academy_ai_learning_candidates USING btree (id)"},{"name":"academy_ai_learning_candidates_tenant_org_id_dedupe_key_key","definition":"CREATE UNIQUE INDEX academy_ai_learning_candidates_tenant_org_id_dedupe_key_key ON public.academy_ai_learning_candidates USING btree (tenant_org_id, dedupe_key)"},{"name":"academy_ai_learning_tenant_created_idx","definition":"CREATE INDEX academy_ai_learning_tenant_created_idx ON public.academy_ai_learning_candidates USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = academy_ai_learning_candidates.tenant_org_id))))","roles":["authenticated"],"tablename":"academy_ai_learning_candidates","permissive":"PERMISSIVE","policyname":"academy_ai_learning_membership","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = academy_ai_learning_candidates.tenant_org_id))))"}],"triggers":[],"constraints":[{"name":"academy_ai_learning_candidates_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_ai_learning_candidates_promoted_lesson_id_fkey","definition":"FOREIGN KEY (promoted_lesson_id) REFERENCES academy_lessons(id) ON DELETE SET NULL"},{"name":"academy_ai_learning_candidates_tenant_org_id_dedupe_key_key","definition":"UNIQUE (tenant_org_id, dedupe_key)"},{"name":"academy_ai_learning_candidates_verification_status_check","definition":"CHECK (verification_status = ANY (ARRAY['candidate'::text, 'verified'::text, 'rejected'::text, 'promoted'::text]))"}]},{"table":"academy_ai_readiness_snapshots","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"target_date","type":"date","default":"'2026-11-01'::date","identity":"","not_null":true,"generated":""},{"name":"overall_score","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"dimensions","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"ready","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_ai_readiness_snapshots_pkey","definition":"CREATE UNIQUE INDEX academy_ai_readiness_snapshots_pkey ON public.academy_ai_readiness_snapshots USING btree (id)"},{"name":"academy_ai_readiness_tenant_created_idx","definition":"CREATE INDEX academy_ai_readiness_tenant_created_idx ON public.academy_ai_readiness_snapshots USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = academy_ai_readiness_snapshots.tenant_org_id))))","roles":["authenticated"],"tablename":"academy_ai_readiness_snapshots","permissive":"PERMISSIVE","policyname":"academy_ai_readiness_membership","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = academy_ai_readiness_snapshots.tenant_org_id))))"}],"triggers":[],"constraints":[{"name":"academy_ai_readiness_snapshots_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_ai_shadow_reviews","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"request_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_utterance","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"paul_plan","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"canonical_path","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"match_score","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"differences","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"duplicate_execution","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"verified","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_ai_shadow_reviews_pkey","definition":"CREATE UNIQUE INDEX academy_ai_shadow_reviews_pkey ON public.academy_ai_shadow_reviews USING btree (id)"},{"name":"academy_ai_shadow_tenant_created_idx","definition":"CREATE INDEX academy_ai_shadow_tenant_created_idx ON public.academy_ai_shadow_reviews USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = academy_ai_shadow_reviews.tenant_org_id))))","roles":["authenticated"],"tablename":"academy_ai_shadow_reviews","permissive":"PERMISSIVE","policyname":"academy_ai_shadow_membership","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = academy_ai_shadow_reviews.tenant_org_id))))"}],"triggers":[],"constraints":[{"name":"academy_ai_shadow_reviews_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_app_actions","schema":"public","columns":[{"name":"key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"module_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"default_route","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_app_actions_pkey","definition":"CREATE UNIQUE INDEX academy_app_actions_pkey ON public.academy_app_actions USING btree (key)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"academy_app_actions","permissive":"PERMISSIVE","policyname":"auth read app_actions","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_app_actions","permissive":"PERMISSIVE","policyname":"godmode write app_actions","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"academy_app_actions_pkey","definition":"PRIMARY KEY (key)"}]},{"table":"academy_assignment_rules","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"course_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_required","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"due_days","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_assignment_rules_pkey","definition":"CREATE UNIQUE INDEX academy_assignment_rules_pkey ON public.academy_assignment_rules USING btree (id)"},{"name":"academy_assignment_rules_tenant_org_id_course_id_role_key","definition":"CREATE UNIQUE INDEX academy_assignment_rules_tenant_org_id_course_id_role_key ON public.academy_assignment_rules USING btree (tenant_org_id, course_id, role)"},{"name":"idx_academy_assignment_rules_role","definition":"CREATE INDEX idx_academy_assignment_rules_role ON public.academy_assignment_rules USING btree (tenant_org_id, role)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IS NOT NULL)","roles":["authenticated"],"tablename":"academy_assignment_rules","permissive":"RESTRICTIVE","policyname":"block null tenant rules","schemaname":"public","with_check":"(tenant_org_id IS NOT NULL)"},{"cmd":"ALL","qual":"(is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_assignment_rules","permissive":"PERMISSIVE","policyname":"owners write rules","schemaname":"public","with_check":"(is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_assignment_rules","permissive":"PERMISSIVE","policyname":"tenant members read rules","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_assignment_rules_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_assignment_rules_tenant_org_id_course_id_role_key","definition":"UNIQUE (tenant_org_id, course_id, role)"}]},{"table":"academy_badge_rules","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"badge_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metric","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"threshold","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_badge_rules_badge_key_key","definition":"CREATE UNIQUE INDEX academy_badge_rules_badge_key_key ON public.academy_badge_rules USING btree (badge_key)"},{"name":"academy_badge_rules_pkey","definition":"CREATE UNIQUE INDEX academy_badge_rules_pkey ON public.academy_badge_rules USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_badge_rules","permissive":"PERMISSIVE","policyname":"Admins manage badge rules","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"academy_badge_rules","permissive":"PERMISSIVE","policyname":"Anyone can view badge rules","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_badge_rules_badge_key_key","definition":"UNIQUE (badge_key)"},{"name":"academy_badge_rules_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_badges","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"badge_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"icon","type":"text","default":"'🏆'::text","identity":"","not_null":false,"generated":""},{"name":"category","type":"text","default":"'general'::text","identity":"","not_null":false,"generated":""},{"name":"points_required","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_badges_badge_key_key","definition":"CREATE UNIQUE INDEX academy_badges_badge_key_key ON public.academy_badges USING btree (badge_key)"},{"name":"academy_badges_pkey","definition":"CREATE UNIQUE INDEX academy_badges_pkey ON public.academy_badges USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"academy_badges","permissive":"PERMISSIVE","policyname":"Admins can manage badges","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"true","roles":["public"],"tablename":"academy_badges","permissive":"PERMISSIVE","policyname":"Anyone can view badges","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_badges_badge_key_key","definition":"UNIQUE (badge_key)"},{"name":"academy_badges_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_certificate_recipients","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"certificate_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"recipient_role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"recipient_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"email_status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"queued_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_certificate_recipients_pkey","definition":"CREATE UNIQUE INDEX academy_certificate_recipients_pkey ON public.academy_certificate_recipients USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM academy_certificates c\n  WHERE ((c.id = academy_certificate_recipients.certificate_id) AND ((c.user_id = uid()) OR is_tenant_owner_for(uid(), c.tenant_org_id) OR is_system_admin(uid())))))","roles":["authenticated"],"tablename":"academy_certificate_recipients","permissive":"PERMISSIVE","policyname":"Certificate recipients readable by proof viewers","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_certificate_recipients","permissive":"PERMISSIVE","policyname":"GodMode manages certificate recipients","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"academy_certificate_recipients_certificate_id_fkey","definition":"FOREIGN KEY (certificate_id) REFERENCES academy_certificates(id) ON DELETE CASCADE"},{"name":"academy_certificate_recipients_email_status_check","definition":"CHECK (email_status = ANY (ARRAY['pending'::text, 'sent'::text, 'failed'::text, 'skipped'::text]))"},{"name":"academy_certificate_recipients_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_certificate_recipients_recipient_role_check","definition":"CHECK (recipient_role = ANY (ARRAY['user'::text, 'tenant_owner'::text, 'godmode'::text]))"}]},{"table":"academy_certificates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"certificate_number","type":"text","default":"('KL-ACADEMY-'::text || upper(replace((gen_random_uuid())::text, '-'::text, ''::text)))","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"course_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"certificate_title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"issued_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"issued_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_certificates_certificate_number_key","definition":"CREATE UNIQUE INDEX academy_certificates_certificate_number_key ON public.academy_certificates USING btree (certificate_number)"},{"name":"academy_certificates_pkey","definition":"CREATE UNIQUE INDEX academy_certificates_pkey ON public.academy_certificates USING btree (id)"},{"name":"academy_certificates_tenant_org_id_user_id_course_id_key","definition":"CREATE UNIQUE INDEX academy_certificates_tenant_org_id_user_id_course_id_key ON public.academy_certificates USING btree (tenant_org_id, user_id, course_id)"},{"name":"idx_academy_certificates_tenant","definition":"CREATE INDEX idx_academy_certificates_tenant ON public.academy_certificates USING btree (tenant_org_id, issued_at DESC)"},{"name":"idx_academy_certificates_user","definition":"CREATE INDEX idx_academy_certificates_user ON public.academy_certificates USING btree (user_id, issued_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"academy_certificates","permissive":"PERMISSIVE","policyname":"System inserts Academy certificates","schemaname":"public","with_check":"((user_id = uid()) OR is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((user_id = uid()) OR is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_certificates","permissive":"PERMISSIVE","policyname":"Users and owners read Academy certificates","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_certificates_certificate_number_key","definition":"UNIQUE (certificate_number)"},{"name":"academy_certificates_course_id_fkey","definition":"FOREIGN KEY (course_id) REFERENCES academy_courses(id) ON DELETE CASCADE"},{"name":"academy_certificates_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_certificates_tenant_org_id_user_id_course_id_key","definition":"UNIQUE (tenant_org_id, user_id, course_id)"}]},{"table":"academy_change_notes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"audience","type":"text","default":"'all_users'::text","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_module_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_course_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"published_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_published","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_change_notes_pkey","definition":"CREATE UNIQUE INDEX academy_change_notes_pkey ON public.academy_change_notes USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_change_notes","permissive":"PERMISSIVE","policyname":"GodMode manages Academy change notes","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((is_published = true) AND ((tenant_org_id IS NULL) OR is_tenant_member(tenant_org_id) OR is_system_admin(uid())))","roles":["authenticated"],"tablename":"academy_change_notes","permissive":"PERMISSIVE","policyname":"Published Academy change notes visible","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_change_notes_audience_check","definition":"CHECK (audience = ANY (ARRAY['all_users'::text, 'tenant_users'::text, 'owners'::text, 'managers'::text, 'reps'::text, 'crew'::text, 'godmode'::text]))"},{"name":"academy_change_notes_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_change_notes_related_course_id_fkey","definition":"FOREIGN KEY (related_course_id) REFERENCES academy_courses(id) ON DELETE SET NULL"},{"name":"academy_change_notes_related_module_key_fkey","definition":"FOREIGN KEY (related_module_key) REFERENCES academy_module_keys(key) ON DELETE SET NULL"}]},{"table":"academy_coaching_moments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"call_log_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"objection_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scenario_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"roleplay_session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_coaching_moments_pkey","definition":"CREATE UNIQUE INDEX academy_coaching_moments_pkey ON public.academy_coaching_moments USING btree (id)"},{"name":"idx_acm_tenant","definition":"CREATE INDEX idx_acm_tenant ON public.academy_coaching_moments USING btree (tenant_org_id)"},{"name":"idx_acm_user_status","definition":"CREATE INDEX idx_acm_user_status ON public.academy_coaching_moments USING btree (user_id, status)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"academy_coaching_moments","permissive":"PERMISSIVE","policyname":"Users insert own coaching moments","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"SELECT","qual":"((user_id = uid()) OR is_tenant_member((tenant_org_id)::text))","roles":["authenticated"],"tablename":"academy_coaching_moments","permissive":"PERMISSIVE","policyname":"Users see own coaching moments","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"academy_coaching_moments","permissive":"PERMISSIVE","policyname":"Users update own coaching moments","schemaname":"public","with_check":"(user_id = uid())"}],"triggers":[],"constraints":[{"name":"academy_coaching_moments_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_compliance_gates","schema":"public","columns":[{"name":"key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"gate_type","type":"text","default":"'phone_readiness'::text","identity":"","not_null":true,"generated":""},{"name":"required_course_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"required_certificate","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"enforcement_status","type":"text","default":"'report_only'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_compliance_gates_pkey","definition":"CREATE UNIQUE INDEX academy_compliance_gates_pkey ON public.academy_compliance_gates USING btree (key)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"academy_compliance_gates","permissive":"PERMISSIVE","policyname":"Academy compliance gates readable","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_compliance_gates","permissive":"PERMISSIVE","policyname":"GodMode manages compliance gates","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"academy_compliance_gates_enforcement_status_check","definition":"CHECK (enforcement_status = ANY (ARRAY['report_only'::text, 'enforced'::text, 'disabled'::text]))"},{"name":"academy_compliance_gates_gate_type_check","definition":"CHECK (gate_type = ANY (ARRAY['phone_readiness'::text, 'sms_readiness'::text, 'crew_closeout'::text, 'pm_verification'::text, 'owner_launch'::text]))"},{"name":"academy_compliance_gates_pkey","definition":"PRIMARY KEY (key)"},{"name":"academy_compliance_gates_required_course_id_fkey","definition":"FOREIGN KEY (required_course_id) REFERENCES academy_courses(id) ON DELETE SET NULL"}]},{"table":"academy_content_blocks","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"lesson_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"block_type","type":"text","default":"'rich_text'::text","identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_content_blocks_pkey","definition":"CREATE UNIQUE INDEX academy_content_blocks_pkey ON public.academy_content_blocks USING btree (id)"},{"name":"idx_academy_content_blocks_lesson_order","definition":"CREATE INDEX idx_academy_content_blocks_lesson_order ON public.academy_content_blocks USING btree (lesson_id, order_index)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM ((academy_lessons l\n     JOIN academy_units u ON ((u.id = l.unit_id)))\n     JOIN academy_courses c ON ((c.id = u.course_id)))\n  WHERE ((l.id = academy_content_blocks.lesson_id) AND academy_course_visible(c.tenant_org_id, c.is_published))))","roles":["public"],"tablename":"academy_content_blocks","permissive":"PERMISSIVE","policyname":"Academy content blocks visible via lesson","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_content_blocks","permissive":"PERMISSIVE","policyname":"GodMode manages Academy content blocks","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"academy_content_blocks_block_type_check","definition":"CHECK (block_type = ANY (ARRAY['rich_text'::text, 'callout'::text, 'checklist'::text, 'video'::text, 'route_link'::text, 'scenario_prompt'::text, 'glossary_terms'::text, 'change_note'::text, 'download'::text, 'sidekick_prompt'::text]))"},{"name":"academy_content_blocks_lesson_id_fkey","definition":"FOREIGN KEY (lesson_id) REFERENCES academy_lessons(id) ON DELETE CASCADE"},{"name":"academy_content_blocks_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_content_versions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"course_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lesson_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"version","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"content_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_content_versions_pkey","definition":"CREATE UNIQUE INDEX academy_content_versions_pkey ON public.academy_content_versions USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_content_versions","permissive":"PERMISSIVE","policyname":"godmode write versions","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM academy_courses c\n  WHERE ((c.id = academy_content_versions.course_id) AND academy_course_visible(c.tenant_org_id, c.is_published)))))","roles":["public"],"tablename":"academy_content_versions","permissive":"PERMISSIVE","policyname":"tenant members read versions","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_content_versions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_courses","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_track","type":"text","default":"'universal'::text","identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'crm-fundamentals'::text","identity":"","not_null":true,"generated":""},{"name":"difficulty_level","type":"text","default":"'beginner'::text","identity":"","not_null":true,"generated":""},{"name":"estimated_duration_minutes","type":"integer","default":"30","identity":"","not_null":false,"generated":""},{"name":"thumbnail_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_published","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"scope","type":"text","default":"'tenant'::text","identity":"","not_null":true,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"required_roles","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"required_module_keys","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"is_required","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"content_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"superseded_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"review_status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"reviewed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"certifies","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"certificate_title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"compliance_gate_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"certificate_email_user","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"certificate_email_owner","type":"boolean","default":"true","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_courses_pkey","definition":"CREATE UNIQUE INDEX academy_courses_pkey ON public.academy_courses USING btree (id)"},{"name":"idx_academy_courses_compliance_gate","definition":"CREATE INDEX idx_academy_courses_compliance_gate ON public.academy_courses USING btree (compliance_gate_key) WHERE (compliance_gate_key IS NOT NULL)"},{"name":"idx_academy_courses_scope","definition":"CREATE INDEX idx_academy_courses_scope ON public.academy_courses USING btree (scope)"},{"name":"idx_academy_courses_scope_published","definition":"CREATE INDEX idx_academy_courses_scope_published ON public.academy_courses USING btree (scope, is_published, review_status)"},{"name":"idx_academy_courses_tenant_review","definition":"CREATE INDEX idx_academy_courses_tenant_review ON public.academy_courses USING btree (tenant_org_id, review_status)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR is_tenant_owner_for(uid(), tenant_org_id))","roles":["public"],"tablename":"academy_courses","permissive":"PERMISSIVE","policyname":"Admins can manage courses","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"academy_course_visible(tenant_org_id, is_published)","roles":["public"],"tablename":"academy_courses","permissive":"PERMISSIVE","policyname":"Members or universal can view published courses","schemaname":"public","with_check":null}],"triggers":[{"name":"update_academy_courses_updated_at","definition":"CREATE TRIGGER update_academy_courses_updated_at BEFORE UPDATE ON academy_courses FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"academy_courses_category_check","definition":"CHECK (category = ANY (ARRAY['crm-fundamentals'::text, 'door-knocking'::text, 'cold-calling'::text, 'insurance-101'::text, 'industry-knowledge'::text, 'objection-handling'::text, 'closing'::text, 'compliance'::text, 'platform-mastery'::text, 'safety'::text, 'storm-report-presentation'::text, 'follow-up'::text, 'onboarding'::text]))"},{"name":"academy_courses_difficulty_level_check","definition":"CHECK (difficulty_level = ANY (ARRAY['beginner'::text, 'intermediate'::text, 'advanced'::text]))"},{"name":"academy_courses_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_courses_review_status_check","definition":"CHECK (review_status = ANY (ARRAY['active'::text, 'review_required'::text, 'retired'::text]))"},{"name":"academy_courses_scope_check","definition":"CHECK (scope = ANY (ARRAY['platform'::text, 'template'::text, 'tenant'::text]))"},{"name":"academy_courses_tenant_track_check","definition":"CHECK (tenant_track = ANY (ARRAY['mitigation'::text, 'roofing'::text, 'public_adjuster'::text, 'realtor'::text, 'universal'::text]))"}]},{"table":"academy_enrollments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"course_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"enrolled_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"progress_percent","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_enrollments_pkey","definition":"CREATE UNIQUE INDEX academy_enrollments_pkey ON public.academy_enrollments USING btree (id)"},{"name":"academy_enrollments_user_course_unique","definition":"CREATE UNIQUE INDEX academy_enrollments_user_course_unique ON public.academy_enrollments USING btree (user_id, course_id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"academy_enrollments","permissive":"PERMISSIVE","policyname":"Admins can manage enrollments","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"can_view_tenant_member_academy(uid(), user_id)","roles":["authenticated"],"tablename":"academy_enrollments","permissive":"PERMISSIVE","policyname":"Tenant owners manage member enrollments","schemaname":"public","with_check":"can_view_tenant_member_academy(uid(), user_id)"},{"cmd":"SELECT","qual":"can_view_tenant_member_academy(uid(), user_id)","roles":["authenticated"],"tablename":"academy_enrollments","permissive":"PERMISSIVE","policyname":"Tenant owners view member enrollments","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"academy_enrollments","permissive":"PERMISSIVE","policyname":"Users can enroll themselves","schemaname":"public","with_check":"((uid() = user_id) OR (uid() = enrolled_by))"},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["public"],"tablename":"academy_enrollments","permissive":"PERMISSIVE","policyname":"Users can update own enrollments","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["public"],"tablename":"academy_enrollments","permissive":"PERMISSIVE","policyname":"Users can view own enrollments","schemaname":"public","with_check":null}],"triggers":[{"name":"update_academy_enrollments_updated_at","definition":"CREATE TRIGGER update_academy_enrollments_updated_at BEFORE UPDATE ON academy_enrollments FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"academy_enrollments_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_enrollments_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'completed'::text, 'dropped'::text]))"},{"name":"academy_enrollments_user_course_unique","definition":"UNIQUE (user_id, course_id)"}]},{"table":"academy_glossary_terms","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"term","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"slug","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"plain_language_definition","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_track","type":"text","default":"'universal'::text","identity":"","not_null":true,"generated":""},{"name":"related_module_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_course_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_published","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_glossary_terms_pkey","definition":"CREATE UNIQUE INDEX academy_glossary_terms_pkey ON public.academy_glossary_terms USING btree (id)"},{"name":"academy_glossary_terms_slug_key","definition":"CREATE UNIQUE INDEX academy_glossary_terms_slug_key ON public.academy_glossary_terms USING btree (slug)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_glossary_terms","permissive":"PERMISSIVE","policyname":"GodMode manages glossary","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((is_published = true) AND ((tenant_org_id IS NULL) OR is_tenant_member(tenant_org_id) OR is_system_admin(uid())))","roles":["authenticated"],"tablename":"academy_glossary_terms","permissive":"PERMISSIVE","policyname":"Published glossary visible to Academy users","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_glossary_terms_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_glossary_terms_related_course_id_fkey","definition":"FOREIGN KEY (related_course_id) REFERENCES academy_courses(id) ON DELETE SET NULL"},{"name":"academy_glossary_terms_related_module_key_fkey","definition":"FOREIGN KEY (related_module_key) REFERENCES academy_module_keys(key) ON DELETE SET NULL"},{"name":"academy_glossary_terms_slug_key","definition":"UNIQUE (slug)"}]},{"table":"academy_lesson_completions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lesson_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"course_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"method","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"verified_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_lesson_completions_pkey","definition":"CREATE UNIQUE INDEX academy_lesson_completions_pkey ON public.academy_lesson_completions USING btree (id)"},{"name":"academy_lesson_completions_user_id_lesson_id_method_key","definition":"CREATE UNIQUE INDEX academy_lesson_completions_user_id_lesson_id_method_key ON public.academy_lesson_completions USING btree (user_id, lesson_id, method)"},{"name":"idx_academy_lesson_completions_user","definition":"CREATE INDEX idx_academy_lesson_completions_user ON public.academy_lesson_completions USING btree (user_id, lesson_id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IS NOT NULL)","roles":["authenticated"],"tablename":"academy_lesson_completions","permissive":"RESTRICTIVE","policyname":"block null tenant completions","schemaname":"public","with_check":"(tenant_org_id IS NOT NULL)"},{"cmd":"UPDATE","qual":"(is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_lesson_completions","permissive":"PERMISSIVE","policyname":"owners verify completions","schemaname":"public","with_check":"(is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"academy_lesson_completions","permissive":"PERMISSIVE","policyname":"self insert completions","schemaname":"public","with_check":"(((user_id = uid()) AND is_tenant_member(tenant_org_id)) OR is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((user_id = uid()) OR is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_lesson_completions","permissive":"PERMISSIVE","policyname":"self read completions","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_lesson_completions_method_check","definition":"CHECK (method = ANY (ARRAY['viewed'::text, 'acknowledged'::text, 'quiz_passed'::text, 'action_completed'::text, 'roleplay_completed'::text, 'manager_verified'::text, 'manual'::text]))"},{"name":"academy_lesson_completions_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_lesson_completions_user_id_lesson_id_method_key","definition":"UNIQUE (user_id, lesson_id, method)"}]},{"table":"academy_lesson_prerequisites","schema":"public","columns":[{"name":"lesson_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"prerequisite_lesson_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_lesson_prerequisites_pkey","definition":"CREATE UNIQUE INDEX academy_lesson_prerequisites_pkey ON public.academy_lesson_prerequisites USING btree (lesson_id, prerequisite_lesson_id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"academy_lesson_prerequisites","permissive":"PERMISSIVE","policyname":"auth read prereqs","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_lesson_prerequisites","permissive":"PERMISSIVE","policyname":"godmode write prereqs","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"academy_lesson_prerequisites_check","definition":"CHECK (lesson_id <> prerequisite_lesson_id)"},{"name":"academy_lesson_prerequisites_pkey","definition":"PRIMARY KEY (lesson_id, prerequisite_lesson_id)"}]},{"table":"academy_lesson_route_links","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"lesson_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"route","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"cta_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_lesson_route_links_pkey","definition":"CREATE UNIQUE INDEX academy_lesson_route_links_pkey ON public.academy_lesson_route_links USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"academy_lesson_route_links","permissive":"PERMISSIVE","policyname":"auth read route links","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_lesson_route_links","permissive":"PERMISSIVE","policyname":"godmode write route links","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"academy_lesson_route_links_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_lessons","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"unit_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"content","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lesson_type","type":"text","default":"'text'::text","identity":"","not_null":true,"generated":""},{"name":"video_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"duration_minutes","type":"integer","default":"5","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"linked_action_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"linked_route","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"action_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"content_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"learning_objective","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"role_scope","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"workflow_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sop_category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"module_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"requires_acknowledgment","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"requires_quiz","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"passing_score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"estimated_minutes","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"review_status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"scenario_key","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_lessons_pkey","definition":"CREATE UNIQUE INDEX academy_lessons_pkey ON public.academy_lessons USING btree (id)"},{"name":"idx_academy_lessons_action_key","definition":"CREATE INDEX idx_academy_lessons_action_key ON public.academy_lessons USING btree (linked_action_key)"},{"name":"idx_academy_lessons_module_key","definition":"CREATE INDEX idx_academy_lessons_module_key ON public.academy_lessons USING btree (module_key)"},{"name":"idx_academy_lessons_workflow_key","definition":"CREATE INDEX idx_academy_lessons_workflow_key ON public.academy_lessons USING btree (workflow_key)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM (academy_units u\n     JOIN academy_courses c ON ((c.id = u.course_id)))\n  WHERE ((u.id = academy_lessons.unit_id) AND (is_system_admin(uid()) OR is_tenant_owner_for(uid(), c.tenant_org_id)))))","roles":["public"],"tablename":"academy_lessons","permissive":"PERMISSIVE","policyname":"Admins can manage lessons","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM (academy_units u\n     JOIN academy_courses c ON ((c.id = u.course_id)))\n  WHERE ((u.id = academy_lessons.unit_id) AND academy_course_visible(c.tenant_org_id, c.is_published))))","roles":["public"],"tablename":"academy_lessons","permissive":"PERMISSIVE","policyname":"Viewable via unit access","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_enforce_academy_lesson_grounding","definition":"CREATE TRIGGER trg_enforce_academy_lesson_grounding BEFORE INSERT OR UPDATE ON academy_lessons FOR EACH ROW EXECUTE FUNCTION enforce_academy_lesson_grounding()"},{"name":"update_academy_lessons_updated_at","definition":"CREATE TRIGGER update_academy_lessons_updated_at BEFORE UPDATE ON academy_lessons FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"academy_lessons_lesson_type_check","definition":"CHECK (lesson_type = ANY (ARRAY['action'::text, 'sop'::text, 'concept'::text, 'quiz'::text, 'roleplay'::text, 'reference'::text, 'video'::text, 'text'::text]))"},{"name":"academy_lessons_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_lessons_review_status_check","definition":"CHECK (review_status = ANY (ARRAY['active'::text, 'review_required'::text, 'stale'::text, 'retired'::text]))"}]},{"table":"academy_manager_trainees","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"manager_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"trainee_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_manager_trainees_manager_id_trainee_id_tenant_org_i_key","definition":"CREATE UNIQUE INDEX academy_manager_trainees_manager_id_trainee_id_tenant_org_i_key ON public.academy_manager_trainees USING btree (manager_id, trainee_id, tenant_org_id)"},{"name":"academy_manager_trainees_pkey","definition":"CREATE UNIQUE INDEX academy_manager_trainees_pkey ON public.academy_manager_trainees USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"academy_manager_trainees","permissive":"PERMISSIVE","policyname":"Admins can manage assignments","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((uid() = manager_id) OR (uid() = trainee_id) OR is_system_admin(uid()))","roles":["public"],"tablename":"academy_manager_trainees","permissive":"PERMISSIVE","policyname":"Managers can view their trainees","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_manager_trainees_manager_id_trainee_id_tenant_org_i_key","definition":"UNIQUE (manager_id, trainee_id, tenant_org_id)"},{"name":"academy_manager_trainees_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_module_keys","schema":"public","columns":[{"name":"key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"verticals","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_module_keys_pkey","definition":"CREATE UNIQUE INDEX academy_module_keys_pkey ON public.academy_module_keys USING btree (key)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"academy_module_keys","permissive":"PERMISSIVE","policyname":"auth read module_keys","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_module_keys","permissive":"PERMISSIVE","policyname":"godmode write module_keys","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"academy_module_keys_pkey","definition":"PRIMARY KEY (key)"}]},{"table":"academy_provisioning_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"academy_track","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"details","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_provisioning_events_pkey","definition":"CREATE UNIQUE INDEX academy_provisioning_events_pkey ON public.academy_provisioning_events USING btree (id)"},{"name":"academy_provisioning_events_tenant_user_idx","definition":"CREATE INDEX academy_provisioning_events_tenant_user_idx ON public.academy_provisioning_events USING btree (tenant_id, user_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"((user_id = uid()) OR is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = academy_provisioning_events.tenant_id) AND (membership.status = 'active'::text)))))","roles":["authenticated"],"tablename":"academy_provisioning_events","permissive":"PERMISSIVE","policyname":"academy_provisioning_events_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_provisioning_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_provisioning_events_status_check","definition":"CHECK (status = ANY (ARRAY['success'::text, 'noop'::text, 'failed'::text]))"}]},{"table":"academy_quiz_attempts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"course_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lesson_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"score","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"passed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"answers","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"attempted_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_quiz_attempts_pkey","definition":"CREATE UNIQUE INDEX academy_quiz_attempts_pkey ON public.academy_quiz_attempts USING btree (id)"},{"name":"idx_academy_quiz_attempts_user_course","definition":"CREATE INDEX idx_academy_quiz_attempts_user_course ON public.academy_quiz_attempts USING btree (user_id, course_id, attempted_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"academy_quiz_attempts","permissive":"PERMISSIVE","policyname":"Users create own Academy attempts","schemaname":"public","with_check":"((user_id = uid()) AND (is_tenant_member(tenant_org_id) OR (tenant_org_id = 'platform'::text) OR is_system_admin(uid())))"},{"cmd":"SELECT","qual":"((user_id = uid()) OR is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_quiz_attempts","permissive":"PERMISSIVE","policyname":"Users read own Academy attempts","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_quiz_attempts_course_id_fkey","definition":"FOREIGN KEY (course_id) REFERENCES academy_courses(id) ON DELETE CASCADE"},{"name":"academy_quiz_attempts_lesson_id_fkey","definition":"FOREIGN KEY (lesson_id) REFERENCES academy_lessons(id) ON DELETE CASCADE"},{"name":"academy_quiz_attempts_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_quiz_attempts_score_check","definition":"CHECK (score >= 0 AND score <= 100)"}]},{"table":"academy_quiz_questions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"lesson_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"question_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"options","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"correct_answer_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"explanation","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_quiz_questions_pkey","definition":"CREATE UNIQUE INDEX academy_quiz_questions_pkey ON public.academy_quiz_questions USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM ((academy_lessons l\n     JOIN academy_units u ON ((u.id = l.unit_id)))\n     JOIN academy_courses c ON ((c.id = u.course_id)))\n  WHERE ((l.id = academy_quiz_questions.lesson_id) AND (is_system_admin(uid()) OR is_tenant_owner_for(uid(), c.tenant_org_id)))))","roles":["public"],"tablename":"academy_quiz_questions","permissive":"PERMISSIVE","policyname":"Admins can manage quiz questions","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM ((academy_lessons l\n     JOIN academy_units u ON ((u.id = l.unit_id)))\n     JOIN academy_courses c ON ((c.id = u.course_id)))\n  WHERE ((l.id = academy_quiz_questions.lesson_id) AND academy_course_visible(c.tenant_org_id, c.is_published))))","roles":["public"],"tablename":"academy_quiz_questions","permissive":"PERMISSIVE","policyname":"Viewable via lesson access","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_quiz_questions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_roleplay_feedback","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"coach_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"trainee_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"feedback_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rating","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_roleplay_feedback_pkey","definition":"CREATE UNIQUE INDEX academy_roleplay_feedback_pkey ON public.academy_roleplay_feedback USING btree (id)"},{"name":"idx_arf_session","definition":"CREATE INDEX idx_arf_session ON public.academy_roleplay_feedback USING btree (session_id)"},{"name":"idx_arf_trainee","definition":"CREATE INDEX idx_arf_trainee ON public.academy_roleplay_feedback USING btree (trainee_id)"}],"policies":[{"cmd":"DELETE","qual":"(uid() = coach_id)","roles":["authenticated"],"tablename":"academy_roleplay_feedback","permissive":"PERMISSIVE","policyname":"Coaches delete their feedback","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"academy_roleplay_feedback","permissive":"PERMISSIVE","policyname":"Coaches insert their feedback","schemaname":"public","with_check":"((uid() = coach_id) AND ((tenant_org_id IS NULL) OR is_tenant_member(tenant_org_id) OR is_system_admin(uid())))"},{"cmd":"UPDATE","qual":"(uid() = coach_id)","roles":["authenticated"],"tablename":"academy_roleplay_feedback","permissive":"PERMISSIVE","policyname":"Coaches update their feedback","schemaname":"public","with_check":"((uid() = coach_id) AND ((tenant_org_id IS NULL) OR is_tenant_member(tenant_org_id) OR is_system_admin(uid())))"},{"cmd":"SELECT","qual":"((uid() = trainee_id) OR (uid() = coach_id))","roles":["authenticated"],"tablename":"academy_roleplay_feedback","permissive":"PERMISSIVE","policyname":"Trainee or coach views feedback","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_roleplay_feedback_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_roleplay_feedback_rating_check","definition":"CHECK (rating >= 1 AND rating <= 5)"}]},{"table":"academy_roleplay_scenarios","schema":"public","columns":[{"name":"scenario_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"icon","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"scope","type":"text","default":"'global'::text","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"required_roles","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"module_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"workflow_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"verticals","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"is_published","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_roleplay_scenarios_pkey","definition":"CREATE UNIQUE INDEX academy_roleplay_scenarios_pkey ON public.academy_roleplay_scenarios USING btree (scenario_key)"}],"policies":[{"cmd":"SELECT","qual":"((scope = 'global'::text) OR is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_roleplay_scenarios","permissive":"PERMISSIVE","policyname":"auth read global scenarios","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(is_system_admin(uid()) OR ((scope = 'tenant'::text) AND is_tenant_owner_for(uid(), tenant_org_id)))","roles":["authenticated"],"tablename":"academy_roleplay_scenarios","permissive":"PERMISSIVE","policyname":"owners write tenant scenarios","schemaname":"public","with_check":"(is_system_admin(uid()) OR ((scope = 'tenant'::text) AND is_tenant_owner_for(uid(), tenant_org_id)))"}],"triggers":[],"constraints":[{"name":"academy_roleplay_scenarios_pkey","definition":"PRIMARY KEY (scenario_key)"},{"name":"scenario_scope_check","definition":"CHECK (scope = ANY (ARRAY['global'::text, 'tenant'::text]))"},{"name":"tenant_scope_has_org","definition":"CHECK (scope = 'global'::text OR tenant_org_id IS NOT NULL)"}]},{"table":"academy_roleplay_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scenario_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_track","type":"text","default":"'universal'::text","identity":"","not_null":true,"generated":""},{"name":"messages","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"feedback","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_roleplay_sessions_pkey","definition":"CREATE UNIQUE INDEX academy_roleplay_sessions_pkey ON public.academy_roleplay_sessions USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"can_view_tenant_member_academy(uid(), user_id)","roles":["authenticated"],"tablename":"academy_roleplay_sessions","permissive":"PERMISSIVE","policyname":"Tenant owners view member roleplays","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"academy_roleplay_sessions","permissive":"PERMISSIVE","policyname":"Users can create sessions","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["public"],"tablename":"academy_roleplay_sessions","permissive":"PERMISSIVE","policyname":"Users can update own sessions","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["public"],"tablename":"academy_roleplay_sessions","permissive":"PERMISSIVE","policyname":"Users can view own sessions","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_roleplay_sessions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_scripts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"content","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'general'::text","identity":"","not_null":true,"generated":""},{"name":"tenant_track","type":"text","default":"'universal'::text","identity":"","not_null":true,"generated":""},{"name":"difficulty_level","type":"text","default":"'beginner'::text","identity":"","not_null":false,"generated":""},{"name":"tags","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"is_published","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"required_roles","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"module_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"workflow_key","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_scripts_pkey","definition":"CREATE UNIQUE INDEX academy_scripts_pkey ON public.academy_scripts USING btree (id)"},{"name":"idx_academy_scripts_module","definition":"CREATE INDEX idx_academy_scripts_module ON public.academy_scripts USING btree (module_key)"},{"name":"idx_academy_scripts_workflow","definition":"CREATE INDEX idx_academy_scripts_workflow ON public.academy_scripts USING btree (workflow_key)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR is_tenant_owner_for(uid(), tenant_org_id))","roles":["public"],"tablename":"academy_scripts","permissive":"PERMISSIVE","policyname":"Admins can manage scripts","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) AND (is_published = true))","roles":["public"],"tablename":"academy_scripts","permissive":"PERMISSIVE","policyname":"Tenant members can view scripts","schemaname":"public","with_check":null}],"triggers":[{"name":"update_academy_scripts_updated_at","definition":"CREATE TRIGGER update_academy_scripts_updated_at BEFORE UPDATE ON academy_scripts FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"academy_scripts_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_scripts_tenant_track_check","definition":"CHECK (tenant_track = ANY (ARRAY['mitigation'::text, 'roofing'::text, 'public_adjuster'::text, 'realtor'::text, 'universal'::text]))"}]},{"table":"academy_tenant_course_overrides","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_course_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"override_course_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_hidden","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"is_required","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_tenant_course_overrid_tenant_org_id_source_course_i_key","definition":"CREATE UNIQUE INDEX academy_tenant_course_overrid_tenant_org_id_source_course_i_key ON public.academy_tenant_course_overrides USING btree (tenant_org_id, source_course_id)"},{"name":"academy_tenant_course_overrides_pkey","definition":"CREATE UNIQUE INDEX academy_tenant_course_overrides_pkey ON public.academy_tenant_course_overrides USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_tenant_course_overrides","permissive":"PERMISSIVE","policyname":"Owners manage Academy course overrides","schemaname":"public","with_check":"(is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_tenant_course_overrides","permissive":"PERMISSIVE","policyname":"Tenant members read Academy course overrides","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_tenant_course_overrid_tenant_org_id_source_course_i_key","definition":"UNIQUE (tenant_org_id, source_course_id)"},{"name":"academy_tenant_course_overrides_override_course_id_fkey","definition":"FOREIGN KEY (override_course_id) REFERENCES academy_courses(id) ON DELETE SET NULL"},{"name":"academy_tenant_course_overrides_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_tenant_course_overrides_source_course_id_fkey","definition":"FOREIGN KEY (source_course_id) REFERENCES academy_courses(id) ON DELETE CASCADE"}]},{"table":"academy_tenant_modules","schema":"public","columns":[{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"module_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"enabled_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"enabled_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_tenant_modules_pkey","definition":"CREATE UNIQUE INDEX academy_tenant_modules_pkey ON public.academy_tenant_modules USING btree (tenant_org_id, module_key)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IS NOT NULL)","roles":["authenticated"],"tablename":"academy_tenant_modules","permissive":"RESTRICTIVE","policyname":"block null tenant modules","schemaname":"public","with_check":"(tenant_org_id IS NOT NULL)"},{"cmd":"ALL","qual":"(is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_tenant_modules","permissive":"PERMISSIVE","policyname":"owners write modules","schemaname":"public","with_check":"(is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_tenant_modules","permissive":"PERMISSIVE","policyname":"tenant members read modules","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_tenant_modules_pkey","definition":"PRIMARY KEY (tenant_org_id, module_key)"}]},{"table":"academy_trainee_progress","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lesson_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"course_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'not_started'::text","identity":"","not_null":true,"generated":""},{"name":"score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_trainee_progress_pkey","definition":"CREATE UNIQUE INDEX academy_trainee_progress_pkey ON public.academy_trainee_progress USING btree (id)"},{"name":"academy_trainee_progress_user_id_lesson_id_key","definition":"CREATE UNIQUE INDEX academy_trainee_progress_user_id_lesson_id_key ON public.academy_trainee_progress USING btree (user_id, lesson_id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"academy_trainee_progress","permissive":"PERMISSIVE","policyname":"Admins can view all progress","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"can_view_tenant_member_academy(uid(), user_id)","roles":["authenticated"],"tablename":"academy_trainee_progress","permissive":"PERMISSIVE","policyname":"Tenant owners view member progress","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"academy_trainee_progress","permissive":"PERMISSIVE","policyname":"Users can manage own progress","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["public"],"tablename":"academy_trainee_progress","permissive":"PERMISSIVE","policyname":"Users can update own progress","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["public"],"tablename":"academy_trainee_progress","permissive":"PERMISSIVE","policyname":"Users can view own progress","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_sync_enrollment_progress","definition":"CREATE TRIGGER trg_sync_enrollment_progress AFTER INSERT OR DELETE OR UPDATE ON academy_trainee_progress FOR EACH ROW EXECUTE FUNCTION tg_sync_enrollment_progress()"},{"name":"update_academy_trainee_progress_updated_at","definition":"CREATE TRIGGER update_academy_trainee_progress_updated_at BEFORE UPDATE ON academy_trainee_progress FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"academy_trainee_progress_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_trainee_progress_status_check","definition":"CHECK (status = ANY (ARRAY['not_started'::text, 'in_progress'::text, 'completed'::text]))"},{"name":"academy_trainee_progress_user_id_lesson_id_key","definition":"UNIQUE (user_id, lesson_id)"}]},{"table":"academy_units","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"course_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_units_pkey","definition":"CREATE UNIQUE INDEX academy_units_pkey ON public.academy_units USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM academy_courses c\n  WHERE ((c.id = academy_units.course_id) AND (is_system_admin(uid()) OR is_tenant_owner_for(uid(), c.tenant_org_id)))))","roles":["public"],"tablename":"academy_units","permissive":"PERMISSIVE","policyname":"Admins can manage units","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM academy_courses c\n  WHERE ((c.id = academy_units.course_id) AND academy_course_visible(c.tenant_org_id, c.is_published))))","roles":["public"],"tablename":"academy_units","permissive":"PERMISSIVE","policyname":"Viewable via course access","schemaname":"public","with_check":null}],"triggers":[{"name":"update_academy_units_updated_at","definition":"CREATE TRIGGER update_academy_units_updated_at BEFORE UPDATE ON academy_units FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"academy_units_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"academy_user_assignments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"course_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assigned_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'assigned'::text","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_user_assignments_pkey","definition":"CREATE UNIQUE INDEX academy_user_assignments_pkey ON public.academy_user_assignments USING btree (id)"},{"name":"academy_user_assignments_tenant_org_id_user_id_course_id_key","definition":"CREATE UNIQUE INDEX academy_user_assignments_tenant_org_id_user_id_course_id_key ON public.academy_user_assignments USING btree (tenant_org_id, user_id, course_id)"},{"name":"idx_academy_user_assignments_user","definition":"CREATE INDEX idx_academy_user_assignments_user ON public.academy_user_assignments USING btree (user_id, status)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IS NOT NULL)","roles":["authenticated"],"tablename":"academy_user_assignments","permissive":"RESTRICTIVE","policyname":"block null tenant assignments","schemaname":"public","with_check":"(tenant_org_id IS NOT NULL)"},{"cmd":"ALL","qual":"(is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_user_assignments","permissive":"PERMISSIVE","policyname":"owners write assignments","schemaname":"public","with_check":"(is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((user_id = uid()) OR is_tenant_owner_for(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"academy_user_assignments","permissive":"PERMISSIVE","policyname":"self read assignments","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_user_assignments_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_user_assignments_tenant_org_id_user_id_course_id_key","definition":"UNIQUE (tenant_org_id, user_id, course_id)"}]},{"table":"academy_user_badges","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"badge_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"earned_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_user_badges_pkey","definition":"CREATE UNIQUE INDEX academy_user_badges_pkey ON public.academy_user_badges USING btree (id)"},{"name":"academy_user_badges_user_id_badge_id_key","definition":"CREATE UNIQUE INDEX academy_user_badges_user_id_badge_id_key ON public.academy_user_badges USING btree (user_id, badge_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"academy_user_badges","permissive":"PERMISSIVE","policyname":"System can award badges","schemaname":"public","with_check":"((uid() = user_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"can_view_tenant_member_academy(uid(), user_id)","roles":["authenticated"],"tablename":"academy_user_badges","permissive":"PERMISSIVE","policyname":"Tenant owners view member badges","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["public"],"tablename":"academy_user_badges","permissive":"PERMISSIVE","policyname":"Users can view own badges","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"academy_user_badges_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_user_badges_user_id_badge_id_key","definition":"UNIQUE (user_id, badge_id)"}]},{"table":"academy_user_points","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"total_points","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"streak_days","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"last_activity_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"academy_user_points_pkey","definition":"CREATE UNIQUE INDEX academy_user_points_pkey ON public.academy_user_points USING btree (id)"},{"name":"academy_user_points_user_id_tenant_org_id_key","definition":"CREATE UNIQUE INDEX academy_user_points_user_id_tenant_org_id_key ON public.academy_user_points USING btree (user_id, tenant_org_id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["public"],"tablename":"academy_user_points","permissive":"PERMISSIVE","policyname":"Tenant members can view leaderboard","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"academy_user_points","permissive":"PERMISSIVE","policyname":"Users can manage own points","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["public"],"tablename":"academy_user_points","permissive":"PERMISSIVE","policyname":"Users can update own points","schemaname":"public","with_check":null}],"triggers":[{"name":"update_academy_user_points_updated_at","definition":"CREATE TRIGGER update_academy_user_points_updated_at BEFORE UPDATE ON academy_user_points FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"academy_user_points_pkey","definition":"PRIMARY KEY (id)"},{"name":"academy_user_points_user_id_tenant_org_id_key","definition":"UNIQUE (user_id, tenant_org_id)"}]},{"table":"academy_workflow_keys","schema":"public","columns":[{"name":"key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"module_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"academy_workflow_keys_pkey","definition":"CREATE UNIQUE INDEX academy_workflow_keys_pkey ON public.academy_workflow_keys USING btree (key)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"academy_workflow_keys","permissive":"PERMISSIVE","policyname":"auth read workflow_keys","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"academy_workflow_keys","permissive":"PERMISSIVE","policyname":"godmode write workflow_keys","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"academy_workflow_keys_pkey","definition":"PRIMARY KEY (key)"}]},{"table":"acceptance_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signer_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_version","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_agreement_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"session_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"acceptance_events_pkey","definition":"CREATE UNIQUE INDEX acceptance_events_pkey ON public.acceptance_events USING btree (id)"},{"name":"idx_acceptance_events_created_at","definition":"CREATE INDEX idx_acceptance_events_created_at ON public.acceptance_events USING btree (created_at DESC)"},{"name":"idx_acceptance_events_event_type","definition":"CREATE INDEX idx_acceptance_events_event_type ON public.acceptance_events USING btree (event_type)"},{"name":"idx_acceptance_events_template","definition":"CREATE INDEX idx_acceptance_events_template ON public.acceptance_events USING btree (template_id)"},{"name":"idx_acceptance_events_user_tenant","definition":"CREATE INDEX idx_acceptance_events_user_tenant ON public.acceptance_events USING btree (user_id, tenant_id)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND (ur.tenant_id = acceptance_events.tenant_id) AND ((ur.role)::text = ANY (ARRAY['Owner'::text, 'Tenant Owner'::text, 'Admin'::text]))))))","roles":["authenticated"],"tablename":"acceptance_events","permissive":"PERMISSIVE","policyname":"Admins can view tenant acceptance events","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"acceptance_events","permissive":"PERMISSIVE","policyname":"Authenticated users can insert their own acceptance events","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"SELECT","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"acceptance_events","permissive":"PERMISSIVE","policyname":"Users can view their own acceptance events","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_acceptance_events_no_delete","definition":"CREATE TRIGGER trg_acceptance_events_no_delete BEFORE DELETE ON acceptance_events FOR EACH ROW EXECUTE FUNCTION block_mutation_append_only()"},{"name":"trg_acceptance_events_no_update","definition":"CREATE TRIGGER trg_acceptance_events_no_update BEFORE UPDATE ON acceptance_events FOR EACH ROW EXECUTE FUNCTION block_mutation_append_only()"}],"constraints":[{"name":"acceptance_events_event_type_check","definition":"CHECK (event_type = ANY (ARRAY['gate_shown'::text, 'document_viewed'::text, 'document_downloaded'::text, 'document_emailed'::text, 'declined'::text, 'signed'::text, 'reaccepted_after_bump'::text, 'superseded'::text]))"},{"name":"acceptance_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"achievements","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"achievement_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"icon","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"unlock_criteria","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"points","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"rarity","type":"text","default":"'common'::text","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"achievements_achievement_key_key","definition":"CREATE UNIQUE INDEX achievements_achievement_key_key ON public.achievements USING btree (achievement_key)"},{"name":"achievements_pkey","definition":"CREATE UNIQUE INDEX achievements_pkey ON public.achievements USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["public"],"tablename":"achievements","permissive":"PERMISSIVE","policyname":"All users view achievements","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"achievements_achievement_key_key","definition":"UNIQUE (achievement_key)"},{"name":"achievements_pkey","definition":"PRIMARY KEY (id)"},{"name":"achievements_rarity_check","definition":"CHECK (rarity = ANY (ARRAY['common'::text, 'rare'::text, 'epic'::text, 'legendary'::text]))"}]},{"table":"acting_pm_grants","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"granted_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"granted_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"acting_pm_grants_pkey","definition":"CREATE UNIQUE INDEX acting_pm_grants_pkey ON public.acting_pm_grants USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(is_manager_or_higher_strict(uid(), tenant_id) OR (user_id = uid()) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"acting_pm_grants","permissive":"PERMISSIVE","policyname":"acting_pm_grants_select","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(is_manager_or_higher_strict(uid(), tenant_id) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"acting_pm_grants","permissive":"PERMISSIVE","policyname":"acting_pm_grants_write","schemaname":"public","with_check":"(is_manager_or_higher_strict(uid(), tenant_id) OR is_platform_admin(uid()))"}],"triggers":[],"constraints":[{"name":"acting_pm_grants_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"action_errors","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"route","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_component","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"button_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"domain","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"action_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"payload","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"action_errors_pkey","definition":"CREATE UNIQUE INDEX action_errors_pkey ON public.action_errors USING btree (id)"},{"name":"idx_action_errors_action_id","definition":"CREATE INDEX idx_action_errors_action_id ON public.action_errors USING btree (action_id)"},{"name":"idx_action_errors_created_at","definition":"CREATE INDEX idx_action_errors_created_at ON public.action_errors USING btree (created_at DESC)"},{"name":"idx_action_errors_domain","definition":"CREATE INDEX idx_action_errors_domain ON public.action_errors USING btree (domain)"},{"name":"idx_action_errors_resolved","definition":"CREATE INDEX idx_action_errors_resolved ON public.action_errors USING btree (resolved_at) WHERE (resolved_at IS NULL)"},{"name":"idx_action_errors_user_id","definition":"CREATE INDEX idx_action_errors_user_id ON public.action_errors USING btree (user_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"action_errors","permissive":"PERMISSIVE","policyname":"Users can log their own action errors","schemaname":"public","with_check":"((uid() = user_id) OR (user_id IS NULL))"},{"cmd":"UPDATE","qual":"is_system_admin(uid())","roles":["public"],"tablename":"action_errors","permissive":"PERMISSIVE","policyname":"platform_admin_update_action_errors","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"action_errors","permissive":"PERMISSIVE","policyname":"platform_admin_view_action_errors","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"action_errors_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"active_call_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":"'twilio'::text","identity":"","not_null":true,"generated":""},{"name":"parent_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"homeowner_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'initiated'::text","identity":"","not_null":true,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"ended_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"force_ended_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"force_ended_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"force_ended_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"voicemail_armed_template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"voicemail_armed_slot","type":"smallint","default":null,"identity":"","not_null":false,"generated":""},{"name":"voicemail_armed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"terminal_outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"terminal_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"auto_advanced","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"drop_and_go_state","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"active_call_sessions_pkey","definition":"CREATE UNIQUE INDEX active_call_sessions_pkey ON public.active_call_sessions USING btree (id)"},{"name":"idx_acs_rep_active","definition":"CREATE INDEX idx_acs_rep_active ON public.active_call_sessions USING btree (rep_id, status)"},{"name":"idx_acs_tenant","definition":"CREATE INDEX idx_acs_tenant ON public.active_call_sessions USING btree (tenant_org_id)"},{"name":"idx_acs_terminal","definition":"CREATE INDEX idx_acs_terminal ON public.active_call_sessions USING btree (rep_id, terminal_at DESC) WHERE (terminal_outcome IS NOT NULL)"},{"name":"idx_acs_vm_armed","definition":"CREATE INDEX idx_acs_vm_armed ON public.active_call_sessions USING btree (voicemail_armed_template_id) WHERE (voicemail_armed_template_id IS NOT NULL)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"active_call_sessions","permissive":"PERMISSIVE","policyname":"acs_insert_self","schemaname":"public","with_check":"(((rep_id = uid()) AND is_tenant_member(tenant_org_id)) OR is_system_admin())"},{"cmd":"SELECT","qual":"((rep_id = uid()) OR (is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())","roles":["public"],"tablename":"active_call_sessions","permissive":"PERMISSIVE","policyname":"acs_select_tenant","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((rep_id = uid()) OR (is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())","roles":["public"],"tablename":"active_call_sessions","permissive":"PERMISSIVE","policyname":"acs_update_self","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"active_call_sessions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"activity_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"activity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"activity_log_pkey","definition":"CREATE UNIQUE INDEX activity_log_pkey ON public.activity_log USING btree (id)"},{"name":"idx_activity_log_contact_id","definition":"CREATE INDEX idx_activity_log_contact_id ON public.activity_log USING btree (contact_id)"},{"name":"idx_activity_log_created_at","definition":"CREATE INDEX idx_activity_log_created_at ON public.activity_log USING btree (created_at DESC)"},{"name":"idx_activity_log_tenant_id","definition":"CREATE INDEX idx_activity_log_tenant_id ON public.activity_log USING btree (tenant_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"activity_log","permissive":"PERMISSIVE","policyname":"Users create activities","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = activity_log.tenant_id))))","roles":["public"],"tablename":"activity_log","permissive":"PERMISSIVE","policyname":"Users view tenant activities","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"activity_log_pkey","definition":"PRIMARY KEY (id)"},{"name":"activity_log_verified_external_actor_check","definition":"CHECK (user_id IS NOT NULL OR activity_type = 'portal_message'::text AND (metadata ->> 'source'::text) = 'customer_portal'::text)"}]},{"table":"activity_timeline","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"activity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"related_entity_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_entity_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"importance","type":"text","default":"'normal'::text","identity":"","not_null":false,"generated":""},{"name":"is_system_generated","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"event_domain","type":"text","default":"'activity'::text","identity":"","not_null":true,"generated":""},{"name":"source_channel","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"touch_channel","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_detail","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_campaign","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_referrer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_system","type":"text","default":"'knocklaunch'::text","identity":"","not_null":true,"generated":""},{"name":"source_record_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_record_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"correlation_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"previous_state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"monetary_value","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"currency","type":"text","default":"'USD'::text","identity":"","not_null":true,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"corrects_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"dedupe_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recorded_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"activity_timeline_contact_created_idx","definition":"CREATE INDEX activity_timeline_contact_created_idx ON public.activity_timeline USING btree (tenant_org_id, contact_id, created_at DESC) WHERE (contact_id IS NOT NULL)"},{"name":"activity_timeline_correlation_idx","definition":"CREATE INDEX activity_timeline_correlation_idx ON public.activity_timeline USING btree (tenant_org_id, correlation_key, created_at DESC) WHERE (correlation_key IS NOT NULL)"},{"name":"activity_timeline_pkey","definition":"CREATE UNIQUE INDEX activity_timeline_pkey ON public.activity_timeline USING btree (id)"},{"name":"activity_timeline_source_created_idx","definition":"CREATE INDEX activity_timeline_source_created_idx ON public.activity_timeline USING btree (tenant_org_id, source_channel, created_at DESC) WHERE (source_channel IS NOT NULL)"},{"name":"activity_timeline_tenant_created_idx","definition":"CREATE INDEX activity_timeline_tenant_created_idx ON public.activity_timeline USING btree (tenant_org_id, created_at DESC)"},{"name":"activity_timeline_tenant_dedupe_uidx","definition":"CREATE UNIQUE INDEX activity_timeline_tenant_dedupe_uidx ON public.activity_timeline USING btree (tenant_org_id, dedupe_key) WHERE (dedupe_key IS NOT NULL)"},{"name":"activity_timeline_touch_created_idx","definition":"CREATE INDEX activity_timeline_touch_created_idx ON public.activity_timeline USING btree (tenant_org_id, touch_channel, created_at DESC) WHERE (touch_channel IS NOT NULL)"},{"name":"idx_activity_timeline_contact","definition":"CREATE INDEX idx_activity_timeline_contact ON public.activity_timeline USING btree (contact_id)"}],"policies":[{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"activity_timeline","permissive":"PERMISSIVE","policyname":"activity_timeline_platform_admin_select","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"ai_user_in_tenant(tenant_org_id)","roles":["authenticated"],"tablename":"activity_timeline","permissive":"PERMISSIVE","policyname":"activity_timeline_tenant_select","schemaname":"public","with_check":null}],"triggers":[{"name":"activity_timeline_append_only","definition":"CREATE TRIGGER activity_timeline_append_only BEFORE DELETE OR UPDATE ON activity_timeline FOR EACH ROW EXECUTE FUNCTION prevent_business_activity_mutation()"},{"name":"activity_timeline_normalize_insert","definition":"CREATE TRIGGER activity_timeline_normalize_insert BEFORE INSERT ON activity_timeline FOR EACH ROW EXECUTE FUNCTION activity_timeline_normalize_insert()"}],"constraints":[{"name":"activity_timeline_activity_type_check","definition":"CHECK ((activity_type = ANY (ARRAY['call'::text, 'email'::text, 'sms'::text, 'note'::text, 'task'::text, 'meeting'::text, 'status_change'::text, 'stage_change'::text, 'assignment'::text, 'document'::text, 'photo'::text, 'automation'::text, 'score_change'::text, 'merge'::text, 'import'::text, 'export'::text, 'field_update'::text, 'contact_created'::text, 'contact_updated'::text, 'job_created'::text, 'job_updated'::text, 'invoice_created'::text, 'invoice_paid'::text, 'invoice_updated'::text, 'settlement_invoice_created'::text, 'settlement_invoice_paid'::text, 'settlement_invoice_updated'::text, 'business_joined_platform'::text, 'business_lifecycle_updated'::text])) OR activity_type ~ '^(opportunity|communication|document|user|proposal|agreement|signed_agreement|task|booking)_[A-Za-z0-9_.:-]+$'::text)"},{"name":"activity_timeline_corrects_event_id_fkey","definition":"FOREIGN KEY (corrects_event_id) REFERENCES activity_timeline(id) ON DELETE RESTRICT"},{"name":"activity_timeline_importance_check","definition":"CHECK (importance = ANY (ARRAY['low'::text, 'normal'::text, 'high'::text, 'critical'::text]))"},{"name":"activity_timeline_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"admin_saved_queries","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sql_query","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_shared","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"admin_saved_queries_created_by_idx","definition":"CREATE INDEX admin_saved_queries_created_by_idx ON public.admin_saved_queries USING btree (created_by, created_at DESC)"},{"name":"admin_saved_queries_pkey","definition":"CREATE UNIQUE INDEX admin_saved_queries_pkey ON public.admin_saved_queries USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"admin_saved_queries","permissive":"PERMISSIVE","policyname":"Admins create saved queries","schemaname":"public","with_check":"((uid() = created_by) AND is_platform_admin(uid()))"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"admin_saved_queries","permissive":"PERMISSIVE","policyname":"Admins read saved queries","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((uid() = created_by) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"admin_saved_queries","permissive":"PERMISSIVE","policyname":"Owners or admins delete saved queries","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((uid() = created_by) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"admin_saved_queries","permissive":"PERMISSIVE","policyname":"Owners or admins update saved queries","schemaname":"public","with_check":"((uid() = created_by) OR is_platform_admin(uid()))"}],"triggers":[{"name":"admin_saved_queries_set_updated_at","definition":"CREATE TRIGGER admin_saved_queries_set_updated_at BEFORE UPDATE ON admin_saved_queries FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"admin_saved_queries_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"aerial_measurement_orders","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"estimate_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"order_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_order_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"property_address","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lat","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"lng","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"product_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"report_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"report_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ordered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"aerial_measurement_orders_pkey","definition":"CREATE UNIQUE INDEX aerial_measurement_orders_pkey ON public.aerial_measurement_orders USING btree (id)"},{"name":"idx_aerial_orders_contact","definition":"CREATE INDEX idx_aerial_orders_contact ON public.aerial_measurement_orders USING btree (contact_id)"},{"name":"idx_aerial_orders_estimate","definition":"CREATE INDEX idx_aerial_orders_estimate ON public.aerial_measurement_orders USING btree (estimate_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"aerial_measurement_orders","permissive":"PERMISSIVE","policyname":"Users create tenant aerial orders","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"aerial_measurement_orders","permissive":"PERMISSIVE","policyname":"Users update tenant aerial orders","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"aerial_measurement_orders","permissive":"PERMISSIVE","policyname":"Users view tenant aerial orders","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"aerial_measurement_orders_pkey","definition":"PRIMARY KEY (id)"},{"name":"aerial_measurement_orders_provider_check","definition":"CHECK (provider = ANY (ARRAY['eagleview'::text, 'gaf'::text, 'roofsnap'::text, 'other'::text]))"},{"name":"aerial_measurement_orders_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'ordered'::text, 'processing'::text, 'completed'::text, 'failed'::text, 'cancelled'::text]))"}]},{"table":"agent_presence","schema":"public","columns":[{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'offline'::text","identity":"","not_null":true,"generated":""},{"name":"current_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_seen_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"agent_presence_pkey","definition":"CREATE UNIQUE INDEX agent_presence_pkey ON public.agent_presence USING btree (user_id)"},{"name":"idx_agent_presence_tenant","definition":"CREATE INDEX idx_agent_presence_tenant ON public.agent_presence USING btree (tenant_id, status)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"agent_presence","permissive":"PERMISSIVE","policyname":"Reps insert own presence","schemaname":"public","with_check":"((user_id = uid()) AND is_tenant_member(uid(), tenant_id))"},{"cmd":"UPDATE","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"agent_presence","permissive":"PERMISSIVE","policyname":"Reps update own presence","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"agent_presence","permissive":"PERMISSIVE","policyname":"Tenant members view presence","schemaname":"public","with_check":null}],"triggers":[{"name":"update_agent_presence_updated_at","definition":"CREATE TRIGGER update_agent_presence_updated_at BEFORE UPDATE ON agent_presence FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"agent_presence_pkey","definition":"PRIMARY KEY (user_id)"},{"name":"agent_presence_status_check","definition":"CHECK (status = ANY (ARRAY['available'::text, 'on_call'::text, 'wrap_up'::text, 'break'::text, 'offline'::text]))"}]},{"table":"agreement_requirements","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"min_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"is_required","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"display_order","type":"integer","default":"100","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"agreement_requirements_pkey","definition":"CREATE UNIQUE INDEX agreement_requirements_pkey ON public.agreement_requirements USING btree (id)"},{"name":"agreement_requirements_tenant_type_role_template_type_tenan_key","definition":"CREATE UNIQUE INDEX agreement_requirements_tenant_type_role_template_type_tenan_key ON public.agreement_requirements USING btree (tenant_type, role, template_type, tenant_id)"},{"name":"idx_agreement_requirements_lookup","definition":"CREATE INDEX idx_agreement_requirements_lookup ON public.agreement_requirements USING btree (tenant_type, role, is_required)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"agreement_requirements","permissive":"PERMISSIVE","policyname":"Authenticated users can read applicable requirements","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"agreement_requirements","permissive":"PERMISSIVE","policyname":"System admins manage all requirements","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"ALL","qual":"((tenant_id IS NOT NULL) AND (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = (agreement_requirements.tenant_id)::text) AND ((ur.role)::text = ANY (ARRAY['Owner'::text, 'Tenant Owner'::text, 'Admin'::text]))))))","roles":["authenticated"],"tablename":"agreement_requirements","permissive":"PERMISSIVE","policyname":"Tenant owners manage their tenant requirements","schemaname":"public","with_check":"((tenant_id IS NOT NULL) AND (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = (agreement_requirements.tenant_id)::text) AND ((ur.role)::text = ANY (ARRAY['Owner'::text, 'Tenant Owner'::text, 'Admin'::text]))))))"}],"triggers":[{"name":"trg_agreement_requirements_updated_at","definition":"CREATE TRIGGER trg_agreement_requirements_updated_at BEFORE UPDATE ON agreement_requirements FOR EACH ROW EXECUTE FUNCTION tg_set_updated_at()"}],"constraints":[{"name":"agreement_requirements_pkey","definition":"PRIMARY KEY (id)"},{"name":"agreement_requirements_tenant_type_role_template_type_tenan_key","definition":"UNIQUE (tenant_type, role, template_type, tenant_id)"}]},{"table":"agreement_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"template_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"html_content","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"change_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_rep_visible","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"effective_date","type":"date","default":"CURRENT_DATE","identity":"","not_null":true,"generated":""},{"name":"requires_reacceptance_on_bump","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"applies_to_tenant_types","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"applies_to_roles","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"is_universal","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"short_description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"display_order","type":"integer","default":"100","identity":"","not_null":true,"generated":""},{"name":"derived_from_template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"adopted_admin_version","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"agreement_templates_pkey","definition":"CREATE UNIQUE INDEX agreement_templates_pkey ON public.agreement_templates USING btree (id)"},{"name":"idx_agreement_templates_active","definition":"CREATE INDEX idx_agreement_templates_active ON public.agreement_templates USING btree (is_active)"},{"name":"idx_agreement_templates_derived","definition":"CREATE INDEX idx_agreement_templates_derived ON public.agreement_templates USING btree (derived_from_template_id)"},{"name":"idx_agreement_templates_type","definition":"CREATE INDEX idx_agreement_templates_type ON public.agreement_templates USING btree (template_type)"},{"name":"uq_template_type_version","definition":"CREATE UNIQUE INDEX uq_template_type_version ON public.agreement_templates USING btree (template_type, version)"}],"policies":[{"cmd":"SELECT","qual":"((uid() IS NOT NULL) AND (is_active = true))","roles":["public"],"tablename":"agreement_templates","permissive":"PERMISSIVE","policyname":"Authenticated users can read active templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"agreement_templates","permissive":"PERMISSIVE","policyname":"System admins manage all agreement templates","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"ALL","qual":"((tenant_id IS NOT NULL) AND (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = (agreement_templates.tenant_id)::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role]))))))","roles":["authenticated"],"tablename":"agreement_templates","permissive":"PERMISSIVE","policyname":"Tenant admins manage their agreement templates","schemaname":"public","with_check":"((tenant_id IS NOT NULL) AND (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = (agreement_templates.tenant_id)::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role]))))))"}],"triggers":[],"constraints":[{"name":"agreement_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"uq_template_type_version","definition":"UNIQUE (template_type, version)"}]},{"table":"ai_conversations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"surface","type":"text","default":"'global'::text","identity":"","not_null":true,"generated":""},{"name":"context_lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"context_property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"context_workflow_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_archived","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"last_message_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"ai_conversations_lead_idx","definition":"CREATE INDEX ai_conversations_lead_idx ON public.ai_conversations USING btree (tenant_org_id, context_lead_id) WHERE (context_lead_id IS NOT NULL)"},{"name":"ai_conversations_pkey","definition":"CREATE UNIQUE INDEX ai_conversations_pkey ON public.ai_conversations USING btree (id)"},{"name":"ai_conversations_property_idx","definition":"CREATE INDEX ai_conversations_property_idx ON public.ai_conversations USING btree (tenant_org_id, context_property_id) WHERE (context_property_id IS NOT NULL)"},{"name":"ai_conversations_tenant_user_idx","definition":"CREATE INDEX ai_conversations_tenant_user_idx ON public.ai_conversations USING btree (tenant_org_id, user_id, last_message_at DESC)"}],"policies":[{"cmd":"DELETE","qual":"((user_id = uid()) OR ai_is_tenant_admin(tenant_org_id))","roles":["authenticated"],"tablename":"ai_conversations","permissive":"PERMISSIVE","policyname":"ai_conv_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"ai_conversations","permissive":"PERMISSIVE","policyname":"ai_conv_insert","schemaname":"public","with_check":"((user_id = uid()) AND ai_user_in_tenant(tenant_org_id))"},{"cmd":"SELECT","qual":"(ai_user_in_tenant(tenant_org_id) AND ((user_id = uid()) OR ai_is_tenant_admin(tenant_org_id)))","roles":["authenticated"],"tablename":"ai_conversations","permissive":"PERMISSIVE","policyname":"ai_conv_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((user_id = uid()) OR ai_is_tenant_admin(tenant_org_id))","roles":["authenticated"],"tablename":"ai_conversations","permissive":"PERMISSIVE","policyname":"ai_conv_update","schemaname":"public","with_check":"((user_id = uid()) OR ai_is_tenant_admin(tenant_org_id))"}],"triggers":[{"name":"ai_conv_touch","definition":"CREATE TRIGGER ai_conv_touch BEFORE UPDATE ON ai_conversations FOR EACH ROW EXECUTE FUNCTION ai_touch_updated_at()"}],"constraints":[{"name":"ai_conversations_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"ai_failures","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"failure_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"http_status","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"tool_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"redacted_payload","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"ai_failures_pkey","definition":"CREATE UNIQUE INDEX ai_failures_pkey ON public.ai_failures USING btree (id)"},{"name":"ai_failures_tenant_idx","definition":"CREATE INDEX ai_failures_tenant_idx ON public.ai_failures USING btree (tenant_org_id, created_at DESC)"},{"name":"ai_failures_type_idx","definition":"CREATE INDEX ai_failures_type_idx ON public.ai_failures USING btree (failure_type, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"((tenant_org_id IS NOT NULL) AND ai_is_tenant_admin(tenant_org_id))","roles":["authenticated"],"tablename":"ai_failures","permissive":"PERMISSIVE","policyname":"ai_fail_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"ai_failures_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"ai_messages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"content","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"structured","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"tool_calls","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"tool_call_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"model","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"prompt_tokens","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"completion_tokens","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"total_tokens","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"latency_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"warnings","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"ai_messages_conv_idx","definition":"CREATE INDEX ai_messages_conv_idx ON public.ai_messages USING btree (conversation_id, created_at)"},{"name":"ai_messages_pkey","definition":"CREATE UNIQUE INDEX ai_messages_pkey ON public.ai_messages USING btree (id)"},{"name":"ai_messages_tenant_idx","definition":"CREATE INDEX ai_messages_tenant_idx ON public.ai_messages USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"ai_messages","permissive":"PERMISSIVE","policyname":"ai_msg_insert","schemaname":"public","with_check":"((user_id = uid()) AND ai_user_in_tenant(tenant_org_id))"},{"cmd":"SELECT","qual":"(ai_user_in_tenant(tenant_org_id) AND ((user_id = uid()) OR ai_is_tenant_admin(tenant_org_id)))","roles":["authenticated"],"tablename":"ai_messages","permissive":"PERMISSIVE","policyname":"ai_msg_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"ai_messages_pkey","definition":"PRIMARY KEY (id)"},{"name":"ai_messages_role_check","definition":"CHECK (role = ANY (ARRAY['system'::text, 'user'::text, 'assistant'::text, 'tool'::text]))"}]},{"table":"ai_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"surface","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"prompt_category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"model","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"request_mode","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"prompt_tokens","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"completion_tokens","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"total_tokens","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"latency_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"tools_called","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"success","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"http_status","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"fallback_used","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"ip_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"ai_requests_pkey","definition":"CREATE UNIQUE INDEX ai_requests_pkey ON public.ai_requests USING btree (id)"},{"name":"ai_requests_tenant_idx","definition":"CREATE INDEX ai_requests_tenant_idx ON public.ai_requests USING btree (tenant_org_id, created_at DESC)"},{"name":"ai_requests_user_idx","definition":"CREATE INDEX ai_requests_user_idx ON public.ai_requests USING btree (user_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"(ai_is_tenant_admin(tenant_org_id) OR (user_id = uid()))","roles":["authenticated"],"tablename":"ai_requests","permissive":"PERMISSIVE","policyname":"ai_req_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"ai_requests_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"ai_tool_calls","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"message_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tool_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tool_call_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_write","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'proposed'::text","identity":"","not_null":true,"generated":""},{"name":"input","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"output","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"requires_confirmation","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"confirmed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"confirmed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"executed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"ai_tool_calls_conv_idx","definition":"CREATE INDEX ai_tool_calls_conv_idx ON public.ai_tool_calls USING btree (conversation_id, created_at)"},{"name":"ai_tool_calls_pkey","definition":"CREATE UNIQUE INDEX ai_tool_calls_pkey ON public.ai_tool_calls USING btree (id)"},{"name":"ai_tool_calls_status_idx","definition":"CREATE INDEX ai_tool_calls_status_idx ON public.ai_tool_calls USING btree (tenant_org_id, status, created_at DESC)"},{"name":"ai_tool_calls_tenant_idx","definition":"CREATE INDEX ai_tool_calls_tenant_idx ON public.ai_tool_calls USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"ai_tool_calls","permissive":"PERMISSIVE","policyname":"ai_tool_insert","schemaname":"public","with_check":"((user_id = uid()) AND ai_user_in_tenant(tenant_org_id))"},{"cmd":"SELECT","qual":"(ai_user_in_tenant(tenant_org_id) AND ((user_id = uid()) OR ai_is_tenant_admin(tenant_org_id)))","roles":["authenticated"],"tablename":"ai_tool_calls","permissive":"PERMISSIVE","policyname":"ai_tool_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((user_id = uid()) OR ai_is_tenant_admin(tenant_org_id))","roles":["authenticated"],"tablename":"ai_tool_calls","permissive":"PERMISSIVE","policyname":"ai_tool_update","schemaname":"public","with_check":"((user_id = uid()) OR ai_is_tenant_admin(tenant_org_id))"}],"triggers":[{"name":"ai_tool_touch","definition":"CREATE TRIGGER ai_tool_touch BEFORE UPDATE ON ai_tool_calls FOR EACH ROW EXECUTE FUNCTION ai_touch_updated_at()"}],"constraints":[{"name":"ai_tool_calls_pkey","definition":"PRIMARY KEY (id)"},{"name":"ai_tool_calls_status_check","definition":"CHECK (status = ANY (ARRAY['proposed'::text, 'confirmed'::text, 'completed'::text, 'failed'::text, 'cancelled'::text]))"}]},{"table":"analytics_metrics","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metric_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metric_value","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"metric_type","type":"text","default":"'gauge'::text","identity":"","not_null":false,"generated":""},{"name":"dimensions","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"timestamp","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"analytics_metrics_pkey","definition":"CREATE UNIQUE INDEX analytics_metrics_pkey ON public.analytics_metrics USING btree (id)"},{"name":"idx_analytics_metric_name","definition":"CREATE INDEX idx_analytics_metric_name ON public.analytics_metrics USING btree (metric_name)"},{"name":"idx_analytics_tenant_id","definition":"CREATE INDEX idx_analytics_tenant_id ON public.analytics_metrics USING btree (tenant_id)"},{"name":"idx_analytics_timestamp","definition":"CREATE INDEX idx_analytics_timestamp ON public.analytics_metrics USING btree (\"timestamp\" DESC)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"analytics_metrics","permissive":"PERMISSIVE","policyname":"platform_admin_view_analytics","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"analytics_metrics","permissive":"PERMISSIVE","policyname":"users_insert_tenant_metrics","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND ((utm.tenant_id)::text = (analytics_metrics.tenant_id)::text) AND (utm.status = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"analytics_metrics_metric_type_check","definition":"CHECK (metric_type = ANY (ARRAY['counter'::text, 'gauge'::text, 'histogram'::text]))"},{"name":"analytics_metrics_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"analytics_snapshots","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"snapshot_type","type":"character varying(50)","default":null,"identity":"","not_null":true,"generated":""},{"name":"snapshot_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"metrics","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"dimensions","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"analytics_snapshots_pkey","definition":"CREATE UNIQUE INDEX analytics_snapshots_pkey ON public.analytics_snapshots USING btree (id)"},{"name":"idx_analytics_snapshots_date","definition":"CREATE INDEX idx_analytics_snapshots_date ON public.analytics_snapshots USING btree (snapshot_date)"},{"name":"idx_analytics_snapshots_tenant","definition":"CREATE INDEX idx_analytics_snapshots_tenant ON public.analytics_snapshots USING btree (tenant_id)"},{"name":"unique_tenant_snapshot","definition":"CREATE UNIQUE INDEX unique_tenant_snapshot ON public.analytics_snapshots USING btree (tenant_id, snapshot_type, snapshot_date)"}],"policies":[{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"analytics_snapshots","permissive":"PERMISSIVE","policyname":"Users can view own tenant snapshots","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"analytics_snapshots_pkey","definition":"PRIMARY KEY (id)"},{"name":"unique_tenant_snapshot","definition":"UNIQUE (tenant_id, snapshot_type, snapshot_date)"}]},{"table":"app_background_jobs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_app","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"job_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"detail","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""},{"name":"progress_percentage","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"progress_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"destination_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"entity_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"entity_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"dedupe_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"finished_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"app_background_jobs_pkey","definition":"CREATE UNIQUE INDEX app_background_jobs_pkey ON public.app_background_jobs USING btree (id)"},{"name":"app_background_jobs_tenant_user_source_dedupe_key","definition":"CREATE UNIQUE INDEX app_background_jobs_tenant_user_source_dedupe_key ON public.app_background_jobs USING btree (tenant_id, user_id, source_app, dedupe_key)"},{"name":"idx_app_background_jobs_active","definition":"CREATE INDEX idx_app_background_jobs_active ON public.app_background_jobs USING btree (tenant_id, user_id, status, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"app_background_jobs","permissive":"PERMISSIVE","policyname":"app_background_jobs_insert_self","schemaname":"public","with_check":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_background_jobs.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))"},{"cmd":"SELECT","qual":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_background_jobs.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"app_background_jobs","permissive":"PERMISSIVE","policyname":"app_background_jobs_select_self","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_background_jobs.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"app_background_jobs","permissive":"PERMISSIVE","policyname":"app_background_jobs_update_self","schemaname":"public","with_check":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_background_jobs.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))"}],"triggers":[{"name":"app_background_job_canonical_notification","definition":"CREATE TRIGGER app_background_job_canonical_notification AFTER UPDATE OF status ON app_background_jobs FOR EACH ROW EXECUTE FUNCTION bridge_background_job_to_canonical_notifications()"},{"name":"platform_background_job_journal","definition":"CREATE TRIGGER platform_background_job_journal AFTER INSERT OR UPDATE OF status ON app_background_jobs FOR EACH ROW EXECUTE FUNCTION journal_background_job_transition()"}],"constraints":[{"name":"app_background_jobs_pkey","definition":"PRIMARY KEY (id)"},{"name":"app_background_jobs_progress_percentage_check","definition":"CHECK (progress_percentage >= 0 AND progress_percentage <= 100)"},{"name":"app_background_jobs_status_check","definition":"CHECK (status = ANY (ARRAY['queued'::text, 'running'::text, 'waiting'::text, 'needs_attention'::text, 'completed'::text, 'failed'::text, 'canceled'::text]))"},{"name":"app_background_jobs_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"app_background_jobs_tenant_user_source_dedupe_key","definition":"UNIQUE (tenant_id, user_id, source_app, dedupe_key)"},{"name":"app_background_jobs_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE CASCADE"}]},{"table":"app_notification_preferences","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"in_app_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"browser_enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"email_enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"sms_enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"source_preferences","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"quiet_hours","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"category_channels","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"app_notification_preferences_pkey","definition":"CREATE UNIQUE INDEX app_notification_preferences_pkey ON public.app_notification_preferences USING btree (id)"},{"name":"app_notification_preferences_tenant_id_user_id_key","definition":"CREATE UNIQUE INDEX app_notification_preferences_tenant_id_user_id_key ON public.app_notification_preferences USING btree (tenant_id, user_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"app_notification_preferences","permissive":"PERMISSIVE","policyname":"app_notification_preferences_insert_self","schemaname":"public","with_check":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_notification_preferences.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))"},{"cmd":"SELECT","qual":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_notification_preferences.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"app_notification_preferences","permissive":"PERMISSIVE","policyname":"app_notification_preferences_select_self","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_notification_preferences.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"app_notification_preferences","permissive":"PERMISSIVE","policyname":"app_notification_preferences_update_self","schemaname":"public","with_check":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_notification_preferences.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"app_notification_category_channels_valid","definition":"CHECK (valid_notification_category_channels(category_channels))"},{"name":"app_notification_preferences_pkey","definition":"PRIMARY KEY (id)"},{"name":"app_notification_preferences_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"app_notification_preferences_tenant_id_user_id_key","definition":"UNIQUE (tenant_id, user_id)"},{"name":"app_notification_preferences_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE CASCADE"}]},{"table":"app_notifications","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_app","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"severity","type":"text","default":"'info'::text","identity":"","not_null":true,"generated":""},{"name":"destination_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"entity_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"entity_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"dedupe_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"read_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"app_notifications_dedupe_idx","definition":"CREATE UNIQUE INDEX app_notifications_dedupe_idx ON public.app_notifications USING btree (tenant_id, user_id, source_app, dedupe_key)"},{"name":"app_notifications_pkey","definition":"CREATE UNIQUE INDEX app_notifications_pkey ON public.app_notifications USING btree (id)"},{"name":"app_notifications_unread_idx","definition":"CREATE INDEX app_notifications_unread_idx ON public.app_notifications USING btree (tenant_id, user_id, created_at DESC) WHERE (read_at IS NULL)"},{"name":"app_notifications_user_feed_idx","definition":"CREATE INDEX app_notifications_user_feed_idx ON public.app_notifications USING btree (tenant_id, user_id, created_at DESC)"}],"policies":[{"cmd":"DELETE","qual":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_notifications.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"app_notifications","permissive":"PERMISSIVE","policyname":"app_notifications_delete_self","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"app_notifications","permissive":"PERMISSIVE","policyname":"app_notifications_insert_self","schemaname":"public","with_check":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_notifications.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))"},{"cmd":"SELECT","qual":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_notifications.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"app_notifications","permissive":"PERMISSIVE","policyname":"app_notifications_select_own_tenant","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_notifications.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"app_notifications","permissive":"PERMISSIVE","policyname":"app_notifications_update_self","schemaname":"public","with_check":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = app_notifications.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"app_notifications_actor_user_id_fkey","definition":"FOREIGN KEY (actor_user_id) REFERENCES profiles(id) ON DELETE SET NULL"},{"name":"app_notifications_pkey","definition":"PRIMARY KEY (id)"},{"name":"app_notifications_severity_check","definition":"CHECK (severity = ANY (ARRAY['info'::text, 'success'::text, 'warning'::text, 'urgent'::text]))"},{"name":"app_notifications_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"app_notifications_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE CASCADE"}]},{"table":"application_action_registry","schema":"public","columns":[{"name":"application_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"implementation_kind","type":"text","default":"'declared'::text","identity":"","not_null":true,"generated":""},{"name":"implementation_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"callable","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"application_action_registry_pkey","definition":"CREATE UNIQUE INDEX application_action_registry_pkey ON public.application_action_registry USING btree (application_id, action)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"application_action_registry","permissive":"PERMISSIVE","policyname":"application_action_registry_authenticated_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"application_action_registry_application_id_fkey","definition":"FOREIGN KEY (application_id) REFERENCES application_catalog(id) ON DELETE CASCADE"},{"name":"application_action_registry_implementation_kind_check","definition":"CHECK (implementation_kind = ANY (ARRAY['declared'::text, 'edge-function'::text, 'client-service'::text, 'database'::text]))"},{"name":"application_action_registry_pkey","definition":"PRIMARY KEY (application_id, action)"}]},{"table":"application_catalog","schema":"public","columns":[{"name":"id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"slug","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"audience","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"workspace_surface","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"bootstrap_mode","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"default_installed","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"capabilities","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"data_owners","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"external_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"supported_tenant_types","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"standalone_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"login_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"bootstrap_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"route_adapter","type":"text","default":"'tenant-workspace'::text","identity":"","not_null":true,"generated":""},{"name":"config_contract","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"application_catalog_login_path_uidx","definition":"CREATE UNIQUE INDEX application_catalog_login_path_uidx ON public.application_catalog USING btree (login_path) WHERE (login_path IS NOT NULL)"},{"name":"application_catalog_pkey","definition":"CREATE UNIQUE INDEX application_catalog_pkey ON public.application_catalog USING btree (id)"},{"name":"application_catalog_slug_key","definition":"CREATE UNIQUE INDEX application_catalog_slug_key ON public.application_catalog USING btree (slug)"},{"name":"application_catalog_standalone_path_uidx","definition":"CREATE UNIQUE INDEX application_catalog_standalone_path_uidx ON public.application_catalog USING btree (standalone_path)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"application_catalog","permissive":"PERMISSIVE","policyname":"application_catalog_authenticated_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"application_catalog_audience_check","definition":"CHECK (audience = ANY (ARRAY['tenant-user'::text, 'customer-public'::text]))"},{"name":"application_catalog_bootstrap_mode_check","definition":"CHECK (bootstrap_mode = ANY (ARRAY['default'::text, 'vertical'::text, 'token'::text]))"},{"name":"application_catalog_pkey","definition":"PRIMARY KEY (id)"},{"name":"application_catalog_slug_key","definition":"UNIQUE (slug)"}]},{"table":"appointment_outcome_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"booking_rep_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"appt_starts_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"prev_outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_outcome","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"note","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"changed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"appointment_outcome_audit_pkey","definition":"CREATE UNIQUE INDEX appointment_outcome_audit_pkey ON public.appointment_outcome_audit USING btree (id)"},{"name":"idx_aoa_contact","definition":"CREATE INDEX idx_aoa_contact ON public.appointment_outcome_audit USING btree (contact_id, changed_at DESC)"},{"name":"idx_aoa_tenant_rep","definition":"CREATE INDEX idx_aoa_tenant_rep ON public.appointment_outcome_audit USING btree (tenant_org_id, booking_rep_id, changed_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN tenants t ON ((t.id = ur.tenant_id)))\n  WHERE ((ur.user_id = uid()) AND ((t.id)::text = appointment_outcome_audit.tenant_org_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'Manager'::app_role, 'Tenant Owner'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"appointment_outcome_audit","permissive":"PERMISSIVE","policyname":"manager_plus_read_outcome_audit","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"appointment_outcome_audit_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"appointment_settings","schema":"public","columns":[{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"company_calendar_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"invite_emails","type":"text[]","default":"ARRAY[]::text[]","identity":"","not_null":false,"generated":""},{"name":"send_customer_sms","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"send_customer_email","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"send_24h_reminder","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"send_1h_reminder","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"notify_owner_emails","type":"text[]","default":"ARRAY[]::text[]","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"send_rep_booking_notification","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"send_agreement_signed_followup","type":"boolean","default":"true","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"appointment_settings_pkey","definition":"CREATE UNIQUE INDEX appointment_settings_pkey ON public.appointment_settings USING btree (tenant_org_id)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = appointment_settings.tenant_org_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'Manager'::app_role, 'Tenant Owner'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"appointment_settings","permissive":"PERMISSIVE","policyname":"manager_plus_read_appt_settings","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = appointment_settings.tenant_org_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'Tenant Owner'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"appointment_settings","permissive":"PERMISSIVE","policyname":"owner_admin_write_appt_settings","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = appointment_settings.tenant_org_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'Tenant Owner'::app_role, 'GodMode'::app_role]))))))"}],"triggers":[{"name":"trg_touch_appt_settings","definition":"CREATE TRIGGER trg_touch_appt_settings BEFORE UPDATE ON appointment_settings FOR EACH ROW EXECUTE FUNCTION touch_appointment_settings_updated_at()"}],"constraints":[{"name":"appointment_settings_pkey","definition":"PRIMARY KEY (tenant_org_id)"}]},{"table":"auto_unlock_upload_tickets","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":"'d60e3c27-73ed-4a5f-a49b-c37636455daf'::uuid","identity":"","not_null":true,"generated":""},{"name":"bucket_id","type":"text","default":"'tenant-d60e3c27-73ed-4a5f-a49b-c37636455daf'::text","identity":"","not_null":true,"generated":""},{"name":"object_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"proof_kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"declared_filename","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"declared_mime","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"declared_size","type":"bigint","default":null,"identity":"","not_null":true,"generated":""},{"name":"ip_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"consumed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"auto_unlock_upload_tickets_expiry_idx","definition":"CREATE INDEX auto_unlock_upload_tickets_expiry_idx ON public.auto_unlock_upload_tickets USING btree (expires_at) WHERE (consumed_at IS NULL)"},{"name":"auto_unlock_upload_tickets_ip_created_idx","definition":"CREATE INDEX auto_unlock_upload_tickets_ip_created_idx ON public.auto_unlock_upload_tickets USING btree (ip_hash, created_at DESC)"},{"name":"auto_unlock_upload_tickets_object_path_key","definition":"CREATE UNIQUE INDEX auto_unlock_upload_tickets_object_path_key ON public.auto_unlock_upload_tickets USING btree (object_path)"},{"name":"auto_unlock_upload_tickets_pkey","definition":"CREATE UNIQUE INDEX auto_unlock_upload_tickets_pkey ON public.auto_unlock_upload_tickets USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"auto_unlock_upload_ticket_bucket","definition":"CHECK (bucket_id = 'tenant-d60e3c27-73ed-4a5f-a49b-c37636455daf'::text)"},{"name":"auto_unlock_upload_ticket_path","definition":"CHECK (object_path ~ '^public-intake/(identity|authority)/[0-9a-f-]+\\.(jpg|png|webp|heic|heif|pdf)$'::text)"},{"name":"auto_unlock_upload_ticket_tenant","definition":"CHECK (tenant_id = 'd60e3c27-73ed-4a5f-a49b-c37636455daf'::uuid)"},{"name":"auto_unlock_upload_tickets_declared_mime_check","definition":"CHECK (declared_mime = ANY (ARRAY['image/jpeg'::text, 'image/png'::text, 'image/webp'::text, 'image/heic'::text, 'image/heif'::text, 'application/pdf'::text]))"},{"name":"auto_unlock_upload_tickets_declared_size_check","definition":"CHECK (declared_size > 0 AND declared_size <= 10485760)"},{"name":"auto_unlock_upload_tickets_ip_hash_check","definition":"CHECK (ip_hash ~ '^[0-9a-f]{64}$'::text)"},{"name":"auto_unlock_upload_tickets_object_path_key","definition":"UNIQUE (object_path)"},{"name":"auto_unlock_upload_tickets_pkey","definition":"PRIMARY KEY (id)"},{"name":"auto_unlock_upload_tickets_proof_kind_check","definition":"CHECK (proof_kind = ANY (ARRAY['identity'::text, 'authority'::text]))"}]},{"table":"automation_rule_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"template_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"vertical","type":"text","default":"'universal'::text","identity":"","not_null":true,"generated":""},{"name":"trigger_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"trigger_config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"conditions","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"actions","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"icon","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recommended_for_verticals","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"automation_rule_templates_pkey","definition":"CREATE UNIQUE INDEX automation_rule_templates_pkey ON public.automation_rule_templates USING btree (id)"},{"name":"automation_rule_templates_template_key_key","definition":"CREATE UNIQUE INDEX automation_rule_templates_template_key_key ON public.automation_rule_templates USING btree (template_key)"},{"name":"idx_automation_templates_category","definition":"CREATE INDEX idx_automation_templates_category ON public.automation_rule_templates USING btree (category)"},{"name":"idx_automation_templates_verticals","definition":"CREATE INDEX idx_automation_templates_verticals ON public.automation_rule_templates USING gin (recommended_for_verticals)"}],"policies":[{"cmd":"SELECT","qual":"(is_active = true)","roles":["authenticated"],"tablename":"automation_rule_templates","permissive":"PERMISSIVE","policyname":"Anyone authenticated can read active templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"automation_rule_templates","permissive":"PERMISSIVE","policyname":"System admins manage templates","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"automation_rule_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"automation_rule_templates_template_key_key","definition":"UNIQUE (template_key)"}]},{"table":"automation_rules","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"trigger_event","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"conditions","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"actions","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"execution_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"last_executed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"automation_rules_pkey","definition":"CREATE UNIQUE INDEX automation_rules_pkey ON public.automation_rules USING btree (id)"},{"name":"idx_automation_rules_active","definition":"CREATE INDEX idx_automation_rules_active ON public.automation_rules USING btree (tenant_id) WHERE (is_active = true)"},{"name":"idx_automation_rules_tenant","definition":"CREATE INDEX idx_automation_rules_tenant ON public.automation_rules USING btree (tenant_id)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN security_active_user_tenant_memberships m ON (((m.user_id = ur.user_id) AND (m.tenant_id = ur.tenant_id))))\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = automation_rules.tenant_id) AND (m.status = 'active'::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"automation_rules","permissive":"PERMISSIVE","policyname":"Admins can manage automation rules","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN security_active_user_tenant_memberships m ON (((m.user_id = ur.user_id) AND (m.tenant_id = ur.tenant_id))))\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = automation_rules.tenant_id) AND (m.status = 'active'::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND ((m.tenant_id)::text = automation_rules.tenant_id)))))","roles":["authenticated"],"tablename":"automation_rules","permissive":"PERMISSIVE","policyname":"Tenant members can view automation rules","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"automation_rules_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id)"},{"name":"automation_rules_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"automation_run_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"rule_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"rule_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"engine","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"trigger_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_kind","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"entity_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'success'::text","identity":"","not_null":true,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"dry_run","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"actions_executed","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"automation_run_log_pkey","definition":"CREATE UNIQUE INDEX automation_run_log_pkey ON public.automation_run_log USING btree (id)"},{"name":"idx_automation_run_log_rule","definition":"CREATE INDEX idx_automation_run_log_rule ON public.automation_run_log USING btree (rule_id, created_at DESC)"},{"name":"idx_automation_run_log_status","definition":"CREATE INDEX idx_automation_run_log_status ON public.automation_run_log USING btree (status)"},{"name":"idx_automation_run_log_tenant","definition":"CREATE INDEX idx_automation_run_log_tenant ON public.automation_run_log USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"automation_run_log","permissive":"PERMISSIVE","policyname":"Service role manages automation runs","schemaname":"public","with_check":"true"},{"cmd":"SELECT","qual":"((tenant_org_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid()))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"automation_run_log","permissive":"PERMISSIVE","policyname":"Tenant members read their automation runs","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"automation_run_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"barbershop_appointment_assignments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"appointment_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"starts_at_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"staff_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"barbershop_appointment_assignment_tenant_id_appointment_key_key","definition":"CREATE UNIQUE INDEX barbershop_appointment_assignment_tenant_id_appointment_key_key ON public.barbershop_appointment_assignments USING btree (tenant_id, appointment_key)"},{"name":"barbershop_appointment_assignments_pkey","definition":"CREATE UNIQUE INDEX barbershop_appointment_assignments_pkey ON public.barbershop_appointment_assignments USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"barbershop_tenant_owner(tenant_id)","roles":["authenticated"],"tablename":"barbershop_appointment_assignments","permissive":"PERMISSIVE","policyname":"barbershop_appointment_assignments_owner_write","schemaname":"public","with_check":"barbershop_tenant_owner(tenant_id)"},{"cmd":"SELECT","qual":"barbershop_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"barbershop_appointment_assignments","permissive":"PERMISSIVE","policyname":"barbershop_appointment_assignments_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"barbershop_appointment_assignment_tenant_id_appointment_key_key","definition":"UNIQUE (tenant_id, appointment_key)"},{"name":"barbershop_appointment_assignments_pkey","definition":"PRIMARY KEY (id)"},{"name":"barbershop_appointment_assignments_staff_id_fkey","definition":"FOREIGN KEY (staff_id) REFERENCES barbershop_staff(id) ON DELETE SET NULL"},{"name":"barbershop_appointment_assignments_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"barbershop_client_profiles","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"preferred_staff_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"usual_service_ids","type":"uuid[]","default":"'{}'::uuid[]","identity":"","not_null":true,"generated":""},{"name":"no_show_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"rebook_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_visit_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_visit_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"lifetime_spend","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"visit_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"preferences","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"barbershop_client_profiles_pkey","definition":"CREATE UNIQUE INDEX barbershop_client_profiles_pkey ON public.barbershop_client_profiles USING btree (tenant_id, contact_id)"}],"policies":[{"cmd":"ALL","qual":"barbershop_tenant_owner(tenant_id)","roles":["authenticated"],"tablename":"barbershop_client_profiles","permissive":"PERMISSIVE","policyname":"barbershop_client_profiles_owner_write","schemaname":"public","with_check":"barbershop_tenant_owner(tenant_id)"},{"cmd":"SELECT","qual":"barbershop_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"barbershop_client_profiles","permissive":"PERMISSIVE","policyname":"barbershop_client_profiles_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"barbershop_client_profiles_no_show_count_check","definition":"CHECK (no_show_count >= 0)"},{"name":"barbershop_client_profiles_pkey","definition":"PRIMARY KEY (tenant_id, contact_id)"},{"name":"barbershop_client_profiles_preferred_staff_id_fkey","definition":"FOREIGN KEY (preferred_staff_id) REFERENCES barbershop_staff(id) ON DELETE SET NULL"},{"name":"barbershop_client_profiles_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"barbershop_queue","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"requested_staff_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"staff_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assignment_mode","type":"text","default":"'next_available'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'waiting'::text","identity":"","not_null":true,"generated":""},{"name":"checked_in_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"called_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"in_chair_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"barbershop_queue_pkey","definition":"CREATE UNIQUE INDEX barbershop_queue_pkey ON public.barbershop_queue USING btree (id)"},{"name":"barbershop_queue_tenant_status_idx","definition":"CREATE INDEX barbershop_queue_tenant_status_idx ON public.barbershop_queue USING btree (tenant_id, status, created_at)"}],"policies":[{"cmd":"UPDATE","qual":"barbershop_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"barbershop_queue","permissive":"PERMISSIVE","policyname":"barbershop_queue_barber_update","schemaname":"public","with_check":"barbershop_tenant_access(tenant_id)"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"barbershop_queue","permissive":"PERMISSIVE","policyname":"barbershop_queue_barber_write","schemaname":"public","with_check":"barbershop_tenant_access(tenant_id)"},{"cmd":"ALL","qual":"barbershop_tenant_owner(tenant_id)","roles":["authenticated"],"tablename":"barbershop_queue","permissive":"PERMISSIVE","policyname":"barbershop_queue_owner_write","schemaname":"public","with_check":"barbershop_tenant_owner(tenant_id)"},{"cmd":"SELECT","qual":"barbershop_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"barbershop_queue","permissive":"PERMISSIVE","policyname":"barbershop_queue_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"barbershop_queue_assignment_mode_check","definition":"CHECK (assignment_mode = ANY (ARRAY['next_available'::text, 'specific_barber'::text]))"},{"name":"barbershop_queue_pkey","definition":"PRIMARY KEY (id)"},{"name":"barbershop_queue_requested_staff_id_fkey","definition":"FOREIGN KEY (requested_staff_id) REFERENCES barbershop_staff(id) ON DELETE SET NULL"},{"name":"barbershop_queue_staff_id_fkey","definition":"FOREIGN KEY (staff_id) REFERENCES barbershop_staff(id) ON DELETE SET NULL"},{"name":"barbershop_queue_status_check","definition":"CHECK (status = ANY (ARRAY['waiting'::text, 'called'::text, 'in_chair'::text, 'complete'::text, 'canceled'::text, 'no_show'::text]))"},{"name":"barbershop_queue_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"barbershop_services","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"duration_minutes","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"price","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"barbershop_services_pkey","definition":"CREATE UNIQUE INDEX barbershop_services_pkey ON public.barbershop_services USING btree (id)"},{"name":"barbershop_services_tenant_id_name_key","definition":"CREATE UNIQUE INDEX barbershop_services_tenant_id_name_key ON public.barbershop_services USING btree (tenant_id, name)"}],"policies":[{"cmd":"ALL","qual":"barbershop_tenant_owner(tenant_id)","roles":["authenticated"],"tablename":"barbershop_services","permissive":"PERMISSIVE","policyname":"barbershop_services_owner_write","schemaname":"public","with_check":"barbershop_tenant_owner(tenant_id)"},{"cmd":"SELECT","qual":"barbershop_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"barbershop_services","permissive":"PERMISSIVE","policyname":"barbershop_services_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"barbershop_services_duration_minutes_check","definition":"CHECK (duration_minutes > 0)"},{"name":"barbershop_services_pkey","definition":"PRIMARY KEY (id)"},{"name":"barbershop_services_price_check","definition":"CHECK (price >= 0::numeric)"},{"name":"barbershop_services_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"barbershop_services_tenant_id_name_key","definition":"UNIQUE (tenant_id, name)"}]},{"table":"barbershop_staff","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"chair_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"working_hours","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"time_off","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"booking_capacity","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"barbershop_staff_pkey","definition":"CREATE UNIQUE INDEX barbershop_staff_pkey ON public.barbershop_staff USING btree (id)"},{"name":"barbershop_staff_tenant_idx","definition":"CREATE INDEX barbershop_staff_tenant_idx ON public.barbershop_staff USING btree (tenant_id)"},{"name":"barbershop_staff_tenant_user_uidx","definition":"CREATE UNIQUE INDEX barbershop_staff_tenant_user_uidx ON public.barbershop_staff USING btree (tenant_id, user_id) WHERE (user_id IS NOT NULL)"}],"policies":[{"cmd":"ALL","qual":"barbershop_tenant_owner(tenant_id)","roles":["authenticated"],"tablename":"barbershop_staff","permissive":"PERMISSIVE","policyname":"barbershop_staff_owner_write","schemaname":"public","with_check":"barbershop_tenant_owner(tenant_id)"},{"cmd":"SELECT","qual":"barbershop_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"barbershop_staff","permissive":"PERMISSIVE","policyname":"barbershop_staff_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"barbershop_staff_booking_capacity_check","definition":"CHECK (booking_capacity > 0)"},{"name":"barbershop_staff_pkey","definition":"PRIMARY KEY (id)"},{"name":"barbershop_staff_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"barbershop_staff_services","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"staff_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"service_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"price_override","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"barbershop_staff_services_pkey","definition":"CREATE UNIQUE INDEX barbershop_staff_services_pkey ON public.barbershop_staff_services USING btree (staff_id, service_id)"}],"policies":[{"cmd":"ALL","qual":"barbershop_tenant_owner(tenant_id)","roles":["authenticated"],"tablename":"barbershop_staff_services","permissive":"PERMISSIVE","policyname":"barbershop_staff_services_owner_write","schemaname":"public","with_check":"barbershop_tenant_owner(tenant_id)"},{"cmd":"SELECT","qual":"barbershop_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"barbershop_staff_services","permissive":"PERMISSIVE","policyname":"barbershop_staff_services_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"barbershop_staff_services_pkey","definition":"PRIMARY KEY (staff_id, service_id)"},{"name":"barbershop_staff_services_price_override_check","definition":"CHECK (price_override IS NULL OR price_override >= 0::numeric)"},{"name":"barbershop_staff_services_service_id_fkey","definition":"FOREIGN KEY (service_id) REFERENCES barbershop_services(id) ON DELETE CASCADE"},{"name":"barbershop_staff_services_staff_id_fkey","definition":"FOREIGN KEY (staff_id) REFERENCES barbershop_staff(id) ON DELETE CASCADE"},{"name":"barbershop_staff_services_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"billing_comps","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"scope","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"granted_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"billing_comps_pkey","definition":"CREATE UNIQUE INDEX billing_comps_pkey ON public.billing_comps USING btree (id)"},{"name":"billing_comps_tenant_unique","definition":"CREATE UNIQUE INDEX billing_comps_tenant_unique ON public.billing_comps USING btree (tenant_id) WHERE (scope = 'tenant'::text)"},{"name":"billing_comps_user_unique","definition":"CREATE UNIQUE INDEX billing_comps_user_unique ON public.billing_comps USING btree (user_id) WHERE (scope = 'user'::text)"}],"policies":[{"cmd":"ALL","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"billing_comps","permissive":"PERMISSIVE","policyname":"Admins manage billing comps","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"SELECT","qual":"(((scope = 'user'::text) AND (user_id = uid())) OR ((scope = 'tenant'::text) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = billing_comps.tenant_id))))))","roles":["authenticated"],"tablename":"billing_comps","permissive":"PERMISSIVE","policyname":"Users view own applicable comps","schemaname":"public","with_check":null}],"triggers":[{"name":"update_billing_comps_updated_at","definition":"CREATE TRIGGER update_billing_comps_updated_at BEFORE UPDATE ON billing_comps FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"billing_comps_pkey","definition":"PRIMARY KEY (id)"},{"name":"billing_comps_scope_check","definition":"CHECK (scope = ANY (ARRAY['tenant'::text, 'user'::text]))"},{"name":"billing_comps_scope_target","definition":"CHECK (scope = 'tenant'::text AND tenant_id IS NOT NULL AND user_id IS NULL OR scope = 'user'::text AND user_id IS NOT NULL AND tenant_id IS NULL)"}]},{"table":"brevard_permit_confidence_feedback","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"jurisdiction_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"searched_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"searched_parcel","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"detected_jurisdiction","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"detected_confidence","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"feedback_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"corrected_jurisdiction","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"submitted_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"brevard_permit_confidence_feedback_pkey","definition":"CREATE UNIQUE INDEX brevard_permit_confidence_feedback_pkey ON public.brevard_permit_confidence_feedback USING btree (id)"},{"name":"idx_brevard_feedback_created","definition":"CREATE INDEX idx_brevard_feedback_created ON public.brevard_permit_confidence_feedback USING btree (created_at DESC)"},{"name":"idx_brevard_feedback_jur","definition":"CREATE INDEX idx_brevard_feedback_jur ON public.brevard_permit_confidence_feedback USING btree (jurisdiction_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"brevard_permit_confidence_feedback","permissive":"PERMISSIVE","policyname":"brevard feedback scoped insert","schemaname":"public","with_check":"((submitted_by = uid()) AND (is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), tenant_org_id))))"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"brevard_permit_confidence_feedback","permissive":"PERMISSIVE","policyname":"brevard_feedback_admin_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"brevard_permit_confidence_feedback_feedback_type_check","definition":"CHECK (feedback_type = ANY (ARRAY['CONFIRMED_CORRECT'::text, 'WRONG_JURISDICTION'::text, 'NEEDS_REVIEW'::text, 'MANUAL_PERMIT_FOUND'::text, 'MANUAL_NO_PERMIT_FOUND'::text, 'PORTAL_LINK_BAD'::text, 'SOURCE_UNRELIABLE'::text]))"},{"name":"brevard_permit_confidence_feedback_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"brevard_permit_jurisdictions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"jurisdiction_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"normalized_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"aliases","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"county","type":"text","default":"'Brevard'::text","identity":"","not_null":true,"generated":""},{"name":"state","type":"text","default":"'FL'::text","identity":"","not_null":true,"generated":""},{"name":"jurisdiction_type","type":"text","default":"'city'::text","identity":"","not_null":true,"generated":""},{"name":"coverage_status","type":"brevard_permit_coverage_status","default":"'PORTAL_ASSISTED'::brevard_permit_coverage_status","identity":"","not_null":true,"generated":""},{"name":"platform","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"official_building_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_search_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_application_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"public_records_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"supports_address_search","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"supports_parcel_search","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"supports_owner_search","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"supports_permit_number_search","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"requires_login","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"captcha_detected","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"js_heavy","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"automation_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"manual_search_instructions","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"confidence_score","type":"integer","default":"50","identity":"","not_null":true,"generated":""},{"name":"last_verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_successful_search_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_failure_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"brevard_permit_jurisdictions_normalized_name_key","definition":"CREATE UNIQUE INDEX brevard_permit_jurisdictions_normalized_name_key ON public.brevard_permit_jurisdictions USING btree (normalized_name)"},{"name":"brevard_permit_jurisdictions_pkey","definition":"CREATE UNIQUE INDEX brevard_permit_jurisdictions_pkey ON public.brevard_permit_jurisdictions USING btree (id)"},{"name":"idx_brevard_jur_normalized","definition":"CREATE INDEX idx_brevard_jur_normalized ON public.brevard_permit_jurisdictions USING btree (normalized_name)"},{"name":"idx_brevard_jur_status","definition":"CREATE INDEX idx_brevard_jur_status ON public.brevard_permit_jurisdictions USING btree (coverage_status)"}],"policies":[{"cmd":"DELETE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"brevard_permit_jurisdictions","permissive":"PERMISSIVE","policyname":"brevard_jur_admin_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"brevard_permit_jurisdictions","permissive":"PERMISSIVE","policyname":"brevard_jur_admin_insert","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"UPDATE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"brevard_permit_jurisdictions","permissive":"PERMISSIVE","policyname":"brevard_jur_admin_update","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"brevard_permit_jurisdictions","permissive":"PERMISSIVE","policyname":"brevard_jur_read_authenticated","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_brevard_jur_updated_at","definition":"CREATE TRIGGER trg_brevard_jur_updated_at BEFORE UPDATE ON brevard_permit_jurisdictions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"brevard_permit_jurisdictions_normalized_name_key","definition":"UNIQUE (normalized_name)"},{"name":"brevard_permit_jurisdictions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"brevard_permit_manual_results","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"jurisdiction_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"issued_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"finaled_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"contractor_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"entered_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"brevard_permit_manual_results_pkey","definition":"CREATE UNIQUE INDEX brevard_permit_manual_results_pkey ON public.brevard_permit_manual_results USING btree (id)"},{"name":"idx_brevard_manual_property","definition":"CREATE INDEX idx_brevard_manual_property ON public.brevard_permit_manual_results USING btree (property_id)"},{"name":"idx_brevard_manual_tenant","definition":"CREATE INDEX idx_brevard_manual_tenant ON public.brevard_permit_manual_results USING btree (tenant_org_id)"}],"policies":[{"cmd":"DELETE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"brevard_permit_manual_results","permissive":"PERMISSIVE","policyname":"brevard_manual_delete_admin","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"brevard_permit_manual_results","permissive":"PERMISSIVE","policyname":"brevard_manual_insert_tenant","schemaname":"public","with_check":"(is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), tenant_org_id)))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), tenant_org_id)))","roles":["authenticated"],"tablename":"brevard_permit_manual_results","permissive":"PERMISSIVE","policyname":"brevard_manual_read_tenant","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), tenant_org_id)))","roles":["authenticated"],"tablename":"brevard_permit_manual_results","permissive":"PERMISSIVE","policyname":"brevard_manual_update_tenant","schemaname":"public","with_check":"(is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), tenant_org_id)))"}],"triggers":[{"name":"trg_brevard_manual_updated_at","definition":"CREATE TRIGGER trg_brevard_manual_updated_at BEFORE UPDATE ON brevard_permit_manual_results FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"brevard_permit_manual_results_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"brevard_permit_search_logs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"jurisdiction_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"searched_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"searched_parcel","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"searched_owner","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"searched_permit_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"coverage_status","type":"brevard_permit_coverage_status","default":null,"identity":"","not_null":false,"generated":""},{"name":"search_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"result_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"result_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_response","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"brevard_permit_search_logs_pkey","definition":"CREATE UNIQUE INDEX brevard_permit_search_logs_pkey ON public.brevard_permit_search_logs USING btree (id)"},{"name":"idx_brevard_logs_created","definition":"CREATE INDEX idx_brevard_logs_created ON public.brevard_permit_search_logs USING btree (created_at DESC)"},{"name":"idx_brevard_logs_jur","definition":"CREATE INDEX idx_brevard_logs_jur ON public.brevard_permit_search_logs USING btree (jurisdiction_id)"},{"name":"idx_brevard_logs_property","definition":"CREATE INDEX idx_brevard_logs_property ON public.brevard_permit_search_logs USING btree (property_id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"brevard_permit_search_logs","permissive":"PERMISSIVE","policyname":"brevard_logs_admin_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"brevard_permit_search_logs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"business_attention_items","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"opportunity_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"priority","type":"text","default":"'normal'::text","identity":"","not_null":true,"generated":""},{"name":"state","type":"text","default":"'open'::text","identity":"","not_null":true,"generated":""},{"name":"deterministic_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"action_route","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"acknowledged_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"dismissed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"business_attention_items_pkey","definition":"CREATE UNIQUE INDEX business_attention_items_pkey ON public.business_attention_items USING btree (id)"},{"name":"business_attention_items_tenant_id_deterministic_key_key","definition":"CREATE UNIQUE INDEX business_attention_items_tenant_id_deterministic_key_key ON public.business_attention_items USING btree (tenant_id, deterministic_key)"},{"name":"business_attention_open_due_idx","definition":"CREATE INDEX business_attention_open_due_idx ON public.business_attention_items USING btree (tenant_id, state, due_at) WHERE (state = ANY (ARRAY['open'::text, 'acknowledged'::text]))"}],"policies":[{"cmd":"SELECT","qual":"ai_user_in_tenant(tenant_id)","roles":["authenticated"],"tablename":"business_attention_items","permissive":"PERMISSIVE","policyname":"business_attention_items_select","schemaname":"public","with_check":null}],"triggers":[{"name":"business_attention_items_touch_updated_at","definition":"CREATE TRIGGER business_attention_items_touch_updated_at BEFORE UPDATE ON business_attention_items FOR EACH ROW EXECUTE FUNCTION business_engine_touch_updated_at()"}],"constraints":[{"name":"business_attention_items_kind_check","definition":"CHECK (kind = ANY (ARRAY['opportunity_response_due'::text, 'proposal_followup_due'::text, 'deposit_due'::text, 'scheduling_needed'::text, 'balance_due'::text]))"},{"name":"business_attention_items_opportunity_id_fkey","definition":"FOREIGN KEY (opportunity_id) REFERENCES business_opportunities(id) ON DELETE CASCADE"},{"name":"business_attention_items_pkey","definition":"PRIMARY KEY (id)"},{"name":"business_attention_items_priority_check","definition":"CHECK (priority = ANY (ARRAY['low'::text, 'normal'::text, 'high'::text, 'urgent'::text]))"},{"name":"business_attention_items_state_check","definition":"CHECK (state = ANY (ARRAY['open'::text, 'acknowledged'::text, 'resolved'::text, 'dismissed'::text]))"},{"name":"business_attention_items_tenant_id_deterministic_key_key","definition":"UNIQUE (tenant_id, deterministic_key)"},{"name":"business_attention_items_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"business_hours_overrides","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"routing_profile_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"override_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"closed","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"open_time","type":"time without time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"close_time","type":"time without time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"business_hours_overrides_pkey","definition":"CREATE UNIQUE INDEX business_hours_overrides_pkey ON public.business_hours_overrides USING btree (id)"},{"name":"uq_bh_override_profile_date","definition":"CREATE UNIQUE INDEX uq_bh_override_profile_date ON public.business_hours_overrides USING btree (routing_profile_id, override_date)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"business_hours_overrides","permissive":"PERMISSIVE","policyname":"business_hours_overrides_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"business_hours_overrides","permissive":"PERMISSIVE","policyname":"business_hours_overrides_write_managers","schemaname":"public","with_check":"is_manager_or_higher(uid(), tenant_org_id)"}],"triggers":[],"constraints":[{"name":"business_hours_overrides_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"business_opportunities","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_module","type":"text","default":"'manual'::text","identity":"","not_null":true,"generated":""},{"name":"source_entity_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_entity_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"dedupe_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"confidence_score","type":"numeric(5,4)","default":null,"identity":"","not_null":false,"generated":""},{"name":"lifecycle_state","type":"text","default":"'captured'::text","identity":"","not_null":true,"generated":""},{"name":"proposal_state","type":"text","default":"'not_started'::text","identity":"","not_null":true,"generated":""},{"name":"payment_state","type":"text","default":"'not_required'::text","identity":"","not_null":true,"generated":""},{"name":"fulfillment_state","type":"text","default":"'not_scheduled'::text","identity":"","not_null":true,"generated":""},{"name":"estimated_value","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"quoted_amount","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"deposit_amount","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"balance_amount","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"invoice_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"calendar_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"response_due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"proposal_followup_due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deposit_due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"fulfillment_due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"balance_due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"proposal_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"accepted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deposit_paid_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"fulfillment_completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"paid_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"lost_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"cancelled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"business_opportunities_contact_idx","definition":"CREATE INDEX business_opportunities_contact_idx ON public.business_opportunities USING btree (tenant_id, contact_id) WHERE (contact_id IS NOT NULL)"},{"name":"business_opportunities_pkey","definition":"CREATE UNIQUE INDEX business_opportunities_pkey ON public.business_opportunities USING btree (id)"},{"name":"business_opportunities_tenant_commercial_idx","definition":"CREATE INDEX business_opportunities_tenant_commercial_idx ON public.business_opportunities USING btree (tenant_id, proposal_state, payment_state, fulfillment_state)"},{"name":"business_opportunities_tenant_id_dedupe_key_key","definition":"CREATE UNIQUE INDEX business_opportunities_tenant_id_dedupe_key_key ON public.business_opportunities USING btree (tenant_id, dedupe_key)"},{"name":"business_opportunities_tenant_lifecycle_idx","definition":"CREATE INDEX business_opportunities_tenant_lifecycle_idx ON public.business_opportunities USING btree (tenant_id, lifecycle_state, updated_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"ai_user_in_tenant(tenant_id)","roles":["authenticated"],"tablename":"business_opportunities","permissive":"PERMISSIVE","policyname":"business_opportunities_select","schemaname":"public","with_check":null}],"triggers":[{"name":"business_opportunities_refresh_attention","definition":"CREATE TRIGGER business_opportunities_refresh_attention AFTER INSERT OR UPDATE OF lifecycle_state, proposal_state, payment_state, fulfillment_state, response_due_at, proposal_followup_due_at, deposit_due_at, fulfillment_due_at, balance_due_at ON business_opportunities FOR EACH ROW EXECUTE FUNCTION business_engine_attention_trigger()"},{"name":"business_opportunities_touch_updated_at","definition":"CREATE TRIGGER business_opportunities_touch_updated_at BEFORE UPDATE ON business_opportunities FOR EACH ROW EXECUTE FUNCTION business_engine_touch_updated_at()"}],"constraints":[{"name":"business_opportunities_balance_amount_check","definition":"CHECK (balance_amount IS NULL OR balance_amount >= 0::numeric)"},{"name":"business_opportunities_calendar_event_id_fkey","definition":"FOREIGN KEY (calendar_event_id) REFERENCES user_calendar_events(id) ON DELETE SET NULL"},{"name":"business_opportunities_confidence_score_check","definition":"CHECK (confidence_score IS NULL OR confidence_score >= 0::numeric AND confidence_score <= 1::numeric)"},{"name":"business_opportunities_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"business_opportunities_deposit_amount_check","definition":"CHECK (deposit_amount IS NULL OR deposit_amount >= 0::numeric)"},{"name":"business_opportunities_estimated_value_check","definition":"CHECK (estimated_value IS NULL OR estimated_value >= 0::numeric)"},{"name":"business_opportunities_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"business_opportunities_fulfillment_state_check","definition":"CHECK (fulfillment_state = ANY (ARRAY['not_scheduled'::text, 'scheduled'::text, 'in_progress'::text, 'completed'::text, 'cancelled'::text]))"},{"name":"business_opportunities_invoice_id_fkey","definition":"FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE SET NULL"},{"name":"business_opportunities_lifecycle_state_check","definition":"CHECK (lifecycle_state = ANY (ARRAY['captured'::text, 'qualified'::text, 'won'::text, 'lost'::text, 'cancelled'::text]))"},{"name":"business_opportunities_payment_state_check","definition":"CHECK (payment_state = ANY (ARRAY['not_required'::text, 'deposit_due'::text, 'deposit_overdue'::text, 'deposit_paid'::text, 'balance_due'::text, 'balance_overdue'::text, 'paid'::text, 'refunded'::text, 'void'::text]))"},{"name":"business_opportunities_pkey","definition":"PRIMARY KEY (id)"},{"name":"business_opportunities_proposal_state_check","definition":"CHECK (proposal_state = ANY (ARRAY['not_started'::text, 'draft'::text, 'sent'::text, 'accepted'::text, 'declined'::text, 'void'::text]))"},{"name":"business_opportunities_quoted_amount_check","definition":"CHECK (quoted_amount IS NULL OR quoted_amount >= 0::numeric)"},{"name":"business_opportunities_source_event_id_fkey","definition":"FOREIGN KEY (source_event_id) REFERENCES intelligence_events(id) ON DELETE SET NULL"},{"name":"business_opportunities_tenant_id_dedupe_key_key","definition":"UNIQUE (tenant_id, dedupe_key)"},{"name":"business_opportunities_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"business_opportunity_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"opportunity_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"dimension","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason_code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"business_opportunity_events_history_idx","definition":"CREATE INDEX business_opportunity_events_history_idx ON public.business_opportunity_events USING btree (opportunity_id, created_at DESC)"},{"name":"business_opportunity_events_pkey","definition":"CREATE UNIQUE INDEX business_opportunity_events_pkey ON public.business_opportunity_events USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"ai_user_in_tenant(tenant_id)","roles":["authenticated"],"tablename":"business_opportunity_events","permissive":"PERMISSIVE","policyname":"business_opportunity_events_select","schemaname":"public","with_check":null}],"triggers":[{"name":"business_opportunity_events_activity_projection","definition":"CREATE TRIGGER business_opportunity_events_activity_projection AFTER INSERT ON business_opportunity_events FOR EACH ROW EXECUTE FUNCTION project_opportunity_business_activity()"}],"constraints":[{"name":"business_opportunity_events_dimension_check","definition":"CHECK (dimension = ANY (ARRAY['materialization'::text, 'lifecycle'::text, 'proposal'::text, 'payment'::text, 'fulfillment'::text, 'terms'::text]))"},{"name":"business_opportunity_events_opportunity_id_fkey","definition":"FOREIGN KEY (opportunity_id) REFERENCES business_opportunities(id) ON DELETE CASCADE"},{"name":"business_opportunity_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"business_opportunity_events_source_event_id_fkey","definition":"FOREIGN KEY (source_event_id) REFERENCES intelligence_events(id) ON DELETE SET NULL"},{"name":"business_opportunity_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"business_workflow_policies","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"auto_create_from_intelligence","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"opportunity_auto_create_min_confidence","type":"numeric(5,4)","default":"0.8000","identity":"","not_null":true,"generated":""},{"name":"response_due_minutes","type":"integer","default":"60","identity":"","not_null":true,"generated":""},{"name":"proposal_followup_hours","type":"integer","default":"48","identity":"","not_null":true,"generated":""},{"name":"deposit_due_hours","type":"integer","default":"72","identity":"","not_null":true,"generated":""},{"name":"balance_due_hours","type":"integer","default":"24","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"business_workflow_policies_pkey","definition":"CREATE UNIQUE INDEX business_workflow_policies_pkey ON public.business_workflow_policies USING btree (tenant_id)"}],"policies":[{"cmd":"ALL","qual":"ai_is_tenant_admin(tenant_id)","roles":["authenticated"],"tablename":"business_workflow_policies","permissive":"PERMISSIVE","policyname":"business_workflow_policies_admin_manage","schemaname":"public","with_check":"ai_is_tenant_admin(tenant_id)"},{"cmd":"SELECT","qual":"ai_user_in_tenant(tenant_id)","roles":["authenticated"],"tablename":"business_workflow_policies","permissive":"PERMISSIVE","policyname":"business_workflow_policies_select","schemaname":"public","with_check":null}],"triggers":[{"name":"business_workflow_policies_touch_updated_at","definition":"CREATE TRIGGER business_workflow_policies_touch_updated_at BEFORE UPDATE ON business_workflow_policies FOR EACH ROW EXECUTE FUNCTION business_engine_touch_updated_at()"}],"constraints":[{"name":"business_workflow_policies_balance_due_hours_check","definition":"CHECK (balance_due_hours >= 1 AND balance_due_hours <= 2160)"},{"name":"business_workflow_policies_deposit_due_hours_check","definition":"CHECK (deposit_due_hours >= 1 AND deposit_due_hours <= 2160)"},{"name":"business_workflow_policies_opportunity_auto_create_min_co_check","definition":"CHECK (opportunity_auto_create_min_confidence >= 0::numeric AND opportunity_auto_create_min_confidence <= 1::numeric)"},{"name":"business_workflow_policies_pkey","definition":"PRIMARY KEY (tenant_id)"},{"name":"business_workflow_policies_proposal_followup_hours_check","definition":"CHECK (proposal_followup_hours >= 1 AND proposal_followup_hours <= 2160)"},{"name":"business_workflow_policies_response_due_minutes_check","definition":"CHECK (response_due_minutes >= 1 AND response_due_minutes <= 10080)"},{"name":"business_workflow_policies_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"cached_parcel_roof_ages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"parcel_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lat","type":"double precision","default":null,"identity":"","not_null":true,"generated":""},{"name":"lng","type":"double precision","default":null,"identity":"","not_null":true,"generated":""},{"name":"year_built","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_age_score","type":"text","default":"'unknown'::text","identity":"","not_null":true,"generated":""},{"name":"viewport_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"fetched_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"sqft_heated","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"assessed_value","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"land_use","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sale_price","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"sale_date","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_permit_year","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_count","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"year_built_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"parcel_geometry","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"geometry_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"geometry_fetched_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"cached_parcel_roof_ages_pkey","definition":"CREATE UNIQUE INDEX cached_parcel_roof_ages_pkey ON public.cached_parcel_roof_ages USING btree (id)"},{"name":"idx_cached_parcel_roof_ages_fetched_at","definition":"CREATE INDEX idx_cached_parcel_roof_ages_fetched_at ON public.cached_parcel_roof_ages USING btree (fetched_at DESC)"},{"name":"idx_cached_parcels_coords","definition":"CREATE INDEX idx_cached_parcels_coords ON public.cached_parcel_roof_ages USING btree (lat, lng)"},{"name":"idx_cached_parcels_parcel_id","definition":"CREATE UNIQUE INDEX idx_cached_parcels_parcel_id ON public.cached_parcel_roof_ages USING btree (parcel_id)"},{"name":"idx_cached_parcels_viewport","definition":"CREATE INDEX idx_cached_parcels_viewport ON public.cached_parcel_roof_ages USING btree (viewport_key)"}],"policies":[{"cmd":"SELECT","qual":"(( SELECT uid() AS uid) IS NOT NULL)","roles":["authenticated"],"tablename":"cached_parcel_roof_ages","permissive":"PERMISSIVE","policyname":"Authenticated read cached parcels","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"cached_parcel_roof_ages","permissive":"PERMISSIVE","policyname":"Service role manages cached parcels","schemaname":"public","with_check":"true"},{"cmd":"UPDATE","qual":"( SELECT has_any_active_tenant_membership(uid()) AS has_any_active_tenant_membership)","roles":["authenticated"],"tablename":"cached_parcel_roof_ages","permissive":"PERMISSIVE","policyname":"Tenant members update cached parcels","schemaname":"public","with_check":"( SELECT has_any_active_tenant_membership(uid()) AS has_any_active_tenant_membership)"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"cached_parcel_roof_ages","permissive":"PERMISSIVE","policyname":"Tenant members upsert cached parcels","schemaname":"public","with_check":"( SELECT has_any_active_tenant_membership(uid()) AS has_any_active_tenant_membership)"}],"triggers":[],"constraints":[{"name":"cached_parcel_roof_ages_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"cafe_campaigns","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"kind","type":"text","default":"'promotion'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"starts_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"ends_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"cafe_campaigns_pkey","definition":"CREATE UNIQUE INDEX cafe_campaigns_pkey ON public.cafe_campaigns USING btree (id)"},{"name":"cafe_campaigns_tenant_created_idx","definition":"CREATE INDEX cafe_campaigns_tenant_created_idx ON public.cafe_campaigns USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_campaigns.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"cafe_campaigns","permissive":"PERMISSIVE","policyname":"cafe_campaigns_owner_access","schemaname":"public","with_check":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_campaigns.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"cafe_campaigns_pkey","definition":"PRIMARY KEY (id)"},{"name":"cafe_campaigns_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'scheduled'::text, 'active'::text, 'paused'::text, 'completed'::text]))"},{"name":"cafe_campaigns_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"cafe_loyalty_members","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"customer_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"points_balance","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"tier","type":"text","default":"'member'::text","identity":"","not_null":true,"generated":""},{"name":"visits","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"cafe_loyalty_members_pkey","definition":"CREATE UNIQUE INDEX cafe_loyalty_members_pkey ON public.cafe_loyalty_members USING btree (id)"},{"name":"cafe_loyalty_members_tenant_updated_idx","definition":"CREATE INDEX cafe_loyalty_members_tenant_updated_idx ON public.cafe_loyalty_members USING btree (tenant_org_id, updated_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_loyalty_members.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"cafe_loyalty_members","permissive":"PERMISSIVE","policyname":"cafe_loyalty_members_owner_access","schemaname":"public","with_check":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_loyalty_members.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"cafe_loyalty_members_pkey","definition":"PRIMARY KEY (id)"},{"name":"cafe_loyalty_members_points_balance_check","definition":"CHECK (points_balance >= 0)"},{"name":"cafe_loyalty_members_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"cafe_loyalty_members_visits_check","definition":"CHECK (visits >= 0)"}]},{"table":"cafe_menu_item_media","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"menu_item_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"asset_role","type":"text","default":"'primary'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'needed'::text","identity":"","not_null":true,"generated":""},{"name":"image_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"alt_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"creative_brief","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"generation_prompt","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"source_references","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"is_primary","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"cafe_menu_item_media_one_primary_idx","definition":"CREATE UNIQUE INDEX cafe_menu_item_media_one_primary_idx ON public.cafe_menu_item_media USING btree (menu_item_id) WHERE is_primary"},{"name":"cafe_menu_item_media_pkey","definition":"CREATE UNIQUE INDEX cafe_menu_item_media_pkey ON public.cafe_menu_item_media USING btree (id)"},{"name":"cafe_menu_item_media_tenant_item_idx","definition":"CREATE INDEX cafe_menu_item_media_tenant_item_idx ON public.cafe_menu_item_media USING btree (tenant_org_id, menu_item_id, sort_order)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_menu_item_media.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"cafe_menu_item_media","permissive":"PERMISSIVE","policyname":"cafe_menu_item_media_owner_access","schemaname":"public","with_check":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_menu_item_media.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))"}],"triggers":[{"name":"cafe_menu_item_media_touch_updated_at","definition":"CREATE TRIGGER cafe_menu_item_media_touch_updated_at BEFORE UPDATE ON cafe_menu_item_media FOR EACH ROW EXECUTE FUNCTION touch_cafe_menu_item_media_updated_at()"}],"constraints":[{"name":"cafe_menu_item_media_asset_role_check","definition":"CHECK (asset_role = ANY (ARRAY['primary'::text, 'alternate'::text, 'reference'::text]))"},{"name":"cafe_menu_item_media_menu_item_id_fkey","definition":"FOREIGN KEY (menu_item_id) REFERENCES cafe_menu_items(id) ON DELETE CASCADE"},{"name":"cafe_menu_item_media_pkey","definition":"PRIMARY KEY (id)"},{"name":"cafe_menu_item_media_status_check","definition":"CHECK (status = ANY (ARRAY['needed'::text, 'brief_ready'::text, 'generating'::text, 'ready'::text, 'rejected'::text]))"},{"name":"cafe_menu_item_media_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"cafe_menu_items","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"external_item_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"menu_section","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"price","type":"numeric(10,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"available","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"stock_quantity","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"low_stock_alert","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"modifiers","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"tags","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"image_url","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"cafe_menu_items_pkey","definition":"CREATE UNIQUE INDEX cafe_menu_items_pkey ON public.cafe_menu_items USING btree (id)"},{"name":"cafe_menu_items_tenant_available_sort_idx","definition":"CREATE INDEX cafe_menu_items_tenant_available_sort_idx ON public.cafe_menu_items USING btree (tenant_org_id, available, sort_order)"},{"name":"cafe_menu_items_tenant_org_id_external_item_id_key","definition":"CREATE UNIQUE INDEX cafe_menu_items_tenant_org_id_external_item_id_key ON public.cafe_menu_items USING btree (tenant_org_id, external_item_id)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_menu_items.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"cafe_menu_items","permissive":"PERMISSIVE","policyname":"cafe_menu_items_owner_access","schemaname":"public","with_check":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_menu_items.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))"},{"cmd":"SELECT","qual":"(available AND (EXISTS ( SELECT 1\n   FROM cafe_public_settings public_settings\n  WHERE ((public_settings.tenant_org_id = cafe_menu_items.tenant_org_id) AND (public_settings.slug = 'thirsty-panda'::text)))))","roles":["anon","authenticated"],"tablename":"cafe_menu_items","permissive":"PERMISSIVE","policyname":"cafe_menu_items_public_read","schemaname":"public","with_check":null}],"triggers":[{"name":"cafe_menu_items_media_stub_after_insert","definition":"CREATE TRIGGER cafe_menu_items_media_stub_after_insert AFTER INSERT ON cafe_menu_items FOR EACH ROW EXECUTE FUNCTION ensure_cafe_menu_item_media_stub()"}],"constraints":[{"name":"cafe_menu_items_pkey","definition":"PRIMARY KEY (id)"},{"name":"cafe_menu_items_price_check","definition":"CHECK (price >= 0::numeric)"},{"name":"cafe_menu_items_tenant_org_id_external_item_id_key","definition":"UNIQUE (tenant_org_id, external_item_id)"},{"name":"cafe_menu_items_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"cafe_order_items","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"order_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"menu_item_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"item_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"quantity","type":"numeric(10,3)","default":"1","identity":"","not_null":true,"generated":""},{"name":"unit_price","type":"numeric(10,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"selected_modifiers","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"cafe_order_items_pkey","definition":"CREATE UNIQUE INDEX cafe_order_items_pkey ON public.cafe_order_items USING btree (id)"},{"name":"cafe_order_items_tenant_order_sort_idx","definition":"CREATE INDEX cafe_order_items_tenant_order_sort_idx ON public.cafe_order_items USING btree (tenant_org_id, order_id, sort_order)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_order_items.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"cafe_order_items","permissive":"PERMISSIVE","policyname":"cafe_order_items_owner_access","schemaname":"public","with_check":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_order_items.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"cafe_order_items_menu_item_id_fkey","definition":"FOREIGN KEY (menu_item_id) REFERENCES cafe_menu_items(id) ON DELETE SET NULL"},{"name":"cafe_order_items_order_id_fkey","definition":"FOREIGN KEY (order_id) REFERENCES cafe_orders(id) ON DELETE CASCADE"},{"name":"cafe_order_items_pkey","definition":"PRIMARY KEY (id)"},{"name":"cafe_order_items_quantity_check","definition":"CHECK (quantity > 0::numeric)"},{"name":"cafe_order_items_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"cafe_order_items_unit_price_check","definition":"CHECK (unit_price >= 0::numeric)"}]},{"table":"cafe_orders","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"order_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'clover'::text","identity":"","not_null":true,"generated":""},{"name":"order_type","type":"text","default":"'pickup'::text","identity":"","not_null":true,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'accepted'::text","identity":"","not_null":true,"generated":""},{"name":"subtotal","type":"numeric(10,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"tax","type":"numeric(10,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"total","type":"numeric(10,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"cafe_orders_pkey","definition":"CREATE UNIQUE INDEX cafe_orders_pkey ON public.cafe_orders USING btree (id)"},{"name":"cafe_orders_tenant_created_idx","definition":"CREATE INDEX cafe_orders_tenant_created_idx ON public.cafe_orders USING btree (tenant_org_id, created_at DESC)"},{"name":"cafe_orders_tenant_org_id_order_number_key","definition":"CREATE UNIQUE INDEX cafe_orders_tenant_org_id_order_number_key ON public.cafe_orders USING btree (tenant_org_id, order_number)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_orders.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"cafe_orders","permissive":"PERMISSIVE","policyname":"cafe_orders_owner_access","schemaname":"public","with_check":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_orders.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"cafe_orders_pkey","definition":"PRIMARY KEY (id)"},{"name":"cafe_orders_status_check","definition":"CHECK (status = ANY (ARRAY['accepted'::text, 'preparing'::text, 'ready'::text, 'completed'::text, 'cancelled'::text]))"},{"name":"cafe_orders_subtotal_check","definition":"CHECK (subtotal >= 0::numeric)"},{"name":"cafe_orders_tax_check","definition":"CHECK (tax >= 0::numeric)"},{"name":"cafe_orders_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"cafe_orders_tenant_org_id_order_number_key","definition":"UNIQUE (tenant_org_id, order_number)"},{"name":"cafe_orders_total_check","definition":"CHECK (total >= 0::numeric)"}]},{"table":"cafe_public_settings","schema":"public","columns":[{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"slug","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"logo_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"hero_video_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"clover_status","type":"text","default":"'setup_required'::text","identity":"","not_null":true,"generated":""},{"name":"clover_checkout_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"cafe_public_settings_pkey","definition":"CREATE UNIQUE INDEX cafe_public_settings_pkey ON public.cafe_public_settings USING btree (tenant_org_id)"},{"name":"cafe_public_settings_slug_key","definition":"CREATE UNIQUE INDEX cafe_public_settings_slug_key ON public.cafe_public_settings USING btree (slug)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_public_settings.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"cafe_public_settings","permissive":"PERMISSIVE","policyname":"cafe_public_settings_owner_write","schemaname":"public","with_check":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_public_settings.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))"},{"cmd":"SELECT","qual":"(slug = 'thirsty-panda'::text)","roles":["anon","authenticated"],"tablename":"cafe_public_settings","permissive":"PERMISSIVE","policyname":"cafe_public_settings_public_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"cafe_public_settings_clover_status_check","definition":"CHECK (clover_status = ANY (ARRAY['setup_required'::text, 'connected'::text, 'disabled'::text]))"},{"name":"cafe_public_settings_pkey","definition":"PRIMARY KEY (tenant_org_id)"},{"name":"cafe_public_settings_slug_key","definition":"UNIQUE (slug)"},{"name":"cafe_public_settings_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"cafe_tables","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'available'::text","identity":"","not_null":true,"generated":""},{"name":"guest_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"cafe_tables_pkey","definition":"CREATE UNIQUE INDEX cafe_tables_pkey ON public.cafe_tables USING btree (id)"},{"name":"cafe_tables_tenant_org_id_label_key","definition":"CREATE UNIQUE INDEX cafe_tables_tenant_org_id_label_key ON public.cafe_tables USING btree (tenant_org_id, label)"},{"name":"cafe_tables_tenant_sort_idx","definition":"CREATE INDEX cafe_tables_tenant_sort_idx ON public.cafe_tables USING btree (tenant_org_id, sort_order)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_tables.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"cafe_tables","permissive":"PERMISSIVE","policyname":"cafe_tables_owner_access","schemaname":"public","with_check":"(is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND (membership.tenant_id = cafe_tables.tenant_org_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"cafe_tables_guest_count_check","definition":"CHECK (guest_count >= 0)"},{"name":"cafe_tables_pkey","definition":"PRIMARY KEY (id)"},{"name":"cafe_tables_status_check","definition":"CHECK (status = ANY (ARRAY['available'::text, 'seated'::text, 'reserved'::text, 'cleaning'::text]))"},{"name":"cafe_tables_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"cafe_tables_tenant_org_id_label_key","definition":"UNIQUE (tenant_org_id, label)"}]},{"table":"calendar_connection_oauth_states","schema":"public","columns":[{"name":"state_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scope","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"return_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"code_verifier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"consumed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"calendar_connection_oauth_states_pkey","definition":"CREATE UNIQUE INDEX calendar_connection_oauth_states_pkey ON public.calendar_connection_oauth_states USING btree (state_hash)"}],"policies":[],"triggers":[],"constraints":[{"name":"calendar_connection_oauth_states_pkey","definition":"PRIMARY KEY (state_hash)"},{"name":"calendar_connection_oauth_states_scope_check","definition":"CHECK (scope = ANY (ARRAY['personal'::text, 'business'::text]))"},{"name":"calendar_connection_oauth_states_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"calendar_connection_oauth_states_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"calendar_connection_secrets","schema":"public","columns":[{"name":"connection_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"ciphertext","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"iv","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"key_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"calendar_connection_secrets_pkey","definition":"CREATE UNIQUE INDEX calendar_connection_secrets_pkey ON public.calendar_connection_secrets USING btree (connection_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"calendar_connection_secrets_connection_id_fkey","definition":"FOREIGN KEY (connection_id) REFERENCES calendar_connections(id) ON DELETE CASCADE"},{"name":"calendar_connection_secrets_pkey","definition":"PRIMARY KEY (connection_id)"}]},{"table":"calendar_connections","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"owner_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"scope","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"account_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_calendar_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"read_only","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"last_synced_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_sync_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"calendar_connections_identity_idx","definition":"CREATE UNIQUE INDEX calendar_connections_identity_idx ON public.calendar_connections USING btree (tenant_id, scope, provider, COALESCE(owner_user_id, '00000000-0000-0000-0000-000000000000'::uuid), COALESCE(external_calendar_id, ''::text))"},{"name":"calendar_connections_pkey","definition":"CREATE UNIQUE INDEX calendar_connections_pkey ON public.calendar_connections USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(((scope = 'personal'::text) AND (owner_user_id = uid())) OR ((scope = 'business'::text) AND is_tenant_member(uid(), tenant_id)))","roles":["authenticated"],"tablename":"calendar_connections","permissive":"PERMISSIVE","policyname":"calendar_connections_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((scope = 'personal'::text) AND (owner_user_id = uid()))","roles":["authenticated"],"tablename":"calendar_connections","permissive":"PERMISSIVE","policyname":"calendar_connections_update_personal","schemaname":"public","with_check":"((scope = 'personal'::text) AND (owner_user_id = uid()))"}],"triggers":[],"constraints":[{"name":"calendar_connections_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id)"},{"name":"calendar_connections_owner_user_id_fkey","definition":"FOREIGN KEY (owner_user_id) REFERENCES users(id) ON DELETE CASCADE"},{"name":"calendar_connections_pkey","definition":"PRIMARY KEY (id)"},{"name":"calendar_connections_provider_check","definition":"CHECK (provider = ANY (ARRAY['google_calendar'::text, 'microsoft_calendar'::text, 'zoho_calendar'::text, 'caldav'::text, 'ics'::text]))"},{"name":"calendar_connections_scope_check","definition":"CHECK (scope = ANY (ARRAY['personal'::text, 'business'::text]))"},{"name":"calendar_connections_scope_owner","definition":"CHECK (scope = 'personal'::text AND owner_user_id IS NOT NULL OR scope = 'business'::text)"},{"name":"calendar_connections_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'needs_attention'::text, 'disabled'::text]))"},{"name":"calendar_connections_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"calendar_external_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"connection_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"owner_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"scope","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"external_event_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"calendar_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"location","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"start_time","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"end_time","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"all_day","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"etag","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"synced_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"calendar_external_events_connection_id_external_event_id_key","definition":"CREATE UNIQUE INDEX calendar_external_events_connection_id_external_event_id_key ON public.calendar_external_events USING btree (connection_id, external_event_id)"},{"name":"calendar_external_events_owner_time_idx","definition":"CREATE INDEX calendar_external_events_owner_time_idx ON public.calendar_external_events USING btree (owner_user_id, start_time) WHERE (owner_user_id IS NOT NULL)"},{"name":"calendar_external_events_pkey","definition":"CREATE UNIQUE INDEX calendar_external_events_pkey ON public.calendar_external_events USING btree (id)"},{"name":"calendar_external_events_tenant_time_idx","definition":"CREATE INDEX calendar_external_events_tenant_time_idx ON public.calendar_external_events USING btree (tenant_id, start_time)"}],"policies":[{"cmd":"SELECT","qual":"(((scope = 'personal'::text) AND (owner_user_id = uid())) OR ((scope = 'business'::text) AND is_tenant_member(uid(), tenant_id)))","roles":["authenticated"],"tablename":"calendar_external_events","permissive":"PERMISSIVE","policyname":"calendar_external_events_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"calendar_external_events_connection_id_external_event_id_key","definition":"UNIQUE (connection_id, external_event_id)"},{"name":"calendar_external_events_connection_id_fkey","definition":"FOREIGN KEY (connection_id) REFERENCES calendar_connections(id) ON DELETE CASCADE"},{"name":"calendar_external_events_owner_user_id_fkey","definition":"FOREIGN KEY (owner_user_id) REFERENCES users(id) ON DELETE CASCADE"},{"name":"calendar_external_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"calendar_external_events_scope_check","definition":"CHECK (scope = ANY (ARRAY['personal'::text, 'business'::text]))"},{"name":"calendar_external_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"call_assist_pushes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"active_call_session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"pushed_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"kind","type":"text","default":"'script'::text","identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"acknowledged_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_assist_pushes_pkey","definition":"CREATE UNIQUE INDEX call_assist_pushes_pkey ON public.call_assist_pushes USING btree (id)"},{"name":"idx_call_assist_pushes_rep_unack","definition":"CREATE INDEX idx_call_assist_pushes_rep_unack ON public.call_assist_pushes USING btree (rep_id, acknowledged_at) WHERE (acknowledged_at IS NULL)"},{"name":"idx_call_assist_pushes_session","definition":"CREATE INDEX idx_call_assist_pushes_session ON public.call_assist_pushes USING btree (active_call_session_id, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"call_assist_pushes","permissive":"PERMISSIVE","policyname":"cap_insert_manager","schemaname":"public","with_check":"((pushed_by = uid()) AND ((is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin()))"},{"cmd":"SELECT","qual":"((rep_id = uid()) OR (is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())","roles":["authenticated"],"tablename":"call_assist_pushes","permissive":"PERMISSIVE","policyname":"cap_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(rep_id = uid())","roles":["authenticated"],"tablename":"call_assist_pushes","permissive":"PERMISSIVE","policyname":"cap_update_ack","schemaname":"public","with_check":"(rep_id = uid())"}],"triggers":[],"constraints":[{"name":"call_assist_pushes_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"call_assist_suggestions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"active_call_session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"confidence","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"acted_on","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_assist_suggestions_pkey","definition":"CREATE UNIQUE INDEX call_assist_suggestions_pkey ON public.call_assist_suggestions USING btree (id)"},{"name":"idx_call_assist_suggestions_session","definition":"CREATE INDEX idx_call_assist_suggestions_session ON public.call_assist_suggestions USING btree (active_call_session_id, created_at DESC)"},{"name":"idx_call_assist_suggestions_tenant_lead","definition":"CREATE INDEX idx_call_assist_suggestions_tenant_lead ON public.call_assist_suggestions USING btree (tenant_org_id, lead_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"call_assist_suggestions","permissive":"PERMISSIVE","policyname":"tenant_members_read_call_assist_suggestions","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"call_assist_suggestions","permissive":"PERMISSIVE","policyname":"tenant_members_update_acted_on","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"}],"triggers":[],"constraints":[{"name":"call_assist_suggestions_kind_check","definition":"CHECK (kind = ANY (ARRAY['objection'::text, 'dnc'::text, 'script_stage'::text, 'final'::text, 'error'::text]))"},{"name":"call_assist_suggestions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"call_attempts_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_normalized","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"attempt_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"was_inbound","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"call_log_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_attempts_log_pkey","definition":"CREATE UNIQUE INDEX call_attempts_log_pkey ON public.call_attempts_log USING btree (id)"},{"name":"idx_call_attempts_lead","definition":"CREATE INDEX idx_call_attempts_lead ON public.call_attempts_log USING btree (lead_id, created_at DESC)"},{"name":"idx_call_attempts_tenant_phone_time","definition":"CREATE INDEX idx_call_attempts_tenant_phone_time ON public.call_attempts_log USING btree (tenant_org_id, phone_normalized, created_at DESC) WHERE (was_inbound = false)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"call_attempts_log","permissive":"PERMISSIVE","policyname":"tenant_members_insert_attempts","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"call_attempts_log","permissive":"PERMISSIVE","policyname":"tenant_members_view_attempts","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"call_attempts_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"call_campaigns","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"storm_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_campaigns_pkey","definition":"CREATE UNIQUE INDEX call_campaigns_pkey ON public.call_campaigns USING btree (id)"},{"name":"idx_call_campaigns_tenant","definition":"CREATE INDEX idx_call_campaigns_tenant ON public.call_campaigns USING btree (tenant_org_id)"}],"policies":[{"cmd":"ALL","qual":"((is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())","roles":["public"],"tablename":"call_campaigns","permissive":"PERMISSIVE","policyname":"campaigns_admin_write","schemaname":"public","with_check":"((is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"call_campaigns","permissive":"PERMISSIVE","policyname":"campaigns_select_tenant","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_call_campaigns_updated_at","definition":"CREATE TRIGGER trg_call_campaigns_updated_at BEFORE UPDATE ON call_campaigns FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"call_campaigns_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"call_center_agents","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"preferred_language","type":"text","default":"'en'::text","identity":"","not_null":true,"generated":""},{"name":"timezone","type":"text","default":"'America/New_York'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"ready_for_calls","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_center_agents_pkey","definition":"CREATE UNIQUE INDEX call_center_agents_pkey ON public.call_center_agents USING btree (id)"},{"name":"call_center_agents_tenant_id_user_id_key","definition":"CREATE UNIQUE INDEX call_center_agents_tenant_id_user_id_key ON public.call_center_agents USING btree (tenant_id, user_id)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["public"],"tablename":"call_center_agents","permissive":"PERMISSIVE","policyname":"call_center_agents_tenant_access","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_agents_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_agents_preferred_language_check","definition":"CHECK (preferred_language = ANY (ARRAY['en'::text, 'fil'::text]))"},{"name":"call_center_agents_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'paused'::text]))"},{"name":"call_center_agents_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"call_center_agents_tenant_id_user_id_key","definition":"UNIQUE (tenant_id, user_id)"},{"name":"call_center_agents_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"call_center_campaign_agents","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"agent_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"assigned_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"assigned_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"call_center_campaign_agents_pkey","definition":"CREATE UNIQUE INDEX call_center_campaign_agents_pkey ON public.call_center_campaign_agents USING btree (id)"},{"name":"call_center_campaign_agents_tenant_id_campaign_id_agent_use_key","definition":"CREATE UNIQUE INDEX call_center_campaign_agents_tenant_id_campaign_id_agent_use_key ON public.call_center_campaign_agents USING btree (tenant_id, campaign_id, agent_user_id)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["public"],"tablename":"call_center_campaign_agents","permissive":"PERMISSIVE","policyname":"call_center_campaign_agents_tenant_access","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_campaign_agents_agent_user_id_fkey","definition":"FOREIGN KEY (agent_user_id) REFERENCES users(id) ON DELETE CASCADE"},{"name":"call_center_campaign_agents_assigned_by_user_id_fkey","definition":"FOREIGN KEY (assigned_by_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"call_center_campaign_agents_campaign_id_fkey","definition":"FOREIGN KEY (campaign_id) REFERENCES call_center_campaigns(id) ON DELETE CASCADE"},{"name":"call_center_campaign_agents_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_campaign_agents_tenant_id_campaign_id_agent_use_key","definition":"UNIQUE (tenant_id, campaign_id, agent_user_id)"},{"name":"call_center_campaign_agents_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"call_center_campaign_members","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'ready'::text","identity":"","not_null":true,"generated":""},{"name":"import_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"last_disposition_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_called_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_action_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"attempt_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"exhausted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"call_center_campaign_members_campaign_id_contact_id_key","definition":"CREATE UNIQUE INDEX call_center_campaign_members_campaign_id_contact_id_key ON public.call_center_campaign_members USING btree (campaign_id, contact_id)"},{"name":"call_center_campaign_members_campaign_status_idx","definition":"CREATE INDEX call_center_campaign_members_campaign_status_idx ON public.call_center_campaign_members USING btree (tenant_id, campaign_id, status, priority DESC)"},{"name":"call_center_campaign_members_contact_idx","definition":"CREATE INDEX call_center_campaign_members_contact_idx ON public.call_center_campaign_members USING btree (tenant_id, contact_id, updated_at DESC)"},{"name":"call_center_campaign_members_pkey","definition":"CREATE UNIQUE INDEX call_center_campaign_members_pkey ON public.call_center_campaign_members USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_campaign_members","permissive":"PERMISSIVE","policyname":"call_center_campaign_members_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_campaign_members_assigned_user_id_fkey","definition":"FOREIGN KEY (assigned_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"call_center_campaign_members_campaign_id_contact_id_key","definition":"UNIQUE (campaign_id, contact_id)"},{"name":"call_center_campaign_members_campaign_id_fkey","definition":"FOREIGN KEY (campaign_id) REFERENCES call_center_campaigns(id) ON DELETE CASCADE"},{"name":"call_center_campaign_members_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE CASCADE"},{"name":"call_center_campaign_members_import_id_fkey","definition":"FOREIGN KEY (import_id) REFERENCES call_center_imports(id) ON DELETE SET NULL"},{"name":"call_center_campaign_members_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_campaign_members_status_check","definition":"CHECK (status = ANY (ARRAY['ready'::text, 'queued'::text, 'in_progress'::text, 'follow_up'::text, 'completed'::text, 'skipped'::text, 'do_not_call'::text, 'removed'::text]))"},{"name":"call_center_campaign_members_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"call_center_campaigns","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"workflow_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"default_assigned_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"default_priority","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"starts_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"ends_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"timezone","type":"text","default":"'America/New_York'::text","identity":"","not_null":true,"generated":""},{"name":"calling_window_start","type":"time without time zone","default":"'09:00:00'::time without time zone","identity":"","not_null":true,"generated":""},{"name":"calling_window_end","type":"time without time zone","default":"'19:00:00'::time without time zone","identity":"","not_null":true,"generated":""},{"name":"max_attempts","type":"integer","default":"3","identity":"","not_null":true,"generated":""},{"name":"retry_delay_minutes","type":"integer","default":"1440","identity":"","not_null":true,"generated":""},{"name":"goal_calls","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"goal_completions","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"call_center_campaigns_pkey","definition":"CREATE UNIQUE INDEX call_center_campaigns_pkey ON public.call_center_campaigns USING btree (id)"},{"name":"call_center_campaigns_tenant_id_name_key","definition":"CREATE UNIQUE INDEX call_center_campaigns_tenant_id_name_key ON public.call_center_campaigns USING btree (tenant_id, name)"},{"name":"call_center_campaigns_tenant_status_idx","definition":"CREATE INDEX call_center_campaigns_tenant_status_idx ON public.call_center_campaigns USING btree (tenant_id, status, updated_at DESC)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_campaigns","permissive":"PERMISSIVE","policyname":"call_center_campaigns_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_campaigns_created_by_user_id_fkey","definition":"FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"call_center_campaigns_default_assigned_user_id_fkey","definition":"FOREIGN KEY (default_assigned_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"call_center_campaigns_max_attempts_check","definition":"CHECK (max_attempts >= 1 AND max_attempts <= 25)"},{"name":"call_center_campaigns_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_campaigns_retry_delay_minutes_check","definition":"CHECK (retry_delay_minutes >= 5)"},{"name":"call_center_campaigns_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'active'::text, 'paused'::text, 'completed'::text, 'archived'::text]))"},{"name":"call_center_campaigns_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"call_center_campaigns_tenant_id_name_key","definition":"UNIQUE (tenant_id, name)"},{"name":"call_center_campaigns_workflow_id_fkey","definition":"FOREIGN KEY (workflow_id) REFERENCES call_center_workflows(id) ON DELETE SET NULL"}]},{"table":"call_center_dispositions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"requires_follow_up","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_center_dispositions_pkey","definition":"CREATE UNIQUE INDEX call_center_dispositions_pkey ON public.call_center_dispositions USING btree (id)"},{"name":"call_center_dispositions_tenant_id_key_key","definition":"CREATE UNIQUE INDEX call_center_dispositions_tenant_id_key_key ON public.call_center_dispositions USING btree (tenant_id, key)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_dispositions","permissive":"PERMISSIVE","policyname":"call_center_dispositions_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_dispositions_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_dispositions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"call_center_dispositions_tenant_id_key_key","definition":"UNIQUE (tenant_id, key)"}]},{"table":"call_center_import_mappings","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"mapping","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_center_import_mappings_pkey","definition":"CREATE UNIQUE INDEX call_center_import_mappings_pkey ON public.call_center_import_mappings USING btree (id)"},{"name":"call_center_import_mappings_tenant_id_name_key","definition":"CREATE UNIQUE INDEX call_center_import_mappings_tenant_id_name_key ON public.call_center_import_mappings USING btree (tenant_id, name)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_import_mappings","permissive":"PERMISSIVE","policyname":"call_center_import_mappings_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_import_mappings_created_by_user_id_fkey","definition":"FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"call_center_import_mappings_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_import_mappings_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"call_center_import_mappings_tenant_id_name_key","definition":"UNIQUE (tenant_id, name)"}]},{"table":"call_center_imports","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"file_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_kind","type":"text","default":"'csv'::text","identity":"","not_null":true,"generated":""},{"name":"mapping","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"total_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"imported_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"duplicate_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"invalid_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"skipped_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"imported_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_center_imports_pkey","definition":"CREATE UNIQUE INDEX call_center_imports_pkey ON public.call_center_imports USING btree (id)"},{"name":"call_center_imports_tenant_idx","definition":"CREATE INDEX call_center_imports_tenant_idx ON public.call_center_imports USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_imports","permissive":"PERMISSIVE","policyname":"call_center_imports_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_imports_campaign_id_fkey","definition":"FOREIGN KEY (campaign_id) REFERENCES call_center_campaigns(id) ON DELETE SET NULL"},{"name":"call_center_imports_imported_by_user_id_fkey","definition":"FOREIGN KEY (imported_by_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"call_center_imports_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_imports_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"call_center_notes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"author_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_center_notes_pkey","definition":"CREATE UNIQUE INDEX call_center_notes_pkey ON public.call_center_notes USING btree (id)"},{"name":"call_center_notes_session_idx","definition":"CREATE INDEX call_center_notes_session_idx ON public.call_center_notes USING btree (tenant_id, session_id, created_at)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_notes","permissive":"PERMISSIVE","policyname":"call_center_notes_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_notes_author_user_id_fkey","definition":"FOREIGN KEY (author_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"call_center_notes_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"call_center_notes_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_notes_session_id_fkey","definition":"FOREIGN KEY (session_id) REFERENCES call_center_sessions(id) ON DELETE CASCADE"},{"name":"call_center_notes_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"call_center_playbooks","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"opener","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"discovery","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"objections","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"offer","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"close_text","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"updated_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_center_playbooks_pkey","definition":"CREATE UNIQUE INDEX call_center_playbooks_pkey ON public.call_center_playbooks USING btree (id)"},{"name":"call_center_playbooks_tenant_campaign_idx","definition":"CREATE INDEX call_center_playbooks_tenant_campaign_idx ON public.call_center_playbooks USING btree (tenant_id, campaign_id)"},{"name":"call_center_playbooks_tenant_id_campaign_id_key","definition":"CREATE UNIQUE INDEX call_center_playbooks_tenant_id_campaign_id_key ON public.call_center_playbooks USING btree (tenant_id, campaign_id)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_playbooks","permissive":"PERMISSIVE","policyname":"call_center_playbooks_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_playbooks_campaign_id_fkey","definition":"FOREIGN KEY (campaign_id) REFERENCES call_center_campaigns(id) ON DELETE CASCADE"},{"name":"call_center_playbooks_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_playbooks_tenant_id_campaign_id_key","definition":"UNIQUE (tenant_id, campaign_id)"},{"name":"call_center_playbooks_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"call_center_playbooks_updated_by_user_id_fkey","definition":"FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL"}]},{"table":"call_center_qa_reviews","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"reviewer_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"rating","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"review_status","type":"text","default":"'reviewed'::text","identity":"","not_null":true,"generated":""},{"name":"coaching_note","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_center_qa_reviews_pkey","definition":"CREATE UNIQUE INDEX call_center_qa_reviews_pkey ON public.call_center_qa_reviews USING btree (id)"},{"name":"call_center_qa_reviews_tenant_id_session_id_key","definition":"CREATE UNIQUE INDEX call_center_qa_reviews_tenant_id_session_id_key ON public.call_center_qa_reviews USING btree (tenant_id, session_id)"},{"name":"call_center_qa_reviews_tenant_status_idx","definition":"CREATE INDEX call_center_qa_reviews_tenant_status_idx ON public.call_center_qa_reviews USING btree (tenant_id, review_status, reviewed_at DESC)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_qa_reviews","permissive":"PERMISSIVE","policyname":"call_center_qa_reviews_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_qa_reviews_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_qa_reviews_rating_check","definition":"CHECK (rating >= 1 AND rating <= 5)"},{"name":"call_center_qa_reviews_review_status_check","definition":"CHECK (review_status = ANY (ARRAY['reviewed'::text, 'coaching'::text, 'resolved'::text]))"},{"name":"call_center_qa_reviews_reviewer_user_id_fkey","definition":"FOREIGN KEY (reviewer_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"call_center_qa_reviews_session_id_fkey","definition":"FOREIGN KEY (session_id) REFERENCES call_center_sessions(id) ON DELETE CASCADE"},{"name":"call_center_qa_reviews_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"call_center_qa_reviews_tenant_id_session_id_key","definition":"UNIQUE (tenant_id, session_id)"}]},{"table":"call_center_queue","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assigned_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""},{"name":"priority","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"next_action_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_disposition_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"attempt_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"last_attempt_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"call_center_queue_assignee_idx","definition":"CREATE INDEX call_center_queue_assignee_idx ON public.call_center_queue USING btree (tenant_id, assigned_user_id, status)"},{"name":"call_center_queue_campaign_contact_unique","definition":"CREATE UNIQUE INDEX call_center_queue_campaign_contact_unique ON public.call_center_queue USING btree (tenant_id, campaign_id, contact_id) WHERE (campaign_id IS NOT NULL)"},{"name":"call_center_queue_campaign_idx","definition":"CREATE INDEX call_center_queue_campaign_idx ON public.call_center_queue USING btree (tenant_id, campaign_id, status, priority DESC)"},{"name":"call_center_queue_general_contact_unique","definition":"CREATE UNIQUE INDEX call_center_queue_general_contact_unique ON public.call_center_queue USING btree (tenant_id, contact_id) WHERE (campaign_id IS NULL)"},{"name":"call_center_queue_pkey","definition":"CREATE UNIQUE INDEX call_center_queue_pkey ON public.call_center_queue USING btree (id)"},{"name":"call_center_queue_tenant_status_priority_idx","definition":"CREATE INDEX call_center_queue_tenant_status_priority_idx ON public.call_center_queue USING btree (tenant_id, status, priority DESC, created_at)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_queue","permissive":"PERMISSIVE","policyname":"call_center_queue_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_queue_assigned_user_id_fkey","definition":"FOREIGN KEY (assigned_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"call_center_queue_campaign_id_fkey","definition":"FOREIGN KEY (campaign_id) REFERENCES call_center_campaigns(id) ON DELETE SET NULL"},{"name":"call_center_queue_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE CASCADE"},{"name":"call_center_queue_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_queue_status_check","definition":"CHECK (status = ANY (ARRAY['queued'::text, 'assigned'::text, 'in_progress'::text, 'completed'::text, 'paused'::text, 'removed'::text]))"},{"name":"call_center_queue_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"call_center_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"queue_item_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"agent_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"workflow_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_stage_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"channel","type":"text","default":"'phone'::text","identity":"","not_null":true,"generated":""},{"name":"direction","type":"text","default":"'outbound'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'in_progress'::text","identity":"","not_null":true,"generated":""},{"name":"disposition_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"follow_up_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_call_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_parent_call_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"transcript_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"answered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"ended_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"call_center_sessions_campaign_idx","definition":"CREATE INDEX call_center_sessions_campaign_idx ON public.call_center_sessions USING btree (tenant_id, campaign_id, started_at DESC)"},{"name":"call_center_sessions_contact_idx","definition":"CREATE INDEX call_center_sessions_contact_idx ON public.call_center_sessions USING btree (tenant_id, contact_id, started_at DESC)"},{"name":"call_center_sessions_pkey","definition":"CREATE UNIQUE INDEX call_center_sessions_pkey ON public.call_center_sessions USING btree (id)"},{"name":"call_center_sessions_provider_call_idx","definition":"CREATE INDEX call_center_sessions_provider_call_idx ON public.call_center_sessions USING btree (provider_name, provider_call_id) WHERE (provider_call_id IS NOT NULL)"},{"name":"call_center_sessions_tenant_started_idx","definition":"CREATE INDEX call_center_sessions_tenant_started_idx ON public.call_center_sessions USING btree (tenant_id, started_at DESC)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_sessions","permissive":"PERMISSIVE","policyname":"call_center_sessions_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_sessions_agent_user_id_fkey","definition":"FOREIGN KEY (agent_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"call_center_sessions_campaign_id_fkey","definition":"FOREIGN KEY (campaign_id) REFERENCES call_center_campaigns(id) ON DELETE SET NULL"},{"name":"call_center_sessions_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"call_center_sessions_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_sessions_queue_item_id_fkey","definition":"FOREIGN KEY (queue_item_id) REFERENCES call_center_queue(id) ON DELETE SET NULL"},{"name":"call_center_sessions_status_check","definition":"CHECK (status = ANY (ARRAY['queued'::text, 'ringing'::text, 'in_progress'::text, 'completed'::text, 'failed'::text, 'cancelled'::text]))"},{"name":"call_center_sessions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"call_center_sessions_workflow_id_fkey","definition":"FOREIGN KEY (workflow_id) REFERENCES call_center_workflows(id) ON DELETE SET NULL"}]},{"table":"call_center_stages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"workflow_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"prompt","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_center_stages_pkey","definition":"CREATE UNIQUE INDEX call_center_stages_pkey ON public.call_center_stages USING btree (id)"},{"name":"call_center_stages_workflow_id_stage_key_key","definition":"CREATE UNIQUE INDEX call_center_stages_workflow_id_stage_key_key ON public.call_center_stages USING btree (workflow_id, stage_key)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_stages","permissive":"PERMISSIVE","policyname":"call_center_stages_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_stages_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_stages_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"call_center_stages_workflow_id_fkey","definition":"FOREIGN KEY (workflow_id) REFERENCES call_center_workflows(id) ON DELETE CASCADE"},{"name":"call_center_stages_workflow_id_stage_key_key","definition":"UNIQUE (workflow_id, stage_key)"}]},{"table":"call_center_weekly_reports","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"report_scope","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scope_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_start","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_end","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"report_data","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"generated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_center_weekly_reports_pkey","definition":"CREATE UNIQUE INDEX call_center_weekly_reports_pkey ON public.call_center_weekly_reports USING btree (id)"},{"name":"call_center_weekly_reports_tenant_id_scope_key_period_start_key","definition":"CREATE UNIQUE INDEX call_center_weekly_reports_tenant_id_scope_key_period_start_key ON public.call_center_weekly_reports USING btree (tenant_id, scope_key, period_start, period_end)"},{"name":"call_center_weekly_reports_tenant_idx","definition":"CREATE INDEX call_center_weekly_reports_tenant_idx ON public.call_center_weekly_reports USING btree (tenant_id, period_end DESC)"}],"policies":[{"cmd":"SELECT","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_weekly_reports","permissive":"PERMISSIVE","policyname":"call_center_weekly_reports_tenant","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"call_center_weekly_reports_campaign_id_fkey","definition":"FOREIGN KEY (campaign_id) REFERENCES call_center_campaigns(id) ON DELETE CASCADE"},{"name":"call_center_weekly_reports_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_weekly_reports_report_scope_check","definition":"CHECK (report_scope = ANY (ARRAY['tenant'::text, 'campaign'::text]))"},{"name":"call_center_weekly_reports_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"call_center_weekly_reports_tenant_id_scope_key_period_start_key","definition":"UNIQUE (tenant_id, scope_key, period_start, period_end)"}]},{"table":"call_center_workflows","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":"'Guided Call Workflow'::text","identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"is_default","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_center_workflows_pkey","definition":"CREATE UNIQUE INDEX call_center_workflows_pkey ON public.call_center_workflows USING btree (id)"},{"name":"call_center_workflows_tenant_id_name_key","definition":"CREATE UNIQUE INDEX call_center_workflows_tenant_id_name_key ON public.call_center_workflows USING btree (tenant_id, name)"}],"policies":[{"cmd":"ALL","qual":"call_center_tenant_access(tenant_id)","roles":["authenticated"],"tablename":"call_center_workflows","permissive":"PERMISSIVE","policyname":"call_center_workflows_tenant","schemaname":"public","with_check":"call_center_tenant_access(tenant_id)"}],"triggers":[],"constraints":[{"name":"call_center_workflows_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_center_workflows_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"call_center_workflows_tenant_id_name_key","definition":"UNIQUE (tenant_id, name)"}]},{"table":"call_lifecycle_events","schema":"public","columns":[{"name":"id","type":"bigint","default":"nextval('call_lifecycle_events_id_seq'::regclass)","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"data","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_lifecycle_events_pkey","definition":"CREATE UNIQUE INDEX call_lifecycle_events_pkey ON public.call_lifecycle_events USING btree (id)"},{"name":"idx_cle_session","definition":"CREATE INDEX idx_cle_session ON public.call_lifecycle_events USING btree (session_id, created_at DESC)"},{"name":"idx_cle_tenant_recent","definition":"CREATE INDEX idx_cle_tenant_recent ON public.call_lifecycle_events USING btree (tenant_org_id, created_at DESC)"},{"name":"idx_cle_user_recent","definition":"CREATE INDEX idx_cle_user_recent ON public.call_lifecycle_events USING btree (user_id, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"call_lifecycle_events","permissive":"PERMISSIVE","policyname":"cle_insert_self","schemaname":"public","with_check":"((user_id IS NULL) OR (user_id = uid()))"},{"cmd":"SELECT","qual":"((user_id = uid()) OR is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), tenant_org_id)))","roles":["authenticated"],"tablename":"call_lifecycle_events","permissive":"PERMISSIVE","policyname":"cle_select_admins_or_self","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"call_lifecycle_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"call_logs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_called","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"outcome","type":"call_outcome","default":null,"identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"callback_date","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"lead_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"direction","type":"text","default":"'outbound'::text","identity":"","not_null":true,"generated":""},{"name":"twilio_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"from_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"twilio_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"disclosure_played","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"disclosure_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"disclosure_timestamp","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"compliance_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"disclosure_confirmed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"transcript","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"transcription_received_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"bridge_confirmation","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"call_logs_pkey","definition":"CREATE UNIQUE INDEX call_logs_pkey ON public.call_logs USING btree (id)"},{"name":"idx_call_logs_contact","definition":"CREATE INDEX idx_call_logs_contact ON public.call_logs USING btree (contact_id) WHERE (contact_id IS NOT NULL)"},{"name":"idx_call_logs_created_at","definition":"CREATE INDEX idx_call_logs_created_at ON public.call_logs USING btree (created_at DESC)"},{"name":"idx_call_logs_lead_id","definition":"CREATE INDEX idx_call_logs_lead_id ON public.call_logs USING btree (lead_id)"},{"name":"idx_call_logs_lead_outcome","definition":"CREATE INDEX idx_call_logs_lead_outcome ON public.call_logs USING btree (lead_id, outcome)"},{"name":"idx_call_logs_outcome","definition":"CREATE INDEX idx_call_logs_outcome ON public.call_logs USING btree (outcome)"},{"name":"idx_call_logs_phone","definition":"CREATE INDEX idx_call_logs_phone ON public.call_logs USING btree (phone_called)"},{"name":"idx_call_logs_tenant_created","definition":"CREATE INDEX idx_call_logs_tenant_created ON public.call_logs USING btree (tenant_id, created_at DESC)"},{"name":"idx_call_logs_tenant_id","definition":"CREATE INDEX idx_call_logs_tenant_id ON public.call_logs USING btree (tenant_id)"},{"name":"idx_call_logs_twilio_sid","definition":"CREATE INDEX idx_call_logs_twilio_sid ON public.call_logs USING btree (twilio_call_sid) WHERE (twilio_call_sid IS NOT NULL)"},{"name":"idx_call_logs_user_id","definition":"CREATE INDEX idx_call_logs_user_id ON public.call_logs USING btree (user_id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = call_logs.tenant_id) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))","roles":["authenticated"],"tablename":"call_logs","permissive":"PERMISSIVE","policyname":"Admins can view all tenant call logs","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"call_logs","permissive":"PERMISSIVE","policyname":"Users can insert own call logs","schemaname":"public","with_check":"((user_id = uid()) AND (tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))))"},{"cmd":"UPDATE","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"call_logs","permissive":"PERMISSIVE","policyname":"Users can update own call logs","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"SELECT","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"call_logs","permissive":"PERMISSIVE","policyname":"Users can view own call logs","schemaname":"public","with_check":null}],"triggers":[{"name":"audit_trigger_call_logs","definition":"CREATE TRIGGER audit_trigger_call_logs AFTER INSERT OR DELETE OR UPDATE ON call_logs FOR EACH ROW EXECUTE FUNCTION comprehensive_audit_trigger_fn()"},{"name":"update_call_logs_updated_at","definition":"CREATE TRIGGER update_call_logs_updated_at BEFORE UPDATE ON call_logs FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"call_logs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"call_qa_reviews","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"call_log_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"reviewer_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"sentiment","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"flagged","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"coaching_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tags","type":"text[]","default":"ARRAY[]::text[]","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_qa_reviews_pkey","definition":"CREATE UNIQUE INDEX call_qa_reviews_pkey ON public.call_qa_reviews USING btree (id)"},{"name":"idx_call_qa_call","definition":"CREATE INDEX idx_call_qa_call ON public.call_qa_reviews USING btree (call_log_id)"},{"name":"idx_call_qa_rep","definition":"CREATE INDEX idx_call_qa_rep ON public.call_qa_reviews USING btree (rep_id)"},{"name":"idx_call_qa_tenant","definition":"CREATE INDEX idx_call_qa_tenant ON public.call_qa_reviews USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"DELETE","qual":"((reviewer_id = uid()) AND is_tenant_member(uid(), tenant_id))","roles":["authenticated"],"tablename":"call_qa_reviews","permissive":"PERMISSIVE","policyname":"Tenant managers delete QA reviews","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"call_qa_reviews","permissive":"PERMISSIVE","policyname":"Tenant managers insert QA reviews","schemaname":"public","with_check":"((reviewer_id = uid()) AND is_tenant_member(uid(), tenant_id) AND (EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = call_qa_reviews.tenant_id) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))"},{"cmd":"UPDATE","qual":"((reviewer_id = uid()) AND is_tenant_member(uid(), tenant_id))","roles":["authenticated"],"tablename":"call_qa_reviews","permissive":"PERMISSIVE","policyname":"Tenant managers update QA reviews","schemaname":"public","with_check":"(reviewer_id = uid())"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) AND ((EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = call_qa_reviews.tenant_id) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))) OR (rep_id = uid())))","roles":["authenticated"],"tablename":"call_qa_reviews","permissive":"PERMISSIVE","policyname":"Tenant managers view QA reviews","schemaname":"public","with_check":null}],"triggers":[{"name":"update_call_qa_reviews_updated_at","definition":"CREATE TRIGGER update_call_qa_reviews_updated_at BEFORE UPDATE ON call_qa_reviews FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"call_qa_reviews_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_qa_reviews_score_check","definition":"CHECK (score >= 1 AND score <= 5)"},{"name":"call_qa_reviews_sentiment_check","definition":"CHECK (sentiment = ANY (ARRAY['positive'::text, 'neutral'::text, 'negative'::text]))"}]},{"table":"call_queue","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assignment_source","type":"text","default":"'admin_curated'::text","identity":"","not_null":true,"generated":""},{"name":"priority","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"last_attempt_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_attempt_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"attempt_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_queue_pkey","definition":"CREATE UNIQUE INDEX call_queue_pkey ON public.call_queue USING btree (id)"},{"name":"idx_call_queue_rep","definition":"CREATE INDEX idx_call_queue_rep ON public.call_queue USING btree (rep_id, status, priority DESC)"},{"name":"idx_call_queue_tenant","definition":"CREATE INDEX idx_call_queue_tenant ON public.call_queue USING btree (tenant_org_id)"}],"policies":[{"cmd":"DELETE","qual":"((is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())","roles":["public"],"tablename":"call_queue","permissive":"PERMISSIVE","policyname":"queue_admin_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"call_queue","permissive":"PERMISSIVE","policyname":"queue_admin_insert","schemaname":"public","with_check":"((is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())"},{"cmd":"SELECT","qual":"((rep_id = uid()) OR (is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())","roles":["public"],"tablename":"call_queue","permissive":"PERMISSIVE","policyname":"queue_rep_select_own","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((rep_id = uid()) OR (is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())","roles":["public"],"tablename":"call_queue","permissive":"PERMISSIVE","policyname":"queue_rep_update_own","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_call_queue_updated_at","definition":"CREATE TRIGGER trg_call_queue_updated_at BEFORE UPDATE ON call_queue FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"call_queue_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"call_recordings","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"active_call_session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_url","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"channels","type":"integer","default":"1","identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":"'live_call'::text","identity":"","not_null":true,"generated":""},{"name":"ai_summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ai_sentiment","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ai_topics","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"ai_action_items","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"ai_outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ai_score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"ai_status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"ai_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"analyzed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"call_recordings_pkey","definition":"CREATE UNIQUE INDEX call_recordings_pkey ON public.call_recordings USING btree (id)"},{"name":"call_recordings_recording_sid_key","definition":"CREATE UNIQUE INDEX call_recordings_recording_sid_key ON public.call_recordings USING btree (recording_sid)"},{"name":"idx_call_recordings_session","definition":"CREATE INDEX idx_call_recordings_session ON public.call_recordings USING btree (active_call_session_id)"},{"name":"idx_call_recordings_status","definition":"CREATE INDEX idx_call_recordings_status ON public.call_recordings USING btree (ai_status) WHERE (ai_status = ANY (ARRAY['pending'::text, 'processing'::text]))"},{"name":"idx_call_recordings_tenant","definition":"CREATE INDEX idx_call_recordings_tenant ON public.call_recordings USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) AND is_manager_or_higher(uid(), (tenant_org_id)::uuid))","roles":["authenticated"],"tablename":"call_recordings","permissive":"PERMISSIVE","policyname":"managers_write_call_recordings","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) AND is_manager_or_higher(uid(), (tenant_org_id)::uuid))"},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"call_recordings","permissive":"PERMISSIVE","policyname":"tenant_members_read_call_recordings","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"call_recordings_ai_score_check","definition":"CHECK (ai_score >= 0 AND ai_score <= 100 OR ai_score IS NULL)"},{"name":"call_recordings_ai_sentiment_check","definition":"CHECK ((ai_sentiment = ANY (ARRAY['positive'::text, 'neutral'::text, 'negative'::text, 'urgent'::text])) OR ai_sentiment IS NULL)"},{"name":"call_recordings_ai_status_check","definition":"CHECK (ai_status = ANY (ARRAY['pending'::text, 'processing'::text, 'complete'::text, 'failed'::text, 'skipped'::text]))"},{"name":"call_recordings_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_recordings_recording_sid_key","definition":"UNIQUE (recording_sid)"},{"name":"call_recordings_source_check","definition":"CHECK (source = ANY (ARRAY['live_call'::text, 'voicemail'::text, 'transfer'::text, 'conference'::text]))"}]},{"table":"call_scripts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenancy_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"script_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"script_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"script_content","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"prompts","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"is_template","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"derived_from_template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"adopted_admin_version","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"call_scripts_pkey","definition":"CREATE UNIQUE INDEX call_scripts_pkey ON public.call_scripts USING btree (id)"},{"name":"call_scripts_unique_per_tenant","definition":"CREATE UNIQUE INDEX call_scripts_unique_per_tenant ON public.call_scripts USING btree (tenant_org_id, tenancy_type, script_type, script_name)"},{"name":"idx_call_scripts_template","definition":"CREATE INDEX idx_call_scripts_template ON public.call_scripts USING btree (is_template, tenancy_type) WHERE (is_template = true)"},{"name":"ux_call_scripts_tenant_type_name_active","definition":"CREATE UNIQUE INDEX ux_call_scripts_tenant_type_name_active ON public.call_scripts USING btree (tenant_org_id, tenancy_type, script_name) WHERE (is_active = true)"}],"policies":[{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND (is_system_admin(uid()) OR is_tenant_owner_for(uid(), tenant_org_id)))","roles":["public"],"tablename":"call_scripts","permissive":"PERMISSIVE","policyname":"Tenant owners manage tenant scripts","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(((tenant_org_id IS NULL) AND (is_template = true)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = call_scripts.tenant_org_id)))))","roles":["public"],"tablename":"call_scripts","permissive":"PERMISSIVE","policyname":"Users view tenant scripts and templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"call_scripts","permissive":"PERMISSIVE","policyname":"call_scripts_godmode","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR is_tenant_member(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"call_scripts","permissive":"PERMISSIVE","policyname":"call_scripts_tenant_member_read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"call_scripts","permissive":"PERMISSIVE","policyname":"call_scripts_tenant_owner_manage","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))"}],"triggers":[],"constraints":[{"name":"call_scripts_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_scripts_unique_per_tenant","definition":"UNIQUE (tenant_org_id, tenancy_type, script_type, script_name)"}]},{"table":"call_summaries","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"active_call_session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"summary","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"generated_by","type":"text","default":"'post-call-summarize'::text","identity":"","not_null":true,"generated":""},{"name":"applied","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_summaries_contact_idx","definition":"CREATE INDEX call_summaries_contact_idx ON public.call_summaries USING btree (contact_id, created_at DESC)"},{"name":"call_summaries_lead_idx","definition":"CREATE INDEX call_summaries_lead_idx ON public.call_summaries USING btree (lead_id, created_at DESC)"},{"name":"call_summaries_pkey","definition":"CREATE UNIQUE INDEX call_summaries_pkey ON public.call_summaries USING btree (id)"},{"name":"call_summaries_session_uniq","definition":"CREATE UNIQUE INDEX call_summaries_session_uniq ON public.call_summaries USING btree (active_call_session_id)"},{"name":"call_summaries_tenant_idx","definition":"CREATE INDEX call_summaries_tenant_idx ON public.call_summaries USING btree (tenant_org_id, active_call_session_id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member((tenant_org_id)::text)","roles":["authenticated"],"tablename":"call_summaries","permissive":"PERMISSIVE","policyname":"tenant members read summaries","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_call_summaries_touch","definition":"CREATE TRIGGER trg_call_summaries_touch BEFORE UPDATE ON call_summaries FOR EACH ROW EXECUTE FUNCTION touch_call_summaries_updated_at()"}],"constraints":[{"name":"call_summaries_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"call_supervision_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"parent_call_sid","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"conference_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"supervisor_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"supervised_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"mode","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"supervisor_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"ended_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_supervision_sessions_pkey","definition":"CREATE UNIQUE INDEX call_supervision_sessions_pkey ON public.call_supervision_sessions USING btree (id)"},{"name":"idx_supervision_parent","definition":"CREATE INDEX idx_supervision_parent ON public.call_supervision_sessions USING btree (parent_call_sid)"},{"name":"idx_supervision_supervisor","definition":"CREATE INDEX idx_supervision_supervisor ON public.call_supervision_sessions USING btree (supervisor_user_id)"},{"name":"idx_supervision_tenant","definition":"CREATE INDEX idx_supervision_tenant ON public.call_supervision_sessions USING btree (tenant_org_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"call_supervision_sessions","permissive":"PERMISSIVE","policyname":"Managers+ can insert supervision sessions","schemaname":"public","with_check":"(is_manager_or_higher(uid(), tenant_org_id) AND (supervisor_user_id = uid()))"},{"cmd":"UPDATE","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"call_supervision_sessions","permissive":"PERMISSIVE","policyname":"Managers+ can update supervision sessions","schemaname":"public","with_check":"is_manager_or_higher(uid(), tenant_org_id)"},{"cmd":"SELECT","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"call_supervision_sessions","permissive":"PERMISSIVE","policyname":"Managers+ can view supervision sessions","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_supervision_updated","definition":"CREATE TRIGGER trg_supervision_updated BEFORE UPDATE ON call_supervision_sessions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"call_supervision_sessions_mode_check","definition":"CHECK (mode = ANY (ARRAY['monitor'::text, 'whisper'::text, 'barge'::text]))"},{"name":"call_supervision_sessions_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_supervision_sessions_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'ended'::text, 'failed'::text]))"}]},{"table":"call_transcript_segments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"active_call_session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_stream_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"twilio_stream_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"twilio_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"parent_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"track","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"speaker","type":"text","default":"'unknown'::text","identity":"","not_null":true,"generated":""},{"name":"transcript","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_final","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"confidence","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"ended_at_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"sequence_number","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_transcript_segments_pkey","definition":"CREATE UNIQUE INDEX call_transcript_segments_pkey ON public.call_transcript_segments USING btree (id)"},{"name":"idx_cts_lead_created","definition":"CREATE INDEX idx_cts_lead_created ON public.call_transcript_segments USING btree (lead_id, created_at)"},{"name":"idx_cts_stream_sid","definition":"CREATE INDEX idx_cts_stream_sid ON public.call_transcript_segments USING btree (twilio_stream_sid)"},{"name":"idx_cts_tenant_session_created","definition":"CREATE INDEX idx_cts_tenant_session_created ON public.call_transcript_segments USING btree (tenant_org_id, active_call_session_id, created_at)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"call_transcript_segments","permissive":"PERMISSIVE","policyname":"tenant members can read transcript segments","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"call_transcript_segments_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"call_transcripts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"active_call_session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"channel","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_final","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"start_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"end_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"confidence","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_transcripts_pkey","definition":"CREATE UNIQUE INDEX call_transcripts_pkey ON public.call_transcripts USING btree (id)"},{"name":"idx_call_transcripts_session","definition":"CREATE INDEX idx_call_transcripts_session ON public.call_transcripts USING btree (active_call_session_id, created_at)"},{"name":"idx_call_transcripts_tenant_lead","definition":"CREATE INDEX idx_call_transcripts_tenant_lead ON public.call_transcripts USING btree (tenant_org_id, lead_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"call_transcripts","permissive":"PERMISSIVE","policyname":"tenant_members_read_call_transcripts","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"call_transcripts_channel_check","definition":"CHECK (channel = ANY (ARRAY['rep'::text, 'homeowner'::text, 'unknown'::text]))"},{"name":"call_transcripts_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"call_transfers","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"parent_call_sid","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"conference_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"transfer_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"initiated_by_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"target_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"target_extension","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"target_external_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"target_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'initiated'::text","identity":"","not_null":true,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"call_transfers_pkey","definition":"CREATE UNIQUE INDEX call_transfers_pkey ON public.call_transfers USING btree (id)"},{"name":"idx_call_transfers_initiator","definition":"CREATE INDEX idx_call_transfers_initiator ON public.call_transfers USING btree (initiated_by_user_id)"},{"name":"idx_call_transfers_parent","definition":"CREATE INDEX idx_call_transfers_parent ON public.call_transfers USING btree (parent_call_sid)"},{"name":"idx_call_transfers_target_user","definition":"CREATE INDEX idx_call_transfers_target_user ON public.call_transfers USING btree (target_user_id)"},{"name":"idx_call_transfers_tenant","definition":"CREATE INDEX idx_call_transfers_tenant ON public.call_transfers USING btree (tenant_org_id)"}],"policies":[{"cmd":"UPDATE","qual":"((initiated_by_user_id = uid()) OR is_manager_or_higher(uid(), tenant_org_id))","roles":["authenticated"],"tablename":"call_transfers","permissive":"PERMISSIVE","policyname":"Initiator or managers+ can update transfers","schemaname":"public","with_check":"((initiated_by_user_id = uid()) OR is_manager_or_higher(uid(), tenant_org_id))"},{"cmd":"SELECT","qual":"((initiated_by_user_id = uid()) OR (target_user_id = uid()) OR is_manager_or_higher(uid(), tenant_org_id))","roles":["authenticated"],"tablename":"call_transfers","permissive":"PERMISSIVE","policyname":"Initiator or managers+ can view transfers","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"call_transfers","permissive":"PERMISSIVE","policyname":"Tenant members can insert their own transfers","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) AND ((initiated_by_user_id = uid()) OR is_manager_or_higher(uid(), tenant_org_id)))"}],"triggers":[{"name":"trg_call_transfers_updated","definition":"CREATE TRIGGER trg_call_transfers_updated BEFORE UPDATE ON call_transfers FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"call_transfers_check","definition":"CHECK (target_user_id IS NOT NULL OR target_extension IS NOT NULL OR target_external_number IS NOT NULL)"},{"name":"call_transfers_pkey","definition":"PRIMARY KEY (id)"},{"name":"call_transfers_status_check","definition":"CHECK (status = ANY (ARRAY['initiated'::text, 'ringing'::text, 'consult'::text, 'completed'::text, 'cancelled'::text, 'failed'::text, 'no_answer'::text]))"},{"name":"call_transfers_transfer_type_check","definition":"CHECK (transfer_type = ANY (ARRAY['warm'::text, 'cold'::text, 'conference'::text]))"}]},{"table":"canvasser_breadcrumbs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lat","type":"double precision","default":null,"identity":"","not_null":true,"generated":""},{"name":"lng","type":"double precision","default":null,"identity":"","not_null":true,"generated":""},{"name":"accuracy_m","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"captured_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"day_key","type":"date","default":"((now() AT TIME ZONE 'UTC'::text))::date","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"canvasser_breadcrumbs_pkey","definition":"CREATE UNIQUE INDEX canvasser_breadcrumbs_pkey ON public.canvasser_breadcrumbs USING btree (id)"},{"name":"idx_breadcrumbs_tenant_day","definition":"CREATE INDEX idx_breadcrumbs_tenant_day ON public.canvasser_breadcrumbs USING btree (tenant_org_id, day_key, captured_at)"},{"name":"idx_breadcrumbs_user_time","definition":"CREATE INDEX idx_breadcrumbs_user_time ON public.canvasser_breadcrumbs USING btree (user_id, captured_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"canvasser_breadcrumbs","permissive":"PERMISSIVE","policyname":"Reps insert own breadcrumbs","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"canvasser_breadcrumbs","permissive":"PERMISSIVE","policyname":"Reps view own breadcrumbs","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND (ur.tenant_id = canvasser_breadcrumbs.tenant_org_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))","roles":["authenticated"],"tablename":"canvasser_breadcrumbs","permissive":"PERMISSIVE","policyname":"Tenant managers view all tenant breadcrumbs","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"canvasser_breadcrumbs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"canvasser_locations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lat","type":"double precision","default":null,"identity":"","not_null":true,"generated":""},{"name":"lng","type":"double precision","default":null,"identity":"","not_null":true,"generated":""},{"name":"heading","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"accuracy","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_seen","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"canvasser_locations_pkey","definition":"CREATE UNIQUE INDEX canvasser_locations_pkey ON public.canvasser_locations USING btree (id)"},{"name":"canvasser_locations_user_id_tenant_org_id_key","definition":"CREATE UNIQUE INDEX canvasser_locations_user_id_tenant_org_id_key ON public.canvasser_locations USING btree (user_id, tenant_org_id)"},{"name":"idx_canvasser_locations_tenant","definition":"CREATE INDEX idx_canvasser_locations_tenant ON public.canvasser_locations USING btree (tenant_org_id, last_seen DESC)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = canvasser_locations.tenant_org_id) AND (utm.status = 'active'::text))))","roles":["authenticated"],"tablename":"canvasser_locations","permissive":"PERMISSIVE","policyname":"Tenant members can view team locations","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = canvasser_locations.tenant_org_id) AND (utm.status = 'active'::text)))))","roles":["authenticated"],"tablename":"canvasser_locations","permissive":"PERMISSIVE","policyname":"Users delete their own location","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"canvasser_locations","permissive":"PERMISSIVE","policyname":"Users insert their own location","schemaname":"public","with_check":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = canvasser_locations.tenant_org_id) AND (utm.status = 'active'::text)))))"},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"canvasser_locations","permissive":"PERMISSIVE","policyname":"Users update their own location","schemaname":"public","with_check":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = canvasser_locations.tenant_org_id) AND (utm.status = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"canvasser_locations_pkey","definition":"PRIMARY KEY (id)"},{"name":"canvasser_locations_user_id_tenant_org_id_key","definition":"UNIQUE (user_id, tenant_org_id)"}]},{"table":"canvassing_batch_operations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"operation_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"door_ids","type":"uuid[]","default":null,"identity":"","not_null":true,"generated":""},{"name":"parameters","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"result","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"executed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"canvassing_batch_operations_pkey","definition":"CREATE UNIQUE INDEX canvassing_batch_operations_pkey ON public.canvassing_batch_operations USING btree (id)"},{"name":"idx_batch_ops_user","definition":"CREATE INDEX idx_batch_ops_user ON public.canvassing_batch_operations USING btree (user_id, executed_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(((uid())::text = user_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"canvassing_batch_operations","permissive":"PERMISSIVE","policyname":"Users manage own batch operations","schemaname":"public","with_check":"(((uid())::text = user_id) OR is_system_admin(uid()))"}],"triggers":[],"constraints":[{"name":"canvassing_batch_operations_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"canvassing_check_ins","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"territory_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_in_time","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"expected_end_time","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"actual_end_time","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_in_location","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_heartbeat","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":false,"generated":""},{"name":"panic_triggered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"panic_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"canvassing_check_ins_pkey","definition":"CREATE UNIQUE INDEX canvassing_check_ins_pkey ON public.canvassing_check_ins USING btree (id)"},{"name":"idx_check_ins_status","definition":"CREATE INDEX idx_check_ins_status ON public.canvassing_check_ins USING btree (status)"},{"name":"idx_check_ins_tenant","definition":"CREATE INDEX idx_check_ins_tenant ON public.canvassing_check_ins USING btree (tenant_org_id)"},{"name":"idx_check_ins_user_id","definition":"CREATE INDEX idx_check_ins_user_id ON public.canvassing_check_ins USING btree (user_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"canvassing_check_ins","permissive":"PERMISSIVE","policyname":"Users insert own check-ins","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["public"],"tablename":"canvassing_check_ins","permissive":"PERMISSIVE","policyname":"Users update own check-ins","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["public"],"tablename":"canvassing_check_ins","permissive":"PERMISSIVE","policyname":"Users view own check-ins","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"canvassing_check_ins_pkey","definition":"PRIMARY KEY (id)"},{"name":"canvassing_check_ins_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'completed'::text, 'overdue'::text, 'panic'::text]))"}]},{"table":"canvassing_goals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"date","type":"date","default":"CURRENT_DATE","identity":"","not_null":true,"generated":""},{"name":"target_doors","type":"integer","default":"50","identity":"","not_null":false,"generated":""},{"name":"completed_doors","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"target_appointments","type":"integer","default":"5","identity":"","not_null":false,"generated":""},{"name":"completed_appointments","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"target_interested","type":"integer","default":"10","identity":"","not_null":false,"generated":""},{"name":"completed_interested","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"canvassing_goals_pkey","definition":"CREATE UNIQUE INDEX canvassing_goals_pkey ON public.canvassing_goals USING btree (id)"},{"name":"canvassing_goals_user_id_date_key","definition":"CREATE UNIQUE INDEX canvassing_goals_user_id_date_key ON public.canvassing_goals USING btree (user_id, date)"},{"name":"idx_goals_tenant","definition":"CREATE INDEX idx_goals_tenant ON public.canvassing_goals USING btree (tenant_org_id, date DESC)"},{"name":"idx_goals_user_date","definition":"CREATE INDEX idx_goals_user_date ON public.canvassing_goals USING btree (user_id, date DESC)"}],"policies":[{"cmd":"ALL","qual":"(((uid())::text = user_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"canvassing_goals","permissive":"PERMISSIVE","policyname":"Users manage own canvassing goals","schemaname":"public","with_check":"(((uid())::text = user_id) OR is_system_admin(uid()))"},{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"canvassing_goals","permissive":"PERMISSIVE","policyname":"cg_all","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"canvassing_goals_pkey","definition":"PRIMARY KEY (id)"},{"name":"canvassing_goals_user_id_date_key","definition":"UNIQUE (user_id, date)"}]},{"table":"canvassing_leaderboard","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"period","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_start","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_end","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"doors_knocked","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"appointments_set","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"interested_contacts","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"not_home_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"total_distance_km","type":"numeric(10,2)","default":"0","identity":"","not_null":false,"generated":""},{"name":"avg_time_per_door","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"canvassing_leaderboard_pkey","definition":"CREATE UNIQUE INDEX canvassing_leaderboard_pkey ON public.canvassing_leaderboard USING btree (id)"},{"name":"canvassing_leaderboard_user_id_period_period_start_key","definition":"CREATE UNIQUE INDEX canvassing_leaderboard_user_id_period_period_start_key ON public.canvassing_leaderboard USING btree (user_id, period, period_start)"},{"name":"idx_leaderboard_period","definition":"CREATE INDEX idx_leaderboard_period ON public.canvassing_leaderboard USING btree (tenant_org_id, period, period_start DESC)"},{"name":"idx_leaderboard_ranking","definition":"CREATE INDEX idx_leaderboard_ranking ON public.canvassing_leaderboard USING btree (tenant_org_id, period, doors_knocked DESC)"}],"policies":[{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"canvassing_leaderboard","permissive":"PERMISSIVE","policyname":"Tenant members read leaderboard","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((uid())::text = user_id)","roles":["public"],"tablename":"canvassing_leaderboard","permissive":"PERMISSIVE","policyname":"canvassing_leaderboard_update_policy","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"canvassing_leaderboard","permissive":"PERMISSIVE","policyname":"canvassing_leaderboard_write_policy","schemaname":"public","with_check":"((uid())::text = user_id)"},{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"canvassing_leaderboard","permissive":"PERMISSIVE","policyname":"clb_all","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"canvassing_leaderboard_pkey","definition":"PRIMARY KEY (id)"},{"name":"canvassing_leaderboard_user_id_period_period_start_key","definition":"UNIQUE (user_id, period, period_start)"}]},{"table":"canvassing_live_locations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lat","type":"double precision","default":null,"identity":"","not_null":true,"generated":""},{"name":"lng","type":"double precision","default":null,"identity":"","not_null":true,"generated":""},{"name":"current_door_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":false,"generated":""},{"name":"route_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"canvassing_live_locations_pkey","definition":"CREATE UNIQUE INDEX canvassing_live_locations_pkey ON public.canvassing_live_locations USING btree (id)"},{"name":"canvassing_live_locations_user_id_tenant_org_id_key","definition":"CREATE UNIQUE INDEX canvassing_live_locations_user_id_tenant_org_id_key ON public.canvassing_live_locations USING btree (user_id, tenant_org_id)"},{"name":"idx_live_locations_tenant","definition":"CREATE INDEX idx_live_locations_tenant ON public.canvassing_live_locations USING btree (tenant_org_id, updated_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"((tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE (utm.user_id = uid()))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"canvassing_live_locations","permissive":"PERMISSIVE","policyname":"Tenant members view live locations","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((user_id = (uid())::text) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"canvassing_live_locations","permissive":"PERMISSIVE","policyname":"Users delete their own location","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"canvassing_live_locations","permissive":"PERMISSIVE","policyname":"Users insert their own location","schemaname":"public","with_check":"((user_id = (uid())::text) AND (tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE (utm.user_id = uid()))))"},{"cmd":"UPDATE","qual":"(user_id = (uid())::text)","roles":["authenticated"],"tablename":"canvassing_live_locations","permissive":"PERMISSIVE","policyname":"Users update their own location","schemaname":"public","with_check":"(user_id = (uid())::text)"}],"triggers":[],"constraints":[{"name":"canvassing_live_locations_pkey","definition":"PRIMARY KEY (id)"},{"name":"canvassing_live_locations_user_id_tenant_org_id_key","definition":"UNIQUE (user_id, tenant_org_id)"}]},{"table":"canvassing_recontacts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"door_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_to","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scheduled_for","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"priority","type":"integer","default":"1","identity":"","not_null":false,"generated":""},{"name":"completed","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"text","default":null,"identity":"","not_null":true,"generated":""}],"indexes":[{"name":"canvassing_recontacts_pkey","definition":"CREATE UNIQUE INDEX canvassing_recontacts_pkey ON public.canvassing_recontacts USING btree (id)"},{"name":"idx_recontacts_door","definition":"CREATE INDEX idx_recontacts_door ON public.canvassing_recontacts USING btree (door_id)"},{"name":"idx_recontacts_priority","definition":"CREATE INDEX idx_recontacts_priority ON public.canvassing_recontacts USING btree (tenant_org_id, priority DESC, scheduled_for)"},{"name":"idx_recontacts_scheduled","definition":"CREATE INDEX idx_recontacts_scheduled ON public.canvassing_recontacts USING btree (assigned_to, scheduled_for, completed)"}],"policies":[{"cmd":"ALL","qual":"(((uid())::text = assigned_to) OR ((uid())::text = created_by) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"canvassing_recontacts","permissive":"PERMISSIVE","policyname":"Tenant members manage recontacts","schemaname":"public","with_check":"(((uid())::text = assigned_to) OR ((uid())::text = created_by) OR is_system_admin(uid()))"}],"triggers":[],"constraints":[{"name":"canvassing_recontacts_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"canvassing_routes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"territory_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"door_ids","type":"uuid[]","default":null,"identity":"","not_null":true,"generated":""},{"name":"optimized_order","type":"integer[]","default":null,"identity":"","not_null":true,"generated":""},{"name":"total_distance_meters","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"estimated_time_minutes","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"canvassing_routes_pkey","definition":"CREATE UNIQUE INDEX canvassing_routes_pkey ON public.canvassing_routes USING btree (id)"},{"name":"idx_routes_status","definition":"CREATE INDEX idx_routes_status ON public.canvassing_routes USING btree (status, user_id)"},{"name":"idx_routes_territory","definition":"CREATE INDEX idx_routes_territory ON public.canvassing_routes USING btree (territory_id)"},{"name":"idx_routes_user","definition":"CREATE INDEX idx_routes_user ON public.canvassing_routes USING btree (user_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(((uid())::text = user_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"canvassing_routes","permissive":"PERMISSIVE","policyname":"Users manage own canvassing routes","schemaname":"public","with_check":"(((uid())::text = user_id) OR is_system_admin(uid()))"},{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"canvassing_routes","permissive":"PERMISSIVE","policyname":"cr_all","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"canvassing_routes_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"canvassing_safe_zones","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"polygon_geojson","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"zone_type","type":"text","default":"'safe'::text","identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"canvassing_safe_zones_pkey","definition":"CREATE UNIQUE INDEX canvassing_safe_zones_pkey ON public.canvassing_safe_zones USING btree (id)"},{"name":"idx_safe_zones_tenant","definition":"CREATE INDEX idx_safe_zones_tenant ON public.canvassing_safe_zones USING btree (tenant_org_id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = canvassing_safe_zones.tenant_org_id))))","roles":["public"],"tablename":"canvassing_safe_zones","permissive":"PERMISSIVE","policyname":"Tenant members view safe zones","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"canvassing_safe_zones_pkey","definition":"PRIMARY KEY (id)"},{"name":"canvassing_safe_zones_zone_type_check","definition":"CHECK (zone_type = ANY (ARRAY['safe'::text, 'restricted'::text, 'avoid'::text]))"}]},{"table":"capability_delegation_leases","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"capability","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"adapter_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"principal_key","type":"text","default":"'command_center'::text","identity":"","not_null":true,"generated":""},{"name":"delegated_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"capability_delegation_leases_expiry_idx","definition":"CREATE INDEX capability_delegation_leases_expiry_idx ON public.capability_delegation_leases USING btree (expires_at)"},{"name":"capability_delegation_leases_pkey","definition":"CREATE UNIQUE INDEX capability_delegation_leases_pkey ON public.capability_delegation_leases USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"capability_delegation_leases_adapter_key_check","definition":"CHECK (length(TRIM(BOTH FROM adapter_key)) > 0)"},{"name":"capability_delegation_leases_capability_check","definition":"CHECK (capability ~ '^[a-z][a-z0-9_]*\\.[a-z][a-z0-9_]*$'::text)"},{"name":"capability_delegation_leases_pkey","definition":"PRIMARY KEY (id)"},{"name":"capability_delegation_leases_principal_key_check","definition":"CHECK (principal_key = 'command_center'::text)"}]},{"table":"capability_execution_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"capability","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adapter_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"capability_execution_audit_pkey","definition":"CREATE UNIQUE INDEX capability_execution_audit_pkey ON public.capability_execution_audit USING btree (id)"},{"name":"capability_execution_audit_tenant_created_idx","definition":"CREATE INDEX capability_execution_audit_tenant_created_idx ON public.capability_execution_audit USING btree (tenant_id, created_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"capability_execution_audit_actor_type_check","definition":"CHECK (actor_type = ANY (ARRAY['user'::text, 'command_center'::text]))"},{"name":"capability_execution_audit_pkey","definition":"PRIMARY KEY (id)"},{"name":"capability_execution_audit_status_check","definition":"CHECK (status = ANY (ARRAY['started'::text, 'succeeded'::text, 'blocked'::text, 'failed'::text]))"}]},{"table":"card_grading_cards","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"submission_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"cert_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sequence_number","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"year","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"brand_set","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"player_character","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"card_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"variation","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"declared_value","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"grade","type":"numeric(4,1)","default":null,"identity":"","not_null":false,"generated":""},{"name":"grade_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'received'::text","identity":"","not_null":true,"generated":""},{"name":"front_image_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"back_image_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"slab_image_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"grader_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"population_count","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"import_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"is_demo","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"card_description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"autograph_present","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"manufacturer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"set_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"subset","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"serial_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"relic_present","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"identified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"identified_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"finalized_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"slab_back_image_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pcg_submission_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pcg_submission_year","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"publish_to_website","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"publish_to_ebay","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"sale_price","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"publish_intent_updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"internal_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"front_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"back_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"deletion_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"restored_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"restored_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"restore_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"card_grading_cards_active_tenant_idx","definition":"CREATE INDEX card_grading_cards_active_tenant_idx ON public.card_grading_cards USING btree (tenant_id, created_at DESC) WHERE (deleted_at IS NULL)"},{"name":"card_grading_cards_cert_number_unique","definition":"CREATE UNIQUE INDEX card_grading_cards_cert_number_unique ON public.card_grading_cards USING btree (cert_number) WHERE (cert_number IS NOT NULL)"},{"name":"card_grading_cards_deleted_tenant_idx","definition":"CREATE INDEX card_grading_cards_deleted_tenant_idx ON public.card_grading_cards USING btree (tenant_id, deleted_at DESC) WHERE (deleted_at IS NOT NULL)"},{"name":"card_grading_cards_pcg_submission_number_unique","definition":"CREATE UNIQUE INDEX card_grading_cards_pcg_submission_number_unique ON public.card_grading_cards USING btree (tenant_id, pcg_submission_number) WHERE (pcg_submission_number IS NOT NULL)"},{"name":"card_grading_cards_pkey","definition":"CREATE UNIQUE INDEX card_grading_cards_pkey ON public.card_grading_cards USING btree (id)"},{"name":"card_grading_cards_publish_intent_idx","definition":"CREATE INDEX card_grading_cards_publish_intent_idx ON public.card_grading_cards USING btree (tenant_id, publish_to_website, publish_to_ebay, status)"},{"name":"card_grading_cards_tenant_id_cert_number_key","definition":"CREATE UNIQUE INDEX card_grading_cards_tenant_id_cert_number_key ON public.card_grading_cards USING btree (tenant_id, cert_number)"},{"name":"card_grading_cards_tenant_identity_uidx","definition":"CREATE UNIQUE INDEX card_grading_cards_tenant_identity_uidx ON public.card_grading_cards USING btree (tenant_id, id)"},{"name":"card_grading_cards_tenant_import_key_uidx","definition":"CREATE UNIQUE INDEX card_grading_cards_tenant_import_key_uidx ON public.card_grading_cards USING btree (tenant_id, import_key)"},{"name":"idx_card_grading_cards_cert","definition":"CREATE INDEX idx_card_grading_cards_cert ON public.card_grading_cards USING btree (tenant_id, cert_number)"},{"name":"idx_card_grading_cards_submission","definition":"CREATE INDEX idx_card_grading_cards_submission ON public.card_grading_cards USING btree (submission_id)"},{"name":"idx_card_grading_cards_tenant_created_at","definition":"CREATE INDEX idx_card_grading_cards_tenant_created_at ON public.card_grading_cards USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(( SELECT is_system_admin(( SELECT uid() AS uid)) AS is_system_admin) OR (tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))))","roles":["public"],"tablename":"card_grading_cards","permissive":"PERMISSIVE","policyname":"card_grading_cards_tenant_all","schemaname":"public","with_check":"(( SELECT is_system_admin(( SELECT uid() AS uid)) AS is_system_admin) OR (tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))))"}],"triggers":[{"name":"card_grading_cards_finalized_immutable","definition":"CREATE TRIGGER card_grading_cards_finalized_immutable BEFORE UPDATE ON card_grading_cards FOR EACH ROW EXECUTE FUNCTION card_grading_protect_finalized_card()"},{"name":"card_grading_cards_status_audit","definition":"CREATE TRIGGER card_grading_cards_status_audit AFTER UPDATE OF status ON card_grading_cards FOR EACH ROW EXECUTE FUNCTION card_grading_audit_status_change()"},{"name":"pcg_cert_cross_format_registration","definition":"CREATE TRIGGER pcg_cert_cross_format_registration BEFORE INSERT OR UPDATE OF cert_number ON card_grading_cards FOR EACH ROW EXECUTE FUNCTION pcg_guard_cert_registration()"},{"name":"pcg_revoke_deleted_card_publications","definition":"CREATE TRIGGER pcg_revoke_deleted_card_publications AFTER UPDATE OF deleted_at ON card_grading_cards FOR EACH ROW EXECUTE FUNCTION pcg_revoke_deleted_card_publications()"},{"name":"trg_pcg_default_publish_destination","definition":"CREATE TRIGGER trg_pcg_default_publish_destination BEFORE INSERT ON card_grading_cards FOR EACH ROW EXECUTE FUNCTION pcg_default_publish_destination()"},{"name":"trg_pcg_internal_inventory_defaults","definition":"CREATE TRIGGER trg_pcg_internal_inventory_defaults BEFORE INSERT OR UPDATE OF submission_id ON card_grading_cards FOR EACH ROW EXECUTE FUNCTION apply_pcg_internal_inventory_defaults()"},{"name":"trg_pcg_mark_external_withdrawal_pending","definition":"CREATE TRIGGER trg_pcg_mark_external_withdrawal_pending AFTER UPDATE OF deleted_at ON card_grading_cards FOR EACH ROW EXECUTE FUNCTION pcg_mark_external_withdrawal_pending()"},{"name":"trg_pcg_submission_stage_from_cards","definition":"CREATE TRIGGER trg_pcg_submission_stage_from_cards AFTER INSERT OR DELETE OR UPDATE OF status ON card_grading_cards FOR EACH ROW EXECUTE FUNCTION sync_pcg_submission_stage_from_cards()"}],"constraints":[{"name":"card_grading_cards_pkey","definition":"PRIMARY KEY (id)"},{"name":"card_grading_cards_sale_price_nonnegative","definition":"CHECK (sale_price IS NULL OR sale_price >= 0::numeric)"},{"name":"card_grading_cards_status_check","definition":"CHECK (status = ANY (ARRAY['received'::text, 'intake_imaging'::text, 'authentication'::text, 'grading'::text, 'encapsulation'::text, 'qa'::text, 'ready'::text, 'shipped'::text, 'picked_up'::text]))"},{"name":"card_grading_cards_submission_id_fkey","definition":"FOREIGN KEY (submission_id) REFERENCES card_grading_submissions(id) ON DELETE CASCADE"},{"name":"card_grading_cards_tenant_id_cert_number_key","definition":"UNIQUE (tenant_id, cert_number)"},{"name":"card_grading_cards_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"card_grading_cert_prefix_assignments","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"grader_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"grader_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"grader_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"cert_prefix","type":"smallint","default":null,"identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"card_grading_cert_prefix_assignments_pkey","definition":"CREATE UNIQUE INDEX card_grading_cert_prefix_assignments_pkey ON public.card_grading_cert_prefix_assignments USING btree (tenant_id, grader_key)"},{"name":"card_grading_cert_prefix_assignments_tenant_id_cert_prefix_key","definition":"CREATE UNIQUE INDEX card_grading_cert_prefix_assignments_tenant_id_cert_prefix_key ON public.card_grading_cert_prefix_assignments USING btree (tenant_id, cert_prefix)"},{"name":"card_grading_cert_prefix_assignments_user_uidx","definition":"CREATE UNIQUE INDEX card_grading_cert_prefix_assignments_user_uidx ON public.card_grading_cert_prefix_assignments USING btree (tenant_id, grader_user_id) WHERE (grader_user_id IS NOT NULL)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = card_grading_cert_prefix_assignments.tenant_id) AND (m.status = 'active'::text) AND (m.is_owner = true)))))","roles":["authenticated"],"tablename":"card_grading_cert_prefix_assignments","permissive":"PERMISSIVE","policyname":"PCG cert prefixes managed by tenant owners","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = card_grading_cert_prefix_assignments.tenant_id) AND (m.status = 'active'::text) AND (m.is_owner = true)))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = card_grading_cert_prefix_assignments.tenant_id) AND (m.status = 'active'::text)))))","roles":["authenticated"],"tablename":"card_grading_cert_prefix_assignments","permissive":"PERMISSIVE","policyname":"PCG cert prefixes visible to tenant members","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"card_grading_cert_prefix_assignments_cert_prefix_check","definition":"CHECK (cert_prefix = ANY (ARRAY[7, 8, 9]))"},{"name":"card_grading_cert_prefix_assignments_pkey","definition":"PRIMARY KEY (tenant_id, grader_key)"},{"name":"card_grading_cert_prefix_assignments_tenant_id_cert_prefix_key","definition":"UNIQUE (tenant_id, cert_prefix)"}]},{"table":"card_grading_certificates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"cert_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"year","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"manufacturer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"set_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"brand_set","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"subset","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"player_character","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"card_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"variation","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"serial_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"autograph_present","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"relic_present","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"final_grade","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"grade_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"final_image_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"finalized_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"published_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"card_grading_certificates_card_id_key","definition":"CREATE UNIQUE INDEX card_grading_certificates_card_id_key ON public.card_grading_certificates USING btree (card_id)"},{"name":"card_grading_certificates_lookup_idx","definition":"CREATE INDEX card_grading_certificates_lookup_idx ON public.card_grading_certificates USING btree (cert_number) WHERE (published_at IS NOT NULL)"},{"name":"card_grading_certificates_pkey","definition":"CREATE UNIQUE INDEX card_grading_certificates_pkey ON public.card_grading_certificates USING btree (id)"},{"name":"card_grading_certificates_tenant_id_cert_number_key","definition":"CREATE UNIQUE INDEX card_grading_certificates_tenant_id_cert_number_key ON public.card_grading_certificates USING btree (tenant_id, cert_number)"}],"policies":[{"cmd":"SELECT","qual":"((published_at IS NOT NULL) AND ((tenant_id IS DISTINCT FROM '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid) OR (cert_number ~ '^[0-9]{5}$'::text)))","roles":["anon"],"tablename":"card_grading_certificates","permissive":"PERMISSIVE","policyname":"card_grading_certificates_public_select","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_certificates.tenant_id)))) OR ((published_at IS NOT NULL) AND ((tenant_id IS DISTINCT FROM '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid) OR (cert_number ~ '^[0-9]{5}$'::text))))","roles":["authenticated"],"tablename":"card_grading_certificates","permissive":"PERMISSIVE","policyname":"card_grading_certificates_staff_select","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"card_grading_certificates","permissive":"PERMISSIVE","policyname":"card_grading_certificates_tenant_insert","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_certificates.tenant_id)))))"},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_certificates.tenant_id)))))","roles":["authenticated"],"tablename":"card_grading_certificates","permissive":"PERMISSIVE","policyname":"card_grading_certificates_tenant_update","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_certificates.tenant_id)))))"}],"triggers":[{"name":"card_grading_certificates_immutable","definition":"CREATE TRIGGER card_grading_certificates_immutable BEFORE UPDATE ON card_grading_certificates FOR EACH ROW EXECUTE FUNCTION card_grading_protect_published_certificate()"},{"name":"pcg_certificate_registry_format_guard","definition":"CREATE TRIGGER pcg_certificate_registry_format_guard BEFORE INSERT OR UPDATE OF cert_number ON card_grading_certificates FOR EACH ROW EXECUTE FUNCTION pcg_guard_certificate_registry_format()"}],"constraints":[{"name":"card_grading_certificates_card_id_fkey","definition":"FOREIGN KEY (card_id) REFERENCES card_grading_cards(id) ON DELETE CASCADE"},{"name":"card_grading_certificates_card_id_key","definition":"UNIQUE (card_id)"},{"name":"card_grading_certificates_pkey","definition":"PRIMARY KEY (id)"},{"name":"card_grading_certificates_tenant_id_cert_number_key","definition":"UNIQUE (tenant_id, cert_number)"},{"name":"card_grading_certificates_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"card_grading_criterion_results","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"criterion_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"score","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"card_grading_criterion_results_pkey","definition":"CREATE UNIQUE INDEX card_grading_criterion_results_pkey ON public.card_grading_criterion_results USING btree (id)"},{"name":"card_grading_criterion_results_session_id_criterion_key_key","definition":"CREATE UNIQUE INDEX card_grading_criterion_results_session_id_criterion_key_key ON public.card_grading_criterion_results USING btree (session_id, criterion_key)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_criterion_results.tenant_id)))))","roles":["authenticated"],"tablename":"card_grading_criterion_results","permissive":"PERMISSIVE","policyname":"card_grading_criterion_results_tenant_all","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_criterion_results.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"card_grading_criterion_results_pkey","definition":"PRIMARY KEY (id)"},{"name":"card_grading_criterion_results_session_id_criterion_key_key","definition":"UNIQUE (session_id, criterion_key)"},{"name":"card_grading_criterion_results_session_id_fkey","definition":"FOREIGN KEY (session_id) REFERENCES card_grading_grading_sessions(id) ON DELETE CASCADE"},{"name":"card_grading_criterion_results_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"card_grading_exceptions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"submission_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'open'::text","identity":"","not_null":true,"generated":""},{"name":"opened_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"opened_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"resolved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolution","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"card_grading_exceptions_open_idx","definition":"CREATE INDEX card_grading_exceptions_open_idx ON public.card_grading_exceptions USING btree (tenant_id, status, opened_at DESC)"},{"name":"card_grading_exceptions_pkey","definition":"CREATE UNIQUE INDEX card_grading_exceptions_pkey ON public.card_grading_exceptions USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_exceptions.tenant_id)))))","roles":["authenticated"],"tablename":"card_grading_exceptions","permissive":"PERMISSIVE","policyname":"card_grading_exceptions_tenant_all","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_exceptions.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"card_grading_exceptions_card_id_fkey","definition":"FOREIGN KEY (card_id) REFERENCES card_grading_cards(id) ON DELETE CASCADE"},{"name":"card_grading_exceptions_kind_check","definition":"CHECK (kind = ANY (ARRAY['hold'::text, 'rework'::text, 'escalation'::text]))"},{"name":"card_grading_exceptions_pkey","definition":"PRIMARY KEY (id)"},{"name":"card_grading_exceptions_status_check","definition":"CHECK (status = ANY (ARRAY['open'::text, 'resolved'::text]))"},{"name":"card_grading_exceptions_submission_id_fkey","definition":"FOREIGN KEY (submission_id) REFERENCES card_grading_submissions(id) ON DELETE CASCADE"},{"name":"card_grading_exceptions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"card_grading_external_population","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"year","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"brand_set","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"player_character","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"card_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"variation","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"grade","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"grade_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"population","type":"bigint","default":"0","identity":"","not_null":true,"generated":""},{"name":"population_higher","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"total_population","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"observed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"match_confidence","type":"numeric","default":"1","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"card_grading_external_population_identity_uq","definition":"CREATE UNIQUE INDEX card_grading_external_population_identity_uq ON public.card_grading_external_population USING btree (tenant_id, provider_key, COALESCE(year, ''::text), COALESCE(brand_set, ''::text), COALESCE(player_character, ''::text), COALESCE(card_number, ''::text), COALESCE(variation, ''::text), COALESCE(grade, ('-1'::integer)::numeric))"},{"name":"card_grading_external_population_lookup_idx","definition":"CREATE INDEX card_grading_external_population_lookup_idx ON public.card_grading_external_population USING btree (tenant_id, player_character, brand_set, year, card_number, variation)"},{"name":"card_grading_external_population_pkey","definition":"CREATE UNIQUE INDEX card_grading_external_population_pkey ON public.card_grading_external_population USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"card_grading_external_population_match_confidence_check","definition":"CHECK (match_confidence >= 0::numeric AND match_confidence <= 1::numeric)"},{"name":"card_grading_external_population_pkey","definition":"PRIMARY KEY (id)"},{"name":"card_grading_external_population_population_check","definition":"CHECK (population >= 0)"},{"name":"card_grading_external_population_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"card_grading_grading_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"grader_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"overall_grade","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"grade_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"submitted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"card_grading_grading_sessions_card_idx","definition":"CREATE INDEX card_grading_grading_sessions_card_idx ON public.card_grading_grading_sessions USING btree (card_id, created_at DESC)"},{"name":"card_grading_grading_sessions_pkey","definition":"CREATE UNIQUE INDEX card_grading_grading_sessions_pkey ON public.card_grading_grading_sessions USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_grading_sessions.tenant_id)))))","roles":["authenticated"],"tablename":"card_grading_grading_sessions","permissive":"PERMISSIVE","policyname":"card_grading_grading_sessions_tenant_all","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_grading_sessions.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"card_grading_grading_sessions_card_id_fkey","definition":"FOREIGN KEY (card_id) REFERENCES card_grading_cards(id) ON DELETE CASCADE"},{"name":"card_grading_grading_sessions_pkey","definition":"PRIMARY KEY (id)"},{"name":"card_grading_grading_sessions_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'submitted'::text, 'superseded'::text]))"},{"name":"card_grading_grading_sessions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"card_grading_media","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":"'knocklaunch'::text","identity":"","not_null":true,"generated":""},{"name":"provider_file_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_revision_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"delivery_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mime_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"width","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"height","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"bytes","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"checksum","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_current","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"is_public","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"superseded_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"card_grading_media_card_idx","definition":"CREATE INDEX card_grading_media_card_idx ON public.card_grading_media USING btree (card_id, kind, created_at DESC)"},{"name":"card_grading_media_one_current_kind_idx","definition":"CREATE UNIQUE INDEX card_grading_media_one_current_kind_idx ON public.card_grading_media USING btree (card_id, kind) WHERE is_current"},{"name":"card_grading_media_pkey","definition":"CREATE UNIQUE INDEX card_grading_media_pkey ON public.card_grading_media USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_media.tenant_id)))))","roles":["authenticated"],"tablename":"card_grading_media","permissive":"PERMISSIVE","policyname":"card_grading_media_tenant_all","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_media.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"card_grading_media_card_id_fkey","definition":"FOREIGN KEY (card_id) REFERENCES card_grading_cards(id) ON DELETE CASCADE"},{"name":"card_grading_media_kind_check","definition":"CHECK (kind = ANY (ARRAY['front'::text, 'back'::text, 'detail'::text, 'defect'::text, 'label'::text, 'final'::text]))"},{"name":"card_grading_media_pkey","definition":"PRIMARY KEY (id)"},{"name":"card_grading_media_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"card_grading_qc_reviews","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"grading_session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewer_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"card_grading_qc_reviews_card_idx","definition":"CREATE INDEX card_grading_qc_reviews_card_idx ON public.card_grading_qc_reviews USING btree (card_id, reviewed_at DESC)"},{"name":"card_grading_qc_reviews_pkey","definition":"CREATE UNIQUE INDEX card_grading_qc_reviews_pkey ON public.card_grading_qc_reviews USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_qc_reviews.tenant_id)))))","roles":["authenticated"],"tablename":"card_grading_qc_reviews","permissive":"PERMISSIVE","policyname":"card_grading_qc_reviews_tenant_all","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_qc_reviews.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"card_grading_qc_reviews_card_id_fkey","definition":"FOREIGN KEY (card_id) REFERENCES card_grading_cards(id) ON DELETE CASCADE"},{"name":"card_grading_qc_reviews_grading_session_id_fkey","definition":"FOREIGN KEY (grading_session_id) REFERENCES card_grading_grading_sessions(id) ON DELETE SET NULL"},{"name":"card_grading_qc_reviews_outcome_check","definition":"CHECK (outcome = ANY (ARRAY['approved'::text, 'regrade'::text, 'rework'::text, 'discrepancy'::text]))"},{"name":"card_grading_qc_reviews_pkey","definition":"PRIMARY KEY (id)"},{"name":"card_grading_qc_reviews_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"card_grading_submissions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"submission_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"customer_contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_tier","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"service_price","type":"numeric(10,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'received'::text","identity":"","not_null":true,"generated":""},{"name":"delivery_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tracking_in","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tracking_out","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"received_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"payment_status","type":"text","default":"'unverified'::text","identity":"","not_null":true,"generated":""},{"name":"payment_reference","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"paid_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_demo","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"expected_card_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"return_shipping_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"return_shipping_cost","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"return_insurance_amount","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"wmp_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"wmp_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"wmp_created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"shipping_carrier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"shipping_service","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"shipping_label_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"shipping_label_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"shipping_tracking_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"shipping_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"shipped_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"delivered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"picked_up_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"lifecycle_state","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"cancelled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"cancelled_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"cancellation_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"deletion_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_last_synced_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_checkout_session_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_payment_intent_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_charge_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_amount_total_cents","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_amount_paid_cents","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_amount_refunded_cents","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_currency","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_dispute_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_receipt_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"intake_request_key","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"card_grading_submissions_pkey","definition":"CREATE UNIQUE INDEX card_grading_submissions_pkey ON public.card_grading_submissions USING btree (id)"},{"name":"card_grading_submissions_stripe_payment_intent_idx","definition":"CREATE INDEX card_grading_submissions_stripe_payment_intent_idx ON public.card_grading_submissions USING btree (tenant_id, stripe_payment_intent_id) WHERE (stripe_payment_intent_id IS NOT NULL)"},{"name":"card_grading_submissions_stripe_session_idx","definition":"CREATE INDEX card_grading_submissions_stripe_session_idx ON public.card_grading_submissions USING btree (tenant_id, stripe_checkout_session_id) WHERE (stripe_checkout_session_id IS NOT NULL)"},{"name":"card_grading_submissions_tenant_id_submission_number_key","definition":"CREATE UNIQUE INDEX card_grading_submissions_tenant_id_submission_number_key ON public.card_grading_submissions USING btree (tenant_id, submission_number)"},{"name":"card_grading_submissions_tenant_identity_uidx","definition":"CREATE UNIQUE INDEX card_grading_submissions_tenant_identity_uidx ON public.card_grading_submissions USING btree (tenant_id, id)"},{"name":"card_grading_submissions_tenant_intake_request_key_uidx","definition":"CREATE UNIQUE INDEX card_grading_submissions_tenant_intake_request_key_uidx ON public.card_grading_submissions USING btree (tenant_id, intake_request_key) WHERE (intake_request_key IS NOT NULL)"},{"name":"card_grading_submissions_tenant_wmp_number_uidx","definition":"CREATE UNIQUE INDEX card_grading_submissions_tenant_wmp_number_uidx ON public.card_grading_submissions USING btree (tenant_id, wmp_number) WHERE (wmp_number IS NOT NULL)"},{"name":"card_grading_submissions_wmp_token_uidx","definition":"CREATE UNIQUE INDEX card_grading_submissions_wmp_token_uidx ON public.card_grading_submissions USING btree (wmp_token) WHERE (wmp_token IS NOT NULL)"},{"name":"idx_card_grading_submissions_due","definition":"CREATE INDEX idx_card_grading_submissions_due ON public.card_grading_submissions USING btree (tenant_id, due_at)"},{"name":"idx_card_grading_submissions_tenant_payment","definition":"CREATE INDEX idx_card_grading_submissions_tenant_payment ON public.card_grading_submissions USING btree (tenant_id, payment_status)"},{"name":"idx_card_grading_submissions_tenant_status","definition":"CREATE INDEX idx_card_grading_submissions_tenant_status ON public.card_grading_submissions USING btree (tenant_id, status)"}],"policies":[{"cmd":"ALL","qual":"(( SELECT is_system_admin(( SELECT uid() AS uid)) AS is_system_admin) OR (tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))))","roles":["public"],"tablename":"card_grading_submissions","permissive":"PERMISSIVE","policyname":"card_grading_submissions_tenant_all","schemaname":"public","with_check":"(( SELECT is_system_admin(( SELECT uid() AS uid)) AS is_system_admin) OR (tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))))"}],"triggers":[{"name":"card_grading_submissions_status_audit","definition":"CREATE TRIGGER card_grading_submissions_status_audit AFTER UPDATE OF status ON card_grading_submissions FOR EACH ROW EXECUTE FUNCTION card_grading_audit_status_change()"},{"name":"trg_card_grading_submissions_wmp_identity","definition":"CREATE TRIGGER trg_card_grading_submissions_wmp_identity BEFORE INSERT OR UPDATE OF submission_number, status, wmp_number, wmp_token ON card_grading_submissions FOR EACH ROW EXECUTE FUNCTION ensure_pcg_submission_wmp_identity()"}],"constraints":[{"name":"card_grading_submissions_customer_contact_id_fkey","definition":"FOREIGN KEY (customer_contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"card_grading_submissions_delivery_method_check","definition":"CHECK (delivery_method = ANY (ARRAY['walk_in'::text, 'mail_in'::text, 'ship_back'::text, 'pickup'::text]))"},{"name":"card_grading_submissions_expected_card_count_check","definition":"CHECK (expected_card_count >= 0 AND expected_card_count <= 100000)"},{"name":"card_grading_submissions_lifecycle_state_check","definition":"CHECK (lifecycle_state = ANY (ARRAY['active'::text, 'cancelled'::text]))"},{"name":"card_grading_submissions_payment_status_check","definition":"CHECK (payment_status = ANY (ARRAY['unverified'::text, 'manually_verified'::text, 'waived'::text, 'refunded'::text]))"},{"name":"card_grading_submissions_pkey","definition":"PRIMARY KEY (id)"},{"name":"card_grading_submissions_return_insurance_amount_check","definition":"CHECK (return_insurance_amount IS NULL OR return_insurance_amount >= 0::numeric)"},{"name":"card_grading_submissions_return_shipping_cost_check","definition":"CHECK (return_shipping_cost IS NULL OR return_shipping_cost >= 0::numeric)"},{"name":"card_grading_submissions_return_shipping_method_check","definition":"CHECK (return_shipping_method IS NULL OR (return_shipping_method = ANY (ARRAY['fedex_2_day'::text, 'fedex_saver'::text, 'pickup'::text, 'usps'::text])))"},{"name":"card_grading_submissions_service_price_check","definition":"CHECK (service_price >= 0::numeric)"},{"name":"card_grading_submissions_service_tier_check","definition":"CHECK (service_tier = ANY (ARRAY['two_weeks'::text, 'one_week'::text, 'three_days'::text, 'same_day'::text, 'inventory'::text]))"},{"name":"card_grading_submissions_status_check","definition":"CHECK (status = ANY (ARRAY['received'::text, 'intake_imaging'::text, 'authentication'::text, 'grading'::text, 'encapsulation'::text, 'qa'::text, 'ready'::text, 'shipped'::text, 'picked_up'::text]))"},{"name":"card_grading_submissions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"card_grading_submissions_tenant_id_submission_number_key","definition":"UNIQUE (tenant_id, submission_number)"}]},{"table":"card_grading_workflow_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"submission_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"card_grading_workflow_events_card_idx","definition":"CREATE INDEX card_grading_workflow_events_card_idx ON public.card_grading_workflow_events USING btree (card_id, occurred_at DESC)"},{"name":"card_grading_workflow_events_pkey","definition":"CREATE UNIQUE INDEX card_grading_workflow_events_pkey ON public.card_grading_workflow_events USING btree (id)"},{"name":"card_grading_workflow_events_submission_idx","definition":"CREATE INDEX card_grading_workflow_events_submission_idx ON public.card_grading_workflow_events USING btree (submission_id, occurred_at DESC)"},{"name":"card_grading_workflow_events_tenant_time_idx","definition":"CREATE INDEX card_grading_workflow_events_tenant_time_idx ON public.card_grading_workflow_events USING btree (tenant_id, occurred_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"card_grading_workflow_events","permissive":"PERMISSIVE","policyname":"card_grading_workflow_events_tenant_insert","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_workflow_events.tenant_id)))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = card_grading_workflow_events.tenant_id)))))","roles":["authenticated"],"tablename":"card_grading_workflow_events","permissive":"PERMISSIVE","policyname":"card_grading_workflow_events_tenant_select","schemaname":"public","with_check":null}],"triggers":[{"name":"pcg_workflow_platform_journal","definition":"CREATE TRIGGER pcg_workflow_platform_journal AFTER INSERT ON card_grading_workflow_events FOR EACH ROW EXECUTE FUNCTION journal_pcg_workflow_transition()"}],"constraints":[{"name":"card_grading_workflow_events_card_id_fkey","definition":"FOREIGN KEY (card_id) REFERENCES card_grading_cards(id) ON DELETE CASCADE"},{"name":"card_grading_workflow_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"card_grading_workflow_events_submission_id_fkey","definition":"FOREIGN KEY (submission_id) REFERENCES card_grading_submissions(id) ON DELETE CASCADE"},{"name":"card_grading_workflow_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"carrier_preferences","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"carrier_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"requires_line_item_photos","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"allows_op","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"op_min_claim_amount","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"pays_code_upgrades","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"supplement_turnaround_days","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"preferred_submission_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"carrier_preferences_pkey","definition":"CREATE UNIQUE INDEX carrier_preferences_pkey ON public.carrier_preferences USING btree (id)"},{"name":"carrier_preferences_tenant_org_id_carrier_name_key","definition":"CREATE UNIQUE INDEX carrier_preferences_tenant_org_id_carrier_name_key ON public.carrier_preferences USING btree (tenant_org_id, carrier_name)"},{"name":"idx_carrier_preferences_tenant","definition":"CREATE INDEX idx_carrier_preferences_tenant ON public.carrier_preferences USING btree (tenant_org_id)"}],"policies":[{"cmd":"DELETE","qual":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))","roles":["public"],"tablename":"carrier_preferences","permissive":"PERMISSIVE","policyname":"tenant members delete carrier prefs","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"carrier_preferences","permissive":"PERMISSIVE","policyname":"tenant members insert carrier prefs","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))"},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))","roles":["public"],"tablename":"carrier_preferences","permissive":"PERMISSIVE","policyname":"tenant members read carrier prefs","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))","roles":["public"],"tablename":"carrier_preferences","permissive":"PERMISSIVE","policyname":"tenant members update carrier prefs","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_carrier_preferences_updated_at","definition":"CREATE TRIGGER trg_carrier_preferences_updated_at BEFORE UPDATE ON carrier_preferences FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"carrier_preferences_pkey","definition":"PRIMARY KEY (id)"},{"name":"carrier_preferences_tenant_org_id_carrier_name_key","definition":"UNIQUE (tenant_org_id, carrier_name)"}]},{"table":"case_documents_required","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"document_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_required","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'Missing'::text","identity":"","not_null":true,"generated":""},{"name":"linked_file_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"linked_file_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"verified_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"case_documents_required_pkey","definition":"CREATE UNIQUE INDEX case_documents_required_pkey ON public.case_documents_required USING btree (id)"},{"name":"idx_case_docs_claim","definition":"CREATE INDEX idx_case_docs_claim ON public.case_documents_required USING btree (claim_id)"},{"name":"idx_case_docs_status","definition":"CREATE INDEX idx_case_docs_status ON public.case_documents_required USING btree (tenant_org_id, status)"},{"name":"idx_case_docs_tenant","definition":"CREATE INDEX idx_case_docs_tenant ON public.case_documents_required USING btree (tenant_org_id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"case_documents_required","permissive":"PERMISSIVE","policyname":"case_docs_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"case_documents_required","permissive":"PERMISSIVE","policyname":"case_docs_insert","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"case_documents_required","permissive":"PERMISSIVE","policyname":"case_docs_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"case_documents_required","permissive":"PERMISSIVE","policyname":"case_docs_update","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))"}],"triggers":[{"name":"trg_case_docs_updated_at","definition":"CREATE TRIGGER trg_case_docs_updated_at BEFORE UPDATE ON case_documents_required FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"case_documents_required_pkey","definition":"PRIMARY KEY (id)"},{"name":"case_documents_required_status_check","definition":"CHECK (status = ANY (ARRAY['Missing'::text, 'Requested'::text, 'Received'::text, 'Verified'::text, 'Not Applicable'::text]))"}]},{"table":"challenge_participants","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"challenge_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_score","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"rank","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"progress","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"joined_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"challenge_participants_challenge_id_user_id_key","definition":"CREATE UNIQUE INDEX challenge_participants_challenge_id_user_id_key ON public.challenge_participants USING btree (challenge_id, user_id)"},{"name":"challenge_participants_pkey","definition":"CREATE UNIQUE INDEX challenge_participants_pkey ON public.challenge_participants USING btree (id)"},{"name":"idx_challenge_participants_challenge","definition":"CREATE INDEX idx_challenge_participants_challenge ON public.challenge_participants USING btree (challenge_id)"},{"name":"idx_challenge_participants_user","definition":"CREATE INDEX idx_challenge_participants_user ON public.challenge_participants USING btree (user_id)"}],"policies":[{"cmd":"ALL","qual":"(uid() = user_id)","roles":["public"],"tablename":"challenge_participants","permissive":"PERMISSIVE","policyname":"Users manage own participation","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM challenges\n  WHERE (challenges.id = challenge_participants.challenge_id)))","roles":["public"],"tablename":"challenge_participants","permissive":"PERMISSIVE","policyname":"Users view challenge participants","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"challenge_participants_challenge_id_user_id_key","definition":"UNIQUE (challenge_id, user_id)"},{"name":"challenge_participants_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"challenges","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"challenge_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"start_date","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"end_date","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"rules","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"reward_description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'upcoming'::text","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"challenges_pkey","definition":"CREATE UNIQUE INDEX challenges_pkey ON public.challenges USING btree (id)"},{"name":"idx_challenges_status","definition":"CREATE INDEX idx_challenges_status ON public.challenges USING btree (status)"},{"name":"idx_challenges_tenant","definition":"CREATE INDEX idx_challenges_tenant ON public.challenges USING btree (tenant_org_id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = challenges.tenant_org_id))))","roles":["public"],"tablename":"challenges","permissive":"PERMISSIVE","policyname":"Tenant members view challenges","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"challenges_pkey","definition":"PRIMARY KEY (id)"},{"name":"challenges_status_check","definition":"CHECK (status = ANY (ARRAY['upcoming'::text, 'active'::text, 'completed'::text, 'cancelled'::text]))"}]},{"table":"claim_deadlines","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"due_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'Open'::text","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_statutory","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"priority","type":"text","default":"'Medium'::text","identity":"","not_null":true,"generated":""},{"name":"assigned_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"due_time","type":"time without time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deadline_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"cancelled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"claim_deadlines_pkey","definition":"CREATE UNIQUE INDEX claim_deadlines_pkey ON public.claim_deadlines USING btree (id)"},{"name":"idx_claim_deadlines_assigned_user","definition":"CREATE INDEX idx_claim_deadlines_assigned_user ON public.claim_deadlines USING btree (assigned_user_id) WHERE (assigned_user_id IS NOT NULL)"},{"name":"idx_claim_deadlines_claim","definition":"CREATE INDEX idx_claim_deadlines_claim ON public.claim_deadlines USING btree (claim_id)"},{"name":"idx_claim_deadlines_due","definition":"CREATE INDEX idx_claim_deadlines_due ON public.claim_deadlines USING btree (due_date) WHERE (status = 'Open'::text)"},{"name":"idx_claim_deadlines_open","definition":"CREATE INDEX idx_claim_deadlines_open ON public.claim_deadlines USING btree (tenant_org_id, status, due_date) WHERE (status = 'Open'::text)"},{"name":"idx_claim_deadlines_tenant","definition":"CREATE INDEX idx_claim_deadlines_tenant ON public.claim_deadlines USING btree (tenant_org_id)"},{"name":"idx_claim_deadlines_tenant_due","definition":"CREATE INDEX idx_claim_deadlines_tenant_due ON public.claim_deadlines USING btree (tenant_org_id, due_date)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"claim_deadlines","permissive":"PERMISSIVE","policyname":"deadlines_delete_tenant_or_admin","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"claim_deadlines","permissive":"PERMISSIVE","policyname":"deadlines_insert_tenant_or_admin","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (is_tenant_member(tenant_org_id) OR is_system_admin(uid())))"},{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND (uid() IS NOT NULL))","roles":["authenticated"],"tablename":"claim_deadlines","permissive":"RESTRICTIVE","policyname":"deadlines_restrict_null_or_anon","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (uid() IS NOT NULL))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"claim_deadlines","permissive":"PERMISSIVE","policyname":"deadlines_select_tenant_or_admin","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"claim_deadlines","permissive":"PERMISSIVE","policyname":"deadlines_update_tenant_or_admin","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (is_tenant_member(tenant_org_id) OR is_system_admin(uid())))"}],"triggers":[{"name":"trg_mark_late_deadlines","definition":"CREATE TRIGGER trg_mark_late_deadlines BEFORE INSERT OR UPDATE ON claim_deadlines FOR EACH ROW EXECUTE FUNCTION mark_late_deadlines()"},{"name":"update_claim_deadlines_updated_at","definition":"CREATE TRIGGER update_claim_deadlines_updated_at BEFORE UPDATE ON claim_deadlines FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"claim_deadlines_pkey","definition":"PRIMARY KEY (id)"},{"name":"claim_deadlines_priority_check","definition":"CHECK (priority = ANY (ARRAY['Low'::text, 'Medium'::text, 'High'::text, 'Critical'::text]))"}]},{"table":"claim_negotiation_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"amount","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"who","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_date","type":"date","default":"CURRENT_DATE","identity":"","not_null":true,"generated":""},{"name":"next_action_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"attachment_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"carrier_offer_amount","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"pa_demand_amount","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"settlement_amount","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"estimate_amount","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"made_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"received_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"communication_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_followup_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"claim_negotiation_events_pkey","definition":"CREATE UNIQUE INDEX claim_negotiation_events_pkey ON public.claim_negotiation_events USING btree (id)"},{"name":"idx_claim_neg_tenant_date","definition":"CREATE INDEX idx_claim_neg_tenant_date ON public.claim_negotiation_events USING btree (tenant_org_id, event_date DESC)"},{"name":"idx_negotiation_claim","definition":"CREATE INDEX idx_negotiation_claim ON public.claim_negotiation_events USING btree (claim_id, event_date DESC)"},{"name":"idx_negotiation_tenant","definition":"CREATE INDEX idx_negotiation_tenant ON public.claim_negotiation_events USING btree (tenant_org_id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"claim_negotiation_events","permissive":"PERMISSIVE","policyname":"negotiation_delete_tenant_or_admin","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"claim_negotiation_events","permissive":"PERMISSIVE","policyname":"negotiation_insert_tenant_or_admin","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (is_tenant_member(tenant_org_id) OR is_system_admin(uid())))"},{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND (uid() IS NOT NULL))","roles":["authenticated"],"tablename":"claim_negotiation_events","permissive":"RESTRICTIVE","policyname":"negotiation_restrict_null_or_anon","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (uid() IS NOT NULL))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"claim_negotiation_events","permissive":"PERMISSIVE","policyname":"negotiation_select_tenant_or_admin","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"claim_negotiation_events","permissive":"PERMISSIVE","policyname":"negotiation_update_tenant_or_admin","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (is_tenant_member(tenant_org_id) OR is_system_admin(uid())))"}],"triggers":[{"name":"update_negotiation_updated_at","definition":"CREATE TRIGGER update_negotiation_updated_at BEFORE UPDATE ON claim_negotiation_events FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"claim_negotiation_events_communication_method_check","definition":"CHECK (communication_method IS NULL OR (communication_method = ANY (ARRAY['call'::text, 'email'::text, 'letter'::text, 'portal'::text, 'in-person'::text, 'other'::text])))"},{"name":"claim_negotiation_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"claim_payment_status_history","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_status","type":"claim_payment_lifecycle_v4","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_status","type":"claim_payment_lifecycle_v4","default":null,"identity":"","not_null":true,"generated":""},{"name":"changed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"note","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":"'manual'::text","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"claim_payment_status_history_pkey","definition":"CREATE UNIQUE INDEX claim_payment_status_history_pkey ON public.claim_payment_status_history USING btree (id)"},{"name":"idx_cpsh_claim_id_changed_at","definition":"CREATE INDEX idx_cpsh_claim_id_changed_at ON public.claim_payment_status_history USING btree (claim_id, changed_at DESC)"},{"name":"idx_cpsh_tenant","definition":"CREATE INDEX idx_cpsh_tenant ON public.claim_payment_status_history USING btree (tenant_org_id)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR is_manager_or_higher(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"claim_payment_status_history","permissive":"PERMISSIVE","policyname":"Manager+ can view claim payment history","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"claim_payment_status_history_pkey","definition":"PRIMARY KEY (id)"},{"name":"claim_payment_status_history_source_check","definition":"CHECK (source = ANY (ARRAY['manual'::text, 'backfill'::text, 'system'::text]))"}]},{"table":"claim_supplements","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"estimate_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"supplement_number","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"amount_requested","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"amount_approved","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"gaps_snapshot","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"letter_html","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recipient_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recipient_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"responded_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"claim_supplements_claim_number_unique","definition":"CREATE UNIQUE INDEX claim_supplements_claim_number_unique ON public.claim_supplements USING btree (claim_id, supplement_number)"},{"name":"claim_supplements_pkey","definition":"CREATE UNIQUE INDEX claim_supplements_pkey ON public.claim_supplements USING btree (id)"},{"name":"idx_claim_supplements_claim","definition":"CREATE INDEX idx_claim_supplements_claim ON public.claim_supplements USING btree (claim_id)"},{"name":"idx_claim_supplements_contact","definition":"CREATE INDEX idx_claim_supplements_contact ON public.claim_supplements USING btree (contact_id)"},{"name":"idx_claim_supplements_tenant","definition":"CREATE INDEX idx_claim_supplements_tenant ON public.claim_supplements USING btree (tenant_org_id)"}],"policies":[{"cmd":"DELETE","qual":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))","roles":["authenticated"],"tablename":"claim_supplements","permissive":"PERMISSIVE","policyname":"tenant members delete supplements","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"claim_supplements","permissive":"PERMISSIVE","policyname":"tenant members insert supplements","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))"},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))","roles":["authenticated"],"tablename":"claim_supplements","permissive":"PERMISSIVE","policyname":"tenant members read supplements","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))","roles":["authenticated"],"tablename":"claim_supplements","permissive":"PERMISSIVE","policyname":"tenant members update supplements","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))"}],"triggers":[{"name":"update_claim_supplements_updated_at","definition":"CREATE TRIGGER update_claim_supplements_updated_at BEFORE UPDATE ON claim_supplements FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"claim_supplements_claim_number_unique","definition":"UNIQUE (claim_id, supplement_number)"},{"name":"claim_supplements_pkey","definition":"PRIMARY KEY (id)"},{"name":"claim_supplements_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'sent'::text, 'partial-approved'::text, 'approved'::text, 'denied'::text, 'withdrawn'::text]))"}]},{"table":"claim_valuation_items","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"quantity","type":"numeric","default":"1","identity":"","not_null":true,"generated":""},{"name":"unit_cost","type":"numeric","default":"0","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"shared_claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"claim_valuation_items_pkey","definition":"CREATE UNIQUE INDEX claim_valuation_items_pkey ON public.claim_valuation_items USING btree (id)"},{"name":"claim_valuation_items_shared_claim_idx","definition":"CREATE INDEX claim_valuation_items_shared_claim_idx ON public.claim_valuation_items USING btree (tenant_org_id, shared_claim_id) WHERE (shared_claim_id IS NOT NULL)"},{"name":"idx_claim_valuation_items_claim","definition":"CREATE INDEX idx_claim_valuation_items_claim ON public.claim_valuation_items USING btree (claim_id, created_at)"},{"name":"idx_claim_valuation_items_tenant","definition":"CREATE INDEX idx_claim_valuation_items_tenant ON public.claim_valuation_items USING btree (tenant_org_id, contact_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"claim_valuation_items","permissive":"PERMISSIVE","policyname":"Tenant members can create claim valuation items","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"claim_valuation_items","permissive":"PERMISSIVE","policyname":"Tenant members can delete claim valuation items","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"claim_valuation_items","permissive":"PERMISSIVE","policyname":"Tenant members can update claim valuation items","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"claim_valuation_items","permissive":"PERMISSIVE","policyname":"Tenant members can view claim valuation items","schemaname":"public","with_check":null}],"triggers":[{"name":"update_claim_valuation_items_updated_at","definition":"CREATE TRIGGER update_claim_valuation_items_updated_at BEFORE UPDATE ON claim_valuation_items FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"claim_valuation_items_claim_id_fkey","definition":"FOREIGN KEY (claim_id) REFERENCES contact_claims(id) ON DELETE CASCADE"},{"name":"claim_valuation_items_claim_reference_check","definition":"CHECK ((claim_id IS NOT NULL) <> (shared_claim_id IS NOT NULL))"},{"name":"claim_valuation_items_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"claim_valuation_items_pkey","definition":"PRIMARY KEY (id)"},{"name":"claim_valuation_items_quantity_check","definition":"CHECK (quantity > 0::numeric)"},{"name":"claim_valuation_items_shared_claim_id_fkey","definition":"FOREIGN KEY (shared_claim_id) REFERENCES shared_claims(id) ON DELETE CASCADE"},{"name":"claim_valuation_items_unit_cost_check","definition":"CHECK (unit_cost >= 0::numeric)"}]},{"table":"code_audit_rules","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"rule_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"pattern_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_pattern","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"code_pattern","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"severity","type":"text","default":"'warning'::text","identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"last_scanned_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"violations_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"code_audit_rules_pkey","definition":"CREATE UNIQUE INDEX code_audit_rules_pkey ON public.code_audit_rules USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"code_audit_rules","permissive":"PERMISSIVE","policyname":"platform_admin_manage_code_audit","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"code_audit_rules_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"cohort_definitions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"character varying(255)","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"cohort_type","type":"character varying(50)","default":null,"identity":"","not_null":true,"generated":""},{"name":"definition","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"cohort_definitions_pkey","definition":"CREATE UNIQUE INDEX cohort_definitions_pkey ON public.cohort_definitions USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"cohort_definitions","permissive":"PERMISSIVE","policyname":"Users can manage cohorts","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"cohort_definitions","permissive":"PERMISSIVE","policyname":"Users can view own tenant cohorts","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"cohort_definitions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"command_center_activity_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"command_center_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"action_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"old_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"actor_type","type":"text","default":"'human'::text","identity":"","not_null":true,"generated":""},{"name":"actor_agent_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_display_name","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"command_center_activity_log_pkey","definition":"CREATE UNIQUE INDEX command_center_activity_log_pkey ON public.command_center_activity_log USING btree (id)"},{"name":"idx_ccal_event","definition":"CREATE INDEX idx_ccal_event ON public.command_center_activity_log USING btree (command_center_event_id, created_at)"},{"name":"idx_ccal_platform_created","definition":"CREATE INDEX idx_ccal_platform_created ON public.command_center_activity_log USING btree (created_at DESC) WHERE (tenant_id IS NULL)"},{"name":"idx_ccal_tenant","definition":"CREATE INDEX idx_ccal_tenant ON public.command_center_activity_log USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM command_center_events e\n  WHERE ((e.id = command_center_activity_log.command_center_event_id) AND is_tenant_member(uid(), e.tenant_id) AND (is_command_agent(uid(), e.tenant_id) OR (e.created_by_user_id = uid()) OR (e.assigned_to_user_id = uid())))))","roles":["authenticated"],"tablename":"command_center_activity_log","permissive":"PERMISSIVE","policyname":"ccal_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"command_center_activity_log_action_type_check","definition":"CHECK (action_type = ANY (ARRAY['acknowledged'::text, 'approval_decision'::text, 'approval_pending'::text, 'assigned'::text, 'closed'::text, 'created'::text, 'deploy_dispatched'::text, 'escalated'::text, 'owner_notified'::text, 'owner_notify_failed'::text, 'replied'::text, 'repo_pr_closed'::text, 'reported_by_agent'::text, 'resolved'::text, 'status_changed'::text, 'event_resolved_by_cleanup'::text, 'sql_ops_executed'::text]))"},{"name":"command_center_activity_log_actor_type_check","definition":"CHECK (actor_type = ANY (ARRAY['human'::text, 'agent'::text, 'system'::text]))"},{"name":"command_center_activity_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"command_center_agent_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"agent_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"agent_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"route","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"method","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status_code","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"latency_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"command_center_agent_runs_pkey","definition":"CREATE UNIQUE INDEX command_center_agent_runs_pkey ON public.command_center_agent_runs USING btree (id)"},{"name":"idx_ccar_agent_created","definition":"CREATE INDEX idx_ccar_agent_created ON public.command_center_agent_runs USING btree (agent_id, created_at DESC)"},{"name":"idx_ccar_status","definition":"CREATE INDEX idx_ccar_status ON public.command_center_agent_runs USING btree (status_code)"},{"name":"idx_ccar_tenant_created","definition":"CREATE INDEX idx_ccar_tenant_created ON public.command_center_agent_runs USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"command_center_agent_runs","permissive":"PERMISSIVE","policyname":"ccar_godmode_select","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((tenant_id IS NOT NULL) AND is_command_agent(uid(), tenant_id))","roles":["authenticated"],"tablename":"command_center_agent_runs","permissive":"PERMISSIVE","policyname":"ccar_tenant_admin_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"command_center_agent_runs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"command_center_agent_tenants","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"agent_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"access_level","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"command_center_agent_tenants_agent_id_tenant_id_key","definition":"CREATE UNIQUE INDEX command_center_agent_tenants_agent_id_tenant_id_key ON public.command_center_agent_tenants USING btree (agent_id, tenant_id)"},{"name":"command_center_agent_tenants_pkey","definition":"CREATE UNIQUE INDEX command_center_agent_tenants_pkey ON public.command_center_agent_tenants USING btree (id)"},{"name":"idx_ccat_agent","definition":"CREATE INDEX idx_ccat_agent ON public.command_center_agent_tenants USING btree (agent_id)"},{"name":"idx_ccat_tenant","definition":"CREATE INDEX idx_ccat_tenant ON public.command_center_agent_tenants USING btree (tenant_id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"command_center_agent_tenants","permissive":"PERMISSIVE","policyname":"ccat_godmode_all","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"command_center_agent_tenants_access_level_check","definition":"CHECK (access_level = ANY (ARRAY['read'::text, 'triage'::text, 'admin'::text]))"},{"name":"command_center_agent_tenants_agent_id_tenant_id_key","definition":"UNIQUE (agent_id, tenant_id)"},{"name":"command_center_agent_tenants_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"command_center_agents","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scopes","type":"text[]","default":"ARRAY[]::text[]","identity":"","not_null":true,"generated":""},{"name":"platform_scope","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"api_key_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"api_key_prefix","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rate_limit_per_min","type":"integer","default":"60","identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"disabled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"rotated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_used_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"command_center_agents_api_key_hash_key","definition":"CREATE UNIQUE INDEX command_center_agents_api_key_hash_key ON public.command_center_agents USING btree (api_key_hash)"},{"name":"command_center_agents_name_key","definition":"CREATE UNIQUE INDEX command_center_agents_name_key ON public.command_center_agents USING btree (name)"},{"name":"command_center_agents_pkey","definition":"CREATE UNIQUE INDEX command_center_agents_pkey ON public.command_center_agents USING btree (id)"},{"name":"idx_cc_agents_enabled","definition":"CREATE INDEX idx_cc_agents_enabled ON public.command_center_agents USING btree (enabled)"},{"name":"idx_cc_agents_role","definition":"CREATE INDEX idx_cc_agents_role ON public.command_center_agents USING btree (role)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"command_center_agents","permissive":"PERMISSIVE","policyname":"cca_godmode_all","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"command_center_agents","permissive":"PERMISSIVE","policyname":"cca_godmode_select","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_cca_updated_at","definition":"CREATE TRIGGER trg_cca_updated_at BEFORE UPDATE ON command_center_agents FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"command_center_agents_api_key_hash_key","definition":"UNIQUE (api_key_hash)"},{"name":"command_center_agents_name_key","definition":"UNIQUE (name)"},{"name":"command_center_agents_pkey","definition":"PRIMARY KEY (id)"},{"name":"command_center_agents_role_check","definition":"CHECK (role = ANY (ARRAY['worker'::text, 'commander'::text, 'approval_gate'::text]))"}]},{"table":"command_center_deploy_approvals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"token_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"agent_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"function_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"head_sha","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"consumed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"command_center_deploy_approvals_pkey","definition":"CREATE UNIQUE INDEX command_center_deploy_approvals_pkey ON public.command_center_deploy_approvals USING btree (id)"},{"name":"command_center_deploy_approvals_token_hash_key","definition":"CREATE UNIQUE INDEX command_center_deploy_approvals_token_hash_key ON public.command_center_deploy_approvals USING btree (token_hash)"},{"name":"idx_cc_deploy_approvals_expires","definition":"CREATE INDEX idx_cc_deploy_approvals_expires ON public.command_center_deploy_approvals USING btree (expires_at) WHERE (consumed_at IS NULL)"}],"policies":[{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"command_center_deploy_approvals","permissive":"PERMISSIVE","policyname":"service_role full access cc_deploy_approvals","schemaname":"public","with_check":"true"}],"triggers":[],"constraints":[{"name":"command_center_deploy_approvals_pkey","definition":"PRIMARY KEY (id)"},{"name":"command_center_deploy_approvals_token_hash_key","definition":"UNIQUE (token_hash)"}]},{"table":"command_center_dispatch_jobs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"agent_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"function_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"workflow","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"head_sha","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"run_id","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"run_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"run_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"run_conclusion","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"payload","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"dispatched_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"command_center_dispatch_jobs_one_active_deploy_per_target_idx","definition":"CREATE UNIQUE INDEX command_center_dispatch_jobs_one_active_deploy_per_target_idx ON public.command_center_dispatch_jobs USING btree (function_name, workflow) WHERE ((kind = 'deploy_function'::text) AND (status = ANY (ARRAY['pending'::text, 'dispatched'::text, 'running'::text])))"},{"name":"command_center_dispatch_jobs_pkey","definition":"CREATE UNIQUE INDEX command_center_dispatch_jobs_pkey ON public.command_center_dispatch_jobs USING btree (id)"},{"name":"idx_ccdj_agent_created","definition":"CREATE INDEX idx_ccdj_agent_created ON public.command_center_dispatch_jobs USING btree (agent_id, created_at DESC)"},{"name":"idx_ccdj_status","definition":"CREATE INDEX idx_ccdj_status ON public.command_center_dispatch_jobs USING btree (status, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"false","roles":["authenticated"],"tablename":"command_center_dispatch_jobs","permissive":"PERMISSIVE","policyname":"no client access","schemaname":"public","with_check":"false"}],"triggers":[],"constraints":[{"name":"command_center_dispatch_jobs_kind_check","definition":"CHECK (kind = ANY (ARRAY['deploy_function'::text, 'function_logs'::text, 'deploy_status'::text]))"},{"name":"command_center_dispatch_jobs_pkey","definition":"PRIMARY KEY (id)"},{"name":"command_center_dispatch_jobs_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'dispatched'::text, 'in_progress'::text, 'succeeded'::text, 'failed'::text, 'expired'::text]))"}]},{"table":"command_center_event_artifacts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"command_center_event_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"artifact_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"storage_bucket","type":"text","default":"'command-center-visual-witness'::text","identity":"","not_null":true,"generated":""},{"name":"storage_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"mime_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"width","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"height","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"device_pixel_ratio","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"route","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_marker","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by_role","type":"text","default":"'visual-witness-extension'::text","identity":"","not_null":true,"generated":""},{"name":"safe_metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"command_center_event_artifacts_pkey","definition":"CREATE UNIQUE INDEX command_center_event_artifacts_pkey ON public.command_center_event_artifacts USING btree (id)"},{"name":"command_center_event_artifacts_storage_path_unique","definition":"CREATE UNIQUE INDEX command_center_event_artifacts_storage_path_unique ON public.command_center_event_artifacts USING btree (storage_bucket, storage_path)"},{"name":"idx_ccea_event_created","definition":"CREATE INDEX idx_ccea_event_created ON public.command_center_event_artifacts USING btree (command_center_event_id, created_at DESC)"},{"name":"idx_ccea_tenant_created","definition":"CREATE INDEX idx_ccea_tenant_created ON public.command_center_event_artifacts USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"command_center_event_artifacts","permissive":"PERMISSIVE","policyname":"ccea_no_client_insert","schemaname":"public","with_check":"false"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM command_center_events e\n  WHERE ((e.id = command_center_event_artifacts.command_center_event_id) AND (e.tenant_id = command_center_event_artifacts.tenant_id) AND is_tenant_member(uid(), e.tenant_id) AND (is_command_agent(uid(), e.tenant_id) OR (e.created_by_user_id = uid()) OR (e.assigned_to_user_id = uid())))))","roles":["authenticated"],"tablename":"command_center_event_artifacts","permissive":"PERMISSIVE","policyname":"ccea_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"command_center_event_artifacts_artifact_type_check","definition":"CHECK (artifact_type = 'visible_tab_screenshot'::text)"},{"name":"command_center_event_artifacts_command_center_event_id_fkey","definition":"FOREIGN KEY (command_center_event_id) REFERENCES command_center_events(id) ON DELETE CASCADE"},{"name":"command_center_event_artifacts_mime_type_check","definition":"CHECK (mime_type = ANY (ARRAY['image/png'::text, 'image/jpeg'::text]))"},{"name":"command_center_event_artifacts_pkey","definition":"PRIMARY KEY (id)"},{"name":"command_center_event_artifacts_storage_path_unique","definition":"UNIQUE (storage_bucket, storage_path)"}]},{"table":"command_center_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by_role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_module","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"related_lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_job_request_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_job_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"priority","type":"text","default":"'info'::text","identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'new'::text","identity":"","not_null":true,"generated":""},{"name":"assigned_to_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"requires_response","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"acknowledged_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"acknowledged_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"requires_approval","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"approval_status","type":"text","default":"'n/a'::text","identity":"","not_null":true,"generated":""},{"name":"approval_decided_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"approval_decided_by_agent_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"approval_decided_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"approval_decision_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_agent_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_type","type":"text","default":"'human'::text","identity":"","not_null":true,"generated":""},{"name":"actor_agent_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_display_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mission_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mission_phase","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mission_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_authorized","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"authorization_scope","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_step","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"attempt_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"leased_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lease_expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_progress_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"queue_deadline","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"execution_deadline","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"terminal_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"final_receipt","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"mission_context","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"command_center_events_pkey","definition":"CREATE UNIQUE INDEX command_center_events_pkey ON public.command_center_events USING btree (id)"},{"name":"idx_cce_active_missions","definition":"CREATE INDEX idx_cce_active_missions ON public.command_center_events USING btree (mission_status, last_progress_at, created_at) WHERE (mission_status = ANY (ARRAY['accepted'::text, 'queued'::text, 'pending'::text, 'running'::text, 'waiting'::text, 'retryable'::text]))"},{"name":"idx_cce_approval_pending","definition":"CREATE INDEX idx_cce_approval_pending ON public.command_center_events USING btree (tenant_id, created_at DESC) WHERE (approval_status = 'pending'::text)"},{"name":"idx_cce_creator","definition":"CREATE INDEX idx_cce_creator ON public.command_center_events USING btree (created_by_user_id)"},{"name":"idx_cce_mission_lease","definition":"CREATE INDEX idx_cce_mission_lease ON public.command_center_events USING btree (lease_expires_at) WHERE (leased_by IS NOT NULL)"},{"name":"idx_cce_owner_mission_key","definition":"CREATE UNIQUE INDEX idx_cce_owner_mission_key ON public.command_center_events USING btree (((mission_context ->> 'mission_key'::text))) WHERE ((event_type = 'owner_mission'::text) AND (mission_context ? 'mission_key'::text))"},{"name":"idx_cce_related_job","definition":"CREATE INDEX idx_cce_related_job ON public.command_center_events USING btree (related_job_id) WHERE (related_job_id IS NOT NULL)"},{"name":"idx_cce_related_lead","definition":"CREATE INDEX idx_cce_related_lead ON public.command_center_events USING btree (related_lead_id) WHERE (related_lead_id IS NOT NULL)"},{"name":"idx_cce_source_agent","definition":"CREATE INDEX idx_cce_source_agent ON public.command_center_events USING btree (source_agent_id) WHERE (source_agent_id IS NOT NULL)"},{"name":"idx_cce_tenant_assignee_status","definition":"CREATE INDEX idx_cce_tenant_assignee_status ON public.command_center_events USING btree (tenant_id, assigned_to_user_id, status)"},{"name":"idx_cce_tenant_status_priority_created","definition":"CREATE INDEX idx_cce_tenant_status_priority_created ON public.command_center_events USING btree (tenant_id, status, priority, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"command_center_events","permissive":"PERMISSIVE","policyname":"cce_insert","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_id) AND (created_by_user_id = uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) AND (is_command_agent(uid(), tenant_id) OR (created_by_user_id = uid()) OR (assigned_to_user_id = uid()) OR (EXISTS ( SELECT 1\n   FROM unified_contacts uc\n  WHERE ((uc.id = command_center_events.related_lead_id) AND (uc.assigned_user = (uid())::text)))) OR (EXISTS ( SELECT 1\n   FROM jobs j\n  WHERE ((j.id = command_center_events.related_job_id) AND ((j.assigned_crew_id = uid()) OR (j.assigned_pm_id = uid())))))))","roles":["authenticated"],"tablename":"command_center_events","permissive":"PERMISSIVE","policyname":"cce_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_command_agent(uid(), tenant_id)","roles":["authenticated"],"tablename":"command_center_events","permissive":"PERMISSIVE","policyname":"cce_update","schemaname":"public","with_check":"is_command_agent(uid(), tenant_id)"}],"triggers":[{"name":"trg_cce_apply_approval_gate","definition":"CREATE TRIGGER trg_cce_apply_approval_gate BEFORE INSERT ON command_center_events FOR EACH ROW EXECUTE FUNCTION cce_apply_approval_gate()"},{"name":"trg_cce_dispatch_owner_alert_ins","definition":"CREATE TRIGGER trg_cce_dispatch_owner_alert_ins AFTER INSERT ON command_center_events FOR EACH ROW EXECUTE FUNCTION cce_dispatch_owner_alert()"},{"name":"trg_cce_dispatch_owner_alert_upd","definition":"CREATE TRIGGER trg_cce_dispatch_owner_alert_upd AFTER UPDATE OF priority, requires_approval, approval_status, event_type ON command_center_events FOR EACH ROW EXECUTE FUNCTION cce_dispatch_owner_alert()"},{"name":"trg_cce_on_insert","definition":"CREATE TRIGGER trg_cce_on_insert AFTER INSERT ON command_center_events FOR EACH ROW EXECUTE FUNCTION cce_on_insert()"},{"name":"trg_cce_on_update","definition":"CREATE TRIGGER trg_cce_on_update AFTER UPDATE ON command_center_events FOR EACH ROW EXECUTE FUNCTION cce_on_update()"},{"name":"trg_cce_updated_at","definition":"CREATE TRIGGER trg_cce_updated_at BEFORE UPDATE ON command_center_events FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"cce_actor_present","definition":"CHECK (actor_type = 'human'::text AND created_by_user_id IS NOT NULL OR actor_type = 'agent'::text AND actor_agent_id IS NOT NULL OR actor_type = 'system'::text)"},{"name":"command_center_events_actor_type_check","definition":"CHECK (actor_type = ANY (ARRAY['human'::text, 'agent'::text, 'system'::text]))"},{"name":"command_center_events_approval_status_check","definition":"CHECK (approval_status = ANY (ARRAY['n/a'::text, 'pending'::text, 'approved'::text, 'rejected'::text, 'needs_changes'::text]))"},{"name":"command_center_events_mission_status_check","definition":"CHECK (mission_status IS NULL OR (mission_status = ANY (ARRAY['accepted'::text, 'queued'::text, 'pending'::text, 'running'::text, 'waiting'::text, 'retryable'::text, 'verified'::text, 'completed_with_findings'::text, 'blocked'::text, 'failed'::text, 'timed_out'::text, 'cancelled'::text, 'superseded'::text])))"},{"name":"command_center_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"command_center_events_priority_check","definition":"CHECK (priority = ANY (ARRAY['info'::text, 'task'::text, 'urgent'::text, 'blocker'::text]))"},{"name":"command_center_events_source_module_check","definition":"CHECK (source_module = ANY (ARRAY['lead'::text, 'job_request'::text, 'job'::text, 'claim'::text, 'crew'::text, 'phone'::text, 'canvassing'::text, 'website'::text, 'ai'::text, 'system'::text, 'command_center'::text]))"},{"name":"command_center_events_status_check","definition":"CHECK (status = ANY (ARRAY['new'::text, 'acknowledged'::text, 'assigned'::text, 'in_progress'::text, 'pending_approval'::text, 'resolved'::text, 'closed'::text]))"}]},{"table":"command_center_messages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"command_center_event_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"sender_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"sender_role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"actor_type","type":"text","default":"'human'::text","identity":"","not_null":true,"generated":""},{"name":"actor_agent_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_display_name","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"command_center_messages_pkey","definition":"CREATE UNIQUE INDEX command_center_messages_pkey ON public.command_center_messages USING btree (id)"},{"name":"idx_ccm_event","definition":"CREATE INDEX idx_ccm_event ON public.command_center_messages USING btree (command_center_event_id, created_at)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"command_center_messages","permissive":"PERMISSIVE","policyname":"ccm_insert","schemaname":"public","with_check":"((sender_user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM command_center_events e\n  WHERE ((e.id = command_center_messages.command_center_event_id) AND (e.tenant_id = command_center_messages.tenant_id) AND is_tenant_member(uid(), e.tenant_id) AND (is_command_agent(uid(), e.tenant_id) OR (e.created_by_user_id = uid()) OR (e.assigned_to_user_id = uid()) OR (EXISTS ( SELECT 1\n           FROM unified_contacts uc\n          WHERE ((uc.id = e.related_lead_id) AND (uc.assigned_user = (uid())::text)))) OR (EXISTS ( SELECT 1\n           FROM jobs j\n          WHERE ((j.id = e.related_job_id) AND ((j.assigned_crew_id = uid()) OR (j.assigned_pm_id = uid()))))))))))"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM command_center_events e\n  WHERE ((e.id = command_center_messages.command_center_event_id) AND is_tenant_member(uid(), e.tenant_id) AND (is_command_agent(uid(), e.tenant_id) OR (e.created_by_user_id = uid()) OR (e.assigned_to_user_id = uid()) OR (EXISTS ( SELECT 1\n           FROM unified_contacts uc\n          WHERE ((uc.id = e.related_lead_id) AND (uc.assigned_user = (uid())::text)))) OR (EXISTS ( SELECT 1\n           FROM jobs j\n          WHERE ((j.id = e.related_job_id) AND ((j.assigned_crew_id = uid()) OR (j.assigned_pm_id = uid())))))))))","roles":["authenticated"],"tablename":"command_center_messages","permissive":"PERMISSIVE","policyname":"ccm_select","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_ccm_on_insert","definition":"CREATE TRIGGER trg_ccm_on_insert AFTER INSERT ON command_center_messages FOR EACH ROW EXECUTE FUNCTION ccm_on_insert()"}],"constraints":[{"name":"ccm_actor_present","definition":"CHECK (actor_type = 'human'::text AND sender_user_id IS NOT NULL OR actor_type = 'agent'::text AND actor_agent_id IS NOT NULL OR actor_type = 'system'::text)"},{"name":"command_center_messages_actor_type_check","definition":"CHECK (actor_type = ANY (ARRAY['human'::text, 'agent'::text, 'system'::text]))"},{"name":"command_center_messages_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"command_center_mission_steps","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"command_center_event_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"step_order","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"step_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lane","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"attempt_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"idempotency_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"input","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"output","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_progress_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deadline_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"command_center_mission_steps_command_center_event_id_step_k_key","definition":"CREATE UNIQUE INDEX command_center_mission_steps_command_center_event_id_step_k_key ON public.command_center_mission_steps USING btree (command_center_event_id, step_key)"},{"name":"command_center_mission_steps_idempotency_key_key","definition":"CREATE UNIQUE INDEX command_center_mission_steps_idempotency_key_key ON public.command_center_mission_steps USING btree (idempotency_key)"},{"name":"command_center_mission_steps_pkey","definition":"CREATE UNIQUE INDEX command_center_mission_steps_pkey ON public.command_center_mission_steps USING btree (id)"},{"name":"idx_ccms_event_order","definition":"CREATE INDEX idx_ccms_event_order ON public.command_center_mission_steps USING btree (command_center_event_id, step_order)"},{"name":"idx_ccms_runnable","definition":"CREATE INDEX idx_ccms_runnable ON public.command_center_mission_steps USING btree (status, deadline_at, created_at) WHERE (status = ANY (ARRAY['ready'::text, 'running'::text, 'waiting'::text, 'retryable'::text]))"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"command_center_mission_steps","permissive":"PERMISSIVE","policyname":"ccms_insert","schemaname":"public","with_check":"is_command_agent(( SELECT uid() AS uid), tenant_id)"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM command_center_events e\n  WHERE ((e.id = command_center_mission_steps.command_center_event_id) AND is_command_agent(( SELECT uid() AS uid), e.tenant_id))))","roles":["authenticated"],"tablename":"command_center_mission_steps","permissive":"PERMISSIVE","policyname":"ccms_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_command_agent(( SELECT uid() AS uid), tenant_id)","roles":["authenticated"],"tablename":"command_center_mission_steps","permissive":"PERMISSIVE","policyname":"ccms_update","schemaname":"public","with_check":"is_command_agent(( SELECT uid() AS uid), tenant_id)"}],"triggers":[{"name":"trg_ccms_updated_at","definition":"CREATE TRIGGER trg_ccms_updated_at BEFORE UPDATE ON command_center_mission_steps FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"command_center_mission_steps_command_center_event_id_fkey","definition":"FOREIGN KEY (command_center_event_id) REFERENCES command_center_events(id) ON DELETE CASCADE"},{"name":"command_center_mission_steps_command_center_event_id_step_k_key","definition":"UNIQUE (command_center_event_id, step_key)"},{"name":"command_center_mission_steps_idempotency_key_key","definition":"UNIQUE (idempotency_key)"},{"name":"command_center_mission_steps_pkey","definition":"PRIMARY KEY (id)"},{"name":"command_center_mission_steps_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'ready'::text, 'running'::text, 'waiting'::text, 'retryable'::text, 'verified'::text, 'completed_with_findings'::text, 'blocked'::text, 'failed'::text, 'timed_out'::text, 'cancelled'::text, 'skipped'::text, 'superseded'::text]))"}]},{"table":"command_center_receipts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"command_center_event_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"mission_step_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"receipt_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"proof_gate","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_sha","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"idempotency_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"command_center_receipts_idempotency_key_key","definition":"CREATE UNIQUE INDEX command_center_receipts_idempotency_key_key ON public.command_center_receipts USING btree (idempotency_key)"},{"name":"command_center_receipts_mission_step_id_idx","definition":"CREATE INDEX command_center_receipts_mission_step_id_idx ON public.command_center_receipts USING btree (mission_step_id)"},{"name":"command_center_receipts_pkey","definition":"CREATE UNIQUE INDEX command_center_receipts_pkey ON public.command_center_receipts USING btree (id)"},{"name":"idx_ccr_event_created","definition":"CREATE INDEX idx_ccr_event_created ON public.command_center_receipts USING btree (command_center_event_id, created_at DESC)"},{"name":"idx_ccr_external","definition":"CREATE INDEX idx_ccr_external ON public.command_center_receipts USING btree (source, external_id) WHERE (external_id IS NOT NULL)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM command_center_events e\n  WHERE ((e.id = command_center_receipts.command_center_event_id) AND is_command_agent(( SELECT uid() AS uid), e.tenant_id))))","roles":["authenticated"],"tablename":"command_center_receipts","permissive":"PERMISSIVE","policyname":"ccr_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"command_center_receipts_command_center_event_id_fkey","definition":"FOREIGN KEY (command_center_event_id) REFERENCES command_center_events(id) ON DELETE CASCADE"},{"name":"command_center_receipts_idempotency_key_key","definition":"UNIQUE (idempotency_key)"},{"name":"command_center_receipts_mission_step_id_fkey","definition":"FOREIGN KEY (mission_step_id) REFERENCES command_center_mission_steps(id) ON DELETE SET NULL"},{"name":"command_center_receipts_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"command_center_tenant_aliases","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"alias","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"normalized_alias","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'learned'::text","identity":"","not_null":true,"generated":""},{"name":"confidence","type":"double precision","default":"1.0","identity":"","not_null":true,"generated":""},{"name":"use_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_used_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"command_center_tenant_aliases_normalized_idx","definition":"CREATE INDEX command_center_tenant_aliases_normalized_idx ON public.command_center_tenant_aliases USING btree (normalized_alias)"},{"name":"command_center_tenant_aliases_pkey","definition":"CREATE UNIQUE INDEX command_center_tenant_aliases_pkey ON public.command_center_tenant_aliases USING btree (id)"},{"name":"command_center_tenant_aliases_tenant_id_normalized_alias_key","definition":"CREATE UNIQUE INDEX command_center_tenant_aliases_tenant_id_normalized_alias_key ON public.command_center_tenant_aliases USING btree (tenant_id, normalized_alias)"}],"policies":[],"triggers":[],"constraints":[{"name":"command_center_tenant_aliases_confidence_check","definition":"CHECK (confidence >= 0::double precision AND confidence <= 1::double precision)"},{"name":"command_center_tenant_aliases_pkey","definition":"PRIMARY KEY (id)"},{"name":"command_center_tenant_aliases_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"command_center_tenant_aliases_tenant_id_normalized_alias_key","definition":"UNIQUE (tenant_id, normalized_alias)"},{"name":"command_center_tenant_aliases_use_count_check","definition":"CHECK (use_count >= 0)"}]},{"table":"communication_compliance_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_normalized","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"result","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"decision","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_response","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"checked_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"checked_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"communication_compliance_events_pkey","definition":"CREATE UNIQUE INDEX communication_compliance_events_pkey ON public.communication_compliance_events USING btree (id)"},{"name":"idx_cce_lead","definition":"CREATE INDEX idx_cce_lead ON public.communication_compliance_events USING btree (lead_id, checked_at DESC)"},{"name":"idx_cce_tenant_phone","definition":"CREATE INDEX idx_cce_tenant_phone ON public.communication_compliance_events USING btree (tenant_org_id, phone_normalized, checked_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"communication_compliance_events","permissive":"PERMISSIVE","policyname":"tenant_members_insert_cce","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"communication_compliance_events","permissive":"PERMISSIVE","policyname":"tenant_members_view_cce","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"communication_compliance_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"communication_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"direction","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider","type":"text","default":"'twilio'::text","identity":"","not_null":true,"generated":""},{"name":"provider_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"parent_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"homeowner_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voicemail_template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"blocked_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"transcription_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"transcript_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ai_summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"disposition","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"from_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"compliance_disclosure_played","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"consent_logged","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"drop_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"result","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"communication_events_pkey","definition":"CREATE UNIQUE INDEX communication_events_pkey ON public.communication_events USING btree (id)"},{"name":"idx_comm_events_provider_sid","definition":"CREATE INDEX idx_comm_events_provider_sid ON public.communication_events USING btree (tenant_org_id, provider_call_sid) WHERE (provider_call_sid IS NOT NULL)"},{"name":"idx_comm_events_rep","definition":"CREATE INDEX idx_comm_events_rep ON public.communication_events USING btree (rep_id, created_at DESC)"},{"name":"idx_comm_events_rep_today","definition":"CREATE INDEX idx_comm_events_rep_today ON public.communication_events USING btree (rep_id, tenant_org_id, created_at DESC) WHERE (event_type = ANY (ARRAY['call_initiated'::text, 'call_completed'::text, 'call_ended_by_rep'::text, 'outbound_call'::text]))"},{"name":"idx_comm_events_tenant_lead","definition":"CREATE INDEX idx_comm_events_tenant_lead ON public.communication_events USING btree (tenant_org_id, lead_id, created_at DESC)"}],"policies":[{"cmd":"DELETE","qual":"is_system_admin()","roles":["public"],"tablename":"communication_events","permissive":"PERMISSIVE","policyname":"comm_events_admin_delete","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_system_admin()","roles":["public"],"tablename":"communication_events","permissive":"PERMISSIVE","policyname":"comm_events_admin_update","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"communication_events","permissive":"PERMISSIVE","policyname":"comm_events_insert_tenant","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin())"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"communication_events","permissive":"PERMISSIVE","policyname":"comm_events_select_tenant","schemaname":"public","with_check":null}],"triggers":[{"name":"communication_events_activity_projection","definition":"CREATE TRIGGER communication_events_activity_projection AFTER INSERT ON communication_events FOR EACH ROW EXECUTE FUNCTION project_communication_business_activity()"},{"name":"trg_comm_events_updated_at","definition":"CREATE TRIGGER trg_comm_events_updated_at BEFORE UPDATE ON communication_events FOR EACH ROW EXECUTE FUNCTION set_communication_events_updated_at()"}],"constraints":[{"name":"communication_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"communication_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"communication_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"direction","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"communication_log_pkey","definition":"CREATE UNIQUE INDEX communication_log_pkey ON public.communication_log USING btree (id)"},{"name":"idx_comm_log_contact","definition":"CREATE INDEX idx_comm_log_contact ON public.communication_log USING btree (contact_id, created_at DESC)"},{"name":"idx_comm_log_tenant","definition":"CREATE INDEX idx_comm_log_tenant ON public.communication_log USING btree (tenant_org_id, created_at DESC)"},{"name":"idx_comm_log_user","definition":"CREATE INDEX idx_comm_log_user ON public.communication_log USING btree (user_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND ((user_roles.tenant_id)::text = communication_log.tenant_org_id) AND (user_roles.role = 'Owner'::app_role))))","roles":["authenticated"],"tablename":"communication_log","permissive":"PERMISSIVE","policyname":"Tenant owners view tenant communication logs","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"communication_log","permissive":"PERMISSIVE","policyname":"Users insert own communication logs","schemaname":"public","with_check":"(user_id = (uid())::text)"},{"cmd":"UPDATE","qual":"(user_id = (uid())::text)","roles":["authenticated"],"tablename":"communication_log","permissive":"PERMISSIVE","policyname":"Users update own communication logs","schemaname":"public","with_check":"(user_id = (uid())::text)"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM unified_contacts\n  WHERE (((unified_contacts.id)::text = communication_log.contact_id) AND ((unified_contacts.assigned_to = (uid())::text) OR (lower(unified_contacts.assigned_to) = lower(( SELECT profiles.email\n           FROM profiles\n          WHERE (profiles.id = uid()))))))))","roles":["authenticated"],"tablename":"communication_log","permissive":"PERMISSIVE","policyname":"Users view assigned contact communication logs","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"communication_log","permissive":"PERMISSIVE","policyname":"platform_admin_view_communication_log","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"communication_log_communication_type_check","definition":"CHECK (communication_type = ANY (ARRAY['call'::text, 'sms'::text, 'email'::text, 'note'::text]))"},{"name":"communication_log_direction_check","definition":"CHECK (direction = ANY (ARRAY['inbound'::text, 'outbound'::text]))"},{"name":"communication_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"communication_sequence_steps","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"sequence_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"step_order","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"step_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"delay_minutes","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"subject","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"condition_config","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"task_config","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"communication_sequence_steps_pkey","definition":"CREATE UNIQUE INDEX communication_sequence_steps_pkey ON public.communication_sequence_steps USING btree (id)"},{"name":"idx_sequence_steps_order","definition":"CREATE INDEX idx_sequence_steps_order ON public.communication_sequence_steps USING btree (sequence_id, step_order)"}],"policies":[{"cmd":"ALL","qual":"(sequence_id IN ( SELECT communication_sequences.id\n   FROM communication_sequences\n  WHERE (communication_sequences.tenant_org_id IN ( SELECT user_roles.tenant_id\n           FROM user_roles\n          WHERE (user_roles.user_id = uid())))))","roles":["public"],"tablename":"communication_sequence_steps","permissive":"PERMISSIVE","policyname":"Tenant isolation for sequence_steps","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"communication_sequence_steps_pkey","definition":"PRIMARY KEY (id)"},{"name":"communication_sequence_steps_step_type_check","definition":"CHECK (step_type = ANY (ARRAY['email'::text, 'sms'::text, 'wait'::text, 'condition'::text, 'task'::text]))"}]},{"table":"communication_sequences","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"trigger_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"trigger_config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"steps","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"total_enrollments","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"active_enrollments","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"completion_rate","type":"numeric(5,2)","default":"0","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"communication_sequences_pkey","definition":"CREATE UNIQUE INDEX communication_sequences_pkey ON public.communication_sequences USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"communication_sequences","permissive":"PERMISSIVE","policyname":"Tenant isolation for communication_sequences","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"communication_sequences_pkey","definition":"PRIMARY KEY (id)"},{"name":"communication_sequences_trigger_type_check","definition":"CHECK (trigger_type = ANY (ARRAY['manual'::text, 'status'::text, 'stage'::text, 'event'::text]))"}]},{"table":"communication_setup_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"channel","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"request_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"requested_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'requested'::text","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"admin_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"requested_by","type":"uuid","default":"uid()","identity":"","not_null":true,"generated":""},{"name":"resolved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"communication_setup_requests_one_active_per_channel","definition":"CREATE UNIQUE INDEX communication_setup_requests_one_active_per_channel ON public.communication_setup_requests USING btree (tenant_id, channel) WHERE (status = ANY (ARRAY['requested'::text, 'in_progress'::text, 'needs_info'::text]))"},{"name":"communication_setup_requests_pkey","definition":"CREATE UNIQUE INDEX communication_setup_requests_pkey ON public.communication_setup_requests USING btree (id)"},{"name":"communication_setup_requests_queue_idx","definition":"CREATE INDEX communication_setup_requests_queue_idx ON public.communication_setup_requests USING btree (status, created_at DESC)"},{"name":"communication_setup_requests_tenant_idx","definition":"CREATE INDEX communication_setup_requests_tenant_idx ON public.communication_setup_requests USING btree (tenant_id, channel, created_at DESC)"}],"policies":[{"cmd":"DELETE","qual":"is_system_admin()","roles":["public"],"tablename":"communication_setup_requests","permissive":"PERMISSIVE","policyname":"communication_setup_requests_admin_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"communication_setup_requests","permissive":"PERMISSIVE","policyname":"communication_setup_requests_tenant_insert","schemaname":"public","with_check":"((is_tenant_member(uid(), tenant_id) AND (requested_by = uid()) AND (status = 'requested'::text)) OR is_system_admin())"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["public"],"tablename":"communication_setup_requests","permissive":"PERMISSIVE","policyname":"communication_setup_requests_tenant_read","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["public"],"tablename":"communication_setup_requests","permissive":"PERMISSIVE","policyname":"communication_setup_requests_tenant_update","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())"}],"triggers":[{"name":"communication_setup_mail_continuity_seed","definition":"CREATE TRIGGER communication_setup_mail_continuity_seed AFTER INSERT OR UPDATE OF requested_value, status ON communication_setup_requests FOR EACH ROW EXECUTE FUNCTION seed_mail_continuity_from_email_setup()"},{"name":"communication_setup_requests_guard_update","definition":"CREATE TRIGGER communication_setup_requests_guard_update BEFORE UPDATE ON communication_setup_requests FOR EACH ROW EXECUTE FUNCTION guard_communication_setup_request_update()"}],"constraints":[{"name":"communication_setup_requests_channel_check","definition":"CHECK (channel = ANY (ARRAY['phone'::text, 'email'::text]))"},{"name":"communication_setup_requests_pkey","definition":"PRIMARY KEY (id)"},{"name":"communication_setup_requests_request_type_check","definition":"CHECK (request_type = ANY (ARRAY['managed'::text, 'connect_existing'::text]))"},{"name":"communication_setup_requests_status_check","definition":"CHECK (status = ANY (ARRAY['requested'::text, 'in_progress'::text, 'needs_info'::text, 'connected'::text, 'declined'::text]))"},{"name":"communication_setup_requests_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"community_shoutout_reactions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"shoutout_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"reaction_key_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"community_shoutout_reactions_pkey","definition":"CREATE UNIQUE INDEX community_shoutout_reactions_pkey ON public.community_shoutout_reactions USING btree (id)"},{"name":"community_shoutout_reactions_shoutout_key_unique","definition":"CREATE UNIQUE INDEX community_shoutout_reactions_shoutout_key_unique ON public.community_shoutout_reactions USING btree (shoutout_id, reaction_key_hash)"},{"name":"community_shoutout_reactions_tenant_idx","definition":"CREATE INDEX community_shoutout_reactions_tenant_idx ON public.community_shoutout_reactions USING btree (tenant_org_id, created_at DESC)"}],"policies":[],"triggers":[{"name":"community_shoutout_reaction_increment","definition":"CREATE TRIGGER community_shoutout_reaction_increment AFTER INSERT ON community_shoutout_reactions FOR EACH ROW EXECUTE FUNCTION increment_community_shoutout_heart_count()"}],"constraints":[{"name":"community_shoutout_reactions_pkey","definition":"PRIMARY KEY (id)"},{"name":"community_shoutout_reactions_shoutout_id_fkey","definition":"FOREIGN KEY (shoutout_id) REFERENCES community_shoutouts(id) ON DELETE CASCADE"},{"name":"community_shoutout_reactions_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"community_shoutouts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"business_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"social_handle","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"submitter_key_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"heart_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"approved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"approved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"community_shoutouts_pkey","definition":"CREATE UNIQUE INDEX community_shoutouts_pkey ON public.community_shoutouts USING btree (id)"},{"name":"community_shoutouts_submitter_created_idx","definition":"CREATE INDEX community_shoutouts_submitter_created_idx ON public.community_shoutouts USING btree (tenant_org_id, submitter_key_hash, created_at DESC)"},{"name":"community_shoutouts_tenant_status_created_idx","definition":"CREATE INDEX community_shoutouts_tenant_status_created_idx ON public.community_shoutouts USING btree (tenant_org_id, status, created_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"community_shoutouts_approved_by_fkey","definition":"FOREIGN KEY (approved_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"community_shoutouts_business_name_check","definition":"CHECK (char_length(business_name) >= 2 AND char_length(business_name) <= 120)"},{"name":"community_shoutouts_heart_count_check","definition":"CHECK (heart_count >= 0)"},{"name":"community_shoutouts_message_check","definition":"CHECK (char_length(message) >= 3 AND char_length(message) <= 500)"},{"name":"community_shoutouts_pkey","definition":"PRIMARY KEY (id)"},{"name":"community_shoutouts_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'approved'::text, 'hidden'::text]))"},{"name":"community_shoutouts_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"competitor_sightings","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"territory_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"competitor_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"sighted_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"location","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reported_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"competitor_sightings_pkey","definition":"CREATE UNIQUE INDEX competitor_sightings_pkey ON public.competitor_sightings USING btree (id)"},{"name":"idx_competitor_sightings_territory","definition":"CREATE INDEX idx_competitor_sightings_territory ON public.competitor_sightings USING btree (territory_id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = competitor_sightings.tenant_org_id))))","roles":["public"],"tablename":"competitor_sightings","permissive":"PERMISSIVE","policyname":"Tenant members view competitor sightings","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"competitor_sightings","permissive":"PERMISSIVE","policyname":"Users create competitor sightings","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = competitor_sightings.tenant_org_id))))"}],"triggers":[],"constraints":[{"name":"competitor_sightings_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"compliance_audit_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"audit_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"findings","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"score","type":"integer","default":"100","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"compliance_audit_runs_pkey","definition":"CREATE UNIQUE INDEX compliance_audit_runs_pkey ON public.compliance_audit_runs USING btree (id)"},{"name":"compliance_audit_runs_unique","definition":"CREATE UNIQUE INDEX compliance_audit_runs_unique ON public.compliance_audit_runs USING btree (audit_date, tenant_org_id)"},{"name":"idx_compliance_audit_tenant_date","definition":"CREATE INDEX idx_compliance_audit_tenant_date ON public.compliance_audit_runs USING btree (tenant_org_id, audit_date DESC)"}],"policies":[{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["authenticated"],"tablename":"compliance_audit_runs","permissive":"PERMISSIVE","policyname":"tenant_members_view_audit","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"compliance_audit_runs_pkey","definition":"PRIMARY KEY (id)"},{"name":"compliance_audit_runs_score_check","definition":"CHECK (score >= 0 AND score <= 100)"},{"name":"compliance_audit_runs_unique","definition":"UNIQUE (audit_date, tenant_org_id)"}]},{"table":"compliance_provider_settings","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rnd_enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"rnd_provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rnd_block_on_yes","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"rnd_require_override_on_no_data","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"rnd_default_date_strategy","type":"text","default":"'import_date'::text","identity":"","not_null":true,"generated":""},{"name":"litigator_suppression_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"frequency_cap_max_attempts","type":"integer","default":"3","identity":"","not_null":true,"generated":""},{"name":"frequency_cap_window_days","type":"integer","default":"30","identity":"","not_null":true,"generated":""},{"name":"frequency_cap_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"recording_disclosure_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"recording_disclosure_text","type":"text","default":"'This call may be recorded for quality and compliance.'::text","identity":"","not_null":true,"generated":""},{"name":"florida_dnc_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"compliance_provider_settings_pkey","definition":"CREATE UNIQUE INDEX compliance_provider_settings_pkey ON public.compliance_provider_settings USING btree (id)"},{"name":"compliance_provider_settings_tenant_org_id_key","definition":"CREATE UNIQUE INDEX compliance_provider_settings_tenant_org_id_key ON public.compliance_provider_settings USING btree (tenant_org_id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"compliance_provider_settings","permissive":"PERMISSIVE","policyname":"tenant_members_view_compliance_settings","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) AND (is_system_admin() OR (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = compliance_provider_settings.tenant_org_id) AND (ur.role = ANY (ARRAY['Tenant Owner'::app_role, 'Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))))","roles":["authenticated"],"tablename":"compliance_provider_settings","permissive":"PERMISSIVE","policyname":"tenant_owners_manage_compliance_settings","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"}],"triggers":[{"name":"trg_compliance_settings_updated_at","definition":"CREATE TRIGGER trg_compliance_settings_updated_at BEFORE UPDATE ON compliance_provider_settings FOR EACH ROW EXECUTE FUNCTION touch_compliance_settings_updated_at()"}],"constraints":[{"name":"compliance_provider_settings_pkey","definition":"PRIMARY KEY (id)"},{"name":"compliance_provider_settings_tenant_org_id_key","definition":"UNIQUE (tenant_org_id)"}]},{"table":"compliance_test_numbers","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_normalized","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"added_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"compliance_test_numbers_pkey","definition":"CREATE UNIQUE INDEX compliance_test_numbers_pkey ON public.compliance_test_numbers USING btree (id)"},{"name":"compliance_test_numbers_tenant_org_id_phone_normalized_key","definition":"CREATE UNIQUE INDEX compliance_test_numbers_tenant_org_id_phone_normalized_key ON public.compliance_test_numbers USING btree (tenant_org_id, phone_normalized)"},{"name":"idx_compliance_test_numbers_phone","definition":"CREATE INDEX idx_compliance_test_numbers_phone ON public.compliance_test_numbers USING btree (phone_normalized)"}],"policies":[{"cmd":"DELETE","qual":"(is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_owner_for(uid(), tenant_org_id)))","roles":["authenticated"],"tablename":"compliance_test_numbers","permissive":"PERMISSIVE","policyname":"test_numbers_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"compliance_test_numbers","permissive":"PERMISSIVE","policyname":"test_numbers_insert","schemaname":"public","with_check":"(is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_owner_for(uid(), tenant_org_id)))"},{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"compliance_test_numbers","permissive":"PERMISSIVE","policyname":"test_numbers_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"compliance_test_numbers_pkey","definition":"PRIMARY KEY (id)"},{"name":"compliance_test_numbers_tenant_org_id_phone_normalized_key","definition":"UNIQUE (tenant_org_id, phone_normalized)"}]},{"table":"compliance_violations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"violation_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"attempted_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"details","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"acknowledged_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"acknowledged_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"compliance_violations_pkey","definition":"CREATE UNIQUE INDEX compliance_violations_pkey ON public.compliance_violations USING btree (id)"},{"name":"idx_compliance_violations_tenant","definition":"CREATE INDEX idx_compliance_violations_tenant ON public.compliance_violations USING btree (tenant_id, created_at DESC)"},{"name":"idx_compliance_violations_user","definition":"CREATE INDEX idx_compliance_violations_user ON public.compliance_violations USING btree (user_id, created_at DESC)"}],"policies":[{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR ((tenant_id IS NOT NULL) AND has_role(uid(), tenant_id, 'Owner'::app_role)))","roles":["authenticated"],"tablename":"compliance_violations","permissive":"PERMISSIVE","policyname":"Acknowledge violations: admins and owners","schemaname":"public","with_check":"(is_system_admin(uid()) OR ((tenant_id IS NOT NULL) AND has_role(uid(), tenant_id, 'Owner'::app_role)))"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"compliance_violations","permissive":"PERMISSIVE","policyname":"Users log their own violations","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (uid() = user_id) OR ((tenant_id IS NOT NULL) AND has_role(uid(), tenant_id, 'Owner'::app_role)))","roles":["authenticated"],"tablename":"compliance_violations","permissive":"PERMISSIVE","policyname":"View violations: admins, owners, self","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"compliance_violations_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"comprehensive_audit_logs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"timestamp","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"resource_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"resource_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"resource_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"old_value","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_value","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"ip_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"session_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"request_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"success","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"severity","type":"text","default":"'info'::text","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"human_summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_fields","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"comprehensive_audit_logs_impersonation_lookup_idx","definition":"CREATE INDEX comprehensive_audit_logs_impersonation_lookup_idx ON public.comprehensive_audit_logs USING btree (user_id, event_action, tenant_id, resource_id, \"timestamp\" DESC) WHERE (event_category = 'admin'::text)"},{"name":"comprehensive_audit_logs_pkey","definition":"CREATE UNIQUE INDEX comprehensive_audit_logs_pkey ON public.comprehensive_audit_logs USING btree (id)"},{"name":"idx_comprehensive_audit_event_category","definition":"CREATE INDEX idx_comprehensive_audit_event_category ON public.comprehensive_audit_logs USING btree (event_category)"},{"name":"idx_comprehensive_audit_event_type","definition":"CREATE INDEX idx_comprehensive_audit_event_type ON public.comprehensive_audit_logs USING btree (event_type)"},{"name":"idx_comprehensive_audit_resource","definition":"CREATE INDEX idx_comprehensive_audit_resource ON public.comprehensive_audit_logs USING btree (resource_type, resource_id)"},{"name":"idx_comprehensive_audit_severity","definition":"CREATE INDEX idx_comprehensive_audit_severity ON public.comprehensive_audit_logs USING btree (severity) WHERE (severity = ANY (ARRAY['warn'::text, 'error'::text, 'critical'::text]))"},{"name":"idx_comprehensive_audit_tenant","definition":"CREATE INDEX idx_comprehensive_audit_tenant ON public.comprehensive_audit_logs USING btree (tenant_id)"},{"name":"idx_comprehensive_audit_timestamp","definition":"CREATE INDEX idx_comprehensive_audit_timestamp ON public.comprehensive_audit_logs USING btree (\"timestamp\" DESC)"},{"name":"idx_comprehensive_audit_user","definition":"CREATE INDEX idx_comprehensive_audit_user ON public.comprehensive_audit_logs USING btree (user_id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"comprehensive_audit_logs","permissive":"PERMISSIVE","policyname":"godmode_full_access_audit","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role])))))","roles":["authenticated"],"tablename":"comprehensive_audit_logs","permissive":"PERMISSIVE","policyname":"tenant_admins_view_audit","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"comprehensive_audit_logs","permissive":"PERMISSIVE","policyname":"users_view_own_audit","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"comprehensive_audit_logs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"config_history","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"config_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"old_value","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_value","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"config_history_pkey","definition":"CREATE UNIQUE INDEX config_history_pkey ON public.config_history USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"config_history","permissive":"PERMISSIVE","policyname":"platform_admin_view_config_history","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"config_history_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"consent_ledger","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_normalized","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"consent_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"consent_status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"capture_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signature_artifact_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"granted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"revocation_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"captured_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"consent_ledger_pkey","definition":"CREATE UNIQUE INDEX consent_ledger_pkey ON public.consent_ledger USING btree (id)"},{"name":"idx_consent_lead","definition":"CREATE INDEX idx_consent_lead ON public.consent_ledger USING btree (lead_id)"},{"name":"idx_consent_tenant_phone","definition":"CREATE INDEX idx_consent_tenant_phone ON public.consent_ledger USING btree (tenant_org_id, phone_normalized, granted_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"consent_ledger","permissive":"PERMISSIVE","policyname":"tenant_members_insert_consent","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"},{"cmd":"UPDATE","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"consent_ledger","permissive":"PERMISSIVE","policyname":"tenant_members_update_consent","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"consent_ledger","permissive":"PERMISSIVE","policyname":"tenant_members_view_consent","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"consent_ledger_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"contact_assignments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assignment_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"can_edit","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"can_view_notes","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"assigned_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"contact_assignments_contact_id_user_id_tenant_id_key","definition":"CREATE UNIQUE INDEX contact_assignments_contact_id_user_id_tenant_id_key ON public.contact_assignments USING btree (contact_id, user_id, tenant_id)"},{"name":"contact_assignments_pkey","definition":"CREATE UNIQUE INDEX contact_assignments_pkey ON public.contact_assignments USING btree (id)"},{"name":"idx_contact_assignments_contact","definition":"CREATE INDEX idx_contact_assignments_contact ON public.contact_assignments USING btree (contact_id)"},{"name":"idx_contact_assignments_tenant","definition":"CREATE INDEX idx_contact_assignments_tenant ON public.contact_assignments USING btree (tenant_id)"},{"name":"idx_contact_assignments_user","definition":"CREATE INDEX idx_contact_assignments_user ON public.contact_assignments USING btree (user_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"contact_assignments","permissive":"PERMISSIVE","policyname":"Users create contact assignments","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN unified_contacts uc ON ((uc.tenant_org_id = (ur.tenant_id)::text)))\n  WHERE ((ur.user_id = uid()) AND (uc.id = contact_assignments.contact_id)))) OR is_system_admin(uid()))"},{"cmd":"DELETE","qual":"((assigned_by = uid()) OR is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND (ur.tenant_id = contact_assignments.tenant_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))","roles":["public"],"tablename":"contact_assignments","permissive":"PERMISSIVE","policyname":"Users delete contact assignments","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((assigned_by = uid()) OR is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND (ur.tenant_id = contact_assignments.tenant_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))","roles":["public"],"tablename":"contact_assignments","permissive":"PERMISSIVE","policyname":"Users update contact assignments","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((user_id = uid()) OR is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND (contact_assignments.tenant_id = ur.tenant_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))","roles":["public"],"tablename":"contact_assignments","permissive":"PERMISSIVE","policyname":"Users view contact assignments","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(COALESCE(is_system_admin(uid()), false) OR (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.tenant_id = contact_assignments.tenant_id) AND (m.user_id = uid()) AND (m.status = 'active'::text)))))","roles":["authenticated"],"tablename":"contact_assignments","permissive":"RESTRICTIVE","policyname":"contact_assignments_active_tenant_scope","schemaname":"public","with_check":"(COALESCE(is_system_admin(uid()), false) OR (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.tenant_id = contact_assignments.tenant_id) AND (m.user_id = uid()) AND (m.status = 'active'::text)))))"}],"triggers":[{"name":"contact_assignment_platform_journal","definition":"CREATE TRIGGER contact_assignment_platform_journal AFTER INSERT OR DELETE OR UPDATE ON contact_assignments FOR EACH ROW EXECUTE FUNCTION journal_contact_assignment()"},{"name":"contact_assignment_tenant_integrity","definition":"CREATE TRIGGER contact_assignment_tenant_integrity BEFORE INSERT OR UPDATE OF tenant_id, contact_id, user_id ON contact_assignments FOR EACH ROW EXECUTE FUNCTION enforce_contact_assignment_tenant_context()"}],"constraints":[{"name":"contact_assignments_contact_id_user_id_tenant_id_key","definition":"UNIQUE (contact_id, user_id, tenant_id)"},{"name":"contact_assignments_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"contact_claims","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"slot_number","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"claim_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"carrier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"carrier_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"date_of_loss","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_type","type":"text","default":"'Other'::text","identity":"","not_null":false,"generated":""},{"name":"claim_status","type":"text","default":"'Open'::text","identity":"","not_null":false,"generated":""},{"name":"adjuster_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"deductible","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"coverage_a","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"settlement_amount","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"fee_percentage","type":"numeric(5,2)","default":"10.00","identity":"","not_null":false,"generated":""},{"name":"fee_amount","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"fee_status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"settlement_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"referral_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"referral_partner_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_issued_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_issued_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_issued_amount","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_issued_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_issued_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_received_by_homeowner_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_received_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payment_pipeline_status","type":"payment_pipeline_status","default":null,"identity":"","not_null":false,"generated":""},{"name":"cause_of_loss","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"representation_agreement_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pa_inspection_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"carrier_inspection_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"estimate_amount","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"pa_estimate_amount","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_payment_status","type":"claim_payment_lifecycle_v4","default":"'claim_not_started'::claim_payment_lifecycle_v4","identity":"","not_null":true,"generated":""},{"name":"claim_payment_status_updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_payment_status_updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_effective_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_expiration_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"coverage_b","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"coverage_c","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"coverage_d","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"mortgage_company","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"loss_cause","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_filed_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"carrier_acknowledged_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"inspection_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"carrier_offer_amount","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"pa_demand_amount","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"prior_pa_or_attorney_involved","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"homeowner_occupied","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"damage_summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"interior_damage","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"exterior_damage","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_damage","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"water_damage","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"emergency_mitigation_done","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"best_contact_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"preferred_contact_time","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"expected_fee_amount","type":"numeric","default":"\nCASE\n    WHEN ((settlement_amount IS NOT NULL) AND (fee_percentage IS NOT NULL)) THEN round(((settlement_amount * fee_percentage) / 100.0), 2)\n    ELSE NULL::numeric\nEND","identity":"","not_null":false,"generated":"s"},{"name":"next_action","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"call_disposition","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"consultation_requested","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"last_call_captured_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_call_captured_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_stage","type":"text","default":"'P1_INTRO'::text","identity":"","not_null":true,"generated":""},{"name":"canonical_contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"contact_claims_pkey","definition":"CREATE UNIQUE INDEX contact_claims_pkey ON public.contact_claims USING btree (id)"},{"name":"contact_claims_unique_slot","definition":"CREATE UNIQUE INDEX contact_claims_unique_slot ON public.contact_claims USING btree (contact_id, tenant_org_id, slot_number)"},{"name":"idx_contact_claims_cause","definition":"CREATE INDEX idx_contact_claims_cause ON public.contact_claims USING btree (tenant_org_id, cause_of_loss)"},{"name":"idx_contact_claims_contact","definition":"CREATE INDEX idx_contact_claims_contact ON public.contact_claims USING btree (contact_id, tenant_org_id)"},{"name":"idx_contact_claims_fee_status","definition":"CREATE INDEX idx_contact_claims_fee_status ON public.contact_claims USING btree (fee_status) WHERE (fee_status IS NOT NULL)"},{"name":"idx_contact_claims_rep_status","definition":"CREATE INDEX idx_contact_claims_rep_status ON public.contact_claims USING btree (tenant_org_id, representation_agreement_status)"},{"name":"idx_contact_claims_tenant","definition":"CREATE INDEX idx_contact_claims_tenant ON public.contact_claims USING btree (tenant_org_id)"},{"name":"idx_contact_claims_tenant_stage","definition":"CREATE INDEX idx_contact_claims_tenant_stage ON public.contact_claims USING btree (tenant_org_id, claim_stage)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"contact_claims","permissive":"PERMISSIVE","policyname":"Tenant members can create claims","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"contact_claims","permissive":"PERMISSIVE","policyname":"Tenant members can delete claims","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"contact_claims","permissive":"PERMISSIVE","policyname":"Tenant members can update claims","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"contact_claims","permissive":"PERMISSIVE","policyname":"Tenant members can view claims","schemaname":"public","with_check":null}],"triggers":[{"name":"contact_claims_business_activity","definition":"CREATE TRIGGER contact_claims_business_activity AFTER INSERT OR UPDATE ON contact_claims FOR EACH ROW EXECUTE FUNCTION project_claim_business_activity()"},{"name":"revoke_customer_portal_when_claims_close","definition":"CREATE TRIGGER revoke_customer_portal_when_claims_close AFTER DELETE OR UPDATE OF claim_stage ON contact_claims FOR EACH ROW EXECUTE FUNCTION revoke_customer_portal_when_claims_close()"},{"name":"trg_auto_stamp_claim_check_issued","definition":"CREATE TRIGGER trg_auto_stamp_claim_check_issued BEFORE INSERT OR UPDATE OF settlement_amount, settlement_date ON contact_claims FOR EACH ROW EXECUTE FUNCTION auto_stamp_claim_check_issued()"},{"name":"trg_dispatch_homeowner_update_on_claim_stage","definition":"CREATE TRIGGER trg_dispatch_homeowner_update_on_claim_stage AFTER UPDATE OF claim_status ON contact_claims FOR EACH ROW EXECUTE FUNCTION dispatch_homeowner_claim_stage_update()"},{"name":"trg_run_pa_claim_automation_rules","definition":"CREATE TRIGGER trg_run_pa_claim_automation_rules AFTER UPDATE OF claim_stage ON contact_claims FOR EACH ROW WHEN (old.claim_stage IS DISTINCT FROM new.claim_stage) EXECUTE FUNCTION run_pa_claim_automation_rules()"},{"name":"trg_seed_statutory_deadlines","definition":"CREATE TRIGGER trg_seed_statutory_deadlines AFTER INSERT ON contact_claims FOR EACH ROW EXECUTE FUNCTION seed_statutory_deadlines()"},{"name":"update_contact_claims_updated_at","definition":"CREATE TRIGGER update_contact_claims_updated_at BEFORE UPDATE ON contact_claims FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"contact_claims_canonical_contact_fkey","definition":"FOREIGN KEY (canonical_contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"contact_claims_claim_stage_check","definition":"CHECK (claim_stage = ANY (ARRAY['P1_INTRO'::text, 'P2_SCREEN'::text, 'P3_SIGN'::text, 'P4_SCHEDULE'::text, 'P5_DOCS'::text, 'P6_NEGOTIATE'::text, 'P7_CLOSE'::text]))"},{"name":"contact_claims_pkey","definition":"PRIMARY KEY (id)"},{"name":"contact_claims_slot_check","definition":"CHECK (slot_number >= 1)"},{"name":"contact_claims_unique_slot","definition":"UNIQUE (contact_id, tenant_org_id, slot_number)"}]},{"table":"contact_communication_preferences","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"email_enabled","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"sms_enabled","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"call_enabled","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"preferred_channel","type":"text","default":"'email'::text","identity":"","not_null":false,"generated":""},{"name":"preferred_time_start","type":"time without time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"preferred_time_end","type":"time without time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"timezone","type":"text","default":"'America/New_York'::text","identity":"","not_null":false,"generated":""},{"name":"do_not_contact_until","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"contact_communication_preferences_pkey","definition":"CREATE UNIQUE INDEX contact_communication_preferences_pkey ON public.contact_communication_preferences USING btree (id)"},{"name":"contact_communication_preferences_tenant_id_contact_id_key","definition":"CREATE UNIQUE INDEX contact_communication_preferences_tenant_id_contact_id_key ON public.contact_communication_preferences USING btree (tenant_id, contact_id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"contact_communication_preferences","permissive":"PERMISSIVE","policyname":"Tenant isolation for contact_preferences","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"contact_communication_preferences_pkey","definition":"PRIMARY KEY (id)"},{"name":"contact_communication_preferences_tenant_id_contact_id_key","definition":"UNIQUE (tenant_id, contact_id)"}]},{"table":"contact_files","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_size","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"mime_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"public_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"extracted_metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"drive_file_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"drive_sync_status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"drive_synced_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"folder","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tags","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"contact_files_pkey","definition":"CREATE UNIQUE INDEX contact_files_pkey ON public.contact_files USING btree (id)"},{"name":"idx_contact_files_archived","definition":"CREATE INDEX idx_contact_files_archived ON public.contact_files USING btree (tenant_org_id, archived_at)"},{"name":"idx_contact_files_claim","definition":"CREATE INDEX idx_contact_files_claim ON public.contact_files USING btree (claim_id)"},{"name":"idx_contact_files_contact_id","definition":"CREATE INDEX idx_contact_files_contact_id ON public.contact_files USING btree (contact_id)"},{"name":"idx_contact_files_created_at","definition":"CREATE INDEX idx_contact_files_created_at ON public.contact_files USING btree (created_at DESC)"},{"name":"idx_contact_files_drive_file_id","definition":"CREATE INDEX idx_contact_files_drive_file_id ON public.contact_files USING btree (drive_file_id) WHERE (drive_file_id IS NOT NULL)"},{"name":"idx_contact_files_drive_sync_status","definition":"CREATE INDEX idx_contact_files_drive_sync_status ON public.contact_files USING btree (drive_sync_status)"},{"name":"idx_contact_files_folder","definition":"CREATE INDEX idx_contact_files_folder ON public.contact_files USING btree (tenant_org_id, folder) WHERE (folder IS NOT NULL)"},{"name":"idx_contact_files_tags","definition":"CREATE INDEX idx_contact_files_tags ON public.contact_files USING gin (tags)"},{"name":"idx_contact_files_tenant_org_id","definition":"CREATE INDEX idx_contact_files_tenant_org_id ON public.contact_files USING btree (tenant_org_id)"}],"policies":[{"cmd":"DELETE","qual":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.status = 'active'::text)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"contact_files","permissive":"PERMISSIVE","policyname":"Users can delete files for their tenant","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"contact_files","permissive":"PERMISSIVE","policyname":"Users can insert files for their tenant","schemaname":"public","with_check":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.status = 'active'::text)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.status = 'active'::text)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"contact_files","permissive":"PERMISSIVE","policyname":"Users can update files for their tenant","schemaname":"public","with_check":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.status = 'active'::text)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.status = 'active'::text)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"contact_files","permissive":"PERMISSIVE","policyname":"Users can view files for their tenant","schemaname":"public","with_check":null}],"triggers":[{"name":"audit_trigger_contact_files","definition":"CREATE TRIGGER audit_trigger_contact_files AFTER INSERT OR DELETE OR UPDATE ON contact_files FOR EACH ROW EXECUTE FUNCTION comprehensive_audit_trigger_fn()"}],"constraints":[{"name":"contact_files_file_type_check","definition":"CHECK (file_type = ANY (ARRAY['doc'::text, 'photo'::text, 'audio'::text, 'video'::text, 'document'::text, 'other'::text]))"},{"name":"contact_files_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"contact_links","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"link_group_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_origin","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"contact_links_contact_id_tenant_id_key","definition":"CREATE UNIQUE INDEX contact_links_contact_id_tenant_id_key ON public.contact_links USING btree (contact_id, tenant_id)"},{"name":"contact_links_pkey","definition":"CREATE UNIQUE INDEX contact_links_pkey ON public.contact_links USING btree (id)"},{"name":"idx_contact_links_contact","definition":"CREATE INDEX idx_contact_links_contact ON public.contact_links USING btree (contact_id)"},{"name":"idx_contact_links_group","definition":"CREATE INDEX idx_contact_links_group ON public.contact_links USING btree (link_group_id)"},{"name":"idx_contact_links_tenant","definition":"CREATE INDEX idx_contact_links_tenant ON public.contact_links USING btree (tenant_id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"contact_links","permissive":"PERMISSIVE","policyname":"System admins can manage contact links","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"is_tenant_member((tenant_id)::text)","roles":["authenticated"],"tablename":"contact_links","permissive":"PERMISSIVE","policyname":"Tenant members can view their contact links","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(link_group_id IN ( SELECT get_user_link_group_ids() AS get_user_link_group_ids))","roles":["authenticated"],"tablename":"contact_links","permissive":"PERMISSIVE","policyname":"Users can view linked group members","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"contact_links_contact_id_tenant_id_key","definition":"UNIQUE (contact_id, tenant_id)"},{"name":"contact_links_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"contact_note_revisions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"note_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"previous_content","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"edited_by_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"edited_by_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"contact_note_revisions_pkey","definition":"CREATE UNIQUE INDEX contact_note_revisions_pkey ON public.contact_note_revisions USING btree (id)"},{"name":"idx_note_revisions_note","definition":"CREATE INDEX idx_note_revisions_note ON public.contact_note_revisions USING btree (note_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"contact_note_revisions","permissive":"PERMISSIVE","policyname":"Authenticated users can insert revisions","schemaname":"public","with_check":"(edited_by_id = uid())"},{"cmd":"SELECT","qual":"(note_id IN ( SELECT cn.id\n   FROM contact_notes cn\n  WHERE (cn.tenant_org_id IN ( SELECT user_tenant_memberships.tenant_id\n           FROM security_active_user_tenant_memberships user_tenant_memberships\n          WHERE (user_tenant_memberships.user_id = uid())))))","roles":["authenticated"],"tablename":"contact_note_revisions","permissive":"PERMISSIVE","policyname":"Tenant members can view revisions","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"contact_note_revisions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"contact_notes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"note_type","type":"text","default":"'general'::text","identity":"","not_null":true,"generated":""},{"name":"content","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"contact_notes_pkey","definition":"CREATE UNIQUE INDEX contact_notes_pkey ON public.contact_notes USING btree (id)"},{"name":"idx_contact_notes_claim","definition":"CREATE INDEX idx_contact_notes_claim ON public.contact_notes USING btree (claim_id)"},{"name":"idx_contact_notes_contact","definition":"CREATE INDEX idx_contact_notes_contact ON public.contact_notes USING btree (contact_id)"},{"name":"idx_contact_notes_tenant","definition":"CREATE INDEX idx_contact_notes_tenant ON public.contact_notes USING btree (tenant_org_id)"}],"policies":[{"cmd":"DELETE","qual":"is_admin_or_higher(tenant_org_id, uid())","roles":["authenticated"],"tablename":"contact_notes","permissive":"PERMISSIVE","policyname":"Admins and owners can delete notes","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"contact_notes","permissive":"PERMISSIVE","policyname":"Authenticated users can insert notes","schemaname":"public","with_check":"((tenant_org_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) AND (user_id = uid()))"},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["authenticated"],"tablename":"contact_notes","permissive":"PERMISSIVE","policyname":"Tenant members can view notes","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"contact_notes","permissive":"PERMISSIVE","policyname":"Users can edit own notes","schemaname":"public","with_check":"(user_id = uid())"}],"triggers":[],"constraints":[{"name":"contact_notes_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"contact_photos","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phase","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tags","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"drive_file_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"drive_sync_status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"drive_synced_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"slope","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"exif_lat","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"exif_lng","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"exif_taken_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_slope","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_slope_confidence","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"damage_indicators","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"damage_severity","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ai_analyzed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"contact_photos_pkey","definition":"CREATE UNIQUE INDEX contact_photos_pkey ON public.contact_photos USING btree (id)"},{"name":"idx_contact_photos_claim","definition":"CREATE INDEX idx_contact_photos_claim ON public.contact_photos USING btree (claim_id)"},{"name":"idx_contact_photos_contact_id","definition":"CREATE INDEX idx_contact_photos_contact_id ON public.contact_photos USING btree (contact_id)"},{"name":"idx_contact_photos_contact_slope","definition":"CREATE INDEX idx_contact_photos_contact_slope ON public.contact_photos USING btree (contact_id, roof_slope)"},{"name":"idx_contact_photos_drive_file_id","definition":"CREATE INDEX idx_contact_photos_drive_file_id ON public.contact_photos USING btree (drive_file_id) WHERE (drive_file_id IS NOT NULL)"},{"name":"idx_contact_photos_drive_sync_status","definition":"CREATE INDEX idx_contact_photos_drive_sync_status ON public.contact_photos USING btree (drive_sync_status)"},{"name":"idx_contact_photos_slope","definition":"CREATE INDEX idx_contact_photos_slope ON public.contact_photos USING btree (contact_id, slope)"},{"name":"idx_contact_photos_status","definition":"CREATE INDEX idx_contact_photos_status ON public.contact_photos USING btree (status)"},{"name":"idx_contact_photos_tenant","definition":"CREATE INDEX idx_contact_photos_tenant ON public.contact_photos USING btree (tenant_org_id)"}],"policies":[{"cmd":"DELETE","qual":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = (contact_photos.tenant_org_id)::uuid) AND (user_roles.role = ANY (ARRAY['Admin'::app_role, 'GodMode'::app_role, 'Owner'::app_role])))))","roles":["public"],"tablename":"contact_photos","permissive":"PERMISSIVE","policyname":"Admins can delete photos","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"contact_photos","permissive":"PERMISSIVE","policyname":"Users can insert photos in their tenant","schemaname":"public","with_check":"((tenant_org_id)::uuid IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"UPDATE","qual":"(created_by = uid())","roles":["public"],"tablename":"contact_photos","permissive":"PERMISSIVE","policyname":"Users can update their own photos","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((tenant_org_id)::uuid IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"contact_photos","permissive":"PERMISSIVE","policyname":"Users can view photos in their tenant","schemaname":"public","with_check":null}],"triggers":[{"name":"audit_trigger_contact_photos","definition":"CREATE TRIGGER audit_trigger_contact_photos AFTER INSERT OR DELETE OR UPDATE ON contact_photos FOR EACH ROW EXECUTE FUNCTION comprehensive_audit_trigger_fn()"},{"name":"update_contact_photos_updated_at","definition":"CREATE TRIGGER update_contact_photos_updated_at BEFORE UPDATE ON contact_photos FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"contact_photos_damage_severity_chk","definition":"CHECK (damage_severity IS NULL OR (damage_severity = ANY (ARRAY['low'::text, 'medium'::text, 'high'::text])))"},{"name":"contact_photos_phase_check","definition":"CHECK (phase = ANY (ARRAY['before'::text, 'after'::text, 'general'::text]))"},{"name":"contact_photos_pkey","definition":"PRIMARY KEY (id)"},{"name":"contact_photos_roof_slope_chk","definition":"CHECK (roof_slope IS NULL OR (roof_slope = ANY (ARRAY['north'::text, 'south'::text, 'east'::text, 'west'::text, 'northeast'::text, 'northwest'::text, 'southeast'::text, 'southwest'::text, 'ridge'::text, 'valley'::text, 'eave'::text, 'penetration'::text, 'overview'::text, 'unknown'::text])))"},{"name":"contact_photos_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'ready'::text, 'failed'::text]))"}]},{"table":"contact_price_overrides","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"item_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"item_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"unit_price","type":"numeric(12,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"currency","type":"text","default":"'USD'::text","identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"contact_price_overrides_pkey","definition":"CREATE UNIQUE INDEX contact_price_overrides_pkey ON public.contact_price_overrides USING btree (id)"},{"name":"contact_price_overrides_tenant_contact_idx","definition":"CREATE INDEX contact_price_overrides_tenant_contact_idx ON public.contact_price_overrides USING btree (tenant_org_id, contact_id) WHERE (active = true)"},{"name":"contact_price_overrides_tenant_org_id_contact_id_item_key_key","definition":"CREATE UNIQUE INDEX contact_price_overrides_tenant_org_id_contact_id_item_key_key ON public.contact_price_overrides USING btree (tenant_org_id, contact_id, item_key)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"contact_price_overrides","permissive":"PERMISSIVE","policyname":"contact_price_overrides_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"contact_price_overrides","permissive":"PERMISSIVE","policyname":"contact_price_overrides_insert","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin())"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"contact_price_overrides","permissive":"PERMISSIVE","policyname":"contact_price_overrides_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"contact_price_overrides","permissive":"PERMISSIVE","policyname":"contact_price_overrides_update","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin())"}],"triggers":[{"name":"contact_price_overrides_validate_tenant_trg","definition":"CREATE TRIGGER contact_price_overrides_validate_tenant_trg BEFORE INSERT OR UPDATE ON contact_price_overrides FOR EACH ROW EXECUTE FUNCTION contact_price_overrides_validate_tenant()"}],"constraints":[{"name":"contact_price_overrides_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE CASCADE"},{"name":"contact_price_overrides_pkey","definition":"PRIMARY KEY (id)"},{"name":"contact_price_overrides_tenant_org_id_contact_id_item_key_key","definition":"UNIQUE (tenant_org_id, contact_id, item_key)"},{"name":"contact_price_overrides_unit_price_check","definition":"CHECK (unit_price >= 0::numeric)"}]},{"table":"contact_tenant_memberships","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assigned_to","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_rep","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_user","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_stage","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"jobs_stage","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_stage","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"graduated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"appt_date","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"appt_time","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes2","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes3","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes4","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"additional_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"quality_score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_tags","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"insurance_claim_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"estimate_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"job_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"work_classification","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"salesperson_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_touched_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_contact","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"deletion_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"service_scopes","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"agreement_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_document_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_resolver_status","type":"text","default":"'unresolved'::text","identity":"","not_null":true,"generated":""},{"name":"agreement_resolver_confidence","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_resolver_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_resolver_confirmed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_resolver_confirmed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"dnc_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"lost_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"contact_tenant_memberships_contact_id_tenant_id_key","definition":"CREATE UNIQUE INDEX contact_tenant_memberships_contact_id_tenant_id_key ON public.contact_tenant_memberships USING btree (contact_id, tenant_id)"},{"name":"contact_tenant_memberships_pkey","definition":"CREATE UNIQUE INDEX contact_tenant_memberships_pkey ON public.contact_tenant_memberships USING btree (id)"},{"name":"idx_contact_tenant_memberships_tenant_lifecycle","definition":"CREATE INDEX idx_contact_tenant_memberships_tenant_lifecycle ON public.contact_tenant_memberships USING btree (tenant_id, deleted_at, archived_at, dnc_at, lost_at)"},{"name":"idx_ctm_assigned_to","definition":"CREATE INDEX idx_ctm_assigned_to ON public.contact_tenant_memberships USING btree (assigned_to)"},{"name":"idx_ctm_contact_id","definition":"CREATE INDEX idx_ctm_contact_id ON public.contact_tenant_memberships USING btree (contact_id)"},{"name":"idx_ctm_deleted_at","definition":"CREATE INDEX idx_ctm_deleted_at ON public.contact_tenant_memberships USING btree (deleted_at)"},{"name":"idx_ctm_lead_id","definition":"CREATE INDEX idx_ctm_lead_id ON public.contact_tenant_memberships USING btree (lead_id)"},{"name":"idx_ctm_tenant_id","definition":"CREATE INDEX idx_ctm_tenant_id ON public.contact_tenant_memberships USING btree (tenant_id)"},{"name":"idx_ctm_tenant_status","definition":"CREATE INDEX idx_ctm_tenant_status ON public.contact_tenant_memberships USING btree (tenant_id, status) WHERE (deleted_at IS NULL)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_member((tenant_id)::text)","roles":["authenticated"],"tablename":"contact_tenant_memberships","permissive":"PERMISSIVE","policyname":"ctm_delete_own_tenant","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"contact_tenant_memberships","permissive":"PERMISSIVE","policyname":"ctm_insert_own_tenant","schemaname":"public","with_check":"is_tenant_member((tenant_id)::text)"},{"cmd":"SELECT","qual":"is_tenant_member((tenant_id)::text)","roles":["authenticated"],"tablename":"contact_tenant_memberships","permissive":"PERMISSIVE","policyname":"ctm_select_own_tenant","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member((tenant_id)::text)","roles":["authenticated"],"tablename":"contact_tenant_memberships","permissive":"PERMISSIVE","policyname":"ctm_update_own_tenant","schemaname":"public","with_check":"is_tenant_member((tenant_id)::text)"},{"cmd":"ALL","qual":"((tenant_id <> '669daee1-57e8-4960-937c-ce397106f32e'::uuid) OR (assigned_user = (( SELECT uid() AS uid))::text) OR (assigned_to = (( SELECT uid() AS uid))::text) OR (lower(COALESCE(assigned_to, ''::text)) = lower(COALESCE(( SELECT current_user_email() AS current_user_email), ''::text))) OR (lower(COALESCE(assigned_rep, ''::text)) = lower(COALESCE(( SELECT current_user_email() AS current_user_email), ''::text))) OR (EXISTS ( SELECT 1\n   FROM (admin_action_logs started\n     JOIN profiles target_profile ON ((target_profile.id = started.target_user_id)))\n  WHERE ((started.admin_user_id = ( SELECT uid() AS uid)) AND (started.action_type = 'impersonation_started'::text) AND (started.target_tenant_id = contact_tenant_memberships.tenant_id) AND ((contact_tenant_memberships.assigned_user = (started.target_user_id)::text) OR (contact_tenant_memberships.assigned_to = (started.target_user_id)::text) OR (lower(COALESCE(contact_tenant_memberships.assigned_to, ''::text)) = lower(COALESCE(target_profile.email, ''::text))) OR (lower(COALESCE(contact_tenant_memberships.assigned_rep, ''::text)) = lower(COALESCE(target_profile.email, ''::text)))) AND (NOT (EXISTS ( SELECT 1\n           FROM admin_action_logs stopped\n          WHERE ((stopped.admin_user_id = started.admin_user_id) AND (stopped.target_user_id = started.target_user_id) AND (stopped.action_type = 'impersonation_stopped'::text) AND (COALESCE(stopped.\"timestamp\", stopped.created_at) > COALESCE(started.\"timestamp\", started.created_at))))))))))","roles":["authenticated"],"tablename":"contact_tenant_memberships","permissive":"RESTRICTIVE","policyname":"tennex_user_contact_membership_exclusivity","schemaname":"public","with_check":"((tenant_id <> '669daee1-57e8-4960-937c-ce397106f32e'::uuid) OR (assigned_user = (( SELECT uid() AS uid))::text) OR (assigned_to = (( SELECT uid() AS uid))::text) OR (lower(COALESCE(assigned_to, ''::text)) = lower(COALESCE(( SELECT current_user_email() AS current_user_email), ''::text))) OR (lower(COALESCE(assigned_rep, ''::text)) = lower(COALESCE(( SELECT current_user_email() AS current_user_email), ''::text))) OR (EXISTS ( SELECT 1\n   FROM (admin_action_logs started\n     JOIN profiles target_profile ON ((target_profile.id = started.target_user_id)))\n  WHERE ((started.admin_user_id = ( SELECT uid() AS uid)) AND (started.action_type = 'impersonation_started'::text) AND (started.target_tenant_id = contact_tenant_memberships.tenant_id) AND ((contact_tenant_memberships.assigned_user = (started.target_user_id)::text) OR (contact_tenant_memberships.assigned_to = (started.target_user_id)::text) OR (lower(COALESCE(contact_tenant_memberships.assigned_to, ''::text)) = lower(COALESCE(target_profile.email, ''::text))) OR (lower(COALESCE(contact_tenant_memberships.assigned_rep, ''::text)) = lower(COALESCE(target_profile.email, ''::text)))) AND (NOT (EXISTS ( SELECT 1\n           FROM admin_action_logs stopped\n          WHERE ((stopped.admin_user_id = started.admin_user_id) AND (stopped.target_user_id = started.target_user_id) AND (stopped.action_type = 'impersonation_stopped'::text) AND (COALESCE(stopped.\"timestamp\", stopped.created_at) > COALESCE(started.\"timestamp\", started.created_at))))))))))"}],"triggers":[{"name":"update_ctm_updated_at","definition":"CREATE TRIGGER update_ctm_updated_at BEFORE UPDATE ON contact_tenant_memberships FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"contact_tenant_memberships_contact_id_tenant_id_key","definition":"UNIQUE (contact_id, tenant_id)"},{"name":"contact_tenant_memberships_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"conversion_funnels","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"character varying(255)","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stages","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"conversion_funnels_pkey","definition":"CREATE UNIQUE INDEX conversion_funnels_pkey ON public.conversion_funnels USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"conversion_funnels","permissive":"PERMISSIVE","policyname":"Users can manage funnels","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"conversion_funnels","permissive":"PERMISSIVE","policyname":"Users can view own tenant funnels","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"conversion_funnels_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"creative_profiles","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"favorite_fonts","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"design_preferences","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"preferred_media_ids","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"creative_profiles_pkey","definition":"CREATE UNIQUE INDEX creative_profiles_pkey ON public.creative_profiles USING btree (tenant_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"creative_profiles","permissive":"PERMISSIVE","policyname":"creative_profiles_member_insert","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = creative_profiles.tenant_id)))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = creative_profiles.tenant_id)))))","roles":["public"],"tablename":"creative_profiles","permissive":"PERMISSIVE","policyname":"creative_profiles_member_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = creative_profiles.tenant_id)))))","roles":["public"],"tablename":"creative_profiles","permissive":"PERMISSIVE","policyname":"creative_profiles_member_update","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = creative_profiles.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"creative_profiles_pkey","definition":"PRIMARY KEY (tenant_id)"},{"name":"creative_profiles_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"creative_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"format_key","type":"text","default":"'custom'::text","identity":"","not_null":true,"generated":""},{"name":"presentation","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"content","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"creative_templates_pkey","definition":"CREATE UNIQUE INDEX creative_templates_pkey ON public.creative_templates USING btree (id)"},{"name":"creative_templates_tenant_kind_updated_idx","definition":"CREATE INDEX creative_templates_tenant_kind_updated_idx ON public.creative_templates USING btree (tenant_id, kind, updated_at DESC)"},{"name":"creative_templates_tenant_system_starter_uidx","definition":"CREATE UNIQUE INDEX creative_templates_tenant_system_starter_uidx ON public.creative_templates USING btree (tenant_id, kind, ((metadata ->> 'system_starter_key'::text))) WHERE (metadata ? 'system_starter_key'::text)"}],"policies":[{"cmd":"DELETE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = creative_templates.tenant_id)))))","roles":["public"],"tablename":"creative_templates","permissive":"PERMISSIVE","policyname":"creative_templates_member_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"creative_templates","permissive":"PERMISSIVE","policyname":"creative_templates_member_insert","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = creative_templates.tenant_id)))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = creative_templates.tenant_id)))))","roles":["public"],"tablename":"creative_templates","permissive":"PERMISSIVE","policyname":"creative_templates_member_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = creative_templates.tenant_id)))))","roles":["public"],"tablename":"creative_templates","permissive":"PERMISSIVE","policyname":"creative_templates_member_update","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = creative_templates.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"creative_templates_kind_check","definition":"CHECK (kind = ANY (ARRAY['flyer'::text, 'proposal'::text, 'invoice'::text]))"},{"name":"creative_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"creative_templates_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"cross_tenant_assignment_backfill_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_tenant","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"prior_assigned_user","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"prior_assigned_to","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_tenant","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"cleared_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"cross_tenant_assignment_backfill_log_pkey","definition":"CREATE UNIQUE INDEX cross_tenant_assignment_backfill_log_pkey ON public.cross_tenant_assignment_backfill_log USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"cross_tenant_assignment_backfill_log","permissive":"PERMISSIVE","policyname":"system admins can read backfill log","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"cross_tenant_assignment_backfill_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"custom_field_values","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"custom_field_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"entity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"custom_field_values_custom_field_id_entity_id_key","definition":"CREATE UNIQUE INDEX custom_field_values_custom_field_id_entity_id_key ON public.custom_field_values USING btree (custom_field_id, entity_id)"},{"name":"custom_field_values_pkey","definition":"CREATE UNIQUE INDEX custom_field_values_pkey ON public.custom_field_values USING btree (id)"},{"name":"idx_custom_field_values_custom_field_id","definition":"CREATE INDEX idx_custom_field_values_custom_field_id ON public.custom_field_values USING btree (custom_field_id)"},{"name":"idx_custom_field_values_entity","definition":"CREATE INDEX idx_custom_field_values_entity ON public.custom_field_values USING btree (entity_type, entity_id)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = custom_field_values.tenant_id))))","roles":["public"],"tablename":"custom_field_values","permissive":"PERMISSIVE","policyname":"Users manage custom values","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = custom_field_values.tenant_id))))","roles":["public"],"tablename":"custom_field_values","permissive":"PERMISSIVE","policyname":"Users view tenant custom values","schemaname":"public","with_check":null}],"triggers":[{"name":"custom_field_values_updated_at","definition":"CREATE TRIGGER custom_field_values_updated_at BEFORE UPDATE ON custom_field_values FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"custom_field_values_custom_field_id_entity_id_key","definition":"UNIQUE (custom_field_id, entity_id)"},{"name":"custom_field_values_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"custom_fields","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"field_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"field_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"field_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"options","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_required","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"display_order","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"custom_fields_pkey","definition":"CREATE UNIQUE INDEX custom_fields_pkey ON public.custom_fields USING btree (id)"},{"name":"custom_fields_tenant_id_entity_type_field_name_key","definition":"CREATE UNIQUE INDEX custom_fields_tenant_id_entity_type_field_name_key ON public.custom_fields USING btree (tenant_id, entity_type, field_name)"},{"name":"idx_custom_fields_entity_type","definition":"CREATE INDEX idx_custom_fields_entity_type ON public.custom_fields USING btree (entity_type)"},{"name":"idx_custom_fields_tenant_id","definition":"CREATE INDEX idx_custom_fields_tenant_id ON public.custom_fields USING btree (tenant_id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = custom_fields.tenant_id))))","roles":["public"],"tablename":"custom_fields","permissive":"PERMISSIVE","policyname":"Users view tenant custom fields","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"custom_fields","permissive":"PERMISSIVE","policyname":"custom_fields_godmode","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((tenant_id IS NULL) OR is_tenant_member(uid(), (tenant_id)::uuid))","roles":["public"],"tablename":"custom_fields","permissive":"PERMISSIVE","policyname":"custom_fields_tenant_member_read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((tenant_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_id)::uuid))","roles":["public"],"tablename":"custom_fields","permissive":"PERMISSIVE","policyname":"custom_fields_tenant_owner_manage","schemaname":"public","with_check":"((tenant_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_id)::uuid))"}],"triggers":[{"name":"custom_fields_updated_at","definition":"CREATE TRIGGER custom_fields_updated_at BEFORE UPDATE ON custom_fields FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"custom_fields_pkey","definition":"PRIMARY KEY (id)"},{"name":"custom_fields_tenant_id_entity_type_field_name_key","definition":"UNIQUE (tenant_id, entity_type, field_name)"}]},{"table":"customer_leads","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"storm_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"damage_description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"insurance_company","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'New'::text","identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"customer_leads_pkey","definition":"CREATE UNIQUE INDEX customer_leads_pkey ON public.customer_leads USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["anon","authenticated"],"tablename":"customer_leads","permissive":"PERMISSIVE","policyname":"Public can submit leads with valid name","schemaname":"public","with_check":"((name IS NOT NULL) AND ((char_length(btrim(name)) >= 2) AND (char_length(btrim(name)) <= 120)) AND (tenant_org_id IS NOT NULL) AND (tenant_org_id ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'::text) AND (EXISTS ( SELECT 1\n   FROM tenants t\n  WHERE ((t.id = (customer_leads.tenant_org_id)::uuid) AND (COALESCE(t.is_active, true) = true) AND (COALESCE(t.status, 'active'::text) = 'active'::text)))) AND ((NULLIF(btrim(email), ''::text) IS NOT NULL) OR (NULLIF(btrim(phone), ''::text) IS NOT NULL)) AND ((email IS NULL) OR ((char_length(email) <= 254) AND (email ~* '^[^@[:space:]]+@[^@[:space:]]+[.][^@[:space:]]+$'::text))) AND ((phone IS NULL) OR ((char_length(regexp_replace(phone, '\\D'::text, ''::text, 'g'::text)) >= 7) AND (char_length(regexp_replace(phone, '\\D'::text, ''::text, 'g'::text)) <= 15))) AND ((address IS NULL) OR (char_length(address) <= 500)) AND ((damage_description IS NULL) OR (char_length(damage_description) <= 4000)) AND (COALESCE(status, 'New'::text) = 'New'::text))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"customer_leads","permissive":"PERMISSIVE","policyname":"cl_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"customer_leads","permissive":"PERMISSIVE","policyname":"cl_update","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (customer_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"customer_leads","permissive":"PERMISSIVE","policyname":"tenant_users_delete_customer_leads","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"customer_leads","permissive":"PERMISSIVE","policyname":"tenant_users_insert_customer_leads","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (customer_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (customer_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"customer_leads","permissive":"PERMISSIVE","policyname":"tenant_users_update_customer_leads","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (customer_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (customer_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"customer_leads","permissive":"PERMISSIVE","policyname":"tenant_users_view_customer_leads","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"customer_leads_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"customer_portal_access","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"access_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"last_login_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"token_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"customer_portal_access_access_token_key","definition":"CREATE UNIQUE INDEX customer_portal_access_access_token_key ON public.customer_portal_access USING btree (access_token)"},{"name":"customer_portal_access_claim_scope_idx","definition":"CREATE INDEX customer_portal_access_claim_scope_idx ON public.customer_portal_access USING btree (tenant_id, contact_id, claim_id) WHERE (claim_id IS NOT NULL)"},{"name":"customer_portal_access_contact_id_key","definition":"CREATE UNIQUE INDEX customer_portal_access_contact_id_key ON public.customer_portal_access USING btree (contact_id)"},{"name":"customer_portal_access_pkey","definition":"CREATE UNIQUE INDEX customer_portal_access_pkey ON public.customer_portal_access USING btree (id)"},{"name":"customer_portal_access_token_hash_key","definition":"CREATE UNIQUE INDEX customer_portal_access_token_hash_key ON public.customer_portal_access USING btree (token_hash) WHERE (token_hash IS NOT NULL)"},{"name":"idx_customer_portal_access_token","definition":"CREATE INDEX idx_customer_portal_access_token ON public.customer_portal_access USING btree (access_token)"},{"name":"idx_customer_portal_contact_id","definition":"CREATE INDEX idx_customer_portal_contact_id ON public.customer_portal_access USING btree (contact_id)"},{"name":"idx_portal_access_token_hash","definition":"CREATE INDEX idx_portal_access_token_hash ON public.customer_portal_access USING btree (token_hash)"}],"policies":[{"cmd":"SELECT","qual":"((email = (( SELECT users.email\n   FROM users\n  WHERE (users.id = uid())))::text) OR ((is_active = true) AND (access_token IN ( SELECT unnest(string_to_array(((current_setting('request.headers'::text, true))::json ->> 'x-portal-token'::text), ','::text)) AS unnest))))","roles":["public"],"tablename":"customer_portal_access","permissive":"PERMISSIVE","policyname":"Customers can access own portal records","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(is_system_admin(uid()) OR is_admin_or_higher(uid(), (tenant_id)::uuid))","roles":["authenticated"],"tablename":"customer_portal_access","permissive":"PERMISSIVE","policyname":"Tenant admins manage portal access","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"customer_portal_access_access_token_key","definition":"UNIQUE (access_token)"},{"name":"customer_portal_access_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"dashboard_widgets","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"widget_type","type":"character varying(50)","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"character varying(255)","default":null,"identity":"","not_null":true,"generated":""},{"name":"config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"position","type":"jsonb","default":"'{\"h\": 3, \"w\": 4, \"x\": 0, \"y\": 0}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"is_visible","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"refresh_interval","type":"integer","default":"300","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"dashboard_widgets_pkey","definition":"CREATE UNIQUE INDEX dashboard_widgets_pkey ON public.dashboard_widgets USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"((tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) AND ((user_id = uid()) OR (user_id IS NULL)))","roles":["public"],"tablename":"dashboard_widgets","permissive":"PERMISSIVE","policyname":"Users can manage own widgets","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"dashboard_widgets_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"data_integrity_quarantine","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"table_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"record_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"snapshot","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"quarantined_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"quarantined_by","type":"text","default":"'system_migration_phase2'::text","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"data_integrity_quarantine_pkey","definition":"CREATE UNIQUE INDEX data_integrity_quarantine_pkey ON public.data_integrity_quarantine USING btree (id)"},{"name":"idx_data_integrity_quarantine_table_record","definition":"CREATE INDEX idx_data_integrity_quarantine_table_record ON public.data_integrity_quarantine USING btree (table_name, record_id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"data_integrity_quarantine","permissive":"PERMISSIVE","policyname":"godmode_full_access_quarantine","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"data_integrity_quarantine_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"data_quality_issues","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"table_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"issue_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"severity","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"details","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"auto_fixable","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolution_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"data_quality_issues_pkey","definition":"CREATE UNIQUE INDEX data_quality_issues_pkey ON public.data_quality_issues USING btree (id)"},{"name":"idx_dqi_lead_id","definition":"CREATE INDEX idx_dqi_lead_id ON public.data_quality_issues USING btree (lead_id)"},{"name":"idx_dqi_severity","definition":"CREATE INDEX idx_dqi_severity ON public.data_quality_issues USING btree (severity)"},{"name":"idx_dqi_unresolved","definition":"CREATE INDEX idx_dqi_unresolved ON public.data_quality_issues USING btree (resolved_at) WHERE (resolved_at IS NULL)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM lead_deck ld\n  WHERE ((ld.lead_id = data_quality_issues.lead_id) AND (EXISTS ( SELECT 1\n           FROM user_roles\n          WHERE ((user_roles.user_id = uid()) AND ((user_roles.tenant_id)::text = ld.tenant_org_id) AND (user_roles.role = 'Owner'::app_role)))))))","roles":["authenticated"],"tablename":"data_quality_issues","permissive":"PERMISSIVE","policyname":"Tenant owners view tenant quality issues","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"data_quality_issues","permissive":"PERMISSIVE","policyname":"platform_admin_manage_quality_issues","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"data_quality_issues_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"data_retention_policies","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"table_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"retention_days","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"last_executed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"data_retention_policies_pkey","definition":"CREATE UNIQUE INDEX data_retention_policies_pkey ON public.data_retention_policies USING btree (id)"},{"name":"data_retention_policies_table_name_key","definition":"CREATE UNIQUE INDEX data_retention_policies_table_name_key ON public.data_retention_policies USING btree (table_name)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"data_retention_policies","permissive":"PERMISSIVE","policyname":"platform_admin_manage_retention","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"data_retention_policies_action_check","definition":"CHECK (action = ANY (ARRAY['delete'::text, 'anonymize'::text, 'archive'::text]))"},{"name":"data_retention_policies_pkey","definition":"PRIMARY KEY (id)"},{"name":"data_retention_policies_table_name_key","definition":"UNIQUE (table_name)"}]},{"table":"demo_activity_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"environment_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"persona_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"application_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"route","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"record_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"record_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"severity","type":"text","default":"'info'::text","identity":"","not_null":true,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"demo_activity_application_time_idx","definition":"CREATE INDEX demo_activity_application_time_idx ON public.demo_activity_log USING btree (application_id, created_at DESC) WHERE (application_id IS NOT NULL)"},{"name":"demo_activity_environment_time_idx","definition":"CREATE INDEX demo_activity_environment_time_idx ON public.demo_activity_log USING btree (environment_id, created_at DESC)"},{"name":"demo_activity_log_pkey","definition":"CREATE UNIQUE INDEX demo_activity_log_pkey ON public.demo_activity_log USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"demo_activity_log","permissive":"PERMISSIVE","policyname":"demo_activity_log_platform_admin_read","schemaname":"public","with_check":null}],"triggers":[{"name":"demo_activity_log_immutable","definition":"CREATE TRIGGER demo_activity_log_immutable BEFORE DELETE OR UPDATE ON demo_activity_log FOR EACH ROW EXECUTE FUNCTION prevent_demo_activity_log_mutation()"}],"constraints":[{"name":"demo_activity_log_application_id_fkey","definition":"FOREIGN KEY (application_id) REFERENCES application_catalog(id) ON DELETE SET NULL"},{"name":"demo_activity_log_environment_id_fkey","definition":"FOREIGN KEY (environment_id) REFERENCES demo_environments(id) ON DELETE RESTRICT"},{"name":"demo_activity_log_persona_id_fkey","definition":"FOREIGN KEY (persona_id) REFERENCES demo_personas(id) ON DELETE SET NULL"},{"name":"demo_activity_log_pkey","definition":"PRIMARY KEY (id)"},{"name":"demo_activity_log_session_id_fkey","definition":"FOREIGN KEY (session_id) REFERENCES demo_sessions(id) ON DELETE SET NULL"},{"name":"demo_activity_log_severity_check","definition":"CHECK (severity = ANY (ARRAY['debug'::text, 'info'::text, 'warning'::text, 'error'::text]))"}]},{"table":"demo_environment_applications","schema":"public","columns":[{"name":"environment_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"application_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"configuration","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"demo_environment_applications_app_idx","definition":"CREATE INDEX demo_environment_applications_app_idx ON public.demo_environment_applications USING btree (application_id, environment_id)"},{"name":"demo_environment_applications_pkey","definition":"CREATE UNIQUE INDEX demo_environment_applications_pkey ON public.demo_environment_applications USING btree (environment_id, application_id)"}],"policies":[{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"demo_environment_applications","permissive":"PERMISSIVE","policyname":"demo_environment_applications_platform_admin_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"demo_environment_applications_application_id_fkey","definition":"FOREIGN KEY (application_id) REFERENCES application_catalog(id) ON DELETE RESTRICT"},{"name":"demo_environment_applications_environment_id_fkey","definition":"FOREIGN KEY (environment_id) REFERENCES demo_environments(id) ON DELETE CASCADE"},{"name":"demo_environment_applications_pkey","definition":"PRIMARY KEY (environment_id, application_id)"}]},{"table":"demo_environments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"public_id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"request_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"opportunity_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"business_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"demo_mode","type":"text","default":"'basic'::text","identity":"","not_null":true,"generated":""},{"name":"template_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"configuration","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"demo_environments_pkey","definition":"CREATE UNIQUE INDEX demo_environments_pkey ON public.demo_environments USING btree (id)"},{"name":"demo_environments_public_id_key","definition":"CREATE UNIQUE INDEX demo_environments_public_id_key ON public.demo_environments USING btree (public_id)"},{"name":"demo_environments_request_idx","definition":"CREATE INDEX demo_environments_request_idx ON public.demo_environments USING btree (request_id) WHERE (request_id IS NOT NULL)"},{"name":"demo_environments_status_created_idx","definition":"CREATE INDEX demo_environments_status_created_idx ON public.demo_environments USING btree (status, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"demo_environments","permissive":"PERMISSIVE","policyname":"demo_environments_platform_admin_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"demo_environments_demo_mode_check","definition":"CHECK (demo_mode = ANY (ARRAY['basic'::text, 'applications'::text]))"},{"name":"demo_environments_opportunity_id_fkey","definition":"FOREIGN KEY (opportunity_id) REFERENCES business_opportunities(id) ON DELETE SET NULL"},{"name":"demo_environments_pkey","definition":"PRIMARY KEY (id)"},{"name":"demo_environments_public_id_key","definition":"UNIQUE (public_id)"},{"name":"demo_environments_request_id_fkey","definition":"FOREIGN KEY (request_id) REFERENCES knocklaunch_demo_requests(id) ON DELETE SET NULL"},{"name":"demo_environments_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'human_review'::text, 'ready'::text, 'archived'::text]))"}]},{"table":"demo_personas","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"environment_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"persona_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"role_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"synthetic_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permissions","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"demo_personas_environment_id_persona_key_key","definition":"CREATE UNIQUE INDEX demo_personas_environment_id_persona_key_key ON public.demo_personas USING btree (environment_id, persona_key)"},{"name":"demo_personas_one_default_idx","definition":"CREATE UNIQUE INDEX demo_personas_one_default_idx ON public.demo_personas USING btree (environment_id) WHERE is_default"},{"name":"demo_personas_pkey","definition":"CREATE UNIQUE INDEX demo_personas_pkey ON public.demo_personas USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"demo_personas","permissive":"PERMISSIVE","policyname":"demo_personas_platform_admin_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"demo_personas_environment_id_fkey","definition":"FOREIGN KEY (environment_id) REFERENCES demo_environments(id) ON DELETE CASCADE"},{"name":"demo_personas_environment_id_persona_key_key","definition":"UNIQUE (environment_id, persona_key)"},{"name":"demo_personas_pkey","definition":"PRIMARY KEY (id)"},{"name":"demo_personas_role_key_check","definition":"CHECK (role_key = ANY (ARRAY['owner'::text, 'manager'::text, 'sales'::text, 'staff'::text, 'customer'::text]))"}]},{"table":"demo_records","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"environment_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"application_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"persona_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"record_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"record_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subtitle","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"data","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"demo_records_environment_id_application_id_persona_id_recor_key","definition":"CREATE UNIQUE INDEX demo_records_environment_id_application_id_persona_id_recor_key ON public.demo_records USING btree (environment_id, application_id, persona_id, record_key)"},{"name":"demo_records_lookup_idx","definition":"CREATE INDEX demo_records_lookup_idx ON public.demo_records USING btree (environment_id, persona_id, application_id, sort_order)"},{"name":"demo_records_pkey","definition":"CREATE UNIQUE INDEX demo_records_pkey ON public.demo_records USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"demo_records","permissive":"PERMISSIVE","policyname":"demo_records_platform_admin_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"demo_records_application_id_fkey","definition":"FOREIGN KEY (application_id) REFERENCES application_catalog(id) ON DELETE RESTRICT"},{"name":"demo_records_environment_id_application_id_persona_id_recor_key","definition":"UNIQUE (environment_id, application_id, persona_id, record_key)"},{"name":"demo_records_environment_id_fkey","definition":"FOREIGN KEY (environment_id) REFERENCES demo_environments(id) ON DELETE CASCADE"},{"name":"demo_records_persona_id_fkey","definition":"FOREIGN KEY (persona_id) REFERENCES demo_personas(id) ON DELETE CASCADE"},{"name":"demo_records_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"demo_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"environment_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"persona_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"session_token","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'public-demo'::text","identity":"","not_null":true,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_seen_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"ended_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"demo_sessions_environment_idx","definition":"CREATE INDEX demo_sessions_environment_idx ON public.demo_sessions USING btree (environment_id, started_at DESC)"},{"name":"demo_sessions_pkey","definition":"CREATE UNIQUE INDEX demo_sessions_pkey ON public.demo_sessions USING btree (id)"},{"name":"demo_sessions_session_token_key","definition":"CREATE UNIQUE INDEX demo_sessions_session_token_key ON public.demo_sessions USING btree (session_token)"}],"policies":[{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"demo_sessions","permissive":"PERMISSIVE","policyname":"demo_sessions_platform_admin_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"demo_sessions_environment_id_fkey","definition":"FOREIGN KEY (environment_id) REFERENCES demo_environments(id) ON DELETE CASCADE"},{"name":"demo_sessions_persona_id_fkey","definition":"FOREIGN KEY (persona_id) REFERENCES demo_personas(id) ON DELETE SET NULL"},{"name":"demo_sessions_pkey","definition":"PRIMARY KEY (id)"},{"name":"demo_sessions_session_token_key","definition":"UNIQUE (session_token)"}]},{"table":"dnc_audit_entries","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"run_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_table","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_normalized","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_original","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"scan_result","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"was_previously_clean","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"newly_flagged","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"previous_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"dnc_match_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"dnc_match_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"scanned_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"dnc_audit_entries_pkey","definition":"CREATE UNIQUE INDEX dnc_audit_entries_pkey ON public.dnc_audit_entries USING btree (id)"},{"name":"idx_dnc_audit_entries_lead","definition":"CREATE INDEX idx_dnc_audit_entries_lead ON public.dnc_audit_entries USING btree (lead_id, scanned_at DESC)"},{"name":"idx_dnc_audit_entries_newly_flagged","definition":"CREATE INDEX idx_dnc_audit_entries_newly_flagged ON public.dnc_audit_entries USING btree (newly_flagged) WHERE (newly_flagged = true)"},{"name":"idx_dnc_audit_entries_phone","definition":"CREATE INDEX idx_dnc_audit_entries_phone ON public.dnc_audit_entries USING btree (phone_normalized)"},{"name":"idx_dnc_audit_entries_run","definition":"CREATE INDEX idx_dnc_audit_entries_run ON public.dnc_audit_entries USING btree (run_id)"},{"name":"idx_dnc_audit_entries_scanned","definition":"CREATE INDEX idx_dnc_audit_entries_scanned ON public.dnc_audit_entries USING btree (scanned_at DESC)"}],"policies":[{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"dnc_audit_entries","permissive":"PERMISSIVE","policyname":"Service role manages audit entries","schemaname":"public","with_check":"true"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"dnc_audit_entries","permissive":"PERMISSIVE","policyname":"platform_admin_view_dnc_audit_entries","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_prevent_dnc_audit_update","definition":"CREATE TRIGGER trg_prevent_dnc_audit_update BEFORE DELETE OR UPDATE ON dnc_audit_entries FOR EACH ROW EXECUTE FUNCTION prevent_dnc_audit_modification()"}],"constraints":[{"name":"dnc_audit_entries_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"dnc_audit_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"run_type","type":"text","default":"'scheduled'::text","identity":"","not_null":true,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"leads_scanned","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"matches_found","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"newly_flagged","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"errors_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'running'::text","identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"triggered_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"dnc_audit_runs_pkey","definition":"CREATE UNIQUE INDEX dnc_audit_runs_pkey ON public.dnc_audit_runs USING btree (id)"},{"name":"idx_dnc_audit_runs_started","definition":"CREATE INDEX idx_dnc_audit_runs_started ON public.dnc_audit_runs USING btree (started_at DESC)"},{"name":"idx_dnc_audit_runs_status","definition":"CREATE INDEX idx_dnc_audit_runs_status ON public.dnc_audit_runs USING btree (status)"}],"policies":[{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"dnc_audit_runs","permissive":"PERMISSIVE","policyname":"Service role manages audit runs","schemaname":"public","with_check":"true"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"dnc_audit_runs","permissive":"PERMISSIVE","policyname":"platform_admin_view_dnc_audit_runs","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"dnc_audit_runs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"dnc_federal_numbers","schema":"public","columns":[{"name":"phone","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"area_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":"'ftc_national'::text","identity":"","not_null":true,"generated":""},{"name":"added_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"dnc_federal_numbers_pkey","definition":"CREATE UNIQUE INDEX dnc_federal_numbers_pkey ON public.dnc_federal_numbers USING btree (phone)"},{"name":"idx_dnc_federal_numbers_area_code","definition":"CREATE INDEX idx_dnc_federal_numbers_area_code ON public.dnc_federal_numbers USING btree (area_code)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"dnc_federal_numbers","permissive":"PERMISSIVE","policyname":"Authenticated users lookup federal DNC numbers","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_propagate_fed_dnc","definition":"CREATE TRIGGER trg_propagate_fed_dnc AFTER INSERT ON dnc_federal_numbers FOR EACH ROW EXECUTE FUNCTION propagate_federal_dnc_to_contacts()"}],"constraints":[{"name":"dnc_federal_numbers_pkey","definition":"PRIMARY KEY (phone)"}]},{"table":"dnc_federal_subscriptions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"san","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"organization_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"area_codes","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"login_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_synced_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_renewal_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"dnc_federal_subscriptions_pkey","definition":"CREATE UNIQUE INDEX dnc_federal_subscriptions_pkey ON public.dnc_federal_subscriptions USING btree (id)"},{"name":"dnc_federal_subscriptions_tenant_id_key","definition":"CREATE UNIQUE INDEX dnc_federal_subscriptions_tenant_id_key ON public.dnc_federal_subscriptions USING btree (tenant_id)"}],"policies":[{"cmd":"ALL","qual":"(has_role(uid(), tenant_id, 'Owner'::app_role) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"dnc_federal_subscriptions","permissive":"PERMISSIVE","policyname":"Owners manage federal DNC subscription","schemaname":"public","with_check":"(has_role(uid(), tenant_id, 'Owner'::app_role) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = dnc_federal_subscriptions.tenant_id)))) OR is_system_admin(uid()))","roles":["public"],"tablename":"dnc_federal_subscriptions","permissive":"PERMISSIVE","policyname":"Tenant members view federal DNC subscription","schemaname":"public","with_check":null}],"triggers":[{"name":"update_dnc_federal_subscriptions_updated_at","definition":"CREATE TRIGGER update_dnc_federal_subscriptions_updated_at BEFORE UPDATE ON dnc_federal_subscriptions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"dnc_federal_subscriptions_pkey","definition":"PRIMARY KEY (id)"},{"name":"dnc_federal_subscriptions_tenant_id_key","definition":"UNIQUE (tenant_id)"}]},{"table":"dnc_florida_registry","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_normalized","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'ftsa_official'::text","identity":"","not_null":true,"generated":""},{"name":"added_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"removed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"dnc_florida_registry_phone_normalized_source_key","definition":"CREATE UNIQUE INDEX dnc_florida_registry_phone_normalized_source_key ON public.dnc_florida_registry USING btree (phone_normalized, source)"},{"name":"dnc_florida_registry_pkey","definition":"CREATE UNIQUE INDEX dnc_florida_registry_pkey ON public.dnc_florida_registry USING btree (id)"},{"name":"idx_dnc_fl_phone","definition":"CREATE INDEX idx_dnc_fl_phone ON public.dnc_florida_registry USING btree (phone_normalized) WHERE (removed_at IS NULL)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"dnc_florida_registry","permissive":"PERMISSIVE","policyname":"authenticated_view_florida_dnc","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin()","roles":["authenticated"],"tablename":"dnc_florida_registry","permissive":"PERMISSIVE","policyname":"system_admins_manage_florida_dnc","schemaname":"public","with_check":"is_system_admin()"}],"triggers":[{"name":"trg_propagate_fl_dnc","definition":"CREATE TRIGGER trg_propagate_fl_dnc AFTER INSERT ON dnc_florida_registry FOR EACH ROW EXECUTE FUNCTION propagate_florida_dnc_to_contacts()"}],"constraints":[{"name":"dnc_florida_registry_phone_normalized_source_key","definition":"UNIQUE (phone_normalized, source)"},{"name":"dnc_florida_registry_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"dnc_list","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"added_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"phone_normalized","type":"text","default":"normalize_phone_for_dnc(phone)","identity":"","not_null":false,"generated":"s"},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"batch_id","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"dnc_list_phone_key","definition":"CREATE UNIQUE INDEX dnc_list_phone_key ON public.dnc_list USING btree (phone)"},{"name":"dnc_list_pkey","definition":"CREATE UNIQUE INDEX dnc_list_pkey ON public.dnc_list USING btree (id)"},{"name":"idx_dnc_list_batch_id","definition":"CREATE INDEX idx_dnc_list_batch_id ON public.dnc_list USING btree (batch_id)"},{"name":"idx_dnc_list_phone_normalized","definition":"CREATE INDEX idx_dnc_list_phone_normalized ON public.dnc_list USING btree (phone_normalized)"},{"name":"idx_dnc_list_source","definition":"CREATE INDEX idx_dnc_list_source ON public.dnc_list USING btree (source)"},{"name":"idx_dnc_phone","definition":"CREATE INDEX idx_dnc_phone ON public.dnc_list USING btree (phone)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"dnc_list","permissive":"PERMISSIVE","policyname":"dnc_godmode_all","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"dnc_list","permissive":"PERMISSIVE","policyname":"dnc_tenant_member_select","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"dnc_list","permissive":"PERMISSIVE","policyname":"dnc_tenant_owner_admin_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"dnc_list","permissive":"PERMISSIVE","policyname":"dnc_tenant_owner_admin_insert","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))"},{"cmd":"UPDATE","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"dnc_list","permissive":"PERMISSIVE","policyname":"dnc_tenant_owner_admin_update","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))"}],"triggers":[{"name":"trg_enforce_dnc_quarantine","definition":"CREATE TRIGGER trg_enforce_dnc_quarantine AFTER INSERT ON dnc_list FOR EACH ROW EXECUTE FUNCTION enforce_dnc_quarantine()"},{"name":"trg_propagate_dnc","definition":"CREATE TRIGGER trg_propagate_dnc AFTER INSERT ON dnc_list FOR EACH ROW EXECUTE FUNCTION propagate_dnc_to_leads()"}],"constraints":[{"name":"dnc_list_phone_key","definition":"UNIQUE (phone)"},{"name":"dnc_list_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"dnc_quarantine","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"phone_normalized","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"original_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_table","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"dnc_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_snapshot","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"quarantined_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"quarantined_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"dnc_quarantine_pkey","definition":"CREATE UNIQUE INDEX dnc_quarantine_pkey ON public.dnc_quarantine USING btree (id)"},{"name":"idx_dnc_quarantine_at","definition":"CREATE INDEX idx_dnc_quarantine_at ON public.dnc_quarantine USING btree (quarantined_at DESC)"},{"name":"idx_dnc_quarantine_phone","definition":"CREATE INDEX idx_dnc_quarantine_phone ON public.dnc_quarantine USING btree (phone_normalized)"},{"name":"idx_dnc_quarantine_tenant","definition":"CREATE INDEX idx_dnc_quarantine_tenant ON public.dnc_quarantine USING btree (tenant_org_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"dnc_quarantine","permissive":"PERMISSIVE","policyname":"Only system admins may directly insert quarantine","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"dnc_quarantine","permissive":"PERMISSIVE","policyname":"System admins can view quarantine","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_dnc_quarantine_immutable","definition":"CREATE TRIGGER trg_dnc_quarantine_immutable BEFORE DELETE OR UPDATE ON dnc_quarantine FOR EACH ROW EXECUTE FUNCTION prevent_quarantine_modification()"}],"constraints":[{"name":"dnc_quarantine_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"dnc_scrub_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"batch_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scope","type":"text","default":"'platform'::text","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"run_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"run_by_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"run_by_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"files","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"total_ftc_numbers","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"contacts_checked","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"matches_quarantined","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"certificate_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"dnc_scrub_runs_pkey","definition":"CREATE UNIQUE INDEX dnc_scrub_runs_pkey ON public.dnc_scrub_runs USING btree (id)"},{"name":"idx_dnc_scrub_runs_created_at","definition":"CREATE INDEX idx_dnc_scrub_runs_created_at ON public.dnc_scrub_runs USING btree (created_at DESC)"},{"name":"idx_dnc_scrub_runs_scope","definition":"CREATE INDEX idx_dnc_scrub_runs_scope ON public.dnc_scrub_runs USING btree (scope)"},{"name":"idx_dnc_scrub_runs_tenant","definition":"CREATE INDEX idx_dnc_scrub_runs_tenant ON public.dnc_scrub_runs USING btree (tenant_id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"dnc_scrub_runs","permissive":"PERMISSIVE","policyname":"platform_admin_manage_dnc_scrub_runs","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((tenant_id IS NOT NULL) AND (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND (ur.tenant_id = dnc_scrub_runs.tenant_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'Tenant Owner'::app_role, 'Manager'::app_role]))))))","roles":["public"],"tablename":"dnc_scrub_runs","permissive":"PERMISSIVE","policyname":"tenant_owners_view_their_scrub_runs","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"dnc_scrub_runs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"dnc_sync_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'running'::text","identity":"","not_null":true,"generated":""},{"name":"area_codes","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"rows_added","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"rows_removed","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"details","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"dnc_sync_log_pkey","definition":"CREATE UNIQUE INDEX dnc_sync_log_pkey ON public.dnc_sync_log USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR ((tenant_id IS NOT NULL) AND has_role(uid(), tenant_id, 'Owner'::app_role)))","roles":["authenticated"],"tablename":"dnc_sync_log","permissive":"PERMISSIVE","policyname":"Admins view sync log","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"dnc_sync_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"document_activity","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"document_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"document_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"activity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"activity_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"document_activity_pkey","definition":"CREATE UNIQUE INDEX document_activity_pkey ON public.document_activity USING btree (id)"},{"name":"idx_document_activity_created","definition":"CREATE INDEX idx_document_activity_created ON public.document_activity USING btree (created_at DESC)"},{"name":"idx_document_activity_doc","definition":"CREATE INDEX idx_document_activity_doc ON public.document_activity USING btree (document_id)"},{"name":"idx_document_activity_tenant","definition":"CREATE INDEX idx_document_activity_tenant ON public.document_activity USING btree (tenant_org_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"document_activity","permissive":"PERMISSIVE","policyname":"Users can create activity in their tenant","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"document_activity","permissive":"PERMISSIVE","policyname":"Users can view activity in their tenant","schemaname":"public","with_check":null}],"triggers":[{"name":"document_activity_business_projection","definition":"CREATE TRIGGER document_activity_business_projection AFTER INSERT ON document_activity FOR EACH ROW EXECUTE FUNCTION project_document_business_activity()"}],"constraints":[{"name":"document_activity_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"document_comments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"document_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"document_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"comment_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"document_comments_pkey","definition":"CREATE UNIQUE INDEX document_comments_pkey ON public.document_comments USING btree (id)"},{"name":"idx_document_comments_created","definition":"CREATE INDEX idx_document_comments_created ON public.document_comments USING btree (created_at DESC)"},{"name":"idx_document_comments_doc","definition":"CREATE INDEX idx_document_comments_doc ON public.document_comments USING btree (document_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"document_comments","permissive":"PERMISSIVE","policyname":"Users can create comments in their tenant","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"UPDATE","qual":"(user_id = uid())","roles":["public"],"tablename":"document_comments","permissive":"PERMISSIVE","policyname":"Users can update their own comments","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"document_comments","permissive":"PERMISSIVE","policyname":"Users can view comments in their tenant","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"document_comments_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"document_drafts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"document_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"content","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"document_drafts_pkey","definition":"CREATE UNIQUE INDEX document_drafts_pkey ON public.document_drafts USING btree (id)"},{"name":"idx_document_drafts_contact","definition":"CREATE INDEX idx_document_drafts_contact ON public.document_drafts USING btree (contact_id)"},{"name":"idx_document_drafts_created_by","definition":"CREATE INDEX idx_document_drafts_created_by ON public.document_drafts USING btree (created_by)"},{"name":"idx_document_drafts_tenant","definition":"CREATE INDEX idx_document_drafts_tenant ON public.document_drafts USING btree (tenant_org_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"document_drafts","permissive":"PERMISSIVE","policyname":"Users can create drafts in their tenant","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"DELETE","qual":"(created_by = uid())","roles":["public"],"tablename":"document_drafts","permissive":"PERMISSIVE","policyname":"Users can delete their drafts","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(created_by = uid())","roles":["public"],"tablename":"document_drafts","permissive":"PERMISSIVE","policyname":"Users can update their drafts","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"document_drafts","permissive":"PERMISSIVE","policyname":"Users can view drafts in their tenant","schemaname":"public","with_check":null}],"triggers":[{"name":"update_document_drafts_updated_at","definition":"CREATE TRIGGER update_document_drafts_updated_at BEFORE UPDATE ON document_drafts FOR EACH ROW EXECUTE FUNCTION update_document_drafts_updated_at()"}],"constraints":[{"name":"document_drafts_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"document_field_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"pdf_fingerprint","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"field_config","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"field_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"source_file_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"document_field_templates_pkey","definition":"CREATE UNIQUE INDEX document_field_templates_pkey ON public.document_field_templates USING btree (id)"},{"name":"idx_field_templates_fingerprint","definition":"CREATE INDEX idx_field_templates_fingerprint ON public.document_field_templates USING btree (pdf_fingerprint)"},{"name":"idx_field_templates_tenant","definition":"CREATE INDEX idx_field_templates_tenant ON public.document_field_templates USING btree (tenant_org_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"document_field_templates","permissive":"PERMISSIVE","policyname":"Tenant members can create templates","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE (utm.user_id = uid())))"},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE (utm.user_id = uid())))","roles":["authenticated"],"tablename":"document_field_templates","permissive":"PERMISSIVE","policyname":"Tenant members can update templates","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE (utm.user_id = uid())))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND ((m.tenant_id)::text = document_field_templates.tenant_org_id)))))","roles":["authenticated"],"tablename":"document_field_templates","permissive":"PERMISSIVE","policyname":"Tenant members can view templates","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"document_field_templates_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"document_fill_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"document_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"field_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"field_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"fill_source","type":"text","default":"'manual'::text","identity":"","not_null":true,"generated":""},{"name":"old_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"confidence","type":"numeric(4,3)","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"document_fill_audit_pkey","definition":"CREATE UNIQUE INDEX document_fill_audit_pkey ON public.document_fill_audit USING btree (id)"},{"name":"idx_fill_audit_document","definition":"CREATE INDEX idx_fill_audit_document ON public.document_fill_audit USING btree (document_id)"},{"name":"idx_fill_audit_tenant","definition":"CREATE INDEX idx_fill_audit_tenant ON public.document_fill_audit USING btree (tenant_org_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"document_fill_audit","permissive":"PERMISSIVE","policyname":"Authenticated users can insert audit entries","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND ((m.tenant_id)::text = document_fill_audit.tenant_org_id))))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND ((m.tenant_id)::text = document_fill_audit.tenant_org_id)))))","roles":["authenticated"],"tablename":"document_fill_audit","permissive":"PERMISSIVE","policyname":"Tenant members can view fill audit","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"document_fill_audit_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"document_fill_audit_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"document_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"requested_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"channel","type":"text","default":"'email'::text","identity":"","not_null":true,"generated":""},{"name":"recipient_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recipient_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"share_token","type":"text","default":"encode(gen_random_bytes(24), 'hex'::text)","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":"(now() + '14 days'::interval)","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"uploaded_file_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"uploaded_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"reminder_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"last_reminder_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"document_requests_pkey","definition":"CREATE UNIQUE INDEX document_requests_pkey ON public.document_requests USING btree (id)"},{"name":"document_requests_share_token_key","definition":"CREATE UNIQUE INDEX document_requests_share_token_key ON public.document_requests USING btree (share_token)"},{"name":"idx_document_requests_contact","definition":"CREATE INDEX idx_document_requests_contact ON public.document_requests USING btree (contact_id)"},{"name":"idx_document_requests_tenant","definition":"CREATE INDEX idx_document_requests_tenant ON public.document_requests USING btree (tenant_org_id, status)"},{"name":"idx_document_requests_token","definition":"CREATE INDEX idx_document_requests_token ON public.document_requests USING btree (share_token) WHERE (status = 'pending'::text)"}],"policies":[{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND ((utm.tenant_id)::text = document_requests.tenant_org_id) AND (utm.status = 'active'::text) AND (utm.is_owner = true)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"document_requests","permissive":"PERMISSIVE","policyname":"owner_admin_delete_doc_requests","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"document_requests","permissive":"PERMISSIVE","policyname":"tenant_members_insert_doc_requests","schemaname":"public","with_check":"((tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.status = 'active'::text)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.status = 'active'::text)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"document_requests","permissive":"PERMISSIVE","policyname":"tenant_members_select_doc_requests","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.status = 'active'::text)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"document_requests","permissive":"PERMISSIVE","policyname":"tenant_members_update_doc_requests","schemaname":"public","with_check":"((tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.status = 'active'::text)))) OR is_system_admin(uid()))"}],"triggers":[{"name":"trg_document_requests_updated_at","definition":"CREATE TRIGGER trg_document_requests_updated_at BEFORE UPDATE ON document_requests FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"document_requests_channel_check","definition":"CHECK (channel = ANY (ARRAY['email'::text, 'sms'::text, 'both'::text, 'link_only'::text]))"},{"name":"document_requests_pkey","definition":"PRIMARY KEY (id)"},{"name":"document_requests_share_token_key","definition":"UNIQUE (share_token)"},{"name":"document_requests_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'uploaded'::text, 'expired'::text, 'cancelled'::text]))"}]},{"table":"document_share_links","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"document_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"document_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"share_token","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"password_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"view_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"last_viewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"document_share_links_pkey","definition":"CREATE UNIQUE INDEX document_share_links_pkey ON public.document_share_links USING btree (id)"},{"name":"document_share_links_share_token_key","definition":"CREATE UNIQUE INDEX document_share_links_share_token_key ON public.document_share_links USING btree (share_token)"},{"name":"idx_document_share_doc","definition":"CREATE INDEX idx_document_share_doc ON public.document_share_links USING btree (document_id)"},{"name":"idx_document_share_token","definition":"CREATE INDEX idx_document_share_token ON public.document_share_links USING btree (share_token)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"document_share_links","permissive":"PERMISSIVE","policyname":"Users can create share links in their tenant","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"document_share_links","permissive":"PERMISSIVE","policyname":"Users can view share links in their tenant","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"document_share_links_pkey","definition":"PRIMARY KEY (id)"},{"name":"document_share_links_share_token_key","definition":"UNIQUE (share_token)"}]},{"table":"document_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"document_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"template_data","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"variables","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"usage_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"form_fields","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"field_mappings","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"pdf_template_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_fillable_pdf","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"false","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"document_templates_pkey","definition":"CREATE UNIQUE INDEX document_templates_pkey ON public.document_templates USING btree (id)"},{"name":"idx_document_templates_tenant","definition":"CREATE INDEX idx_document_templates_tenant ON public.document_templates USING btree (tenant_org_id)"},{"name":"idx_document_templates_type","definition":"CREATE INDEX idx_document_templates_type ON public.document_templates USING btree (document_type, tenant_type)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"document_templates","permissive":"PERMISSIVE","policyname":"Users can create templates in their tenant","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"DELETE","qual":"((tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.status = 'active'::text)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"document_templates","permissive":"PERMISSIVE","policyname":"Users can delete templates in their tenant","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"document_templates","permissive":"PERMISSIVE","policyname":"Users can update templates in their tenant","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"document_templates","permissive":"PERMISSIVE","policyname":"Users can view templates in their tenant","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"document_templates_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"document_versions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_file_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"version_number","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_size","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"mime_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"changes_description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"document_versions_contact_file_id_version_number_key","definition":"CREATE UNIQUE INDEX document_versions_contact_file_id_version_number_key ON public.document_versions USING btree (contact_file_id, version_number)"},{"name":"document_versions_pkey","definition":"CREATE UNIQUE INDEX document_versions_pkey ON public.document_versions USING btree (id)"},{"name":"idx_document_versions_contact_file_id","definition":"CREATE INDEX idx_document_versions_contact_file_id ON public.document_versions USING btree (contact_file_id)"},{"name":"idx_document_versions_created_at","definition":"CREATE INDEX idx_document_versions_created_at ON public.document_versions USING btree (created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"document_versions","permissive":"PERMISSIVE","policyname":"Users create document versions","schemaname":"public","with_check":"(uid() = created_by)"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM (contact_files cf\n     JOIN security_active_user_tenant_memberships utm ON (((utm.tenant_id)::text = cf.tenant_org_id)))\n  WHERE ((cf.id = document_versions.contact_file_id) AND (utm.user_id = uid()))))","roles":["public"],"tablename":"document_versions","permissive":"PERMISSIVE","policyname":"Users view document versions","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"document_versions_contact_file_id_version_number_key","definition":"UNIQUE (contact_file_id, version_number)"},{"name":"document_versions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"documents","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"scope","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"mime_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"drive_file_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"drive_web_view_link","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"uploaded_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"uploaded_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"documents_event_booking_idx","definition":"CREATE INDEX documents_event_booking_idx ON public.documents USING btree (event_booking_id)"},{"name":"documents_pkey","definition":"CREATE UNIQUE INDEX documents_pkey ON public.documents USING btree (id)"},{"name":"idx_documents_category","definition":"CREATE INDEX idx_documents_category ON public.documents USING btree (category)"},{"name":"idx_documents_scope","definition":"CREATE INDEX idx_documents_scope ON public.documents USING btree (scope)"},{"name":"idx_documents_tenant","definition":"CREATE INDEX idx_documents_tenant ON public.documents USING btree (tenant_id)"},{"name":"idx_documents_uploaded_at","definition":"CREATE INDEX idx_documents_uploaded_at ON public.documents USING btree (uploaded_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"((tenant_id IS NULL) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.tenant_id = documents.tenant_id)))))","roles":["authenticated"],"tablename":"documents","permissive":"PERMISSIVE","policyname":"Users can view accessible documents","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"documents","permissive":"PERMISSIVE","policyname":"platform_admin_manage_documents","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"ALL","qual":"((tenant_id IS NOT NULL) AND is_tenant_member(uid(), tenant_id))","roles":["authenticated"],"tablename":"documents","permissive":"PERMISSIVE","policyname":"tenant_members_manage_documents","schemaname":"public","with_check":"((tenant_id IS NOT NULL) AND is_tenant_member(uid(), tenant_id))"}],"triggers":[],"constraints":[{"name":"documents_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"documents_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"door_notes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"door_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"visit_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"author_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"author_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"author_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"visibility","type":"text","default":"'internal'::text","identity":"","not_null":true,"generated":""},{"name":"note_type","type":"text","default":"'general'::text","identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"edited_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"door_notes_pkey","definition":"CREATE UNIQUE INDEX door_notes_pkey ON public.door_notes USING btree (id)"},{"name":"idx_door_notes_author","definition":"CREATE INDEX idx_door_notes_author ON public.door_notes USING btree (author_id)"},{"name":"idx_door_notes_door","definition":"CREATE INDEX idx_door_notes_door ON public.door_notes USING btree (door_id, created_at DESC)"},{"name":"idx_door_notes_tenant","definition":"CREATE INDEX idx_door_notes_tenant ON public.door_notes USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"UPDATE","qual":"((author_id = uid()) AND (created_at > (now() - '00:15:00'::interval)))","roles":["authenticated"],"tablename":"door_notes","permissive":"PERMISSIVE","policyname":"door_notes_author_edit_window","schemaname":"public","with_check":"(author_id = uid())"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"door_notes","permissive":"PERMISSIVE","policyname":"door_notes_tenant_insert","schemaname":"public","with_check":"((author_id = uid()) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = door_notes.tenant_org_id) AND (utm.status = 'active'::text)))))"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = door_notes.tenant_org_id) AND (utm.status = 'active'::text))))","roles":["authenticated"],"tablename":"door_notes","permissive":"PERMISSIVE","policyname":"door_notes_tenant_read","schemaname":"public","with_check":null}],"triggers":[{"name":"door_notes_stamp_edited","definition":"CREATE TRIGGER door_notes_stamp_edited BEFORE UPDATE ON door_notes FOR EACH ROW EXECUTE FUNCTION tg_door_notes_stamp_edited()"}],"constraints":[{"name":"door_notes_body_not_empty","definition":"CHECK (length(TRIM(BOTH FROM body)) > 0)"},{"name":"door_notes_note_type_check","definition":"CHECK (note_type = ANY (ARRAY['general'::text, 'visit'::text, 'status_change'::text, 'contact'::text, 'followup'::text, 'system'::text]))"},{"name":"door_notes_pkey","definition":"PRIMARY KEY (id)"},{"name":"door_notes_visibility_check","definition":"CHECK (visibility = ANY (ARRAY['internal'::text, 'public'::text, 'system'::text]))"}]},{"table":"door_objects","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"territory_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lat","type":"double precision","default":null,"identity":"","not_null":true,"generated":""},{"name":"lng","type":"double precision","default":null,"identity":"","not_null":true,"generated":""},{"name":"current_status","type":"door_result_status","default":"'not_home'::door_result_status","identity":"","not_null":false,"generated":""},{"name":"last_result_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_visited_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"deletion_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":"'crm'::text","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"door_objects_pkey","definition":"CREATE UNIQUE INDEX door_objects_pkey ON public.door_objects USING btree (id)"},{"name":"idx_door_objects_contact_id","definition":"CREATE INDEX idx_door_objects_contact_id ON public.door_objects USING btree (contact_id) WHERE (contact_id IS NOT NULL)"},{"name":"idx_door_objects_deleted_at","definition":"CREATE INDEX idx_door_objects_deleted_at ON public.door_objects USING btree (deleted_at) WHERE (deleted_at IS NULL)"},{"name":"idx_door_objects_location","definition":"CREATE INDEX idx_door_objects_location ON public.door_objects USING btree (lat, lng)"},{"name":"idx_door_objects_status","definition":"CREATE INDEX idx_door_objects_status ON public.door_objects USING btree (current_status)"},{"name":"idx_door_objects_tenant","definition":"CREATE INDEX idx_door_objects_tenant ON public.door_objects USING btree (tenant_org_id)"},{"name":"idx_door_objects_territory","definition":"CREATE INDEX idx_door_objects_territory ON public.door_objects USING btree (territory_id)"}],"policies":[{"cmd":"ALL","qual":"((deleted_at IS NULL) AND (tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))))","roles":["authenticated"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Tenant members manage active doors","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Users can create doors","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Users can create doors in their tenant","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"DELETE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["authenticated"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Users can delete doors in their tenant","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((uid() = created_by) OR (EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = (door_objects.tenant_org_id)::uuid) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Users can delete doors they created","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Users can insert doors in their tenant","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = (door_objects.tenant_org_id)::uuid))))"},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Users can update doors","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["authenticated"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Users can update doors in their tenant","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"UPDATE","qual":"is_door_accessible(tenant_org_id, created_by, last_visited_by)","roles":["authenticated"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Users can update doors they can access","schemaname":"public","with_check":"is_door_accessible(tenant_org_id, created_by, last_visited_by)"},{"cmd":"ALL","qual":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) AND ((territory_id IS NULL) OR (territory_id IN ( SELECT territory_assignments.territory_id\n   FROM territory_assignments\n  WHERE (territory_assignments.user_id = uid())))))","roles":["public"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Users manage doors in assigned territories","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((deleted_at IS NULL) AND (tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))))","roles":["authenticated"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"Users view active tenant doors","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"do_all","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"door_objects_godmode_view_all","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"door_objects","permissive":"PERMISSIVE","policyname":"door_objects_tenant_owner_view_all","schemaname":"public","with_check":null}],"triggers":[{"name":"set_door_created_by_trigger","definition":"CREATE TRIGGER set_door_created_by_trigger BEFORE INSERT ON door_objects FOR EACH ROW EXECUTE FUNCTION set_door_created_by()"}],"constraints":[{"name":"door_objects_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"door_scores","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"door_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"best_visit_hour","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"best_day_of_week","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"scoring_factors","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"calculated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":"(now() + '24:00:00'::interval)","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"door_scores_door_id_key","definition":"CREATE UNIQUE INDEX door_scores_door_id_key ON public.door_scores USING btree (door_id)"},{"name":"door_scores_pkey","definition":"CREATE UNIQUE INDEX door_scores_pkey ON public.door_scores USING btree (id)"},{"name":"idx_door_scores_door_id","definition":"CREATE INDEX idx_door_scores_door_id ON public.door_scores USING btree (door_id)"},{"name":"idx_door_scores_score","definition":"CREATE INDEX idx_door_scores_score ON public.door_scores USING btree (score DESC)"},{"name":"idx_door_scores_tenant","definition":"CREATE INDEX idx_door_scores_tenant ON public.door_scores USING btree (tenant_org_id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = door_scores.tenant_org_id))))","roles":["public"],"tablename":"door_scores","permissive":"PERMISSIVE","policyname":"Tenant members view door scores","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"door_scores_best_visit_hour_check","definition":"CHECK (best_visit_hour >= 0 AND best_visit_hour <= 23)"},{"name":"door_scores_door_id_key","definition":"UNIQUE (door_id)"},{"name":"door_scores_pkey","definition":"PRIMARY KEY (id)"},{"name":"door_scores_score_check","definition":"CHECK (score >= 0 AND score <= 100)"}]},{"table":"door_status_history","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"door_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"visit_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"previous_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'visit'::text","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"door_status_history_pkey","definition":"CREATE UNIQUE INDEX door_status_history_pkey ON public.door_status_history USING btree (id)"},{"name":"idx_door_status_history_door","definition":"CREATE INDEX idx_door_status_history_door ON public.door_status_history USING btree (door_id, created_at DESC)"},{"name":"idx_door_status_history_tenant","definition":"CREATE INDEX idx_door_status_history_tenant ON public.door_status_history USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"door_status_history","permissive":"PERMISSIVE","policyname":"door_status_history_tenant_insert","schemaname":"public","with_check":"((actor_id = uid()) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = door_status_history.tenant_org_id) AND (utm.status = 'active'::text)))))"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = door_status_history.tenant_org_id) AND (utm.status = 'active'::text))))","roles":["authenticated"],"tablename":"door_status_history","permissive":"PERMISSIVE","policyname":"door_status_history_tenant_read","schemaname":"public","with_check":null}],"triggers":[{"name":"door_status_to_timeline","definition":"CREATE TRIGGER door_status_to_timeline AFTER INSERT ON door_status_history FOR EACH ROW EXECUTE FUNCTION tg_door_status_to_timeline()"}],"constraints":[{"name":"door_status_history_pkey","definition":"PRIMARY KEY (id)"},{"name":"door_status_history_source_check","definition":"CHECK (source = ANY (ARRAY['visit'::text, 'manual'::text, 'system'::text, 'batch'::text, 'import'::text]))"}]},{"table":"door_visit_media","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"visit_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"media_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"caption","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"transcription","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"file_size_bytes","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"compressed","type":"boolean","default":"false","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"door_visit_media_pkey","definition":"CREATE UNIQUE INDEX door_visit_media_pkey ON public.door_visit_media USING btree (id)"},{"name":"idx_door_visit_media_visit","definition":"CREATE INDEX idx_door_visit_media_visit ON public.door_visit_media USING btree (visit_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"door_visit_media","permissive":"PERMISSIVE","policyname":"Users can create visit media","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM door_visits\n  WHERE ((door_visits.id = door_visit_media.visit_id) AND (door_visits.user_id = uid())))) OR (EXISTS ( SELECT 1\n   FROM (door_visits dv\n     JOIN user_roles ur ON (((ur.user_id = uid()) AND (ur.tenant_id = (dv.tenant_org_id)::uuid) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))\n  WHERE (dv.id = door_visit_media.visit_id))))","roles":["authenticated"],"tablename":"door_visit_media","permissive":"PERMISSIVE","policyname":"Users can delete their visit media","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"door_visit_media","permissive":"PERMISSIVE","policyname":"Users can insert visit media","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM door_visits\n  WHERE ((door_visits.id = door_visit_media.visit_id) AND (door_visits.user_id = uid()))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM door_visits dv\n  WHERE ((dv.id = door_visit_media.visit_id) AND (dv.user_id = uid())))) OR (EXISTS ( SELECT 1\n   FROM ((door_visits dv\n     JOIN user_roles ur ON (((ur.user_id = uid()) AND (ur.tenant_id = (dv.tenant_org_id)::uuid))))\n     JOIN security_active_user_tenant_memberships m ON (((m.user_id = ur.user_id) AND (m.tenant_id = ur.tenant_id))))\n  WHERE ((dv.id = door_visit_media.visit_id) AND (m.status = 'active'::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"door_visit_media","permissive":"PERMISSIVE","policyname":"Users can view visit media","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"door_visit_media","permissive":"PERMISSIVE","policyname":"Users can view visit media in their tenant","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"door_visit_media_media_type_check","definition":"CHECK (media_type = ANY (ARRAY['photo'::text, 'video'::text, 'document'::text]))"},{"name":"door_visit_media_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"door_visits","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"door_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"visited_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"result_status","type":"door_result_status","default":null,"identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"follow_up_date","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"synced","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"offline_created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"route_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"visit_sequence","type":"integer","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"door_visits_pkey","definition":"CREATE UNIQUE INDEX door_visits_pkey ON public.door_visits USING btree (id)"},{"name":"idx_door_visits_created_contact_id","definition":"CREATE INDEX idx_door_visits_created_contact_id ON public.door_visits USING btree (created_contact_id) WHERE (created_contact_id IS NOT NULL)"},{"name":"idx_door_visits_door","definition":"CREATE INDEX idx_door_visits_door ON public.door_visits USING btree (door_id)"},{"name":"idx_door_visits_route","definition":"CREATE INDEX idx_door_visits_route ON public.door_visits USING btree (route_id, visit_sequence)"},{"name":"idx_door_visits_synced","definition":"CREATE INDEX idx_door_visits_synced ON public.door_visits USING btree (synced, offline_created_at)"},{"name":"idx_door_visits_tenant","definition":"CREATE INDEX idx_door_visits_tenant ON public.door_visits USING btree (tenant_org_id)"},{"name":"idx_door_visits_user","definition":"CREATE INDEX idx_door_visits_user ON public.door_visits USING btree (user_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"door_visits","permissive":"PERMISSIVE","policyname":"Users can create visits","schemaname":"public","with_check":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) AND (user_id = uid()))"},{"cmd":"DELETE","qual":"((user_id = uid()) OR (EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = (door_visits.tenant_org_id)::uuid) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"door_visits","permissive":"PERMISSIVE","policyname":"Users can delete their own visits","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"door_visits","permissive":"PERMISSIVE","policyname":"Users can insert their own visits","schemaname":"public","with_check":"((user_id = uid()) AND (EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = (door_visits.tenant_org_id)::uuid)))))"},{"cmd":"UPDATE","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"door_visits","permissive":"PERMISSIVE","policyname":"Users can update their own visits","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"SELECT","qual":"((user_id = uid()) OR is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN security_active_user_tenant_memberships m ON (((m.user_id = ur.user_id) AND (m.tenant_id = ur.tenant_id))))\n  WHERE ((ur.user_id = uid()) AND (ur.tenant_id = (door_visits.tenant_org_id)::uuid) AND (m.status = 'active'::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"door_visits","permissive":"PERMISSIVE","policyname":"Users can view accessible visits","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"door_visits","permissive":"PERMISSIVE","policyname":"Users can view visits in their tenant","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"door_visits","permissive":"PERMISSIVE","policyname":"dv_all","schemaname":"public","with_check":null}],"triggers":[{"name":"auto_create_recontact_trigger","definition":"CREATE TRIGGER auto_create_recontact_trigger AFTER INSERT ON door_visits FOR EACH ROW EXECUTE FUNCTION auto_create_recontact()"},{"name":"trigger_update_door_status","definition":"CREATE TRIGGER trigger_update_door_status AFTER INSERT ON door_visits FOR EACH ROW EXECUTE FUNCTION update_door_object_status()"},{"name":"update_canvassing_stats_trigger","definition":"CREATE TRIGGER update_canvassing_stats_trigger AFTER INSERT ON door_visits FOR EACH ROW EXECUTE FUNCTION update_canvassing_stats()"}],"constraints":[{"name":"door_visits_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"duplicate_detection_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_id_1","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_id_2","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"similarity_score","type":"numeric(5,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"match_fields","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"resolved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"duplicate_detection_log_pkey","definition":"CREATE UNIQUE INDEX duplicate_detection_log_pkey ON public.duplicate_detection_log USING btree (id)"},{"name":"idx_duplicate_detection_status","definition":"CREATE INDEX idx_duplicate_detection_status ON public.duplicate_detection_log USING btree (status)"},{"name":"idx_duplicate_detection_tenant","definition":"CREATE INDEX idx_duplicate_detection_tenant ON public.duplicate_detection_log USING btree (tenant_id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = duplicate_detection_log.tenant_id))))","roles":["public"],"tablename":"duplicate_detection_log","permissive":"PERMISSIVE","policyname":"Users view tenant duplicates","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"duplicate_detection_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"duplicate_detection_results","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id_1","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id_2","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"confidence_score","type":"numeric(5,4)","default":null,"identity":"","not_null":true,"generated":""},{"name":"matching_fields","type":"text[]","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"merged_to_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"auto_detected","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"duplicate_detection_results_lead_id_1_lead_id_2_key","definition":"CREATE UNIQUE INDEX duplicate_detection_results_lead_id_1_lead_id_2_key ON public.duplicate_detection_results USING btree (lead_id_1, lead_id_2)"},{"name":"duplicate_detection_results_pkey","definition":"CREATE UNIQUE INDEX duplicate_detection_results_pkey ON public.duplicate_detection_results USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"duplicate_detection_results","permissive":"PERMISSIVE","policyname":"Tenant isolation for duplicate_detection_results","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"duplicate_detection_results_lead_id_1_lead_id_2_key","definition":"UNIQUE (lead_id_1, lead_id_2)"},{"name":"duplicate_detection_results_pkey","definition":"PRIMARY KEY (id)"},{"name":"duplicate_detection_results_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'merged'::text, 'dismissed'::text, 'reviewed'::text]))"}]},{"table":"duplicate_merge_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"merge_date","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"merged_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"keeper_record_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"merged_record_ids","type":"uuid[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"merge_strategy","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"merged_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"merge_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"can_undo","type":"boolean","default":"true","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"duplicate_merge_audit_pkey","definition":"CREATE UNIQUE INDEX duplicate_merge_audit_pkey ON public.duplicate_merge_audit USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"duplicate_merge_audit","permissive":"PERMISSIVE","policyname":"System admins can manage merge audit","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"duplicate_merge_audit_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"elevated_patch_audit_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"request_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"elevated_patch_audit_events_pkey","definition":"CREATE UNIQUE INDEX elevated_patch_audit_events_pkey ON public.elevated_patch_audit_events USING btree (id)"},{"name":"idx_epae_request_created","definition":"CREATE INDEX idx_epae_request_created ON public.elevated_patch_audit_events USING btree (request_id, created_at)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin() OR (actor_user_id = uid()) OR (EXISTS ( SELECT 1\n   FROM elevated_patch_requests r\n  WHERE ((r.request_id = elevated_patch_audit_events.request_id) AND (r.tenant_id IS NOT NULL) AND is_tenant_member(uid(), r.tenant_id)))))","roles":["authenticated"],"tablename":"elevated_patch_audit_events","permissive":"PERMISSIVE","policyname":"epae_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"elevated_patch_audit_events_event_type_check","definition":"CHECK (event_type = ANY (ARRAY['planned'::text, 'approved'::text, 'running'::text, 'succeeded'::text, 'failed'::text, 'cancelled'::text, 'rolled_back'::text]))"},{"name":"elevated_patch_audit_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"elevated_patch_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"request_id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"command_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"parsed_intent","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"verb","type":"text","default":"'unsupported'::text","identity":"","not_null":true,"generated":""},{"name":"target_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"target_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"generated_plan","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"plan_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"approved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"approved_plan_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"approval_note","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'awaiting_approval'::text","identity":"","not_null":true,"generated":""},{"name":"action_taken","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"result","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"supported","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"authorized","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"approved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"executed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"risk_level","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pre_approved_by_godmode","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"human_summary","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"elevated_patch_requests_pkey","definition":"CREATE UNIQUE INDEX elevated_patch_requests_pkey ON public.elevated_patch_requests USING btree (id)"},{"name":"elevated_patch_requests_request_id_key","definition":"CREATE UNIQUE INDEX elevated_patch_requests_request_id_key ON public.elevated_patch_requests USING btree (request_id)"},{"name":"idx_elevated_patch_requests_actor_created","definition":"CREATE INDEX idx_elevated_patch_requests_actor_created ON public.elevated_patch_requests USING btree (actor_user_id, created_at DESC)"},{"name":"idx_epr_status","definition":"CREATE INDEX idx_epr_status ON public.elevated_patch_requests USING btree (status)"},{"name":"idx_epr_tenant_created","definition":"CREATE INDEX idx_epr_tenant_created ON public.elevated_patch_requests USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin() OR (actor_user_id = uid()) OR ((tenant_id IS NOT NULL) AND is_tenant_member(uid(), tenant_id)))","roles":["authenticated"],"tablename":"elevated_patch_requests","permissive":"PERMISSIVE","policyname":"epr_select","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_touch_elevated_patch_requests","definition":"CREATE TRIGGER trg_touch_elevated_patch_requests BEFORE UPDATE ON elevated_patch_requests FOR EACH ROW EXECUTE FUNCTION touch_elevated_patch_requests()"}],"constraints":[{"name":"elevated_patch_requests_pkey","definition":"PRIMARY KEY (id)"},{"name":"elevated_patch_requests_request_id_key","definition":"UNIQUE (request_id)"},{"name":"elevated_patch_requests_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'awaiting_approval'::text, 'approved'::text, 'running'::text, 'succeeded'::text, 'failed'::text, 'cancelled'::text, 'rolled_back'::text]))"}]},{"table":"email_campaigns","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":false,"generated":""},{"name":"scheduled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"recipient_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"opened_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"clicked_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"email_campaigns_pkey","definition":"CREATE UNIQUE INDEX email_campaigns_pkey ON public.email_campaigns USING btree (id)"},{"name":"idx_email_campaigns_status","definition":"CREATE INDEX idx_email_campaigns_status ON public.email_campaigns USING btree (status)"},{"name":"idx_email_campaigns_tenant_id","definition":"CREATE INDEX idx_email_campaigns_tenant_id ON public.email_campaigns USING btree (tenant_id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = email_campaigns.tenant_id))))","roles":["public"],"tablename":"email_campaigns","permissive":"PERMISSIVE","policyname":"Users view tenant campaigns","schemaname":"public","with_check":null}],"triggers":[{"name":"email_campaigns_updated_at","definition":"CREATE TRIGGER email_campaigns_updated_at BEFORE UPDATE ON email_campaigns FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"email_campaigns_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"email_messages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"recipient_email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"sender_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"sender_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sender_display_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"subject","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""},{"name":"provider_message_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"idempotency_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"email_messages_event_booking_idx","definition":"CREATE INDEX email_messages_event_booking_idx ON public.email_messages USING btree (event_booking_id)"},{"name":"email_messages_pkey","definition":"CREATE UNIQUE INDEX email_messages_pkey ON public.email_messages USING btree (id)"},{"name":"email_messages_tenant_idem_uidx","definition":"CREATE UNIQUE INDEX email_messages_tenant_idem_uidx ON public.email_messages USING btree (tenant_org_id, idempotency_key) WHERE (idempotency_key IS NOT NULL)"},{"name":"idx_email_messages_contact","definition":"CREATE INDEX idx_email_messages_contact ON public.email_messages USING btree (contact_id)"},{"name":"idx_email_messages_sender","definition":"CREATE INDEX idx_email_messages_sender ON public.email_messages USING btree (sender_user_id)"},{"name":"idx_email_messages_status","definition":"CREATE INDEX idx_email_messages_status ON public.email_messages USING btree (status)"},{"name":"idx_email_messages_tenant","definition":"CREATE INDEX idx_email_messages_tenant ON public.email_messages USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(NOT is_tenant_crew_only(uid(), tenant_org_id))","roles":["authenticated"],"tablename":"email_messages","permissive":"RESTRICTIVE","policyname":"email_messages_block_crew","schemaname":"public","with_check":"(NOT is_tenant_crew_only(uid(), tenant_org_id))"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"email_messages","permissive":"PERMISSIVE","policyname":"email_messages_godmode_read","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((sender_user_id = uid()) AND is_tenant_member(uid(), tenant_org_id))","roles":["public"],"tablename":"email_messages","permissive":"PERMISSIVE","policyname":"email_messages_self_read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"email_messages","permissive":"PERMISSIVE","policyname":"email_messages_service_role","schemaname":"public","with_check":"true"},{"cmd":"SELECT","qual":"(is_tenant_owner_or_admin(uid(), tenant_org_id) OR is_manager_or_higher(uid(), tenant_org_id))","roles":["public"],"tablename":"email_messages","permissive":"PERMISSIVE","policyname":"email_messages_tenant_managers_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"email_messages_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"email_messages_pkey","definition":"PRIMARY KEY (id)"},{"name":"email_messages_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'queued'::text, 'sent'::text, 'failed'::text, 'bounced'::text]))"}]},{"table":"email_send_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"message_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"recipient_email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"email_send_log_pkey","definition":"CREATE UNIQUE INDEX email_send_log_pkey ON public.email_send_log USING btree (id)"},{"name":"idx_email_send_log_created","definition":"CREATE INDEX idx_email_send_log_created ON public.email_send_log USING btree (created_at DESC)"},{"name":"idx_email_send_log_message","definition":"CREATE INDEX idx_email_send_log_message ON public.email_send_log USING btree (message_id)"},{"name":"idx_email_send_log_message_sent_unique","definition":"CREATE UNIQUE INDEX idx_email_send_log_message_sent_unique ON public.email_send_log USING btree (message_id) WHERE (status = 'sent'::text)"},{"name":"idx_email_send_log_recipient","definition":"CREATE INDEX idx_email_send_log_recipient ON public.email_send_log USING btree (recipient_email)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["service_role"],"tablename":"email_send_log","permissive":"PERMISSIVE","policyname":"Service role can insert send log","schemaname":"public","with_check":"true"},{"cmd":"SELECT","qual":"true","roles":["service_role"],"tablename":"email_send_log","permissive":"PERMISSIVE","policyname":"Service role can read send log","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"true","roles":["service_role"],"tablename":"email_send_log","permissive":"PERMISSIVE","policyname":"Service role can update send log","schemaname":"public","with_check":"true"}],"triggers":[],"constraints":[{"name":"email_send_log_pkey","definition":"PRIMARY KEY (id)"},{"name":"email_send_log_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'sent'::text, 'suppressed'::text, 'failed'::text, 'bounced'::text, 'complained'::text, 'dlq'::text]))"}]},{"table":"email_send_state","schema":"public","columns":[{"name":"id","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"retry_after_until","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"batch_size","type":"integer","default":"10","identity":"","not_null":true,"generated":""},{"name":"send_delay_ms","type":"integer","default":"200","identity":"","not_null":true,"generated":""},{"name":"auth_email_ttl_minutes","type":"integer","default":"15","identity":"","not_null":true,"generated":""},{"name":"transactional_email_ttl_minutes","type":"integer","default":"60","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"email_send_state_pkey","definition":"CREATE UNIQUE INDEX email_send_state_pkey ON public.email_send_state USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"email_send_state","permissive":"PERMISSIVE","policyname":"Service role can manage send state","schemaname":"public","with_check":"true"}],"triggers":[],"constraints":[{"name":"email_send_state_id_check","definition":"CHECK (id = 1)"},{"name":"email_send_state_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"email_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"variables","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"template_context","type":"text","default":"'all'::text","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"email_templates_pkey","definition":"CREATE UNIQUE INDEX email_templates_pkey ON public.email_templates USING btree (id)"},{"name":"idx_email_templates_category","definition":"CREATE INDEX idx_email_templates_category ON public.email_templates USING btree (category)"},{"name":"idx_email_templates_context","definition":"CREATE INDEX idx_email_templates_context ON public.email_templates USING btree (tenant_id, template_context, is_active)"},{"name":"idx_email_templates_tenant_id","definition":"CREATE INDEX idx_email_templates_tenant_id ON public.email_templates USING btree (tenant_id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = email_templates.tenant_id))))","roles":["public"],"tablename":"email_templates","permissive":"PERMISSIVE","policyname":"Users view tenant templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((tenant_id IS NULL) OR (NOT is_tenant_crew_only(uid(), (tenant_id)::uuid)))","roles":["authenticated"],"tablename":"email_templates","permissive":"RESTRICTIVE","policyname":"email_templates_block_crew","schemaname":"public","with_check":"((tenant_id IS NULL) OR (NOT is_tenant_crew_only(uid(), (tenant_id)::uuid)))"},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"email_templates","permissive":"PERMISSIVE","policyname":"email_templates_godmode","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"ALL","qual":"((tenant_id IS NOT NULL) AND is_manager_or_higher(uid(), (tenant_id)::uuid))","roles":["public"],"tablename":"email_templates","permissive":"PERMISSIVE","policyname":"email_templates_manager_manage","schemaname":"public","with_check":"((tenant_id IS NOT NULL) AND is_manager_or_higher(uid(), (tenant_id)::uuid))"},{"cmd":"SELECT","qual":"((tenant_id IS NULL) OR is_tenant_member(uid(), (tenant_id)::uuid))","roles":["public"],"tablename":"email_templates","permissive":"PERMISSIVE","policyname":"email_templates_tenant_member_read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((tenant_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_id)::uuid))","roles":["public"],"tablename":"email_templates","permissive":"PERMISSIVE","policyname":"email_templates_tenant_owner_manage","schemaname":"public","with_check":"((tenant_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_id)::uuid))"}],"triggers":[{"name":"email_templates_updated_at","definition":"CREATE TRIGGER email_templates_updated_at BEFORE UPDATE ON email_templates FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"email_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"email_templates_template_context_check","definition":"CHECK (template_context = ANY (ARRAY['contact'::text, 'appointment'::text, 'all'::text, 'event_booking'::text]))"}]},{"table":"email_tracking_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"email_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"ip_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"link_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"email_tracking_events_pkey","definition":"CREATE UNIQUE INDEX email_tracking_events_pkey ON public.email_tracking_events USING btree (id)"},{"name":"idx_email_tracking_contact","definition":"CREATE INDEX idx_email_tracking_contact ON public.email_tracking_events USING btree (contact_id)"},{"name":"idx_email_tracking_email","definition":"CREATE INDEX idx_email_tracking_email ON public.email_tracking_events USING btree (email_id)"},{"name":"idx_email_tracking_tenant","definition":"CREATE INDEX idx_email_tracking_tenant ON public.email_tracking_events USING btree (tenant_id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"email_tracking_events","permissive":"PERMISSIVE","policyname":"Tenant isolation for email_tracking_events","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"email_tracking_events_event_type_check","definition":"CHECK (event_type = ANY (ARRAY['sent'::text, 'delivered'::text, 'opened'::text, 'clicked'::text, 'bounced'::text, 'complained'::text, 'unsubscribed'::text]))"},{"name":"email_tracking_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"email_unsubscribe_tokens","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"token","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"used_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"email_unsubscribe_tokens_email_key","definition":"CREATE UNIQUE INDEX email_unsubscribe_tokens_email_key ON public.email_unsubscribe_tokens USING btree (email)"},{"name":"email_unsubscribe_tokens_pkey","definition":"CREATE UNIQUE INDEX email_unsubscribe_tokens_pkey ON public.email_unsubscribe_tokens USING btree (id)"},{"name":"email_unsubscribe_tokens_token_key","definition":"CREATE UNIQUE INDEX email_unsubscribe_tokens_token_key ON public.email_unsubscribe_tokens USING btree (token)"},{"name":"idx_unsubscribe_tokens_token","definition":"CREATE INDEX idx_unsubscribe_tokens_token ON public.email_unsubscribe_tokens USING btree (token)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["service_role"],"tablename":"email_unsubscribe_tokens","permissive":"PERMISSIVE","policyname":"Service role can insert tokens","schemaname":"public","with_check":"true"},{"cmd":"UPDATE","qual":"true","roles":["service_role"],"tablename":"email_unsubscribe_tokens","permissive":"PERMISSIVE","policyname":"Service role can mark tokens as used","schemaname":"public","with_check":"true"},{"cmd":"SELECT","qual":"true","roles":["service_role"],"tablename":"email_unsubscribe_tokens","permissive":"PERMISSIVE","policyname":"Service role can read tokens","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"email_unsubscribe_tokens_email_key","definition":"UNIQUE (email)"},{"name":"email_unsubscribe_tokens_pkey","definition":"PRIMARY KEY (id)"},{"name":"email_unsubscribe_tokens_token_key","definition":"UNIQUE (token)"}]},{"table":"email_unsubscribes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"unsubscribed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"resubscribed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"email_unsubscribes_pkey","definition":"CREATE UNIQUE INDEX email_unsubscribes_pkey ON public.email_unsubscribes USING btree (id)"},{"name":"email_unsubscribes_tenant_id_email_key","definition":"CREATE UNIQUE INDEX email_unsubscribes_tenant_id_email_key ON public.email_unsubscribes USING btree (tenant_id, email)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"email_unsubscribes","permissive":"PERMISSIVE","policyname":"Tenant isolation for email_unsubscribes","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"email_unsubscribes_pkey","definition":"PRIMARY KEY (id)"},{"name":"email_unsubscribes_tenant_id_email_key","definition":"UNIQUE (tenant_id, email)"}]},{"table":"enrichment_queue","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"total_contacts","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"processed","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"enriched","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"failed","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_invocation_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"invocation_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"current_offset","type":"integer","default":"0","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"enrichment_queue_pkey","definition":"CREATE UNIQUE INDEX enrichment_queue_pkey ON public.enrichment_queue USING btree (id)"},{"name":"idx_enrichment_queue_tenant_status","definition":"CREATE INDEX idx_enrichment_queue_tenant_status ON public.enrichment_queue USING btree (tenant_org_id, status)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"enrichment_queue","permissive":"PERMISSIVE","policyname":"Users can create enrichment jobs for their tenant","schemaname":"public","with_check":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) OR is_system_admin(uid()))","roles":["public"],"tablename":"enrichment_queue","permissive":"PERMISSIVE","policyname":"Users can view their tenant enrichment jobs","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"enrichment_queue","permissive":"PERMISSIVE","policyname":"tenant_members_update_enrichment","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"}],"triggers":[],"constraints":[{"name":"enrichment_queue_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"esign_health_checks","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"check_type","type":"text","default":"'synthetic_canary'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"runtime_identity","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"evidence","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"error_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"esign_health_checks_created_at_idx","definition":"CREATE INDEX esign_health_checks_created_at_idx ON public.esign_health_checks USING btree (created_at DESC)"},{"name":"esign_health_checks_pkey","definition":"CREATE UNIQUE INDEX esign_health_checks_pkey ON public.esign_health_checks USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"esign_health_checks_check_type_check","definition":"CHECK (check_type = 'synthetic_canary'::text)"},{"name":"esign_health_checks_pkey","definition":"PRIMARY KEY (id)"},{"name":"esign_health_checks_status_check","definition":"CHECK (status = ANY (ARRAY['running'::text, 'passed'::text, 'failed'::text]))"}]},{"table":"estimate_share_links","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"estimate_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"share_token","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"password_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"view_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"last_viewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"allow_acceptance","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"accepted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"accepted_signature","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"accepted_ip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"estimate_share_links_pkey","definition":"CREATE UNIQUE INDEX estimate_share_links_pkey ON public.estimate_share_links USING btree (id)"},{"name":"estimate_share_links_share_token_key","definition":"CREATE UNIQUE INDEX estimate_share_links_share_token_key ON public.estimate_share_links USING btree (share_token)"},{"name":"idx_share_links_estimate","definition":"CREATE INDEX idx_share_links_estimate ON public.estimate_share_links USING btree (estimate_id)"},{"name":"idx_share_links_token","definition":"CREATE INDEX idx_share_links_token ON public.estimate_share_links USING btree (share_token)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"estimate_share_links","permissive":"PERMISSIVE","policyname":"Users create tenant share links","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"DELETE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"estimate_share_links","permissive":"PERMISSIVE","policyname":"Users delete tenant share links","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"estimate_share_links","permissive":"PERMISSIVE","policyname":"Users update tenant share links","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"estimate_share_links","permissive":"PERMISSIVE","policyname":"Users view tenant share links","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(share_token = ((current_setting('request.headers'::text, true))::json ->> 'x-share-token'::text))","roles":["anon","authenticated"],"tablename":"estimate_share_links","permissive":"PERMISSIVE","policyname":"View by share token only","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"estimate_share_links_pkey","definition":"PRIMARY KEY (id)"},{"name":"estimate_share_links_share_token_key","definition":"UNIQUE (share_token)"}]},{"table":"estimate_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"manufacturer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"shingle_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"underlayment_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"material_items","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"labor_items","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"default_margin_pct","type":"numeric","default":"20","identity":"","not_null":false,"generated":""},{"name":"default_tax_pct","type":"numeric","default":"7","identity":"","not_null":false,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"estimate_templates_pkey","definition":"CREATE UNIQUE INDEX estimate_templates_pkey ON public.estimate_templates USING btree (id)"},{"name":"idx_templates_tenant","definition":"CREATE INDEX idx_templates_tenant ON public.estimate_templates USING btree (tenant_org_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"estimate_templates","permissive":"PERMISSIVE","policyname":"Users create tenant templates","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"DELETE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"estimate_templates","permissive":"PERMISSIVE","policyname":"Users delete tenant templates","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"estimate_templates","permissive":"PERMISSIVE","policyname":"Users update tenant templates","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"estimate_templates","permissive":"PERMISSIVE","policyname":"Users view tenant templates","schemaname":"public","with_check":null}],"triggers":[{"name":"estimate_templates_updated_at","definition":"CREATE TRIGGER estimate_templates_updated_at BEFORE UPDATE ON estimate_templates FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"estimate_templates_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"event_bookings","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"venue_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":"'other'::text","identity":"","not_null":true,"generated":""},{"name":"stage","type":"text","default":"'Inquiry'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"event_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"start_time","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"end_time","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"location","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"guest_count","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"pricing_basis","type":"text","default":"'flat_event'::text","identity":"","not_null":true,"generated":""},{"name":"service_unit_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"quoted_units","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"served_units","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"setup","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_package","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"quote_amount","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"deposit_amount","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"balance_due","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"staffing","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"requirements","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"loadout","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"expenses","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_intake","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"confirmed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"event_bookings_contact_idx","definition":"CREATE INDEX event_bookings_contact_idx ON public.event_bookings USING btree (contact_id)"},{"name":"event_bookings_pkey","definition":"CREATE UNIQUE INDEX event_bookings_pkey ON public.event_bookings USING btree (id)"},{"name":"event_bookings_source_ref_uq","definition":"CREATE UNIQUE INDEX event_bookings_source_ref_uq ON public.event_bookings USING btree (tenant_org_id, source, source_ref) WHERE (source_ref IS NOT NULL)"},{"name":"event_bookings_tenant_date_idx","definition":"CREATE INDEX event_bookings_tenant_date_idx ON public.event_bookings USING btree (tenant_org_id, event_date)"},{"name":"event_bookings_tenant_stage_idx","definition":"CREATE INDEX event_bookings_tenant_stage_idx ON public.event_bookings USING btree (tenant_org_id, stage)"},{"name":"event_bookings_tenant_start_idx","definition":"CREATE INDEX event_bookings_tenant_start_idx ON public.event_bookings USING btree (tenant_org_id, start_time)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"event_bookings","permissive":"PERMISSIVE","policyname":"event_bookings_tenant_access","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin())"}],"triggers":[{"name":"event_booking_completion_normalizer","definition":"CREATE TRIGGER event_booking_completion_normalizer BEFORE INSERT OR UPDATE OF stage, status, completed_at ON event_bookings FOR EACH ROW EXECUTE FUNCTION normalize_event_booking_completion()"},{"name":"event_bookings_business_activity","definition":"CREATE TRIGGER event_bookings_business_activity AFTER INSERT OR UPDATE ON event_bookings FOR EACH ROW EXECUTE FUNCTION project_event_booking_business_activity()"},{"name":"sync_mobile_vendor_event_expenses_to_finance_trigger","definition":"CREATE TRIGGER sync_mobile_vendor_event_expenses_to_finance_trigger AFTER INSERT OR UPDATE OF expenses, event_date, event_name ON event_bookings FOR EACH ROW EXECUTE FUNCTION sync_mobile_vendor_event_expenses_to_finance()"}],"constraints":[{"name":"event_bookings_amounts_nonnegative","definition":"CHECK ((quote_amount IS NULL OR quote_amount >= 0::numeric) AND (deposit_amount IS NULL OR deposit_amount >= 0::numeric) AND (balance_due IS NULL OR balance_due >= 0::numeric))"},{"name":"event_bookings_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"event_bookings_guest_count_nonnegative","definition":"CHECK (guest_count IS NULL OR guest_count >= 0)"},{"name":"event_bookings_pkey","definition":"PRIMARY KEY (id)"},{"name":"event_bookings_service_units_nonnegative","definition":"CHECK ((quoted_units IS NULL OR quoted_units >= 0) AND (served_units IS NULL OR served_units >= 0))"}]},{"table":"event_rental_asset_allocations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"asset_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"quantity","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'reserved'::text","identity":"","not_null":true,"generated":""},{"name":"starts_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"ends_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"event_rental_allocations_asset_time_idx","definition":"CREATE INDEX event_rental_allocations_asset_time_idx ON public.event_rental_asset_allocations USING btree (asset_id, starts_at, ends_at) WHERE (status = ANY (ARRAY['reserved'::text, 'deployed'::text]))"},{"name":"event_rental_allocations_tenant_event_idx","definition":"CREATE INDEX event_rental_allocations_tenant_event_idx ON public.event_rental_asset_allocations USING btree (tenant_id, event_booking_id)"},{"name":"event_rental_asset_allocations_pkey","definition":"CREATE UNIQUE INDEX event_rental_asset_allocations_pkey ON public.event_rental_asset_allocations USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member((tenant_id)::text) OR is_system_admin())","roles":["public"],"tablename":"event_rental_asset_allocations","permissive":"PERMISSIVE","policyname":"event_rental_allocations_tenant_access","schemaname":"public","with_check":"(is_tenant_member((tenant_id)::text) OR is_system_admin())"}],"triggers":[{"name":"event_rental_allocations_capacity_guard","definition":"CREATE TRIGGER event_rental_allocations_capacity_guard BEFORE INSERT OR UPDATE OF tenant_id, event_booking_id, asset_id, quantity, status, starts_at, ends_at ON event_rental_asset_allocations FOR EACH ROW EXECUTE FUNCTION check_event_rental_allocation_capacity()"},{"name":"event_rental_allocations_tenant_guard","definition":"CREATE TRIGGER event_rental_allocations_tenant_guard BEFORE INSERT OR UPDATE OF tenant_id, event_booking_id ON event_rental_asset_allocations FOR EACH ROW EXECUTE FUNCTION assert_event_rental_booking_tenant()"}],"constraints":[{"name":"event_rental_asset_allocations_asset_id_fkey","definition":"FOREIGN KEY (asset_id) REFERENCES event_rental_assets(id) ON DELETE RESTRICT"},{"name":"event_rental_asset_allocations_check","definition":"CHECK (ends_at > starts_at)"},{"name":"event_rental_asset_allocations_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE CASCADE"},{"name":"event_rental_asset_allocations_pkey","definition":"PRIMARY KEY (id)"},{"name":"event_rental_asset_allocations_quantity_check","definition":"CHECK (quantity > 0)"},{"name":"event_rental_asset_allocations_status_check","definition":"CHECK (status = ANY (ARRAY['reserved'::text, 'deployed'::text, 'returned'::text, 'cancelled'::text]))"},{"name":"event_rental_asset_allocations_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"event_rental_assets","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"asset_code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"total_quantity","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"lifecycle_status","type":"text","default":"'available'::text","identity":"","not_null":true,"generated":""},{"name":"condition_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"event_rental_assets_pkey","definition":"CREATE UNIQUE INDEX event_rental_assets_pkey ON public.event_rental_assets USING btree (id)"},{"name":"event_rental_assets_tenant_category_idx","definition":"CREATE INDEX event_rental_assets_tenant_category_idx ON public.event_rental_assets USING btree (tenant_id, category, lifecycle_status)"},{"name":"event_rental_assets_tenant_id_asset_code_key","definition":"CREATE UNIQUE INDEX event_rental_assets_tenant_id_asset_code_key ON public.event_rental_assets USING btree (tenant_id, asset_code)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member((tenant_id)::text) OR is_system_admin())","roles":["public"],"tablename":"event_rental_assets","permissive":"PERMISSIVE","policyname":"event_rental_assets_tenant_access","schemaname":"public","with_check":"(is_tenant_member((tenant_id)::text) OR is_system_admin())"}],"triggers":[],"constraints":[{"name":"event_rental_assets_lifecycle_status_check","definition":"CHECK (lifecycle_status = ANY (ARRAY['available'::text, 'inspection_needed'::text, 'damaged'::text, 'repair'::text, 'retired'::text]))"},{"name":"event_rental_assets_pkey","definition":"PRIMARY KEY (id)"},{"name":"event_rental_assets_tenant_id_asset_code_key","definition":"UNIQUE (tenant_id, asset_code)"},{"name":"event_rental_assets_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"event_rental_assets_total_quantity_check","definition":"CHECK (total_quantity > 0)"}]},{"table":"event_rental_event_vendors","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"vendor_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assignment_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'planned'::text","identity":"","not_null":true,"generated":""},{"name":"financial_metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"event_rental_event_vendors_event_booking_id_vendor_id_key","definition":"CREATE UNIQUE INDEX event_rental_event_vendors_event_booking_id_vendor_id_key ON public.event_rental_event_vendors USING btree (event_booking_id, vendor_id)"},{"name":"event_rental_event_vendors_event_idx","definition":"CREATE INDEX event_rental_event_vendors_event_idx ON public.event_rental_event_vendors USING btree (tenant_id, event_booking_id, status)"},{"name":"event_rental_event_vendors_pkey","definition":"CREATE UNIQUE INDEX event_rental_event_vendors_pkey ON public.event_rental_event_vendors USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member((tenant_id)::text) OR is_system_admin())","roles":["public"],"tablename":"event_rental_event_vendors","permissive":"PERMISSIVE","policyname":"event_rental_event_vendors_tenant_access","schemaname":"public","with_check":"(is_tenant_member((tenant_id)::text) OR is_system_admin())"}],"triggers":[{"name":"event_rental_event_vendors_tenant_guard","definition":"CREATE TRIGGER event_rental_event_vendors_tenant_guard BEFORE INSERT OR UPDATE OF tenant_id, event_booking_id ON event_rental_event_vendors FOR EACH ROW EXECUTE FUNCTION assert_event_rental_booking_tenant()"},{"name":"event_rental_event_vendors_vendor_guard","definition":"CREATE TRIGGER event_rental_event_vendors_vendor_guard BEFORE INSERT OR UPDATE OF tenant_id, vendor_id ON event_rental_event_vendors FOR EACH ROW EXECUTE FUNCTION assert_event_rental_vendor_tenant()"}],"constraints":[{"name":"event_rental_event_vendors_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE CASCADE"},{"name":"event_rental_event_vendors_event_booking_id_vendor_id_key","definition":"UNIQUE (event_booking_id, vendor_id)"},{"name":"event_rental_event_vendors_pkey","definition":"PRIMARY KEY (id)"},{"name":"event_rental_event_vendors_status_check","definition":"CHECK (status = ANY (ARRAY['planned'::text, 'invited'::text, 'confirmed'::text, 'onsite'::text, 'complete'::text, 'cancelled'::text, 'blocked'::text]))"},{"name":"event_rental_event_vendors_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"event_rental_event_vendors_vendor_id_fkey","definition":"FOREIGN KEY (vendor_id) REFERENCES event_rental_vendors(id) ON DELETE RESTRICT"}]},{"table":"event_rental_readiness_items","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"item_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"required","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"blocker_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"event_rental_readiness_event_idx","definition":"CREATE INDEX event_rental_readiness_event_idx ON public.event_rental_readiness_items USING btree (tenant_id, event_booking_id, status)"},{"name":"event_rental_readiness_items_event_booking_id_item_key_key","definition":"CREATE UNIQUE INDEX event_rental_readiness_items_event_booking_id_item_key_key ON public.event_rental_readiness_items USING btree (event_booking_id, item_key)"},{"name":"event_rental_readiness_items_pkey","definition":"CREATE UNIQUE INDEX event_rental_readiness_items_pkey ON public.event_rental_readiness_items USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member((tenant_id)::text) OR is_system_admin())","roles":["public"],"tablename":"event_rental_readiness_items","permissive":"PERMISSIVE","policyname":"event_rental_readiness_tenant_access","schemaname":"public","with_check":"(is_tenant_member((tenant_id)::text) OR is_system_admin())"}],"triggers":[{"name":"event_rental_readiness_tenant_guard","definition":"CREATE TRIGGER event_rental_readiness_tenant_guard BEFORE INSERT OR UPDATE OF tenant_id, event_booking_id ON event_rental_readiness_items FOR EACH ROW EXECUTE FUNCTION assert_event_rental_booking_tenant()"}],"constraints":[{"name":"event_rental_readiness_items_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE CASCADE"},{"name":"event_rental_readiness_items_event_booking_id_item_key_key","definition":"UNIQUE (event_booking_id, item_key)"},{"name":"event_rental_readiness_items_pkey","definition":"PRIMARY KEY (id)"},{"name":"event_rental_readiness_items_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'ready'::text, 'blocked'::text, 'not_applicable'::text]))"},{"name":"event_rental_readiness_items_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"event_rental_vendors","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"organization_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"license_metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"document_metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"insurance_coi_metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"insurance_expires_on","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"performance_history","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"event_rental_vendor_insurance_idx","definition":"CREATE INDEX event_rental_vendor_insurance_idx ON public.event_rental_vendors USING btree (tenant_id, insurance_expires_on) WHERE (insurance_expires_on IS NOT NULL)"},{"name":"event_rental_vendors_pkey","definition":"CREATE UNIQUE INDEX event_rental_vendors_pkey ON public.event_rental_vendors USING btree (id)"},{"name":"event_rental_vendors_tenant_category_idx","definition":"CREATE INDEX event_rental_vendors_tenant_category_idx ON public.event_rental_vendors USING btree (tenant_id, category, status)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member((tenant_id)::text) OR is_system_admin())","roles":["public"],"tablename":"event_rental_vendors","permissive":"PERMISSIVE","policyname":"event_rental_vendors_tenant_access","schemaname":"public","with_check":"(is_tenant_member((tenant_id)::text) OR is_system_admin())"}],"triggers":[],"constraints":[{"name":"event_rental_vendors_pkey","definition":"PRIMARY KEY (id)"},{"name":"event_rental_vendors_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'inactive'::text, 'needs_review'::text, 'blocked'::text]))"},{"name":"event_rental_vendors_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"event_workflow_steps","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"phase","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"step_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"event_workflow_steps_event_booking_id_step_key_key","definition":"CREATE UNIQUE INDEX event_workflow_steps_event_booking_id_step_key_key ON public.event_workflow_steps USING btree (event_booking_id, step_key)"},{"name":"event_workflow_steps_event_idx","definition":"CREATE INDEX event_workflow_steps_event_idx ON public.event_workflow_steps USING btree (event_booking_id, sort_order)"},{"name":"event_workflow_steps_pkey","definition":"CREATE UNIQUE INDEX event_workflow_steps_pkey ON public.event_workflow_steps USING btree (id)"},{"name":"event_workflow_steps_tenant_status_idx","definition":"CREATE INDEX event_workflow_steps_tenant_status_idx ON public.event_workflow_steps USING btree (tenant_org_id, status)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"event_workflow_steps","permissive":"PERMISSIVE","policyname":"event_workflow_steps_tenant_access","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin())"}],"triggers":[],"constraints":[{"name":"event_workflow_steps_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE CASCADE"},{"name":"event_workflow_steps_event_booking_id_step_key_key","definition":"UNIQUE (event_booking_id, step_key)"},{"name":"event_workflow_steps_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"experience_preview_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"token_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"projected_role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"surface_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"route","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"device","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"version_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"parent_origin","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"validated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"experience_preview_sessions_expiry_idx","definition":"CREATE INDEX experience_preview_sessions_expiry_idx ON public.experience_preview_sessions USING btree (expires_at)"},{"name":"experience_preview_sessions_pkey","definition":"CREATE UNIQUE INDEX experience_preview_sessions_pkey ON public.experience_preview_sessions USING btree (id)"},{"name":"experience_preview_sessions_token_hash_key","definition":"CREATE UNIQUE INDEX experience_preview_sessions_token_hash_key ON public.experience_preview_sessions USING btree (token_hash)"},{"name":"experience_preview_sessions_user_tenant_idx","definition":"CREATE INDEX experience_preview_sessions_user_tenant_idx ON public.experience_preview_sessions USING btree (user_id, tenant_id, expires_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"experience_preview_sessions_device_check","definition":"CHECK (device = ANY (ARRAY['desktop'::text, 'tablet'::text, 'mobile'::text]))"},{"name":"experience_preview_sessions_pkey","definition":"PRIMARY KEY (id)"},{"name":"experience_preview_sessions_projected_role_check","definition":"CHECK (projected_role = ANY (ARRAY['Owner'::text, 'Manager'::text, 'Operator'::text, 'Field'::text]))"},{"name":"experience_preview_sessions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"experience_preview_sessions_token_hash_key","definition":"UNIQUE (token_hash)"},{"name":"experience_preview_sessions_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"feature_entitlement_audit_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"target_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"feature_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"previous_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"previous_effective_access","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_effective_access","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"feature_entitlement_audit_log_pkey","definition":"CREATE UNIQUE INDEX feature_entitlement_audit_log_pkey ON public.feature_entitlement_audit_log USING btree (id)"},{"name":"idx_feal_created","definition":"CREATE INDEX idx_feal_created ON public.feature_entitlement_audit_log USING btree (created_at DESC)"},{"name":"idx_feal_feature","definition":"CREATE INDEX idx_feal_feature ON public.feature_entitlement_audit_log USING btree (feature_key)"},{"name":"idx_feal_tenant","definition":"CREATE INDEX idx_feal_tenant ON public.feature_entitlement_audit_log USING btree (tenant_org_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"feature_entitlement_audit_log","permissive":"PERMISSIVE","policyname":"feal system admin insert","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"feature_entitlement_audit_log","permissive":"PERMISSIVE","policyname":"feal system admin read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"feature_entitlement_audit_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"feature_flags","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"flag_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'experimental'::text","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"rollout_percentage","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"feature_flags_flag_key_tenant_id_key","definition":"CREATE UNIQUE INDEX feature_flags_flag_key_tenant_id_key ON public.feature_flags USING btree (flag_key, tenant_id)"},{"name":"feature_flags_pkey","definition":"CREATE UNIQUE INDEX feature_flags_pkey ON public.feature_flags USING btree (id)"},{"name":"idx_feature_flags_key","definition":"CREATE INDEX idx_feature_flags_key ON public.feature_flags USING btree (flag_key)"},{"name":"idx_feature_flags_tenant","definition":"CREATE INDEX idx_feature_flags_tenant ON public.feature_flags USING btree (tenant_id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"feature_flags","permissive":"PERMISSIVE","policyname":"Authenticated can read feature flags","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"feature_flags","permissive":"PERMISSIVE","policyname":"Platform admins can manage feature flags","schemaname":"public","with_check":"is_platform_admin(uid())"}],"triggers":[{"name":"trg_feature_flags_updated_at","definition":"CREATE TRIGGER trg_feature_flags_updated_at BEFORE UPDATE ON feature_flags FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"feature_flags_flag_key_tenant_id_key","definition":"UNIQUE (flag_key, tenant_id)"},{"name":"feature_flags_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"feature_permissions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"feature_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"granted_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"granted_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"feature_permissions_pkey","definition":"CREATE UNIQUE INDEX feature_permissions_pkey ON public.feature_permissions USING btree (id)"},{"name":"feature_permissions_user_tenant_feature_uniq","definition":"CREATE UNIQUE INDEX feature_permissions_user_tenant_feature_uniq ON public.feature_permissions USING btree (user_id, COALESCE(tenant_id, '00000000-0000-0000-0000-000000000000'::uuid), feature_name)"},{"name":"idx_feature_permissions_user_feature","definition":"CREATE INDEX idx_feature_permissions_user_feature ON public.feature_permissions USING btree (user_id, feature_name)"}],"policies":[{"cmd":"ALL","qual":"((tenant_id IS NOT NULL) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = feature_permissions.tenant_id) AND (m.is_owner = true) AND (m.status = 'active'::text)))))","roles":["authenticated"],"tablename":"feature_permissions","permissive":"PERMISSIVE","policyname":"Tenant owners manage feature permissions in their tenant","schemaname":"public","with_check":"((tenant_id IS NOT NULL) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = feature_permissions.tenant_id) AND (m.is_owner = true) AND (m.status = 'active'::text)))))"},{"cmd":"SELECT","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"feature_permissions","permissive":"PERMISSIVE","policyname":"Users view own permissions","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"feature_permissions","permissive":"PERMISSIVE","policyname":"platform_admin_manage_feature_permissions","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"feature_permissions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"feature_preview_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"feature_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"feature_preview_log_pkey","definition":"CREATE UNIQUE INDEX feature_preview_log_pkey ON public.feature_preview_log USING btree (id)"},{"name":"idx_feature_preview_log_tenant","definition":"CREATE INDEX idx_feature_preview_log_tenant ON public.feature_preview_log USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"feature_preview_log","permissive":"PERMISSIVE","policyname":"Authenticated users log their own preview events","schemaname":"public","with_check":"((uid() IS NOT NULL) AND ((user_id IS NULL) OR (user_id = uid())))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = feature_preview_log.tenant_id) AND (m.status = 'active'::text)))))","roles":["public"],"tablename":"feature_preview_log","permissive":"PERMISSIVE","policyname":"Tenant members and admins read preview log","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"feature_preview_log_action_check","definition":"CHECK (action = ANY (ARRAY['view_blurred'::text, 'click_locked'::text, 'hover_upgrade'::text, 'open_upgrade_modal'::text, 'dismiss_upgrade'::text]))"},{"name":"feature_preview_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"finance_accounts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"external_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"institution_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"account_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"account_subtype","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last4","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"last_synced_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"finance_accounts_pkey","definition":"CREATE UNIQUE INDEX finance_accounts_pkey ON public.finance_accounts USING btree (id)"},{"name":"finance_accounts_tenant_idx","definition":"CREATE INDEX finance_accounts_tenant_idx ON public.finance_accounts USING btree (tenant_id, provider, status)"},{"name":"finance_accounts_tenant_provider_external_key","definition":"CREATE UNIQUE INDEX finance_accounts_tenant_provider_external_key ON public.finance_accounts USING btree (tenant_id, provider, external_id)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = finance_accounts.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["public"],"tablename":"finance_accounts","permissive":"PERMISSIVE","policyname":"finance_accounts_tenant_select","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = finance_accounts.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["public"],"tablename":"finance_accounts","permissive":"PERMISSIVE","policyname":"finance_accounts_tenant_write","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = finance_accounts.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"finance_accounts_pkey","definition":"PRIMARY KEY (id)"},{"name":"finance_accounts_provider_check","definition":"CHECK (provider = ANY (ARRAY['stripe'::text, 'stripe_financial_connections'::text, 'manual'::text, 'import'::text]))"},{"name":"finance_accounts_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'pending'::text, 'disconnected'::text, 'error'::text]))"},{"name":"finance_accounts_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"finance_accounts_tenant_provider_external_key","definition":"UNIQUE (tenant_id, provider, external_id)"}]},{"table":"finance_report_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"scheduled_report_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"period_start","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_end","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'generating'::text","identity":"","not_null":true,"generated":""},{"name":"storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recipients","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"recipient_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"totals","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"finance_report_runs_pkey","definition":"CREATE UNIQUE INDEX finance_report_runs_pkey ON public.finance_report_runs USING btree (id)"},{"name":"finance_report_runs_schedule_created_idx","definition":"CREATE INDEX finance_report_runs_schedule_created_idx ON public.finance_report_runs USING btree (scheduled_report_id, created_at DESC) WHERE (scheduled_report_id IS NOT NULL)"},{"name":"finance_report_runs_tenant_created_idx","definition":"CREATE INDEX finance_report_runs_tenant_created_idx ON public.finance_report_runs USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = finance_report_runs.tenant_id) AND (COALESCE(membership.status, 'active'::text) = 'active'::text)))))","roles":["public"],"tablename":"finance_report_runs","permissive":"PERMISSIVE","policyname":"finance_report_runs_tenant_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"finance_report_runs_period_check","definition":"CHECK (period_end >= period_start)"},{"name":"finance_report_runs_pkey","definition":"PRIMARY KEY (id)"},{"name":"finance_report_runs_recipient_count_check","definition":"CHECK (recipient_count >= 0)"},{"name":"finance_report_runs_scheduled_report_id_fkey","definition":"FOREIGN KEY (scheduled_report_id) REFERENCES scheduled_reports(id) ON DELETE SET NULL"},{"name":"finance_report_runs_status_check","definition":"CHECK (status = ANY (ARRAY['generating'::text, 'generated'::text, 'queued'::text, 'sent'::text, 'failed'::text]))"},{"name":"finance_report_runs_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"finance_transactions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"account_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":"'manual'::text","identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_external_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"transaction_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"posted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"merchant","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"description","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"amount","type":"numeric(14,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"direction","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"transaction_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"category","type":"text","default":"'Uncategorized'::text","identity":"","not_null":true,"generated":""},{"name":"classification","type":"text","default":"'review'::text","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"receipt_document_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"finance_transactions_pkey","definition":"CREATE UNIQUE INDEX finance_transactions_pkey ON public.finance_transactions USING btree (id)"},{"name":"finance_transactions_tenant_category_idx","definition":"CREATE INDEX finance_transactions_tenant_category_idx ON public.finance_transactions USING btree (tenant_id, category, transaction_date DESC)"},{"name":"finance_transactions_tenant_date_idx","definition":"CREATE INDEX finance_transactions_tenant_date_idx ON public.finance_transactions USING btree (tenant_id, transaction_date DESC)"},{"name":"finance_transactions_tenant_review_idx","definition":"CREATE INDEX finance_transactions_tenant_review_idx ON public.finance_transactions USING btree (tenant_id, classification, transaction_date DESC)"},{"name":"finance_transactions_tenant_source_external_key","definition":"CREATE UNIQUE INDEX finance_transactions_tenant_source_external_key ON public.finance_transactions USING btree (tenant_id, source, provider_external_id)"}],"policies":[{"cmd":"ALL","qual":"((uid() IS NOT NULL) AND (is_system_admin(uid()) OR is_tenant_owner_or_admin(uid(), tenant_id) OR user_has_permission(uid(), 'admin.billing'::text, tenant_id)))","roles":["public"],"tablename":"finance_transactions","permissive":"RESTRICTIVE","policyname":"finance_transactions_permission_gate","schemaname":"public","with_check":"((uid() IS NOT NULL) AND (is_system_admin(uid()) OR is_tenant_owner_or_admin(uid(), tenant_id) OR user_has_permission(uid(), 'admin.billing'::text, tenant_id)))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = finance_transactions.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["public"],"tablename":"finance_transactions","permissive":"PERMISSIVE","policyname":"finance_transactions_tenant_select","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = finance_transactions.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))","roles":["public"],"tablename":"finance_transactions","permissive":"PERMISSIVE","policyname":"finance_transactions_tenant_write","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = finance_transactions.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"finance_transactions_account_id_fkey","definition":"FOREIGN KEY (account_id) REFERENCES finance_accounts(id) ON DELETE SET NULL"},{"name":"finance_transactions_amount_check","definition":"CHECK (amount >= 0::numeric)"},{"name":"finance_transactions_classification_check","definition":"CHECK (classification = ANY (ARRAY['business'::text, 'personal'::text, 'review'::text]))"},{"name":"finance_transactions_direction_check","definition":"CHECK (direction = ANY (ARRAY['income'::text, 'expense'::text]))"},{"name":"finance_transactions_pkey","definition":"PRIMARY KEY (id)"},{"name":"finance_transactions_source_check","definition":"CHECK (source ~ '^[a-z0-9][a-z0-9_]{1,63}$'::text)"},{"name":"finance_transactions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"finance_transactions_tenant_source_external_key","definition":"UNIQUE (tenant_id, source, provider_external_id)"}]},{"table":"florida_jurisdictions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"jurisdiction_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"jurisdiction_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"county","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"region","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"portal_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"portal_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"portal_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adapter_status","type":"text","default":"'not_started'::text","identity":"","not_null":true,"generated":""},{"name":"adapter_class","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"edge_function_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"supports_roof_permits","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"supports_all_permits","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"data_quality_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"population","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority","type":"integer","default":"50","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"florida_jurisdictions_jurisdiction_key_key","definition":"CREATE UNIQUE INDEX florida_jurisdictions_jurisdiction_key_key ON public.florida_jurisdictions USING btree (jurisdiction_key)"},{"name":"florida_jurisdictions_pkey","definition":"CREATE UNIQUE INDEX florida_jurisdictions_pkey ON public.florida_jurisdictions USING btree (id)"},{"name":"idx_florida_jurisdictions_adapter_status","definition":"CREATE INDEX idx_florida_jurisdictions_adapter_status ON public.florida_jurisdictions USING btree (adapter_status)"},{"name":"idx_florida_jurisdictions_county","definition":"CREATE INDEX idx_florida_jurisdictions_county ON public.florida_jurisdictions USING btree (county)"},{"name":"idx_florida_jurisdictions_portal_type","definition":"CREATE INDEX idx_florida_jurisdictions_portal_type ON public.florida_jurisdictions USING btree (portal_type)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["public"],"tablename":"florida_jurisdictions","permissive":"PERMISSIVE","policyname":"Anyone can read jurisdiction data","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"florida_jurisdictions","permissive":"PERMISSIVE","policyname":"System admins can modify jurisdiction data","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[{"name":"update_florida_jurisdictions_updated_at","definition":"CREATE TRIGGER update_florida_jurisdictions_updated_at BEFORE UPDATE ON florida_jurisdictions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"florida_jurisdictions_adapter_status_check","definition":"CHECK (adapter_status = ANY (ARRAY['not_started'::text, 'in_progress'::text, 'active'::text, 'deprecated'::text, 'blocked'::text]))"},{"name":"florida_jurisdictions_jurisdiction_key_key","definition":"UNIQUE (jurisdiction_key)"},{"name":"florida_jurisdictions_jurisdiction_type_check","definition":"CHECK (jurisdiction_type = ANY (ARRAY['county'::text, 'city'::text, 'town'::text, 'village'::text, 'special_district'::text]))"},{"name":"florida_jurisdictions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"foil_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"property_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"municipality","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"request_status","type":"text","default":"'not_requested'::text","identity":"","not_null":true,"generated":""},{"name":"request_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"response_due_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"response_received_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"records_requested","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"records_received_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"foil_requests_pkey","definition":"CREATE UNIQUE INDEX foil_requests_pkey ON public.foil_requests USING btree (id)"},{"name":"idx_foil_property","definition":"CREATE INDEX idx_foil_property ON public.foil_requests USING btree (property_id)"},{"name":"idx_foil_status","definition":"CREATE INDEX idx_foil_status ON public.foil_requests USING btree (request_status)"},{"name":"idx_foil_tenant","definition":"CREATE INDEX idx_foil_tenant ON public.foil_requests USING btree (tenant_org_id)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"foil_requests","permissive":"PERMISSIVE","policyname":"foil_delete_tenant_members","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"foil_requests","permissive":"PERMISSIVE","policyname":"foil_insert_tenant_members","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_org_id)"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"foil_requests","permissive":"PERMISSIVE","policyname":"foil_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"foil_requests","permissive":"PERMISSIVE","policyname":"foil_update_tenant_members","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_org_id)"}],"triggers":[{"name":"trg_foil_updated_at","definition":"CREATE TRIGGER trg_foil_updated_at BEFORE UPDATE ON foil_requests FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"foil_requests_pkey","definition":"PRIMARY KEY (id)"},{"name":"foil_requests_request_status_check","definition":"CHECK (request_status = ANY (ARRAY['not_requested'::text, 'drafted'::text, 'submitted'::text, 'received'::text, 'denied'::text, 'archived'::text]))"}]},{"table":"followups","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"followup_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'Pending'::text","identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"followups_pkey","definition":"CREATE UNIQUE INDEX followups_pkey ON public.followups USING btree (id)"},{"name":"idx_followups_date","definition":"CREATE INDEX idx_followups_date ON public.followups USING btree (followup_date)"},{"name":"idx_followups_rep","definition":"CREATE INDEX idx_followups_rep ON public.followups USING btree (rep_email)"}],"policies":[{"cmd":"ALL","qual":"(rep_email = ( SELECT profiles.email\n   FROM profiles\n  WHERE (profiles.id = uid())))","roles":["public"],"tablename":"followups","permissive":"PERMISSIVE","policyname":"Users manage own followups","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(rep_email = ( SELECT profiles.email\n   FROM profiles\n  WHERE (profiles.id = uid())))","roles":["public"],"tablename":"followups","permissive":"PERMISSIVE","policyname":"Users view own followups","schemaname":"public","with_check":null}],"triggers":[{"name":"audit_trigger_followups","definition":"CREATE TRIGGER audit_trigger_followups AFTER INSERT OR DELETE OR UPDATE ON followups FOR EACH ROW EXECUTE FUNCTION comprehensive_audit_trigger_fn()"}],"constraints":[{"name":"followups_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"funnel_snapshots","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"funnel_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"snapshot_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage_data","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"total_leads","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"total_converted","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"overall_conversion_rate","type":"numeric(5,2)","default":"0","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"funnel_snapshots_pkey","definition":"CREATE UNIQUE INDEX funnel_snapshots_pkey ON public.funnel_snapshots USING btree (id)"},{"name":"idx_funnel_snapshots_date","definition":"CREATE INDEX idx_funnel_snapshots_date ON public.funnel_snapshots USING btree (snapshot_date)"},{"name":"idx_funnel_snapshots_funnel","definition":"CREATE INDEX idx_funnel_snapshots_funnel ON public.funnel_snapshots USING btree (funnel_id)"}],"policies":[{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"funnel_snapshots","permissive":"PERMISSIVE","policyname":"Users can view own tenant funnel snapshots","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"funnel_snapshots_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"godmode_page_overrides","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"route_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"route_pattern","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_scope","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"device_scope","type":"text","default":"'all'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":"'Untitled Shell Studio override'::text","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"operations","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"published_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"published_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"godmode_page_overrides_pkey","definition":"CREATE UNIQUE INDEX godmode_page_overrides_pkey ON public.godmode_page_overrides USING btree (id)"},{"name":"godmode_page_overrides_route_status_idx","definition":"CREATE INDEX godmode_page_overrides_route_status_idx ON public.godmode_page_overrides USING btree (route_path, status, device_scope)"}],"policies":[{"cmd":"ALL","qual":"is_platform_admin(request_user_id())","roles":["authenticated"],"tablename":"godmode_page_overrides","permissive":"PERMISSIVE","policyname":"godmode_page_overrides_platform_admin_manage","schemaname":"public","with_check":"is_platform_admin(request_user_id())"},{"cmd":"SELECT","qual":"(status = 'published'::text)","roles":["public"],"tablename":"godmode_page_overrides","permissive":"PERMISSIVE","policyname":"godmode_page_overrides_published_read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"can_manage_page_override(request_user_id(), tenant_scope)","roles":["authenticated"],"tablename":"godmode_page_overrides","permissive":"PERMISSIVE","policyname":"godmode_page_overrides_tenant_manage","schemaname":"public","with_check":"can_manage_page_override(request_user_id(), tenant_scope)"}],"triggers":[],"constraints":[{"name":"godmode_page_overrides_device_scope_check","definition":"CHECK (device_scope = ANY (ARRAY['all'::text, 'desktop'::text, 'mobile'::text]))"},{"name":"godmode_page_overrides_pkey","definition":"PRIMARY KEY (id)"},{"name":"godmode_page_overrides_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'published'::text, 'archived'::text]))"}]},{"table":"hail_swaths","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"event_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"bbox_minlat","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"bbox_minlng","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"bbox_maxlat","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"bbox_maxlng","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"max_hail_inches","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"cells_geojson","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"cell_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'mrms_mesh'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"hail_swaths_pkey","definition":"CREATE UNIQUE INDEX hail_swaths_pkey ON public.hail_swaths USING btree (id)"},{"name":"idx_hail_swaths_bbox","definition":"CREATE INDEX idx_hail_swaths_bbox ON public.hail_swaths USING btree (bbox_minlat, bbox_maxlat, bbox_minlng, bbox_maxlng)"},{"name":"idx_hail_swaths_dedupe","definition":"CREATE UNIQUE INDEX idx_hail_swaths_dedupe ON public.hail_swaths USING btree (event_date, bbox_minlat, bbox_minlng, bbox_maxlat, bbox_maxlng, source)"},{"name":"idx_hail_swaths_event_date","definition":"CREATE INDEX idx_hail_swaths_event_date ON public.hail_swaths USING btree (event_date DESC)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"hail_swaths","permissive":"PERMISSIVE","policyname":"Authenticated users can read hail swaths","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"hail_swaths_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"homeowner_financing_prequals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"credit_tier","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"annual_income","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"requested_amount","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"term_months","type":"integer","default":"120","identity":"","not_null":true,"generated":""},{"name":"estimated_apr","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"monthly_payment","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"approval_likelihood","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lender_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_reference","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"homeowner_financing_prequals_pkey","definition":"CREATE UNIQUE INDEX homeowner_financing_prequals_pkey ON public.homeowner_financing_prequals USING btree (id)"},{"name":"idx_financing_prequals_contact","definition":"CREATE INDEX idx_financing_prequals_contact ON public.homeowner_financing_prequals USING btree (contact_id)"},{"name":"idx_financing_prequals_tenant","definition":"CREATE INDEX idx_financing_prequals_tenant ON public.homeowner_financing_prequals USING btree (tenant_org_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"homeowner_financing_prequals","permissive":"PERMISSIVE","policyname":"Tenant members create financing prequals","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.status = 'active'::text))))"},{"cmd":"DELETE","qual":"(tenant_org_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.status = 'active'::text))))","roles":["public"],"tablename":"homeowner_financing_prequals","permissive":"PERMISSIVE","policyname":"Tenant members delete financing prequals","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.status = 'active'::text))))","roles":["public"],"tablename":"homeowner_financing_prequals","permissive":"PERMISSIVE","policyname":"Tenant members update financing prequals","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.status = 'active'::text))))","roles":["public"],"tablename":"homeowner_financing_prequals","permissive":"PERMISSIVE","policyname":"Tenant members view financing prequals","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_financing_prequals_updated_at","definition":"CREATE TRIGGER trg_financing_prequals_updated_at BEFORE UPDATE ON homeowner_financing_prequals FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"homeowner_financing_prequals_approval_likelihood_check","definition":"CHECK (approval_likelihood = ANY (ARRAY['high'::text, 'medium'::text, 'low'::text]))"},{"name":"homeowner_financing_prequals_credit_tier_check","definition":"CHECK (credit_tier = ANY (ARRAY['excellent'::text, 'good'::text, 'fair'::text, 'poor'::text]))"},{"name":"homeowner_financing_prequals_pkey","definition":"PRIMARY KEY (id)"},{"name":"homeowner_financing_prequals_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'submitted'::text, 'approved'::text, 'declined'::text, 'funded'::text]))"}]},{"table":"homeowner_stage_messages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"vertical","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"pipeline_kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body_md","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_milestone","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"send_to_homeowner","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"homeowner_stage_messages_pkey","definition":"CREATE UNIQUE INDEX homeowner_stage_messages_pkey ON public.homeowner_stage_messages USING btree (id)"},{"name":"homeowner_stage_messages_tenant_org_id_vertical_pipeline_ki_key","definition":"CREATE UNIQUE INDEX homeowner_stage_messages_tenant_org_id_vertical_pipeline_ki_key ON public.homeowner_stage_messages USING btree (tenant_org_id, vertical, pipeline_kind, stage_name)"},{"name":"idx_hsm_lookup","definition":"CREATE INDEX idx_hsm_lookup ON public.homeowner_stage_messages USING btree (vertical, pipeline_kind, stage_name) WHERE (send_to_homeowner = true)"},{"name":"idx_hsm_tenant","definition":"CREATE INDEX idx_hsm_tenant ON public.homeowner_stage_messages USING btree (tenant_org_id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"homeowner_stage_messages","permissive":"PERMISSIVE","policyname":"hsm_godmode_manage","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))","roles":["authenticated"],"tablename":"homeowner_stage_messages","permissive":"PERMISSIVE","policyname":"hsm_read_defaults_or_tenant","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_org_id))","roles":["public"],"tablename":"homeowner_stage_messages","permissive":"PERMISSIVE","policyname":"hsm_tenant_owner_manage","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_org_id))"}],"triggers":[{"name":"trg_hsm_updated_at","definition":"CREATE TRIGGER trg_hsm_updated_at BEFORE UPDATE ON homeowner_stage_messages FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"homeowner_stage_messages_pipeline_kind_check","definition":"CHECK (pipeline_kind = ANY (ARRAY['LEAD'::text, 'CLAIM'::text, 'JOB'::text]))"},{"name":"homeowner_stage_messages_pkey","definition":"PRIMARY KEY (id)"},{"name":"homeowner_stage_messages_tenant_org_id_vertical_pipeline_ki_key","definition":"UNIQUE (tenant_org_id, vertical, pipeline_kind, stage_name)"},{"name":"homeowner_stage_messages_vertical_check","definition":"CHECK (vertical = ANY (ARRAY['public_adjuster'::text, 'roofer'::text, 'mitigation'::text, 'realtor'::text, 'universal'::text]))"}]},{"table":"ims_logs","schema":"public","columns":[{"name":"id","type":"bigint","default":"nextval('ims_logs_id_seq'::regclass)","identity":"","not_null":true,"generated":""},{"name":"ts","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"op","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"ok","type":"boolean","default":null,"identity":"","not_null":true,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"extra","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"ims_logs_pkey","definition":"CREATE UNIQUE INDEX ims_logs_pkey ON public.ims_logs USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"ims_logs","permissive":"PERMISSIVE","policyname":"ims_logs_insert","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND ((m.tenant_id)::text = ims_logs.tenant_id)))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND ((m.tenant_id)::text = ims_logs.tenant_id)))))","roles":["authenticated"],"tablename":"ims_logs","permissive":"PERMISSIVE","policyname":"ims_logs_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"ims_logs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"ims_sessions","schema":"public","columns":[{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"cookie","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"refreshed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"meta","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"ims_sessions_pkey","definition":"CREATE UNIQUE INDEX ims_sessions_pkey ON public.ims_sessions USING btree (tenant_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"ims_sessions","permissive":"PERMISSIVE","policyname":"ims_sessions_insert","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND ((m.tenant_id)::text = ims_sessions.tenant_id)))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN security_active_user_tenant_memberships m ON (((m.user_id = ur.user_id) AND (m.tenant_id = ur.tenant_id))))\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = ims_sessions.tenant_id) AND (m.status = 'active'::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"ims_sessions","permissive":"PERMISSIVE","policyname":"ims_sessions_select_owner_admin","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND ((m.tenant_id)::text = ims_sessions.tenant_id)))))","roles":["authenticated"],"tablename":"ims_sessions","permissive":"PERMISSIVE","policyname":"ims_sessions_update","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND ((m.tenant_id)::text = ims_sessions.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"ims_sessions_pkey","definition":"PRIMARY KEY (tenant_id)"}]},{"table":"inbound_call_logs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assigned_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"twilio_number_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"twilio_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"from_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"to_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"direction","type":"text","default":"'inbound'::text","identity":"","not_null":true,"generated":""},{"name":"call_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voicemail_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voicemail_transcription","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"forwarded_to","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_payload","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_inbound_call_logs_tenant","definition":"CREATE INDEX idx_inbound_call_logs_tenant ON public.inbound_call_logs USING btree (tenant_org_id)"},{"name":"idx_inbound_call_logs_to","definition":"CREATE INDEX idx_inbound_call_logs_to ON public.inbound_call_logs USING btree (to_number)"},{"name":"idx_inbound_call_logs_user","definition":"CREATE INDEX idx_inbound_call_logs_user ON public.inbound_call_logs USING btree (assigned_user_id)"},{"name":"inbound_call_logs_pkey","definition":"CREATE UNIQUE INDEX inbound_call_logs_pkey ON public.inbound_call_logs USING btree (id)"},{"name":"inbound_call_logs_twilio_call_sid_key","definition":"CREATE UNIQUE INDEX inbound_call_logs_twilio_call_sid_key ON public.inbound_call_logs USING btree (twilio_call_sid)"}],"policies":[{"cmd":"SELECT","qual":"(assigned_user_id = uid())","roles":["authenticated"],"tablename":"inbound_call_logs","permissive":"PERMISSIVE","policyname":"Reps view their own inbound calls","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id, uid())","roles":["authenticated"],"tablename":"inbound_call_logs","permissive":"PERMISSIVE","policyname":"Tenant owners view all inbound calls","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_owner_capture_unknown_inbound_call_contact","definition":"CREATE TRIGGER trg_owner_capture_unknown_inbound_call_contact BEFORE INSERT ON inbound_call_logs FOR EACH ROW EXECUTE FUNCTION owner_capture_unknown_inbound_call_contact()"},{"name":"update_inbound_call_logs_updated_at","definition":"CREATE TRIGGER update_inbound_call_logs_updated_at BEFORE UPDATE ON inbound_call_logs FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"inbound_call_logs_pkey","definition":"PRIMARY KEY (id)"},{"name":"inbound_call_logs_twilio_call_sid_key","definition":"UNIQUE (twilio_call_sid)"}]},{"table":"inbound_email_signals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider","type":"text","default":"'provider_agnostic'::text","identity":"","not_null":true,"generated":""},{"name":"provider_message_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sender_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sender_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"subject","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"received_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"classification","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"confidence","type":"numeric(5,4)","default":null,"identity":"","not_null":false,"generated":""},{"name":"extracted","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"attachments","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"proposed_actions","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"safe_updates","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'review'::text","identity":"","not_null":true,"generated":""},{"name":"raw_metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"inbound_email_signals_pkey","definition":"CREATE UNIQUE INDEX inbound_email_signals_pkey ON public.inbound_email_signals USING btree (id)"},{"name":"inbound_email_signals_provider_message_uq","definition":"CREATE UNIQUE INDEX inbound_email_signals_provider_message_uq ON public.inbound_email_signals USING btree (tenant_org_id, provider, provider_message_id) WHERE (provider_message_id IS NOT NULL)"},{"name":"inbound_email_signals_review_idx","definition":"CREATE INDEX inbound_email_signals_review_idx ON public.inbound_email_signals USING btree (tenant_org_id, status, received_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"inbound_email_signals","permissive":"PERMISSIVE","policyname":"inbound_email_signals_tenant_access","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin())"}],"triggers":[{"name":"inbound_email_signals_materialize_owner_notes_tasks","definition":"CREATE TRIGGER inbound_email_signals_materialize_owner_notes_tasks AFTER INSERT OR UPDATE OF classification, status, proposed_actions, extracted, subject, sender_name, sender_email, provider, provider_message_id ON inbound_email_signals FOR EACH ROW EXECUTE FUNCTION materialize_owner_notes_tasks_from_email_signal()"}],"constraints":[{"name":"inbound_email_signals_confidence_range","definition":"CHECK (confidence IS NULL OR confidence >= 0::numeric AND confidence <= 1::numeric)"},{"name":"inbound_email_signals_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"inbound_email_signals_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"inbound_email_signals_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"inbound_integration_keys","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"key_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"key_prefix","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"allowed_sources","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_used_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_inbound_integration_keys_active","definition":"CREATE INDEX idx_inbound_integration_keys_active ON public.inbound_integration_keys USING btree (is_active) WHERE (is_active = true)"},{"name":"idx_inbound_integration_keys_tenant","definition":"CREATE INDEX idx_inbound_integration_keys_tenant ON public.inbound_integration_keys USING btree (tenant_org_id)"},{"name":"inbound_integration_keys_key_hash_key","definition":"CREATE UNIQUE INDEX inbound_integration_keys_key_hash_key ON public.inbound_integration_keys USING btree (key_hash)"},{"name":"inbound_integration_keys_pkey","definition":"CREATE UNIQUE INDEX inbound_integration_keys_pkey ON public.inbound_integration_keys USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin()","roles":["authenticated"],"tablename":"inbound_integration_keys","permissive":"PERMISSIVE","policyname":"GodMode can manage inbound integration keys","schemaname":"public","with_check":"is_system_admin()"}],"triggers":[],"constraints":[{"name":"inbound_integration_keys_key_hash_key","definition":"UNIQUE (key_hash)"},{"name":"inbound_integration_keys_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"inbound_routing_profiles","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"timezone","type":"text","default":"'America/New_York'::text","identity":"","not_null":true,"generated":""},{"name":"business_hours","type":"jsonb","default":"'{\"fri\": {\"open\": \"09:00\", \"close\": \"18:00\"}, \"mon\": {\"open\": \"09:00\", \"close\": \"18:00\"}, \"sat\": {\"closed\": true}, \"sun\": {\"closed\": true}, \"thu\": {\"open\": \"09:00\", \"close\": \"18:00\"}, \"tue\": {\"open\": \"09:00\", \"close\": \"18:00\"}, \"wed\": {\"open\": \"09:00\", \"close\": \"18:00\"}}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"caller_id_match_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"open_action","type":"text","default":"'ivr'::text","identity":"","not_null":true,"generated":""},{"name":"open_target_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"closed_action","type":"text","default":"'voicemail'::text","identity":"","not_null":true,"generated":""},{"name":"closed_target_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"closed_greeting","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_routing_profile_tenant","definition":"CREATE INDEX idx_routing_profile_tenant ON public.inbound_routing_profiles USING btree (tenant_org_id)"},{"name":"inbound_routing_profiles_pkey","definition":"CREATE UNIQUE INDEX inbound_routing_profiles_pkey ON public.inbound_routing_profiles USING btree (id)"},{"name":"uq_routing_profile_phone","definition":"CREATE UNIQUE INDEX uq_routing_profile_phone ON public.inbound_routing_profiles USING btree (phone_number) WHERE (phone_number IS NOT NULL)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"inbound_routing_profiles","permissive":"PERMISSIVE","policyname":"inbound_routing_profiles_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"inbound_routing_profiles","permissive":"PERMISSIVE","policyname":"inbound_routing_profiles_write_managers","schemaname":"public","with_check":"is_manager_or_higher(uid(), tenant_org_id)"}],"triggers":[{"name":"trg_inbound_routing_profiles_updated_at","definition":"CREATE TRIGGER trg_inbound_routing_profiles_updated_at BEFORE UPDATE ON inbound_routing_profiles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"inbound_routing_profiles_closed_action_check","definition":"CHECK (closed_action = ANY (ARRAY['ivr'::text, 'ring_group'::text, 'voicemail'::text, 'hangup'::text]))"},{"name":"inbound_routing_profiles_open_action_check","definition":"CHECK (open_action = ANY (ARRAY['ivr'::text, 'ring_group'::text, 'voicemail'::text, 'hangup'::text]))"},{"name":"inbound_routing_profiles_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"inbound_sms_logs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assigned_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"twilio_message_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"from_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"to_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"num_media","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"media_urls","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"forwarded_to","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_payload","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_inbound_sms_logs_tenant","definition":"CREATE INDEX idx_inbound_sms_logs_tenant ON public.inbound_sms_logs USING btree (tenant_org_id)"},{"name":"idx_inbound_sms_logs_to","definition":"CREATE INDEX idx_inbound_sms_logs_to ON public.inbound_sms_logs USING btree (to_number)"},{"name":"idx_inbound_sms_logs_user","definition":"CREATE INDEX idx_inbound_sms_logs_user ON public.inbound_sms_logs USING btree (assigned_user_id)"},{"name":"inbound_sms_logs_pkey","definition":"CREATE UNIQUE INDEX inbound_sms_logs_pkey ON public.inbound_sms_logs USING btree (id)"},{"name":"inbound_sms_logs_twilio_message_sid_key","definition":"CREATE UNIQUE INDEX inbound_sms_logs_twilio_message_sid_key ON public.inbound_sms_logs USING btree (twilio_message_sid)"}],"policies":[{"cmd":"SELECT","qual":"(assigned_user_id = uid())","roles":["authenticated"],"tablename":"inbound_sms_logs","permissive":"PERMISSIVE","policyname":"Reps view their own inbound SMS","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id, uid())","roles":["authenticated"],"tablename":"inbound_sms_logs","permissive":"PERMISSIVE","policyname":"Tenant owners view all inbound SMS","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"inbound_sms_logs_pkey","definition":"PRIMARY KEY (id)"},{"name":"inbound_sms_logs_twilio_message_sid_key","definition":"UNIQUE (twilio_message_sid)"}]},{"table":"intelligence_briefs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"brief_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"window_start","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"window_end","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"health_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"headline","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sections_json","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"evidence_json","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"open_event_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"recommendation_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"generated_by_module","type":"text","default":"'intelligence-brief'::text","identity":"","not_null":true,"generated":""},{"name":"generated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"intelligence_briefs_latest_idx","definition":"CREATE INDEX intelligence_briefs_latest_idx ON public.intelligence_briefs USING btree (tenant_id, brief_type, generated_at DESC)"},{"name":"intelligence_briefs_pkey","definition":"CREATE UNIQUE INDEX intelligence_briefs_pkey ON public.intelligence_briefs USING btree (id)"},{"name":"intelligence_briefs_window_idx","definition":"CREATE INDEX intelligence_briefs_window_idx ON public.intelligence_briefs USING btree (tenant_id, window_start DESC, window_end DESC)"}],"policies":[{"cmd":"SELECT","qual":"ai_user_in_tenant(tenant_id)","roles":["authenticated"],"tablename":"intelligence_briefs","permissive":"PERMISSIVE","policyname":"intelligence_briefs_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"intelligence_briefs_health_status_check","definition":"CHECK (health_status = ANY (ARRAY['green'::text, 'yellow'::text, 'red'::text, 'blocked'::text]))"},{"name":"intelligence_briefs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"intelligence_entity_context","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"context_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"facts_json","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"scores_json","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"recommendations_json","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"evidence_json","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"freshness_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"intelligence_entity_context_lookup_idx","definition":"CREATE INDEX intelligence_entity_context_lookup_idx ON public.intelligence_entity_context USING btree (tenant_id, entity_type, entity_id, context_type, freshness_at DESC)"},{"name":"intelligence_entity_context_pkey","definition":"CREATE UNIQUE INDEX intelligence_entity_context_pkey ON public.intelligence_entity_context USING btree (id)"},{"name":"intelligence_entity_context_type_idx","definition":"CREATE INDEX intelligence_entity_context_type_idx ON public.intelligence_entity_context USING btree (tenant_id, context_type, freshness_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"ai_user_in_tenant(tenant_id)","roles":["authenticated"],"tablename":"intelligence_entity_context","permissive":"PERMISSIVE","policyname":"intelligence_entity_context_select","schemaname":"public","with_check":null}],"triggers":[{"name":"intelligence_entity_context_touch","definition":"CREATE TRIGGER intelligence_entity_context_touch BEFORE UPDATE ON intelligence_entity_context FOR EACH ROW EXECUTE FUNCTION ai_touch_updated_at()"}],"constraints":[{"name":"intelligence_entity_context_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"intelligence_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"severity","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'open'::text","identity":"","not_null":true,"generated":""},{"name":"source_module","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_entity_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_entity_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_job_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_rep_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_storm_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_storm_zone_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"why_it_matters","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recommended_action","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"evidence_json","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"confidence_score","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"dedupe_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"detected_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"intelligence_events_claim_idx","definition":"CREATE INDEX intelligence_events_claim_idx ON public.intelligence_events USING btree (related_claim_id) WHERE (related_claim_id IS NOT NULL)"},{"name":"intelligence_events_dedupe_idx","definition":"CREATE INDEX intelligence_events_dedupe_idx ON public.intelligence_events USING btree (tenant_id, dedupe_key) WHERE (dedupe_key IS NOT NULL)"},{"name":"intelligence_events_job_idx","definition":"CREATE INDEX intelligence_events_job_idx ON public.intelligence_events USING btree (related_job_id) WHERE (related_job_id IS NOT NULL)"},{"name":"intelligence_events_lead_idx","definition":"CREATE INDEX intelligence_events_lead_idx ON public.intelligence_events USING btree (related_lead_id) WHERE (related_lead_id IS NOT NULL)"},{"name":"intelligence_events_pkey","definition":"CREATE UNIQUE INDEX intelligence_events_pkey ON public.intelligence_events USING btree (id)"},{"name":"intelligence_events_storm_idx","definition":"CREATE INDEX intelligence_events_storm_idx ON public.intelligence_events USING btree (related_storm_id) WHERE (related_storm_id IS NOT NULL)"},{"name":"intelligence_events_storm_zone_idx","definition":"CREATE INDEX intelligence_events_storm_zone_idx ON public.intelligence_events USING btree (related_storm_zone_id) WHERE (related_storm_zone_id IS NOT NULL)"},{"name":"intelligence_events_tenant_status_idx","definition":"CREATE INDEX intelligence_events_tenant_status_idx ON public.intelligence_events USING btree (tenant_id, status, severity, detected_at DESC)"},{"name":"intelligence_events_tenant_type_idx","definition":"CREATE INDEX intelligence_events_tenant_type_idx ON public.intelligence_events USING btree (tenant_id, event_type, detected_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"ai_user_in_tenant(tenant_id)","roles":["authenticated"],"tablename":"intelligence_events","permissive":"PERMISSIVE","policyname":"intelligence_events_select","schemaname":"public","with_check":null}],"triggers":[{"name":"intelligence_events_materialize_business_opportunity","definition":"CREATE TRIGGER intelligence_events_materialize_business_opportunity AFTER INSERT ON intelligence_events FOR EACH ROW EXECUTE FUNCTION business_intelligence_event_after_insert()"},{"name":"intelligence_events_touch","definition":"CREATE TRIGGER intelligence_events_touch BEFORE UPDATE ON intelligence_events FOR EACH ROW EXECUTE FUNCTION ai_touch_updated_at()"}],"constraints":[{"name":"intelligence_events_confidence_score_check","definition":"CHECK (confidence_score IS NULL OR confidence_score >= 0::numeric AND confidence_score <= 1::numeric)"},{"name":"intelligence_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"intelligence_events_severity_check","definition":"CHECK (severity = ANY (ARRAY['info'::text, 'task'::text, 'urgent'::text, 'blocker'::text]))"},{"name":"intelligence_events_status_check","definition":"CHECK (status = ANY (ARRAY['open'::text, 'acknowledged'::text, 'dismissed'::text, 'resolved'::text, 'expired'::text]))"}]},{"table":"intelligence_recommendations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"recommendation_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"priority","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'open'::text","identity":"","not_null":true,"generated":""},{"name":"subject_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recommended_action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"why_it_matters","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"evidence_json","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"confidence_score","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"requires_human_review","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"requires_confirmation_before_write","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"allowed_action_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_from_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by_module","type":"text","default":"'intelligence'::text","identity":"","not_null":true,"generated":""},{"name":"accepted_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"accepted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"dismissed_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"dismissed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"intelligence_recommendations_event_idx","definition":"CREATE INDEX intelligence_recommendations_event_idx ON public.intelligence_recommendations USING btree (created_from_event_id) WHERE (created_from_event_id IS NOT NULL)"},{"name":"intelligence_recommendations_open_idx","definition":"CREATE INDEX intelligence_recommendations_open_idx ON public.intelligence_recommendations USING btree (tenant_id, status, priority, created_at DESC)"},{"name":"intelligence_recommendations_pkey","definition":"CREATE UNIQUE INDEX intelligence_recommendations_pkey ON public.intelligence_recommendations USING btree (id)"},{"name":"intelligence_recommendations_subject_idx","definition":"CREATE INDEX intelligence_recommendations_subject_idx ON public.intelligence_recommendations USING btree (tenant_id, subject_type, subject_id, created_at DESC)"}],"policies":[{"cmd":"UPDATE","qual":"ai_is_tenant_admin(tenant_id)","roles":["authenticated"],"tablename":"intelligence_recommendations","permissive":"PERMISSIVE","policyname":"intelligence_recommendations_admin_update","schemaname":"public","with_check":"ai_is_tenant_admin(tenant_id)"},{"cmd":"SELECT","qual":"ai_user_in_tenant(tenant_id)","roles":["authenticated"],"tablename":"intelligence_recommendations","permissive":"PERMISSIVE","policyname":"intelligence_recommendations_select","schemaname":"public","with_check":null}],"triggers":[{"name":"intelligence_recommendations_touch","definition":"CREATE TRIGGER intelligence_recommendations_touch BEFORE UPDATE ON intelligence_recommendations FOR EACH ROW EXECUTE FUNCTION ai_touch_updated_at()"}],"constraints":[{"name":"intelligence_recommendations_confidence_score_check","definition":"CHECK (confidence_score IS NULL OR confidence_score >= 0::numeric AND confidence_score <= 1::numeric)"},{"name":"intelligence_recommendations_created_from_event_id_fkey","definition":"FOREIGN KEY (created_from_event_id) REFERENCES intelligence_events(id) ON DELETE SET NULL"},{"name":"intelligence_recommendations_pkey","definition":"PRIMARY KEY (id)"},{"name":"intelligence_recommendations_priority_check","definition":"CHECK (priority = ANY (ARRAY['info'::text, 'task'::text, 'urgent'::text, 'blocker'::text]))"},{"name":"intelligence_recommendations_status_check","definition":"CHECK (status = ANY (ARRAY['open'::text, 'accepted'::text, 'dismissed'::text, 'completed'::text, 'expired'::text, 'superseded'::text]))"}]},{"table":"intelligence_source_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"module_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"run_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"window_start","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"window_end","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"input_summary","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"output_summary","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"intelligence_source_runs_module_idx","definition":"CREATE INDEX intelligence_source_runs_module_idx ON public.intelligence_source_runs USING btree (module_name, status, started_at DESC)"},{"name":"intelligence_source_runs_pkey","definition":"CREATE UNIQUE INDEX intelligence_source_runs_pkey ON public.intelligence_source_runs USING btree (id)"},{"name":"intelligence_source_runs_tenant_idx","definition":"CREATE INDEX intelligence_source_runs_tenant_idx ON public.intelligence_source_runs USING btree (tenant_id, started_at DESC) WHERE (tenant_id IS NOT NULL)"}],"policies":[{"cmd":"SELECT","qual":"((tenant_id IS NOT NULL) AND ai_is_tenant_admin(tenant_id))","roles":["authenticated"],"tablename":"intelligence_source_runs","permissive":"PERMISSIVE","policyname":"intelligence_source_runs_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"intelligence_source_runs_pkey","definition":"PRIMARY KEY (id)"},{"name":"intelligence_source_runs_status_check","definition":"CHECK (status = ANY (ARRAY['started'::text, 'completed'::text, 'failed'::text, 'skipped'::text]))"}]},{"table":"invoice_payment_allocations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"invoice_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"finance_transaction_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"entry_kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"amount","type":"numeric(14,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"evidence_level","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"idempotency_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"reverses_allocation_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"invoice_allocation_tenant_idempotent","definition":"CREATE UNIQUE INDEX invoice_allocation_tenant_idempotent ON public.invoice_payment_allocations USING btree (tenant_id, idempotency_key)"},{"name":"invoice_payment_allocations_invoice_idx","definition":"CREATE INDEX invoice_payment_allocations_invoice_idx ON public.invoice_payment_allocations USING btree (tenant_id, invoice_id, created_at DESC)"},{"name":"invoice_payment_allocations_pkey","definition":"CREATE UNIQUE INDEX invoice_payment_allocations_pkey ON public.invoice_payment_allocations USING btree (id)"},{"name":"invoice_payment_allocations_single_reversal_idx","definition":"CREATE UNIQUE INDEX invoice_payment_allocations_single_reversal_idx ON public.invoice_payment_allocations USING btree (reverses_allocation_id) WHERE (entry_kind = 'reversal'::text)"},{"name":"invoice_payment_allocations_transaction_idx","definition":"CREATE INDEX invoice_payment_allocations_transaction_idx ON public.invoice_payment_allocations USING btree (tenant_id, finance_transaction_id, created_at DESC)"}],"policies":[],"triggers":[{"name":"invoice_allocation_no_update_or_delete","definition":"CREATE TRIGGER invoice_allocation_no_update_or_delete BEFORE DELETE OR UPDATE ON invoice_payment_allocations FOR EACH ROW EXECUTE FUNCTION knocklaunch_invoice_allocation_append_only()"}],"constraints":[{"name":"invoice_allocation_reversal_shape","definition":"CHECK (entry_kind = 'allocation'::text AND reverses_allocation_id IS NULL OR entry_kind = 'reversal'::text AND reverses_allocation_id IS NOT NULL)"},{"name":"invoice_allocation_tenant_idempotent","definition":"UNIQUE (tenant_id, idempotency_key)"},{"name":"invoice_payment_allocations_amount_check","definition":"CHECK (amount > 0::numeric)"},{"name":"invoice_payment_allocations_entry_kind_check","definition":"CHECK (entry_kind = ANY (ARRAY['allocation'::text, 'reversal'::text]))"},{"name":"invoice_payment_allocations_evidence_level_check","definition":"CHECK (evidence_level = ANY (ARRAY['owner_attested'::text, 'bank_verified'::text]))"},{"name":"invoice_payment_allocations_finance_transaction_id_fkey","definition":"FOREIGN KEY (finance_transaction_id) REFERENCES finance_transactions(id) ON DELETE RESTRICT"},{"name":"invoice_payment_allocations_idempotency_key_check","definition":"CHECK (length(idempotency_key) >= 8 AND length(idempotency_key) <= 180)"},{"name":"invoice_payment_allocations_invoice_id_fkey","definition":"FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE RESTRICT"},{"name":"invoice_payment_allocations_pkey","definition":"PRIMARY KEY (id)"},{"name":"invoice_payment_allocations_reverses_allocation_id_fkey","definition":"FOREIGN KEY (reverses_allocation_id) REFERENCES invoice_payment_allocations(id) ON DELETE RESTRICT"}]},{"table":"invoice_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tone","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"variables","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_invoice_templates_tenant_key","definition":"CREATE INDEX idx_invoice_templates_tenant_key ON public.invoice_templates USING btree (tenant_id, key)"},{"name":"idx_invoice_templates_tone","definition":"CREATE INDEX idx_invoice_templates_tone ON public.invoice_templates USING btree (tone)"},{"name":"invoice_templates_pkey","definition":"CREATE UNIQUE INDEX invoice_templates_pkey ON public.invoice_templates USING btree (id)"},{"name":"invoice_templates_tenant_id_key_key","definition":"CREATE UNIQUE INDEX invoice_templates_tenant_id_key_key ON public.invoice_templates USING btree (tenant_id, key)"}],"policies":[{"cmd":"SELECT","qual":"((uid() IS NOT NULL) AND ((tenant_id IS NULL) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = invoice_templates.tenant_id))))))","roles":["public"],"tablename":"invoice_templates","permissive":"PERMISSIVE","policyname":"Authenticated users view global invoice templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"invoice_templates","permissive":"PERMISSIVE","policyname":"Tenant owners manage their invoice templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"invoice_templates","permissive":"PERMISSIVE","policyname":"invoice_templates_godmode","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((tenant_id IS NULL) OR is_tenant_member(uid(), tenant_id))","roles":["public"],"tablename":"invoice_templates","permissive":"PERMISSIVE","policyname":"invoice_templates_tenant_member_read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((tenant_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_id))","roles":["public"],"tablename":"invoice_templates","permissive":"PERMISSIVE","policyname":"invoice_templates_tenant_owner_manage","schemaname":"public","with_check":"((tenant_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_id))"}],"triggers":[],"constraints":[{"name":"invoice_templates_body_not_blank","definition":"CHECK (length(btrim(body)) > 0)"},{"name":"invoice_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"invoice_templates_tenant_id_key_key","definition":"UNIQUE (tenant_id, key)"},{"name":"invoice_templates_tone_check","definition":"CHECK (tone = ANY (ARRAY['friendly'::text, 'standard'::text, 'stern'::text, 'vertical'::text]))"}]},{"table":"invoices","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"invoice_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"customer_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"amount","type":"numeric(10,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'Draft'::text","identity":"","not_null":false,"generated":""},{"name":"due_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"line_items","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"subtotal","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"tax_rate","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"tax_amount","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"invoice_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payment_terms","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"insurance_carrier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pdf_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pdf_file_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payment_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"paid_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"payment_provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payment_provider_link_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payment_provider_order_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payment_provider_payment_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payment_provider_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"canonical_contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"document_kind","type":"text","default":"'invoice'::text","identity":"","not_null":true,"generated":""},{"name":"document_subtype","type":"text","default":"'standard'::text","identity":"","not_null":true,"generated":""},{"name":"document_metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"render_bucket","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"render_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rendered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_proposal_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_invoices_contact_id","definition":"CREATE INDEX idx_invoices_contact_id ON public.invoices USING btree (contact_id)"},{"name":"idx_invoices_invoice_date","definition":"CREATE INDEX idx_invoices_invoice_date ON public.invoices USING btree (invoice_date)"},{"name":"idx_invoices_status","definition":"CREATE INDEX idx_invoices_status ON public.invoices USING btree (status)"},{"name":"idx_invoices_tenant","definition":"CREATE INDEX idx_invoices_tenant ON public.invoices USING btree (tenant_org_id)"},{"name":"invoices_document_subtype_idx","definition":"CREATE INDEX invoices_document_subtype_idx ON public.invoices USING btree (tenant_org_id, document_kind, document_subtype, created_at DESC)"},{"name":"invoices_event_booking_idx","definition":"CREATE INDEX invoices_event_booking_idx ON public.invoices USING btree (event_booking_id)"},{"name":"invoices_pkey","definition":"CREATE UNIQUE INDEX invoices_pkey ON public.invoices USING btree (id)"},{"name":"invoices_source_proposal_idx","definition":"CREATE INDEX invoices_source_proposal_idx ON public.invoices USING btree (source_proposal_id) WHERE (source_proposal_id IS NOT NULL)"},{"name":"invoices_square_order_lookup_idx","definition":"CREATE INDEX invoices_square_order_lookup_idx ON public.invoices USING btree (tenant_org_id, payment_provider, payment_provider_order_id) WHERE (payment_provider = 'square'::text)"},{"name":"invoices_tenant_invoice_id_key","definition":"CREATE UNIQUE INDEX invoices_tenant_invoice_id_key ON public.invoices USING btree (tenant_org_id, invoice_id)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN security_active_user_tenant_memberships utm ON (((ur.user_id = utm.user_id) AND (ur.tenant_id = utm.tenant_id))))\n  WHERE ((ur.user_id = uid()) AND ((utm.tenant_id)::text = invoices.tenant_org_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))","roles":["public"],"tablename":"invoices","permissive":"PERMISSIVE","policyname":"Admins manage invoices","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN security_active_user_tenant_memberships utm ON (((ur.user_id = utm.user_id) AND (ur.tenant_id = utm.tenant_id))))\n  WHERE ((ur.user_id = uid()) AND ((utm.tenant_id)::text = invoices.tenant_org_id) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = invoices.tenant_org_id))))","roles":["public"],"tablename":"invoices","permissive":"PERMISSIVE","policyname":"Users view tenant invoices","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"invoices","permissive":"PERMISSIVE","policyname":"inv_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"invoices","permissive":"PERMISSIVE","policyname":"inv_insert","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin())"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"invoices","permissive":"PERMISSIVE","policyname":"inv_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"invoices","permissive":"PERMISSIVE","policyname":"inv_update","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"\nCASE\n    WHEN (uid() IS NULL) THEN false\n    WHEN is_system_admin(uid()) THEN true\n    WHEN ((tenant_org_id IS NULL) OR (tenant_org_id !~* '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'::text)) THEN false\n    ELSE (is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid) OR user_has_permission(uid(), 'admin.billing'::text, (tenant_org_id)::uuid))\nEND","roles":["public"],"tablename":"invoices","permissive":"RESTRICTIVE","policyname":"invoice_finance_permission_gate","schemaname":"public","with_check":"\nCASE\n    WHEN (uid() IS NULL) THEN false\n    WHEN is_system_admin(uid()) THEN true\n    WHEN ((tenant_org_id IS NULL) OR (tenant_org_id !~* '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'::text)) THEN false\n    ELSE (is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid) OR user_has_permission(uid(), 'admin.billing'::text, (tenant_org_id)::uuid))\nEND"},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (invoices.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"invoices","permissive":"PERMISSIVE","policyname":"tenant_users_delete_invoices","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"invoices","permissive":"PERMISSIVE","policyname":"tenant_users_insert_invoices","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (invoices.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (invoices.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"invoices","permissive":"PERMISSIVE","policyname":"tenant_users_update_invoices","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (invoices.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (invoices.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"invoices","permissive":"PERMISSIVE","policyname":"tenant_users_view_invoices","schemaname":"public","with_check":null}],"triggers":[{"name":"invoices_business_activity","definition":"CREATE TRIGGER invoices_business_activity AFTER INSERT OR UPDATE OF status, amount, paid_at ON invoices FOR EACH ROW EXECUTE FUNCTION project_invoice_business_activity()"},{"name":"knocklaunch_invoice_paid_integrity","definition":"CREATE TRIGGER knocklaunch_invoice_paid_integrity BEFORE DELETE OR UPDATE ON invoices FOR EACH ROW EXECUTE FUNCTION knocklaunch_invoice_paid_integrity_guard()"},{"name":"update_invoices_updated_at","definition":"CREATE TRIGGER update_invoices_updated_at BEFORE UPDATE ON invoices FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"invoices_canonical_contact_fkey","definition":"FOREIGN KEY (canonical_contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"invoices_document_kind_check","definition":"CHECK (document_kind = ANY (ARRAY['invoice'::text, 'order_request'::text]))"},{"name":"invoices_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"invoices_pkey","definition":"PRIMARY KEY (id)"},{"name":"invoices_source_proposal_id_fkey","definition":"FOREIGN KEY (source_proposal_id) REFERENCES proposals(id) ON DELETE SET NULL"}]},{"table":"ivr_menus","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"greeting_text","type":"text","default":"'Thanks for calling. Please choose from the following options.'::text","identity":"","not_null":true,"generated":""},{"name":"greeting_audio_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice","type":"text","default":"'alice'::text","identity":"","not_null":true,"generated":""},{"name":"invalid_message","type":"text","default":"'Sorry, that is not a valid option.'::text","identity":"","not_null":true,"generated":""},{"name":"timeout_seconds","type":"smallint","default":"6","identity":"","not_null":true,"generated":""},{"name":"max_retries","type":"smallint","default":"2","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_ivr_menus_tenant","definition":"CREATE INDEX idx_ivr_menus_tenant ON public.ivr_menus USING btree (tenant_org_id)"},{"name":"ivr_menus_pkey","definition":"CREATE UNIQUE INDEX ivr_menus_pkey ON public.ivr_menus USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"ivr_menus","permissive":"PERMISSIVE","policyname":"ivr_menus_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"ivr_menus","permissive":"PERMISSIVE","policyname":"ivr_menus_write_managers","schemaname":"public","with_check":"is_manager_or_higher(uid(), tenant_org_id)"}],"triggers":[{"name":"trg_ivr_menus_updated_at","definition":"CREATE TRIGGER trg_ivr_menus_updated_at BEFORE UPDATE ON ivr_menus FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"ivr_menus_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"ivr_options","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"menu_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"digit","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"target_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sort_order","type":"smallint","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"ivr_options_pkey","definition":"CREATE UNIQUE INDEX ivr_options_pkey ON public.ivr_options USING btree (id)"},{"name":"uq_ivr_option_per_menu_digit","definition":"CREATE UNIQUE INDEX uq_ivr_option_per_menu_digit ON public.ivr_options USING btree (menu_id, digit)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"ivr_options","permissive":"PERMISSIVE","policyname":"ivr_options_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"ivr_options","permissive":"PERMISSIVE","policyname":"ivr_options_write_managers","schemaname":"public","with_check":"is_manager_or_higher(uid(), tenant_org_id)"}],"triggers":[],"constraints":[{"name":"ivr_options_action_check","definition":"CHECK (action = ANY (ARRAY['ring_group'::text, 'menu'::text, 'voicemail'::text, 'hangup'::text, 'external'::text]))"},{"name":"ivr_options_digit_check","definition":"CHECK (digit ~ '^[0-9*#]$'::text)"},{"name":"ivr_options_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"job_activity_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"activity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"timestamp","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_job_activity_job","definition":"CREATE INDEX idx_job_activity_job ON public.job_activity_log USING btree (job_id, \"timestamp\" DESC)"},{"name":"idx_job_activity_tenant","definition":"CREATE INDEX idx_job_activity_tenant ON public.job_activity_log USING btree (tenant_id)"},{"name":"job_activity_log_pkey","definition":"CREATE UNIQUE INDEX job_activity_log_pkey ON public.job_activity_log USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"job_activity_log","permissive":"PERMISSIVE","policyname":"job_activity_insert_tenant_members","schemaname":"public","with_check":"(is_system_admin(uid()) OR is_tenant_member(uid(), tenant_id))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR is_tenant_member(uid(), tenant_id))","roles":["authenticated"],"tablename":"job_activity_log","permissive":"PERMISSIVE","policyname":"job_activity_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"job_activity_log","permissive":"PERMISSIVE","policyname":"job_activity_service_all","schemaname":"public","with_check":"true"}],"triggers":[{"name":"trg_job_activity_set_tenant","definition":"CREATE TRIGGER trg_job_activity_set_tenant BEFORE INSERT ON job_activity_log FOR EACH ROW EXECUTE FUNCTION job_activity_set_tenant()"}],"constraints":[{"name":"job_activity_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"job_photos","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"photo_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_url","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"uploaded_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"uploaded_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"caption","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_job_photos_job","definition":"CREATE INDEX idx_job_photos_job ON public.job_photos USING btree (job_id, uploaded_at DESC)"},{"name":"job_photos_pkey","definition":"CREATE UNIQUE INDEX job_photos_pkey ON public.job_photos USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"job_photos","permissive":"PERMISSIVE","policyname":"job_photos_insert_tenant_members","schemaname":"public","with_check":"(is_system_admin(uid()) OR is_tenant_member(uid(), tenant_id))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR is_tenant_member(uid(), tenant_id))","roles":["authenticated"],"tablename":"job_photos","permissive":"PERMISSIVE","policyname":"job_photos_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"job_photos","permissive":"PERMISSIVE","policyname":"job_photos_service_all","schemaname":"public","with_check":"true"}],"triggers":[{"name":"trg_job_photos_set_tenant","definition":"CREATE TRIGGER trg_job_photos_set_tenant BEFORE INSERT ON job_photos FOR EACH ROW EXECUTE FUNCTION job_photos_set_tenant()"}],"constraints":[{"name":"job_photos_photo_type_check","definition":"CHECK (photo_type = ANY (ARRAY['before'::text, 'during'::text, 'after'::text, 'damage'::text, 'completion'::text]))"},{"name":"job_photos_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"job_request_email_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"job_request_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":"'job_request_pending'::text","identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'sent'::text","identity":"","not_null":true,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"job_request_email_log_pkey","definition":"CREATE UNIQUE INDEX job_request_email_log_pkey ON public.job_request_email_log USING btree (id)"},{"name":"job_request_email_log_unique","definition":"CREATE UNIQUE INDEX job_request_email_log_unique ON public.job_request_email_log USING btree (job_request_id, user_id, event_type)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM (job_requests jr\n     JOIN user_roles ur ON (((ur.tenant_id = jr.tenant_id) AND (ur.user_id = uid()) AND (ur.role = ANY (ARRAY['Manager'::app_role, 'Admin'::app_role, 'Tenant Owner'::app_role, 'Owner'::app_role])))))\n  WHERE (jr.id = job_request_email_log.job_request_id)))","roles":["authenticated"],"tablename":"job_request_email_log","permissive":"PERMISSIVE","policyname":"managers read job_request email log","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"job_request_email_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"job_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_document_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_signed_agreement_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_kind","type":"text","default":"'manual'::text","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"requested_pm_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"requested_crew_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"job_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"scope","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority","type":"text","default":"'normal'::text","identity":"","not_null":false,"generated":""},{"name":"property_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"photos_summary","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"job_request_status","default":"'pending_review'::job_request_status","identity":"","not_null":true,"generated":""},{"name":"reviewed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"reject_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"converted_job_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_job_requests_contact","definition":"CREATE INDEX idx_job_requests_contact ON public.job_requests USING btree (contact_id)"},{"name":"idx_job_requests_tenant_status","definition":"CREATE INDEX idx_job_requests_tenant_status ON public.job_requests USING btree (tenant_id, status)"},{"name":"job_requests_pkey","definition":"CREATE UNIQUE INDEX job_requests_pkey ON public.job_requests USING btree (id)"},{"name":"job_requests_source_signed_agreement_id_key","definition":"CREATE UNIQUE INDEX job_requests_source_signed_agreement_id_key ON public.job_requests USING btree (source_signed_agreement_id)"}],"policies":[{"cmd":"DELETE","qual":"(is_manager_or_higher_strict(uid(), tenant_id) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"job_requests","permissive":"PERMISSIVE","policyname":"job_requests_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"job_requests","permissive":"PERMISSIVE","policyname":"job_requests_insert","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_id) AND (created_by = uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"job_requests","permissive":"PERMISSIVE","policyname":"job_requests_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_manager_or_higher_strict(uid(), tenant_id) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"job_requests","permissive":"PERMISSIVE","policyname":"job_requests_update","schemaname":"public","with_check":"(is_manager_or_higher_strict(uid(), tenant_id) OR is_platform_admin(uid()))"}],"triggers":[{"name":"trg_enforce_job_request_state_machine","definition":"CREATE TRIGGER trg_enforce_job_request_state_machine BEFORE UPDATE ON job_requests FOR EACH ROW EXECUTE FUNCTION enforce_job_request_state_machine()"},{"name":"trg_job_requests_updated_at","definition":"CREATE TRIGGER trg_job_requests_updated_at BEFORE UPDATE ON job_requests FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"},{"name":"trg_notify_managers_on_new_job_request","definition":"CREATE TRIGGER trg_notify_managers_on_new_job_request AFTER INSERT ON job_requests FOR EACH ROW EXECUTE FUNCTION tg_notify_managers_on_new_job_request()"}],"constraints":[{"name":"job_requests_pkey","definition":"PRIMARY KEY (id)"},{"name":"job_requests_source_kind_check","definition":"CHECK (source_kind = ANY (ARRAY['manual'::text, 'signed_work_auth'::text, 'imported'::text, 'other'::text]))"},{"name":"job_requests_source_signed_agreement_id_key","definition":"UNIQUE (source_signed_agreement_id)"}]},{"table":"job_requests_activity_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"job_request_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_jral_request","definition":"CREATE INDEX idx_jral_request ON public.job_requests_activity_log USING btree (job_request_id)"},{"name":"job_requests_activity_log_pkey","definition":"CREATE UNIQUE INDEX job_requests_activity_log_pkey ON public.job_requests_activity_log USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"job_requests_activity_log","permissive":"PERMISSIVE","policyname":"jral_insert","schemaname":"public","with_check":"is_tenant_member(tenant_id, uid())"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_id, uid()) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"job_requests_activity_log","permissive":"PERMISSIVE","policyname":"jral_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"job_requests_activity_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"job_sheet","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"job_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"job_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'Scheduled'::text","identity":"","not_null":false,"generated":""},{"name":"scheduled_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_crew","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"job_sheet_job_id_key","definition":"CREATE UNIQUE INDEX job_sheet_job_id_key ON public.job_sheet USING btree (job_id)"},{"name":"job_sheet_pkey","definition":"CREATE UNIQUE INDEX job_sheet_pkey ON public.job_sheet USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = job_sheet.tenant_org_id))))","roles":["public"],"tablename":"job_sheet","permissive":"PERMISSIVE","policyname":"Users view tenant jobs","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"job_sheet_job_id_key","definition":"UNIQUE (job_id)"},{"name":"job_sheet_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"job_time_logs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"clock_in_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"clock_out_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_minutes","type":"integer","default":"\nCASE\n    WHEN (clock_out_at IS NOT NULL) THEN ((EXTRACT(epoch FROM (clock_out_at - clock_in_at)))::integer / 60)\n    ELSE NULL::integer\nEND","identity":"","not_null":false,"generated":"s"},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"clock_in_location","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"clock_out_location","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_job_time_logs_job","definition":"CREATE INDEX idx_job_time_logs_job ON public.job_time_logs USING btree (job_id)"},{"name":"idx_job_time_logs_open","definition":"CREATE INDEX idx_job_time_logs_open ON public.job_time_logs USING btree (user_id, job_id) WHERE (clock_out_at IS NULL)"},{"name":"idx_job_time_logs_tenant","definition":"CREATE INDEX idx_job_time_logs_tenant ON public.job_time_logs USING btree (tenant_org_id)"},{"name":"idx_job_time_logs_user","definition":"CREATE INDEX idx_job_time_logs_user ON public.job_time_logs USING btree (user_id)"},{"name":"job_time_logs_pkey","definition":"CREATE UNIQUE INDEX job_time_logs_pkey ON public.job_time_logs USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_owner(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"job_time_logs","permissive":"PERMISSIVE","policyname":"Owners delete tenant time logs","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_owner(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"job_time_logs","permissive":"PERMISSIVE","policyname":"Owners update tenant time logs","schemaname":"public","with_check":"is_tenant_owner(uid(), tenant_org_id)"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"job_time_logs","permissive":"PERMISSIVE","policyname":"Users create own time logs","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"job_time_logs","permissive":"PERMISSIVE","policyname":"Users update own time logs","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"job_time_logs","permissive":"PERMISSIVE","policyname":"Users view own time logs","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_org_id)))","roles":["public"],"tablename":"job_time_logs","permissive":"PERMISSIVE","policyname":"time_logs_tenant_owner_select","schemaname":"public","with_check":null}],"triggers":[{"name":"update_job_time_logs_updated_at","definition":"CREATE TRIGGER update_job_time_logs_updated_at BEFORE UPDATE ON job_time_logs FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"job_time_logs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"job_verification_checklist","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"photos_complete","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"aerial_uploaded","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"closeups_uploaded","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"notes_complete","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"customer_signature","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"work_auth_signed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"invoice_complete","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"docs_reviewed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"last_updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"job_verification_checklist_job_id_key","definition":"CREATE UNIQUE INDEX job_verification_checklist_job_id_key ON public.job_verification_checklist USING btree (job_id)"},{"name":"job_verification_checklist_pkey","definition":"CREATE UNIQUE INDEX job_verification_checklist_pkey ON public.job_verification_checklist USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(is_tenant_member(tenant_id, uid()) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"job_verification_checklist","permissive":"PERMISSIVE","policyname":"jvc_select","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(is_manager_or_higher_strict(uid(), tenant_id) OR has_acting_pm_grant(uid(), tenant_id) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"job_verification_checklist","permissive":"PERMISSIVE","policyname":"jvc_write","schemaname":"public","with_check":"(is_manager_or_higher_strict(uid(), tenant_id) OR has_acting_pm_grant(uid(), tenant_id) OR is_platform_admin(uid()))"}],"triggers":[{"name":"trg_jvc_updated_at","definition":"CREATE TRIGGER trg_jvc_updated_at BEFORE UPDATE ON job_verification_checklist FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"job_verification_checklist_job_id_key","definition":"UNIQUE (job_id)"},{"name":"job_verification_checklist_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"jobs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"appointment_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"job_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"customer_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_address","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"latitude","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"longitude","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"job_type","type":"text","default":"'tarp'::text","identity":"","not_null":true,"generated":""},{"name":"priority","type":"text","default":"'normal'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'scheduled'::text","identity":"","not_null":true,"generated":""},{"name":"assigned_crew_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_crew_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_pm_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_pm_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"scheduled_date","type":"date","default":"CURRENT_DATE","identity":"","not_null":true,"generated":""},{"name":"scheduled_time","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"appointment_date","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"verified_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"carrier_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"work_auth_signed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"tarp_installed","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"photos_uploaded","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"docs_complete","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"special_instructions","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"crew_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pm_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"manager_approved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"manager_approved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_job_request_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_signed_agreement_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_payment_status","type":"sce_claim_payment_status","default":"'not_started'::sce_claim_payment_status","identity":"","not_null":true,"generated":""},{"name":"tarping_invoice_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"invoice_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"submitted_to_carrier_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_sent_to_homeowner_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"paid_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_payment_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_payment_updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_payment_updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_payment_status_v2","type":"claim_payment_lifecycle","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_payment_status_v2_updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"funding_type","type":"text","default":"'retail'::text","identity":"","not_null":true,"generated":""},{"name":"financing_mode","type":"text","default":"'none'::text","identity":"","not_null":true,"generated":""},{"name":"financed_amount","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_jobs_assigned_crew","definition":"CREATE INDEX idx_jobs_assigned_crew ON public.jobs USING btree (assigned_crew_id)"},{"name":"idx_jobs_claim_payment_status","definition":"CREATE INDEX idx_jobs_claim_payment_status ON public.jobs USING btree (tenant_id, claim_payment_status)"},{"name":"idx_jobs_contact","definition":"CREATE INDEX idx_jobs_contact ON public.jobs USING btree (contact_id)"},{"name":"idx_jobs_contact_claim_id","definition":"CREATE INDEX idx_jobs_contact_claim_id ON public.jobs USING btree (contact_claim_id) WHERE (contact_claim_id IS NOT NULL)"},{"name":"idx_jobs_scheduled_date","definition":"CREATE INDEX idx_jobs_scheduled_date ON public.jobs USING btree (tenant_id, scheduled_date)"},{"name":"idx_jobs_source_job_request_id","definition":"CREATE INDEX idx_jobs_source_job_request_id ON public.jobs USING btree (source_job_request_id)"},{"name":"idx_jobs_source_signed_agreement_id","definition":"CREATE INDEX idx_jobs_source_signed_agreement_id ON public.jobs USING btree (source_signed_agreement_id)"},{"name":"idx_jobs_status","definition":"CREATE INDEX idx_jobs_status ON public.jobs USING btree (tenant_id, status)"},{"name":"idx_jobs_tenant","definition":"CREATE INDEX idx_jobs_tenant ON public.jobs USING btree (tenant_id)"},{"name":"jobs_pkey","definition":"CREATE UNIQUE INDEX jobs_pkey ON public.jobs USING btree (id)"},{"name":"jobs_tenant_id_job_number_key","definition":"CREATE UNIQUE INDEX jobs_tenant_id_job_number_key ON public.jobs USING btree (tenant_id, job_number)"}],"policies":[{"cmd":"DELETE","qual":"(is_system_admin(uid()) OR is_manager_or_higher(uid(), tenant_id))","roles":["authenticated"],"tablename":"jobs","permissive":"PERMISSIVE","policyname":"jobs_delete_manager_plus","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"jobs","permissive":"PERMISSIVE","policyname":"jobs_insert_manager_plus","schemaname":"public","with_check":"(is_system_admin(uid()) OR is_manager_or_higher(uid(), tenant_id))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR is_tenant_member(uid(), tenant_id))","roles":["authenticated"],"tablename":"jobs","permissive":"PERMISSIVE","policyname":"jobs_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"jobs","permissive":"PERMISSIVE","policyname":"jobs_service_role_all","schemaname":"public","with_check":"true"},{"cmd":"UPDATE","qual":"(assigned_crew_id = uid())","roles":["authenticated"],"tablename":"jobs","permissive":"PERMISSIVE","policyname":"jobs_update_assigned_crew","schemaname":"public","with_check":"(assigned_crew_id = uid())"},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR is_manager_or_higher(uid(), tenant_id))","roles":["authenticated"],"tablename":"jobs","permissive":"PERMISSIVE","policyname":"jobs_update_manager_plus","schemaname":"public","with_check":"(is_system_admin(uid()) OR is_manager_or_higher(uid(), tenant_id))"}],"triggers":[{"name":"bootstrap_roofing_project_ops","definition":"CREATE TRIGGER bootstrap_roofing_project_ops AFTER INSERT OR UPDATE OF contact_id, funding_type, financing_mode, status ON jobs FOR EACH ROW EXECUTE FUNCTION bootstrap_roofing_project_ops()"},{"name":"jobs_business_activity","definition":"CREATE TRIGGER jobs_business_activity AFTER INSERT OR UPDATE OF status, assigned_crew_id, assigned_pm_id, scheduled_date, completed_at, paid_at, financing_mode, financed_amount ON jobs FOR EACH ROW EXECUTE FUNCTION project_job_business_activity()"},{"name":"trg_enforce_job_verify_authority","definition":"CREATE TRIGGER trg_enforce_job_verify_authority BEFORE UPDATE ON jobs FOR EACH ROW EXECUTE FUNCTION enforce_job_verify_authority()"},{"name":"trg_enforce_jobs_crew_update_scope","definition":"CREATE TRIGGER trg_enforce_jobs_crew_update_scope BEFORE UPDATE ON jobs FOR EACH ROW EXECUTE FUNCTION enforce_jobs_crew_update_scope()"},{"name":"trg_jobs_contact_claim_link_check","definition":"CREATE TRIGGER trg_jobs_contact_claim_link_check BEFORE INSERT OR UPDATE OF contact_claim_id, contact_id, tenant_id ON jobs FOR EACH ROW EXECUTE FUNCTION jobs_contact_claim_link_check()"},{"name":"trg_jobs_set_job_number","definition":"CREATE TRIGGER trg_jobs_set_job_number BEFORE INSERT ON jobs FOR EACH ROW EXECUTE FUNCTION jobs_set_job_number()"},{"name":"trg_jobs_updated_at","definition":"CREATE TRIGGER trg_jobs_updated_at BEFORE UPDATE ON jobs FOR EACH ROW EXECUTE FUNCTION jobs_set_updated_at()"},{"name":"trg_jobs_verify_authority","definition":"CREATE TRIGGER trg_jobs_verify_authority BEFORE UPDATE ON jobs FOR EACH ROW EXECUTE FUNCTION enforce_job_verify_authority()"},{"name":"trg_jobs_verify_checklist","definition":"CREATE TRIGGER trg_jobs_verify_checklist BEFORE UPDATE ON jobs FOR EACH ROW EXECUTE FUNCTION enforce_job_verify_checklist()"}],"constraints":[{"name":"jobs_contact_id_unified_contacts_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"jobs_financed_amount_nonnegative_check","definition":"CHECK (financed_amount >= 0::numeric)"},{"name":"jobs_financing_mode_check","definition":"CHECK (financing_mode = ANY (ARRAY['none'::text, 'partial'::text, 'full'::text]))"},{"name":"jobs_funding_type_check","definition":"CHECK (funding_type = ANY (ARRAY['retail'::text, 'insurance'::text]))"},{"name":"jobs_pkey","definition":"PRIMARY KEY (id)"},{"name":"jobs_priority_check","definition":"CHECK (priority = ANY (ARRAY['low'::text, 'normal'::text, 'high'::text, 'urgent'::text]))"},{"name":"jobs_status_check","definition":"CHECK (status = ANY (ARRAY['signed_authorization_received'::text, 'job_request_pending'::text, 'job_request_approved'::text, 'scheduled'::text, 'acknowledged'::text, 'dispatched'::text, 'on_site'::text, 'in_progress'::text, 'crew_completed'::text, 'pm_verifying'::text, 'pm_verified'::text, 'manager_review'::text, 'manager_approved'::text, 'payroll_ready'::text, 'submitted'::text, 'completed'::text, 'verified'::text, 'paid'::text, 'cancelled'::text]))"},{"name":"jobs_tenant_id_job_number_key","definition":"UNIQUE (tenant_id, job_number)"}]},{"table":"jurisdiction_scraper_configs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"county_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"state_code","type":"text","default":"'FL'::text","identity":"","not_null":true,"generated":""},{"name":"appraiser_url","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"search_url_pattern","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"api_endpoint","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"scraper_type","type":"text","default":"'html'::text","identity":"","not_null":true,"generated":""},{"name":"selectors","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"field_mappings","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"headers","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"discovered_by_ai","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"verified","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"last_verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_jurisdiction_scraper_configs_county","definition":"CREATE INDEX idx_jurisdiction_scraper_configs_county ON public.jurisdiction_scraper_configs USING btree (lower(county_name))"},{"name":"jurisdiction_scraper_configs_county_name_key","definition":"CREATE UNIQUE INDEX jurisdiction_scraper_configs_county_name_key ON public.jurisdiction_scraper_configs USING btree (county_name)"},{"name":"jurisdiction_scraper_configs_pkey","definition":"CREATE UNIQUE INDEX jurisdiction_scraper_configs_pkey ON public.jurisdiction_scraper_configs USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"jurisdiction_scraper_configs","permissive":"PERMISSIVE","policyname":"jurisdiction_scraper_configs_admin_read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"jurisdiction_scraper_configs","permissive":"PERMISSIVE","policyname":"system_admins_manage_scraper_configs","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"jurisdiction_scraper_configs_county_name_key","definition":"UNIQUE (county_name)"},{"name":"jurisdiction_scraper_configs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"jurisdictions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"state_code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"county_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"parcel_source_strategy","type":"parcel_source_strategy","default":"'ParcelDB'::parcel_source_strategy","identity":"","not_null":true,"generated":""},{"name":"parcel_data_drive_folder_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip_codes","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_jurisdictions_code","definition":"CREATE INDEX idx_jurisdictions_code ON public.jurisdictions USING btree (code)"},{"name":"idx_jurisdictions_state_county","definition":"CREATE INDEX idx_jurisdictions_state_county ON public.jurisdictions USING btree (state_code, county_name)"},{"name":"idx_jurisdictions_zip_codes","definition":"CREATE INDEX idx_jurisdictions_zip_codes ON public.jurisdictions USING gin (zip_codes)"},{"name":"jurisdictions_code_key","definition":"CREATE UNIQUE INDEX jurisdictions_code_key ON public.jurisdictions USING btree (code)"},{"name":"jurisdictions_pkey","definition":"CREATE UNIQUE INDEX jurisdictions_pkey ON public.jurisdictions USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"jurisdictions","permissive":"PERMISSIVE","policyname":"Users can view jurisdictions","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"jurisdictions","permissive":"PERMISSIVE","policyname":"platform_admin_manage_jurisdictions","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[{"name":"update_jurisdictions_updated_at","definition":"CREATE TRIGGER update_jurisdictions_updated_at BEFORE UPDATE ON jurisdictions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"jurisdictions_code_key","definition":"UNIQUE (code)"},{"name":"jurisdictions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"knocklaunch_demo_request_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"request_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"knocklaunch_demo_request_events_pkey","definition":"CREATE UNIQUE INDEX knocklaunch_demo_request_events_pkey ON public.knocklaunch_demo_request_events USING btree (id)"},{"name":"knocklaunch_demo_request_events_request_created_idx","definition":"CREATE INDEX knocklaunch_demo_request_events_request_created_idx ON public.knocklaunch_demo_request_events USING btree (request_id, created_at DESC)"},{"name":"knocklaunch_demo_request_events_request_id_event_type_key","definition":"CREATE UNIQUE INDEX knocklaunch_demo_request_events_request_id_event_type_key ON public.knocklaunch_demo_request_events USING btree (request_id, event_type)"}],"policies":[{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"knocklaunch_demo_request_events","permissive":"PERMISSIVE","policyname":"platform admins can read demo request events","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"knocklaunch_demo_request_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"knocklaunch_demo_request_events_request_id_event_type_key","definition":"UNIQUE (request_id, event_type)"},{"name":"knocklaunch_demo_request_events_request_id_fkey","definition":"FOREIGN KEY (request_id) REFERENCES knocklaunch_demo_requests(id) ON DELETE CASCADE"}]},{"table":"knocklaunch_demo_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'business_card_qr'::text","identity":"","not_null":true,"generated":""},{"name":"business_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"business_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"website_or_social","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"requested_help","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"primary_pain_point","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_area","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"logo_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"has_logo","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"landing_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"referrer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'received'::text","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"opportunity_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"demo_brief","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"confirmation_email_status","type":"text","default":"'not_queued'::text","identity":"","not_null":true,"generated":""},{"name":"owner_alert_status","type":"text","default":"'not_queued'::text","identity":"","not_null":true,"generated":""},{"name":"enrichment_status","type":"text","default":"'not_requested'::text","identity":"","not_null":true,"generated":""},{"name":"enrichment_data","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"workflow_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"processed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"knocklaunch_demo_requests_email_created_idx","definition":"CREATE INDEX knocklaunch_demo_requests_email_created_idx ON public.knocklaunch_demo_requests USING btree (lower(email), created_at DESC)"},{"name":"knocklaunch_demo_requests_opportunity_idx","definition":"CREATE INDEX knocklaunch_demo_requests_opportunity_idx ON public.knocklaunch_demo_requests USING btree (opportunity_id) WHERE (opportunity_id IS NOT NULL)"},{"name":"knocklaunch_demo_requests_pkey","definition":"CREATE UNIQUE INDEX knocklaunch_demo_requests_pkey ON public.knocklaunch_demo_requests USING btree (id)"},{"name":"knocklaunch_demo_requests_status_updated_idx","definition":"CREATE INDEX knocklaunch_demo_requests_status_updated_idx ON public.knocklaunch_demo_requests USING btree (status, updated_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"knocklaunch_demo_requests","permissive":"PERMISSIVE","policyname":"platform admins can read demo requests","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"knocklaunch_demo_requests","permissive":"PERMISSIVE","policyname":"platform admins can update demo requests","schemaname":"public","with_check":"is_platform_admin(uid())"}],"triggers":[],"constraints":[{"name":"knocklaunch_demo_requests_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"knocklaunch_demo_requests_opportunity_id_fkey","definition":"FOREIGN KEY (opportunity_id) REFERENCES business_opportunities(id) ON DELETE SET NULL"},{"name":"knocklaunch_demo_requests_pkey","definition":"PRIMARY KEY (id)"},{"name":"knocklaunch_demo_requests_status_check","definition":"CHECK (status = ANY (ARRAY['new'::text, 'received'::text, 'preparing'::text, 'ready_for_review'::text, 'workflow_failed'::text, 'reviewing'::text, 'demo_building'::text, 'demo_ready'::text, 'contacted'::text, 'closed'::text]))"}]},{"table":"kpi_goals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"kpi_name","type":"character varying(100)","default":null,"identity":"","not_null":true,"generated":""},{"name":"target_value","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"current_value","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"period_type","type":"character varying(20)","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_start","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_end","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"goal_type","type":"character varying(50)","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_kpi_goals_period","definition":"CREATE INDEX idx_kpi_goals_period ON public.kpi_goals USING btree (period_start, period_end)"},{"name":"idx_kpi_goals_tenant","definition":"CREATE INDEX idx_kpi_goals_tenant ON public.kpi_goals USING btree (tenant_id)"},{"name":"kpi_goals_pkey","definition":"CREATE UNIQUE INDEX kpi_goals_pkey ON public.kpi_goals USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"kpi_goals","permissive":"PERMISSIVE","policyname":"Users can manage KPIs","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"kpi_goals","permissive":"PERMISSIVE","policyname":"Users can view own tenant KPIs","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"kpi_goals_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"lawn_care_readiness_items","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"item_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"item_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"role_or_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"serial","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_to","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_lawn_care_readiness_tenant_type","definition":"CREATE INDEX idx_lawn_care_readiness_tenant_type ON public.lawn_care_readiness_items USING btree (tenant_id, item_type)"},{"name":"lawn_care_readiness_items_pkey","definition":"CREATE UNIQUE INDEX lawn_care_readiness_items_pkey ON public.lawn_care_readiness_items USING btree (id)"},{"name":"lawn_care_readiness_items_tenant_id_item_type_item_id_key","definition":"CREATE UNIQUE INDEX lawn_care_readiness_items_tenant_id_item_type_item_id_key ON public.lawn_care_readiness_items USING btree (tenant_id, item_type, item_id)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_care_readiness_items","permissive":"PERMISSIVE","policyname":"lawn_readiness_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"lawn_care_readiness_items","permissive":"PERMISSIVE","policyname":"lawn_readiness_insert","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_care_readiness_items","permissive":"PERMISSIVE","policyname":"lawn_readiness_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_care_readiness_items","permissive":"PERMISSIVE","policyname":"lawn_readiness_update","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_lawn_care_readiness_items_updated_at","definition":"CREATE TRIGGER trg_lawn_care_readiness_items_updated_at BEFORE UPDATE ON lawn_care_readiness_items FOR EACH ROW EXECUTE FUNCTION touch_lawn_care_readiness_items_updated_at()"}],"constraints":[{"name":"lawn_care_readiness_items_item_type_check","definition":"CHECK (item_type = ANY (ARRAY['gear'::text, 'crew'::text]))"},{"name":"lawn_care_readiness_items_pkey","definition":"PRIMARY KEY (id)"},{"name":"lawn_care_readiness_items_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"lawn_care_readiness_items_tenant_id_item_type_item_id_key","definition":"UNIQUE (tenant_id, item_type, item_id)"}]},{"table":"lawn_service_plans","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"cadence","type":"text","default":"'biweekly'::text","identity":"","not_null":true,"generated":""},{"name":"route_day","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_price","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"turf_sq_ft","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"edging_linear_ft","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"beds_sq_ft","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"shrub_count","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"access_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pause_until","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_crew_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_service_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_service_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_lawn_service_plans_tenant_day","definition":"CREATE INDEX idx_lawn_service_plans_tenant_day ON public.lawn_service_plans USING btree (tenant_id, route_day, status)"},{"name":"lawn_service_plans_pkey","definition":"CREATE UNIQUE INDEX lawn_service_plans_pkey ON public.lawn_service_plans USING btree (id)"},{"name":"lawn_service_plans_tenant_id_contact_id_key","definition":"CREATE UNIQUE INDEX lawn_service_plans_tenant_id_contact_id_key ON public.lawn_service_plans USING btree (tenant_id, contact_id)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_plans","permissive":"PERMISSIVE","policyname":"lawn_service_plans_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"lawn_service_plans","permissive":"PERMISSIVE","policyname":"lawn_service_plans_insert","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_plans","permissive":"PERMISSIVE","policyname":"lawn_service_plans_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_plans","permissive":"PERMISSIVE","policyname":"lawn_service_plans_update","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_lawn_service_plans_updated_at","definition":"CREATE TRIGGER trg_lawn_service_plans_updated_at BEFORE UPDATE ON lawn_service_plans FOR EACH ROW EXECUTE FUNCTION touch_lawn_service_updated_at()"}],"constraints":[{"name":"lawn_service_plans_cadence_check","definition":"CHECK (cadence = ANY (ARRAY['weekly'::text, 'biweekly'::text, 'monthly'::text, 'one_time'::text]))"},{"name":"lawn_service_plans_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE CASCADE"},{"name":"lawn_service_plans_pkey","definition":"PRIMARY KEY (id)"},{"name":"lawn_service_plans_status_check","definition":"CHECK (status = ANY (ARRAY['lead'::text, 'active'::text, 'paused'::text, 'cancelled'::text]))"},{"name":"lawn_service_plans_tenant_id_contact_id_key","definition":"UNIQUE (tenant_id, contact_id)"},{"name":"lawn_service_plans_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"lawn_service_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"request_action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'received'::text","identity":"","not_null":true,"generated":""},{"name":"service_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_price","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_cadence","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"preferred_day","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pause_option","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"resume_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_lawn_service_requests_tenant_status","definition":"CREATE INDEX idx_lawn_service_requests_tenant_status ON public.lawn_service_requests USING btree (tenant_id, status, created_at DESC)"},{"name":"lawn_service_requests_pkey","definition":"CREATE UNIQUE INDEX lawn_service_requests_pkey ON public.lawn_service_requests USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_requests","permissive":"PERMISSIVE","policyname":"lawn_service_requests_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"lawn_service_requests","permissive":"PERMISSIVE","policyname":"lawn_service_requests_insert","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_requests","permissive":"PERMISSIVE","policyname":"lawn_service_requests_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_requests","permissive":"PERMISSIVE","policyname":"lawn_service_requests_update","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_lawn_service_requests_updated_at","definition":"CREATE TRIGGER trg_lawn_service_requests_updated_at BEFORE UPDATE ON lawn_service_requests FOR EACH ROW EXECUTE FUNCTION touch_lawn_service_updated_at()"}],"constraints":[{"name":"lawn_service_requests_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"lawn_service_requests_pkey","definition":"PRIMARY KEY (id)"},{"name":"lawn_service_requests_status_check","definition":"CHECK (status = ANY (ARRAY['received'::text, 'reviewing'::text, 'estimated'::text, 'accepted'::text, 'scheduled'::text, 'completed'::text, 'declined'::text, 'cancelled'::text]))"},{"name":"lawn_service_requests_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"lawn_service_routes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"service_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'planned'::text","identity":"","not_null":true,"generated":""},{"name":"assigned_crew_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"exception_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"exception_note","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"lawn_service_routes_pkey","definition":"CREATE UNIQUE INDEX lawn_service_routes_pkey ON public.lawn_service_routes USING btree (id)"},{"name":"lawn_service_routes_tenant_id_service_date_key","definition":"CREATE UNIQUE INDEX lawn_service_routes_tenant_id_service_date_key ON public.lawn_service_routes USING btree (tenant_id, service_date)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_routes","permissive":"PERMISSIVE","policyname":"lawn_service_routes_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"lawn_service_routes","permissive":"PERMISSIVE","policyname":"lawn_service_routes_insert","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_routes","permissive":"PERMISSIVE","policyname":"lawn_service_routes_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_routes","permissive":"PERMISSIVE","policyname":"lawn_service_routes_update","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_lawn_service_routes_updated_at","definition":"CREATE TRIGGER trg_lawn_service_routes_updated_at BEFORE UPDATE ON lawn_service_routes FOR EACH ROW EXECUTE FUNCTION touch_lawn_service_updated_at()"}],"constraints":[{"name":"lawn_service_routes_pkey","definition":"PRIMARY KEY (id)"},{"name":"lawn_service_routes_status_check","definition":"CHECK (status = ANY (ARRAY['planned'::text, 'dispatched'::text, 'in_progress'::text, 'complete'::text, 'cancelled'::text]))"},{"name":"lawn_service_routes_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"lawn_service_routes_tenant_id_service_date_key","definition":"UNIQUE (tenant_id, service_date)"}]},{"table":"lawn_service_visits","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"route_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_plan_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"service_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"stop_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'scheduled'::text","identity":"","not_null":true,"generated":""},{"name":"assigned_crew_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"checklist","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"evidence","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"exception_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"exception_note","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"invoice_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_lawn_service_visits_tenant_date","definition":"CREATE INDEX idx_lawn_service_visits_tenant_date ON public.lawn_service_visits USING btree (tenant_id, service_date, stop_order)"},{"name":"lawn_service_visits_pkey","definition":"CREATE UNIQUE INDEX lawn_service_visits_pkey ON public.lawn_service_visits USING btree (id)"},{"name":"lawn_service_visits_tenant_id_contact_id_service_date_key","definition":"CREATE UNIQUE INDEX lawn_service_visits_tenant_id_contact_id_service_date_key ON public.lawn_service_visits USING btree (tenant_id, contact_id, service_date)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_visits","permissive":"PERMISSIVE","policyname":"lawn_service_visits_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"lawn_service_visits","permissive":"PERMISSIVE","policyname":"lawn_service_visits_insert","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_visits","permissive":"PERMISSIVE","policyname":"lawn_service_visits_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"lawn_service_visits","permissive":"PERMISSIVE","policyname":"lawn_service_visits_update","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_lawn_service_visits_updated_at","definition":"CREATE TRIGGER trg_lawn_service_visits_updated_at BEFORE UPDATE ON lawn_service_visits FOR EACH ROW EXECUTE FUNCTION touch_lawn_service_updated_at()"}],"constraints":[{"name":"lawn_service_visits_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE CASCADE"},{"name":"lawn_service_visits_pkey","definition":"PRIMARY KEY (id)"},{"name":"lawn_service_visits_route_id_fkey","definition":"FOREIGN KEY (route_id) REFERENCES lawn_service_routes(id) ON DELETE SET NULL"},{"name":"lawn_service_visits_service_plan_id_fkey","definition":"FOREIGN KEY (service_plan_id) REFERENCES lawn_service_plans(id) ON DELETE SET NULL"},{"name":"lawn_service_visits_status_check","definition":"CHECK (status = ANY (ARRAY['scheduled'::text, 'in_progress'::text, 'complete'::text, 'skipped'::text, 'rescheduled'::text, 'blocked'::text, 'cancelled'::text]))"},{"name":"lawn_service_visits_tenant_id_contact_id_service_date_key","definition":"UNIQUE (tenant_id, contact_id, service_date)"},{"name":"lawn_service_visits_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"lead_batch_rows","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"batch_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"row_index","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"raw_data","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"normalized_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"tags","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"match_decision","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"matched_contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"compliance_results","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"mapping_metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_lead_batch_rows_batch","definition":"CREATE INDEX idx_lead_batch_rows_batch ON public.lead_batch_rows USING btree (batch_id)"},{"name":"idx_lead_batch_rows_decision","definition":"CREATE INDEX idx_lead_batch_rows_decision ON public.lead_batch_rows USING btree (batch_id, match_decision)"},{"name":"lead_batch_rows_pkey","definition":"CREATE UNIQUE INDEX lead_batch_rows_pkey ON public.lead_batch_rows USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM (lead_batches lb\n     JOIN security_active_user_tenant_memberships utm ON (((utm.tenant_id)::text = lb.tenant_org_id)))\n  WHERE ((lb.id = lead_batch_rows.batch_id) AND (utm.user_id = uid()))))","roles":["public"],"tablename":"lead_batch_rows","permissive":"PERMISSIVE","policyname":"Users view tenant batch rows","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"lead_batch_rows","permissive":"PERMISSIVE","policyname":"users_insert_tenant_batch_rows","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (lead_batches lb\n     JOIN security_active_user_tenant_memberships utm ON (((utm.tenant_id)::text = lb.tenant_org_id)))\n  WHERE ((lb.id = lead_batch_rows.batch_id) AND (utm.user_id = uid()) AND (utm.status = 'active'::text)))))"},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (lead_batches lb\n     JOIN security_active_user_tenant_memberships utm ON (((utm.tenant_id)::text = lb.tenant_org_id)))\n  WHERE ((lb.id = lead_batch_rows.batch_id) AND (utm.user_id = uid()) AND (utm.status = 'active'::text)))))","roles":["authenticated"],"tablename":"lead_batch_rows","permissive":"PERMISSIVE","policyname":"users_update_tenant_batch_rows","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (lead_batches lb\n     JOIN security_active_user_tenant_memberships utm ON (((utm.tenant_id)::text = lb.tenant_org_id)))\n  WHERE ((lb.id = lead_batch_rows.batch_id) AND (utm.user_id = uid()) AND (utm.status = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"lead_batch_rows_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"lead_batches","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"mapped_columns","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"total_rows","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"processed_rows","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"success_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"update_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"error_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"import_kind","type":"text","default":"'csv'::text","identity":"","not_null":true,"generated":""},{"name":"dedup_summary","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"compliance_summary","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_lead_batches_import_kind","definition":"CREATE INDEX idx_lead_batches_import_kind ON public.lead_batches USING btree (import_kind)"},{"name":"idx_lead_batches_status","definition":"CREATE INDEX idx_lead_batches_status ON public.lead_batches USING btree (status)"},{"name":"idx_lead_batches_tenant","definition":"CREATE INDEX idx_lead_batches_tenant ON public.lead_batches USING btree (tenant_org_id)"},{"name":"lead_batches_pkey","definition":"CREATE UNIQUE INDEX lead_batches_pkey ON public.lead_batches USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"lead_batches","permissive":"PERMISSIVE","policyname":"Users create tenant batches","schemaname":"public","with_check":"((created_by = uid()) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = lead_batches.tenant_org_id)))))"},{"cmd":"UPDATE","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = lead_batches.tenant_org_id))))","roles":["public"],"tablename":"lead_batches","permissive":"PERMISSIVE","policyname":"Users update tenant batches","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = lead_batches.tenant_org_id))))","roles":["public"],"tablename":"lead_batches","permissive":"PERMISSIVE","policyname":"Users view tenant batches","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"lead_batches_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"lead_campaigns","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"channel","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"start_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"end_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"target_zips","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_lead_campaigns_tenant","definition":"CREATE INDEX idx_lead_campaigns_tenant ON public.lead_campaigns USING btree (tenant_org_id, is_active)"},{"name":"lead_campaigns_pkey","definition":"CREATE UNIQUE INDEX lead_campaigns_pkey ON public.lead_campaigns USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"lead_campaigns","permissive":"PERMISSIVE","policyname":"campaigns_delete_tenant_or_admin","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"lead_campaigns","permissive":"PERMISSIVE","policyname":"campaigns_insert_tenant_or_admin","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (is_tenant_member(tenant_org_id) OR is_system_admin(uid())))"},{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND (uid() IS NOT NULL))","roles":["authenticated"],"tablename":"lead_campaigns","permissive":"RESTRICTIVE","policyname":"campaigns_restrict_null_or_anon","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (uid() IS NOT NULL))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"lead_campaigns","permissive":"PERMISSIVE","policyname":"campaigns_select_tenant_or_admin","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"lead_campaigns","permissive":"PERMISSIVE","policyname":"campaigns_update_tenant_or_admin","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (is_tenant_member(tenant_org_id) OR is_system_admin(uid())))"}],"triggers":[{"name":"trg_lead_campaigns_updated_at","definition":"CREATE TRIGGER trg_lead_campaigns_updated_at BEFORE UPDATE ON lead_campaigns FOR EACH ROW EXECUTE FUNCTION touch_lead_campaigns_updated_at()"}],"constraints":[{"name":"lead_campaigns_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"lead_deck","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'New'::text","identity":"","not_null":false,"generated":""},{"name":"priority","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_to","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"deletion_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_data","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"property_square_feet","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_parcel_id","type":"character varying(100)","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_data_fetched_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_owner_name","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_assessed_value","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_bedrooms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_bathrooms","type":"numeric(3,1)","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_year_built","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_lot_size","type":"numeric(10,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_data_jurisdiction","type":"character varying(100)","default":null,"identity":"","not_null":false,"generated":""},{"name":"quality_score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_stage","type":"text","default":"'New / Unassigned'::text","identity":"","not_null":false,"generated":""},{"name":"graduated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"lat","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"lng","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"geocoded_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"geocode_confidence","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"lost_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"dnc_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"referral_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"referral_partner_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_dnc","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"dnc_checked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"dnc_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_lead_deck_assigned_to","definition":"CREATE INDEX idx_lead_deck_assigned_to ON public.lead_deck USING btree (assigned_to) WHERE (deleted_at IS NULL)"},{"name":"idx_lead_deck_campaign","definition":"CREATE INDEX idx_lead_deck_campaign ON public.lead_deck USING btree (campaign_id) WHERE (campaign_id IS NOT NULL)"},{"name":"idx_lead_deck_created_at","definition":"CREATE INDEX idx_lead_deck_created_at ON public.lead_deck USING btree (created_at DESC) WHERE (deleted_at IS NULL)"},{"name":"idx_lead_deck_deleted_at","definition":"CREATE INDEX idx_lead_deck_deleted_at ON public.lead_deck USING btree (deleted_at) WHERE (deleted_at IS NOT NULL)"},{"name":"idx_lead_deck_global_pool","definition":"CREATE INDEX idx_lead_deck_global_pool ON public.lead_deck USING btree (tenant_org_id, assigned_to, status) WHERE (tenant_org_id IS NULL)"},{"name":"idx_lead_deck_is_dnc","definition":"CREATE INDEX idx_lead_deck_is_dnc ON public.lead_deck USING btree (is_dnc) WHERE (is_dnc = false)"},{"name":"idx_lead_deck_lead_stage","definition":"CREATE INDEX idx_lead_deck_lead_stage ON public.lead_deck USING btree (lead_stage) WHERE (deleted_at IS NULL)"},{"name":"idx_lead_deck_priority","definition":"CREATE INDEX idx_lead_deck_priority ON public.lead_deck USING btree (tenant_org_id, created_at) WHERE ((phone IS NOT NULL) AND (email IS NOT NULL))"},{"name":"idx_lead_deck_property_fetched","definition":"CREATE INDEX idx_lead_deck_property_fetched ON public.lead_deck USING btree (property_data_fetched_at)"},{"name":"idx_lead_deck_property_parcel","definition":"CREATE INDEX idx_lead_deck_property_parcel ON public.lead_deck USING btree (property_parcel_id)"},{"name":"idx_lead_deck_status","definition":"CREATE INDEX idx_lead_deck_status ON public.lead_deck USING btree (status)"},{"name":"idx_lead_deck_tenant_assigned","definition":"CREATE INDEX idx_lead_deck_tenant_assigned ON public.lead_deck USING btree (tenant_org_id, assigned_to) WHERE (deleted_at IS NULL)"},{"name":"idx_lead_deck_tenant_org","definition":"CREATE INDEX idx_lead_deck_tenant_org ON public.lead_deck USING btree (tenant_org_id) WHERE (deleted_at IS NULL)"},{"name":"idx_lead_deck_tenant_org_id","definition":"CREATE INDEX idx_lead_deck_tenant_org_id ON public.lead_deck USING btree (tenant_org_id)"},{"name":"idx_lead_deck_tenant_status","definition":"CREATE INDEX idx_lead_deck_tenant_status ON public.lead_deck USING btree (tenant_org_id, status)"},{"name":"lead_deck_lead_id_key","definition":"CREATE UNIQUE INDEX lead_deck_lead_id_key ON public.lead_deck USING btree (lead_id)"},{"name":"lead_deck_pkey","definition":"CREATE UNIQUE INDEX lead_deck_pkey ON public.lead_deck USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"lead_deck","permissive":"PERMISSIVE","policyname":"ld_admin_all_select","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"lead_deck","permissive":"PERMISSIVE","policyname":"ld_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"lead_deck","permissive":"PERMISSIVE","policyname":"ld_insert","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin())"},{"cmd":"SELECT","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_for(uid(), tenant_org_id))","roles":["authenticated"],"tablename":"lead_deck","permissive":"PERMISSIVE","policyname":"ld_owner_tenant_select","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"lead_deck","permissive":"PERMISSIVE","policyname":"ld_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"lead_deck","permissive":"PERMISSIVE","policyname":"ld_update","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(((tenant_org_id IS NULL) AND ((assigned_to IS NULL) OR (assigned_to = ''::text))) OR is_assigned_to(uid(), assigned_to))","roles":["authenticated"],"tablename":"lead_deck","permissive":"PERMISSIVE","policyname":"ld_user_pool_and_assigned_select","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"lead_deck","permissive":"PERMISSIVE","policyname":"tenant_members_all_leads","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"}],"triggers":[{"name":"lead_deck_auto_graduate","definition":"CREATE TRIGGER lead_deck_auto_graduate BEFORE UPDATE ON lead_deck FOR EACH ROW EXECUTE FUNCTION auto_graduate_lead()"},{"name":"lead_deck_quality_score","definition":"CREATE TRIGGER lead_deck_quality_score BEFORE INSERT OR UPDATE ON lead_deck FOR EACH ROW EXECUTE FUNCTION update_quality_score()"},{"name":"trg_audit_lead_deck_write","definition":"CREATE TRIGGER trg_audit_lead_deck_write AFTER INSERT OR DELETE OR UPDATE ON lead_deck FOR EACH ROW EXECUTE FUNCTION audit_lead_deck_write()"},{"name":"trg_mirror_lead_deck_to_unified","definition":"CREATE TRIGGER trg_mirror_lead_deck_to_unified AFTER INSERT OR DELETE OR UPDATE ON lead_deck FOR EACH ROW EXECUTE FUNCTION mirror_lead_deck_to_unified()"},{"name":"trg_scrub_lead_deck_dnc","definition":"CREATE TRIGGER trg_scrub_lead_deck_dnc BEFORE INSERT OR UPDATE OF phone ON lead_deck FOR EACH ROW EXECUTE FUNCTION scrub_lead_against_dnc()"},{"name":"trg_validate_assigned_to_ld","definition":"CREATE TRIGGER trg_validate_assigned_to_ld BEFORE INSERT OR UPDATE OF assigned_to ON lead_deck FOR EACH ROW EXECUTE FUNCTION validate_assigned_to_uuid()"},{"name":"update_lead_deck_updated_at","definition":"CREATE TRIGGER update_lead_deck_updated_at BEFORE UPDATE ON lead_deck FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"lead_deck_lead_id_key","definition":"UNIQUE (lead_id)"},{"name":"lead_deck_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"lead_deck_write_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"op","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_deck_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"db_user","type":"text","default":"CURRENT_USER","identity":"","not_null":true,"generated":""},{"name":"auth_uid","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_hint","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_columns","type":"text[]","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_lead_deck_write_audit_occurred_at","definition":"CREATE INDEX idx_lead_deck_write_audit_occurred_at ON public.lead_deck_write_audit USING btree (occurred_at DESC)"},{"name":"idx_lead_deck_write_audit_op","definition":"CREATE INDEX idx_lead_deck_write_audit_op ON public.lead_deck_write_audit USING btree (op)"},{"name":"lead_deck_write_audit_pkey","definition":"CREATE UNIQUE INDEX lead_deck_write_audit_pkey ON public.lead_deck_write_audit USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"lead_deck_write_audit","permissive":"PERMISSIVE","policyname":"System admins can read lead_deck write audit","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"lead_deck_write_audit_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"lead_intelligence_scores","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"score_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"score","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"bucket","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"confidence","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rank","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"reasons","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"factors","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"recommended_action","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recommended_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recommended_script","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"dismissed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"dismissed_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"dismissed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"dismissed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"manually_boosted","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"manual_priority_override","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"manual_priority_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"manual_priority_set_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"manual_priority_set_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"stale","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"stale_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_calculated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"model_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_lis_bucket","definition":"CREATE INDEX idx_lis_bucket ON public.lead_intelligence_scores USING btree (tenant_org_id, score_type, bucket)"},{"name":"idx_lis_stale","definition":"CREATE INDEX idx_lis_stale ON public.lead_intelligence_scores USING btree (tenant_org_id, score_type) WHERE (stale = true)"},{"name":"idx_lis_subject","definition":"CREATE INDEX idx_lis_subject ON public.lead_intelligence_scores USING btree (subject_type, subject_id)"},{"name":"idx_lis_tenant_score_rank","definition":"CREATE INDEX idx_lis_tenant_score_rank ON public.lead_intelligence_scores USING btree (tenant_org_id, score_type, score DESC) WHERE (dismissed = false)"},{"name":"lead_intelligence_scores_pkey","definition":"CREATE UNIQUE INDEX lead_intelligence_scores_pkey ON public.lead_intelligence_scores USING btree (id)"},{"name":"lis_unique_per_subject","definition":"CREATE UNIQUE INDEX lis_unique_per_subject ON public.lead_intelligence_scores USING btree (tenant_org_id, score_type, subject_type, subject_id)"}],"policies":[{"cmd":"DELETE","qual":"is_system_admin(uid())","roles":["public"],"tablename":"lead_intelligence_scores","permissive":"PERMISSIVE","policyname":"lis_admin_delete","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR is_admin_or_higher(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"lead_intelligence_scores","permissive":"PERMISSIVE","policyname":"lis_admin_update","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"lead_intelligence_scores","permissive":"PERMISSIVE","policyname":"lis_admin_write","schemaname":"public","with_check":"(is_system_admin(uid()) OR is_admin_or_higher(uid(), (tenant_org_id)::uuid))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["public"],"tablename":"lead_intelligence_scores","permissive":"PERMISSIVE","policyname":"lis_select_tenant_member","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_lis_updated_at","definition":"CREATE TRIGGER trg_lis_updated_at BEFORE UPDATE ON lead_intelligence_scores FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"},{"name":"trg_sync_lead_score_to_contact","definition":"CREATE TRIGGER trg_sync_lead_score_to_contact AFTER INSERT OR UPDATE OF score ON lead_intelligence_scores FOR EACH ROW EXECUTE FUNCTION sync_lead_score_to_contact()"}],"constraints":[{"name":"lead_intelligence_scores_manual_priority_override_check","definition":"CHECK (manual_priority_override IS NULL OR manual_priority_override >= 0 AND manual_priority_override <= 100)"},{"name":"lead_intelligence_scores_pkey","definition":"PRIMARY KEY (id)"},{"name":"lead_intelligence_scores_score_check","definition":"CHECK (score >= 0 AND score <= 100)"},{"name":"lis_unique_per_subject","definition":"UNIQUE (tenant_org_id, score_type, subject_type, subject_id)"}]},{"table":"lead_lane_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_state","type":"lead_lane_state","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_state","type":"lead_lane_state","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"disclosure_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"lead_lane_audit_lead_idx","definition":"CREATE INDEX lead_lane_audit_lead_idx ON public.lead_lane_audit USING btree (tenant_org_id, lead_id, created_at DESC)"},{"name":"lead_lane_audit_pkey","definition":"CREATE UNIQUE INDEX lead_lane_audit_pkey ON public.lead_lane_audit USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"false","roles":["authenticated"],"tablename":"lead_lane_audit","permissive":"PERMISSIVE","policyname":"lane_audit_no_delete","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"false","roles":["authenticated"],"tablename":"lead_lane_audit","permissive":"PERMISSIVE","policyname":"lane_audit_no_update","schemaname":"public","with_check":"false"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"lead_lane_audit","permissive":"PERMISSIVE","policyname":"lane_audit_tenant_insert","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) AND (actor_user_id = uid()))"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"lead_lane_audit","permissive":"PERMISSIVE","policyname":"lane_audit_tenant_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"lead_lane_audit_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"lead_lifecycle_rules","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"rule_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rule_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"conditions","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"lead_lifecycle_rules_pkey","definition":"CREATE UNIQUE INDEX lead_lifecycle_rules_pkey ON public.lead_lifecycle_rules USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"((enabled = true) AND ((tenant_id IS NULL) OR (tenant_id IN ( SELECT utm.tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.status = 'active'::text)))) OR is_system_admin(uid())))","roles":["authenticated"],"tablename":"lead_lifecycle_rules","permissive":"PERMISSIVE","policyname":"Tenant members view their lifecycle rules + globals","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"lead_lifecycle_rules","permissive":"PERMISSIVE","policyname":"platform_admin_manage_lifecycle_rules","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"lead_lifecycle_rules_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"lead_lifecycle_stages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"color","type":"text","default":"'#6366f1'::text","identity":"","not_null":false,"generated":""},{"name":"icon","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stage_order","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"is_system","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"auto_actions","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"exit_criteria","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"entry_criteria","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"sla_hours","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_lead_lifecycle_stages_tenant","definition":"CREATE INDEX idx_lead_lifecycle_stages_tenant ON public.lead_lifecycle_stages USING btree (tenant_org_id)"},{"name":"lead_lifecycle_stages_pkey","definition":"CREATE UNIQUE INDEX lead_lifecycle_stages_pkey ON public.lead_lifecycle_stages USING btree (id)"},{"name":"lead_lifecycle_stages_tenant_org_id_name_key","definition":"CREATE UNIQUE INDEX lead_lifecycle_stages_tenant_org_id_name_key ON public.lead_lifecycle_stages USING btree (tenant_org_id, name)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"lead_lifecycle_stages","permissive":"PERMISSIVE","policyname":"Tenant isolation for lead_lifecycle_stages","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"lead_lifecycle_stages_pkey","definition":"PRIMARY KEY (id)"},{"name":"lead_lifecycle_stages_tenant_org_id_name_key","definition":"UNIQUE (tenant_org_id, name)"}]},{"table":"lead_repair_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"action_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_ids","type":"text[]","default":null,"identity":"","not_null":true,"generated":""},{"name":"performed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"details","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_lra_created_at","definition":"CREATE INDEX idx_lra_created_at ON public.lead_repair_audit USING btree (created_at)"},{"name":"idx_lra_performed_by","definition":"CREATE INDEX idx_lra_performed_by ON public.lead_repair_audit USING btree (performed_by)"},{"name":"lead_repair_audit_pkey","definition":"CREATE UNIQUE INDEX lead_repair_audit_pkey ON public.lead_repair_audit USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(performed_by = uid())","roles":["authenticated"],"tablename":"lead_repair_audit","permissive":"PERMISSIVE","policyname":"Users can view their repair audits","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"lead_repair_audit","permissive":"PERMISSIVE","policyname":"authenticated_insert_repair_audit","schemaname":"public","with_check":"(uid() IS NOT NULL)"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"lead_repair_audit","permissive":"PERMISSIVE","policyname":"platform_admin_view_repair_audit","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"lead_repair_audit_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"lead_score_history","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"previous_score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_score","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"score_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"change_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"factors","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_lead_score_history_contact","definition":"CREATE INDEX idx_lead_score_history_contact ON public.lead_score_history USING btree (contact_id)"},{"name":"lead_score_history_pkey","definition":"CREATE UNIQUE INDEX lead_score_history_pkey ON public.lead_score_history USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"lead_score_history","permissive":"PERMISSIVE","policyname":"Tenant isolation for lead_score_history","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"lead_score_history_pkey","definition":"PRIMARY KEY (id)"},{"name":"lead_score_history_score_type_check","definition":"CHECK (score_type = ANY (ARRAY['total'::text, 'data_quality'::text, 'engagement'::text, 'recency'::text, 'custom'::text]))"}]},{"table":"lead_stage_transitions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_stage_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_stage_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"transition_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"triggered_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"automation_rule_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"time_in_previous_stage_hours","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_lead_stage_transitions_contact","definition":"CREATE INDEX idx_lead_stage_transitions_contact ON public.lead_stage_transitions USING btree (contact_id)"},{"name":"lead_stage_transitions_pkey","definition":"CREATE UNIQUE INDEX lead_stage_transitions_pkey ON public.lead_stage_transitions USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"lead_stage_transitions","permissive":"PERMISSIVE","policyname":"Tenant isolation for lead_stage_transitions","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"lead_stage_transitions_pkey","definition":"PRIMARY KEY (id)"},{"name":"lead_stage_transitions_triggered_by_check","definition":"CHECK (triggered_by = ANY (ARRAY['user'::text, 'automation'::text, 'system'::text]))"}]},{"table":"leads","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"storm_damage_description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"insurance_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"qualification_score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"qualification_reasoning","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority_level","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recommended_actions","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"qualified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_leads_created_at","definition":"CREATE INDEX idx_leads_created_at ON public.leads USING btree (created_at DESC)"},{"name":"idx_leads_priority","definition":"CREATE INDEX idx_leads_priority ON public.leads USING btree (priority_level) WHERE (priority_level IS NOT NULL)"},{"name":"leads_pkey","definition":"CREATE UNIQUE INDEX leads_pkey ON public.leads USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["anon","authenticated"],"tablename":"leads","permissive":"PERMISSIVE","policyname":"Public can submit leads with valid name","schemaname":"public","with_check":"((name IS NOT NULL) AND ((char_length(btrim(name)) >= 2) AND (char_length(btrim(name)) <= 120)) AND (email IS NOT NULL) AND (char_length(email) <= 254) AND (email ~* '^[^@[:space:]]+@[^@[:space:]]+[.][^@[:space:]]+$'::text) AND ((phone IS NULL) OR ((char_length(regexp_replace(phone, '\\D'::text, ''::text, 'g'::text)) >= 7) AND (char_length(regexp_replace(phone, '\\D'::text, ''::text, 'g'::text)) <= 15))) AND ((property_address IS NULL) OR (char_length(property_address) <= 500)) AND ((storm_damage_description IS NULL) OR (char_length(storm_damage_description) <= 4000)) AND (qualification_score IS NULL) AND (qualification_reasoning IS NULL) AND (priority_level IS NULL) AND (recommended_actions IS NULL) AND (qualified_at IS NULL))"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"leads","permissive":"PERMISSIVE","policyname":"System admins can view submitted leads","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"leads_pkey","definition":"PRIMARY KEY (id)"},{"name":"leads_priority_level_check","definition":"CHECK (priority_level = ANY (ARRAY['high'::text, 'medium'::text, 'low'::text]))"},{"name":"leads_qualification_score_check","definition":"CHECK (qualification_score >= 0 AND qualification_score <= 100)"}]},{"table":"legal_page_versions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"legal_page_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"slug","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body_format","type":"text","default":"'markdown'::text","identity":"","not_null":true,"generated":""},{"name":"effective_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"version","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"change_summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_legal_page_versions_page","definition":"CREATE INDEX idx_legal_page_versions_page ON public.legal_page_versions USING btree (legal_page_id, version DESC)"},{"name":"idx_legal_page_versions_slug","definition":"CREATE INDEX idx_legal_page_versions_slug ON public.legal_page_versions USING btree (slug, version DESC)"},{"name":"legal_page_versions_pkey","definition":"CREATE UNIQUE INDEX legal_page_versions_pkey ON public.legal_page_versions USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"legal_page_versions","permissive":"PERMISSIVE","policyname":"System admins can insert legal page versions","schemaname":"public","with_check":"is_system_admin()"},{"cmd":"SELECT","qual":"is_system_admin()","roles":["authenticated"],"tablename":"legal_page_versions","permissive":"PERMISSIVE","policyname":"System admins can read legal page versions","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"legal_page_versions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"legal_pages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"slug","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body_format","type":"text","default":"'markdown'::text","identity":"","not_null":true,"generated":""},{"name":"effective_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"published_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"published_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_legal_pages_slug_status","definition":"CREATE INDEX idx_legal_pages_slug_status ON public.legal_pages USING btree (slug, status)"},{"name":"legal_pages_pkey","definition":"CREATE UNIQUE INDEX legal_pages_pkey ON public.legal_pages USING btree (id)"},{"name":"legal_pages_slug_key","definition":"CREATE UNIQUE INDEX legal_pages_slug_key ON public.legal_pages USING btree (slug)"}],"policies":[{"cmd":"SELECT","qual":"(status = 'published'::text)","roles":["anon","authenticated"],"tablename":"legal_pages","permissive":"PERMISSIVE","policyname":"Public can read published legal pages","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"legal_pages","permissive":"PERMISSIVE","policyname":"System admins can insert legal pages","schemaname":"public","with_check":"is_system_admin()"},{"cmd":"SELECT","qual":"is_system_admin()","roles":["authenticated"],"tablename":"legal_pages","permissive":"PERMISSIVE","policyname":"System admins can read all legal pages","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_system_admin()","roles":["authenticated"],"tablename":"legal_pages","permissive":"PERMISSIVE","policyname":"System admins can update legal pages","schemaname":"public","with_check":"is_system_admin()"}],"triggers":[{"name":"trg_legal_pages_updated_at","definition":"CREATE TRIGGER trg_legal_pages_updated_at BEFORE UPDATE ON legal_pages FOR EACH ROW EXECUTE FUNCTION tg_legal_pages_set_updated_at()"}],"constraints":[{"name":"legal_pages_body_format_check","definition":"CHECK (body_format = ANY (ARRAY['markdown'::text, 'html'::text, 'text'::text]))"},{"name":"legal_pages_pkey","definition":"PRIMARY KEY (id)"},{"name":"legal_pages_slug_key","definition":"UNIQUE (slug)"},{"name":"legal_pages_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'published'::text, 'archived'::text]))"}]},{"table":"litigator_suppression_list","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_normalized","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scope","type":"text","default":"'global'::text","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"risk_level","type":"text","default":"'high'::text","identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"added_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"added_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_litigator_phone","definition":"CREATE INDEX idx_litigator_phone ON public.litigator_suppression_list USING btree (phone_normalized)"},{"name":"idx_litigator_tenant","definition":"CREATE INDEX idx_litigator_tenant ON public.litigator_suppression_list USING btree (tenant_org_id) WHERE (scope = 'tenant'::text)"},{"name":"litigator_suppression_list_pkey","definition":"CREATE UNIQUE INDEX litigator_suppression_list_pkey ON public.litigator_suppression_list USING btree (id)"},{"name":"uq_litigator_global","definition":"CREATE UNIQUE INDEX uq_litigator_global ON public.litigator_suppression_list USING btree (phone_normalized) WHERE (scope = 'global'::text)"},{"name":"uq_litigator_tenant","definition":"CREATE UNIQUE INDEX uq_litigator_tenant ON public.litigator_suppression_list USING btree (phone_normalized, tenant_org_id) WHERE (scope = 'tenant'::text)"}],"policies":[{"cmd":"SELECT","qual":"((scope = 'global'::text) OR ((scope = 'tenant'::text) AND is_tenant_member(tenant_org_id)))","roles":["authenticated"],"tablename":"litigator_suppression_list","permissive":"PERMISSIVE","policyname":"authenticated_view_litigator","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((scope = 'global'::text) AND is_system_admin())","roles":["authenticated"],"tablename":"litigator_suppression_list","permissive":"PERMISSIVE","policyname":"system_admins_manage_global_litigator","schemaname":"public","with_check":"((scope = 'global'::text) AND is_system_admin())"},{"cmd":"ALL","qual":"((scope = 'tenant'::text) AND is_tenant_member(tenant_org_id) AND (is_system_admin() OR (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND ((ur.tenant_id)::text = litigator_suppression_list.tenant_org_id) AND (ur.role = ANY (ARRAY['Tenant Owner'::app_role, 'Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))))","roles":["authenticated"],"tablename":"litigator_suppression_list","permissive":"PERMISSIVE","policyname":"tenant_owners_manage_tenant_litigator","schemaname":"public","with_check":"((scope = 'tenant'::text) AND is_tenant_member(tenant_org_id))"}],"triggers":[],"constraints":[{"name":"litigator_suppression_list_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"live_edit_revisions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"route_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"override_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"parent_revision_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"operations","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"live_edit_revisions_pkey","definition":"CREATE UNIQUE INDEX live_edit_revisions_pkey ON public.live_edit_revisions USING btree (id)"},{"name":"live_edit_revisions_tenant_route_created_idx","definition":"CREATE INDEX live_edit_revisions_tenant_route_created_idx ON public.live_edit_revisions USING btree (tenant_id, route_path, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"can_manage_page_override(request_user_id(), (tenant_id)::text)","roles":["authenticated"],"tablename":"live_edit_revisions","permissive":"PERMISSIVE","policyname":"live_edit_revisions_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"live_edit_revisions_operations_check","definition":"CHECK (live_edit_operations_safe(operations))"},{"name":"live_edit_revisions_override_id_fkey","definition":"FOREIGN KEY (override_id) REFERENCES godmode_page_overrides(id) ON DELETE SET NULL"},{"name":"live_edit_revisions_parent_revision_id_fkey","definition":"FOREIGN KEY (parent_revision_id) REFERENCES live_edit_revisions(id) ON DELETE SET NULL"},{"name":"live_edit_revisions_pkey","definition":"PRIMARY KEY (id)"},{"name":"live_edit_revisions_route_path_check","definition":"CHECK (length(route_path) >= 1 AND length(route_path) <= 512)"},{"name":"live_edit_revisions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"live_edit_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"compatibility_tenant_type","type":"text","default":"'*'::text","identity":"","not_null":true,"generated":""},{"name":"route_pattern","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"operations","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"live_edit_templates_compatibility_idx","definition":"CREATE INDEX live_edit_templates_compatibility_idx ON public.live_edit_templates USING btree (compatibility_tenant_type, route_pattern, updated_at DESC)"},{"name":"live_edit_templates_pkey","definition":"CREATE UNIQUE INDEX live_edit_templates_pkey ON public.live_edit_templates USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"\nCASE\n    WHEN (tenant_id IS NULL) THEN is_platform_admin(request_user_id())\n    ELSE can_manage_page_override(request_user_id(), (tenant_id)::text)\nEND","roles":["authenticated"],"tablename":"live_edit_templates","permissive":"PERMISSIVE","policyname":"live_edit_templates_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"live_edit_templates","permissive":"PERMISSIVE","policyname":"live_edit_templates_insert","schemaname":"public","with_check":"\nCASE\n    WHEN (tenant_id IS NULL) THEN is_platform_admin(request_user_id())\n    ELSE can_manage_page_override(request_user_id(), (tenant_id)::text)\nEND"},{"cmd":"SELECT","qual":"((tenant_id IS NULL) OR can_manage_page_override(request_user_id(), (tenant_id)::text))","roles":["authenticated"],"tablename":"live_edit_templates","permissive":"PERMISSIVE","policyname":"live_edit_templates_read","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"\nCASE\n    WHEN (tenant_id IS NULL) THEN is_platform_admin(request_user_id())\n    ELSE can_manage_page_override(request_user_id(), (tenant_id)::text)\nEND","roles":["authenticated"],"tablename":"live_edit_templates","permissive":"PERMISSIVE","policyname":"live_edit_templates_update","schemaname":"public","with_check":"\nCASE\n    WHEN (tenant_id IS NULL) THEN is_platform_admin(request_user_id())\n    ELSE can_manage_page_override(request_user_id(), (tenant_id)::text)\nEND"}],"triggers":[],"constraints":[{"name":"live_edit_templates_name_check","definition":"CHECK (length(btrim(name)) >= 1 AND length(btrim(name)) <= 120)"},{"name":"live_edit_templates_operations_check","definition":"CHECK (live_edit_operations_safe(operations))"},{"name":"live_edit_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"live_edit_templates_route_pattern_check","definition":"CHECK (length(route_pattern) >= 1 AND length(route_pattern) <= 512)"},{"name":"live_edit_templates_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"live_edit_templates_version_check","definition":"CHECK (version > 0)"}]},{"table":"login_attempts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"ip_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"success","type":"boolean","default":null,"identity":"","not_null":true,"generated":""},{"name":"failure_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_login_attempts_email","definition":"CREATE INDEX idx_login_attempts_email ON public.login_attempts USING btree (email, created_at DESC)"},{"name":"idx_login_attempts_ip","definition":"CREATE INDEX idx_login_attempts_ip ON public.login_attempts USING btree (ip_address, created_at DESC)"},{"name":"login_attempts_pkey","definition":"CREATE UNIQUE INDEX login_attempts_pkey ON public.login_attempts USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"login_attempts","permissive":"PERMISSIVE","policyname":"platform_admin_view_login_attempts","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"login_attempts_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"mail_continuity_health_state","schema":"public","columns":[{"name":"scope","type":"text","default":"'platform'::text","identity":"","not_null":true,"generated":""},{"name":"state","type":"text","default":"'healthy'::text","identity":"","not_null":true,"generated":""},{"name":"consecutive_failures","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"consecutive_healthy","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"last_checked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_changed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_probe","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mail_continuity_health_state_pkey","definition":"CREATE UNIQUE INDEX mail_continuity_health_state_pkey ON public.mail_continuity_health_state USING btree (scope)"}],"policies":[],"triggers":[],"constraints":[{"name":"mail_continuity_health_state_consecutive_failures_check","definition":"CHECK (consecutive_failures >= 0)"},{"name":"mail_continuity_health_state_consecutive_healthy_check","definition":"CHECK (consecutive_healthy >= 0)"},{"name":"mail_continuity_health_state_pkey","definition":"PRIMARY KEY (scope)"},{"name":"mail_continuity_health_state_scope_check","definition":"CHECK (scope = 'platform'::text)"},{"name":"mail_continuity_health_state_state_check","definition":"CHECK (state = ANY (ARRAY['healthy'::text, 'degraded'::text]))"}]},{"table":"mail_webhook_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"mailbox_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_event_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_message_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_thread_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload_summary","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mail_webhook_events_message_idx","definition":"CREATE INDEX mail_webhook_events_message_idx ON public.mail_webhook_events USING btree (mailbox_id, provider_message_id) WHERE (provider_message_id IS NOT NULL)"},{"name":"mail_webhook_events_pkey","definition":"CREATE UNIQUE INDEX mail_webhook_events_pkey ON public.mail_webhook_events USING btree (id)"},{"name":"mail_webhook_events_provider_event_key_key","definition":"CREATE UNIQUE INDEX mail_webhook_events_provider_event_key_key ON public.mail_webhook_events USING btree (provider_event_key)"},{"name":"mail_webhook_events_tenant_created_idx","definition":"CREATE INDEX mail_webhook_events_tenant_created_idx ON public.mail_webhook_events USING btree (tenant_org_id, created_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"mail_webhook_events_mailbox_id_fkey","definition":"FOREIGN KEY (mailbox_id) REFERENCES tenant_mailboxes(id) ON DELETE CASCADE"},{"name":"mail_webhook_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"mail_webhook_events_provider_event_key_key","definition":"UNIQUE (provider_event_key)"},{"name":"mail_webhook_events_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"manager_approvals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"job_request_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"approved_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"approved_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"manager_approvals_pkey","definition":"CREATE UNIQUE INDEX manager_approvals_pkey ON public.manager_approvals USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"manager_approvals","permissive":"PERMISSIVE","policyname":"manager_approvals_insert","schemaname":"public","with_check":"((is_manager_or_higher_strict(uid(), tenant_id) AND (approved_by = uid())) OR is_platform_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_id, uid()) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"manager_approvals","permissive":"PERMISSIVE","policyname":"manager_approvals_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"manager_approvals_kind_check","definition":"CHECK (kind = ANY (ARRAY['final_completion'::text, 'payroll'::text, 'submission'::text, 'close'::text, 'override'::text, 'dispatch_approval'::text]))"},{"name":"manager_approvals_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"marketing_campaign_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":"'google_workspace'::text","identity":"","not_null":true,"generated":""},{"name":"audience_snapshot","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"total_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"next_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"sent_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"skipped_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"failed_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""},{"name":"blocked_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"heartbeat_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"marketing_campaign_runs_pkey","definition":"CREATE UNIQUE INDEX marketing_campaign_runs_pkey ON public.marketing_campaign_runs USING btree (id)"},{"name":"marketing_campaign_runs_status_heartbeat_idx","definition":"CREATE INDEX marketing_campaign_runs_status_heartbeat_idx ON public.marketing_campaign_runs USING btree (status, heartbeat_at)"},{"name":"marketing_campaign_runs_tenant_created_idx","definition":"CREATE INDEX marketing_campaign_runs_tenant_created_idx ON public.marketing_campaign_runs USING btree (tenant_id, created_at DESC)"}],"policies":[],"triggers":[{"name":"marketing_campaign_platform_journal","definition":"CREATE TRIGGER marketing_campaign_platform_journal AFTER INSERT OR UPDATE OF status ON marketing_campaign_runs FOR EACH ROW EXECUTE FUNCTION journal_marketing_campaign_state()"}],"constraints":[{"name":"marketing_campaign_runs_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE"},{"name":"marketing_campaign_runs_failed_count_check","definition":"CHECK (failed_count >= 0)"},{"name":"marketing_campaign_runs_next_index_check","definition":"CHECK (next_index >= 0)"},{"name":"marketing_campaign_runs_pkey","definition":"PRIMARY KEY (id)"},{"name":"marketing_campaign_runs_sent_count_check","definition":"CHECK (sent_count >= 0)"},{"name":"marketing_campaign_runs_skipped_count_check","definition":"CHECK (skipped_count >= 0)"},{"name":"marketing_campaign_runs_status_check","definition":"CHECK (status = ANY (ARRAY['queued'::text, 'processing'::text, 'blocked'::text, 'completed'::text, 'failed'::text, 'cancelled'::text]))"},{"name":"marketing_campaign_runs_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"marketing_campaign_runs_total_count_check","definition":"CHECK (total_count >= 0)"}]},{"table":"message_attachments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"message_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"uploader_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"bucket_name","type":"text","default":"'message-attachments'::text","identity":"","not_null":true,"generated":""},{"name":"storage_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"mime_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"size_bytes","type":"bigint","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"encrypted_metadata","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"encryption_nonce","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"key_version","type":"integer","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"message_attachments_message_idx","definition":"CREATE INDEX message_attachments_message_idx ON public.message_attachments USING btree (message_id)"},{"name":"message_attachments_pkey","definition":"CREATE UNIQUE INDEX message_attachments_pkey ON public.message_attachments USING btree (id)"},{"name":"message_attachments_storage_path_key","definition":"CREATE UNIQUE INDEX message_attachments_storage_path_key ON public.message_attachments USING btree (storage_path)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM messages m\n  WHERE ((m.id = message_attachments.message_id) AND (((m.deleted_at IS NULL) AND can_access_message_conversation(m.conversation_id, uid())) OR ((m.deleted_at IS NOT NULL) AND can_review_deleted_message_conversation(m.conversation_id, uid()))))))","roles":["public"],"tablename":"message_attachments","permissive":"PERMISSIVE","policyname":"attachments_member_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"message_attachments_conversation_id_fkey","definition":"FOREIGN KEY (conversation_id) REFERENCES message_conversations(id) ON DELETE CASCADE"},{"name":"message_attachments_message_id_fkey","definition":"FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE CASCADE"},{"name":"message_attachments_pkey","definition":"PRIMARY KEY (id)"},{"name":"message_attachments_size_bytes_check","definition":"CHECK (size_bytes >= 0 AND size_bytes <= 15728640)"},{"name":"message_attachments_storage_path_key","definition":"UNIQUE (storage_path)"}]},{"table":"message_conversation_key_envelopes","schema":"public","columns":[{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"key_version","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"device_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"sender_device_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"sender_public_key","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"wrapped_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"wrap_nonce","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_conversation_key_envelopes_pkey","definition":"CREATE UNIQUE INDEX message_conversation_key_envelopes_pkey ON public.message_conversation_key_envelopes USING btree (conversation_id, key_version, user_id, device_id)"}],"policies":[{"cmd":"SELECT","qual":"((user_id = uid()) AND can_access_message_conversation(conversation_id, uid()))","roles":["public"],"tablename":"message_conversation_key_envelopes","permissive":"PERMISSIVE","policyname":"message_key_envelopes_own_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"message_conversation_key_envelopes_conversation_id_fkey","definition":"FOREIGN KEY (conversation_id) REFERENCES message_conversations(id) ON DELETE CASCADE"},{"name":"message_conversation_key_envelopes_key_version_check","definition":"CHECK (key_version > 0)"},{"name":"message_conversation_key_envelopes_pkey","definition":"PRIMARY KEY (conversation_id, key_version, user_id, device_id)"},{"name":"message_conversation_key_envelopes_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE CASCADE"}]},{"table":"message_conversation_members","schema":"public","columns":[{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"role","type":"text","default":"'member'::text","identity":"","not_null":true,"generated":""},{"name":"joined_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_read_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"muted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"message_conversation_members_pkey","definition":"CREATE UNIQUE INDEX message_conversation_members_pkey ON public.message_conversation_members USING btree (conversation_id, user_id)"},{"name":"message_members_user_idx","definition":"CREATE INDEX message_members_user_idx ON public.message_conversation_members USING btree (user_id, conversation_id)"}],"policies":[{"cmd":"SELECT","qual":"can_access_message_conversation(conversation_id, uid())","roles":["authenticated"],"tablename":"message_conversation_members","permissive":"PERMISSIVE","policyname":"message_members_member_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"message_conversation_members_conversation_id_fkey","definition":"FOREIGN KEY (conversation_id) REFERENCES message_conversations(id) ON DELETE CASCADE"},{"name":"message_conversation_members_pkey","definition":"PRIMARY KEY (conversation_id, user_id)"},{"name":"message_conversation_members_role_check","definition":"CHECK (role = ANY (ARRAY['owner'::text, 'admin'::text, 'member'::text]))"}]},{"table":"message_conversation_preferences","schema":"public","columns":[{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"folder_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"labels","type":"text[]","default":"ARRAY[]::text[]","identity":"","not_null":true,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"pinned_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"muted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_conversation_preferences_pkey","definition":"CREATE UNIQUE INDEX message_conversation_preferences_pkey ON public.message_conversation_preferences USING btree (conversation_id, user_id)"}],"policies":[{"cmd":"SELECT","qual":"((user_id = uid()) AND can_access_message_conversation(conversation_id, uid()))","roles":["public"],"tablename":"message_conversation_preferences","permissive":"PERMISSIVE","policyname":"message_preferences_own_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"message_conversation_preferences_conversation_id_fkey","definition":"FOREIGN KEY (conversation_id) REFERENCES message_conversations(id) ON DELETE CASCADE"},{"name":"message_conversation_preferences_folder_id_fkey","definition":"FOREIGN KEY (folder_id) REFERENCES message_folders(id) ON DELETE SET NULL"},{"name":"message_conversation_preferences_pkey","definition":"PRIMARY KEY (conversation_id, user_id)"},{"name":"message_conversation_preferences_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE CASCADE"}]},{"table":"message_conversations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"direct_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"encryption_enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"current_key_version","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"key_rotation_required","type":"boolean","default":"true","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_conversations_direct_key_uidx","definition":"CREATE UNIQUE INDEX message_conversations_direct_key_uidx ON public.message_conversations USING btree (direct_key) WHERE (direct_key IS NOT NULL)"},{"name":"message_conversations_pkey","definition":"CREATE UNIQUE INDEX message_conversations_pkey ON public.message_conversations USING btree (id)"},{"name":"message_conversations_tenant_uidx","definition":"CREATE UNIQUE INDEX message_conversations_tenant_uidx ON public.message_conversations USING btree (tenant_id) WHERE (kind = 'tenant'::text)"}],"policies":[{"cmd":"SELECT","qual":"can_access_message_conversation(id, uid())","roles":["authenticated"],"tablename":"message_conversations","permissive":"PERMISSIVE","policyname":"message_conversations_member_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"message_conversations_check","definition":"CHECK (kind = 'tenant'::text AND tenant_id IS NOT NULL OR kind <> 'tenant'::text)"},{"name":"message_conversations_kind_check","definition":"CHECK (kind = ANY (ARRAY['direct'::text, 'group'::text, 'tenant'::text]))"},{"name":"message_conversations_pkey","definition":"PRIMARY KEY (id)"},{"name":"message_conversations_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"message_deleted_retention","schema":"public","columns":[{"name":"message_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"sender_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"deleted_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"original_created_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"original_edited_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"retained_body_cipher","type":"bytea","default":null,"identity":"","not_null":true,"generated":""},{"name":"retained_context","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"original_encrypted_payload","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"original_encryption_nonce","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"original_encryption_alg","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"original_key_version","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"attachment_manifest","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_deleted_retention_pkey","definition":"CREATE UNIQUE INDEX message_deleted_retention_pkey ON public.message_deleted_retention USING btree (message_id)"}],"policies":[],"triggers":[{"name":"message_deleted_retention_immutable_trigger","definition":"CREATE TRIGGER message_deleted_retention_immutable_trigger BEFORE DELETE OR UPDATE ON message_deleted_retention FOR EACH ROW EXECUTE FUNCTION message_deleted_retention_immutable()"}],"constraints":[{"name":"message_deleted_retention_pkey","definition":"PRIMARY KEY (message_id)"}]},{"table":"message_device_keys","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"device_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"public_key","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_seen_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"revoked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"message_device_keys_pkey","definition":"CREATE UNIQUE INDEX message_device_keys_pkey ON public.message_device_keys USING btree (id)"},{"name":"message_device_keys_user_id_device_id_key","definition":"CREATE UNIQUE INDEX message_device_keys_user_id_device_id_key ON public.message_device_keys USING btree (user_id, device_id)"}],"policies":[{"cmd":"SELECT","qual":"(user_id = uid())","roles":["public"],"tablename":"message_device_keys","permissive":"PERMISSIVE","policyname":"message_device_keys_own_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"message_device_keys_pkey","definition":"PRIMARY KEY (id)"},{"name":"message_device_keys_user_id_device_id_key","definition":"UNIQUE (user_id, device_id)"},{"name":"message_device_keys_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE CASCADE"}]},{"table":"message_folders","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"position","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_folders_pkey","definition":"CREATE UNIQUE INDEX message_folders_pkey ON public.message_folders USING btree (id)"},{"name":"message_folders_user_id_name_key","definition":"CREATE UNIQUE INDEX message_folders_user_id_name_key ON public.message_folders USING btree (user_id, name)"}],"policies":[{"cmd":"SELECT","qual":"(user_id = uid())","roles":["public"],"tablename":"message_folders","permissive":"PERMISSIVE","policyname":"message_folders_own_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"message_folders_name_check","definition":"CHECK (char_length(name) >= 1 AND char_length(name) <= 80)"},{"name":"message_folders_pkey","definition":"PRIMARY KEY (id)"},{"name":"message_folders_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE CASCADE"},{"name":"message_folders_user_id_name_key","definition":"UNIQUE (user_id, name)"}]},{"table":"message_push_config","schema":"public","columns":[{"name":"singleton","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"vapid_public_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"vapid_private_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_push_config_pkey","definition":"CREATE UNIQUE INDEX message_push_config_pkey ON public.message_push_config USING btree (singleton)"}],"policies":[],"triggers":[],"constraints":[{"name":"message_push_config_pkey","definition":"PRIMARY KEY (singleton)"},{"name":"message_push_config_singleton_check","definition":"CHECK (singleton)"}]},{"table":"message_push_outbox","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"message_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"recipient_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"subscription_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"state","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"attempt_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"next_attempt_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"lease_token","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lease_expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_accepted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_push_outbox_message","definition":"CREATE INDEX message_push_outbox_message ON public.message_push_outbox USING btree (message_id, state)"},{"name":"message_push_outbox_message_id_subscription_id_key","definition":"CREATE UNIQUE INDEX message_push_outbox_message_id_subscription_id_key ON public.message_push_outbox USING btree (message_id, subscription_id)"},{"name":"message_push_outbox_pkey","definition":"CREATE UNIQUE INDEX message_push_outbox_pkey ON public.message_push_outbox USING btree (id)"},{"name":"message_push_outbox_ready","definition":"CREATE INDEX message_push_outbox_ready ON public.message_push_outbox USING btree (next_attempt_at, created_at) WHERE (state = ANY (ARRAY['pending'::text, 'retry'::text, 'processing'::text]))"}],"policies":[],"triggers":[{"name":"message_push_outbox_delivery_receipt_sync","definition":"CREATE TRIGGER message_push_outbox_delivery_receipt_sync AFTER UPDATE OF state, provider_accepted_at ON message_push_outbox FOR EACH ROW EXECUTE FUNCTION sync_message_push_delivery_receipt()"}],"constraints":[{"name":"message_push_outbox_attempt_count_check","definition":"CHECK (attempt_count >= 0)"},{"name":"message_push_outbox_conversation_id_fkey","definition":"FOREIGN KEY (conversation_id) REFERENCES message_conversations(id) ON DELETE CASCADE"},{"name":"message_push_outbox_message_id_fkey","definition":"FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE CASCADE"},{"name":"message_push_outbox_message_id_subscription_id_key","definition":"UNIQUE (message_id, subscription_id)"},{"name":"message_push_outbox_pkey","definition":"PRIMARY KEY (id)"},{"name":"message_push_outbox_state_check","definition":"CHECK (state = ANY (ARRAY['pending'::text, 'processing'::text, 'retry'::text, 'accepted'::text, 'expired'::text, 'failed'::text, 'skipped'::text]))"},{"name":"message_push_outbox_subscription_id_fkey","definition":"FOREIGN KEY (subscription_id) REFERENCES message_push_subscriptions(id) ON DELETE CASCADE"},{"name":"message_push_outbox_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"message_push_subscriptions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"device_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"endpoint","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"p256dh","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"auth_secret","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"disabled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"message_push_subscriptions_pkey","definition":"CREATE UNIQUE INDEX message_push_subscriptions_pkey ON public.message_push_subscriptions USING btree (id)"},{"name":"message_push_subscriptions_user_id_endpoint_key","definition":"CREATE UNIQUE INDEX message_push_subscriptions_user_id_endpoint_key ON public.message_push_subscriptions USING btree (user_id, endpoint)"}],"policies":[{"cmd":"SELECT","qual":"(user_id = uid())","roles":["public"],"tablename":"message_push_subscriptions","permissive":"PERMISSIVE","policyname":"message_push_subscriptions_own_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"message_push_subscriptions_pkey","definition":"PRIMARY KEY (id)"},{"name":"message_push_subscriptions_user_id_endpoint_key","definition":"UNIQUE (user_id, endpoint)"},{"name":"message_push_subscriptions_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE CASCADE"}]},{"table":"message_push_worker_config","schema":"public","columns":[{"name":"singleton","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"token_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"function_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_push_worker_config_pkey","definition":"CREATE UNIQUE INDEX message_push_worker_config_pkey ON public.message_push_worker_config USING btree (singleton)"}],"policies":[],"triggers":[],"constraints":[{"name":"message_push_worker_config_pkey","definition":"PRIMARY KEY (singleton)"},{"name":"message_push_worker_config_singleton_check","definition":"CHECK (singleton)"}]},{"table":"message_reactions","schema":"public","columns":[{"name":"message_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"emoji","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_reactions_pkey","definition":"CREATE UNIQUE INDEX message_reactions_pkey ON public.message_reactions USING btree (message_id, user_id, emoji)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM messages m\n  WHERE ((m.id = message_reactions.message_id) AND can_access_message_conversation(m.conversation_id, uid()))))","roles":["authenticated"],"tablename":"message_reactions","permissive":"PERMISSIVE","policyname":"reactions_member_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"message_reactions_emoji_check","definition":"CHECK (char_length(emoji) >= 1 AND char_length(emoji) <= 16)"},{"name":"message_reactions_message_id_fkey","definition":"FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE CASCADE"},{"name":"message_reactions_pkey","definition":"PRIMARY KEY (message_id, user_id, emoji)"}]},{"table":"message_retention_config","schema":"public","columns":[{"name":"singleton","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"archive_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_retention_config_pkey","definition":"CREATE UNIQUE INDEX message_retention_config_pkey ON public.message_retention_config USING btree (singleton)"}],"policies":[],"triggers":[],"constraints":[{"name":"message_retention_config_pkey","definition":"PRIMARY KEY (singleton)"},{"name":"message_retention_config_singleton_check","definition":"CHECK (singleton)"}]},{"table":"message_user_events","schema":"public","columns":[{"name":"id","type":"bigint","default":null,"identity":"a","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"message_user_events_pkey","definition":"CREATE UNIQUE INDEX message_user_events_pkey ON public.message_user_events USING btree (id)"},{"name":"message_user_events_user_idx","definition":"CREATE INDEX message_user_events_user_idx ON public.message_user_events USING btree (user_id, id DESC)"}],"policies":[{"cmd":"SELECT","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"message_user_events","permissive":"PERMISSIVE","policyname":"message_events_own_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"message_user_events_conversation_id_fkey","definition":"FOREIGN KEY (conversation_id) REFERENCES message_conversations(id) ON DELETE CASCADE"},{"name":"message_user_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"messages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"conversation_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"sender_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"reply_to_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"context","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"edited_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"encrypted_payload","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"encryption_nonce","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"encryption_alg","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"key_version","type":"integer","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"messages_conversation_created_idx","definition":"CREATE INDEX messages_conversation_created_idx ON public.messages USING btree (conversation_id, created_at DESC)"},{"name":"messages_pkey","definition":"CREATE UNIQUE INDEX messages_pkey ON public.messages USING btree (id)"},{"name":"messages_search_idx","definition":"CREATE INDEX messages_search_idx ON public.messages USING gin (to_tsvector('simple'::regconfig, COALESCE(body, ''::text)))"}],"policies":[{"cmd":"SELECT","qual":"(((deleted_at IS NULL) AND can_access_message_conversation(conversation_id, uid())) OR ((deleted_at IS NOT NULL) AND can_review_deleted_message_conversation(conversation_id, uid())))","roles":["public"],"tablename":"messages","permissive":"PERMISSIVE","policyname":"messages_member_select","schemaname":"public","with_check":null}],"triggers":[{"name":"enqueue_platform_message_push_after_insert","definition":"CREATE TRIGGER enqueue_platform_message_push_after_insert AFTER INSERT ON messages FOR EACH ROW EXECUTE FUNCTION enqueue_platform_message_push()"},{"name":"platform_message_after_insert_trigger","definition":"CREATE TRIGGER platform_message_after_insert_trigger AFTER INSERT ON messages FOR EACH ROW EXECUTE FUNCTION platform_message_after_insert()"}],"constraints":[{"name":"messages_body_check","definition":"CHECK (char_length(body) <= 4000)"},{"name":"messages_conversation_id_fkey","definition":"FOREIGN KEY (conversation_id) REFERENCES message_conversations(id) ON DELETE CASCADE"},{"name":"messages_pkey","definition":"PRIMARY KEY (id)"},{"name":"messages_reply_to_id_fkey","definition":"FOREIGN KEY (reply_to_id) REFERENCES messages(id) ON DELETE SET NULL"}]},{"table":"missing_info_leads","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"moved_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"full_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"missing_phone","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"missing_address","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"original_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_missing_info_created","definition":"CREATE INDEX idx_missing_info_created ON public.missing_info_leads USING btree (created_at DESC)"},{"name":"idx_missing_info_status","definition":"CREATE INDEX idx_missing_info_status ON public.missing_info_leads USING btree (status)"},{"name":"missing_info_leads_pkey","definition":"CREATE UNIQUE INDEX missing_info_leads_pkey ON public.missing_info_leads USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"missing_info_leads","permissive":"PERMISSIVE","policyname":"Users insert missing leads","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (missing_info_leads.tenant_org_id)::uuid)))))"},{"cmd":"ALL","qual":"is_system_admin()","roles":["public"],"tablename":"missing_info_leads","permissive":"PERMISSIVE","policyname":"mil_all","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"missing_info_leads","permissive":"PERMISSIVE","policyname":"missing_leads_godmode","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"missing_info_leads","permissive":"PERMISSIVE","policyname":"missing_leads_tenant_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"missing_info_leads","permissive":"PERMISSIVE","policyname":"missing_leads_tenant_update","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), (tenant_org_id)::uuid))"},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (missing_info_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"missing_info_leads","permissive":"PERMISSIVE","policyname":"tenant_users_delete_missing_info","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"missing_info_leads","permissive":"PERMISSIVE","policyname":"tenant_users_insert_missing_info","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (missing_info_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (missing_info_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"missing_info_leads","permissive":"PERMISSIVE","policyname":"tenant_users_update_missing_info","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (missing_info_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (missing_info_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"missing_info_leads","permissive":"PERMISSIVE","policyname":"tenant_users_view_missing_info","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"missing_info_leads_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"mobile_vendor_campaign_recipients","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"member_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""},{"name":"provider_message_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"mobile_vendor_campaign_recipients_campaign_idx","definition":"CREATE INDEX mobile_vendor_campaign_recipients_campaign_idx ON public.mobile_vendor_campaign_recipients USING btree (campaign_id, status)"},{"name":"mobile_vendor_campaign_recipients_campaign_member_uq","definition":"CREATE UNIQUE INDEX mobile_vendor_campaign_recipients_campaign_member_uq ON public.mobile_vendor_campaign_recipients USING btree (campaign_id, member_id)"},{"name":"mobile_vendor_campaign_recipients_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_campaign_recipients_pkey ON public.mobile_vendor_campaign_recipients USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_campaign_recipients_campaign_id_fkey","definition":"FOREIGN KEY (campaign_id) REFERENCES mobile_vendor_campaigns(id) ON DELETE CASCADE"},{"name":"mobile_vendor_campaign_recipients_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"mobile_vendor_campaign_recipients_member_id_fkey","definition":"FOREIGN KEY (member_id) REFERENCES mobile_vendor_loyalty_members(id) ON DELETE CASCADE"},{"name":"mobile_vendor_campaign_recipients_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_campaign_recipients_status_check","definition":"CHECK (status = ANY (ARRAY['queued'::text, 'sent'::text, 'skipped'::text, 'failed'::text]))"},{"name":"mobile_vendor_campaign_recipients_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"mobile_vendor_campaigns","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"campaign_type","type":"text","default":"'custom'::text","identity":"","not_null":true,"generated":""},{"name":"audience","type":"text","default":"'next_stop_club_email'::text","identity":"","not_null":true,"generated":""},{"name":"subject","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"recipient_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"sent_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"skipped_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"failed_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"mobile_vendor_campaigns_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_campaigns_pkey ON public.mobile_vendor_campaigns USING btree (id)"},{"name":"mobile_vendor_campaigns_tenant_idx","definition":"CREATE INDEX mobile_vendor_campaigns_tenant_idx ON public.mobile_vendor_campaigns USING btree (tenant_org_id, created_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_campaigns_campaign_type_check","definition":"CHECK (campaign_type = ANY (ARRAY['next_stop'::text, 'loyalty'::text, 'custom'::text]))"},{"name":"mobile_vendor_campaigns_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_campaigns_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'sending'::text, 'sent'::text, 'partial'::text, 'failed'::text]))"},{"name":"mobile_vendor_campaigns_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"mobile_vendor_inventory_items","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"sku","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"item_kind","type":"text","default":"'flavor'::text","identity":"","not_null":true,"generated":""},{"name":"unit","type":"text","default":"'unit'::text","identity":"","not_null":true,"generated":""},{"name":"quantity_on_hand","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"unit_cost","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"units_per_container","type":"numeric(12,2)","default":"1","identity":"","not_null":true,"generated":""},{"name":"reorder_point","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"public_available","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"public_featured","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mobile_vendor_inventory_items_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_inventory_items_pkey ON public.mobile_vendor_inventory_items USING btree (id)"},{"name":"mobile_vendor_inventory_items_tenant_kind_idx","definition":"CREATE INDEX mobile_vendor_inventory_items_tenant_kind_idx ON public.mobile_vendor_inventory_items USING btree (tenant_org_id, item_kind, sort_order, name)"},{"name":"mobile_vendor_inventory_items_tenant_org_id_sku_key","definition":"CREATE UNIQUE INDEX mobile_vendor_inventory_items_tenant_org_id_sku_key ON public.mobile_vendor_inventory_items USING btree (tenant_org_id, sku)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"mobile_vendor_inventory_items","permissive":"PERMISSIVE","policyname":"mobile_vendor_inventory_items_tenant_access","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin())"}],"triggers":[],"constraints":[{"name":"mobile_vendor_inventory_items_item_kind_check","definition":"CHECK (item_kind = ANY (ARRAY['flavor'::text, 'supply'::text]))"},{"name":"mobile_vendor_inventory_items_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_inventory_items_quantity_on_hand_check","definition":"CHECK (quantity_on_hand >= 0::numeric)"},{"name":"mobile_vendor_inventory_items_reorder_point_check","definition":"CHECK (reorder_point >= 0::numeric)"},{"name":"mobile_vendor_inventory_items_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"mobile_vendor_inventory_items_tenant_org_id_sku_key","definition":"UNIQUE (tenant_org_id, sku)"},{"name":"mobile_vendor_inventory_items_unit_cost_check","definition":"CHECK (unit_cost >= 0::numeric)"},{"name":"mobile_vendor_inventory_items_units_per_container_check","definition":"CHECK (units_per_container > 0::numeric)"}]},{"table":"mobile_vendor_inventory_movements","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"inventory_item_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"movement_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"quantity_delta","type":"numeric(12,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"balance_after","type":"numeric(12,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"unit_cost_snapshot","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"note","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mobile_vendor_inventory_movements_event_idx","definition":"CREATE INDEX mobile_vendor_inventory_movements_event_idx ON public.mobile_vendor_inventory_movements USING btree (tenant_org_id, event_booking_id, occurred_at DESC) WHERE (event_booking_id IS NOT NULL)"},{"name":"mobile_vendor_inventory_movements_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_inventory_movements_pkey ON public.mobile_vendor_inventory_movements USING btree (id)"},{"name":"mobile_vendor_inventory_movements_tenant_item_idx","definition":"CREATE INDEX mobile_vendor_inventory_movements_tenant_item_idx ON public.mobile_vendor_inventory_movements USING btree (tenant_org_id, inventory_item_id, occurred_at DESC)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"mobile_vendor_inventory_movements","permissive":"PERMISSIVE","policyname":"mobile_vendor_inventory_movements_tenant_access","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin())"}],"triggers":[],"constraints":[{"name":"mobile_vendor_inventory_movements_balance_after_check","definition":"CHECK (balance_after >= 0::numeric)"},{"name":"mobile_vendor_inventory_movements_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"mobile_vendor_inventory_movements_inventory_item_id_fkey","definition":"FOREIGN KEY (inventory_item_id) REFERENCES mobile_vendor_inventory_items(id) ON DELETE CASCADE"},{"name":"mobile_vendor_inventory_movements_movement_type_check","definition":"CHECK (movement_type = ANY (ARRAY['purchase'::text, 'adjustment'::text, 'event_usage'::text, 'waste'::text]))"},{"name":"mobile_vendor_inventory_movements_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_inventory_movements_quantity_delta_check","definition":"CHECK (quantity_delta <> 0::numeric)"},{"name":"mobile_vendor_inventory_movements_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"mobile_vendor_inventory_movements_unit_cost_snapshot_check","definition":"CHECK (unit_cost_snapshot >= 0::numeric)"}]},{"table":"mobile_vendor_loyalty_activity","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"member_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"activity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"stamps_delta","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"balance_after","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'knocklaunch'::text","identity":"","not_null":true,"generated":""},{"name":"source_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"points_delta","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"points_balance_after","type":"integer","default":"0","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mobile_vendor_loyalty_activity_idempotency_uidx","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_activity_idempotency_uidx ON public.mobile_vendor_loyalty_activity USING btree (tenant_org_id, member_id, activity_type, source, source_ref) WHERE (source_ref IS NOT NULL)"},{"name":"mobile_vendor_loyalty_activity_member_idx","definition":"CREATE INDEX mobile_vendor_loyalty_activity_member_idx ON public.mobile_vendor_loyalty_activity USING btree (member_id, created_at DESC)"},{"name":"mobile_vendor_loyalty_activity_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_activity_pkey ON public.mobile_vendor_loyalty_activity USING btree (id)"},{"name":"mobile_vendor_loyalty_activity_tenant_idx","definition":"CREATE INDEX mobile_vendor_loyalty_activity_tenant_idx ON public.mobile_vendor_loyalty_activity USING btree (tenant_org_id, created_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_loyalty_activity_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"mobile_vendor_loyalty_activity_member_id_fkey","definition":"FOREIGN KEY (member_id) REFERENCES mobile_vendor_loyalty_members(id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_activity_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_loyalty_activity_tenant_member_fk","definition":"FOREIGN KEY (tenant_org_id, member_id) REFERENCES mobile_vendor_loyalty_members(tenant_org_id, id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_activity_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"mobile_vendor_loyalty_claims","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"member_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"claim_type","type":"text","default":"'photo_moment'::text","identity":"","not_null":true,"generated":""},{"name":"storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"content_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"file_size_bytes","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"latitude","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"longitude","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"location_accuracy_m","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"captured_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"submitted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'uploading'::text","identity":"","not_null":true,"generated":""},{"name":"awarded_delta","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"reviewed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"review_note","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_mv_loyalty_claims_member","definition":"CREATE INDEX idx_mv_loyalty_claims_member ON public.mobile_vendor_loyalty_claims USING btree (tenant_org_id, member_id, created_at DESC)"},{"name":"idx_mv_loyalty_claims_status","definition":"CREATE INDEX idx_mv_loyalty_claims_status ON public.mobile_vendor_loyalty_claims USING btree (tenant_org_id, status, submitted_at DESC)"},{"name":"mobile_vendor_loyalty_claims_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_claims_pkey ON public.mobile_vendor_loyalty_claims USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_loyalty_claims_claim_type_check","definition":"CHECK (claim_type = 'photo_moment'::text)"},{"name":"mobile_vendor_loyalty_claims_member_id_fkey","definition":"FOREIGN KEY (member_id) REFERENCES mobile_vendor_loyalty_members(id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_claims_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_loyalty_claims_status_check","definition":"CHECK (status = ANY (ARRAY['uploading'::text, 'pending'::text, 'approved'::text, 'rejected'::text]))"},{"name":"mobile_vendor_loyalty_claims_tenant_member_fk","definition":"FOREIGN KEY (tenant_org_id, member_id) REFERENCES mobile_vendor_loyalty_members(tenant_org_id, id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_claims_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"mobile_vendor_loyalty_consent_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"member_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"channel","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"consent_status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"identity_value","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"capture_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mobile_vendor_loyalty_consent_events_idempotency_uidx","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_consent_events_idempotency_uidx ON public.mobile_vendor_loyalty_consent_events USING btree (tenant_org_id, member_id, channel, consent_status, event_ref) WHERE (event_ref IS NOT NULL)"},{"name":"mobile_vendor_loyalty_consent_events_member_idx","definition":"CREATE INDEX mobile_vendor_loyalty_consent_events_member_idx ON public.mobile_vendor_loyalty_consent_events USING btree (tenant_org_id, member_id, occurred_at DESC)"},{"name":"mobile_vendor_loyalty_consent_events_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_consent_events_pkey ON public.mobile_vendor_loyalty_consent_events USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_loyalty_consent_events_channel_check","definition":"CHECK (channel = ANY (ARRAY['email'::text, 'sms'::text]))"},{"name":"mobile_vendor_loyalty_consent_events_consent_status_check","definition":"CHECK (consent_status = ANY (ARRAY['granted'::text, 'revoked'::text]))"},{"name":"mobile_vendor_loyalty_consent_events_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"mobile_vendor_loyalty_consent_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_loyalty_consent_events_tenant_member_fk","definition":"FOREIGN KEY (tenant_org_id, member_id) REFERENCES mobile_vendor_loyalty_members(tenant_org_id, id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_consent_events_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"mobile_vendor_loyalty_login_challenges","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"member_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"normalized_email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"code_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"attempts","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"max_attempts","type":"integer","default":"5","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"consumed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_mv_loyalty_login_email_created","definition":"CREATE INDEX idx_mv_loyalty_login_email_created ON public.mobile_vendor_loyalty_login_challenges USING btree (tenant_org_id, normalized_email, created_at DESC)"},{"name":"idx_mv_loyalty_login_expiry","definition":"CREATE INDEX idx_mv_loyalty_login_expiry ON public.mobile_vendor_loyalty_login_challenges USING btree (expires_at)"},{"name":"mobile_vendor_loyalty_login_challenges_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_login_challenges_pkey ON public.mobile_vendor_loyalty_login_challenges USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_loyalty_login_challenges_attempts_check","definition":"CHECK (attempts >= 0 AND attempts <= 10)"},{"name":"mobile_vendor_loyalty_login_challenges_max_attempts_check","definition":"CHECK (max_attempts >= 1 AND max_attempts <= 10)"},{"name":"mobile_vendor_loyalty_login_challenges_member_id_fkey","definition":"FOREIGN KEY (member_id) REFERENCES mobile_vendor_loyalty_members(id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_login_challenges_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_loyalty_login_challenges_tenant_member_fk","definition":"FOREIGN KEY (tenant_org_id, member_id) REFERENCES mobile_vendor_loyalty_members(tenant_org_id, id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_login_challenges_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"mobile_vendor_loyalty_members","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"normalized_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"normalized_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"email_opt_in","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"sms_opt_in","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'public_site'::text","identity":"","not_null":true,"generated":""},{"name":"join_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"joined_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_visit_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"visits","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"stamp_balance","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"lifetime_stamps","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"rewards_redeemed","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"unsubscribe_token","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"points_balance","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"lifetime_points","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"referral_code","type":"text","default":"upper(substr(replace((gen_random_uuid())::text, '-'::text, ''::text), 1, 10))","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mobile_vendor_loyalty_members_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_members_pkey ON public.mobile_vendor_loyalty_members USING btree (id)"},{"name":"mobile_vendor_loyalty_members_tenant_contact_uq","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_members_tenant_contact_uq ON public.mobile_vendor_loyalty_members USING btree (tenant_org_id, contact_id) WHERE (contact_id IS NOT NULL)"},{"name":"mobile_vendor_loyalty_members_tenant_email_uq","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_members_tenant_email_uq ON public.mobile_vendor_loyalty_members USING btree (tenant_org_id, normalized_email) WHERE (normalized_email IS NOT NULL)"},{"name":"mobile_vendor_loyalty_members_tenant_id_unique","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_members_tenant_id_unique ON public.mobile_vendor_loyalty_members USING btree (tenant_org_id, id)"},{"name":"mobile_vendor_loyalty_members_tenant_referral_code_uidx","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_members_tenant_referral_code_uidx ON public.mobile_vendor_loyalty_members USING btree (tenant_org_id, referral_code)"},{"name":"mobile_vendor_loyalty_members_tenant_status_idx","definition":"CREATE INDEX mobile_vendor_loyalty_members_tenant_status_idx ON public.mobile_vendor_loyalty_members USING btree (tenant_org_id, status, joined_at DESC)"},{"name":"mobile_vendor_loyalty_members_unsubscribe_uq","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_members_unsubscribe_uq ON public.mobile_vendor_loyalty_members USING btree (unsubscribe_token)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_loyalty_members_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"mobile_vendor_loyalty_members_lifetime_points_nonnegative","definition":"CHECK (lifetime_points >= 0)"},{"name":"mobile_vendor_loyalty_members_lifetime_stamps_check","definition":"CHECK (lifetime_stamps >= 0)"},{"name":"mobile_vendor_loyalty_members_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_loyalty_members_points_balance_nonnegative","definition":"CHECK (points_balance >= 0)"},{"name":"mobile_vendor_loyalty_members_points_not_above_lifetime","definition":"CHECK (points_balance <= lifetime_points)"},{"name":"mobile_vendor_loyalty_members_rewards_redeemed_check","definition":"CHECK (rewards_redeemed >= 0)"},{"name":"mobile_vendor_loyalty_members_stamp_balance_check","definition":"CHECK (stamp_balance >= 0)"},{"name":"mobile_vendor_loyalty_members_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'unsubscribed'::text]))"},{"name":"mobile_vendor_loyalty_members_tenant_id_unique","definition":"UNIQUE (tenant_org_id, id)"},{"name":"mobile_vendor_loyalty_members_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_members_visits_check","definition":"CHECK (visits >= 0)"}]},{"table":"mobile_vendor_loyalty_purchases","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"member_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"purchase_ref","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"payment_method","type":"text","default":"'cash'::text","identity":"","not_null":true,"generated":""},{"name":"amount_cents","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"currency","type":"text","default":"'USD'::text","identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'owner_action'::text","identity":"","not_null":true,"generated":""},{"name":"source_transaction_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'confirmed'::text","identity":"","not_null":true,"generated":""},{"name":"confirmed_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mobile_vendor_loyalty_purchases_member_occurred_idx","definition":"CREATE INDEX mobile_vendor_loyalty_purchases_member_occurred_idx ON public.mobile_vendor_loyalty_purchases USING btree (tenant_org_id, member_id, occurred_at DESC)"},{"name":"mobile_vendor_loyalty_purchases_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_purchases_pkey ON public.mobile_vendor_loyalty_purchases USING btree (id)"},{"name":"mobile_vendor_loyalty_purchases_source_transaction_key","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_purchases_source_transaction_key ON public.mobile_vendor_loyalty_purchases USING btree (tenant_org_id, payment_method, source_transaction_id) WHERE (source_transaction_id IS NOT NULL)"},{"name":"mobile_vendor_loyalty_purchases_tenant_ref_key","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_purchases_tenant_ref_key ON public.mobile_vendor_loyalty_purchases USING btree (tenant_org_id, purchase_ref)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_loyalty_purchases_amount_cents_check","definition":"CHECK (amount_cents IS NULL OR amount_cents >= 0)"},{"name":"mobile_vendor_loyalty_purchases_confirmed_by_user_id_fkey","definition":"FOREIGN KEY (confirmed_by_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"mobile_vendor_loyalty_purchases_currency_check","definition":"CHECK (char_length(currency) = 3)"},{"name":"mobile_vendor_loyalty_purchases_payment_method_check","definition":"CHECK (payment_method = ANY (ARRAY['cash'::text, 'square'::text, 'other'::text]))"},{"name":"mobile_vendor_loyalty_purchases_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_loyalty_purchases_source_check","definition":"CHECK (btrim(source) <> ''::text)"},{"name":"mobile_vendor_loyalty_purchases_status_check","definition":"CHECK (status = ANY (ARRAY['confirmed'::text, 'voided'::text]))"},{"name":"mobile_vendor_loyalty_purchases_tenant_member_fk","definition":"FOREIGN KEY (tenant_org_id, member_id) REFERENCES mobile_vendor_loyalty_members(tenant_org_id, id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_purchases_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_purchases_tenant_ref_key","definition":"UNIQUE (tenant_org_id, purchase_ref)"}]},{"table":"mobile_vendor_loyalty_referrals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"referrer_member_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"friend_member_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"referral_code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'joined'::text","identity":"","not_null":true,"generated":""},{"name":"joined_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"first_purchase_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"referrer_points_awarded","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"referrer_points_awarded_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"welcome_reward_status","type":"text","default":"'pending_return'::text","identity":"","not_null":true,"generated":""},{"name":"welcome_unlocked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"welcome_redeemed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"first_purchase_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"first_purchase_source","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"mobile_vendor_loyalty_referrals_one_friend","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_referrals_one_friend ON public.mobile_vendor_loyalty_referrals USING btree (tenant_org_id, friend_member_id)"},{"name":"mobile_vendor_loyalty_referrals_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_referrals_pkey ON public.mobile_vendor_loyalty_referrals USING btree (id)"},{"name":"mobile_vendor_loyalty_referrals_referrer_idx","definition":"CREATE INDEX mobile_vendor_loyalty_referrals_referrer_idx ON public.mobile_vendor_loyalty_referrals USING btree (tenant_org_id, referrer_member_id, created_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_loyalty_referrals_friend_member_id_fkey","definition":"FOREIGN KEY (friend_member_id) REFERENCES mobile_vendor_loyalty_members(id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_referrals_no_self","definition":"CHECK (referrer_member_id <> friend_member_id)"},{"name":"mobile_vendor_loyalty_referrals_one_friend","definition":"UNIQUE (tenant_org_id, friend_member_id)"},{"name":"mobile_vendor_loyalty_referrals_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_loyalty_referrals_referrer_member_id_fkey","definition":"FOREIGN KEY (referrer_member_id) REFERENCES mobile_vendor_loyalty_members(id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_referrals_status_check","definition":"CHECK (status = ANY (ARRAY['joined'::text, 'purchase_confirmed'::text, 'welcome_ready'::text, 'completed'::text]))"},{"name":"mobile_vendor_loyalty_referrals_tenant_friend_fk","definition":"FOREIGN KEY (tenant_org_id, friend_member_id) REFERENCES mobile_vendor_loyalty_members(tenant_org_id, id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_referrals_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_referrals_tenant_referrer_fk","definition":"FOREIGN KEY (tenant_org_id, referrer_member_id) REFERENCES mobile_vendor_loyalty_members(tenant_org_id, id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_referrals_welcome_reward_status_check","definition":"CHECK (welcome_reward_status = ANY (ARRAY['pending_return'::text, 'ready'::text, 'redeemed'::text]))"}]},{"table":"mobile_vendor_loyalty_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"member_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"token_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"revoked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_seen_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_mv_loyalty_sessions_expiry","definition":"CREATE INDEX idx_mv_loyalty_sessions_expiry ON public.mobile_vendor_loyalty_sessions USING btree (expires_at)"},{"name":"idx_mv_loyalty_sessions_member","definition":"CREATE INDEX idx_mv_loyalty_sessions_member ON public.mobile_vendor_loyalty_sessions USING btree (tenant_org_id, member_id, created_at DESC)"},{"name":"mobile_vendor_loyalty_sessions_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_sessions_pkey ON public.mobile_vendor_loyalty_sessions USING btree (id)"},{"name":"mobile_vendor_loyalty_sessions_token_hash_key","definition":"CREATE UNIQUE INDEX mobile_vendor_loyalty_sessions_token_hash_key ON public.mobile_vendor_loyalty_sessions USING btree (token_hash)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_loyalty_sessions_member_id_fkey","definition":"FOREIGN KEY (member_id) REFERENCES mobile_vendor_loyalty_members(id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_sessions_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_loyalty_sessions_tenant_member_fk","definition":"FOREIGN KEY (tenant_org_id, member_id) REFERENCES mobile_vendor_loyalty_members(tenant_org_id, id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_sessions_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"mobile_vendor_loyalty_sessions_token_hash_key","definition":"UNIQUE (token_hash)"}]},{"table":"mobile_vendor_proposal_sequences","schema":"public","columns":[{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"proposal_year","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"last_sequence","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mobile_vendor_proposal_sequences_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_proposal_sequences_pkey ON public.mobile_vendor_proposal_sequences USING btree (tenant_org_id, proposal_year)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_proposal_sequences_last_sequence_check","definition":"CHECK (last_sequence >= 0)"},{"name":"mobile_vendor_proposal_sequences_pkey","definition":"PRIMARY KEY (tenant_org_id, proposal_year)"},{"name":"mobile_vendor_proposal_sequences_proposal_year_check","definition":"CHECK (proposal_year >= 2000 AND proposal_year <= 2200)"},{"name":"mobile_vendor_proposal_sequences_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"mobile_vendor_schedule_imports","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'uploading'::text","identity":"","not_null":true,"generated":""},{"name":"source_files","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"extracted_events","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"reviewed_events","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"warnings","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"model","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"default_year","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_booking_ids","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"skipped_duplicates","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"error_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"extracted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"committed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"failed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mobile_vendor_schedule_imports_owner_pending_idx","definition":"CREATE INDEX mobile_vendor_schedule_imports_owner_pending_idx ON public.mobile_vendor_schedule_imports USING btree (tenant_org_id, created_by, status, created_at DESC)"},{"name":"mobile_vendor_schedule_imports_pkey","definition":"CREATE UNIQUE INDEX mobile_vendor_schedule_imports_pkey ON public.mobile_vendor_schedule_imports USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"mobile_vendor_schedule_imports_pkey","definition":"PRIMARY KEY (id)"},{"name":"mobile_vendor_schedule_imports_skipped_duplicates_check","definition":"CHECK (skipped_duplicates >= 0)"},{"name":"mobile_vendor_schedule_imports_status_check","definition":"CHECK (status = ANY (ARRAY['uploading'::text, 'extracted'::text, 'committed'::text, 'duplicate'::text, 'failed'::text]))"},{"name":"mobile_vendor_schedule_imports_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"mode_change_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"from_mode","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"to_mode","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_by_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"mode_change_log_pkey","definition":"CREATE UNIQUE INDEX mode_change_log_pkey ON public.mode_change_log USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"mode_change_log","permissive":"PERMISSIVE","policyname":"Only GodMode can insert mode log","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"mode_change_log","permissive":"PERMISSIVE","policyname":"System admins read mode log","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"mode_change_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"nav_items","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"route","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"icon","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"roles","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"tenant_types","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_nav_items_order_index","definition":"CREATE INDEX idx_nav_items_order_index ON public.nav_items USING btree (order_index)"},{"name":"idx_nav_items_tenant_org_id","definition":"CREATE INDEX idx_nav_items_tenant_org_id ON public.nav_items USING btree (tenant_org_id)"},{"name":"nav_items_pkey","definition":"CREATE UNIQUE INDEX nav_items_pkey ON public.nav_items USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"((is_active = true) AND ((tenant_org_id IS NULL) OR is_tenant_member(tenant_org_id) OR is_system_admin(uid())))","roles":["authenticated"],"tablename":"nav_items","permissive":"PERMISSIVE","policyname":"Users view active nav items in their tenant","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"nav_items","permissive":"PERMISSIVE","policyname":"platform_admin_manage_nav_items","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"nav_items_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"needs_skiptrace","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"moved_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"original_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'Pending Skiptrace'::text","identity":"","not_null":false,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"moved_back_to_lead_deck","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"raw_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":"'No name extracted from document'::text","identity":"","not_null":true,"generated":""},{"name":"source_file","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"moved_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"skiptrace_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_needs_skiptrace_status","definition":"CREATE INDEX idx_needs_skiptrace_status ON public.needs_skiptrace USING btree (status)"},{"name":"idx_needs_skiptrace_tenant","definition":"CREATE INDEX idx_needs_skiptrace_tenant ON public.needs_skiptrace USING btree (tenant_org_id)"},{"name":"needs_skiptrace_pkey","definition":"CREATE UNIQUE INDEX needs_skiptrace_pkey ON public.needs_skiptrace USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = needs_skiptrace.tenant_org_id))))","roles":["public"],"tablename":"needs_skiptrace","permissive":"PERMISSIVE","policyname":"Users view tenant skiptrace leads","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin()","roles":["public"],"tablename":"needs_skiptrace","permissive":"PERMISSIVE","policyname":"ns_all","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"needs_skiptrace","permissive":"PERMISSIVE","policyname":"skiptrace_godmode","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"needs_skiptrace","permissive":"PERMISSIVE","policyname":"skiptrace_tenant_owner_admin","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))"},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (needs_skiptrace.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"needs_skiptrace","permissive":"PERMISSIVE","policyname":"tenant_users_delete_skiptrace","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"needs_skiptrace","permissive":"PERMISSIVE","policyname":"tenant_users_insert_skiptrace","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (needs_skiptrace.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (needs_skiptrace.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"needs_skiptrace","permissive":"PERMISSIVE","policyname":"tenant_users_update_skiptrace","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (needs_skiptrace.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (needs_skiptrace.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"needs_skiptrace","permissive":"PERMISSIVE","policyname":"tenant_users_view_skiptrace","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"needs_skiptrace_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"new_roofs_queue","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_finaled_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_age_years","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"moved_to_queue_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"moved_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":"'Recent roof permit'::text","identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":false,"generated":""},{"name":"reviewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_new_roofs_queue_lead","definition":"CREATE INDEX idx_new_roofs_queue_lead ON public.new_roofs_queue USING btree (lead_id)"},{"name":"idx_new_roofs_queue_tenant","definition":"CREATE INDEX idx_new_roofs_queue_tenant ON public.new_roofs_queue USING btree (tenant_org_id, status)"},{"name":"new_roofs_queue_lead_id_tenant_org_id_key","definition":"CREATE UNIQUE INDEX new_roofs_queue_lead_id_tenant_org_id_key ON public.new_roofs_queue USING btree (lead_id, tenant_org_id)"},{"name":"new_roofs_queue_pkey","definition":"CREATE UNIQUE INDEX new_roofs_queue_pkey ON public.new_roofs_queue USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND ((user_roles.tenant_id)::text = new_roofs_queue.tenant_org_id) AND (user_roles.role = ANY (ARRAY['Admin'::app_role, 'GodMode'::app_role, 'Owner'::app_role])))))","roles":["public"],"tablename":"new_roofs_queue","permissive":"PERMISSIVE","policyname":"Admins manage new roofs queue","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = new_roofs_queue.tenant_org_id))))","roles":["public"],"tablename":"new_roofs_queue","permissive":"PERMISSIVE","policyname":"Users view tenant new roofs queue","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin()","roles":["public"],"tablename":"new_roofs_queue","permissive":"PERMISSIVE","policyname":"nrq_all","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (new_roofs_queue.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"new_roofs_queue","permissive":"PERMISSIVE","policyname":"tenant_users_delete_new_roofs","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"new_roofs_queue","permissive":"PERMISSIVE","policyname":"tenant_users_insert_new_roofs","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (new_roofs_queue.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (new_roofs_queue.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"new_roofs_queue","permissive":"PERMISSIVE","policyname":"tenant_users_update_new_roofs","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (new_roofs_queue.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (new_roofs_queue.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"new_roofs_queue","permissive":"PERMISSIVE","policyname":"tenant_users_view_new_roofs","schemaname":"public","with_check":null}],"triggers":[{"name":"new_roofs_queue_updated_at","definition":"CREATE TRIGGER new_roofs_queue_updated_at BEFORE UPDATE ON new_roofs_queue FOR EACH ROW EXECUTE FUNCTION update_new_roofs_queue_updated_at()"}],"constraints":[{"name":"new_roofs_queue_lead_id_tenant_org_id_key","definition":"UNIQUE (lead_id, tenant_org_id)"},{"name":"new_roofs_queue_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"notes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"gid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"note","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":"'preworkflow'::text","identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_notes_lead_id","definition":"CREATE INDEX idx_notes_lead_id ON public.notes USING btree (lead_id)"},{"name":"notes_pkey","definition":"CREATE UNIQUE INDEX notes_pkey ON public.notes USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(rep_email = (( SELECT users.email\n   FROM users\n  WHERE (users.id = uid())))::text)","roles":["authenticated"],"tablename":"notes","permissive":"PERMISSIVE","policyname":"Users can delete own notes","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(rep_email = (( SELECT users.email\n   FROM users\n  WHERE (users.id = uid())))::text)","roles":["authenticated"],"tablename":"notes","permissive":"PERMISSIVE","policyname":"Users can update own notes","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((rep_email = (( SELECT users.email\n   FROM users\n  WHERE (users.id = uid())))::text) OR (EXISTS ( SELECT 1\n   FROM (lead_deck ld\n     JOIN security_active_user_tenant_memberships utm ON (((utm.tenant_id)::text = ld.tenant_org_id)))\n  WHERE ((ld.lead_id = notes.lead_id) AND (utm.user_id = uid()) AND (utm.status = 'active'::text)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"notes","permissive":"PERMISSIVE","policyname":"Users can view own or tenant notes","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"false","roles":["public"],"tablename":"notes","permissive":"PERMISSIVE","policyname":"deny all","schemaname":"public","with_check":"false"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"notes","permissive":"PERMISSIVE","policyname":"users_insert_tenant_notes","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (lead_deck ld\n     JOIN security_active_user_tenant_memberships utm ON (((utm.tenant_id)::text = ld.tenant_org_id)))\n  WHERE ((ld.lead_id = notes.lead_id) AND (utm.user_id = uid()) AND (utm.status = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"notes_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"notification_preferences","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"in_app_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"email_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"sms_enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"frequency","type":"text","default":"'instant'::text","identity":"","not_null":true,"generated":""},{"name":"quiet_hours_start","type":"time without time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"quiet_hours_end","type":"time without time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"push_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_notif_prefs_user","definition":"CREATE INDEX idx_notif_prefs_user ON public.notification_preferences USING btree (user_id)"},{"name":"notification_preferences_pkey","definition":"CREATE UNIQUE INDEX notification_preferences_pkey ON public.notification_preferences USING btree (id)"},{"name":"notification_preferences_user_id_event_type_key","definition":"CREATE UNIQUE INDEX notification_preferences_user_id_event_type_key ON public.notification_preferences USING btree (user_id, event_type)"}],"policies":[{"cmd":"DELETE","qual":"(uid() = user_id)","roles":["public"],"tablename":"notification_preferences","permissive":"PERMISSIVE","policyname":"Users delete their own notification prefs","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"notification_preferences","permissive":"PERMISSIVE","policyname":"Users insert their own notification prefs","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["public"],"tablename":"notification_preferences","permissive":"PERMISSIVE","policyname":"Users update their own notification prefs","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["public"],"tablename":"notification_preferences","permissive":"PERMISSIVE","policyname":"Users view their own notification prefs","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_notif_prefs_updated_at","definition":"CREATE TRIGGER trg_notif_prefs_updated_at BEFORE UPDATE ON notification_preferences FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"notification_preferences_pkey","definition":"PRIMARY KEY (id)"},{"name":"notification_preferences_user_id_event_type_key","definition":"UNIQUE (user_id, event_type)"},{"name":"valid_frequency","definition":"CHECK (frequency = ANY (ARRAY['instant'::text, 'hourly_digest'::text, 'daily_digest'::text, 'never'::text]))"}]},{"table":"notification_queue","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"notification_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"severity","type":"text","default":"'info'::text","identity":"","not_null":false,"generated":""},{"name":"read","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"action_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"read_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_notification_created","definition":"CREATE INDEX idx_notification_created ON public.notification_queue USING btree (created_at DESC)"},{"name":"idx_notification_read","definition":"CREATE INDEX idx_notification_read ON public.notification_queue USING btree (read)"},{"name":"idx_notification_user_id","definition":"CREATE INDEX idx_notification_user_id ON public.notification_queue USING btree (user_id)"},{"name":"notification_queue_pkey","definition":"CREATE UNIQUE INDEX notification_queue_pkey ON public.notification_queue USING btree (id)"},{"name":"notification_queue_unique_per_jobreq_user","definition":"CREATE UNIQUE INDEX notification_queue_unique_per_jobreq_user ON public.notification_queue USING btree (user_id, notification_type, ((metadata ->> 'job_request_id'::text))) WHERE (notification_type = 'job_request_pending'::text)"}],"policies":[{"cmd":"UPDATE","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"notification_queue","permissive":"PERMISSIVE","policyname":"Users can update own notifications","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"SELECT","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"notification_queue","permissive":"PERMISSIVE","policyname":"Users can view own notifications","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"notification_queue","permissive":"PERMISSIVE","policyname":"platform_admin_insert_notifications","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"notification_queue_pkey","definition":"PRIMARY KEY (id)"},{"name":"notification_queue_severity_check","definition":"CHECK (severity = ANY (ARRAY['info'::text, 'warning'::text, 'critical'::text]))"}]},{"table":"notifications","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"link","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"read_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"acknowledged_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"snoozed_until","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_notifications_unread","definition":"CREATE INDEX idx_notifications_unread ON public.notifications USING btree (user_id) WHERE (read_at IS NULL)"},{"name":"idx_notifications_user_id","definition":"CREATE INDEX idx_notifications_user_id ON public.notifications USING btree (user_id)"},{"name":"notifications_message_push_receipt_lookup","definition":"CREATE INDEX notifications_message_push_receipt_lookup ON public.notifications USING btree (user_id, tenant_id, ((metadata ->> 'dedupe_key'::text))) WHERE (type = 'message_received'::text)"},{"name":"notifications_pkey","definition":"CREATE UNIQUE INDEX notifications_pkey ON public.notifications USING btree (id)"},{"name":"notifications_unique_per_jobreq_user","definition":"CREATE UNIQUE INDEX notifications_unique_per_jobreq_user ON public.notifications USING btree (user_id, type, ((metadata ->> 'job_request_id'::text))) WHERE (type = 'job_request_pending'::text)"},{"name":"notifications_user_snooze","definition":"CREATE INDEX notifications_user_snooze ON public.notifications USING btree (user_id, snoozed_until) WHERE (snoozed_until IS NOT NULL)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["service_role"],"tablename":"notifications","permissive":"PERMISSIVE","policyname":"Service role can insert notifications","schemaname":"public","with_check":"true"},{"cmd":"UPDATE","qual":"(( SELECT uid() AS uid) = user_id)","roles":["public"],"tablename":"notifications","permissive":"PERMISSIVE","policyname":"Users can update their own notifications","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(( SELECT uid() AS uid) = user_id)","roles":["public"],"tablename":"notifications","permissive":"PERMISSIVE","policyname":"Users can view their own notifications","schemaname":"public","with_check":null}],"triggers":[{"name":"notification_safe_destination","definition":"CREATE TRIGGER notification_safe_destination BEFORE INSERT OR UPDATE OF link ON notifications FOR EACH ROW EXECUTE FUNCTION enforce_safe_notification_destination()"},{"name":"notifications_platform_delivery_route","definition":"CREATE TRIGGER notifications_platform_delivery_route AFTER INSERT ON notifications FOR EACH ROW EXECUTE FUNCTION route_platform_notification_delivery()"},{"name":"zz_notifications_message_push_intent","definition":"CREATE TRIGGER zz_notifications_message_push_intent AFTER INSERT ON notifications FOR EACH ROW EXECUTE FUNCTION promote_committed_message_push_intent()"}],"constraints":[{"name":"notifications_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"ocr_jobs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"total_files","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"processed_files","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"ocr_progress","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"results","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"ocr_jobs_pkey","definition":"CREATE UNIQUE INDEX ocr_jobs_pkey ON public.ocr_jobs USING btree (id)"},{"name":"ocr_jobs_user_id_idx","definition":"CREATE INDEX ocr_jobs_user_id_idx ON public.ocr_jobs USING btree (user_id, created_at DESC)"}],"policies":[{"cmd":"DELETE","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"ocr_jobs","permissive":"PERMISSIVE","policyname":"Users manage own OCR jobs - delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"ocr_jobs","permissive":"PERMISSIVE","policyname":"Users manage own OCR jobs - insert","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"ocr_jobs","permissive":"PERMISSIVE","policyname":"Users manage own OCR jobs - select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"ocr_jobs","permissive":"PERMISSIVE","policyname":"Users manage own OCR jobs - update","schemaname":"public","with_check":"(uid() = user_id)"}],"triggers":[{"name":"ocr_jobs_set_updated_at","definition":"CREATE TRIGGER ocr_jobs_set_updated_at BEFORE UPDATE ON ocr_jobs FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"ocr_jobs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"offline_sync_queue","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"operation_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"table_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"record_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"data","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"synced_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_offline_sync_queue_status","definition":"CREATE INDEX idx_offline_sync_queue_status ON public.offline_sync_queue USING btree (status)"},{"name":"idx_offline_sync_queue_user_id","definition":"CREATE INDEX idx_offline_sync_queue_user_id ON public.offline_sync_queue USING btree (user_id)"},{"name":"offline_sync_queue_pkey","definition":"CREATE UNIQUE INDEX offline_sync_queue_pkey ON public.offline_sync_queue USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(uid() = user_id)","roles":["public"],"tablename":"offline_sync_queue","permissive":"PERMISSIVE","policyname":"Users manage their sync queue","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"offline_sync_queue_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"onboarding_email_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"template_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'invitation'::text","identity":"","not_null":false,"generated":""},{"name":"variables","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"onboarding_email_templates_pkey","definition":"CREATE UNIQUE INDEX onboarding_email_templates_pkey ON public.onboarding_email_templates USING btree (id)"},{"name":"onboarding_email_templates_template_key_key","definition":"CREATE UNIQUE INDEX onboarding_email_templates_template_key_key ON public.onboarding_email_templates USING btree (template_key)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"onboarding_email_templates","permissive":"PERMISSIVE","policyname":"Authenticated users can view templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"onboarding_email_templates","permissive":"PERMISSIVE","policyname":"system_admins_manage_templates","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[{"name":"update_onboarding_email_templates_updated_at","definition":"CREATE TRIGGER update_onboarding_email_templates_updated_at BEFORE UPDATE ON onboarding_email_templates FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"onboarding_email_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"onboarding_email_templates_template_key_key","definition":"UNIQUE (template_key)"}]},{"table":"onboarding_license_sources","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"jurisdiction","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"business_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_official","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"onboarding_license_sources_jurisdiction_business_type_provi_key","definition":"CREATE UNIQUE INDEX onboarding_license_sources_jurisdiction_business_type_provi_key ON public.onboarding_license_sources USING btree (jurisdiction, business_type, provider_key)"},{"name":"onboarding_license_sources_pkey","definition":"CREATE UNIQUE INDEX onboarding_license_sources_pkey ON public.onboarding_license_sources USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"onboarding_license_sources","permissive":"PERMISSIVE","policyname":"onboarding_license_sources_platform_read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"onboarding_license_sources","permissive":"PERMISSIVE","policyname":"onboarding_license_sources_platform_write","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"onboarding_license_sources_jurisdiction_business_type_provi_key","definition":"UNIQUE (jurisdiction, business_type, provider_key)"},{"name":"onboarding_license_sources_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"onboarding_research_tasks","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"research_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"jurisdiction","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"query","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"result","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"dispatch_token","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"dispatched_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_onboarding_research_session","definition":"CREATE INDEX idx_onboarding_research_session ON public.onboarding_research_tasks USING btree (session_id, status)"},{"name":"onboarding_research_tasks_pkey","definition":"CREATE UNIQUE INDEX onboarding_research_tasks_pkey ON public.onboarding_research_tasks USING btree (id)"},{"name":"uq_onboarding_research_task_scope","definition":"CREATE UNIQUE INDEX uq_onboarding_research_task_scope ON public.onboarding_research_tasks USING btree (session_id, research_type, jurisdiction)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"onboarding_research_tasks","permissive":"PERMISSIVE","policyname":"onboarding_research_admin_manage","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM onboarding_sessions s\n  WHERE ((s.id = onboarding_research_tasks.session_id) AND (s.owner_user_id = uid())))))","roles":["public"],"tablename":"onboarding_research_tasks","permissive":"PERMISSIVE","policyname":"onboarding_research_owner_select","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_dispatch_onboarding_research_task","definition":"CREATE TRIGGER trg_dispatch_onboarding_research_task AFTER INSERT OR UPDATE OF status, dispatch_token, provider_key ON onboarding_research_tasks FOR EACH ROW EXECUTE FUNCTION dispatch_onboarding_research_task()"}],"constraints":[{"name":"onboarding_research_tasks_pkey","definition":"PRIMARY KEY (id)"},{"name":"onboarding_research_tasks_session_id_fkey","definition":"FOREIGN KEY (session_id) REFERENCES onboarding_sessions(id) ON DELETE CASCADE"},{"name":"onboarding_research_tasks_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'running'::text, 'verified'::text, 'not_found'::text, 'needs_review'::text, 'failed'::text, 'skipped'::text]))"}]},{"table":"onboarding_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"owner_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"company_slug","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"requested_business_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"canonical_tenant_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_lines","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"operating_states","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"service_area","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"team_size","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"goals","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"requested_capabilities","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"intake_answers","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"research_state","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"derived_blueprint","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"readiness","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_onboarding_sessions_owner","definition":"CREATE INDEX idx_onboarding_sessions_owner ON public.onboarding_sessions USING btree (owner_user_id, created_at DESC)"},{"name":"idx_onboarding_sessions_status","definition":"CREATE INDEX idx_onboarding_sessions_status ON public.onboarding_sessions USING btree (status, updated_at DESC)"},{"name":"onboarding_sessions_pkey","definition":"CREATE UNIQUE INDEX onboarding_sessions_pkey ON public.onboarding_sessions USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"is_system_admin(uid())","roles":["public"],"tablename":"onboarding_sessions","permissive":"PERMISSIVE","policyname":"onboarding_sessions_admin_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"onboarding_sessions","permissive":"PERMISSIVE","policyname":"onboarding_sessions_owner_insert","schemaname":"public","with_check":"((owner_user_id = uid()) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((owner_user_id = uid()) OR is_system_admin(uid()))","roles":["public"],"tablename":"onboarding_sessions","permissive":"PERMISSIVE","policyname":"onboarding_sessions_owner_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((owner_user_id = uid()) OR is_system_admin(uid()))","roles":["public"],"tablename":"onboarding_sessions","permissive":"PERMISSIVE","policyname":"onboarding_sessions_owner_update","schemaname":"public","with_check":"((owner_user_id = uid()) OR is_system_admin(uid()))"}],"triggers":[],"constraints":[{"name":"onboarding_sessions_pkey","definition":"PRIMARY KEY (id)"},{"name":"onboarding_sessions_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'intake'::text, 'researching'::text, 'validating'::text, 'needs_input'::text, 'ready_to_provision'::text, 'provisioning'::text, 'ready'::text, 'live'::text, 'blocked'::text, 'failed'::text, 'cancelled'::text]))"},{"name":"onboarding_sessions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE SET NULL"}]},{"table":"opportunity_radar_opportunities","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_kind","type":"text","default":"'public_web'::text","identity":"","not_null":true,"generated":""},{"name":"source_external_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"excerpt","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"intent_score","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"confidence","type":"numeric(5,4)","default":"0","identity":"","not_null":true,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"posted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"captured_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'new'::text","identity":"","not_null":true,"generated":""},{"name":"dedupe_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provenance","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_opportunity_radar_tenant_captured","definition":"CREATE INDEX idx_opportunity_radar_tenant_captured ON public.opportunity_radar_opportunities USING btree (tenant_id, captured_at DESC)"},{"name":"idx_opportunity_radar_tenant_status","definition":"CREATE INDEX idx_opportunity_radar_tenant_status ON public.opportunity_radar_opportunities USING btree (tenant_id, status, intent_score DESC)"},{"name":"opportunity_radar_opportunities_pkey","definition":"CREATE UNIQUE INDEX opportunity_radar_opportunities_pkey ON public.opportunity_radar_opportunities USING btree (id)"},{"name":"opportunity_radar_opportunities_tenant_id_dedupe_key_key","definition":"CREATE UNIQUE INDEX opportunity_radar_opportunities_tenant_id_dedupe_key_key ON public.opportunity_radar_opportunities USING btree (tenant_id, dedupe_key)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"opportunity_radar_opportunities","permissive":"PERMISSIVE","policyname":"opportunity_radar_opportunities_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"opportunity_radar_opportunities","permissive":"PERMISSIVE","policyname":"opportunity_radar_opportunities_insert","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"opportunity_radar_opportunities","permissive":"PERMISSIVE","policyname":"opportunity_radar_opportunities_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"opportunity_radar_opportunities","permissive":"PERMISSIVE","policyname":"opportunity_radar_opportunities_update","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_opportunity_radar_updated_at","definition":"CREATE TRIGGER trg_opportunity_radar_updated_at BEFORE UPDATE ON opportunity_radar_opportunities FOR EACH ROW EXECUTE FUNCTION touch_opportunity_radar_updated_at()"}],"constraints":[{"name":"opportunity_radar_opportunities_confidence_check","definition":"CHECK (confidence >= 0::numeric AND confidence <= 1::numeric)"},{"name":"opportunity_radar_opportunities_intent_score_check","definition":"CHECK (intent_score >= 0 AND intent_score <= 100)"},{"name":"opportunity_radar_opportunities_pkey","definition":"PRIMARY KEY (id)"},{"name":"opportunity_radar_opportunities_status_check","definition":"CHECK (status = ANY (ARRAY['new'::text, 'saved'::text, 'dismissed'::text, 'converted'::text]))"},{"name":"opportunity_radar_opportunities_tenant_id_dedupe_key_key","definition":"UNIQUE (tenant_id, dedupe_key)"},{"name":"opportunity_radar_opportunities_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"opportunity_radar_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"anchor_zip","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"anchor_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'running'::text","identity":"","not_null":true,"generated":""},{"name":"source_summary","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"discovered_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"inserted_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_opportunity_radar_runs_tenant_started","definition":"CREATE INDEX idx_opportunity_radar_runs_tenant_started ON public.opportunity_radar_runs USING btree (tenant_id, started_at DESC)"},{"name":"opportunity_radar_runs_pkey","definition":"CREATE UNIQUE INDEX opportunity_radar_runs_pkey ON public.opportunity_radar_runs USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"opportunity_radar_runs","permissive":"PERMISSIVE","policyname":"opportunity_radar_runs_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"opportunity_radar_runs_pkey","definition":"PRIMARY KEY (id)"},{"name":"opportunity_radar_runs_status_check","definition":"CHECK (status = ANY (ARRAY['running'::text, 'complete'::text, 'failed'::text, 'skipped'::text]))"},{"name":"opportunity_radar_runs_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"opportunity_radar_seed_state","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"fingerprint","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"last_run_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_attempt_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"opportunity_radar_seed_state_pkey","definition":"CREATE UNIQUE INDEX opportunity_radar_seed_state_pkey ON public.opportunity_radar_seed_state USING btree (tenant_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"opportunity_radar_seed_state_last_run_id_fkey","definition":"FOREIGN KEY (last_run_id) REFERENCES opportunity_radar_runs(id) ON DELETE SET NULL"},{"name":"opportunity_radar_seed_state_pkey","definition":"PRIMARY KEY (tenant_id)"},{"name":"opportunity_radar_seed_state_status_check","definition":"CHECK (status = ANY (ARRAY['running'::text, 'complete'::text, 'failed'::text, 'waiting_for_location'::text, 'profile_not_configured'::text]))"},{"name":"opportunity_radar_seed_state_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"owner_business_prospects","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"business_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"vertical","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"website_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"evidence_tier","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"captured_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"dedupe_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"fit_score","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"fit_rationale","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"recommended_application_ids","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"recommended_tenant_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stage","type":"text","default":"'discovered'::text","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"converted_tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"provenance","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"owner_business_prospects_dedupe_key_key","definition":"CREATE UNIQUE INDEX owner_business_prospects_dedupe_key_key ON public.owner_business_prospects USING btree (dedupe_key)"},{"name":"owner_business_prospects_pkey","definition":"CREATE UNIQUE INDEX owner_business_prospects_pkey ON public.owner_business_prospects USING btree (id)"},{"name":"owner_business_prospects_stage_idx","definition":"CREATE INDEX owner_business_prospects_stage_idx ON public.owner_business_prospects USING btree (stage, updated_at DESC)"},{"name":"owner_business_prospects_vertical_idx","definition":"CREATE INDEX owner_business_prospects_vertical_idx ON public.owner_business_prospects USING btree (vertical, updated_at DESC)"}],"policies":[{"cmd":"DELETE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_business_prospects","permissive":"PERMISSIVE","policyname":"owner_business_prospects_platform_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"owner_business_prospects","permissive":"PERMISSIVE","policyname":"owner_business_prospects_platform_insert","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_business_prospects","permissive":"PERMISSIVE","policyname":"owner_business_prospects_platform_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_business_prospects","permissive":"PERMISSIVE","policyname":"owner_business_prospects_platform_update","schemaname":"public","with_check":"is_platform_admin(uid())"}],"triggers":[],"constraints":[{"name":"owner_business_prospects_converted_tenant_id_fkey","definition":"FOREIGN KEY (converted_tenant_id) REFERENCES tenants(id) ON DELETE SET NULL"},{"name":"owner_business_prospects_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"owner_business_prospects_dedupe_key_key","definition":"UNIQUE (dedupe_key)"},{"name":"owner_business_prospects_evidence_tier_check","definition":"CHECK (evidence_tier = ANY (ARRAY['public_page_verified'::text, 'direct_public_source'::text, 'connected_source'::text]))"},{"name":"owner_business_prospects_fit_score_check","definition":"CHECK (fit_score >= 0 AND fit_score <= 100)"},{"name":"owner_business_prospects_pkey","definition":"PRIMARY KEY (id)"},{"name":"owner_business_prospects_stage_check","definition":"CHECK (stage = ANY (ARRAY['discovered'::text, 'qualified'::text, 'demo'::text, 'proposal'::text, 'won'::text, 'lost'::text]))"}]},{"table":"owner_compensation_terms","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"relationship_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"proposal_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lane_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'proposed'::text","identity":"","not_null":true,"generated":""},{"name":"earning_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rate_pct","type":"numeric(9,4)","default":null,"identity":"","not_null":false,"generated":""},{"name":"fixed_amount","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"currency","type":"text","default":"'USD'::text","identity":"","not_null":true,"generated":""},{"name":"trigger_event","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"settlement_rule","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"effective_start","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"effective_end","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"supersedes_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"owner_compensation_terms_lane_version_uidx","definition":"CREATE UNIQUE INDEX owner_compensation_terms_lane_version_uidx ON public.owner_compensation_terms USING btree (tenant_id, lane_key, version)"},{"name":"owner_compensation_terms_pkey","definition":"CREATE UNIQUE INDEX owner_compensation_terms_pkey ON public.owner_compensation_terms USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_compensation_terms","permissive":"PERMISSIVE","policyname":"owner_compensation_terms_platform_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"owner_compensation_terms","permissive":"PERMISSIVE","policyname":"owner_compensation_terms_platform_insert","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_compensation_terms","permissive":"PERMISSIVE","policyname":"owner_compensation_terms_platform_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_compensation_terms","permissive":"PERMISSIVE","policyname":"owner_compensation_terms_platform_update","schemaname":"public","with_check":"is_platform_admin(uid())"}],"triggers":[{"name":"owner_compensation_terms_updated_at","definition":"CREATE TRIGGER owner_compensation_terms_updated_at BEFORE UPDATE ON owner_compensation_terms FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"owner_compensation_terms_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"owner_compensation_terms_earning_type_check","definition":"CHECK (earning_type = ANY (ARRAY['personal_sales_commission'::text, 'draw_advance'::text, 'digital_originated_percentage'::text, 'monthly_management_fee'::text, 'one_time_fee'::text, 'custom'::text]))"},{"name":"owner_compensation_terms_fixed_amount_check","definition":"CHECK (fixed_amount IS NULL OR fixed_amount >= 0::numeric)"},{"name":"owner_compensation_terms_pkey","definition":"PRIMARY KEY (id)"},{"name":"owner_compensation_terms_proposal_id_fkey","definition":"FOREIGN KEY (proposal_id) REFERENCES owner_relationship_proposals(id) ON DELETE SET NULL"},{"name":"owner_compensation_terms_rate_pct_check","definition":"CHECK (rate_pct IS NULL OR rate_pct >= 0::numeric AND rate_pct <= 100::numeric)"},{"name":"owner_compensation_terms_relationship_id_fkey","definition":"FOREIGN KEY (relationship_id) REFERENCES owner_tenant_relationships(id) ON DELETE CASCADE"},{"name":"owner_compensation_terms_status_check","definition":"CHECK (status = ANY (ARRAY['proposed'::text, 'active'::text, 'superseded'::text, 'ended'::text, 'declined'::text]))"},{"name":"owner_compensation_terms_supersedes_id_fkey","definition":"FOREIGN KEY (supersedes_id) REFERENCES owner_compensation_terms(id) ON DELETE SET NULL"},{"name":"owner_compensation_terms_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"owner_compensation_terms_version_check","definition":"CHECK (version > 0)"}]},{"table":"owner_receivable_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"receivable_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"amount","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"note","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"snapshot","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"payment_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payment_reference","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"invoice_record_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"finance_transaction_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"owner_receivable_events_payment_idx","definition":"CREATE INDEX owner_receivable_events_payment_idx ON public.owner_receivable_events USING btree (receivable_id, occurred_at DESC) WHERE (event_type = 'payment_received'::text)"},{"name":"owner_receivable_events_pkey","definition":"CREATE UNIQUE INDEX owner_receivable_events_pkey ON public.owner_receivable_events USING btree (id)"},{"name":"owner_receivable_events_receivable_idx","definition":"CREATE INDEX owner_receivable_events_receivable_idx ON public.owner_receivable_events USING btree (receivable_id, created_at DESC)"},{"name":"owner_receivable_payment_finance_tx_uidx","definition":"CREATE UNIQUE INDEX owner_receivable_payment_finance_tx_uidx ON public.owner_receivable_events USING btree (receivable_id, finance_transaction_id) WHERE ((event_type = 'payment_received'::text) AND (finance_transaction_id IS NOT NULL))"}],"policies":[{"cmd":"DELETE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_receivable_events","permissive":"PERMISSIVE","policyname":"owner_receivable_events_platform_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"owner_receivable_events","permissive":"PERMISSIVE","policyname":"owner_receivable_events_platform_insert","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_receivable_events","permissive":"PERMISSIVE","policyname":"owner_receivable_events_platform_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_receivable_events","permissive":"PERMISSIVE","policyname":"owner_receivable_events_platform_update","schemaname":"public","with_check":"is_platform_admin(uid())"}],"triggers":[{"name":"owner_receivable_payment_event_rollup","definition":"CREATE TRIGGER owner_receivable_payment_event_rollup AFTER INSERT OR DELETE OR UPDATE ON owner_receivable_events FOR EACH ROW EXECUTE FUNCTION owner_receivable_payment_event_rollup()"}],"constraints":[{"name":"owner_receivable_events_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"owner_receivable_events_finance_transaction_id_fkey","definition":"FOREIGN KEY (finance_transaction_id) REFERENCES finance_transactions(id) ON DELETE SET NULL"},{"name":"owner_receivable_events_invoice_record_id_fkey","definition":"FOREIGN KEY (invoice_record_id) REFERENCES invoices(id) ON DELETE SET NULL"},{"name":"owner_receivable_events_payment_method_check","definition":"CHECK (payment_method IS NULL OR (payment_method = ANY (ARRAY['zelle'::text, 'apple_pay'::text, 'cash_app'::text, 'venmo'::text, 'cash'::text, 'check'::text, 'ach'::text, 'card'::text, 'other'::text])))"},{"name":"owner_receivable_events_payment_received_check","definition":"CHECK (event_type <> 'payment_received'::text OR amount IS NOT NULL AND amount > 0::numeric AND payment_method IS NOT NULL AND occurred_at IS NOT NULL)"},{"name":"owner_receivable_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"owner_receivable_events_receivable_id_fkey","definition":"FOREIGN KEY (receivable_id) REFERENCES owner_receivables(id) ON DELETE CASCADE"},{"name":"owner_receivable_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"owner_receivables","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"relationship_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"compensation_term_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"earning_lane","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"currency","type":"text","default":"'USD'::text","identity":"","not_null":true,"generated":""},{"name":"gross_basis","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"collected_basis","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"expected_amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"earned_amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"paid_amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"trigger_event","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"due_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"stage","type":"text","default":"'expected'::text","identity":"","not_null":true,"generated":""},{"name":"next_action","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_action_due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"supporting_artifact","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"earned_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"requested_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"paid_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"invoice_record_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"billing_account_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_period_start","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_period_end","type":"date","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"owner_receivables_invoice_record_idx","definition":"CREATE INDEX owner_receivables_invoice_record_idx ON public.owner_receivables USING btree (invoice_record_id) WHERE (invoice_record_id IS NOT NULL)"},{"name":"owner_receivables_pkey","definition":"CREATE UNIQUE INDEX owner_receivables_pkey ON public.owner_receivables USING btree (id)"},{"name":"owner_receivables_service_period_idx","definition":"CREATE INDEX owner_receivables_service_period_idx ON public.owner_receivables USING btree (tenant_id, service_period_end DESC) WHERE (service_period_end IS NOT NULL)"},{"name":"owner_receivables_stage_due_idx","definition":"CREATE INDEX owner_receivables_stage_due_idx ON public.owner_receivables USING btree (stage, due_date)"},{"name":"owner_receivables_tenant_lane_idx","definition":"CREATE INDEX owner_receivables_tenant_lane_idx ON public.owner_receivables USING btree (tenant_id, earning_lane, updated_at DESC)"}],"policies":[{"cmd":"DELETE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_receivables","permissive":"PERMISSIVE","policyname":"owner_receivables_platform_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"owner_receivables","permissive":"PERMISSIVE","policyname":"owner_receivables_platform_insert","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_receivables","permissive":"PERMISSIVE","policyname":"owner_receivables_platform_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_receivables","permissive":"PERMISSIVE","policyname":"owner_receivables_platform_update","schemaname":"public","with_check":"is_platform_admin(uid())"}],"triggers":[{"name":"owner_receivables_audit_change","definition":"CREATE TRIGGER owner_receivables_audit_change AFTER INSERT OR UPDATE ON owner_receivables FOR EACH ROW EXECUTE FUNCTION audit_owner_receivable_change()"},{"name":"owner_receivables_updated_at","definition":"CREATE TRIGGER owner_receivables_updated_at BEFORE UPDATE ON owner_receivables FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"owner_receivables_collected_basis_check","definition":"CHECK (collected_basis IS NULL OR collected_basis >= 0::numeric)"},{"name":"owner_receivables_compensation_term_id_fkey","definition":"FOREIGN KEY (compensation_term_id) REFERENCES owner_compensation_terms(id) ON DELETE SET NULL"},{"name":"owner_receivables_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"owner_receivables_earned_amount_check","definition":"CHECK (earned_amount >= 0::numeric)"},{"name":"owner_receivables_expected_amount_check","definition":"CHECK (expected_amount >= 0::numeric)"},{"name":"owner_receivables_gross_basis_check","definition":"CHECK (gross_basis IS NULL OR gross_basis >= 0::numeric)"},{"name":"owner_receivables_invoice_record_id_fkey","definition":"FOREIGN KEY (invoice_record_id) REFERENCES invoices(id) ON DELETE SET NULL"},{"name":"owner_receivables_paid_amount_check","definition":"CHECK (paid_amount >= 0::numeric)"},{"name":"owner_receivables_pkey","definition":"PRIMARY KEY (id)"},{"name":"owner_receivables_relationship_id_fkey","definition":"FOREIGN KEY (relationship_id) REFERENCES owner_tenant_relationships(id) ON DELETE CASCADE"},{"name":"owner_receivables_stage_check","definition":"CHECK (stage = ANY (ARRAY['proposed'::text, 'expected'::text, 'trigger_pending'::text, 'earned'::text, 'requested'::text, 'partially_paid'::text, 'paid'::text, 'overdue'::text, 'disputed'::text, 'written_off'::text]))"},{"name":"owner_receivables_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"owner_relationship_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"relationship_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"channel","type":"text","default":"'note'::text","identity":"","not_null":true,"generated":""},{"name":"direction","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"body_excerpt","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"participants","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"attachment_refs","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'manual'::text","identity":"","not_null":true,"generated":""},{"name":"source_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"owner_relationship_events_pkey","definition":"CREATE UNIQUE INDEX owner_relationship_events_pkey ON public.owner_relationship_events USING btree (id)"},{"name":"owner_relationship_events_source_uidx","definition":"CREATE UNIQUE INDEX owner_relationship_events_source_uidx ON public.owner_relationship_events USING btree (tenant_id, source, source_id) WHERE (source_id IS NOT NULL)"},{"name":"owner_relationship_events_tenant_occurred_idx","definition":"CREATE INDEX owner_relationship_events_tenant_occurred_idx ON public.owner_relationship_events USING btree (tenant_id, occurred_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"owner_relationship_events","permissive":"PERMISSIVE","policyname":"owner_relationship_events_platform_insert","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_relationship_events","permissive":"PERMISSIVE","policyname":"owner_relationship_events_platform_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_relationship_events","permissive":"PERMISSIVE","policyname":"owner_relationship_events_platform_update","schemaname":"public","with_check":"is_platform_admin(uid())"}],"triggers":[{"name":"owner_invitation_outcome_notification_bridge","definition":"CREATE TRIGGER owner_invitation_outcome_notification_bridge AFTER INSERT ON owner_relationship_events FOR EACH ROW EXECUTE FUNCTION bridge_invitation_outcome_to_notifications()"},{"name":"owner_relationship_event_touch_summary","definition":"CREATE TRIGGER owner_relationship_event_touch_summary AFTER INSERT ON owner_relationship_events FOR EACH ROW EXECUTE FUNCTION touch_owner_relationship_from_event()"}],"constraints":[{"name":"owner_relationship_events_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"owner_relationship_events_direction_check","definition":"CHECK (direction IS NULL OR (direction = ANY (ARRAY['inbound'::text, 'outbound'::text, 'internal'::text])))"},{"name":"owner_relationship_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"owner_relationship_events_relationship_id_fkey","definition":"FOREIGN KEY (relationship_id) REFERENCES owner_tenant_relationships(id) ON DELETE CASCADE"},{"name":"owner_relationship_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"owner_relationship_followups","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"relationship_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'open'::text","identity":"","not_null":true,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"related_proposal_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"owner_relationship_followups_due_idx","definition":"CREATE INDEX owner_relationship_followups_due_idx ON public.owner_relationship_followups USING btree (status, due_at)"},{"name":"owner_relationship_followups_pkey","definition":"CREATE UNIQUE INDEX owner_relationship_followups_pkey ON public.owner_relationship_followups USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_relationship_followups","permissive":"PERMISSIVE","policyname":"owner_relationship_followups_platform_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"owner_relationship_followups","permissive":"PERMISSIVE","policyname":"owner_relationship_followups_platform_insert","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_relationship_followups","permissive":"PERMISSIVE","policyname":"owner_relationship_followups_platform_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_relationship_followups","permissive":"PERMISSIVE","policyname":"owner_relationship_followups_platform_update","schemaname":"public","with_check":"is_platform_admin(uid())"}],"triggers":[{"name":"owner_followups_refresh_relationship","definition":"CREATE TRIGGER owner_followups_refresh_relationship AFTER INSERT OR DELETE OR UPDATE ON owner_relationship_followups FOR EACH ROW EXECUTE FUNCTION refresh_owner_relationship_next_action()"},{"name":"owner_relationship_followups_updated_at","definition":"CREATE TRIGGER owner_relationship_followups_updated_at BEFORE UPDATE ON owner_relationship_followups FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"owner_relationship_followups_owner_user_id_fkey","definition":"FOREIGN KEY (owner_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"owner_relationship_followups_pkey","definition":"PRIMARY KEY (id)"},{"name":"owner_relationship_followups_related_event_id_fkey","definition":"FOREIGN KEY (related_event_id) REFERENCES owner_relationship_events(id) ON DELETE SET NULL"},{"name":"owner_relationship_followups_related_proposal_id_fkey","definition":"FOREIGN KEY (related_proposal_id) REFERENCES owner_relationship_proposals(id) ON DELETE SET NULL"},{"name":"owner_relationship_followups_relationship_id_fkey","definition":"FOREIGN KEY (relationship_id) REFERENCES owner_tenant_relationships(id) ON DELETE CASCADE"},{"name":"owner_relationship_followups_status_check","definition":"CHECK (status = ANY (ARRAY['open'::text, 'snoozed'::text, 'completed'::text, 'cancelled'::text]))"},{"name":"owner_relationship_followups_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"owner_relationship_proposals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"relationship_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"recipient_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recipient_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"viewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"accepted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"declined_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"terms_summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"attachment_ref","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"supersedes_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":"'manual'::text","identity":"","not_null":true,"generated":""},{"name":"source_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"canonical_proposal_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"owner_relationship_proposals_pkey","definition":"CREATE UNIQUE INDEX owner_relationship_proposals_pkey ON public.owner_relationship_proposals USING btree (id)"},{"name":"owner_relationship_proposals_source_uidx","definition":"CREATE UNIQUE INDEX owner_relationship_proposals_source_uidx ON public.owner_relationship_proposals USING btree (tenant_id, source, source_id) WHERE (source_id IS NOT NULL)"},{"name":"owner_relationship_proposals_tenant_status_idx","definition":"CREATE INDEX owner_relationship_proposals_tenant_status_idx ON public.owner_relationship_proposals USING btree (tenant_id, status, updated_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"owner_relationship_proposals","permissive":"PERMISSIVE","policyname":"owner_relationship_proposals_platform_insert","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_relationship_proposals","permissive":"PERMISSIVE","policyname":"owner_relationship_proposals_platform_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_relationship_proposals","permissive":"PERMISSIVE","policyname":"owner_relationship_proposals_platform_update","schemaname":"public","with_check":"is_platform_admin(uid())"}],"triggers":[{"name":"owner_relationship_proposals_updated_at","definition":"CREATE TRIGGER owner_relationship_proposals_updated_at BEFORE UPDATE ON owner_relationship_proposals FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"owner_relationship_proposals_canonical_proposal_id_fkey","definition":"FOREIGN KEY (canonical_proposal_id) REFERENCES proposals(id) ON DELETE SET NULL"},{"name":"owner_relationship_proposals_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"owner_relationship_proposals_pkey","definition":"PRIMARY KEY (id)"},{"name":"owner_relationship_proposals_relationship_id_fkey","definition":"FOREIGN KEY (relationship_id) REFERENCES owner_tenant_relationships(id) ON DELETE CASCADE"},{"name":"owner_relationship_proposals_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'sent'::text, 'viewed'::text, 'accepted'::text, 'declined'::text, 'superseded'::text]))"},{"name":"owner_relationship_proposals_supersedes_id_fkey","definition":"FOREIGN KEY (supersedes_id) REFERENCES owner_relationship_proposals(id) ON DELETE SET NULL"},{"name":"owner_relationship_proposals_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"owner_relationship_proposals_version_check","definition":"CHECK (version > 0)"}]},{"table":"owner_tenant_relationships","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"relationship_status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"key_contacts","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"last_meaningful_contact_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_action","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_action_due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"relationship_kind","type":"text","default":"'unclassified'::text","identity":"","not_null":true,"generated":""},{"name":"priority_horizon","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority_lane","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority_rank","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority_value_amount","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority_value_cadence","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority_pinned","type":"boolean","default":"false","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"owner_tenant_relationships_kind_idx","definition":"CREATE INDEX owner_tenant_relationships_kind_idx ON public.owner_tenant_relationships USING btree (relationship_kind, updated_at DESC)"},{"name":"owner_tenant_relationships_pkey","definition":"CREATE UNIQUE INDEX owner_tenant_relationships_pkey ON public.owner_tenant_relationships USING btree (id)"},{"name":"owner_tenant_relationships_priority_idx","definition":"CREATE INDEX owner_tenant_relationships_priority_idx ON public.owner_tenant_relationships USING btree (priority_pinned DESC, priority_horizon, priority_rank) WHERE (priority_horizon IS NOT NULL)"},{"name":"owner_tenant_relationships_tenant_id_key","definition":"CREATE UNIQUE INDEX owner_tenant_relationships_tenant_id_key ON public.owner_tenant_relationships USING btree (tenant_id)"}],"policies":[{"cmd":"DELETE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_tenant_relationships","permissive":"PERMISSIVE","policyname":"owner_tenant_relationships_platform_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"owner_tenant_relationships","permissive":"PERMISSIVE","policyname":"owner_tenant_relationships_platform_insert","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_tenant_relationships","permissive":"PERMISSIVE","policyname":"owner_tenant_relationships_platform_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_platform_admin(uid())","roles":["public"],"tablename":"owner_tenant_relationships","permissive":"PERMISSIVE","policyname":"owner_tenant_relationships_platform_update","schemaname":"public","with_check":"is_platform_admin(uid())"}],"triggers":[{"name":"owner_tenant_relationships_updated_at","definition":"CREATE TRIGGER owner_tenant_relationships_updated_at BEFORE UPDATE ON owner_tenant_relationships FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"owner_tenant_relationships_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"owner_tenant_relationships_pkey","definition":"PRIMARY KEY (id)"},{"name":"owner_tenant_relationships_priority_horizon_check","definition":"CHECK (priority_horizon IS NULL OR (priority_horizon = ANY (ARRAY['now'::text, 'today'::text, 'this_week'::text, 'parked'::text])))"},{"name":"owner_tenant_relationships_priority_lane_check","definition":"CHECK (priority_lane IS NULL OR (priority_lane = ANY (ARRAY['protect'::text, 'close'::text, 'nurture'::text, 'build'::text])))"},{"name":"owner_tenant_relationships_priority_rank_check","definition":"CHECK (priority_rank IS NULL OR priority_rank >= 1)"},{"name":"owner_tenant_relationships_priority_value_amount_check","definition":"CHECK (priority_value_amount IS NULL OR priority_value_amount >= 0::numeric)"},{"name":"owner_tenant_relationships_priority_value_cadence_check","definition":"CHECK (priority_value_cadence IS NULL OR (priority_value_cadence = ANY (ARRAY['one_time'::text, 'weekly'::text, 'monthly'::text, 'annual'::text, 'unknown'::text])))"},{"name":"owner_tenant_relationships_relationship_kind_check","definition":"CHECK (relationship_kind = ANY (ARRAY['unclassified'::text, 'my_business'::text, 'client'::text, 'prospect'::text, 'partner'::text, 'internal_product'::text, 'demo'::text]))"},{"name":"owner_tenant_relationships_relationship_status_check","definition":"CHECK (relationship_status = ANY (ARRAY['prospect'::text, 'active'::text, 'paused'::text, 'closed'::text, 'archived'::text]))"},{"name":"owner_tenant_relationships_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"owner_tenant_relationships_tenant_id_key","definition":"UNIQUE (tenant_id)"}]},{"table":"owner_workspace_notes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"pinned","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"source_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"dismissed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"owner_workspace_notes_pkey","definition":"CREATE UNIQUE INDEX owner_workspace_notes_pkey ON public.owner_workspace_notes USING btree (id)"},{"name":"owner_workspace_notes_source_uidx","definition":"CREATE UNIQUE INDEX owner_workspace_notes_source_uidx ON public.owner_workspace_notes USING btree (tenant_id, source_type, source_id) WHERE ((source_type IS NOT NULL) AND (source_id IS NOT NULL))"},{"name":"owner_workspace_notes_tenant_updated_idx","definition":"CREATE INDEX owner_workspace_notes_tenant_updated_idx ON public.owner_workspace_notes USING btree (tenant_id, pinned DESC, updated_at DESC)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(tenant_id) OR is_system_admin())","roles":["public"],"tablename":"owner_workspace_notes","permissive":"PERMISSIVE","policyname":"owner_workspace_notes_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"owner_workspace_notes","permissive":"PERMISSIVE","policyname":"owner_workspace_notes_insert","schemaname":"public","with_check":"((uid() = user_id) AND (is_tenant_member(tenant_id) OR is_system_admin()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_id) OR is_system_admin())","roles":["public"],"tablename":"owner_workspace_notes","permissive":"PERMISSIVE","policyname":"owner_workspace_notes_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_id) OR is_system_admin())","roles":["public"],"tablename":"owner_workspace_notes","permissive":"PERMISSIVE","policyname":"owner_workspace_notes_update","schemaname":"public","with_check":"(is_tenant_member(tenant_id) OR is_system_admin())"}],"triggers":[],"constraints":[{"name":"owner_workspace_notes_pkey","definition":"PRIMARY KEY (id)"},{"name":"owner_workspace_notes_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"pa_carrier_estimate_items","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"valuation_item_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"item_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"quantity","type":"numeric","default":"1","identity":"","not_null":true,"generated":""},{"name":"unit","type":"text","default":"'EA'::text","identity":"","not_null":true,"generated":""},{"name":"unit_price","type":"numeric","default":"0","identity":"","not_null":true,"generated":""},{"name":"total","type":"numeric","default":"(quantity * unit_price)","identity":"","not_null":false,"generated":"s"},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"evidence_doc_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":"uid()","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_pa_carrier_estimate_items_claim","definition":"CREATE INDEX idx_pa_carrier_estimate_items_claim ON public.pa_carrier_estimate_items USING btree (tenant_org_id, claim_id)"},{"name":"idx_pa_carrier_estimate_items_valuation","definition":"CREATE INDEX idx_pa_carrier_estimate_items_valuation ON public.pa_carrier_estimate_items USING btree (valuation_item_id) WHERE (valuation_item_id IS NOT NULL)"},{"name":"pa_carrier_estimate_items_pkey","definition":"CREATE UNIQUE INDEX pa_carrier_estimate_items_pkey ON public.pa_carrier_estimate_items USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"pa_carrier_estimate_items","permissive":"PERMISSIVE","policyname":"Tenant members can create PA carrier estimate items","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"DELETE","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["public"],"tablename":"pa_carrier_estimate_items","permissive":"PERMISSIVE","policyname":"Tenant members can delete PA carrier estimate items","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["public"],"tablename":"pa_carrier_estimate_items","permissive":"PERMISSIVE","policyname":"Tenant members can update PA carrier estimate items","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["public"],"tablename":"pa_carrier_estimate_items","permissive":"PERMISSIVE","policyname":"Tenant members can view PA carrier estimate items","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pa_carrier_estimate_items_pkey","definition":"PRIMARY KEY (id)"},{"name":"pa_carrier_estimate_items_quantity_check","definition":"CHECK (quantity >= 0::numeric)"},{"name":"pa_carrier_estimate_items_unit_price_check","definition":"CHECK (unit_price >= 0::numeric)"},{"name":"pa_carrier_estimate_items_valuation_item_id_fkey","definition":"FOREIGN KEY (valuation_item_id) REFERENCES claim_valuation_items(id) ON DELETE SET NULL"}]},{"table":"pa_clients","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"client_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"insurance_company","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'Active'::text","identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"pa_clients_client_id_key","definition":"CREATE UNIQUE INDEX pa_clients_client_id_key ON public.pa_clients USING btree (client_id)"},{"name":"pa_clients_pkey","definition":"CREATE UNIQUE INDEX pa_clients_pkey ON public.pa_clients USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = pa_clients.tenant_org_id))))","roles":["public"],"tablename":"pa_clients","permissive":"PERMISSIVE","policyname":"Users view tenant PA clients","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (pa_clients.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_clients","permissive":"PERMISSIVE","policyname":"tenant_users_delete_pa_clients","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pa_clients","permissive":"PERMISSIVE","policyname":"tenant_users_insert_pa_clients","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (pa_clients.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (pa_clients.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_clients","permissive":"PERMISSIVE","policyname":"tenant_users_update_pa_clients","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (pa_clients.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (pa_clients.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_clients","permissive":"PERMISSIVE","policyname":"tenant_users_view_pa_clients","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pa_clients_client_id_key","definition":"UNIQUE (client_id)"},{"name":"pa_clients_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"pa_engagements","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'Not Sent'::text","identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"viewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"declined_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"cancelled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"signer_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signer_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signer_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pa_fee_pct","type":"numeric(5,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"engagement_effective_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"scope_of_representation","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_document_file_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_document_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"rendered_lor_html","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rendered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"rendered_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"signature_provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_envelope_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"envelope_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sent_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_provider_event_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pending_agreement_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_pa_engagements_claim","definition":"CREATE INDEX idx_pa_engagements_claim ON public.pa_engagements USING btree (claim_id)"},{"name":"idx_pa_engagements_contact","definition":"CREATE INDEX idx_pa_engagements_contact ON public.pa_engagements USING btree (contact_id)"},{"name":"idx_pa_engagements_external_envelope","definition":"CREATE INDEX idx_pa_engagements_external_envelope ON public.pa_engagements USING btree (signature_provider, external_envelope_id) WHERE (external_envelope_id IS NOT NULL)"},{"name":"idx_pa_engagements_pending_agreement_id","definition":"CREATE INDEX idx_pa_engagements_pending_agreement_id ON public.pa_engagements USING btree (pending_agreement_id) WHERE (pending_agreement_id IS NOT NULL)"},{"name":"idx_pa_engagements_status","definition":"CREATE INDEX idx_pa_engagements_status ON public.pa_engagements USING btree (tenant_org_id, status)"},{"name":"idx_pa_engagements_template","definition":"CREATE INDEX idx_pa_engagements_template ON public.pa_engagements USING btree (template_id)"},{"name":"idx_pa_engagements_tenant","definition":"CREATE INDEX idx_pa_engagements_tenant ON public.pa_engagements USING btree (tenant_org_id)"},{"name":"idx_pa_engagements_tenant_pending_agreement","definition":"CREATE INDEX idx_pa_engagements_tenant_pending_agreement ON public.pa_engagements USING btree (tenant_org_id, pending_agreement_id) WHERE (pending_agreement_id IS NOT NULL)"},{"name":"pa_engagements_pkey","definition":"CREATE UNIQUE INDEX pa_engagements_pkey ON public.pa_engagements USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_engagements","permissive":"PERMISSIVE","policyname":"pa_engagements_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pa_engagements","permissive":"PERMISSIVE","policyname":"pa_engagements_insert","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_engagements","permissive":"PERMISSIVE","policyname":"pa_engagements_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_engagements","permissive":"PERMISSIVE","policyname":"pa_engagements_update","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))"}],"triggers":[{"name":"trg_pa_engagements_updated_at","definition":"CREATE TRIGGER trg_pa_engagements_updated_at BEFORE UPDATE ON pa_engagements FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"pa_engagements_pkey","definition":"PRIMARY KEY (id)"},{"name":"pa_engagements_status_check","definition":"CHECK (status = ANY (ARRAY['Not Sent'::text, 'Sent'::text, 'Viewed'::text, 'Signed'::text, 'Declined'::text, 'Cancelled'::text]))"}]},{"table":"pa_lor_envelope_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"engagement_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_envelope_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"received_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"processed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"processing_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_pa_lor_env_events_engagement","definition":"CREATE INDEX idx_pa_lor_env_events_engagement ON public.pa_lor_envelope_events USING btree (engagement_id)"},{"name":"idx_pa_lor_env_events_external","definition":"CREATE INDEX idx_pa_lor_env_events_external ON public.pa_lor_envelope_events USING btree (provider, external_envelope_id)"},{"name":"idx_pa_lor_env_events_tenant","definition":"CREATE INDEX idx_pa_lor_env_events_tenant ON public.pa_lor_envelope_events USING btree (tenant_org_id)"},{"name":"pa_lor_envelope_events_pkey","definition":"CREATE UNIQUE INDEX pa_lor_envelope_events_pkey ON public.pa_lor_envelope_events USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_lor_envelope_events","permissive":"PERMISSIVE","policyname":"pa_lor_env_events_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pa_lor_envelope_events","permissive":"PERMISSIVE","policyname":"pa_lor_env_events_insert","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_lor_envelope_events","permissive":"PERMISSIVE","policyname":"pa_lor_env_events_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_lor_envelope_events","permissive":"PERMISSIVE","policyname":"pa_lor_env_events_update","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))"}],"triggers":[],"constraints":[{"name":"pa_lor_envelope_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"pa_lor_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"body_html","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"default_fee_percentage","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_pa_lor_templates_active","definition":"CREATE INDEX idx_pa_lor_templates_active ON public.pa_lor_templates USING btree (tenant_org_id, is_active)"},{"name":"idx_pa_lor_templates_tenant","definition":"CREATE INDEX idx_pa_lor_templates_tenant ON public.pa_lor_templates USING btree (tenant_org_id)"},{"name":"pa_lor_templates_pkey","definition":"CREATE UNIQUE INDEX pa_lor_templates_pkey ON public.pa_lor_templates USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_lor_templates","permissive":"PERMISSIVE","policyname":"pa_lor_templates_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pa_lor_templates","permissive":"PERMISSIVE","policyname":"pa_lor_templates_insert","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_lor_templates","permissive":"PERMISSIVE","policyname":"pa_lor_templates_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pa_lor_templates","permissive":"PERMISSIVE","policyname":"pa_lor_templates_update","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))"}],"triggers":[{"name":"trg_pa_lor_templates_single_default","definition":"CREATE TRIGGER trg_pa_lor_templates_single_default AFTER INSERT OR UPDATE OF is_default ON pa_lor_templates FOR EACH ROW EXECUTE FUNCTION pa_lor_templates_enforce_single_default()"},{"name":"trg_pa_lor_templates_touch","definition":"CREATE TRIGGER trg_pa_lor_templates_touch BEFORE UPDATE ON pa_lor_templates FOR EACH ROW EXECUTE FUNCTION pa_lor_templates_touch()"}],"constraints":[{"name":"pa_lor_templates_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"pa_staff_compliance","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"operational_role","type":"text","default":"'Public Adjuster'::text","identity":"","not_null":true,"generated":""},{"name":"license_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"licensed_states","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"license_expires_on","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"bond_expires_on","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"ce_due_on","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_pa_staff_compliance_tenant","definition":"CREATE INDEX idx_pa_staff_compliance_tenant ON public.pa_staff_compliance USING btree (tenant_id)"},{"name":"idx_pa_staff_compliance_user","definition":"CREATE INDEX idx_pa_staff_compliance_user ON public.pa_staff_compliance USING btree (user_id)"},{"name":"pa_staff_compliance_pkey","definition":"CREATE UNIQUE INDEX pa_staff_compliance_pkey ON public.pa_staff_compliance USING btree (id)"},{"name":"pa_staff_compliance_tenant_id_user_id_key","definition":"CREATE UNIQUE INDEX pa_staff_compliance_tenant_id_user_id_key ON public.pa_staff_compliance USING btree (tenant_id, user_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pa_staff_compliance","permissive":"PERMISSIVE","policyname":"PA staff compliance manager insert","schemaname":"public","with_check":"(has_role(uid(), tenant_id, 'Manager'::app_role) OR has_role(uid(), tenant_id, 'Owner'::app_role) OR has_role(uid(), tenant_id, 'Tenant Owner'::app_role) OR has_role(uid(), tenant_id, 'Admin'::app_role) OR has_role(uid(), tenant_id, 'GodMode'::app_role) OR has_role(uid(), tenant_id, 'PlatformAdmin'::app_role))"},{"cmd":"UPDATE","qual":"(has_role(uid(), tenant_id, 'Manager'::app_role) OR has_role(uid(), tenant_id, 'Owner'::app_role) OR has_role(uid(), tenant_id, 'Tenant Owner'::app_role) OR has_role(uid(), tenant_id, 'Admin'::app_role) OR has_role(uid(), tenant_id, 'GodMode'::app_role) OR has_role(uid(), tenant_id, 'PlatformAdmin'::app_role))","roles":["authenticated"],"tablename":"pa_staff_compliance","permissive":"PERMISSIVE","policyname":"PA staff compliance manager update","schemaname":"public","with_check":"(has_role(uid(), tenant_id, 'Manager'::app_role) OR has_role(uid(), tenant_id, 'Owner'::app_role) OR has_role(uid(), tenant_id, 'Tenant Owner'::app_role) OR has_role(uid(), tenant_id, 'Admin'::app_role) OR has_role(uid(), tenant_id, 'GodMode'::app_role) OR has_role(uid(), tenant_id, 'PlatformAdmin'::app_role))"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["public"],"tablename":"pa_staff_compliance","permissive":"PERMISSIVE","policyname":"PA staff compliance tenant read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pa_staff_compliance_pkey","definition":"PRIMARY KEY (id)"},{"name":"pa_staff_compliance_tenant_id_user_id_key","definition":"UNIQUE (tenant_id, user_id)"}]},{"table":"page_views","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"page_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"page_title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"entered_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"exited_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"referrer_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_page_views_tenant","definition":"CREATE INDEX idx_page_views_tenant ON public.page_views USING btree (tenant_id, entered_at DESC)"},{"name":"idx_page_views_user","definition":"CREATE INDEX idx_page_views_user ON public.page_views USING btree (user_id, entered_at DESC)"},{"name":"idx_page_views_user_tenant_path_entered_at","definition":"CREATE INDEX idx_page_views_user_tenant_path_entered_at ON public.page_views USING btree (user_id, COALESCE(tenant_id, ''::text), page_path, entered_at DESC)"},{"name":"page_views_pkey","definition":"CREATE UNIQUE INDEX page_views_pkey ON public.page_views USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"page_views","permissive":"PERMISSIVE","policyname":"Users can insert own page views","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"page_views","permissive":"PERMISSIVE","policyname":"Users can update own page views","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"SELECT","qual":"((uid() = user_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"page_views","permissive":"PERMISSIVE","policyname":"Users can view own page views","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_dedupe_page_view_insert","definition":"CREATE TRIGGER trg_dedupe_page_view_insert BEFORE INSERT ON page_views FOR EACH ROW EXECUTE FUNCTION dedupe_page_view_insert()"}],"constraints":[{"name":"page_views_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"parcel_datasets","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"jurisdiction_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"drive_file_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage","type":"dataset_stage","default":"'raw'::dataset_stage","identity":"","not_null":true,"generated":""},{"name":"uploaded_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"imported_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_parcel_datasets_created_at","definition":"CREATE INDEX idx_parcel_datasets_created_at ON public.parcel_datasets USING btree (created_at DESC)"},{"name":"idx_parcel_datasets_jurisdiction","definition":"CREATE INDEX idx_parcel_datasets_jurisdiction ON public.parcel_datasets USING btree (jurisdiction_id)"},{"name":"idx_parcel_datasets_stage","definition":"CREATE INDEX idx_parcel_datasets_stage ON public.parcel_datasets USING btree (stage)"},{"name":"idx_parcel_datasets_uploaded_by","definition":"CREATE INDEX idx_parcel_datasets_uploaded_by ON public.parcel_datasets USING btree (uploaded_by)"},{"name":"parcel_datasets_pkey","definition":"CREATE UNIQUE INDEX parcel_datasets_pkey ON public.parcel_datasets USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"parcel_datasets","permissive":"PERMISSIVE","policyname":"Users can view parcel datasets","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"parcel_datasets","permissive":"PERMISSIVE","policyname":"platform_admin_manage_parcel_datasets","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"parcel_datasets_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"paul_attachments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"object_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"original_filename","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"mime_type","type":"text","default":"'application/octet-stream'::text","identity":"","not_null":true,"generated":""},{"name":"size_bytes","type":"bigint","default":"0","identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'binary'::text","identity":"","not_null":true,"generated":""},{"name":"upload_status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"interpretation_status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"interpretation","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"paul_attachments_object_path_key","definition":"CREATE UNIQUE INDEX paul_attachments_object_path_key ON public.paul_attachments USING btree (object_path)"},{"name":"paul_attachments_pkey","definition":"CREATE UNIQUE INDEX paul_attachments_pkey ON public.paul_attachments USING btree (id)"},{"name":"paul_attachments_session_idx","definition":"CREATE INDEX paul_attachments_session_idx ON public.paul_attachments USING btree (user_id, session_id, created_at DESC)"},{"name":"paul_attachments_tenant_idx","definition":"CREATE INDEX paul_attachments_tenant_idx ON public.paul_attachments USING btree (tenant_id, created_at DESC)"},{"name":"paul_attachments_user_created_idx","definition":"CREATE INDEX paul_attachments_user_created_idx ON public.paul_attachments USING btree (user_id, created_at DESC)"}],"policies":[{"cmd":"DELETE","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"paul_attachments","permissive":"PERMISSIVE","policyname":"paul_attachments_owner_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"paul_attachments","permissive":"PERMISSIVE","policyname":"paul_attachments_owner_insert","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"paul_attachments","permissive":"PERMISSIVE","policyname":"paul_attachments_owner_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"paul_attachments","permissive":"PERMISSIVE","policyname":"paul_attachments_owner_update","schemaname":"public","with_check":"(uid() = user_id)"}],"triggers":[],"constraints":[{"name":"paul_attachments_interpretation_status_check","definition":"CHECK (interpretation_status = ANY (ARRAY['pending'::text, 'ready'::text, 'degraded'::text, 'not_requested'::text, 'failed'::text]))"},{"name":"paul_attachments_object_path_key","definition":"UNIQUE (object_path)"},{"name":"paul_attachments_pkey","definition":"PRIMARY KEY (id)"},{"name":"paul_attachments_size_bytes_check","definition":"CHECK (size_bytes >= 0)"},{"name":"paul_attachments_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"paul_attachments_upload_status_check","definition":"CHECK (upload_status = ANY (ARRAY['pending'::text, 'ready'::text, 'failed'::text]))"},{"name":"paul_attachments_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"paul_schedules","schema":"public","columns":[{"name":"id","type":"uuid","default":"extensions.gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"objective","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"cadence","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"interval_minutes","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_run_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"request_contract","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"last_run_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_mission_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"failure_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"paul_schedules_due_idx","definition":"CREATE INDEX paul_schedules_due_idx ON public.paul_schedules USING btree (enabled, next_run_at) WHERE (enabled = true)"},{"name":"paul_schedules_pkey","definition":"CREATE UNIQUE INDEX paul_schedules_pkey ON public.paul_schedules USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"paul_schedules_cadence_check","definition":"CHECK (cadence = ANY (ARRAY['once'::text, 'interval'::text]))"},{"name":"paul_schedules_check","definition":"CHECK (cadence = 'once'::text AND interval_minutes IS NULL OR cadence = 'interval'::text AND interval_minutes IS NOT NULL)"},{"name":"paul_schedules_interval_minutes_check","definition":"CHECK (interval_minutes IS NULL OR interval_minutes >= 1 AND interval_minutes <= 10080)"},{"name":"paul_schedules_name_check","definition":"CHECK (char_length(TRIM(BOTH FROM name)) >= 1 AND char_length(TRIM(BOTH FROM name)) <= 120)"},{"name":"paul_schedules_objective_check","definition":"CHECK (char_length(TRIM(BOTH FROM objective)) >= 1 AND char_length(TRIM(BOTH FROM objective)) <= 4000)"},{"name":"paul_schedules_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"pcg_card_lifecycle_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_card_lifecycle_events_card_idx","definition":"CREATE INDEX pcg_card_lifecycle_events_card_idx ON public.pcg_card_lifecycle_events USING btree (tenant_id, card_id, created_at DESC)"},{"name":"pcg_card_lifecycle_events_pkey","definition":"CREATE UNIQUE INDEX pcg_card_lifecycle_events_pkey ON public.pcg_card_lifecycle_events USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pcg_card_lifecycle_events","permissive":"PERMISSIVE","policyname":"pcg_card_lifecycle_events_tenant_insert","schemaname":"public","with_check":"((actor_user_id = ( SELECT uid() AS uid)) AND (( SELECT is_system_admin(( SELECT uid() AS uid)) AS is_system_admin) OR (tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[])))))"},{"cmd":"SELECT","qual":"(( SELECT is_system_admin(( SELECT uid() AS uid)) AS is_system_admin) OR (tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))))","roles":["authenticated"],"tablename":"pcg_card_lifecycle_events","permissive":"PERMISSIVE","policyname":"pcg_card_lifecycle_events_tenant_select","schemaname":"public","with_check":null}],"triggers":[{"name":"pcg_card_shared_journal","definition":"CREATE TRIGGER pcg_card_shared_journal AFTER INSERT ON pcg_card_lifecycle_events FOR EACH ROW EXECUTE FUNCTION journal_pcg_lifecycle()"}],"constraints":[{"name":"pcg_card_lifecycle_events_action_check","definition":"CHECK (action = ANY (ARRAY['delete'::text, 'restore'::text]))"},{"name":"pcg_card_lifecycle_events_card_id_fkey","definition":"FOREIGN KEY (card_id) REFERENCES card_grading_cards(id) ON DELETE CASCADE"},{"name":"pcg_card_lifecycle_events_message_check","definition":"CHECK (length(TRIM(BOTH FROM message)) > 0)"},{"name":"pcg_card_lifecycle_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_card_lifecycle_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_card_order_links","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"submission_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"link_kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":"uid()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_card_order_links_card_idx","definition":"CREATE INDEX pcg_card_order_links_card_idx ON public.pcg_card_order_links USING btree (tenant_id, card_id, created_at DESC)"},{"name":"pcg_card_order_links_one_identity","definition":"CREATE UNIQUE INDEX pcg_card_order_links_one_identity ON public.pcg_card_order_links USING btree (tenant_id, card_id, submission_id)"},{"name":"pcg_card_order_links_order_idx","definition":"CREATE INDEX pcg_card_order_links_order_idx ON public.pcg_card_order_links USING btree (tenant_id, submission_id, created_at DESC)"},{"name":"pcg_card_order_links_pkey","definition":"CREATE UNIQUE INDEX pcg_card_order_links_pkey ON public.pcg_card_order_links USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pcg_card_order_links","permissive":"PERMISSIVE","policyname":"pcg_card_order_links_member_insert","schemaname":"public","with_check":"((created_by = ( SELECT uid() AS uid)) AND ((tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))) OR ( SELECT is_system_admin(uid()) AS is_system_admin)))"},{"cmd":"SELECT","qual":"((tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))) OR ( SELECT is_system_admin(uid()) AS is_system_admin))","roles":["authenticated"],"tablename":"pcg_card_order_links","permissive":"PERMISSIVE","policyname":"pcg_card_order_links_member_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_card_order_links_card_tenant_fk","definition":"FOREIGN KEY (tenant_id, card_id) REFERENCES card_grading_cards(tenant_id, id) ON DELETE RESTRICT"},{"name":"pcg_card_order_links_link_kind_check","definition":"CHECK (link_kind = ANY (ARRAY['return_service'::text, 'legacy_reconciliation'::text, 'photo_attachment'::text]))"},{"name":"pcg_card_order_links_one_identity","definition":"UNIQUE (tenant_id, card_id, submission_id)"},{"name":"pcg_card_order_links_order_tenant_fk","definition":"FOREIGN KEY (tenant_id, submission_id) REFERENCES card_grading_submissions(tenant_id, id) ON DELETE RESTRICT"},{"name":"pcg_card_order_links_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_card_order_links_reason_check","definition":"CHECK (length(btrim(reason)) > 0)"}]},{"table":"pcg_card_photo_fingerprints","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"side","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"sha256","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":"uid()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_card_photo_fingerprints_lookup_idx","definition":"CREATE INDEX pcg_card_photo_fingerprints_lookup_idx ON public.pcg_card_photo_fingerprints USING btree (tenant_id, sha256, side)"},{"name":"pcg_card_photo_fingerprints_per_card_side_hash","definition":"CREATE UNIQUE INDEX pcg_card_photo_fingerprints_per_card_side_hash ON public.pcg_card_photo_fingerprints USING btree (tenant_id, card_id, side, sha256)"},{"name":"pcg_card_photo_fingerprints_pkey","definition":"CREATE UNIQUE INDEX pcg_card_photo_fingerprints_pkey ON public.pcg_card_photo_fingerprints USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pcg_card_photo_fingerprints","permissive":"PERMISSIVE","policyname":"pcg_card_photo_fingerprints_member_insert","schemaname":"public","with_check":"((created_by = ( SELECT uid() AS uid)) AND ((tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))) OR ( SELECT is_system_admin(uid()) AS is_system_admin)))"},{"cmd":"SELECT","qual":"((tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))) OR ( SELECT is_system_admin(uid()) AS is_system_admin))","roles":["authenticated"],"tablename":"pcg_card_photo_fingerprints","permissive":"PERMISSIVE","policyname":"pcg_card_photo_fingerprints_member_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_card_photo_fingerprints_card_tenant_fk","definition":"FOREIGN KEY (tenant_id, card_id) REFERENCES card_grading_cards(tenant_id, id) ON DELETE RESTRICT"},{"name":"pcg_card_photo_fingerprints_per_card_side_hash","definition":"UNIQUE (tenant_id, card_id, side, sha256)"},{"name":"pcg_card_photo_fingerprints_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_card_photo_fingerprints_sha256_check","definition":"CHECK (sha256 ~ '^[0-9a-f]{64}$'::text)"},{"name":"pcg_card_photo_fingerprints_side_check","definition":"CHECK (side = ANY (ARRAY['front'::text, 'back'::text, 'slab_front'::text, 'slab_back'::text]))"}]},{"table":"pcg_card_publication_revocations","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"cert_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_card_publication_revocations_pkey","definition":"CREATE UNIQUE INDEX pcg_card_publication_revocations_pkey ON public.pcg_card_publication_revocations USING btree (tenant_id, card_id)"},{"name":"pcg_public_revoked_cert_idx","definition":"CREATE INDEX pcg_public_revoked_cert_idx ON public.pcg_card_publication_revocations USING btree (tenant_id, cert_number) WHERE (cert_number IS NOT NULL)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_card_publication_revocations_pkey","definition":"PRIMARY KEY (tenant_id, card_id)"}]},{"table":"pcg_cert_sequences","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"prefix","type":"smallint","default":null,"identity":"","not_null":true,"generated":""},{"name":"next_suffix","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_cert_sequences_pkey","definition":"CREATE UNIQUE INDEX pcg_cert_sequences_pkey ON public.pcg_cert_sequences USING btree (tenant_id, prefix)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_cert_sequences_next_suffix_check","definition":"CHECK (next_suffix >= 1 AND next_suffix <= 10000)"},{"name":"pcg_cert_sequences_pkey","definition":"PRIMARY KEY (tenant_id, prefix)"},{"name":"pcg_cert_sequences_prefix_check","definition":"CHECK (prefix = ANY (ARRAY[7, 8, 9]))"}]},{"table":"pcg_certificate_collision_audit","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"five_card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"eleven_card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"normalized_five_digit","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"eleven_digit","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'needs_review'::text","identity":"","not_null":true,"generated":""},{"name":"detected_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_certificate_collision_audit_pkey","definition":"CREATE UNIQUE INDEX pcg_certificate_collision_audit_pkey ON public.pcg_certificate_collision_audit USING btree (tenant_id, five_card_id, eleven_card_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_certificate_collision_audit_pkey","definition":"PRIMARY KEY (tenant_id, five_card_id, eleven_card_id)"},{"name":"pcg_certificate_collision_audit_status_check","definition":"CHECK (status = ANY (ARRAY['needs_review'::text, 'resolved'::text, 'waived'::text]))"}]},{"table":"pcg_commerce_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"publication_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_commerce_events_pkey","definition":"CREATE UNIQUE INDEX pcg_commerce_events_pkey ON public.pcg_commerce_events USING btree (id)"},{"name":"pcg_commerce_events_tenant_id_source_event_key_key","definition":"CREATE UNIQUE INDEX pcg_commerce_events_tenant_id_source_event_key_key ON public.pcg_commerce_events USING btree (tenant_id, source, event_key)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_commerce_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_commerce_events_publication_id_fkey","definition":"FOREIGN KEY (publication_id) REFERENCES pcg_commerce_publications(id) ON DELETE SET NULL"},{"name":"pcg_commerce_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_commerce_events_tenant_id_source_event_key_key","definition":"UNIQUE (tenant_id, source, event_key)"}]},{"table":"pcg_commerce_publications","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"sku","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"images","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"price","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"quantity","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"website_status","type":"text","default":"'uploaded'::text","identity":"","not_null":true,"generated":""},{"name":"website_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ebay_status","type":"text","default":"'uploaded'::text","identity":"","not_null":true,"generated":""},{"name":"ebay_offer_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ebay_listing_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ebay_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"attempt_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"provider_state","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"withdrawal_requested_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"pcg_commerce_publications_pkey","definition":"CREATE UNIQUE INDEX pcg_commerce_publications_pkey ON public.pcg_commerce_publications USING btree (id)"},{"name":"pcg_commerce_publications_tenant_id_card_id_key","definition":"CREATE UNIQUE INDEX pcg_commerce_publications_tenant_id_card_id_key ON public.pcg_commerce_publications USING btree (tenant_id, card_id)"},{"name":"pcg_commerce_publications_tenant_id_sku_key","definition":"CREATE UNIQUE INDEX pcg_commerce_publications_tenant_id_sku_key ON public.pcg_commerce_publications USING btree (tenant_id, sku)"},{"name":"pcg_commerce_publications_tenant_updated_idx","definition":"CREATE INDEX pcg_commerce_publications_tenant_updated_idx ON public.pcg_commerce_publications USING btree (tenant_id, updated_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM user_tenant_access uta\n  WHERE ((uta.user_id = uid()) AND (uta.tenant_id = pcg_commerce_publications.tenant_id))))","roles":["authenticated"],"tablename":"pcg_commerce_publications","permissive":"PERMISSIVE","policyname":"pcg_commerce_publications_tenant_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_commerce_publications_card_id_fkey","definition":"FOREIGN KEY (card_id) REFERENCES card_grading_cards(id) ON DELETE CASCADE"},{"name":"pcg_commerce_publications_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_commerce_publications_price_check","definition":"CHECK (price >= 0::numeric)"},{"name":"pcg_commerce_publications_quantity_check","definition":"CHECK (quantity >= 0)"},{"name":"pcg_commerce_publications_tenant_id_card_id_key","definition":"UNIQUE (tenant_id, card_id)"},{"name":"pcg_commerce_publications_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_commerce_publications_tenant_id_sku_key","definition":"UNIQUE (tenant_id, sku)"}]},{"table":"pcg_forum_categories","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"slug","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"position","type":"integer","default":"0","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_forum_categories_pkey","definition":"CREATE UNIQUE INDEX pcg_forum_categories_pkey ON public.pcg_forum_categories USING btree (id)"},{"name":"pcg_forum_categories_tenant_id_slug_key","definition":"CREATE UNIQUE INDEX pcg_forum_categories_tenant_id_slug_key ON public.pcg_forum_categories USING btree (tenant_id, slug)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["public"],"tablename":"pcg_forum_categories","permissive":"PERMISSIVE","policyname":"pcg_forum_categories_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_forum_categories_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_forum_categories_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_forum_categories_tenant_id_slug_key","definition":"UNIQUE (tenant_id, slug)"}]},{"table":"pcg_forum_posts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"thread_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"author_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"author_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_forum_posts_pkey","definition":"CREATE UNIQUE INDEX pcg_forum_posts_pkey ON public.pcg_forum_posts USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(deleted_at IS NULL)","roles":["public"],"tablename":"pcg_forum_posts","permissive":"PERMISSIVE","policyname":"pcg_forum_posts_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_forum_posts_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_forum_posts_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_forum_posts_thread_id_fkey","definition":"FOREIGN KEY (thread_id) REFERENCES pcg_forum_threads(id) ON DELETE CASCADE"}]},{"table":"pcg_forum_threads","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"category_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"author_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"author_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"pinned","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"locked","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_forum_threads_pkey","definition":"CREATE UNIQUE INDEX pcg_forum_threads_pkey ON public.pcg_forum_threads USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(deleted_at IS NULL)","roles":["public"],"tablename":"pcg_forum_threads","permissive":"PERMISSIVE","policyname":"pcg_forum_threads_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_forum_threads_category_id_fkey","definition":"FOREIGN KEY (category_id) REFERENCES pcg_forum_categories(id)"},{"name":"pcg_forum_threads_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_forum_threads_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_grade_credit_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"submission_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"quantity","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"recorded_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"detail","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_credit_events_period_idx","definition":"CREATE INDEX pcg_credit_events_period_idx ON public.pcg_grade_credit_events USING btree (tenant_id, period_id, recorded_at)"},{"name":"pcg_grade_credit_events_pkey","definition":"CREATE UNIQUE INDEX pcg_grade_credit_events_pkey ON public.pcg_grade_credit_events USING btree (id)"},{"name":"pcg_grade_credit_events_tenant_id_event_key_key","definition":"CREATE UNIQUE INDEX pcg_grade_credit_events_tenant_id_event_key_key ON public.pcg_grade_credit_events USING btree (tenant_id, event_key)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_grade_credit_events_event_type_check","definition":"CHECK (event_type = ANY (ARRAY['grant'::text, 'reserve'::text, 'consume'::text, 'release'::text, 'expire'::text, 'adjust'::text]))"},{"name":"pcg_grade_credit_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_grade_credit_events_quantity_check","definition":"CHECK (quantity > 0)"},{"name":"pcg_grade_credit_events_submission_tenant_fk","definition":"FOREIGN KEY (submission_id) REFERENCES card_grading_submissions(id)"},{"name":"pcg_grade_credit_events_tenant_id_event_key_key","definition":"UNIQUE (tenant_id, event_key)"},{"name":"pcg_grade_credit_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id)"},{"name":"pcg_grade_credit_events_tenant_id_period_id_fkey","definition":"FOREIGN KEY (tenant_id, period_id) REFERENCES pcg_grade_credit_periods(tenant_id, id)"}]},{"table":"pcg_grade_credit_periods","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"membership_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"starts_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"ends_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"granted","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_grade_credit_periods_pkey","definition":"CREATE UNIQUE INDEX pcg_grade_credit_periods_pkey ON public.pcg_grade_credit_periods USING btree (id)"},{"name":"pcg_grade_credit_periods_tenant_id_id_key","definition":"CREATE UNIQUE INDEX pcg_grade_credit_periods_tenant_id_id_key ON public.pcg_grade_credit_periods USING btree (tenant_id, id)"},{"name":"pcg_grade_credit_periods_tenant_id_membership_id_starts_at_key","definition":"CREATE UNIQUE INDEX pcg_grade_credit_periods_tenant_id_membership_id_starts_at_key ON public.pcg_grade_credit_periods USING btree (tenant_id, membership_id, starts_at)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_grade_credit_periods_check","definition":"CHECK (ends_at > starts_at)"},{"name":"pcg_grade_credit_periods_granted_check","definition":"CHECK (granted >= 0)"},{"name":"pcg_grade_credit_periods_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_grade_credit_periods_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id)"},{"name":"pcg_grade_credit_periods_tenant_id_id_key","definition":"UNIQUE (tenant_id, id)"},{"name":"pcg_grade_credit_periods_tenant_id_membership_id_fkey","definition":"FOREIGN KEY (tenant_id, membership_id) REFERENCES pcg_seller_memberships(tenant_id, id)"},{"name":"pcg_grade_credit_periods_tenant_id_membership_id_starts_at_key","definition":"UNIQUE (tenant_id, membership_id, starts_at)"}]},{"table":"pcg_grader_cert_prefixes","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"prefix","type":"smallint","default":null,"identity":"","not_null":true,"generated":""},{"name":"grader_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_grader_cert_prefixes_pkey","definition":"CREATE UNIQUE INDEX pcg_grader_cert_prefixes_pkey ON public.pcg_grader_cert_prefixes USING btree (tenant_id, user_id)"},{"name":"pcg_grader_cert_prefixes_tenant_id_prefix_key","definition":"CREATE UNIQUE INDEX pcg_grader_cert_prefixes_tenant_id_prefix_key ON public.pcg_grader_cert_prefixes USING btree (tenant_id, prefix)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_grader_cert_prefixes_pkey","definition":"PRIMARY KEY (tenant_id, user_id)"},{"name":"pcg_grader_cert_prefixes_prefix_check","definition":"CHECK (prefix = ANY (ARRAY[7, 8, 9]))"},{"name":"pcg_grader_cert_prefixes_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_grader_cert_prefixes_tenant_id_prefix_key","definition":"UNIQUE (tenant_id, prefix)"},{"name":"pcg_grader_cert_prefixes_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"pcg_growth_tasks","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"opportunity_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"task_type","type":"text","default":"'follow_up'::text","identity":"","not_null":true,"generated":""},{"name":"due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'open'::text","identity":"","not_null":true,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"draft_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"approval_required","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"is_demo","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_pcg_growth_tasks_opportunity","definition":"CREATE INDEX idx_pcg_growth_tasks_opportunity ON public.pcg_growth_tasks USING btree (opportunity_id)"},{"name":"idx_pcg_growth_tasks_tenant_status_due","definition":"CREATE INDEX idx_pcg_growth_tasks_tenant_status_due ON public.pcg_growth_tasks USING btree (tenant_id, status, due_at)"},{"name":"pcg_growth_tasks_pkey","definition":"CREATE UNIQUE INDEX pcg_growth_tasks_pkey ON public.pcg_growth_tasks USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin(uid()))","roles":["public"],"tablename":"pcg_growth_tasks","permissive":"PERMISSIVE","policyname":"pcg_growth_tasks_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"pcg_growth_tasks","permissive":"PERMISSIVE","policyname":"pcg_growth_tasks_insert","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin(uid()))","roles":["public"],"tablename":"pcg_growth_tasks","permissive":"PERMISSIVE","policyname":"pcg_growth_tasks_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin(uid()))","roles":["public"],"tablename":"pcg_growth_tasks","permissive":"PERMISSIVE","policyname":"pcg_growth_tasks_update","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_id) OR is_system_admin(uid()))"}],"triggers":[],"constraints":[{"name":"pcg_growth_tasks_opportunity_id_fkey","definition":"FOREIGN KEY (opportunity_id) REFERENCES opportunity_radar_opportunities(id) ON DELETE CASCADE"},{"name":"pcg_growth_tasks_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_growth_tasks_status_check","definition":"CHECK (status = ANY (ARRAY['open'::text, 'completed'::text, 'dismissed'::text]))"},{"name":"pcg_growth_tasks_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_import_batches","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"dry_run","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"total_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"valid_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"duplicate_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"imported_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"review_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"error_rows","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"source_fingerprint","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mapping","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"summary","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":"uid()","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_pcg_import_batches_source_fingerprint","definition":"CREATE INDEX idx_pcg_import_batches_source_fingerprint ON public.pcg_import_batches USING btree (tenant_id, source_fingerprint) WHERE (source_fingerprint IS NOT NULL)"},{"name":"idx_pcg_import_batches_tenant_created","definition":"CREATE INDEX idx_pcg_import_batches_tenant_created ON public.pcg_import_batches USING btree (tenant_id, created_at DESC)"},{"name":"idx_pcg_import_batches_tenant_status","definition":"CREATE INDEX idx_pcg_import_batches_tenant_status ON public.pcg_import_batches USING btree (tenant_id, status)"},{"name":"pcg_import_batches_pkey","definition":"CREATE UNIQUE INDEX pcg_import_batches_pkey ON public.pcg_import_batches USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = pcg_import_batches.tenant_id)))))","roles":["public"],"tablename":"pcg_import_batches","permissive":"PERMISSIVE","policyname":"pcg_import_batches_tenant_all","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = pcg_import_batches.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"pcg_import_batches_duplicate_rows_check","definition":"CHECK (duplicate_rows >= 0)"},{"name":"pcg_import_batches_error_rows_check","definition":"CHECK (error_rows >= 0)"},{"name":"pcg_import_batches_imported_rows_check","definition":"CHECK (imported_rows >= 0)"},{"name":"pcg_import_batches_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_import_batches_review_rows_check","definition":"CHECK (review_rows >= 0)"},{"name":"pcg_import_batches_source_type_check","definition":"CHECK (source_type = ANY (ARRAY['csv'::text, 'website'::text, 'google_drive'::text, 'manual'::text]))"},{"name":"pcg_import_batches_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'analyzing'::text, 'ready'::text, 'importing'::text, 'completed'::text, 'completed_with_errors'::text, 'failed'::text, 'cancelled'::text]))"},{"name":"pcg_import_batches_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_import_batches_total_rows_check","definition":"CHECK (total_rows >= 0)"},{"name":"pcg_import_batches_valid_rows_check","definition":"CHECK (valid_rows >= 0)"}]},{"table":"pcg_import_rows","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"batch_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"row_number","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"external_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"import_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"normalized_payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"validation_status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"planned_action","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"canonical_submission_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"canonical_card_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_pcg_import_rows_batch_status","definition":"CREATE INDEX idx_pcg_import_rows_batch_status ON public.pcg_import_rows USING btree (batch_id, validation_status, row_number)"},{"name":"idx_pcg_import_rows_tenant_external_key","definition":"CREATE INDEX idx_pcg_import_rows_tenant_external_key ON public.pcg_import_rows USING btree (tenant_id, external_key) WHERE (external_key IS NOT NULL)"},{"name":"idx_pcg_import_rows_tenant_import_key","definition":"CREATE INDEX idx_pcg_import_rows_tenant_import_key ON public.pcg_import_rows USING btree (tenant_id, import_key)"},{"name":"pcg_import_rows_batch_id_row_number_key","definition":"CREATE UNIQUE INDEX pcg_import_rows_batch_id_row_number_key ON public.pcg_import_rows USING btree (batch_id, row_number)"},{"name":"pcg_import_rows_pkey","definition":"CREATE UNIQUE INDEX pcg_import_rows_pkey ON public.pcg_import_rows USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = pcg_import_rows.tenant_id)))))","roles":["public"],"tablename":"pcg_import_rows","permissive":"PERMISSIVE","policyname":"pcg_import_rows_tenant_all","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = pcg_import_rows.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"pcg_import_rows_batch_id_fkey","definition":"FOREIGN KEY (batch_id) REFERENCES pcg_import_batches(id) ON DELETE CASCADE"},{"name":"pcg_import_rows_batch_id_row_number_key","definition":"UNIQUE (batch_id, row_number)"},{"name":"pcg_import_rows_canonical_card_id_fkey","definition":"FOREIGN KEY (canonical_card_id) REFERENCES card_grading_cards(id) ON DELETE SET NULL"},{"name":"pcg_import_rows_canonical_submission_id_fkey","definition":"FOREIGN KEY (canonical_submission_id) REFERENCES card_grading_submissions(id) ON DELETE SET NULL"},{"name":"pcg_import_rows_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_import_rows_planned_action_check","definition":"CHECK (planned_action = ANY (ARRAY['pending'::text, 'create'::text, 'update'::text, 'skip_duplicate'::text, 'review'::text]))"},{"name":"pcg_import_rows_row_number_check","definition":"CHECK (row_number > 0)"},{"name":"pcg_import_rows_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_import_rows_validation_status_check","definition":"CHECK (validation_status = ANY (ARRAY['pending'::text, 'valid'::text, 'duplicate'::text, 'review'::text, 'error'::text]))"}]},{"table":"pcg_legacy_media_migration_jobs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"token_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"processed_cards","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"migrated_objects","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"failed_objects","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":"(now() + '24:00:00'::interval)","identity":"","not_null":true,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"dispatch_token","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"pcg_legacy_media_migration_jobs_pkey","definition":"CREATE UNIQUE INDEX pcg_legacy_media_migration_jobs_pkey ON public.pcg_legacy_media_migration_jobs USING btree (id)"},{"name":"pcg_legacy_media_migration_jobs_tenant_status_idx","definition":"CREATE INDEX pcg_legacy_media_migration_jobs_tenant_status_idx ON public.pcg_legacy_media_migration_jobs USING btree (tenant_id, status, created_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_legacy_media_migration_jobs_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_legacy_media_migration_jobs_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'running'::text, 'complete'::text, 'failed'::text, 'cancelled'::text]))"},{"name":"pcg_legacy_media_migration_jobs_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_live_chat","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"room_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"auth_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_live_chat_pkey","definition":"CREATE UNIQUE INDEX pcg_live_chat_pkey ON public.pcg_live_chat USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["public"],"tablename":"pcg_live_chat","permissive":"PERMISSIVE","policyname":"pcg_live_chat_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_live_chat_message_check","definition":"CHECK (char_length(message) >= 1 AND char_length(message) <= 500)"},{"name":"pcg_live_chat_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_live_chat_room_id_fkey","definition":"FOREIGN KEY (room_id) REFERENCES pcg_live_rooms(id) ON DELETE CASCADE"},{"name":"pcg_live_chat_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_live_lots","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"room_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"listing_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"position","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_live_lots_pkey","definition":"CREATE UNIQUE INDEX pcg_live_lots_pkey ON public.pcg_live_lots USING btree (id)"},{"name":"pcg_live_lots_room_id_listing_id_key","definition":"CREATE UNIQUE INDEX pcg_live_lots_room_id_listing_id_key ON public.pcg_live_lots USING btree (room_id, listing_id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["public"],"tablename":"pcg_live_lots","permissive":"PERMISSIVE","policyname":"pcg_live_lots_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_live_lots_listing_id_fkey","definition":"FOREIGN KEY (listing_id) REFERENCES pcg_marketplace_listings(id) ON DELETE CASCADE"},{"name":"pcg_live_lots_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_live_lots_room_id_fkey","definition":"FOREIGN KEY (room_id) REFERENCES pcg_live_rooms(id) ON DELETE CASCADE"},{"name":"pcg_live_lots_room_id_listing_id_key","definition":"UNIQUE (room_id, listing_id)"},{"name":"pcg_live_lots_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_live_rooms","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"seller_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'scheduled'::text","identity":"","not_null":true,"generated":""},{"name":"scheduled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"video_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_live_rooms_pkey","definition":"CREATE UNIQUE INDEX pcg_live_rooms_pkey ON public.pcg_live_rooms USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(status = ANY (ARRAY['scheduled'::text, 'live'::text, 'ended'::text]))","roles":["public"],"tablename":"pcg_live_rooms","permissive":"PERMISSIVE","policyname":"pcg_live_rooms_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_live_rooms_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_live_rooms_seller_id_fkey","definition":"FOREIGN KEY (seller_id) REFERENCES pcg_marketplace_sellers(id)"},{"name":"pcg_live_rooms_status_check","definition":"CHECK (status = ANY (ARRAY['scheduled'::text, 'live'::text, 'ended'::text, 'cancelled'::text]))"},{"name":"pcg_live_rooms_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_marketplace_bids","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"listing_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"bidder_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"amount","type":"numeric(12,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"idempotency_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_marketplace_bids_pkey","definition":"CREATE UNIQUE INDEX pcg_marketplace_bids_pkey ON public.pcg_marketplace_bids USING btree (id)"},{"name":"pcg_marketplace_bids_tenant_id_bidder_user_id_idempotency_k_key","definition":"CREATE UNIQUE INDEX pcg_marketplace_bids_tenant_id_bidder_user_id_idempotency_k_key ON public.pcg_marketplace_bids USING btree (tenant_id, bidder_user_id, idempotency_key)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_marketplace_bids_amount_check","definition":"CHECK (amount > 0::numeric)"},{"name":"pcg_marketplace_bids_listing_id_fkey","definition":"FOREIGN KEY (listing_id) REFERENCES pcg_marketplace_listings(id) ON DELETE CASCADE"},{"name":"pcg_marketplace_bids_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_marketplace_bids_tenant_id_bidder_user_id_idempotency_k_key","definition":"UNIQUE (tenant_id, bidder_user_id, idempotency_key)"},{"name":"pcg_marketplace_bids_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_marketplace_listings","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"seller_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"listing_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"price","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"starting_bid","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_bid","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"min_increment","type":"numeric(12,2)","default":"1","identity":"","not_null":true,"generated":""},{"name":"accepts_offers","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"shipping_price","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"auction_ends_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"sold_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"publication_revoked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"pcg_marketplace_listings_pkey","definition":"CREATE UNIQUE INDEX pcg_marketplace_listings_pkey ON public.pcg_marketplace_listings USING btree (id)"},{"name":"pcg_marketplace_revocation_lookup_idx","definition":"CREATE INDEX pcg_marketplace_revocation_lookup_idx ON public.pcg_marketplace_listings USING btree (tenant_id, card_id, publication_revoked_at)"}],"policies":[{"cmd":"SELECT","qual":"((status = ANY (ARRAY['active'::text, 'sold'::text, 'ended'::text])) AND (publication_revoked_at IS NULL))","roles":["public"],"tablename":"pcg_marketplace_listings","permissive":"PERMISSIVE","policyname":"pcg_marketplace_listings_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_marketplace_listings_card_id_fkey","definition":"FOREIGN KEY (card_id) REFERENCES card_grading_cards(id) ON DELETE RESTRICT"},{"name":"pcg_marketplace_listings_listing_type_check","definition":"CHECK (listing_type = ANY (ARRAY['fixed_price'::text, 'auction'::text, 'accept_offers'::text]))"},{"name":"pcg_marketplace_listings_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_marketplace_listings_seller_id_fkey","definition":"FOREIGN KEY (seller_id) REFERENCES pcg_marketplace_sellers(id) ON DELETE CASCADE"},{"name":"pcg_marketplace_listings_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'scheduled'::text, 'active'::text, 'sold'::text, 'ended'::text, 'cancelled'::text]))"},{"name":"pcg_marketplace_listings_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_marketplace_offers","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"listing_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"buyer_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"amount","type":"numeric(12,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"idempotency_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_marketplace_offers_pkey","definition":"CREATE UNIQUE INDEX pcg_marketplace_offers_pkey ON public.pcg_marketplace_offers USING btree (id)"},{"name":"pcg_marketplace_offers_tenant_id_buyer_user_id_idempotency__key","definition":"CREATE UNIQUE INDEX pcg_marketplace_offers_tenant_id_buyer_user_id_idempotency__key ON public.pcg_marketplace_offers USING btree (tenant_id, buyer_user_id, idempotency_key)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_marketplace_offers_amount_check","definition":"CHECK (amount > 0::numeric)"},{"name":"pcg_marketplace_offers_listing_id_fkey","definition":"FOREIGN KEY (listing_id) REFERENCES pcg_marketplace_listings(id) ON DELETE CASCADE"},{"name":"pcg_marketplace_offers_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_marketplace_offers_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'accepted'::text, 'declined'::text, 'countered'::text, 'expired'::text, 'withdrawn'::text]))"},{"name":"pcg_marketplace_offers_tenant_id_buyer_user_id_idempotency__key","definition":"UNIQUE (tenant_id, buyer_user_id, idempotency_key)"},{"name":"pcg_marketplace_offers_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_marketplace_orders","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"listing_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"seller_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"buyer_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"subtotal","type":"numeric(12,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"shipping","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"total","type":"numeric(12,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'payment_prerequisite_required'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_marketplace_orders_one_pending_request","definition":"CREATE UNIQUE INDEX pcg_marketplace_orders_one_pending_request ON public.pcg_marketplace_orders USING btree (tenant_id, listing_id, buyer_user_id) WHERE (status = 'payment_prerequisite_required'::text)"},{"name":"pcg_marketplace_orders_pkey","definition":"CREATE UNIQUE INDEX pcg_marketplace_orders_pkey ON public.pcg_marketplace_orders USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_marketplace_orders_listing_id_fkey","definition":"FOREIGN KEY (listing_id) REFERENCES pcg_marketplace_listings(id)"},{"name":"pcg_marketplace_orders_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_marketplace_orders_seller_id_fkey","definition":"FOREIGN KEY (seller_id) REFERENCES pcg_marketplace_sellers(id)"},{"name":"pcg_marketplace_orders_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_marketplace_sellers","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"auth_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"bio","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"avatar_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_marketplace_sellers_pkey","definition":"CREATE UNIQUE INDEX pcg_marketplace_sellers_pkey ON public.pcg_marketplace_sellers USING btree (id)"},{"name":"pcg_marketplace_sellers_tenant_id_auth_user_id_key","definition":"CREATE UNIQUE INDEX pcg_marketplace_sellers_tenant_id_auth_user_id_key ON public.pcg_marketplace_sellers USING btree (tenant_id, auth_user_id)"},{"name":"pcg_marketplace_sellers_tenant_id_id_key","definition":"CREATE UNIQUE INDEX pcg_marketplace_sellers_tenant_id_id_key ON public.pcg_marketplace_sellers USING btree (tenant_id, id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["public"],"tablename":"pcg_marketplace_sellers","permissive":"PERMISSIVE","policyname":"pcg_marketplace_sellers_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_marketplace_sellers_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"pcg_marketplace_sellers_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_marketplace_sellers_tenant_id_auth_user_id_key","definition":"UNIQUE (tenant_id, auth_user_id)"},{"name":"pcg_marketplace_sellers_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_marketplace_sellers_tenant_id_id_key","definition":"UNIQUE (tenant_id, id)"}]},{"table":"pcg_marketplace_watchlist","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"listing_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"auth_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_marketplace_watchlist_pkey","definition":"CREATE UNIQUE INDEX pcg_marketplace_watchlist_pkey ON public.pcg_marketplace_watchlist USING btree (listing_id, auth_user_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_marketplace_watchlist_listing_id_fkey","definition":"FOREIGN KEY (listing_id) REFERENCES pcg_marketplace_listings(id) ON DELETE CASCADE"},{"name":"pcg_marketplace_watchlist_pkey","definition":"PRIMARY KEY (listing_id, auth_user_id)"},{"name":"pcg_marketplace_watchlist_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_reconciliation_decisions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"submission_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"card_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"evidence","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"actor_user_id","type":"uuid","default":"uid()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_reconciliation_decisions_latest_idx","definition":"CREATE INDEX pcg_reconciliation_decisions_latest_idx ON public.pcg_reconciliation_decisions USING btree (tenant_id, created_at DESC)"},{"name":"pcg_reconciliation_decisions_pkey","definition":"CREATE UNIQUE INDEX pcg_reconciliation_decisions_pkey ON public.pcg_reconciliation_decisions USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pcg_reconciliation_decisions","permissive":"PERMISSIVE","policyname":"pcg_reconciliation_decisions_member_insert","schemaname":"public","with_check":"((actor_user_id = ( SELECT uid() AS uid)) AND ((tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))) OR ( SELECT is_system_admin(uid()) AS is_system_admin)))"},{"cmd":"SELECT","qual":"((tenant_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))) OR ( SELECT is_system_admin(uid()) AS is_system_admin))","roles":["authenticated"],"tablename":"pcg_reconciliation_decisions","permissive":"PERMISSIVE","policyname":"pcg_reconciliation_decisions_member_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_reconciliation_decisions_action_check","definition":"CHECK (action = ANY (ARRAY['open_existing'::text, 'link_existing'::text, 'attach_photos'::text, 'skip_duplicate'::text, 'create_separate'::text, 'possible_match'::text]))"},{"name":"pcg_reconciliation_decisions_card_tenant_fk","definition":"FOREIGN KEY (tenant_id, card_id) REFERENCES card_grading_cards(tenant_id, id) ON DELETE RESTRICT"},{"name":"pcg_reconciliation_decisions_order_tenant_fk","definition":"FOREIGN KEY (tenant_id, submission_id) REFERENCES card_grading_submissions(tenant_id, id) ON DELETE RESTRICT"},{"name":"pcg_reconciliation_decisions_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_reconciliation_decisions_reason_check","definition":"CHECK (length(btrim(reason)) > 0)"},{"name":"pcg_reconciliation_decisions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id)"}]},{"table":"pcg_seller_billing_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"membership_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_event_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"received_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"processed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"pcg_billing_membership_idx","definition":"CREATE INDEX pcg_billing_membership_idx ON public.pcg_seller_billing_events USING btree (tenant_id, membership_id, received_at)"},{"name":"pcg_seller_billing_events_pkey","definition":"CREATE UNIQUE INDEX pcg_seller_billing_events_pkey ON public.pcg_seller_billing_events USING btree (id)"},{"name":"pcg_seller_billing_events_provider_provider_event_id_key","definition":"CREATE UNIQUE INDEX pcg_seller_billing_events_provider_provider_event_id_key ON public.pcg_seller_billing_events USING btree (provider, provider_event_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_seller_billing_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_seller_billing_events_provider_provider_event_id_key","definition":"UNIQUE (provider, provider_event_id)"},{"name":"pcg_seller_billing_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id)"},{"name":"pcg_seller_billing_events_tenant_id_membership_id_fkey","definition":"FOREIGN KEY (tenant_id, membership_id) REFERENCES pcg_seller_memberships(tenant_id, id)"}]},{"table":"pcg_seller_memberships","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"seller_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"plan_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"billing_provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_subscription_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"period_start","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"period_end","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"cancel_at_period_end","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"provider_customer_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_paid_invoice_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_checkout_session_id","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"pcg_seller_memberships_billing_provider_provider_subscripti_key","definition":"CREATE UNIQUE INDEX pcg_seller_memberships_billing_provider_provider_subscripti_key ON public.pcg_seller_memberships USING btree (billing_provider, provider_subscription_id)"},{"name":"pcg_seller_memberships_pkey","definition":"CREATE UNIQUE INDEX pcg_seller_memberships_pkey ON public.pcg_seller_memberships USING btree (id)"},{"name":"pcg_seller_memberships_provider_checkout_ux","definition":"CREATE UNIQUE INDEX pcg_seller_memberships_provider_checkout_ux ON public.pcg_seller_memberships USING btree (provider_checkout_session_id) WHERE (provider_checkout_session_id IS NOT NULL)"},{"name":"pcg_seller_memberships_provider_customer_idx","definition":"CREATE INDEX pcg_seller_memberships_provider_customer_idx ON public.pcg_seller_memberships USING btree (billing_provider, provider_customer_id) WHERE (provider_customer_id IS NOT NULL)"},{"name":"pcg_seller_memberships_tenant_id_id_key","definition":"CREATE UNIQUE INDEX pcg_seller_memberships_tenant_id_id_key ON public.pcg_seller_memberships USING btree (tenant_id, id)"},{"name":"pcg_seller_memberships_tenant_id_seller_id_key","definition":"CREATE UNIQUE INDEX pcg_seller_memberships_tenant_id_seller_id_key ON public.pcg_seller_memberships USING btree (tenant_id, seller_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_seller_memberships_billing_provider_provider_subscripti_key","definition":"UNIQUE (billing_provider, provider_subscription_id)"},{"name":"pcg_seller_memberships_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_seller_memberships_seller_tenant_fk","definition":"FOREIGN KEY (tenant_id, seller_id) REFERENCES pcg_marketplace_sellers(tenant_id, id)"},{"name":"pcg_seller_memberships_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'active'::text, 'past_due'::text, 'cancelled'::text, 'expired'::text, 'paused'::text]))"},{"name":"pcg_seller_memberships_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id)"},{"name":"pcg_seller_memberships_tenant_id_id_key","definition":"UNIQUE (tenant_id, id)"},{"name":"pcg_seller_memberships_tenant_id_plan_id_fkey","definition":"FOREIGN KEY (tenant_id, plan_id) REFERENCES pcg_seller_plans(tenant_id, id)"},{"name":"pcg_seller_memberships_tenant_id_seller_id_key","definition":"UNIQUE (tenant_id, seller_id)"}]},{"table":"pcg_seller_plans","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"monthly_price_cents","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"commission_bps","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"grades_per_period","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"max_active_listings","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"active","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"stripe_price_id","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"pcg_seller_plans_pkey","definition":"CREATE UNIQUE INDEX pcg_seller_plans_pkey ON public.pcg_seller_plans USING btree (id)"},{"name":"pcg_seller_plans_tenant_id_code_key","definition":"CREATE UNIQUE INDEX pcg_seller_plans_tenant_id_code_key ON public.pcg_seller_plans USING btree (tenant_id, code)"},{"name":"pcg_seller_plans_tenant_id_id_key","definition":"CREATE UNIQUE INDEX pcg_seller_plans_tenant_id_id_key ON public.pcg_seller_plans USING btree (tenant_id, id)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_seller_plans_commission_bps_check","definition":"CHECK (commission_bps >= 0 AND commission_bps <= 10000)"},{"name":"pcg_seller_plans_grades_per_period_check","definition":"CHECK (grades_per_period >= 0)"},{"name":"pcg_seller_plans_max_active_listings_check","definition":"CHECK (max_active_listings > 0)"},{"name":"pcg_seller_plans_monthly_price_cents_check","definition":"CHECK (monthly_price_cents >= 0)"},{"name":"pcg_seller_plans_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_seller_plans_tenant_id_code_key","definition":"UNIQUE (tenant_id, code)"},{"name":"pcg_seller_plans_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id)"},{"name":"pcg_seller_plans_tenant_id_id_key","definition":"UNIQUE (tenant_id, id)"}]},{"table":"pcg_submission_lifecycle_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"submission_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"prior_lifecycle_state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"prior_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_submission_lifecycle_events_pkey","definition":"CREATE UNIQUE INDEX pcg_submission_lifecycle_events_pkey ON public.pcg_submission_lifecycle_events USING btree (id)"},{"name":"pcg_submission_lifecycle_events_submission_idx","definition":"CREATE INDEX pcg_submission_lifecycle_events_submission_idx ON public.pcg_submission_lifecycle_events USING btree (tenant_id, submission_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (tenant_id = ANY (COALESCE(current_user_tenant_ids(), ARRAY[]::uuid[]))))","roles":["authenticated"],"tablename":"pcg_submission_lifecycle_events","permissive":"PERMISSIVE","policyname":"pcg_submission_lifecycle_events_tenant_select","schemaname":"public","with_check":null}],"triggers":[{"name":"pcg_submission_shared_journal","definition":"CREATE TRIGGER pcg_submission_shared_journal AFTER INSERT ON pcg_submission_lifecycle_events FOR EACH ROW EXECUTE FUNCTION journal_pcg_lifecycle()"}],"constraints":[{"name":"pcg_submission_lifecycle_events_action_check","definition":"CHECK (action = ANY (ARRAY['hold'::text, 'resume'::text, 'cancel'::text, 'reopen'::text, 'archive'::text, 'restore'::text]))"},{"name":"pcg_submission_lifecycle_events_actor_user_id_fkey","definition":"FOREIGN KEY (actor_user_id) REFERENCES users(id)"},{"name":"pcg_submission_lifecycle_events_message_check","definition":"CHECK (length(btrim(message)) > 0)"},{"name":"pcg_submission_lifecycle_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_submission_lifecycle_events_submission_id_fkey","definition":"FOREIGN KEY (submission_id) REFERENCES card_grading_submissions(id) ON DELETE CASCADE"},{"name":"pcg_submission_lifecycle_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pcg_website_media_migration_jobs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"token_sha256","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"allowed_actions","type":"text[]","default":null,"identity":"","not_null":true,"generated":""},{"name":"allowed_filenames","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"pcg_website_media_migration_jobs_pkey","definition":"CREATE UNIQUE INDEX pcg_website_media_migration_jobs_pkey ON public.pcg_website_media_migration_jobs USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"pcg_website_media_migration_jobs_allowed_actions_check","definition":"CHECK (allowed_actions <@ ARRAY['website-bootstrap'::text, 'website-migrate'::text, 'website-upload'::text, 'website-library'::text])"},{"name":"pcg_website_media_migration_jobs_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_website_media_migration_jobs_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'completed'::text, 'revoked'::text]))"},{"name":"pcg_website_media_migration_jobs_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id)"},{"name":"pcg_website_media_migration_jobs_token_sha256_check","definition":"CHECK (token_sha256 ~ '^[0-9a-f]{64}$'::text)"}]},{"table":"pcg_wholesale_activity","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"partner_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":"uid()","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_wholesale_activity_pkey","definition":"CREATE UNIQUE INDEX pcg_wholesale_activity_pkey ON public.pcg_wholesale_activity USING btree (id)"},{"name":"pcg_wholesale_activity_tenant_idx","definition":"CREATE INDEX pcg_wholesale_activity_tenant_idx ON public.pcg_wholesale_activity USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pcg_wholesale_activity","permissive":"PERMISSIVE","policyname":"pcg_wholesale_activity_insert","schemaname":"public","with_check":"((uid() IS NOT NULL) AND (created_by = ( SELECT uid() AS uid)) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))"},{"cmd":"SELECT","qual":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))","roles":["authenticated"],"tablename":"pcg_wholesale_activity","permissive":"PERMISSIVE","policyname":"pcg_wholesale_activity_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pcg_wholesale_activity_event_type_check","definition":"CHECK (event_type = ANY (ARRAY['created'::text, 'status_change'::text, 'follow_up'::text, 'note'::text, 'evidence'::text, 'profile'::text]))"},{"name":"pcg_wholesale_activity_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_wholesale_activity_summary_check","definition":"CHECK (char_length(btrim(summary)) >= 2 AND char_length(btrim(summary)) <= 2000)"},{"name":"pcg_wholesale_activity_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_wholesale_activity_tenant_id_partner_id_fkey","definition":"FOREIGN KEY (tenant_id, partner_id) REFERENCES pcg_wholesale_partners(tenant_id, id) ON DELETE RESTRICT"}]},{"table":"pcg_wholesale_documents","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"partner_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"asset_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"document_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"note","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"reviewed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"include_in_dossier","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":"uid()","identity":"","not_null":false,"generated":""},{"name":"reviewed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_wholesale_documents_pkey","definition":"CREATE UNIQUE INDEX pcg_wholesale_documents_pkey ON public.pcg_wholesale_documents USING btree (id)"},{"name":"pcg_wholesale_documents_tenant_id_asset_id_key","definition":"CREATE UNIQUE INDEX pcg_wholesale_documents_tenant_id_asset_id_key ON public.pcg_wholesale_documents USING btree (tenant_id, asset_id)"},{"name":"pcg_wholesale_documents_tenant_idx","definition":"CREATE INDEX pcg_wholesale_documents_tenant_idx ON public.pcg_wholesale_documents USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pcg_wholesale_documents","permissive":"PERMISSIVE","policyname":"pcg_wholesale_documents_insert","schemaname":"public","with_check":"((uid() IS NOT NULL) AND (created_by = ( SELECT uid() AS uid)) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))"},{"cmd":"SELECT","qual":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))","roles":["authenticated"],"tablename":"pcg_wholesale_documents","permissive":"PERMISSIVE","policyname":"pcg_wholesale_documents_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))","roles":["authenticated"],"tablename":"pcg_wholesale_documents","permissive":"PERMISSIVE","policyname":"pcg_wholesale_documents_update","schemaname":"public","with_check":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))"}],"triggers":[{"name":"pcg_wholesale_evidence_guard","definition":"CREATE TRIGGER pcg_wholesale_evidence_guard BEFORE INSERT OR UPDATE ON pcg_wholesale_documents FOR EACH ROW EXECUTE FUNCTION pcg_wholesale_guard_evidence()"}],"constraints":[{"name":"pcg_wholesale_document_shared_only_if_reviewed","definition":"CHECK (NOT include_in_dossier OR reviewed)"},{"name":"pcg_wholesale_documents_asset_id_fkey","definition":"FOREIGN KEY (asset_id) REFERENCES tenant_media_assets(id)"},{"name":"pcg_wholesale_documents_document_type_check","definition":"CHECK (document_type = ANY (ARRAY['resale_certificate'::text, 'business_registration'::text, 'storefront'::text, 'purchase_invoice'::text, 'retail_sales_report'::text, 'trade_reference'::text, 'application_receipt'::text, 'other'::text]))"},{"name":"pcg_wholesale_documents_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_wholesale_documents_tenant_id_asset_id_key","definition":"UNIQUE (tenant_id, asset_id)"},{"name":"pcg_wholesale_documents_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_wholesale_documents_tenant_id_partner_id_fkey","definition":"FOREIGN KEY (tenant_id, partner_id) REFERENCES pcg_wholesale_partners(tenant_id, id) ON DELETE RESTRICT"},{"name":"pcg_wholesale_review_stamp","definition":"CHECK (NOT reviewed AND reviewed_at IS NULL OR reviewed)"}]},{"table":"pcg_wholesale_partners","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage","type":"text","default":"'researching'::text","identity":"","not_null":true,"generated":""},{"name":"status_basis","type":"text","default":"'owner_reported'::text","identity":"","not_null":true,"generated":""},{"name":"applied_at","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"decision_at","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"follow_up_on","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_name","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"contact_email","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"contact_phone","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"portal_url","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"eligibility_notes","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"commercial_notes","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":"uid()","identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":"uid()","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_wholesale_partners_pkey","definition":"CREATE UNIQUE INDEX pcg_wholesale_partners_pkey ON public.pcg_wholesale_partners USING btree (id)"},{"name":"pcg_wholesale_partners_tenant_followup","definition":"CREATE INDEX pcg_wholesale_partners_tenant_followup ON public.pcg_wholesale_partners USING btree (tenant_id, follow_up_on) WHERE (follow_up_on IS NOT NULL)"},{"name":"pcg_wholesale_partners_tenant_id_id_key","definition":"CREATE UNIQUE INDEX pcg_wholesale_partners_tenant_id_id_key ON public.pcg_wholesale_partners USING btree (tenant_id, id)"},{"name":"pcg_wholesale_partners_unique_name","definition":"CREATE UNIQUE INDEX pcg_wholesale_partners_unique_name ON public.pcg_wholesale_partners USING btree (tenant_id, lower(name))"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pcg_wholesale_partners","permissive":"PERMISSIVE","policyname":"pcg_wholesale_partner_insert","schemaname":"public","with_check":"((uid() IS NOT NULL) AND (created_by = ( SELECT uid() AS uid)) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))"},{"cmd":"SELECT","qual":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))","roles":["authenticated"],"tablename":"pcg_wholesale_partners","permissive":"PERMISSIVE","policyname":"pcg_wholesale_partner_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))","roles":["authenticated"],"tablename":"pcg_wholesale_partners","permissive":"PERMISSIVE","policyname":"pcg_wholesale_partner_update","schemaname":"public","with_check":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))"}],"triggers":[{"name":"pcg_wholesale_partner_audit","definition":"CREATE TRIGGER pcg_wholesale_partner_audit AFTER INSERT OR UPDATE ON pcg_wholesale_partners FOR EACH ROW EXECUTE FUNCTION pcg_wholesale_audit_partner()"},{"name":"pcg_wholesale_partner_touch","definition":"CREATE TRIGGER pcg_wholesale_partner_touch BEFORE UPDATE ON pcg_wholesale_partners FOR EACH ROW EXECUTE FUNCTION pcg_wholesale_touch_partner()"}],"constraints":[{"name":"pcg_wholesale_partners_kind_check","definition":"CHECK (kind = ANY (ARRAY['retail_source'::text, 'distributor'::text, 'manufacturer'::text, 'other'::text]))"},{"name":"pcg_wholesale_partners_name_check","definition":"CHECK (char_length(btrim(name)) >= 2 AND char_length(btrim(name)) <= 180)"},{"name":"pcg_wholesale_partners_pkey","definition":"PRIMARY KEY (id)"},{"name":"pcg_wholesale_partners_stage_check","definition":"CHECK (stage = ANY (ARRAY['researching'::text, 'not_applied'::text, 'applied'::text, 'needs_information'::text, 'under_review'::text, 'approved'::text, 'declined'::text, 'on_hold'::text, 'buying'::text]))"},{"name":"pcg_wholesale_partners_status_basis_check","definition":"CHECK (status_basis = ANY (ARRAY['owner_reported'::text, 'evidence_reviewed'::text]))"},{"name":"pcg_wholesale_partners_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"pcg_wholesale_partners_tenant_id_id_key","definition":"UNIQUE (tenant_id, id)"}]},{"table":"pcg_wholesale_profiles","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"facility_type","type":"text","default":"'grading_office'::text","identity":"","not_null":true,"generated":""},{"name":"public_store_hours","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"business_description","type":"text","default":"'Independent card grading and collectibles services.'::text","identity":"","not_null":true,"generated":""},{"name":"reporting_period_start","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"reporting_period_end","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"gross_retail_sales","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"grading_service_revenue","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":"uid()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pcg_wholesale_profiles_pkey","definition":"CREATE UNIQUE INDEX pcg_wholesale_profiles_pkey ON public.pcg_wholesale_profiles USING btree (tenant_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pcg_wholesale_profiles","permissive":"PERMISSIVE","policyname":"pcg_wholesale_profile_insert","schemaname":"public","with_check":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))"},{"cmd":"SELECT","qual":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))","roles":["authenticated"],"tablename":"pcg_wholesale_profiles","permissive":"PERMISSIVE","policyname":"pcg_wholesale_profile_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))","roles":["authenticated"],"tablename":"pcg_wholesale_profiles","permissive":"PERMISSIVE","policyname":"pcg_wholesale_profile_update","schemaname":"public","with_check":"((uid() IS NOT NULL) AND (is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_system_admin(( SELECT uid() AS uid))))"}],"triggers":[],"constraints":[{"name":"pcg_wholesale_period_order","definition":"CHECK (reporting_period_end IS NULL OR reporting_period_start IS NULL OR reporting_period_end >= reporting_period_start)"},{"name":"pcg_wholesale_profiles_facility_type_check","definition":"CHECK (facility_type = ANY (ARRAY['grading_office'::text, 'mixed_retail'::text, 'retail_shop'::text, 'other'::text]))"},{"name":"pcg_wholesale_profiles_grading_service_revenue_check","definition":"CHECK (grading_service_revenue IS NULL OR grading_service_revenue >= 0::numeric)"},{"name":"pcg_wholesale_profiles_gross_retail_sales_check","definition":"CHECK (gross_retail_sales IS NULL OR gross_retail_sales >= 0::numeric)"},{"name":"pcg_wholesale_profiles_pkey","definition":"PRIMARY KEY (tenant_id)"},{"name":"pcg_wholesale_profiles_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"pending_agreements","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"recipient_email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"recipient_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"agreement_html","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"agreement_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"variables","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"sign_token","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"viewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"signer_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signer_ip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"custom_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sent_by","type":"text","default":"'System'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"sent_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"signer_fields","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"completed_fields","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_pdf_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_pdf_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_pdf_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_pdf_generated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_pending_agreements_status","definition":"CREATE INDEX idx_pending_agreements_status ON public.pending_agreements USING btree (status)"},{"name":"idx_pending_agreements_token","definition":"CREATE INDEX idx_pending_agreements_token ON public.pending_agreements USING btree (sign_token)"},{"name":"pending_agreements_event_booking_idx","definition":"CREATE INDEX pending_agreements_event_booking_idx ON public.pending_agreements USING btree (event_booking_id)"},{"name":"pending_agreements_pkey","definition":"CREATE UNIQUE INDEX pending_agreements_pkey ON public.pending_agreements USING btree (id)"},{"name":"pending_agreements_sign_token_key","definition":"CREATE UNIQUE INDEX pending_agreements_sign_token_key ON public.pending_agreements USING btree (sign_token)"}],"policies":[{"cmd":"SELECT","qual":"(is_tenant_member((tenant_id)::text) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"pending_agreements","permissive":"PERMISSIVE","policyname":"Tenant members can read pending agreements","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_tenant_member((tenant_id)::text)","roles":["authenticated"],"tablename":"pending_agreements","permissive":"PERMISSIVE","policyname":"tenant_members_manage_agreements","schemaname":"public","with_check":"is_tenant_member((tenant_id)::text)"}],"triggers":[{"name":"pending_agreements_business_activity","definition":"CREATE TRIGGER pending_agreements_business_activity AFTER INSERT OR UPDATE ON pending_agreements FOR EACH ROW EXECUTE FUNCTION project_pending_agreement_business_activity()"},{"name":"trg_auto_send_portal_welcome","definition":"CREATE TRIGGER trg_auto_send_portal_welcome AFTER UPDATE OF signed_at ON pending_agreements FOR EACH ROW EXECUTE FUNCTION auto_send_portal_welcome_on_signed_agreement()"},{"name":"trg_enforce_pa_rights_before_lor","definition":"CREATE TRIGGER trg_enforce_pa_rights_before_lor BEFORE INSERT ON pending_agreements FOR EACH ROW EXECUTE FUNCTION enforce_pa_rights_before_lor()"},{"name":"trg_sync_321_lockout_signed_agreement","definition":"CREATE TRIGGER trg_sync_321_lockout_signed_agreement AFTER UPDATE OF status, signer_name, signed_at ON pending_agreements FOR EACH ROW EXECUTE FUNCTION sync_321_lockout_signed_agreement()"},{"name":"trg_sync_pa_engagement_from_pending_agreement","definition":"CREATE TRIGGER trg_sync_pa_engagement_from_pending_agreement AFTER UPDATE OF status ON pending_agreements FOR EACH ROW EXECUTE FUNCTION tg_sync_pa_engagement_from_pending_agreement()"}],"constraints":[{"name":"pending_agreements_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"pending_agreements_pkey","definition":"PRIMARY KEY (id)"},{"name":"pending_agreements_sign_token_key","definition":"UNIQUE (sign_token)"}]},{"table":"pending_join_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"pending_signup_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"requested_by_email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"requested_by_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"requested_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"owner_notified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_response_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_response_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"denial_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"approval_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"token_expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_pending_join_tenant","definition":"CREATE INDEX idx_pending_join_tenant ON public.pending_join_requests USING btree (tenant_id, status)"},{"name":"idx_pending_join_token","definition":"CREATE INDEX idx_pending_join_token ON public.pending_join_requests USING btree (approval_token) WHERE (approval_token IS NOT NULL)"},{"name":"idx_pending_join_unique","definition":"CREATE UNIQUE INDEX idx_pending_join_unique ON public.pending_join_requests USING btree (pending_signup_id, tenant_id)"},{"name":"pending_join_requests_approval_token_key","definition":"CREATE UNIQUE INDEX pending_join_requests_approval_token_key ON public.pending_join_requests USING btree (approval_token)"},{"name":"pending_join_requests_pkey","definition":"CREATE UNIQUE INDEX pending_join_requests_pkey ON public.pending_join_requests USING btree (id)"}],"policies":[{"cmd":"UPDATE","qual":"(EXISTS ( SELECT 1\n   FROM (security_active_user_tenant_memberships utm\n     JOIN user_roles ur ON (((ur.user_id = utm.user_id) AND (ur.tenant_id = utm.tenant_id))))\n  WHERE ((utm.tenant_id = pending_join_requests.tenant_id) AND (utm.user_id = uid()) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))","roles":["public"],"tablename":"pending_join_requests","permissive":"PERMISSIVE","policyname":"Owners can update join requests for their tenants","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM (security_active_user_tenant_memberships utm\n     JOIN user_roles ur ON (((ur.user_id = utm.user_id) AND (ur.tenant_id = utm.tenant_id))))\n  WHERE ((utm.tenant_id = pending_join_requests.tenant_id) AND (utm.user_id = uid()) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))","roles":["public"],"tablename":"pending_join_requests","permissive":"PERMISSIVE","policyname":"Owners can view join requests for their tenants","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((jwt() ->> 'role'::text) = 'service_role'::text)","roles":["public"],"tablename":"pending_join_requests","permissive":"PERMISSIVE","policyname":"Service role full access to join requests","schemaname":"public","with_check":null}],"triggers":[{"name":"update_pending_join_requests_updated_at","definition":"CREATE TRIGGER update_pending_join_requests_updated_at BEFORE UPDATE ON pending_join_requests FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"pending_join_requests_approval_token_key","definition":"UNIQUE (approval_token)"},{"name":"pending_join_requests_pkey","definition":"PRIMARY KEY (id)"},{"name":"pending_join_requests_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'approved_by_owner'::text, 'denied_by_owner'::text]))"}]},{"table":"pending_signups","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"full_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"company_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"company_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"pin_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"license_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending_agreement'::text","identity":"","not_null":true,"generated":""},{"name":"signup_token","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"agreement_html","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_version","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":"(now() + '7 days'::interval)","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"company_slug","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"requested_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signer_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signer_ip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_signed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"approved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_json","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenancy","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"joining_existing","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"target_tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_pending_signups_email","definition":"CREATE INDEX idx_pending_signups_email ON public.pending_signups USING btree (email)"},{"name":"idx_pending_signups_expires_at","definition":"CREATE INDEX idx_pending_signups_expires_at ON public.pending_signups USING btree (expires_at)"},{"name":"idx_pending_signups_status","definition":"CREATE INDEX idx_pending_signups_status ON public.pending_signups USING btree (status)"},{"name":"idx_pending_signups_token","definition":"CREATE INDEX idx_pending_signups_token ON public.pending_signups USING btree (signup_token)"},{"name":"pending_signups_email_key","definition":"CREATE UNIQUE INDEX pending_signups_email_key ON public.pending_signups USING btree (email)"},{"name":"pending_signups_pkey","definition":"CREATE UNIQUE INDEX pending_signups_pkey ON public.pending_signups USING btree (id)"},{"name":"pending_signups_signup_token_key","definition":"CREATE UNIQUE INDEX pending_signups_signup_token_key ON public.pending_signups USING btree (signup_token)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"pending_signups","permissive":"PERMISSIVE","policyname":"Authenticated users can create pending signups","schemaname":"public","with_check":"((current_setting('role'::text) = 'service_role'::text) OR (uid() IS NOT NULL))"},{"cmd":"SELECT","qual":"(email = (jwt() ->> 'email'::text))","roles":["authenticated"],"tablename":"pending_signups","permissive":"PERMISSIVE","policyname":"Users can view own pending signup","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin()","roles":["public"],"tablename":"pending_signups","permissive":"PERMISSIVE","policyname":"pending_signups_admin","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"pending_signups","permissive":"PERMISSIVE","policyname":"platform_admin_manage_pending_signups","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"pending_signups_email_key","definition":"UNIQUE (email)"},{"name":"pending_signups_pkey","definition":"PRIMARY KEY (id)"},{"name":"pending_signups_signup_token_key","definition":"UNIQUE (signup_token)"}]},{"table":"pending_voicemail_drops","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"parent_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"homeowner_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"active_call_session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"voicemail_template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"scheduled_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"fire_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'armed'::text","identity":"","not_null":true,"generated":""},{"name":"trigger_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"cancellation_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"fired_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"slot_requested","type":"smallint","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_release_requested","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"rep_released_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"timing_mode","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"playback_started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"failed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"inject_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"drop_requested_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"parking_started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"parking_timeout_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"parking_twilio_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"parking_timeout_hangup","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"parking_failed_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"inject_started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"slot_selection_mode","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"slot_resolved","type":"smallint","default":null,"identity":"","not_null":false,"generated":""},{"name":"attempt_basis","type":"integer","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"pending_voicemail_drops_armed_homeowner_unique","definition":"CREATE UNIQUE INDEX pending_voicemail_drops_armed_homeowner_unique ON public.pending_voicemail_drops USING btree (homeowner_call_sid) WHERE ((status = ANY (ARRAY['armed'::text, 'queued_waiting_for_homeowner_leg'::text, 'playback_started'::text])) AND (homeowner_call_sid IS NOT NULL))"},{"name":"pending_voicemail_drops_armed_session_unique","definition":"CREATE UNIQUE INDEX pending_voicemail_drops_armed_session_unique ON public.pending_voicemail_drops USING btree (active_call_session_id) WHERE ((status = ANY (ARRAY['armed'::text, 'queued_waiting_for_homeowner_leg'::text, 'playback_started'::text])) AND (active_call_session_id IS NOT NULL))"},{"name":"pending_voicemail_drops_fire_at_idx","definition":"CREATE INDEX pending_voicemail_drops_fire_at_idx ON public.pending_voicemail_drops USING btree (fire_at) WHERE (status = 'armed'::text)"},{"name":"pending_voicemail_drops_pkey","definition":"CREATE UNIQUE INDEX pending_voicemail_drops_pkey ON public.pending_voicemail_drops USING btree (id)"},{"name":"pending_voicemail_drops_session_idx","definition":"CREATE INDEX pending_voicemail_drops_session_idx ON public.pending_voicemail_drops USING btree (active_call_session_id)"},{"name":"pending_voicemail_drops_tenant_idx","definition":"CREATE INDEX pending_voicemail_drops_tenant_idx ON public.pending_voicemail_drops USING btree (tenant_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"pending_voicemail_drops","permissive":"PERMISSIVE","policyname":"tenant members read pending voicemail drops","schemaname":"public","with_check":null}],"triggers":[{"name":"pending_voicemail_drops_touch","definition":"CREATE TRIGGER pending_voicemail_drops_touch BEFORE UPDATE ON pending_voicemail_drops FOR EACH ROW EXECUTE FUNCTION tg_pending_voicemail_drops_touch()"}],"constraints":[{"name":"pending_voicemail_drops_pkey","definition":"PRIMARY KEY (id)"},{"name":"pending_voicemail_drops_status_check","definition":"CHECK (status = ANY (ARRAY['armed'::text, 'queued_waiting_for_homeowner_leg'::text, 'playback_started'::text, 'cancelled'::text, 'fired'::text, 'fired_manual'::text, 'failed'::text]))"}]},{"table":"performance_benchmarks","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"metric_name","type":"character varying(100)","default":null,"identity":"","not_null":true,"generated":""},{"name":"benchmark_type","type":"character varying(50)","default":null,"identity":"","not_null":true,"generated":""},{"name":"benchmark_value","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_type","type":"character varying(20)","default":null,"identity":"","not_null":true,"generated":""},{"name":"valid_from","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"valid_until","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"performance_benchmarks_pkey","definition":"CREATE UNIQUE INDEX performance_benchmarks_pkey ON public.performance_benchmarks USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"performance_benchmarks","permissive":"PERMISSIVE","policyname":"Users can view benchmarks","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"performance_benchmarks_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"permissions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"permission_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"permissions_permission_key_key","definition":"CREATE UNIQUE INDEX permissions_permission_key_key ON public.permissions USING btree (permission_key)"},{"name":"permissions_pkey","definition":"CREATE UNIQUE INDEX permissions_pkey ON public.permissions USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"permissions","permissive":"PERMISSIVE","policyname":"Permissions viewable by authenticated users","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"permissions_permission_key_key","definition":"UNIQUE (permission_key)"},{"name":"permissions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"permit_lookup_attempts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"full_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"searched_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"searched_jurisdiction","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"search_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"search_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"result_status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"permits_found_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"roof_permits_found_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"failure_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_response","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"triggered_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_permit_lookup_attempts_tenantless_unknown_recent","definition":"CREATE INDEX idx_permit_lookup_attempts_tenantless_unknown_recent ON public.permit_lookup_attempts USING btree (created_at DESC) WHERE ((tenant_org_id IS NULL) AND (COALESCE(NULLIF(btrim(searched_source), ''::text), 'Unknown'::text) = 'Unknown'::text) AND (COALESCE(NULLIF(btrim(searched_jurisdiction), ''::text), 'Unknown'::text) = 'Unknown'::text) AND (COALESCE(NULLIF(btrim(search_method), ''::text), 'address'::text) = 'address'::text) AND (result_status = 'source_unavailable'::text))"},{"name":"permit_lookup_attempts_full_address_created_at_idx","definition":"CREATE INDEX permit_lookup_attempts_full_address_created_at_idx ON public.permit_lookup_attempts USING btree (full_address, created_at DESC)"},{"name":"permit_lookup_attempts_pkey","definition":"CREATE UNIQUE INDEX permit_lookup_attempts_pkey ON public.permit_lookup_attempts USING btree (id)"},{"name":"permit_lookup_attempts_tenant_idx","definition":"CREATE INDEX permit_lookup_attempts_tenant_idx ON public.permit_lookup_attempts USING btree (tenant_org_id, created_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"permit_lookup_attempts","permissive":"PERMISSIVE","policyname":"lookup insert tenant","schemaname":"public","with_check":"((tenant_org_id IS NULL) OR (tenant_org_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))) OR ( SELECT is_system_admin(uid()) AS is_system_admin))"},{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR (tenant_org_id = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[]))) OR ( SELECT is_system_admin(uid()) AS is_system_admin))","roles":["authenticated"],"tablename":"permit_lookup_attempts","permissive":"PERMISSIVE","policyname":"lookup read tenant","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_fill_permit_lookup_attempt_attribution","definition":"CREATE TRIGGER trg_fill_permit_lookup_attempt_attribution BEFORE INSERT ON permit_lookup_attempts FOR EACH ROW EXECUTE FUNCTION fill_permit_lookup_attempt_attribution()"}],"constraints":[{"name":"permit_lookup_attempts_no_tenantless_unknown_source","definition":"CHECK (tenant_org_id IS NOT NULL OR NOT (COALESCE(NULLIF(btrim(searched_source), ''::text), 'Unknown'::text) = 'Unknown'::text AND COALESCE(NULLIF(btrim(searched_jurisdiction), ''::text), 'Unknown'::text) = 'Unknown'::text AND COALESCE(NULLIF(btrim(search_method), ''::text), 'address'::text) = 'address'::text AND result_status = 'source_unavailable'::text)) NOT VALID"},{"name":"permit_lookup_attempts_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"permit_source_configs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"municipality","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"county","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_type","type":"text","default":"'manual'::text","identity":"","not_null":true,"generated":""},{"name":"base_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"api_endpoint_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_office_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"requires_auth","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"public_api_available","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_psc_enabled","definition":"CREATE INDEX idx_psc_enabled ON public.permit_source_configs USING btree (enabled)"},{"name":"idx_psc_location","definition":"CREATE INDEX idx_psc_location ON public.permit_source_configs USING btree (state, municipality)"},{"name":"idx_psc_tenant","definition":"CREATE INDEX idx_psc_tenant ON public.permit_source_configs USING btree (tenant_org_id)"},{"name":"permit_source_configs_pkey","definition":"CREATE UNIQUE INDEX permit_source_configs_pkey ON public.permit_source_configs USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"is_global_admin(uid())","roles":["authenticated"],"tablename":"permit_source_configs","permissive":"PERMISSIVE","policyname":"psc_delete_admins","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"permit_source_configs","permissive":"PERMISSIVE","policyname":"psc_insert_admins","schemaname":"public","with_check":"(is_global_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_admin_or_higher(uid(), tenant_org_id)))"},{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR is_tenant_member(uid(), tenant_org_id))","roles":["authenticated"],"tablename":"permit_source_configs","permissive":"PERMISSIVE","policyname":"psc_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_global_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_admin_or_higher(uid(), tenant_org_id)))","roles":["authenticated"],"tablename":"permit_source_configs","permissive":"PERMISSIVE","policyname":"psc_update_admins","schemaname":"public","with_check":"(is_global_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_admin_or_higher(uid(), tenant_org_id)))"}],"triggers":[{"name":"trg_psc_updated_at","definition":"CREATE TRIGGER trg_psc_updated_at BEFORE UPDATE ON permit_source_configs FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"permit_source_configs_pkey","definition":"PRIMARY KEY (id)"},{"name":"permit_source_configs_source_type_check","definition":"CHECK (source_type = ANY (ARRAY['manual'::text, 'website'::text, 'csv_upload'::text, 'arcgis'::text, 'ckan'::text, 'api'::text, 'scraper'::text, 'foil'::text]))"}]},{"table":"permit_sources","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"jurisdiction_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"county","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":"'FL'::text","identity":"","not_null":true,"generated":""},{"name":"source_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"portal_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"portal_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"search_methods_supported","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"requires_login","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"permit_sources_pkey","definition":"CREATE UNIQUE INDEX permit_sources_pkey ON public.permit_sources USING btree (id)"},{"name":"permit_sources_unique","definition":"CREATE UNIQUE INDEX permit_sources_unique ON public.permit_sources USING btree (jurisdiction_name, source_type)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin()","roles":["authenticated"],"tablename":"permit_sources","permissive":"PERMISSIVE","policyname":"permit_sources admin write","schemaname":"public","with_check":"is_system_admin()"},{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"permit_sources","permissive":"PERMISSIVE","policyname":"permit_sources read auth","schemaname":"public","with_check":null}],"triggers":[{"name":"permit_sources_updated_at","definition":"CREATE TRIGGER permit_sources_updated_at BEFORE UPDATE ON permit_sources FOR EACH ROW EXECUTE FUNCTION set_updated_at_simple()"}],"constraints":[{"name":"permit_sources_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"permits","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"property_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"permit_source","default":"'MANUAL'::permit_source","identity":"","not_null":true,"generated":""},{"name":"jurisdiction","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"municipality","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"county","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"permit_status","default":"'unknown'::permit_status","identity":"","not_null":true,"generated":""},{"name":"permit_required","type":"permit_required_state","default":"'unknown'::permit_required_state","identity":"","not_null":true,"generated":""},{"name":"applied_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"issued_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"final_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"applicant","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"valuation","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"square_feet","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"document_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_checked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"checked_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_roof_related","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_permits_contact","definition":"CREATE INDEX idx_permits_contact ON public.permits USING btree (contact_id) WHERE (contact_id IS NOT NULL)"},{"name":"idx_permits_lead","definition":"CREATE INDEX idx_permits_lead ON public.permits USING btree (lead_id) WHERE (lead_id IS NOT NULL)"},{"name":"idx_permits_property","definition":"CREATE INDEX idx_permits_property ON public.permits USING btree (property_id) WHERE (property_id IS NOT NULL)"},{"name":"idx_permits_roof","definition":"CREATE INDEX idx_permits_roof ON public.permits USING btree (tenant_org_id, is_roof_related) WHERE (is_roof_related = true)"},{"name":"idx_permits_source","definition":"CREATE INDEX idx_permits_source ON public.permits USING btree (source)"},{"name":"idx_permits_tenant","definition":"CREATE INDEX idx_permits_tenant ON public.permits USING btree (tenant_org_id)"},{"name":"permits_pkey","definition":"CREATE UNIQUE INDEX permits_pkey ON public.permits USING btree (id)"},{"name":"uq_permits_tenant_source_number","definition":"CREATE UNIQUE INDEX uq_permits_tenant_source_number ON public.permits USING btree (tenant_org_id, source, permit_number) WHERE (permit_number IS NOT NULL)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_member((tenant_org_id)::text)","roles":["authenticated"],"tablename":"permits","permissive":"PERMISSIVE","policyname":"permits_delete_tenant_members","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"permits","permissive":"PERMISSIVE","policyname":"permits_insert_tenant_members","schemaname":"public","with_check":"(is_tenant_member((tenant_org_id)::text) AND ((created_by IS NULL) OR (created_by = uid())))"},{"cmd":"SELECT","qual":"is_tenant_member((tenant_org_id)::text)","roles":["authenticated"],"tablename":"permits","permissive":"PERMISSIVE","policyname":"permits_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member((tenant_org_id)::text)","roles":["authenticated"],"tablename":"permits","permissive":"PERMISSIVE","policyname":"permits_update_tenant_members","schemaname":"public","with_check":"is_tenant_member((tenant_org_id)::text)"}],"triggers":[{"name":"trg_permits_flag_roof","definition":"CREATE TRIGGER trg_permits_flag_roof BEFORE INSERT OR UPDATE OF permit_type, description, notes ON permits FOR EACH ROW EXECUTE FUNCTION flag_roof_related_permit()"},{"name":"trg_permits_updated_at","definition":"CREATE TRIGGER trg_permits_updated_at BEFORE UPDATE ON permits FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"permits_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"pin_reset_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"reset_token","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"request_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"requested_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":"(now() + '24:00:00'::interval)","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"pin_reset_requests_pkey","definition":"CREATE UNIQUE INDEX pin_reset_requests_pkey ON public.pin_reset_requests USING btree (id)"},{"name":"pin_reset_requests_request_id_key","definition":"CREATE UNIQUE INDEX pin_reset_requests_request_id_key ON public.pin_reset_requests USING btree (request_id)"},{"name":"pin_reset_requests_reset_token_key","definition":"CREATE UNIQUE INDEX pin_reset_requests_reset_token_key ON public.pin_reset_requests USING btree (reset_token)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"pin_reset_requests","permissive":"PERMISSIVE","policyname":"platform_admin_manage_pin_resets","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"pin_reset_requests","permissive":"PERMISSIVE","policyname":"users_insert_own_pin_reset","schemaname":"public","with_check":"((email = (jwt() ->> 'email'::text)) OR is_system_admin(uid()))"}],"triggers":[],"constraints":[{"name":"pin_reset_requests_pkey","definition":"PRIMARY KEY (id)"},{"name":"pin_reset_requests_request_id_key","definition":"UNIQUE (request_id)"},{"name":"pin_reset_requests_reset_token_key","definition":"UNIQUE (reset_token)"}]},{"table":"pipeline_automation_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"rule_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"trigger_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"actions_executed","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"success","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"execution_time_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_pipeline_automation_log_contact","definition":"CREATE INDEX idx_pipeline_automation_log_contact ON public.pipeline_automation_log USING btree (contact_id)"},{"name":"idx_pipeline_automation_log_rule","definition":"CREATE INDEX idx_pipeline_automation_log_rule ON public.pipeline_automation_log USING btree (rule_id)"},{"name":"pipeline_automation_log_pkey","definition":"CREATE UNIQUE INDEX pipeline_automation_log_pkey ON public.pipeline_automation_log USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"pipeline_automation_log","permissive":"PERMISSIVE","policyname":"Tenant isolation for pipeline_automation_log","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pipeline_automation_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"pipeline_automation_rules","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"trigger_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"trigger_config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"conditions","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"actions","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"priority","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"execution_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"last_executed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"derived_from_template_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adopted_admin_version","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_par_derived_template_key","definition":"CREATE INDEX idx_par_derived_template_key ON public.pipeline_automation_rules USING btree (derived_from_template_key)"},{"name":"idx_pipeline_automation_rules_tenant","definition":"CREATE INDEX idx_pipeline_automation_rules_tenant ON public.pipeline_automation_rules USING btree (tenant_org_id)"},{"name":"pipeline_automation_rules_pkey","definition":"CREATE UNIQUE INDEX pipeline_automation_rules_pkey ON public.pipeline_automation_rules USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"pipeline_automation_rules","permissive":"PERMISSIVE","policyname":"Tenant isolation for pipeline_automation_rules","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pipeline_automation_rules_pkey","definition":"PRIMARY KEY (id)"},{"name":"pipeline_automation_rules_trigger_type_check","definition":"CHECK (trigger_type = ANY (ARRAY['status_change'::text, 'stage_change'::text, 'field_update'::text, 'time_based'::text, 'score_threshold'::text, 'event_stage_change'::text, 'event_time'::text, 'event_updated'::text]))"}]},{"table":"pipeline_movement_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_stage","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_stage","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"trigger_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"trigger_outcome","type":"call_outcome","default":null,"identity":"","not_null":false,"generated":""},{"name":"triggered_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_pipeline_audit_contact","definition":"CREATE INDEX idx_pipeline_audit_contact ON public.pipeline_movement_audit USING btree (contact_id)"},{"name":"idx_pipeline_audit_tenant","definition":"CREATE INDEX idx_pipeline_audit_tenant ON public.pipeline_movement_audit USING btree (tenant_org_id)"},{"name":"pipeline_movement_audit_pkey","definition":"CREATE UNIQUE INDEX pipeline_movement_audit_pkey ON public.pipeline_movement_audit USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = pipeline_movement_audit.tenant_org_id))))","roles":["public"],"tablename":"pipeline_movement_audit","permissive":"PERMISSIVE","policyname":"Users view tenant pipeline audit","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"pipeline_movement_audit_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"pipeline_stages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"order_index","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"color","type":"text","default":"'gray'::text","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"is_closed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"is_won","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"pipeline_kind","type":"pipeline_kind","default":"'JOB'::pipeline_kind","identity":"","not_null":true,"generated":""},{"name":"tenancy_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_template","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"derived_from_template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_using_master_template","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"template_stage_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adopted_admin_version","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_pipeline_stages_template","definition":"CREATE INDEX idx_pipeline_stages_template ON public.pipeline_stages USING btree (is_template, tenancy_type) WHERE (is_template = true)"},{"name":"idx_pipeline_stages_template_lookup","definition":"CREATE INDEX idx_pipeline_stages_template_lookup ON public.pipeline_stages USING btree (tenant_type, pipeline_kind, is_template) WHERE (is_template = true)"},{"name":"idx_pipeline_stages_templates","definition":"CREATE INDEX idx_pipeline_stages_templates ON public.pipeline_stages USING btree (tenancy_type, is_template) WHERE (tenant_org_id IS NULL)"},{"name":"idx_pipeline_stages_tenant","definition":"CREATE INDEX idx_pipeline_stages_tenant ON public.pipeline_stages USING btree (tenant_org_id)"},{"name":"idx_pipeline_stages_tenant_kind","definition":"CREATE INDEX idx_pipeline_stages_tenant_kind ON public.pipeline_stages USING btree (tenant_org_id, pipeline_kind, order_index) WHERE (tenant_org_id IS NOT NULL)"},{"name":"idx_pipeline_stages_tenant_order","definition":"CREATE INDEX idx_pipeline_stages_tenant_order ON public.pipeline_stages USING btree (tenant_org_id, order_index)"},{"name":"pipeline_stages_pkey","definition":"CREATE UNIQUE INDEX pipeline_stages_pkey ON public.pipeline_stages USING btree (id)"},{"name":"pipeline_stages_tenant_org_id_pipeline_kind_name_key","definition":"CREATE UNIQUE INDEX pipeline_stages_tenant_org_id_pipeline_kind_name_key ON public.pipeline_stages USING btree (tenant_org_id, pipeline_kind, name)"}],"policies":[{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND (is_system_admin(uid()) OR is_tenant_owner_for(uid(), tenant_org_id)))","roles":["public"],"tablename":"pipeline_stages","permissive":"PERMISSIVE","policyname":"Tenant owners manage tenant stages","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = pipeline_stages.tenant_org_id))))","roles":["authenticated"],"tablename":"pipeline_stages","permissive":"PERMISSIVE","policyname":"Users can view stages in their tenant","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(((tenant_org_id IS NULL) AND (is_template = true)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = pipeline_stages.tenant_org_id)))))","roles":["public"],"tablename":"pipeline_stages","permissive":"PERMISSIVE","policyname":"Users view tenant stages and templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"pipeline_stages","permissive":"PERMISSIVE","policyname":"platform_admin_manage_pipeline_stages","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[{"name":"update_pipeline_stages_updated_at","definition":"CREATE TRIGGER update_pipeline_stages_updated_at BEFORE UPDATE ON pipeline_stages FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"pipeline_stages_pkey","definition":"PRIMARY KEY (id)"},{"name":"pipeline_stages_tenant_org_id_pipeline_kind_name_key","definition":"UNIQUE (tenant_org_id, pipeline_kind, name)"}]},{"table":"pipeline_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"pipeline_kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"sort_order","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"color","type":"text","default":"'blue'::text","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"is_closed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"is_won","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_pipeline_templates_tenant_type","definition":"CREATE INDEX idx_pipeline_templates_tenant_type ON public.pipeline_templates USING btree (tenant_type, pipeline_kind)"},{"name":"pipeline_templates_pkey","definition":"CREATE UNIQUE INDEX pipeline_templates_pkey ON public.pipeline_templates USING btree (id)"},{"name":"pipeline_templates_tenant_type_pipeline_kind_stage_key_key","definition":"CREATE UNIQUE INDEX pipeline_templates_tenant_type_pipeline_kind_stage_key_key ON public.pipeline_templates USING btree (tenant_type, pipeline_kind, stage_key)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"pipeline_templates","permissive":"PERMISSIVE","policyname":"Authenticated users can view pipeline templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"pipeline_templates","permissive":"PERMISSIVE","policyname":"platform_admin_manage_pipeline_templates","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"pipeline_templates_pipeline_kind_check","definition":"CHECK (pipeline_kind = ANY (ARRAY['JOB'::text, 'CLAIM'::text]))"},{"name":"pipeline_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"pipeline_templates_tenant_type_check","definition":"CHECK (tenant_type = ANY (ARRAY['MITIGATION'::text, 'ROOFING_COMPANY'::text, 'PUBLIC_ADJUSTER_FIRM'::text, 'REALTOR'::text]))"},{"name":"pipeline_templates_tenant_type_pipeline_kind_stage_key_key","definition":"UNIQUE (tenant_type, pipeline_kind, stage_key)"}]},{"table":"pipeline_transition_rules","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_stage_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_stage_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"trigger_outcome","type":"call_outcome","default":null,"identity":"","not_null":true,"generated":""},{"name":"auto_advance","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_transition_rules_tenant","definition":"CREATE INDEX idx_transition_rules_tenant ON public.pipeline_transition_rules USING btree (tenant_org_id)"},{"name":"pipeline_transition_rules_pkey","definition":"CREATE UNIQUE INDEX pipeline_transition_rules_pkey ON public.pipeline_transition_rules USING btree (id)"},{"name":"pipeline_transition_rules_tenant_org_id_from_stage_id_trigg_key","definition":"CREATE UNIQUE INDEX pipeline_transition_rules_tenant_org_id_from_stage_id_trigg_key ON public.pipeline_transition_rules USING btree (tenant_org_id, from_stage_id, trigger_outcome)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = pipeline_transition_rules.tenant_org_id))))","roles":["public"],"tablename":"pipeline_transition_rules","permissive":"PERMISSIVE","policyname":"Users view tenant transition rules","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"pipeline_transition_rules","permissive":"PERMISSIVE","policyname":"platform_admin_manage_transition_rules","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"pipeline_transition_rules_pkey","definition":"PRIMARY KEY (id)"},{"name":"pipeline_transition_rules_tenant_org_id_from_stage_id_trigg_key","definition":"UNIQUE (tenant_org_id, from_stage_id, trigger_outcome)"}]},{"table":"plan_features","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"plan_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"feature_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"limit_value","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_boolean","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"plan_features_pkey","definition":"CREATE UNIQUE INDEX plan_features_pkey ON public.plan_features USING btree (id)"},{"name":"plan_features_plan_id_feature_key_key","definition":"CREATE UNIQUE INDEX plan_features_plan_id_feature_key_key ON public.plan_features USING btree (plan_id, feature_key)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"plan_features","permissive":"PERMISSIVE","policyname":"Only system admins modify plan features","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"true","roles":["public"],"tablename":"plan_features","permissive":"PERMISSIVE","policyname":"Plan features are publicly readable","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"plan_features_pkey","definition":"PRIMARY KEY (id)"},{"name":"plan_features_plan_id_feature_key_key","definition":"UNIQUE (plan_id, feature_key)"}]},{"table":"plans","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"slug","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tier","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"monthly_cents","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"annual_cents","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"included_seats","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"additional_seat_cents","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"vertical_default","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_public","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"stripe_price_id_monthly","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_price_id_yearly","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"plans_pkey","definition":"CREATE UNIQUE INDEX plans_pkey ON public.plans USING btree (id)"},{"name":"plans_slug_key","definition":"CREATE UNIQUE INDEX plans_slug_key ON public.plans USING btree (slug)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"plans","permissive":"PERMISSIVE","policyname":"Only system admins modify plans","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((is_public = true) OR is_system_admin(uid()))","roles":["public"],"tablename":"plans","permissive":"PERMISSIVE","policyname":"Plans are publicly readable","schemaname":"public","with_check":null}],"triggers":[{"name":"update_plans_updated_at","definition":"CREATE TRIGGER update_plans_updated_at BEFORE UPDATE ON plans FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"plans_pkey","definition":"PRIMARY KEY (id)"},{"name":"plans_slug_key","definition":"UNIQUE (slug)"},{"name":"plans_tier_check","definition":"CHECK (tier = ANY (ARRAY['trial'::text, 'starter'::text, 'pro'::text, 'brokerage'::text, 'enterprise'::text]))"}]},{"table":"platform_business_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"entity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"summary","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"visibility","type":"text","default":"'staff'::text","identity":"","not_null":true,"generated":""},{"name":"correlation_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"idempotency_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"recorded_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"platform_business_events_dedupe","definition":"CREATE UNIQUE INDEX platform_business_events_dedupe ON public.platform_business_events USING btree (tenant_id, idempotency_key)"},{"name":"platform_business_events_pkey","definition":"CREATE UNIQUE INDEX platform_business_events_pkey ON public.platform_business_events USING btree (id)"},{"name":"platform_business_events_record_history","definition":"CREATE INDEX platform_business_events_record_history ON public.platform_business_events USING btree (tenant_id, entity_type, entity_id, occurred_at DESC)"},{"name":"platform_business_events_tenant_recent","definition":"CREATE INDEX platform_business_events_tenant_recent ON public.platform_business_events USING btree (tenant_id, occurred_at DESC, id DESC)"}],"policies":[{"cmd":"SELECT","qual":"((visibility = 'staff'::text) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships m\n  WHERE ((m.tenant_id = platform_business_events.tenant_id) AND (m.user_id = uid()) AND (COALESCE(m.status, 'active'::text) = 'active'::text) AND ((m.is_owner IS TRUE) OR (EXISTS ( SELECT 1\n           FROM user_roles r\n          WHERE ((r.tenant_id = m.tenant_id) AND (r.user_id = uid()) AND (lower((r.role)::text) = ANY (ARRAY['owner'::text, 'tenant owner'::text, 'co_owner'::text, 'co-owner'::text, 'admin'::text, 'administrator'::text]))))))))))","roles":["authenticated"],"tablename":"platform_business_events","permissive":"PERMISSIVE","policyname":"platform_business_events_staff_read","schemaname":"public","with_check":null}],"triggers":[{"name":"platform_business_events_immutable","definition":"CREATE TRIGGER platform_business_events_immutable BEFORE DELETE OR UPDATE ON platform_business_events FOR EACH ROW EXECUTE FUNCTION reject_platform_business_event_mutation()"}],"constraints":[{"name":"platform_business_events_actor_type_check","definition":"CHECK (actor_type = ANY (ARRAY['user'::text, 'system'::text, 'integration'::text, 'paul'::text]))"},{"name":"platform_business_events_nonblank","definition":"CHECK (length(TRIM(BOTH FROM event_type)) > 0 AND length(TRIM(BOTH FROM entity_type)) > 0 AND length(TRIM(BOTH FROM entity_id)) > 0 AND length(TRIM(BOTH FROM idempotency_key)) > 0)"},{"name":"platform_business_events_outcome_check","definition":"CHECK (outcome = ANY (ARRAY['started'::text, 'succeeded'::text, 'failed'::text, 'canceled'::text, 'changed'::text]))"},{"name":"platform_business_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"platform_business_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"platform_business_events_visibility_check","definition":"CHECK (visibility = ANY (ARRAY['staff'::text, 'customer'::text, 'system'::text]))"}]},{"table":"platform_changelog","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'improvement'::text","identity":"","not_null":true,"generated":""},{"name":"icon","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"shipped_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"target_roles","type":"text[]","default":"ARRAY[]::text[]","identity":"","not_null":true,"generated":""},{"name":"is_published","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_platform_changelog_published","definition":"CREATE INDEX idx_platform_changelog_published ON public.platform_changelog USING btree (is_published) WHERE (is_published = true)"},{"name":"idx_platform_changelog_shipped_at","definition":"CREATE INDEX idx_platform_changelog_shipped_at ON public.platform_changelog USING btree (shipped_at DESC)"},{"name":"platform_changelog_pkey","definition":"CREATE UNIQUE INDEX platform_changelog_pkey ON public.platform_changelog USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"platform_changelog","permissive":"PERMISSIVE","policyname":"Platform admins can delete changelog","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"platform_changelog","permissive":"PERMISSIVE","policyname":"Platform admins can insert changelog","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"UPDATE","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"platform_changelog","permissive":"PERMISSIVE","policyname":"Platform admins can update changelog","schemaname":"public","with_check":"is_platform_admin(uid())"},{"cmd":"SELECT","qual":"((is_published = true) AND ((cardinality(target_roles) = 0) OR (EXISTS ( SELECT 1\n   FROM user_roles ur\n  WHERE ((ur.user_id = uid()) AND ((ur.role)::text = ANY (platform_changelog.target_roles)))))))","roles":["authenticated"],"tablename":"platform_changelog","permissive":"PERMISSIVE","policyname":"Signed-in users can view targeted published changelog","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_platform_changelog_updated_at","definition":"CREATE TRIGGER trg_platform_changelog_updated_at BEFORE UPDATE ON platform_changelog FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"platform_changelog_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"platform_communication_mode","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"mode","type":"text","default":"'testing'::text","identity":"","not_null":true,"generated":""},{"name":"admin_sink_email","type":"text","default":"'admin@knocklaunch.app'::text","identity":"","not_null":true,"generated":""},{"name":"admin_sink_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"singleton","type":"boolean","default":"true","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"platform_communication_mode_pkey","definition":"CREATE UNIQUE INDEX platform_communication_mode_pkey ON public.platform_communication_mode USING btree (id)"},{"name":"platform_communication_mode_singleton_key","definition":"CREATE UNIQUE INDEX platform_communication_mode_singleton_key ON public.platform_communication_mode USING btree (singleton)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"platform_communication_mode","permissive":"PERMISSIVE","policyname":"All authenticated can read comm mode","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"platform_communication_mode","permissive":"PERMISSIVE","policyname":"Only GodMode can insert comm mode","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"UPDATE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"platform_communication_mode","permissive":"PERMISSIVE","policyname":"Only GodMode can update comm mode","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[{"name":"trg_log_comm_mode_change","definition":"CREATE TRIGGER trg_log_comm_mode_change BEFORE UPDATE ON platform_communication_mode FOR EACH ROW EXECUTE FUNCTION log_comm_mode_change()"}],"constraints":[{"name":"platform_communication_mode_mode_check","definition":"CHECK (mode = ANY (ARRAY['testing'::text, 'live'::text]))"},{"name":"platform_communication_mode_pkey","definition":"PRIMARY KEY (id)"},{"name":"platform_communication_mode_singleton_key","definition":"UNIQUE (singleton)"}]},{"table":"platform_mode_default_media","schema":"public","columns":[{"name":"mode_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"mime_type","type":"text","default":"'image/webp'::text","identity":"","not_null":true,"generated":""},{"name":"content_base64","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"width","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"height","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"pack_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"sha256","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"platform_mode_default_media_pkey","definition":"CREATE UNIQUE INDEX platform_mode_default_media_pkey ON public.platform_mode_default_media USING btree (mode_key)"}],"policies":[],"triggers":[],"constraints":[{"name":"platform_mode_default_media_height_check","definition":"CHECK (height > 0)"},{"name":"platform_mode_default_media_key_check","definition":"CHECK (mode_key = ANY (ARRAY['operations'::text, 'planning'::text, 'growth'::text, 'financials'::text, 'back-office'::text, 'field'::text, 'rentals'::text, 'events'::text, 'activations'::text, 'vendors'::text]))"},{"name":"platform_mode_default_media_pack_version_check","definition":"CHECK (pack_version > 0)"},{"name":"platform_mode_default_media_pkey","definition":"PRIMARY KEY (mode_key)"},{"name":"platform_mode_default_media_sha256_check","definition":"CHECK (length(sha256) = 64)"},{"name":"platform_mode_default_media_width_check","definition":"CHECK (width > 0)"}]},{"table":"platform_notification_deliveries","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"notification_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"channel","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"route_source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"delivery_state","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_message_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_receipt_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"attempt_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"next_attempt_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_error_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"accepted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"delivered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"platform_notification_deliveries_due","definition":"CREATE INDEX platform_notification_deliveries_due ON public.platform_notification_deliveries USING btree (delivery_state, next_attempt_at, created_at) WHERE (delivery_state = ANY (ARRAY['queued'::text, 'failed'::text]))"},{"name":"platform_notification_deliveries_notification_id_channel_key","definition":"CREATE UNIQUE INDEX platform_notification_deliveries_notification_id_channel_key ON public.platform_notification_deliveries USING btree (notification_id, channel)"},{"name":"platform_notification_deliveries_pkey","definition":"CREATE UNIQUE INDEX platform_notification_deliveries_pkey ON public.platform_notification_deliveries USING btree (id)"},{"name":"platform_notification_deliveries_recipient","definition":"CREATE INDEX platform_notification_deliveries_recipient ON public.platform_notification_deliveries USING btree (tenant_id, user_id, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"((uid() IS NOT NULL) AND (user_id = uid()) AND is_tenant_member(uid(), tenant_id))","roles":["authenticated"],"tablename":"platform_notification_deliveries","permissive":"PERMISSIVE","policyname":"platform_notification_deliveries_self_read","schemaname":"public","with_check":null}],"triggers":[{"name":"platform_notification_delivery_immutable_identity","definition":"CREATE TRIGGER platform_notification_delivery_immutable_identity BEFORE UPDATE ON platform_notification_deliveries FOR EACH ROW EXECUTE FUNCTION enforce_platform_notification_delivery_identity()"}],"constraints":[{"name":"platform_delivery_confirmed_receipt","definition":"CHECK (delivery_state <> 'delivered'::text OR channel <> 'in_app'::text AND provider_receipt_id IS NOT NULL AND delivered_at IS NOT NULL)"},{"name":"platform_delivery_provider_acceptance","definition":"CHECK (delivery_state <> 'provider_accepted'::text OR provider_name IS NOT NULL AND accepted_at IS NOT NULL)"},{"name":"platform_notification_deliveries_attempt_count_check","definition":"CHECK (attempt_count >= 0)"},{"name":"platform_notification_deliveries_category_check","definition":"CHECK (category = ANY (ARRAY['messages'::text, 'assigned'::text, 'deadlines'::text, 'billing'::text, 'updates'::text]))"},{"name":"platform_notification_deliveries_channel_check","definition":"CHECK (channel = ANY (ARRAY['in_app'::text, 'push'::text, 'email'::text]))"},{"name":"platform_notification_deliveries_delivery_state_check","definition":"CHECK (delivery_state = ANY (ARRAY['recorded'::text, 'queued'::text, 'blocked_unconfigured'::text, 'attempting'::text, 'provider_accepted'::text, 'delivered'::text, 'failed'::text, 'canceled'::text]))"},{"name":"platform_notification_deliveries_notification_id_channel_key","definition":"UNIQUE (notification_id, channel)"},{"name":"platform_notification_deliveries_notification_id_fkey","definition":"FOREIGN KEY (notification_id) REFERENCES notifications(id) ON DELETE CASCADE"},{"name":"platform_notification_deliveries_pkey","definition":"PRIMARY KEY (id)"},{"name":"platform_notification_deliveries_route_source_check","definition":"CHECK (route_source = ANY (ARRAY['platform_default'::text, 'tenant_recommendation'::text, 'personal_override'::text, 'tenant_enforced'::text]))"},{"name":"platform_notification_deliveries_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"platform_override_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"actor_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"target_table","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"target_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"platform_override_log_pkey","definition":"CREATE UNIQUE INDEX platform_override_log_pkey ON public.platform_override_log USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"platform_override_log","permissive":"PERMISSIVE","policyname":"pol_insert","schemaname":"public","with_check":"((actor_id = uid()) AND is_platform_admin(uid()))"},{"cmd":"SELECT","qual":"(is_platform_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = platform_override_log.tenant_id) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role]))))))","roles":["authenticated"],"tablename":"platform_override_log","permissive":"PERMISSIVE","policyname":"pol_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"platform_override_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"platform_storage_cleanup_runs","schema":"public","columns":[{"name":"cleanup_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"nonce","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'ready'::text","identity":"","not_null":true,"generated":""},{"name":"migrated_files","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"migrated_bytes","type":"bigint","default":"0","identity":"","not_null":true,"generated":""},{"name":"reference_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"details","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"migrated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"platform_storage_cleanup_runs_pkey","definition":"CREATE UNIQUE INDEX platform_storage_cleanup_runs_pkey ON public.platform_storage_cleanup_runs USING btree (cleanup_key)"}],"policies":[],"triggers":[],"constraints":[{"name":"platform_storage_cleanup_runs_pkey","definition":"PRIMARY KEY (cleanup_key)"}]},{"table":"platform_storage_registry","schema":"public","columns":[{"name":"bucket_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"namespace","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"domain","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"purpose","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"owner_tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_tenant_slug","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"canonical_path_contract","type":"text","default":"''::text","identity":"","not_null":true,"generated":""},{"name":"visibility","type":"text","default":"'private'::text","identity":"","not_null":true,"generated":""},{"name":"lifecycle","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"retention_class","type":"text","default":"'business'::text","identity":"","not_null":true,"generated":""},{"name":"managed_by","type":"text","default":"'knocklaunch'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"architecture_version","type":"text","default":"'v3'::text","identity":"","not_null":true,"generated":""},{"name":"object_count","type":"bigint","default":"0","identity":"","not_null":true,"generated":""},{"name":"bytes","type":"bigint","default":"0","identity":"","not_null":true,"generated":""},{"name":"last_audited_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"platform_storage_registry_pkey","definition":"CREATE UNIQUE INDEX platform_storage_registry_pkey ON public.platform_storage_registry USING btree (bucket_id)"}],"policies":[{"cmd":"SELECT","qual":"COALESCE(is_system_admin(uid()), false)","roles":["authenticated"],"tablename":"platform_storage_registry","permissive":"PERMISSIVE","policyname":"platform_storage_registry_admin_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"platform_storage_registry_namespace_check","definition":"CHECK (namespace = ANY (ARRAY['tenant'::text, 'demo'::text, 'platform'::text, 'system'::text, 'legacy_pending'::text]))"},{"name":"platform_storage_registry_owner_tenant_id_fkey","definition":"FOREIGN KEY (owner_tenant_id) REFERENCES tenants(id) ON DELETE SET NULL"},{"name":"platform_storage_registry_pkey","definition":"PRIMARY KEY (bucket_id)"},{"name":"platform_storage_registry_visibility_check","definition":"CHECK (visibility = ANY (ARRAY['private'::text, 'public'::text]))"}]},{"table":"portal_links","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"token","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"view_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"last_viewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_portal_links_contact","definition":"CREATE INDEX idx_portal_links_contact ON public.portal_links USING btree (contact_id)"},{"name":"idx_portal_links_tenant","definition":"CREATE INDEX idx_portal_links_tenant ON public.portal_links USING btree (tenant_org_id)"},{"name":"idx_portal_links_token","definition":"CREATE INDEX idx_portal_links_token ON public.portal_links USING btree (token)"},{"name":"portal_links_pkey","definition":"CREATE UNIQUE INDEX portal_links_pkey ON public.portal_links USING btree (id)"},{"name":"portal_links_token_key","definition":"CREATE UNIQUE INDEX portal_links_token_key ON public.portal_links USING btree (token)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = portal_links.tenant_org_id))))","roles":["authenticated"],"tablename":"portal_links","permissive":"PERMISSIVE","policyname":"Tenant members can manage portal links","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = portal_links.tenant_org_id))))"}],"triggers":[],"constraints":[{"name":"portal_links_pkey","definition":"PRIMARY KEY (id)"},{"name":"portal_links_token_key","definition":"UNIQUE (token)"}]},{"table":"profiles","schema":"public","columns":[{"name":"id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"role","type":"text","default":"'Rep'::text","identity":"","not_null":false,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"company","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_login","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"pin_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_drive_folder_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"drive_provisioned_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"drive_provisioning_status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"drive_provisioning_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"leaddeck_sheet_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"license_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_login_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"tcpa_certified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"assist_opt_in","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"elevenlabs_voice_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice_clone_consented_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice_clone_consent_typed_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice_clone_consent_ip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice_clone_consent_audio_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice_clone_sample_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice_clone_enrolled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice_clone_disabled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"daily_dial_goal","type":"integer","default":"50","identity":"","not_null":true,"generated":""},{"name":"daily_book_goal","type":"integer","default":"3","identity":"","not_null":true,"generated":""},{"name":"voice_clone_settings","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_profiles_inactive","definition":"CREATE INDEX idx_profiles_inactive ON public.profiles USING btree (id) WHERE (active = false)"},{"name":"idx_profiles_last_login_at","definition":"CREATE INDEX idx_profiles_last_login_at ON public.profiles USING btree (last_login_at)"},{"name":"profiles_email_key","definition":"CREATE UNIQUE INDEX profiles_email_key ON public.profiles USING btree (email)"},{"name":"profiles_pkey","definition":"CREATE UNIQUE INDEX profiles_pkey ON public.profiles USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"((id = ( SELECT uid() AS uid)) OR shares_tenant_as_manager_pm(( SELECT uid() AS uid), id))","roles":["authenticated"],"tablename":"profiles","permissive":"PERMISSIVE","policyname":"Managers view tenant team profiles","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"profiles","permissive":"PERMISSIVE","policyname":"profiles_insert_self_or_admin","schemaname":"public","with_check":"((id = ( SELECT uid() AS uid)) OR ( SELECT is_system_admin(uid()) AS is_system_admin))"},{"cmd":"SELECT","qual":"((id = ( SELECT uid() AS uid)) OR ( SELECT is_system_admin(uid()) AS is_system_admin))","roles":["authenticated"],"tablename":"profiles","permissive":"PERMISSIVE","policyname":"profiles_select_own_or_admin","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(id = ( SELECT uid() AS uid))","roles":["public"],"tablename":"profiles","permissive":"PERMISSIVE","policyname":"profiles_update_self_no_escalation","schemaname":"public","with_check":"((id = ( SELECT uid() AS uid)) AND profile_authority_unchanged(( SELECT uid() AS uid), role, tenant_org_id))"},{"cmd":"UPDATE","qual":"( SELECT is_system_admin(uid()) AS is_system_admin)","roles":["authenticated"],"tablename":"profiles","permissive":"PERMISSIVE","policyname":"profiles_update_system_admin","schemaname":"public","with_check":"( SELECT is_system_admin(uid()) AS is_system_admin)"},{"cmd":"SELECT","qual":"((id = uid()) OR is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM ((security_active_user_tenant_memberships utm_owner\n     JOIN user_roles ur ON (((ur.user_id = utm_owner.user_id) AND (ur.tenant_id = utm_owner.tenant_id))))\n     JOIN security_active_user_tenant_memberships utm_target ON (((utm_target.tenant_id = utm_owner.tenant_id) AND (utm_target.user_id = profiles.id))))\n  WHERE ((utm_owner.user_id = uid()) AND (utm_owner.status = 'active'::text) AND (utm_target.status = 'active'::text) AND ((utm_owner.is_owner = true) OR (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))))","roles":["authenticated"],"tablename":"profiles","permissive":"PERMISSIVE","policyname":"tenant_owners_view_team_profiles_safe","schemaname":"public","with_check":null}],"triggers":[{"name":"audit_trigger_profiles","definition":"CREATE TRIGGER audit_trigger_profiles AFTER INSERT OR DELETE OR UPDATE ON profiles FOR EACH ROW EXECUTE FUNCTION comprehensive_audit_trigger_fn()"},{"name":"throttle_profile_login_touch","definition":"CREATE TRIGGER throttle_profile_login_touch BEFORE UPDATE OF last_login, last_login_at ON profiles FOR EACH ROW EXECUTE FUNCTION throttle_profile_login_touch()"},{"name":"trg_audit_profile_phone","definition":"CREATE TRIGGER trg_audit_profile_phone AFTER UPDATE OF phone ON profiles FOR EACH ROW EXECUTE FUNCTION audit_phone_change()"},{"name":"trg_knocklaunch_profile_delete_to_auth","definition":"CREATE TRIGGER trg_knocklaunch_profile_delete_to_auth AFTER DELETE ON profiles FOR EACH ROW EXECUTE FUNCTION knocklaunch_sync_profile_delete_to_auth()"},{"name":"trg_knocklaunch_profiles_orphan_email_guard","definition":"CREATE TRIGGER trg_knocklaunch_profiles_orphan_email_guard BEFORE INSERT OR UPDATE OF email ON profiles FOR EACH ROW EXECUTE FUNCTION knocklaunch_remove_orphan_profile_email_conflict()"},{"name":"trg_protect_profile_phone","definition":"CREATE TRIGGER trg_protect_profile_phone BEFORE INSERT OR UPDATE OF phone ON profiles FOR EACH ROW EXECUTE FUNCTION protect_profile_phone()"},{"name":"update_profiles_updated_at","definition":"CREATE TRIGGER update_profiles_updated_at BEFORE UPDATE ON profiles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"profiles_email_key","definition":"UNIQUE (email)"},{"name":"profiles_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"property_assessments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"door_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"assessed_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assessed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"roof_condition","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_age","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_material","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"siding_condition","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"siding_material","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"gutters_condition","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"visible_damage","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority_score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"estimated_cost","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"urgency","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"photos","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_property_assessments_door_id","definition":"CREATE INDEX idx_property_assessments_door_id ON public.property_assessments USING btree (door_id)"},{"name":"idx_property_assessments_priority","definition":"CREATE INDEX idx_property_assessments_priority ON public.property_assessments USING btree (priority_score DESC)"},{"name":"idx_property_assessments_tenant","definition":"CREATE INDEX idx_property_assessments_tenant ON public.property_assessments USING btree (tenant_org_id)"},{"name":"property_assessments_pkey","definition":"CREATE UNIQUE INDEX property_assessments_pkey ON public.property_assessments USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = property_assessments.tenant_org_id))))","roles":["public"],"tablename":"property_assessments","permissive":"PERMISSIVE","policyname":"Tenant members view property assessments","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"property_assessments","permissive":"PERMISSIVE","policyname":"Users create property assessments","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = property_assessments.tenant_org_id))))"}],"triggers":[],"constraints":[{"name":"property_assessments_gutters_condition_check","definition":"CHECK (gutters_condition = ANY (ARRAY['Excellent'::text, 'Good'::text, 'Fair'::text, 'Poor'::text]))"},{"name":"property_assessments_pkey","definition":"PRIMARY KEY (id)"},{"name":"property_assessments_priority_score_check","definition":"CHECK (priority_score >= 1 AND priority_score <= 5)"},{"name":"property_assessments_roof_condition_check","definition":"CHECK (roof_condition = ANY (ARRAY['Excellent'::text, 'Good'::text, 'Fair'::text, 'Poor'::text, 'Severe Damage'::text]))"},{"name":"property_assessments_siding_condition_check","definition":"CHECK (siding_condition = ANY (ARRAY['Excellent'::text, 'Good'::text, 'Fair'::text, 'Poor'::text]))"},{"name":"property_assessments_urgency_check","definition":"CHECK (urgency = ANY (ARRAY['Low'::text, 'Medium'::text, 'High'::text, 'Critical'::text]))"}]},{"table":"property_data_enrichment_status","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"full_address","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"property_data_status","type":"text","default":"'unknown'::text","identity":"","not_null":true,"generated":""},{"name":"permit_data_status","type":"text","default":"'unknown'::text","identity":"","not_null":true,"generated":""},{"name":"jurisdiction_status","type":"text","default":"'unknown'::text","identity":"","not_null":true,"generated":""},{"name":"last_property_lookup_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_permit_lookup_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_jurisdiction_check_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_retry_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"manual_review_flag","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"pdes_tenant_idx","definition":"CREATE INDEX pdes_tenant_idx ON public.property_data_enrichment_status USING btree (tenant_org_id)"},{"name":"property_data_enrichment_status_pkey","definition":"CREATE UNIQUE INDEX property_data_enrichment_status_pkey ON public.property_data_enrichment_status USING btree (id)"},{"name":"property_data_enrichment_status_tenant_full_address_upsert_idx","definition":"CREATE UNIQUE INDEX property_data_enrichment_status_tenant_full_address_upsert_idx ON public.property_data_enrichment_status USING btree (tenant_org_id, full_address)"},{"name":"property_data_enrichment_status_unique","definition":"CREATE UNIQUE INDEX property_data_enrichment_status_unique ON public.property_data_enrichment_status USING btree (COALESCE(tenant_org_id, '00000000-0000-0000-0000-000000000000'::uuid), lower(full_address))"}],"policies":[{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))","roles":["authenticated"],"tablename":"property_data_enrichment_status","permissive":"PERMISSIVE","policyname":"pdes read tenant","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))","roles":["authenticated"],"tablename":"property_data_enrichment_status","permissive":"PERMISSIVE","policyname":"pdes write tenant","schemaname":"public","with_check":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))"}],"triggers":[{"name":"property_data_enrichment_status_updated_at","definition":"CREATE TRIGGER property_data_enrichment_status_updated_at BEFORE UPDATE ON property_data_enrichment_status FOR EACH ROW EXECUTE FUNCTION set_updated_at_simple()"}],"constraints":[{"name":"property_data_enrichment_status_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"property_intelligence","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"mortgage_status","type":"text","default":"'unknown'::text","identity":"","not_null":true,"generated":""},{"name":"mortgage_inferred_from","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mortgage_confidence","type":"text","default":"'low'::text","identity":"","not_null":true,"generated":""},{"name":"mortgage_lender","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mortgage_recorded_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_citizens_insured","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"carrier_detected","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"post_storm_permit","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"post_storm_permit_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"pre_storm_permit_age_days","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"enrichment_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_enriched_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_property_intelligence_citizens","definition":"CREATE INDEX idx_property_intelligence_citizens ON public.property_intelligence USING btree (tenant_org_id) WHERE (is_citizens_insured = true)"},{"name":"idx_property_intelligence_mortgage","definition":"CREATE INDEX idx_property_intelligence_mortgage ON public.property_intelligence USING btree (tenant_org_id, mortgage_status) WHERE (mortgage_status = 'active'::text)"},{"name":"idx_property_intelligence_post_storm_permit","definition":"CREATE INDEX idx_property_intelligence_post_storm_permit ON public.property_intelligence USING btree (tenant_org_id) WHERE (post_storm_permit = true)"},{"name":"idx_property_intelligence_tenant_contact","definition":"CREATE INDEX idx_property_intelligence_tenant_contact ON public.property_intelligence USING btree (tenant_org_id, contact_id)"},{"name":"property_intelligence_contact_unique","definition":"CREATE UNIQUE INDEX property_intelligence_contact_unique ON public.property_intelligence USING btree (tenant_org_id, contact_id)"},{"name":"property_intelligence_pkey","definition":"CREATE UNIQUE INDEX property_intelligence_pkey ON public.property_intelligence USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"property_intelligence","permissive":"PERMISSIVE","policyname":"system_admin_delete_property_intelligence","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"property_intelligence","permissive":"PERMISSIVE","policyname":"tenant_members_insert_property_intelligence","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"property_intelligence","permissive":"PERMISSIVE","policyname":"tenant_members_select_property_intelligence","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"property_intelligence","permissive":"PERMISSIVE","policyname":"tenant_members_update_property_intelligence","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))"}],"triggers":[{"name":"trg_property_intelligence_updated_at","definition":"CREATE TRIGGER trg_property_intelligence_updated_at BEFORE UPDATE ON property_intelligence FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"property_intelligence_contact_unique","definition":"UNIQUE (tenant_org_id, contact_id)"},{"name":"property_intelligence_mortgage_confidence_check","definition":"CHECK (mortgage_confidence = ANY (ARRAY['high'::text, 'medium'::text, 'low'::text]))"},{"name":"property_intelligence_mortgage_inferred_from_check","definition":"CHECK (mortgage_inferred_from IS NULL OR (mortgage_inferred_from = ANY (ARRAY['fdor'::text, 'recorder'::text, 'hybrid'::text])))"},{"name":"property_intelligence_mortgage_status_check","definition":"CHECK (mortgage_status = ANY (ARRAY['active'::text, 'paid_off'::text, 'unknown'::text]))"},{"name":"property_intelligence_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"property_jurisdiction_matches","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"full_address","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"parcel_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"latitude","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"longitude","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"county","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":"'FL'::text","identity":"","not_null":false,"generated":""},{"name":"permitting_authority","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"jurisdiction_confidence","type":"text","default":"'low'::text","identity":"","not_null":true,"generated":""},{"name":"jurisdiction_method","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"matched_boundary_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"manual_override_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"manual_override_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"manual_verification_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"property_jurisdiction_matches_addr_idx","definition":"CREATE INDEX property_jurisdiction_matches_addr_idx ON public.property_jurisdiction_matches USING btree (lower(full_address))"},{"name":"property_jurisdiction_matches_parcel_idx","definition":"CREATE INDEX property_jurisdiction_matches_parcel_idx ON public.property_jurisdiction_matches USING btree (parcel_id) WHERE (parcel_id IS NOT NULL)"},{"name":"property_jurisdiction_matches_pkey","definition":"CREATE UNIQUE INDEX property_jurisdiction_matches_pkey ON public.property_jurisdiction_matches USING btree (id)"},{"name":"property_jurisdiction_matches_tenant_idx","definition":"CREATE INDEX property_jurisdiction_matches_tenant_idx ON public.property_jurisdiction_matches USING btree (tenant_org_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"property_jurisdiction_matches","permissive":"PERMISSIVE","policyname":"jurisdiction insert tenant","schemaname":"public","with_check":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))"},{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))","roles":["authenticated"],"tablename":"property_jurisdiction_matches","permissive":"PERMISSIVE","policyname":"jurisdiction read tenant","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))","roles":["authenticated"],"tablename":"property_jurisdiction_matches","permissive":"PERMISSIVE","policyname":"jurisdiction update tenant","schemaname":"public","with_check":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))"}],"triggers":[{"name":"property_jurisdiction_matches_updated_at","definition":"CREATE TRIGGER property_jurisdiction_matches_updated_at BEFORE UPDATE ON property_jurisdiction_matches FOR EACH ROW EXECUTE FUNCTION set_updated_at_simple()"}],"constraints":[{"name":"property_jurisdiction_matches_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"property_permits","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"full_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"parcel_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"issue_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"final_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"expiration_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"contractor_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contractor_license","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"work_description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"declared_value","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"square_footage","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_jurisdiction","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_related","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"confidence_score","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"manually_verified","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"verified_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_payload","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"property_permits_addr_idx","definition":"CREATE INDEX property_permits_addr_idx ON public.property_permits USING btree (lower(full_address))"},{"name":"property_permits_contact_idx","definition":"CREATE INDEX property_permits_contact_idx ON public.property_permits USING btree (contact_id)"},{"name":"property_permits_pkey","definition":"CREATE UNIQUE INDEX property_permits_pkey ON public.property_permits USING btree (id)"},{"name":"property_permits_property_idx","definition":"CREATE INDEX property_permits_property_idx ON public.property_permits USING btree (property_id)"},{"name":"property_permits_roof_idx","definition":"CREATE INDEX property_permits_roof_idx ON public.property_permits USING btree (roof_related, issue_date DESC)"},{"name":"property_permits_tenant_idx","definition":"CREATE INDEX property_permits_tenant_idx ON public.property_permits USING btree (tenant_org_id)"},{"name":"property_permits_tenant_source_permit_upsert_idx","definition":"CREATE UNIQUE INDEX property_permits_tenant_source_permit_upsert_idx ON public.property_permits USING btree (tenant_org_id, source_jurisdiction, permit_number)"},{"name":"property_permits_unique_record","definition":"CREATE UNIQUE INDEX property_permits_unique_record ON public.property_permits USING btree (tenant_org_id, source_jurisdiction, permit_number) WHERE (permit_number IS NOT NULL)"}],"policies":[{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))","roles":["authenticated"],"tablename":"property_permits","permissive":"PERMISSIVE","policyname":"permits read tenant","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))","roles":["authenticated"],"tablename":"property_permits","permissive":"PERMISSIVE","policyname":"permits write tenant","schemaname":"public","with_check":"((tenant_org_id IS NULL) OR is_tenant_member((tenant_org_id)::text))"}],"triggers":[{"name":"property_permits_updated_at","definition":"CREATE TRIGGER property_permits_updated_at BEFORE UPDATE ON property_permits FOR EACH ROW EXECUTE FUNCTION set_updated_at_simple()"}],"constraints":[{"name":"property_permits_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"proposal_operating_commitments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contract_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"proposal_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"proposal_version","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"issuer_tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"acceptor_tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"party_role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"responsible_tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"commitment_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"category","type":"text","default":"'operating'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'proposed'::text","identity":"","not_null":true,"generated":""},{"name":"cadence","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"review_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"terms","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"evidence","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"activated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"proposal_operating_commitment_contract_id_party_role_commit_key","definition":"CREATE UNIQUE INDEX proposal_operating_commitment_contract_id_party_role_commit_key ON public.proposal_operating_commitments USING btree (contract_id, party_role, commitment_key)"},{"name":"proposal_operating_commitments_pkey","definition":"CREATE UNIQUE INDEX proposal_operating_commitments_pkey ON public.proposal_operating_commitments USING btree (id)"},{"name":"proposal_operating_commitments_proposal_idx","definition":"CREATE INDEX proposal_operating_commitments_proposal_idx ON public.proposal_operating_commitments USING btree (proposal_id, proposal_version)"},{"name":"proposal_operating_commitments_responsible_idx","definition":"CREATE INDEX proposal_operating_commitments_responsible_idx ON public.proposal_operating_commitments USING btree (responsible_tenant_id, status, review_at, due_at)"}],"policies":[{"cmd":"SELECT","qual":"(is_platform_admin(uid()) OR is_tenant_member(uid(), issuer_tenant_id) OR ((acceptor_tenant_id IS NOT NULL) AND is_tenant_member(uid(), acceptor_tenant_id)))","roles":["public"],"tablename":"proposal_operating_commitments","permissive":"PERMISSIVE","policyname":"proposal_operating_commitments_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"proposal_operating_commitment_contract_id_party_role_commit_key","definition":"UNIQUE (contract_id, party_role, commitment_key)"},{"name":"proposal_operating_commitments_acceptor_tenant_id_fkey","definition":"FOREIGN KEY (acceptor_tenant_id) REFERENCES tenants(id) ON DELETE SET NULL"},{"name":"proposal_operating_commitments_contract_id_fkey","definition":"FOREIGN KEY (contract_id) REFERENCES proposal_operating_contracts(id) ON DELETE CASCADE"},{"name":"proposal_operating_commitments_issuer_tenant_id_fkey","definition":"FOREIGN KEY (issuer_tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"proposal_operating_commitments_party_role_check","definition":"CHECK (party_role = ANY (ARRAY['issuer'::text, 'acceptor'::text, 'shared'::text]))"},{"name":"proposal_operating_commitments_pkey","definition":"PRIMARY KEY (id)"},{"name":"proposal_operating_commitments_proposal_id_fkey","definition":"FOREIGN KEY (proposal_id) REFERENCES proposals(id) ON DELETE CASCADE"},{"name":"proposal_operating_commitments_proposal_version_check","definition":"CHECK (proposal_version > 0)"},{"name":"proposal_operating_commitments_responsible_tenant_id_fkey","definition":"FOREIGN KEY (responsible_tenant_id) REFERENCES tenants(id) ON DELETE SET NULL"},{"name":"proposal_operating_commitments_status_check","definition":"CHECK (status = ANY (ARRAY['proposed'::text, 'active'::text, 'blocked'::text, 'completed'::text, 'waived'::text, 'ended'::text]))"}]},{"table":"proposal_operating_contract_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contract_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"proposal_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_type","type":"text","default":"'system'::text","identity":"","not_null":true,"generated":""},{"name":"source_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_data","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"dedupe_key","type":"text","default":null,"identity":"","not_null":true,"generated":""}],"indexes":[{"name":"proposal_operating_contract_events_dedupe_key_key","definition":"CREATE UNIQUE INDEX proposal_operating_contract_events_dedupe_key_key ON public.proposal_operating_contract_events USING btree (dedupe_key)"},{"name":"proposal_operating_contract_events_pkey","definition":"CREATE UNIQUE INDEX proposal_operating_contract_events_pkey ON public.proposal_operating_contract_events USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(is_platform_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM proposal_operating_contracts c\n  WHERE ((c.id = proposal_operating_contract_events.contract_id) AND (is_tenant_member(uid(), c.issuer_tenant_id) OR ((c.acceptor_tenant_id IS NOT NULL) AND is_tenant_member(uid(), c.acceptor_tenant_id)))))))","roles":["public"],"tablename":"proposal_operating_contract_events","permissive":"PERMISSIVE","policyname":"proposal_operating_contract_events_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"proposal_operating_contract_events_contract_id_fkey","definition":"FOREIGN KEY (contract_id) REFERENCES proposal_operating_contracts(id) ON DELETE CASCADE"},{"name":"proposal_operating_contract_events_dedupe_key_key","definition":"UNIQUE (dedupe_key)"},{"name":"proposal_operating_contract_events_event_type_check","definition":"CHECK (event_type = ANY (ARRAY['drafted'::text, 'sent'::text, 'received'::text, 'accepted'::text, 'activated'::text, 'declined'::text, 'voided'::text]))"},{"name":"proposal_operating_contract_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"proposal_operating_contract_events_proposal_id_fkey","definition":"FOREIGN KEY (proposal_id) REFERENCES proposals(id) ON DELETE CASCADE"}]},{"table":"proposal_operating_contracts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"proposal_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"proposal_version","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"issuer_tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"acceptor_tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lifecycle_status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"pending_agreement_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_agreement_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_pdf_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"accepted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"activated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"terms","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"proposal_operating_contracts_acceptor_idx","definition":"CREATE INDEX proposal_operating_contracts_acceptor_idx ON public.proposal_operating_contracts USING btree (acceptor_tenant_id, lifecycle_status, updated_at DESC)"},{"name":"proposal_operating_contracts_issuer_idx","definition":"CREATE INDEX proposal_operating_contracts_issuer_idx ON public.proposal_operating_contracts USING btree (issuer_tenant_id, lifecycle_status, updated_at DESC)"},{"name":"proposal_operating_contracts_pkey","definition":"CREATE UNIQUE INDEX proposal_operating_contracts_pkey ON public.proposal_operating_contracts USING btree (id)"},{"name":"proposal_operating_contracts_proposal_id_key","definition":"CREATE UNIQUE INDEX proposal_operating_contracts_proposal_id_key ON public.proposal_operating_contracts USING btree (proposal_id)"}],"policies":[{"cmd":"SELECT","qual":"(is_platform_admin(uid()) OR is_tenant_member(uid(), issuer_tenant_id) OR ((acceptor_tenant_id IS NOT NULL) AND is_tenant_member(uid(), acceptor_tenant_id)))","roles":["public"],"tablename":"proposal_operating_contracts","permissive":"PERMISSIVE","policyname":"proposal_operating_contracts_read","schemaname":"public","with_check":null}],"triggers":[{"name":"tg_enforce_proposal_operating_contract_activation_artifact","definition":"CREATE TRIGGER tg_enforce_proposal_operating_contract_activation_artifact BEFORE INSERT OR UPDATE ON proposal_operating_contracts FOR EACH ROW EXECUTE FUNCTION enforce_proposal_operating_contract_activation_artifact()"}],"constraints":[{"name":"proposal_operating_contracts_acceptor_tenant_id_fkey","definition":"FOREIGN KEY (acceptor_tenant_id) REFERENCES tenants(id) ON DELETE SET NULL"},{"name":"proposal_operating_contracts_issuer_tenant_id_fkey","definition":"FOREIGN KEY (issuer_tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"proposal_operating_contracts_lifecycle_status_check","definition":"CHECK (lifecycle_status = ANY (ARRAY['draft'::text, 'sent'::text, 'received'::text, 'accepted'::text, 'activated'::text, 'declined'::text, 'void'::text]))"},{"name":"proposal_operating_contracts_pending_agreement_id_fkey","definition":"FOREIGN KEY (pending_agreement_id) REFERENCES pending_agreements(id) ON DELETE SET NULL"},{"name":"proposal_operating_contracts_pkey","definition":"PRIMARY KEY (id)"},{"name":"proposal_operating_contracts_proposal_id_fkey","definition":"FOREIGN KEY (proposal_id) REFERENCES proposals(id) ON DELETE CASCADE"},{"name":"proposal_operating_contracts_proposal_id_key","definition":"UNIQUE (proposal_id)"},{"name":"proposal_operating_contracts_proposal_version_check","definition":"CHECK (proposal_version > 0)"},{"name":"proposal_operating_contracts_signed_agreement_id_fkey","definition":"FOREIGN KEY (signed_agreement_id) REFERENCES signed_agreements(id) ON DELETE SET NULL"}]},{"table":"proposal_profiles","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"profile_key","type":"text","default":"'default'::text","identity":"","not_null":true,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"number_prefix","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"renderer_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"proposal_profiles_one_active_per_tenant_idx","definition":"CREATE UNIQUE INDEX proposal_profiles_one_active_per_tenant_idx ON public.proposal_profiles USING btree (tenant_id) WHERE (status = 'active'::text)"},{"name":"proposal_profiles_pkey","definition":"CREATE UNIQUE INDEX proposal_profiles_pkey ON public.proposal_profiles USING btree (id)"},{"name":"proposal_profiles_tenant_id_profile_key_key","definition":"CREATE UNIQUE INDEX proposal_profiles_tenant_id_profile_key_key ON public.proposal_profiles USING btree (tenant_id, profile_key)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["public"],"tablename":"proposal_profiles","permissive":"PERMISSIVE","policyname":"proposal_profiles_member_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"proposal_profiles_pkey","definition":"PRIMARY KEY (id)"},{"name":"proposal_profiles_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'inactive'::text]))"},{"name":"proposal_profiles_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"proposal_profiles_tenant_id_profile_key_key","definition":"UNIQUE (tenant_id, profile_key)"},{"name":"proposal_profiles_version_check","definition":"CHECK (version > 0)"}]},{"table":"proposal_sequences","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"proposal_year","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"number_prefix","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"last_sequence","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"proposal_sequences_pkey","definition":"CREATE UNIQUE INDEX proposal_sequences_pkey ON public.proposal_sequences USING btree (tenant_id, proposal_year, number_prefix)"}],"policies":[],"triggers":[],"constraints":[{"name":"proposal_sequences_last_sequence_check","definition":"CHECK (last_sequence >= 0)"},{"name":"proposal_sequences_pkey","definition":"PRIMARY KEY (tenant_id, proposal_year, number_prefix)"},{"name":"proposal_sequences_proposal_year_check","definition":"CHECK (proposal_year >= 2000 AND proposal_year <= 2200)"},{"name":"proposal_sequences_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"proposal_versions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"proposal_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"version","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"snapshot","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"snapshot_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"render_bucket","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"render_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"render_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rendered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"proposal_versions_pkey","definition":"CREATE UNIQUE INDEX proposal_versions_pkey ON public.proposal_versions USING btree (id)"},{"name":"proposal_versions_proposal_id_version_key","definition":"CREATE UNIQUE INDEX proposal_versions_proposal_id_version_key ON public.proposal_versions USING btree (proposal_id, version)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["public"],"tablename":"proposal_versions","permissive":"PERMISSIVE","policyname":"proposal_versions_member_read","schemaname":"public","with_check":null}],"triggers":[{"name":"kl_proposal_version_content_immutable","definition":"CREATE TRIGGER kl_proposal_version_content_immutable BEFORE UPDATE ON proposal_versions FOR EACH ROW EXECUTE FUNCTION kl_proposal_version_content_immutable()"}],"constraints":[{"name":"proposal_versions_pkey","definition":"PRIMARY KEY (id)"},{"name":"proposal_versions_proposal_id_fkey","definition":"FOREIGN KEY (proposal_id) REFERENCES proposals(id) ON DELETE CASCADE"},{"name":"proposal_versions_proposal_id_version_key","definition":"UNIQUE (proposal_id, version)"},{"name":"proposal_versions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"proposal_versions_version_check","definition":"CHECK (version > 0)"}]},{"table":"proposals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"profile_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"proposal_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"current_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"idempotency_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_opportunity_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"offer_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"selected_option_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pricing_mode","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"currency","type":"text","default":"'USD'::text","identity":"","not_null":true,"generated":""},{"name":"recipient_snapshot","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"context_snapshot","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"line_items","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"subtotal_amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"adjustment_amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"tax_amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"total_amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"deposit_amount","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"balance_amount","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"terms","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"internal_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"profile_snapshot","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"brand_snapshot","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"commercial_snapshot","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"render_bucket","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"render_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"render_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"render_content_fingerprint","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rendered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"approved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"accepted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"declined_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"paid_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"voided_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"counterparty_tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"proposals_pkey","definition":"CREATE UNIQUE INDEX proposals_pkey ON public.proposals USING btree (id)"},{"name":"proposals_tenant_contact_idx","definition":"CREATE INDEX proposals_tenant_contact_idx ON public.proposals USING btree (tenant_id, source_contact_id, updated_at DESC)"},{"name":"proposals_tenant_event_idx","definition":"CREATE INDEX proposals_tenant_event_idx ON public.proposals USING btree (tenant_id, source_event_id, updated_at DESC)"},{"name":"proposals_tenant_id_proposal_number_key","definition":"CREATE UNIQUE INDEX proposals_tenant_id_proposal_number_key ON public.proposals USING btree (tenant_id, proposal_number)"},{"name":"proposals_tenant_idempotency_idx","definition":"CREATE UNIQUE INDEX proposals_tenant_idempotency_idx ON public.proposals USING btree (tenant_id, idempotency_key) WHERE (idempotency_key IS NOT NULL)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["public"],"tablename":"proposals","permissive":"PERMISSIVE","policyname":"proposals_member_read","schemaname":"public","with_check":null}],"triggers":[{"name":"proposals_business_activity","definition":"CREATE TRIGGER proposals_business_activity AFTER INSERT OR UPDATE ON proposals FOR EACH ROW EXECUTE FUNCTION project_proposal_business_activity()"},{"name":"tg_sync_proposal_render_to_document_family","definition":"CREATE TRIGGER tg_sync_proposal_render_to_document_family BEFORE INSERT OR UPDATE OF render_path, render_hash ON proposals FOR EACH ROW WHEN (new.render_path IS NOT NULL AND new.render_hash IS NOT NULL) EXECUTE FUNCTION sync_proposal_render_to_document_family()"}],"constraints":[{"name":"proposals_counterparty_tenant_id_fkey","definition":"FOREIGN KEY (counterparty_tenant_id) REFERENCES tenants(id) ON DELETE SET NULL"},{"name":"proposals_current_version_check","definition":"CHECK (current_version > 0)"},{"name":"proposals_pkey","definition":"PRIMARY KEY (id)"},{"name":"proposals_profile_id_fkey","definition":"FOREIGN KEY (profile_id) REFERENCES proposal_profiles(id)"},{"name":"proposals_source_contact_id_fkey","definition":"FOREIGN KEY (source_contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"proposals_source_event_id_fkey","definition":"FOREIGN KEY (source_event_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"proposals_source_opportunity_id_fkey","definition":"FOREIGN KEY (source_opportunity_id) REFERENCES business_opportunities(id) ON DELETE SET NULL"},{"name":"proposals_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'sent'::text, 'approved'::text, 'accepted'::text, 'declined'::text, 'paid'::text, 'void'::text]))"},{"name":"proposals_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"proposals_tenant_id_proposal_number_key","definition":"UNIQUE (tenant_id, proposal_number)"},{"name":"proposals_verified_render_contract","definition":"CHECK (render_bucket IS NULL AND render_path IS NULL AND render_hash IS NULL AND render_content_fingerprint IS NULL AND rendered_at IS NULL OR render_bucket IS NOT NULL AND render_path IS NOT NULL AND render_hash IS NOT NULL AND render_content_fingerprint IS NOT NULL AND rendered_at IS NOT NULL)"}]},{"table":"qr_campaigns","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"intent_type","type":"text","default":"'lead'::text","identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"utm_source","type":"text","default":"'qr'::text","identity":"","not_null":false,"generated":""},{"name":"utm_medium","type":"text","default":"'offline'::text","identity":"","not_null":false,"generated":""},{"name":"utm_campaign","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"starts_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"ends_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_qr_campaigns_tenant_created","definition":"CREATE INDEX idx_qr_campaigns_tenant_created ON public.qr_campaigns USING btree (tenant_id, created_at DESC)"},{"name":"qr_campaigns_pkey","definition":"CREATE UNIQUE INDEX qr_campaigns_pkey ON public.qr_campaigns USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"qr_campaigns_intent_check","definition":"CHECK (intent_type = ANY (ARRAY['lead'::text, 'booking'::text, 'profile'::text, 'review'::text, 'service'::text, 'platform'::text, 'custom'::text]))"},{"name":"qr_campaigns_pkey","definition":"PRIMARY KEY (id)"},{"name":"qr_campaigns_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"qr_campaigns_tenant_or_platform_check","definition":"CHECK (tenant_id IS NOT NULL OR intent_type = 'platform'::text)"}]},{"table":"qr_codes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"short_code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"type","type":"text","default":"'lead'::text","identity":"","not_null":true,"generated":""},{"name":"destination_mode","type":"text","default":"'external_url'::text","identity":"","not_null":true,"generated":""},{"name":"destination_value","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"fallback_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rules","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"design","type":"jsonb","default":"'{\"frameText\": \"Scan to connect\", \"background\": \"#ffffff\", \"foreground\": \"#111827\", \"logoEnabled\": false, \"errorCorrectionLevel\": \"H\"}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_qr_codes_short_code","definition":"CREATE INDEX idx_qr_codes_short_code ON public.qr_codes USING btree (short_code)"},{"name":"idx_qr_codes_tenant_created","definition":"CREATE INDEX idx_qr_codes_tenant_created ON public.qr_codes USING btree (tenant_id, created_at DESC)"},{"name":"qr_codes_pkey","definition":"CREATE UNIQUE INDEX qr_codes_pkey ON public.qr_codes USING btree (id)"},{"name":"qr_codes_short_code_key","definition":"CREATE UNIQUE INDEX qr_codes_short_code_key ON public.qr_codes USING btree (short_code)"}],"policies":[],"triggers":[],"constraints":[{"name":"qr_codes_campaign_id_fkey","definition":"FOREIGN KEY (campaign_id) REFERENCES qr_campaigns(id) ON DELETE SET NULL"},{"name":"qr_codes_destination_mode_check","definition":"CHECK (destination_mode = ANY (ARRAY['internal_route'::text, 'external_url'::text, 'rules'::text]))"},{"name":"qr_codes_pkey","definition":"PRIMARY KEY (id)"},{"name":"qr_codes_short_code_format","definition":"CHECK (short_code ~ '^[a-zA-Z0-9_-]{5,48}$'::text)"},{"name":"qr_codes_short_code_key","definition":"UNIQUE (short_code)"},{"name":"qr_codes_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"qr_codes_tenant_or_platform_check","definition":"CHECK (tenant_id IS NOT NULL OR type = 'platform'::text)"},{"name":"qr_codes_type_check","definition":"CHECK (type = ANY (ARRAY['lead'::text, 'booking'::text, 'profile'::text, 'review'::text, 'service'::text, 'platform'::text, 'custom'::text]))"}]},{"table":"qr_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"qr_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":"'scan'::text","identity":"","not_null":true,"generated":""},{"name":"session_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"device_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"referrer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"destination_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_qr_events_campaign_created","definition":"CREATE INDEX idx_qr_events_campaign_created ON public.qr_events USING btree (campaign_id, created_at DESC)"},{"name":"idx_qr_events_qr_created","definition":"CREATE INDEX idx_qr_events_qr_created ON public.qr_events USING btree (qr_id, created_at DESC)"},{"name":"idx_qr_events_tenant_created","definition":"CREATE INDEX idx_qr_events_tenant_created ON public.qr_events USING btree (tenant_id, created_at DESC)"},{"name":"qr_events_pkey","definition":"CREATE UNIQUE INDEX qr_events_pkey ON public.qr_events USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"qr_events_campaign_id_fkey","definition":"FOREIGN KEY (campaign_id) REFERENCES qr_campaigns(id) ON DELETE SET NULL"},{"name":"qr_events_event_type_check","definition":"CHECK (event_type = ANY (ARRAY['scan'::text, 'redirect'::text, 'conversion'::text, 'error'::text]))"},{"name":"qr_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"qr_events_qr_id_fkey","definition":"FOREIGN KEY (qr_id) REFERENCES qr_codes(id) ON DELETE CASCADE"},{"name":"qr_events_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"queue_callbacks","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"ring_group_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"from_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"to_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"requested_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"assigned_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"attempts","type":"smallint","default":"0","identity":"","not_null":true,"generated":""},{"name":"last_attempt_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_queue_callbacks_tenant_status","definition":"CREATE INDEX idx_queue_callbacks_tenant_status ON public.queue_callbacks USING btree (tenant_org_id, status, requested_at)"},{"name":"queue_callbacks_pkey","definition":"CREATE UNIQUE INDEX queue_callbacks_pkey ON public.queue_callbacks USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"queue_callbacks","permissive":"PERMISSIVE","policyname":"queue_callbacks_delete_managers","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"queue_callbacks","permissive":"PERMISSIVE","policyname":"queue_callbacks_insert_managers","schemaname":"public","with_check":"is_manager_or_higher(uid(), tenant_org_id)"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"queue_callbacks","permissive":"PERMISSIVE","policyname":"queue_callbacks_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_manager_or_higher(uid(), tenant_org_id) OR (assigned_user_id = uid()))","roles":["authenticated"],"tablename":"queue_callbacks","permissive":"PERMISSIVE","policyname":"queue_callbacks_update_assigned_or_manager","schemaname":"public","with_check":"(is_manager_or_higher(uid(), tenant_org_id) OR (assigned_user_id = uid()))"}],"triggers":[{"name":"trg_queue_callbacks_updated_at","definition":"CREATE TRIGGER trg_queue_callbacks_updated_at BEFORE UPDATE ON queue_callbacks FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"queue_callbacks_pkey","definition":"PRIMARY KEY (id)"},{"name":"queue_callbacks_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'in_progress'::text, 'completed'::text, 'failed'::text, 'cancelled'::text]))"}]},{"table":"quickbooks_entity_mappings","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"realm_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"quickbooks_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"sync_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"quickbooks_updated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"normalized","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"raw_entity","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"last_synced_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"quickbooks_entity_mappings_pkey","definition":"CREATE UNIQUE INDEX quickbooks_entity_mappings_pkey ON public.quickbooks_entity_mappings USING btree (id)"},{"name":"quickbooks_entity_mappings_tenant_id_realm_id_entity_type_q_key","definition":"CREATE UNIQUE INDEX quickbooks_entity_mappings_tenant_id_realm_id_entity_type_q_key ON public.quickbooks_entity_mappings USING btree (tenant_id, realm_id, entity_type, quickbooks_id)"},{"name":"quickbooks_entity_mappings_tenant_realm_idx","definition":"CREATE INDEX quickbooks_entity_mappings_tenant_realm_idx ON public.quickbooks_entity_mappings USING btree (tenant_id, realm_id, entity_type)"}],"policies":[],"triggers":[],"constraints":[{"name":"quickbooks_entity_mappings_entity_type_check","definition":"CHECK (entity_type = ANY (ARRAY['Customer'::text, 'Invoice'::text, 'Payment'::text, 'Item'::text, 'Account'::text, 'TaxCode'::text, 'TaxRate'::text, 'Term'::text, 'Vendor'::text, 'Bill'::text, 'Estimate'::text, 'CreditMemo'::text, 'JournalEntry'::text, 'Class'::text, 'Department'::text]))"},{"name":"quickbooks_entity_mappings_pkey","definition":"PRIMARY KEY (id)"},{"name":"quickbooks_entity_mappings_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"quickbooks_entity_mappings_tenant_id_realm_id_entity_type_q_key","definition":"UNIQUE (tenant_id, realm_id, entity_type, quickbooks_id)"}]},{"table":"quickbooks_sync_state","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"realm_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"last_successful_sync_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_cursor","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"quickbooks_sync_state_pkey","definition":"CREATE UNIQUE INDEX quickbooks_sync_state_pkey ON public.quickbooks_sync_state USING btree (tenant_id, realm_id, entity_type)"}],"policies":[],"triggers":[],"constraints":[{"name":"quickbooks_sync_state_pkey","definition":"PRIMARY KEY (tenant_id, realm_id, entity_type)"},{"name":"quickbooks_sync_state_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"realtor_campaign_activities","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"campaign_property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"activity_type","type":"text","default":"'note'::text","identity":"","not_null":true,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_rca_campaign","definition":"CREATE INDEX idx_rca_campaign ON public.realtor_campaign_activities USING btree (campaign_id)"},{"name":"idx_rca_created","definition":"CREATE INDEX idx_rca_created ON public.realtor_campaign_activities USING btree (created_at DESC)"},{"name":"idx_rca_property","definition":"CREATE INDEX idx_rca_property ON public.realtor_campaign_activities USING btree (property_id)"},{"name":"idx_rca_tenant","definition":"CREATE INDEX idx_rca_tenant ON public.realtor_campaign_activities USING btree (tenant_id)"},{"name":"realtor_campaign_activities_pkey","definition":"CREATE UNIQUE INDEX realtor_campaign_activities_pkey ON public.realtor_campaign_activities USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_campaign_activities","permissive":"PERMISSIVE","policyname":"rca_delete_owner","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"realtor_campaign_activities","permissive":"PERMISSIVE","policyname":"rca_insert_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_campaign_activities","permissive":"PERMISSIVE","policyname":"rca_select_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_campaign_activities","permissive":"PERMISSIVE","policyname":"rca_update_owner","schemaname":"public","with_check":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())"}],"triggers":[],"constraints":[{"name":"realtor_campaign_activities_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"realtor_campaign_outreach_queue","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_property_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"channel","type":"text","default":"'call'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""},{"name":"script_preview","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_rcoq_assigned","definition":"CREATE INDEX idx_rcoq_assigned ON public.realtor_campaign_outreach_queue USING btree (assigned_user_id, status)"},{"name":"idx_rcoq_campaign_property","definition":"CREATE INDEX idx_rcoq_campaign_property ON public.realtor_campaign_outreach_queue USING btree (campaign_property_id)"},{"name":"idx_rcoq_tenant_campaign","definition":"CREATE INDEX idx_rcoq_tenant_campaign ON public.realtor_campaign_outreach_queue USING btree (tenant_id, campaign_id, status)"},{"name":"realtor_campaign_outreach_queue_pkey","definition":"CREATE UNIQUE INDEX realtor_campaign_outreach_queue_pkey ON public.realtor_campaign_outreach_queue USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_campaign_outreach_queue","permissive":"PERMISSIVE","policyname":"rcoq_delete_owner","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"realtor_campaign_outreach_queue","permissive":"PERMISSIVE","policyname":"rcoq_insert_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_campaign_outreach_queue","permissive":"PERMISSIVE","policyname":"rcoq_select_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"realtor_campaign_outreach_queue","permissive":"PERMISSIVE","policyname":"rcoq_update_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_rcoq_tenant_guard","definition":"CREATE TRIGGER trg_rcoq_tenant_guard BEFORE INSERT OR UPDATE ON realtor_campaign_outreach_queue FOR EACH ROW EXECUTE FUNCTION trg_rcoq_tenant_guard()"},{"name":"trg_rcoq_updated_at","definition":"CREATE TRIGGER trg_rcoq_updated_at BEFORE UPDATE ON realtor_campaign_outreach_queue FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"realtor_campaign_outreach_queue_channel_check","definition":"CHECK (channel = ANY (ARRAY['call'::text, 'door_knock'::text, 'sms_preview'::text, 'email_preview'::text]))"},{"name":"realtor_campaign_outreach_queue_pkey","definition":"PRIMARY KEY (id)"},{"name":"realtor_campaign_outreach_queue_status_check","definition":"CHECK (status = ANY (ARRAY['queued'::text, 'in_progress'::text, 'completed'::text, 'skipped'::text, 'do_not_contact'::text]))"}]},{"table":"realtor_campaign_properties","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""},{"name":"added_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"added_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_action_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_rcp_campaign","definition":"CREATE INDEX idx_rcp_campaign ON public.realtor_campaign_properties USING btree (campaign_id)"},{"name":"idx_rcp_property","definition":"CREATE INDEX idx_rcp_property ON public.realtor_campaign_properties USING btree (property_id)"},{"name":"idx_rcp_status","definition":"CREATE INDEX idx_rcp_status ON public.realtor_campaign_properties USING btree (status)"},{"name":"idx_rcp_tenant","definition":"CREATE INDEX idx_rcp_tenant ON public.realtor_campaign_properties USING btree (tenant_id)"},{"name":"realtor_campaign_properties_campaign_id_property_id_key","definition":"CREATE UNIQUE INDEX realtor_campaign_properties_campaign_id_property_id_key ON public.realtor_campaign_properties USING btree (campaign_id, property_id)"},{"name":"realtor_campaign_properties_pkey","definition":"CREATE UNIQUE INDEX realtor_campaign_properties_pkey ON public.realtor_campaign_properties USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_campaign_properties","permissive":"PERMISSIVE","policyname":"rcp_delete_owner","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"realtor_campaign_properties","permissive":"PERMISSIVE","policyname":"rcp_insert_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_campaign_properties","permissive":"PERMISSIVE","policyname":"rcp_select_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"realtor_campaign_properties","permissive":"PERMISSIVE","policyname":"rcp_update_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_rcp_tenant_guard","definition":"CREATE TRIGGER trg_rcp_tenant_guard BEFORE INSERT OR UPDATE ON realtor_campaign_properties FOR EACH ROW EXECUTE FUNCTION realtor_campaign_property_tenant_guard()"},{"name":"trg_rcp_updated","definition":"CREATE TRIGGER trg_rcp_updated BEFORE UPDATE ON realtor_campaign_properties FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"realtor_campaign_properties_campaign_id_property_id_key","definition":"UNIQUE (campaign_id, property_id)"},{"name":"realtor_campaign_properties_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"realtor_campaigns","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"campaign_type","type":"text","default":"'custom'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"target_area","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip_codes","type":"text[]","default":"ARRAY[]::text[]","identity":"","not_null":false,"generated":""},{"name":"tags","type":"text[]","default":"ARRAY[]::text[]","identity":"","not_null":false,"generated":""},{"name":"script_template","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sms_template","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"landing_page_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"approval_status","type":"text","default":"'not_required'::text","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_realtor_campaigns_status","definition":"CREATE INDEX idx_realtor_campaigns_status ON public.realtor_campaigns USING btree (status)"},{"name":"idx_realtor_campaigns_tenant","definition":"CREATE INDEX idx_realtor_campaigns_tenant ON public.realtor_campaigns USING btree (tenant_id)"},{"name":"realtor_campaigns_pkey","definition":"CREATE UNIQUE INDEX realtor_campaigns_pkey ON public.realtor_campaigns USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_campaigns","permissive":"PERMISSIVE","policyname":"rc_delete_owner","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"realtor_campaigns","permissive":"PERMISSIVE","policyname":"rc_insert_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_campaigns","permissive":"PERMISSIVE","policyname":"rc_select_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"realtor_campaigns","permissive":"PERMISSIVE","policyname":"rc_update_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_rc_updated","definition":"CREATE TRIGGER trg_rc_updated BEFORE UPDATE ON realtor_campaigns FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"realtor_campaigns_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"realtor_lead_assignments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"previous_assigned_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_assigned_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"changed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_rla_lead","definition":"CREATE INDEX idx_rla_lead ON public.realtor_lead_assignments USING btree (lead_id)"},{"name":"idx_rla_tenant","definition":"CREATE INDEX idx_rla_tenant ON public.realtor_lead_assignments USING btree (tenant_id)"},{"name":"realtor_lead_assignments_pkey","definition":"CREATE UNIQUE INDEX realtor_lead_assignments_pkey ON public.realtor_lead_assignments USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"realtor_lead_assignments","permissive":"PERMISSIVE","policyname":"rla_insert_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_lead_assignments","permissive":"PERMISSIVE","policyname":"rla_select_member","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"realtor_lead_assignments_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"realtor_properties","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"parcel_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_mailing_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"occupancy_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"absentee_owner","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"estimated_equity","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_sale_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_tags","type":"text[]","default":"ARRAY[]::text[]","identity":"","not_null":false,"generated":""},{"name":"event_tags","type":"text[]","default":"ARRAY[]::text[]","identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_realtor_properties_address","definition":"CREATE INDEX idx_realtor_properties_address ON public.realtor_properties USING btree (lower(address))"},{"name":"idx_realtor_properties_tenant","definition":"CREATE INDEX idx_realtor_properties_tenant ON public.realtor_properties USING btree (tenant_id)"},{"name":"idx_realtor_properties_zip","definition":"CREATE INDEX idx_realtor_properties_zip ON public.realtor_properties USING btree (zip)"},{"name":"realtor_properties_pkey","definition":"CREATE UNIQUE INDEX realtor_properties_pkey ON public.realtor_properties USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_properties","permissive":"PERMISSIVE","policyname":"rp_delete_owner","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"realtor_properties","permissive":"PERMISSIVE","policyname":"rp_insert_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_properties","permissive":"PERMISSIVE","policyname":"rp_select_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"realtor_properties","permissive":"PERMISSIVE","policyname":"rp_update_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_rp_updated","definition":"CREATE TRIGGER trg_rp_updated BEFORE UPDATE ON realtor_properties FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"realtor_properties_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"realtor_property_contacts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"relationship_type","type":"text","default":"'owner'::text","identity":"","not_null":false,"generated":""},{"name":"is_primary","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_rpc_contact","definition":"CREATE INDEX idx_rpc_contact ON public.realtor_property_contacts USING btree (contact_id)"},{"name":"idx_rpc_property","definition":"CREATE INDEX idx_rpc_property ON public.realtor_property_contacts USING btree (property_id)"},{"name":"idx_rpc_tenant","definition":"CREATE INDEX idx_rpc_tenant ON public.realtor_property_contacts USING btree (tenant_id)"},{"name":"realtor_property_contacts_pkey","definition":"CREATE UNIQUE INDEX realtor_property_contacts_pkey ON public.realtor_property_contacts USING btree (id)"},{"name":"realtor_property_contacts_property_id_contact_id_relationsh_key","definition":"CREATE UNIQUE INDEX realtor_property_contacts_property_id_contact_id_relationsh_key ON public.realtor_property_contacts USING btree (property_id, contact_id, relationship_type)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_property_contacts","permissive":"PERMISSIVE","policyname":"rpc_delete_member","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"realtor_property_contacts","permissive":"PERMISSIVE","policyname":"rpc_insert_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_property_contacts","permissive":"PERMISSIVE","policyname":"rpc_select_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"realtor_property_contacts","permissive":"PERMISSIVE","policyname":"rpc_update_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[],"constraints":[{"name":"realtor_property_contacts_pkey","definition":"PRIMARY KEY (id)"},{"name":"realtor_property_contacts_property_id_contact_id_relationsh_key","definition":"UNIQUE (property_id, contact_id, relationship_type)"}]},{"table":"realtor_reports","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"report_type","type":"text","default":"'property_market_snapshot'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'requested'::text","identity":"","not_null":true,"generated":""},{"name":"requested_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"requested_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"viewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"appointment_set_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"delivery_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_rr_property","definition":"CREATE INDEX idx_rr_property ON public.realtor_reports USING btree (property_id)"},{"name":"idx_rr_status","definition":"CREATE INDEX idx_rr_status ON public.realtor_reports USING btree (status)"},{"name":"idx_rr_tenant","definition":"CREATE INDEX idx_rr_tenant ON public.realtor_reports USING btree (tenant_id)"},{"name":"realtor_reports_pkey","definition":"CREATE UNIQUE INDEX realtor_reports_pkey ON public.realtor_reports USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_reports","permissive":"PERMISSIVE","policyname":"rr_delete_owner","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"realtor_reports","permissive":"PERMISSIVE","policyname":"rr_insert_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_reports","permissive":"PERMISSIVE","policyname":"rr_select_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"realtor_reports","permissive":"PERMISSIVE","policyname":"rr_update_owner","schemaname":"public","with_check":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())"}],"triggers":[{"name":"trg_rr_updated","definition":"CREATE TRIGGER trg_rr_updated BEFORE UPDATE ON realtor_reports FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"realtor_reports_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"realtor_transactions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"transaction_side","type":"realtor_transaction_side","default":"'listing_side'::realtor_transaction_side","identity":"","not_null":true,"generated":""},{"name":"status","type":"realtor_transaction_status","default":"'pending'::realtor_transaction_status","identity":"","not_null":true,"generated":""},{"name":"property_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mls_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sale_price","type":"numeric(14,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"commission_pct","type":"numeric(6,3)","default":null,"identity":"","not_null":false,"generated":""},{"name":"gross_commission","type":"numeric(14,2)","default":"((COALESCE(sale_price, (0)::numeric) * COALESCE(commission_pct, (0)::numeric)) / (100)::numeric)","identity":"","not_null":false,"generated":"s"},{"name":"split_pct_to_agent","type":"numeric(6,3)","default":"100","identity":"","not_null":false,"generated":""},{"name":"brokerage_fee","type":"numeric(14,2)","default":"0","identity":"","not_null":false,"generated":""},{"name":"referral_fee_pct","type":"numeric(6,3)","default":"0","identity":"","not_null":false,"generated":""},{"name":"net_to_agent","type":"numeric(14,2)","default":"((((((COALESCE(sale_price, (0)::numeric) * COALESCE(commission_pct, (0)::numeric)) / (100)::numeric) * COALESCE(split_pct_to_agent, (100)::numeric)) / (100)::numeric) * ((1)::numeric - (COALESCE(referral_fee_pct, (0)::numeric) / (100)::numeric))) - COALESCE(brokerage_fee, (0)::numeric))","identity":"","not_null":false,"generated":"s"},{"name":"expected_close_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"actual_close_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"paid_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_to","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"is_demo","type":"boolean","default":"false","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_realtor_transactions_close","definition":"CREATE INDEX idx_realtor_transactions_close ON public.realtor_transactions USING btree (tenant_id, expected_close_date)"},{"name":"idx_realtor_transactions_contact","definition":"CREATE INDEX idx_realtor_transactions_contact ON public.realtor_transactions USING btree (contact_id)"},{"name":"idx_realtor_transactions_status","definition":"CREATE INDEX idx_realtor_transactions_status ON public.realtor_transactions USING btree (tenant_id, status)"},{"name":"idx_realtor_transactions_tenant","definition":"CREATE INDEX idx_realtor_transactions_tenant ON public.realtor_transactions USING btree (tenant_id)"},{"name":"realtor_transactions_pkey","definition":"CREATE UNIQUE INDEX realtor_transactions_pkey ON public.realtor_transactions USING btree (id)"},{"name":"realtor_transactions_tenant_demo_status_idx","definition":"CREATE INDEX realtor_transactions_tenant_demo_status_idx ON public.realtor_transactions USING btree (tenant_id, is_demo, status)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_owner(uid(), tenant_id)","roles":["authenticated"],"tablename":"realtor_transactions","permissive":"PERMISSIVE","policyname":"rt_delete_owner","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"realtor_transactions","permissive":"PERMISSIVE","policyname":"rt_insert_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_id)","roles":["authenticated"],"tablename":"realtor_transactions","permissive":"PERMISSIVE","policyname":"rt_select_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(uid(), tenant_id) AND (is_tenant_owner(uid(), tenant_id) OR (assigned_to = (jwt() ->> 'email'::text)) OR (assigned_to = (uid())::text)))","roles":["authenticated"],"tablename":"realtor_transactions","permissive":"PERMISSIVE","policyname":"rt_update_member","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_id)"}],"triggers":[{"name":"trg_realtor_transactions_updated_at","definition":"CREATE TRIGGER trg_realtor_transactions_updated_at BEFORE UPDATE ON realtor_transactions FOR EACH ROW EXECUTE FUNCTION touch_realtor_transactions_updated_at()"}],"constraints":[{"name":"realtor_transactions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"reassigned_number_checks","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_normalized","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"date_used","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"date_source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":"'fcc_rnd'::text","identity":"","not_null":true,"generated":""},{"name":"rnd_response","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"vendor_reference_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rnd_status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"raw_response","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"checked_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_rnd_tenant_phone","definition":"CREATE INDEX idx_rnd_tenant_phone ON public.reassigned_number_checks USING btree (tenant_org_id, phone_normalized, checked_at DESC)"},{"name":"reassigned_number_checks_pkey","definition":"CREATE UNIQUE INDEX reassigned_number_checks_pkey ON public.reassigned_number_checks USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"reassigned_number_checks","permissive":"PERMISSIVE","policyname":"tenant_members_insert_rnd","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"reassigned_number_checks","permissive":"PERMISSIVE","policyname":"tenant_members_view_rnd","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"reassigned_number_checks_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"rebuttal_usage_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"call_session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"rebuttal_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"objection_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rebuttal_length","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_rue_lead","definition":"CREATE INDEX idx_rue_lead ON public.rebuttal_usage_events USING btree (lead_id)"},{"name":"idx_rue_rebuttal","definition":"CREATE INDEX idx_rue_rebuttal ON public.rebuttal_usage_events USING btree (rebuttal_id)"},{"name":"idx_rue_tenant_created","definition":"CREATE INDEX idx_rue_tenant_created ON public.rebuttal_usage_events USING btree (tenant_org_id, created_at DESC)"},{"name":"rebuttal_usage_events_pkey","definition":"CREATE UNIQUE INDEX rebuttal_usage_events_pkey ON public.rebuttal_usage_events USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"rebuttal_usage_events","permissive":"PERMISSIVE","policyname":"Tenant members can insert rebuttal usage","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) AND (user_id = uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin())","roles":["authenticated"],"tablename":"rebuttal_usage_events","permissive":"PERMISSIVE","policyname":"Tenant members can view rebuttal usage","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"rebuttal_usage_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"rebuttal_usage_events_source_check","definition":"CHECK (source = ANY (ARRAY['live_coach'::text, 'rescue_panel'::text, 'save_the_sale'::text, 'manual'::text]))"}]},{"table":"referrals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"from_tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"to_tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"person_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"referral_type","type":"text","default":"'general'::text","identity":"","not_null":true,"generated":""},{"name":"referral_status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"urgency","type":"text","default":"'normal'::text","identity":"","not_null":false,"generated":""},{"name":"contact_data","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_referrals_from_tenant","definition":"CREATE INDEX idx_referrals_from_tenant ON public.referrals USING btree (from_tenant_id)"},{"name":"idx_referrals_status","definition":"CREATE INDEX idx_referrals_status ON public.referrals USING btree (referral_status)"},{"name":"idx_referrals_to_tenant","definition":"CREATE INDEX idx_referrals_to_tenant ON public.referrals USING btree (to_tenant_id)"},{"name":"referrals_pkey","definition":"CREATE UNIQUE INDEX referrals_pkey ON public.referrals USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"referrals","permissive":"PERMISSIVE","policyname":"members_create_referrals","schemaname":"public","with_check":"is_tenant_member((from_tenant_id)::text)"},{"cmd":"UPDATE","qual":"(is_tenant_member((from_tenant_id)::text) OR is_tenant_member((to_tenant_id)::text) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"referrals","permissive":"PERMISSIVE","policyname":"participants_update_referrals","schemaname":"public","with_check":"(is_tenant_member((from_tenant_id)::text) OR is_tenant_member((to_tenant_id)::text) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member((from_tenant_id)::text) OR is_tenant_member((to_tenant_id)::text) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"referrals","permissive":"PERMISSIVE","policyname":"participants_view_referrals","schemaname":"public","with_check":null}],"triggers":[{"name":"update_referrals_updated_at","definition":"CREATE TRIGGER update_referrals_updated_at BEFORE UPDATE ON referrals FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"referrals_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"rep_auth_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"rep_email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"result","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"ip_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"timestamp","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"rep_auth_log_pkey","definition":"CREATE UNIQUE INDEX rep_auth_log_pkey ON public.rep_auth_log USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"rep_auth_log","permissive":"PERMISSIVE","policyname":"platform_admin_view_rep_auth_log","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"rep_auth_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"rep_leads","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'Active'::text","identity":"","not_null":false,"generated":""},{"name":"stage","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_rep_leads_email","definition":"CREATE INDEX idx_rep_leads_email ON public.rep_leads USING btree (rep_email)"},{"name":"idx_rep_leads_tenant","definition":"CREATE INDEX idx_rep_leads_tenant ON public.rep_leads USING btree (tenant_org_id)"},{"name":"rep_leads_pkey","definition":"CREATE UNIQUE INDEX rep_leads_pkey ON public.rep_leads USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"rep_leads","permissive":"PERMISSIVE","policyname":"rep_leads_godmode","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"(rep_email = (( SELECT users.email\n   FROM users\n  WHERE (users.id = uid())))::text)","roles":["public"],"tablename":"rep_leads","permissive":"PERMISSIVE","policyname":"rep_leads_self_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(rep_email = (( SELECT users.email\n   FROM users\n  WHERE (users.id = uid())))::text)","roles":["public"],"tablename":"rep_leads","permissive":"PERMISSIVE","policyname":"rep_leads_self_update","schemaname":"public","with_check":"(rep_email = (( SELECT users.email\n   FROM users\n  WHERE (users.id = uid())))::text)"},{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"rep_leads","permissive":"PERMISSIVE","policyname":"rep_leads_tenant_owner_admin","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))"},{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"rep_leads","permissive":"PERMISSIVE","policyname":"rl_all","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (rep_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"rep_leads","permissive":"PERMISSIVE","policyname":"tenant_users_delete_rep_leads","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"rep_leads","permissive":"PERMISSIVE","policyname":"tenant_users_insert_rep_leads","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (rep_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (rep_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"rep_leads","permissive":"PERMISSIVE","policyname":"tenant_users_update_rep_leads","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (rep_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (rep_leads.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"rep_leads","permissive":"PERMISSIVE","policyname":"tenant_users_view_rep_leads","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"rep_leads_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"rep_verified_caller_ids","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"friendly_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"twilio_validation_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"twilio_caller_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"forward_to_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sms_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status_callback_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice_recording_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"voicemail_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"voicemail_greeting","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"forward_sms_enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_rep_caller_ids_one_default_per_user","definition":"CREATE UNIQUE INDEX idx_rep_caller_ids_one_default_per_user ON public.rep_verified_caller_ids USING btree (user_id) WHERE (is_default = true)"},{"name":"idx_rep_verified_caller_ids_tenant","definition":"CREATE INDEX idx_rep_verified_caller_ids_tenant ON public.rep_verified_caller_ids USING btree (tenant_org_id)"},{"name":"idx_rep_verified_caller_ids_user","definition":"CREATE INDEX idx_rep_verified_caller_ids_user ON public.rep_verified_caller_ids USING btree (user_id)"},{"name":"rep_verified_caller_ids_pkey","definition":"CREATE UNIQUE INDEX rep_verified_caller_ids_pkey ON public.rep_verified_caller_ids USING btree (id)"},{"name":"rep_verified_caller_ids_user_id_phone_number_key","definition":"CREATE UNIQUE INDEX rep_verified_caller_ids_user_id_phone_number_key ON public.rep_verified_caller_ids USING btree (user_id, phone_number)"}],"policies":[{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_org_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"rep_verified_caller_ids","permissive":"PERMISSIVE","policyname":"Tenant members view tenant caller IDs","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"rep_verified_caller_ids","permissive":"PERMISSIVE","policyname":"Users delete own caller IDs","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"rep_verified_caller_ids","permissive":"PERMISSIVE","policyname":"Users insert own caller IDs","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"UPDATE","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"rep_verified_caller_ids","permissive":"PERMISSIVE","policyname":"Users update own caller IDs","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"SELECT","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"rep_verified_caller_ids","permissive":"PERMISSIVE","policyname":"Users view own caller IDs","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_audit_forward_phone","definition":"CREATE TRIGGER trg_audit_forward_phone AFTER UPDATE OF forward_to_phone ON rep_verified_caller_ids FOR EACH ROW EXECUTE FUNCTION audit_phone_change()"},{"name":"trg_protect_forward_phone","definition":"CREATE TRIGGER trg_protect_forward_phone BEFORE INSERT OR UPDATE OF forward_to_phone ON rep_verified_caller_ids FOR EACH ROW EXECUTE FUNCTION protect_forward_phone()"},{"name":"trg_rep_verified_caller_ids_updated_at","definition":"CREATE TRIGGER trg_rep_verified_caller_ids_updated_at BEFORE UPDATE ON rep_verified_caller_ids FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"rep_verified_caller_ids_pkey","definition":"PRIMARY KEY (id)"},{"name":"rep_verified_caller_ids_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'verified'::text, 'failed'::text, 'expired'::text]))"},{"name":"rep_verified_caller_ids_user_id_phone_number_key","definition":"UNIQUE (user_id, phone_number)"}]},{"table":"repo_agent_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mode","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"http_status","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"ok","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"request_summary","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_repo_agent_audit_created","definition":"CREATE INDEX idx_repo_agent_audit_created ON public.repo_agent_audit USING btree (created_at DESC)"},{"name":"idx_repo_agent_audit_session","definition":"CREATE INDEX idx_repo_agent_audit_session ON public.repo_agent_audit USING btree (session_id)"},{"name":"repo_agent_audit_pkey","definition":"CREATE UNIQUE INDEX repo_agent_audit_pkey ON public.repo_agent_audit USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_repo_agent_admin()","roles":["authenticated"],"tablename":"repo_agent_audit","permissive":"PERMISSIVE","policyname":"repo_agent_audit_admin_select","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"false","roles":["authenticated"],"tablename":"repo_agent_audit","permissive":"PERMISSIVE","policyname":"repo_agent_audit_no_client_write","schemaname":"public","with_check":"false"}],"triggers":[],"constraints":[{"name":"repo_agent_audit_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"repo_agent_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"mode","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"token_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"ended_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_repo_agent_sessions_expires","definition":"CREATE INDEX idx_repo_agent_sessions_expires ON public.repo_agent_sessions USING btree (expires_at)"},{"name":"idx_repo_agent_sessions_user","definition":"CREATE INDEX idx_repo_agent_sessions_user ON public.repo_agent_sessions USING btree (user_id)"},{"name":"repo_agent_sessions_pkey","definition":"CREATE UNIQUE INDEX repo_agent_sessions_pkey ON public.repo_agent_sessions USING btree (id)"},{"name":"repo_agent_sessions_token_hash_key","definition":"CREATE UNIQUE INDEX repo_agent_sessions_token_hash_key ON public.repo_agent_sessions USING btree (token_hash)"}],"policies":[{"cmd":"SELECT","qual":"is_repo_agent_admin()","roles":["authenticated"],"tablename":"repo_agent_sessions","permissive":"PERMISSIVE","policyname":"repo_agent_sessions_admin_select","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"false","roles":["authenticated"],"tablename":"repo_agent_sessions","permissive":"PERMISSIVE","policyname":"repo_agent_sessions_no_client_write","schemaname":"public","with_check":"false"}],"triggers":[],"constraints":[{"name":"repo_agent_sessions_mode_check","definition":"CHECK (mode = ANY (ARRAY['standard'::text, 'elevated'::text]))"},{"name":"repo_agent_sessions_pkey","definition":"PRIMARY KEY (id)"},{"name":"repo_agent_sessions_token_hash_key","definition":"UNIQUE (token_hash)"}]},{"table":"report_definitions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"character varying(255)","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"report_type","type":"character varying(50)","default":null,"identity":"","not_null":true,"generated":""},{"name":"config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"chart_config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"is_public","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"report_definitions_pkey","definition":"CREATE UNIQUE INDEX report_definitions_pkey ON public.report_definitions USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"report_definitions","permissive":"PERMISSIVE","policyname":"Users can manage reports","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"report_definitions","permissive":"PERMISSIVE","policyname":"Users can view own tenant reports","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"report_definitions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"revocation_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_normalized","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"channel","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"trigger_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"matched_keyword","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_message_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_call_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"auto_suppressed","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"acknowledged_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_revocation_tenant_phone","definition":"CREATE INDEX idx_revocation_tenant_phone ON public.revocation_events USING btree (tenant_org_id, phone_normalized, created_at DESC)"},{"name":"revocation_events_pkey","definition":"CREATE UNIQUE INDEX revocation_events_pkey ON public.revocation_events USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"revocation_events","permissive":"PERMISSIVE","policyname":"tenant_members_insert_revocation","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"revocation_events","permissive":"PERMISSIVE","policyname":"tenant_members_view_revocation","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_revocation_to_dnc","definition":"CREATE TRIGGER trg_revocation_to_dnc AFTER INSERT ON revocation_events FOR EACH ROW EXECUTE FUNCTION apply_revocation_to_dnc()"}],"constraints":[{"name":"revocation_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"ring_group_members","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"ring_group_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"priority","type":"smallint","default":"0","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_ring_group_members_user","definition":"CREATE INDEX idx_ring_group_members_user ON public.ring_group_members USING btree (user_id)"},{"name":"ring_group_members_pkey","definition":"CREATE UNIQUE INDEX ring_group_members_pkey ON public.ring_group_members USING btree (id)"},{"name":"uq_ring_group_member","definition":"CREATE UNIQUE INDEX uq_ring_group_member ON public.ring_group_members USING btree (ring_group_id, user_id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"ring_group_members","permissive":"PERMISSIVE","policyname":"ring_group_members_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"ring_group_members","permissive":"PERMISSIVE","policyname":"ring_group_members_write_managers","schemaname":"public","with_check":"is_manager_or_higher(uid(), tenant_org_id)"}],"triggers":[],"constraints":[{"name":"ring_group_members_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"ring_groups","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"strategy","type":"text","default":"'round_robin'::text","identity":"","not_null":true,"generated":""},{"name":"ring_seconds_per_leg","type":"smallint","default":"15","identity":"","not_null":true,"generated":""},{"name":"max_wait_seconds","type":"smallint","default":"90","identity":"","not_null":true,"generated":""},{"name":"hold_music_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"overflow_action","type":"text","default":"'callback'::text","identity":"","not_null":true,"generated":""},{"name":"overflow_target_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_rung_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_ring_groups_tenant","definition":"CREATE INDEX idx_ring_groups_tenant ON public.ring_groups USING btree (tenant_org_id)"},{"name":"ring_groups_pkey","definition":"CREATE UNIQUE INDEX ring_groups_pkey ON public.ring_groups USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"ring_groups","permissive":"PERMISSIVE","policyname":"ring_groups_select_tenant_members","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"ring_groups","permissive":"PERMISSIVE","policyname":"ring_groups_write_managers","schemaname":"public","with_check":"is_manager_or_higher(uid(), tenant_org_id)"}],"triggers":[{"name":"trg_ring_groups_updated_at","definition":"CREATE TRIGGER trg_ring_groups_updated_at BEFORE UPDATE ON ring_groups FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"ring_groups_overflow_action_check","definition":"CHECK (overflow_action = ANY (ARRAY['callback'::text, 'voicemail'::text, 'hangup'::text, 'ring_group'::text]))"},{"name":"ring_groups_pkey","definition":"PRIMARY KEY (id)"},{"name":"ring_groups_strategy_check","definition":"CHECK (strategy = ANY (ARRAY['simultaneous'::text, 'round_robin'::text, 'longest_idle'::text]))"}]},{"table":"rls_policy_changes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"changed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"changed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"table_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"policy_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"operation","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"old_definition","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_definition","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"rls_policy_changes_pkey","definition":"CREATE UNIQUE INDEX rls_policy_changes_pkey ON public.rls_policy_changes USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"rls_policy_changes","permissive":"PERMISSIVE","policyname":"platform_admin_manage_rls_changes","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"rls_policy_changes_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"role_permissions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"permission_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"role_permissions_pkey","definition":"CREATE UNIQUE INDEX role_permissions_pkey ON public.role_permissions USING btree (id)"},{"name":"role_permissions_role_permission_key_tenant_id_key","definition":"CREATE UNIQUE INDEX role_permissions_role_permission_key_tenant_id_key ON public.role_permissions USING btree (role, permission_key, tenant_id)"}],"policies":[{"cmd":"SELECT","qual":"true","roles":["authenticated"],"tablename":"role_permissions","permissive":"PERMISSIVE","policyname":"Role permissions viewable by authenticated users","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"role_permissions_pkey","definition":"PRIMARY KEY (id)"},{"name":"role_permissions_role_permission_key_tenant_id_key","definition":"UNIQUE (role, permission_key, tenant_id)"}]},{"table":"roof_estimate_reports","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"estimate_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"report_type","type":"text","default":"'measurement'::text","identity":"","not_null":false,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":false,"generated":""},{"name":"pdf_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pdf_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"file_size_bytes","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"generated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"generated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"report_data","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_roof_estimate_reports_estimate","definition":"CREATE INDEX idx_roof_estimate_reports_estimate ON public.roof_estimate_reports USING btree (estimate_id)"},{"name":"idx_roof_estimate_reports_tenant","definition":"CREATE INDEX idx_roof_estimate_reports_tenant ON public.roof_estimate_reports USING btree (tenant_org_id)"},{"name":"roof_estimate_reports_pkey","definition":"CREATE UNIQUE INDEX roof_estimate_reports_pkey ON public.roof_estimate_reports USING btree (id)"},{"name":"unique_estimate_version","definition":"CREATE UNIQUE INDEX unique_estimate_version ON public.roof_estimate_reports USING btree (estimate_id, version)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roof_estimate_reports","permissive":"PERMISSIVE","policyname":"Users create reports","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"roof_estimate_reports","permissive":"PERMISSIVE","policyname":"Users view tenant reports","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"roof_estimate_reports_pkey","definition":"PRIMARY KEY (id)"},{"name":"unique_estimate_version","definition":"UNIQUE (estimate_id, version)"}]},{"table":"roof_estimate_versions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"estimate_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"version_number","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"snapshot","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"changed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"change_summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_estimate_versions_estimate","definition":"CREATE INDEX idx_estimate_versions_estimate ON public.roof_estimate_versions USING btree (estimate_id)"},{"name":"roof_estimate_versions_estimate_id_version_number_key","definition":"CREATE UNIQUE INDEX roof_estimate_versions_estimate_id_version_number_key ON public.roof_estimate_versions USING btree (estimate_id, version_number)"},{"name":"roof_estimate_versions_pkey","definition":"CREATE UNIQUE INDEX roof_estimate_versions_pkey ON public.roof_estimate_versions USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roof_estimate_versions","permissive":"PERMISSIVE","policyname":"Tenant members insert estimate versions","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM roof_estimates re\n  WHERE ((re.id = roof_estimate_versions.estimate_id) AND is_tenant_member(re.tenant_org_id))))"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM roof_estimates re\n  WHERE ((re.id = roof_estimate_versions.estimate_id) AND is_tenant_member(re.tenant_org_id))))","roles":["public"],"tablename":"roof_estimate_versions","permissive":"PERMISSIVE","policyname":"Tenant members view estimate versions","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"roof_estimate_versions_estimate_id_version_number_key","definition":"UNIQUE (estimate_id, version_number)"},{"name":"roof_estimate_versions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"roof_estimates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"total_squares","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"pitch","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pitch_degrees","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"layers","type":"integer","default":"1","identity":"","not_null":false,"generated":""},{"name":"waste_factor","type":"numeric","default":"10","identity":"","not_null":false,"generated":""},{"name":"material_cost_total","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"labor_cost_total","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"dump_fees","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"permits_fees","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"other_costs","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"subtotal","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"margin_pct","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"tax_pct","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"total_job_price","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"line_items","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"polygon_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"calculation_metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"approved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"facet_count","type":"integer","default":"1","identity":"","not_null":false,"generated":""},{"name":"predominant_pitch","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pitched_area_sqft","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"flat_area_sqft","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"linear_measurements","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"facet_details","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"aerial_image_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"report_pdf_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"report_pdf_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"squares","type":"numeric","default":"round((total_squares * ((1)::numeric + (COALESCE(waste_factor, (10)::numeric) / (100)::numeric))), 1)","identity":"","not_null":false,"generated":"s"},{"name":"total_sqft","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"pitch_ratio","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"overhead_pct","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"commission_pct","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"pricing_mode","type":"text","default":"'retail'::text","identity":"","not_null":false,"generated":""},{"name":"approval_status","type":"text","default":"'draft'::text","identity":"","not_null":false,"generated":""},{"name":"approved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"rejection_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_roof_estimates_approval","definition":"CREATE INDEX idx_roof_estimates_approval ON public.roof_estimates USING btree (approval_status)"},{"name":"idx_roof_estimates_report","definition":"CREATE INDEX idx_roof_estimates_report ON public.roof_estimates USING btree (report_pdf_path) WHERE (report_pdf_path IS NOT NULL)"},{"name":"idx_roof_estimates_tenant_contact_updated","definition":"CREATE INDEX idx_roof_estimates_tenant_contact_updated ON public.roof_estimates USING btree (tenant_org_id, contact_id, updated_at DESC)"},{"name":"roof_estimates_pkey","definition":"CREATE UNIQUE INDEX roof_estimates_pkey ON public.roof_estimates USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"roof_estimates","permissive":"PERMISSIVE","policyname":"re_all","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (roof_estimates.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"roof_estimates","permissive":"PERMISSIVE","policyname":"tenant_users_delete_roof_estimates","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"roof_estimates","permissive":"PERMISSIVE","policyname":"tenant_users_insert_roof_estimates","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (roof_estimates.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (roof_estimates.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"roof_estimates","permissive":"PERMISSIVE","policyname":"tenant_users_update_roof_estimates","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (roof_estimates.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (roof_estimates.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"roof_estimates","permissive":"PERMISSIVE","policyname":"tenant_users_view_roof_estimates","schemaname":"public","with_check":null}],"triggers":[{"name":"roof_estimates_business_activity","definition":"CREATE TRIGGER roof_estimates_business_activity AFTER INSERT OR UPDATE ON roof_estimates FOR EACH ROW EXECUTE FUNCTION project_roof_estimate_business_activity()"}],"constraints":[{"name":"roof_estimates_pkey","definition":"PRIMARY KEY (id)"},{"name":"roof_estimates_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'sent'::text, 'approved'::text, 'rejected'::text]))"}]},{"table":"roof_help_funnel_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"session_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"landing_path","type":"text","default":"'/'::text","identity":"","not_null":true,"generated":""},{"name":"market_slug","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_slug","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"utm_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"utm_medium","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"utm_campaign","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"utm_content","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"acquisition_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"referrer_host","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"visitor_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"proof_internal","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"roof_help_funnel_events_pkey","definition":"CREATE UNIQUE INDEX roof_help_funnel_events_pkey ON public.roof_help_funnel_events USING btree (id)"},{"name":"roof_help_funnel_events_session_event_landing_key","definition":"CREATE UNIQUE INDEX roof_help_funnel_events_session_event_landing_key ON public.roof_help_funnel_events USING btree (session_id, event_name, landing_path)"},{"name":"roof_help_funnel_events_tenant_event_occurred_idx","definition":"CREATE INDEX roof_help_funnel_events_tenant_event_occurred_idx ON public.roof_help_funnel_events USING btree (tenant_org_id, event_name, occurred_at DESC)"},{"name":"roof_help_funnel_events_tenant_occurred_idx","definition":"CREATE INDEX roof_help_funnel_events_tenant_occurred_idx ON public.roof_help_funnel_events USING btree (tenant_org_id, occurred_at DESC)"},{"name":"roof_help_funnel_events_visitor_hash_created_idx","definition":"CREATE INDEX roof_help_funnel_events_visitor_hash_created_idx ON public.roof_help_funnel_events USING btree (visitor_hash, created_at DESC) WHERE (visitor_hash IS NOT NULL)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin() OR is_tenant_member(tenant_org_id))","roles":["authenticated"],"tablename":"roof_help_funnel_events","permissive":"PERMISSIVE","policyname":"Roof Help Finder members can view funnel events","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"roof_help_funnel_events_event_name_check","definition":"CHECK (event_name = ANY (ARRAY['page_view'::text, 'roof_help_cta_open'::text, 'form_started'::text, 'address_verified'::text, 'submit_attempt'::text, 'submit_success'::text, 'submit_error'::text]))"},{"name":"roof_help_funnel_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"roof_help_funnel_events_session_event_landing_key","definition":"UNIQUE (session_id, event_name, landing_path)"}]},{"table":"roof_measurement_jobs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"requested_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""},{"name":"stage","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""},{"name":"progress","type":"integer","default":"5","identity":"","not_null":true,"generated":""},{"name":"request_payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"result","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"return_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"attempt_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"roof_measurement_jobs_pkey","definition":"CREATE UNIQUE INDEX roof_measurement_jobs_pkey ON public.roof_measurement_jobs USING btree (id)"},{"name":"roof_measurement_jobs_requester_status_idx","definition":"CREATE INDEX roof_measurement_jobs_requester_status_idx ON public.roof_measurement_jobs USING btree (requested_by, status, updated_at DESC)"},{"name":"roof_measurement_jobs_tenant_updated_idx","definition":"CREATE INDEX roof_measurement_jobs_tenant_updated_idx ON public.roof_measurement_jobs USING btree (tenant_org_id, updated_at DESC)"}],"policies":[],"triggers":[],"constraints":[{"name":"roof_measurement_jobs_pkey","definition":"PRIMARY KEY (id)"},{"name":"roof_measurement_jobs_progress_check","definition":"CHECK (progress >= 0 AND progress <= 100)"},{"name":"roof_measurement_jobs_requested_by_fkey","definition":"FOREIGN KEY (requested_by) REFERENCES users(id) ON DELETE CASCADE"},{"name":"roof_measurement_jobs_status_check","definition":"CHECK (status = ANY (ARRAY['queued'::text, 'running'::text, 'complete'::text, 'failed'::text]))"},{"name":"roof_measurement_jobs_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"roof_price_book","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"item_code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'material'::text","identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"unit","type":"text","default":"'SQ'::text","identity":"","not_null":true,"generated":""},{"name":"unit_price","type":"numeric","default":"0","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_roof_price_book_tenant","definition":"CREATE INDEX idx_roof_price_book_tenant ON public.roof_price_book USING btree (tenant_org_id)"},{"name":"roof_price_book_pkey","definition":"CREATE UNIQUE INDEX roof_price_book_pkey ON public.roof_price_book USING btree (id)"},{"name":"roof_price_book_tenant_org_id_item_code_key","definition":"CREATE UNIQUE INDEX roof_price_book_tenant_org_id_item_code_key ON public.roof_price_book USING btree (tenant_org_id, item_code)"}],"policies":[{"cmd":"DELETE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"roof_price_book","permissive":"PERMISSIVE","policyname":"Users delete tenant price book","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roof_price_book","permissive":"PERMISSIVE","policyname":"Users manage tenant price book","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"roof_price_book","permissive":"PERMISSIVE","policyname":"Users update tenant price book","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"roof_price_book","permissive":"PERMISSIVE","policyname":"Users view tenant price book","schemaname":"public","with_check":null}],"triggers":[{"name":"roof_price_book_updated_at","definition":"CREATE TRIGGER roof_price_book_updated_at BEFORE UPDATE ON roof_price_book FOR EACH ROW EXECUTE FUNCTION update_roof_price_book_updated_at()"}],"constraints":[{"name":"roof_price_book_pkey","definition":"PRIMARY KEY (id)"},{"name":"roof_price_book_tenant_org_id_item_code_key","definition":"UNIQUE (tenant_org_id, item_code)"}]},{"table":"roof_price_book_items","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"item_code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'material'::text","identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"unit","type":"text","default":"'SQ'::text","identity":"","not_null":true,"generated":""},{"name":"unit_price","type":"numeric","default":"0","identity":"","not_null":true,"generated":""},{"name":"sort_order","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"roof_type","type":"text","default":"'shingle'::text","identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_price_book_roof_type","definition":"CREATE INDEX idx_price_book_roof_type ON public.roof_price_book_items USING btree (roof_type)"},{"name":"idx_price_book_tenant","definition":"CREATE INDEX idx_price_book_tenant ON public.roof_price_book_items USING btree (tenant_org_id)"},{"name":"roof_price_book_items_pkey","definition":"CREATE UNIQUE INDEX roof_price_book_items_pkey ON public.roof_price_book_items USING btree (id)"},{"name":"roof_price_book_items_tenant_org_id_item_code_roof_type_key","definition":"CREATE UNIQUE INDEX roof_price_book_items_tenant_org_id_item_code_roof_type_key ON public.roof_price_book_items USING btree (tenant_org_id, item_code, roof_type)"}],"policies":[{"cmd":"DELETE","qual":"is_tenant_member(tenant_org_id)","roles":["public"],"tablename":"roof_price_book_items","permissive":"PERMISSIVE","policyname":"Tenant members delete price book","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roof_price_book_items","permissive":"PERMISSIVE","policyname":"Tenant members insert price book","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"},{"cmd":"UPDATE","qual":"is_tenant_member(tenant_org_id)","roles":["public"],"tablename":"roof_price_book_items","permissive":"PERMISSIVE","policyname":"Tenant members update price book","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["public"],"tablename":"roof_price_book_items","permissive":"PERMISSIVE","policyname":"Tenant members view price book","schemaname":"public","with_check":null}],"triggers":[{"name":"roof_price_book_updated_at","definition":"CREATE TRIGGER roof_price_book_updated_at BEFORE UPDATE ON roof_price_book_items FOR EACH ROW EXECUTE FUNCTION update_roof_price_book_updated_at()"}],"constraints":[{"name":"roof_price_book_items_pkey","definition":"PRIMARY KEY (id)"},{"name":"roof_price_book_items_tenant_org_id_item_code_roof_type_key","definition":"UNIQUE (tenant_org_id, item_code, roof_type)"}]},{"table":"roofing_closeout","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"final_photos_complete","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"completion_certificate_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"completion_certificate_complete","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"warranty_registered","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"warranty_provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"warranty_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"final_invoice_sent","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"final_payment_received","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"lien_release_complete","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"review_requested","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"review_completed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"referral_requested","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"referral_received","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"homeowner_handoff_complete","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"closed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"roofing_closeout_job_id_key","definition":"CREATE UNIQUE INDEX roofing_closeout_job_id_key ON public.roofing_closeout USING btree (job_id)"},{"name":"roofing_closeout_pkey","definition":"CREATE UNIQUE INDEX roofing_closeout_pkey ON public.roofing_closeout USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_closeout","permissive":"PERMISSIVE","policyname":"roofing_ops_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roofing_closeout","permissive":"PERMISSIVE","policyname":"roofing_ops_insert","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"},{"cmd":"SELECT","qual":"roofing_ops_can_read(tenant_id)","roles":["public"],"tablename":"roofing_closeout","permissive":"PERMISSIVE","policyname":"roofing_ops_read","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_closeout","permissive":"PERMISSIVE","policyname":"roofing_ops_update","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"}],"triggers":[{"name":"roofing_ops_touch_updated_at","definition":"CREATE TRIGGER roofing_ops_touch_updated_at BEFORE UPDATE ON roofing_closeout FOR EACH ROW EXECUTE FUNCTION roofing_ops_touch_updated_at()"}],"constraints":[{"name":"roofing_closeout_job_id_fkey","definition":"FOREIGN KEY (job_id) REFERENCES jobs(id) ON DELETE CASCADE"},{"name":"roofing_closeout_job_id_key","definition":"UNIQUE (job_id)"},{"name":"roofing_closeout_pkey","definition":"PRIMARY KEY (id)"},{"name":"roofing_closeout_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"roofing_commissions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"payee_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"basis_amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"rate_pct","type":"numeric(7,3)","default":"0","identity":"","not_null":true,"generated":""},{"name":"amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'projected'::text","identity":"","not_null":true,"generated":""},{"name":"earned_at","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"paid_at","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"roofing_commissions_job_idx","definition":"CREATE INDEX roofing_commissions_job_idx ON public.roofing_commissions USING btree (tenant_id, job_id, created_at DESC)"},{"name":"roofing_commissions_pkey","definition":"CREATE UNIQUE INDEX roofing_commissions_pkey ON public.roofing_commissions USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_commissions","permissive":"PERMISSIVE","policyname":"roofing_ops_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roofing_commissions","permissive":"PERMISSIVE","policyname":"roofing_ops_insert","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"},{"cmd":"SELECT","qual":"roofing_ops_can_read(tenant_id)","roles":["public"],"tablename":"roofing_commissions","permissive":"PERMISSIVE","policyname":"roofing_ops_read","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_commissions","permissive":"PERMISSIVE","policyname":"roofing_ops_update","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"}],"triggers":[{"name":"roofing_ops_touch_updated_at","definition":"CREATE TRIGGER roofing_ops_touch_updated_at BEFORE UPDATE ON roofing_commissions FOR EACH ROW EXECUTE FUNCTION roofing_ops_touch_updated_at()"}],"constraints":[{"name":"roofing_commissions_job_id_fkey","definition":"FOREIGN KEY (job_id) REFERENCES jobs(id) ON DELETE CASCADE"},{"name":"roofing_commissions_pkey","definition":"PRIMARY KEY (id)"},{"name":"roofing_commissions_status_check","definition":"CHECK (status = ANY (ARRAY['projected'::text, 'earned'::text, 'approved'::text, 'payable'::text, 'paid'::text, 'void'::text]))"},{"name":"roofing_commissions_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"roofing_cost_entries","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"cost_type","type":"text","default":"'actual'::text","identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"vendor","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reference","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"incurred_on","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"roofing_cost_entries_job_idx","definition":"CREATE INDEX roofing_cost_entries_job_idx ON public.roofing_cost_entries USING btree (tenant_id, job_id, created_at DESC)"},{"name":"roofing_cost_entries_pkey","definition":"CREATE UNIQUE INDEX roofing_cost_entries_pkey ON public.roofing_cost_entries USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_cost_entries","permissive":"PERMISSIVE","policyname":"roofing_ops_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roofing_cost_entries","permissive":"PERMISSIVE","policyname":"roofing_ops_insert","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"},{"cmd":"SELECT","qual":"roofing_ops_can_read(tenant_id)","roles":["public"],"tablename":"roofing_cost_entries","permissive":"PERMISSIVE","policyname":"roofing_ops_read","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_cost_entries","permissive":"PERMISSIVE","policyname":"roofing_ops_update","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"}],"triggers":[],"constraints":[{"name":"roofing_cost_entries_category_check","definition":"CHECK (category = ANY (ARRAY['materials'::text, 'labor'::text, 'subcontractor'::text, 'permit'::text, 'dump'::text, 'equipment'::text, 'commission'::text, 'financing_fee'::text, 'other'::text]))"},{"name":"roofing_cost_entries_cost_type_check","definition":"CHECK (cost_type = ANY (ARRAY['estimated'::text, 'committed'::text, 'actual'::text]))"},{"name":"roofing_cost_entries_job_id_fkey","definition":"FOREIGN KEY (job_id) REFERENCES jobs(id) ON DELETE CASCADE"},{"name":"roofing_cost_entries_pkey","definition":"PRIMARY KEY (id)"},{"name":"roofing_cost_entries_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"roofing_insurance_financials","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"acv","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"rcv","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"deductible","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"depreciation_withheld","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"depreciation_recovered","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"carrier_payment_received","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"mortgage_check_amount","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"mortgage_check_status","type":"text","default":"'not_applicable'::text","identity":"","not_null":true,"generated":""},{"name":"customer_out_of_pocket","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"roofing_insurance_financials_job_id_key","definition":"CREATE UNIQUE INDEX roofing_insurance_financials_job_id_key ON public.roofing_insurance_financials USING btree (job_id)"},{"name":"roofing_insurance_financials_pkey","definition":"CREATE UNIQUE INDEX roofing_insurance_financials_pkey ON public.roofing_insurance_financials USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_insurance_financials","permissive":"PERMISSIVE","policyname":"roofing_ops_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roofing_insurance_financials","permissive":"PERMISSIVE","policyname":"roofing_ops_insert","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"},{"cmd":"SELECT","qual":"roofing_ops_can_read(tenant_id)","roles":["public"],"tablename":"roofing_insurance_financials","permissive":"PERMISSIVE","policyname":"roofing_ops_read","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_insurance_financials","permissive":"PERMISSIVE","policyname":"roofing_ops_update","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"}],"triggers":[{"name":"roofing_ops_touch_updated_at","definition":"CREATE TRIGGER roofing_ops_touch_updated_at BEFORE UPDATE ON roofing_insurance_financials FOR EACH ROW EXECUTE FUNCTION roofing_ops_touch_updated_at()"}],"constraints":[{"name":"roofing_insurance_financials_job_id_fkey","definition":"FOREIGN KEY (job_id) REFERENCES jobs(id) ON DELETE CASCADE"},{"name":"roofing_insurance_financials_job_id_key","definition":"UNIQUE (job_id)"},{"name":"roofing_insurance_financials_mortgage_check_status_check","definition":"CHECK (mortgage_check_status = ANY (ARRAY['not_applicable'::text, 'not_received'::text, 'received'::text, 'endorsement_needed'::text, 'sent_for_endorsement'::text, 'returned'::text, 'deposited'::text, 'blocked'::text]))"},{"name":"roofing_insurance_financials_pkey","definition":"PRIMARY KEY (id)"},{"name":"roofing_insurance_financials_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"roofing_material_orders","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"estimate_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"supplier_provider","type":"text","default":"'manual'::text","identity":"","not_null":true,"generated":""},{"name":"supplier_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"supplier_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"supplier_branch","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"delivery_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"subtotal","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"tax","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"total","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"line_items","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"external_order_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ordered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"delivered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"roofing_material_orders_job_idx","definition":"CREATE INDEX roofing_material_orders_job_idx ON public.roofing_material_orders USING btree (tenant_id, job_id, created_at DESC)"},{"name":"roofing_material_orders_pkey","definition":"CREATE UNIQUE INDEX roofing_material_orders_pkey ON public.roofing_material_orders USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_material_orders","permissive":"PERMISSIVE","policyname":"roofing_ops_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roofing_material_orders","permissive":"PERMISSIVE","policyname":"roofing_ops_insert","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"},{"cmd":"SELECT","qual":"roofing_ops_can_read(tenant_id)","roles":["public"],"tablename":"roofing_material_orders","permissive":"PERMISSIVE","policyname":"roofing_ops_read","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_material_orders","permissive":"PERMISSIVE","policyname":"roofing_ops_update","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"}],"triggers":[{"name":"roofing_ops_touch_updated_at","definition":"CREATE TRIGGER roofing_ops_touch_updated_at BEFORE UPDATE ON roofing_material_orders FOR EACH ROW EXECUTE FUNCTION roofing_ops_touch_updated_at()"}],"constraints":[{"name":"roofing_material_orders_job_id_fkey","definition":"FOREIGN KEY (job_id) REFERENCES jobs(id) ON DELETE CASCADE"},{"name":"roofing_material_orders_pkey","definition":"PRIMARY KEY (id)"},{"name":"roofing_material_orders_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'ordered'::text, 'confirmed'::text, 'scheduled'::text, 'delivered'::text, 'shortage'::text, 'returned'::text, 'cancelled'::text, 'blocked'::text]))"},{"name":"roofing_material_orders_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"roofing_project_ops","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"job_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"estimate_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"project_phase","type":"text","default":"'preproduction'::text","identity":"","not_null":true,"generated":""},{"name":"funding_type","type":"text","default":"'retail'::text","identity":"","not_null":true,"generated":""},{"name":"contract_total","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"deposit_required","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"deposit_collected","type":"numeric(14,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"install_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"weather_hold","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"production_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"measurement_status","type":"text","default":"'not_started'::text","identity":"","not_null":true,"generated":""},{"name":"materials_status","type":"text","default":"'not_started'::text","identity":"","not_null":true,"generated":""},{"name":"permit_status","type":"text","default":"'not_checked'::text","identity":"","not_null":true,"generated":""},{"name":"insurance_status","type":"text","default":"'not_applicable'::text","identity":"","not_null":true,"generated":""},{"name":"financing_status","type":"text","default":"'not_applicable'::text","identity":"","not_null":true,"generated":""},{"name":"closeout_status","type":"text","default":"'not_started'::text","identity":"","not_null":true,"generated":""},{"name":"warranty_status","type":"text","default":"'not_started'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"roofing_project_ops_install_idx","definition":"CREATE INDEX roofing_project_ops_install_idx ON public.roofing_project_ops USING btree (tenant_id, install_date)"},{"name":"roofing_project_ops_job_id_key","definition":"CREATE UNIQUE INDEX roofing_project_ops_job_id_key ON public.roofing_project_ops USING btree (job_id)"},{"name":"roofing_project_ops_pkey","definition":"CREATE UNIQUE INDEX roofing_project_ops_pkey ON public.roofing_project_ops USING btree (id)"},{"name":"roofing_project_ops_tenant_idx","definition":"CREATE INDEX roofing_project_ops_tenant_idx ON public.roofing_project_ops USING btree (tenant_id)"}],"policies":[{"cmd":"DELETE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_project_ops","permissive":"PERMISSIVE","policyname":"roofing_ops_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roofing_project_ops","permissive":"PERMISSIVE","policyname":"roofing_ops_insert","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"},{"cmd":"SELECT","qual":"roofing_ops_can_read(tenant_id)","roles":["public"],"tablename":"roofing_project_ops","permissive":"PERMISSIVE","policyname":"roofing_ops_read","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_project_ops","permissive":"PERMISSIVE","policyname":"roofing_ops_update","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"}],"triggers":[{"name":"roofing_ops_touch_updated_at","definition":"CREATE TRIGGER roofing_ops_touch_updated_at BEFORE UPDATE ON roofing_project_ops FOR EACH ROW EXECUTE FUNCTION roofing_ops_touch_updated_at()"}],"constraints":[{"name":"roofing_project_ops_closeout_status_check","definition":"CHECK (closeout_status = ANY (ARRAY['not_started'::text, 'in_progress'::text, 'ready'::text, 'complete'::text, 'blocked'::text]))"},{"name":"roofing_project_ops_financing_status_check","definition":"CHECK (financing_status = ANY (ARRAY['not_applicable'::text, 'draft'::text, 'submitted'::text, 'approved'::text, 'declined'::text, 'funded'::text]))"},{"name":"roofing_project_ops_funding_type_check","definition":"CHECK (funding_type = ANY (ARRAY['retail'::text, 'insurance'::text]))"},{"name":"roofing_project_ops_insurance_status_check","definition":"CHECK (insurance_status = ANY (ARRAY['not_applicable'::text, 'intake'::text, 'carrier_review'::text, 'supplement_followup'::text, 'payment_pending'::text, 'mortgage_hold'::text, 'ready'::text, 'blocked'::text]))"},{"name":"roofing_project_ops_job_id_fkey","definition":"FOREIGN KEY (job_id) REFERENCES jobs(id) ON DELETE CASCADE"},{"name":"roofing_project_ops_job_id_key","definition":"UNIQUE (job_id)"},{"name":"roofing_project_ops_materials_status_check","definition":"CHECK (materials_status = ANY (ARRAY['not_started'::text, 'draft'::text, 'ordered'::text, 'confirmed'::text, 'scheduled'::text, 'delivered'::text, 'shortage'::text, 'returned'::text, 'blocked'::text]))"},{"name":"roofing_project_ops_measurement_status_check","definition":"CHECK (measurement_status = ANY (ARRAY['not_started'::text, 'ordered'::text, 'processing'::text, 'ready'::text, 'failed'::text]))"},{"name":"roofing_project_ops_permit_status_check","definition":"CHECK (permit_status = ANY (ARRAY['not_checked'::text, 'not_required'::text, 'required'::text, 'applied'::text, 'issued'::text, 'inspection_pending'::text, 'finaled'::text, 'expired'::text, 'denied'::text, 'unknown'::text]))"},{"name":"roofing_project_ops_pkey","definition":"PRIMARY KEY (id)"},{"name":"roofing_project_ops_project_phase_check","definition":"CHECK (project_phase = ANY (ARRAY['inspection'::text, 'estimating'::text, 'proposal'::text, 'contract'::text, 'preproduction'::text, 'scheduled'::text, 'production'::text, 'closeout'::text, 'complete'::text, 'lost'::text]))"},{"name":"roofing_project_ops_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"roofing_project_ops_warranty_status_check","definition":"CHECK (warranty_status = ANY (ARRAY['not_started'::text, 'pending_registration'::text, 'registered'::text, 'not_applicable'::text]))"}]},{"table":"roofing_provider_connections","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'disconnected'::text","identity":"","not_null":true,"generated":""},{"name":"external_account_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"capabilities","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"last_verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_sync_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"roofing_provider_connections_pkey","definition":"CREATE UNIQUE INDEX roofing_provider_connections_pkey ON public.roofing_provider_connections USING btree (id)"},{"name":"roofing_provider_connections_tenant_id_provider_category_pr_key","definition":"CREATE UNIQUE INDEX roofing_provider_connections_tenant_id_provider_category_pr_key ON public.roofing_provider_connections USING btree (tenant_id, provider_category, provider_code)"}],"policies":[{"cmd":"DELETE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_provider_connections","permissive":"PERMISSIVE","policyname":"roofing_ops_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"roofing_provider_connections","permissive":"PERMISSIVE","policyname":"roofing_ops_insert","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"},{"cmd":"SELECT","qual":"roofing_ops_can_read(tenant_id)","roles":["public"],"tablename":"roofing_provider_connections","permissive":"PERMISSIVE","policyname":"roofing_ops_read","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"roofing_ops_can_manage(tenant_id)","roles":["public"],"tablename":"roofing_provider_connections","permissive":"PERMISSIVE","policyname":"roofing_ops_update","schemaname":"public","with_check":"roofing_ops_can_manage(tenant_id)"}],"triggers":[{"name":"roofing_ops_touch_updated_at","definition":"CREATE TRIGGER roofing_ops_touch_updated_at BEFORE UPDATE ON roofing_provider_connections FOR EACH ROW EXECUTE FUNCTION roofing_ops_touch_updated_at()"}],"constraints":[{"name":"roofing_provider_connections_pkey","definition":"PRIMARY KEY (id)"},{"name":"roofing_provider_connections_provider_category_check","definition":"CHECK (provider_category = ANY (ARRAY['measurement'::text, 'supplier'::text, 'accounting'::text, 'financing'::text, 'payments'::text, 'photos'::text]))"},{"name":"roofing_provider_connections_status_check","definition":"CHECK (status = ANY (ARRAY['disconnected'::text, 'action_required'::text, 'connected'::text, 'degraded'::text, 'disabled'::text]))"},{"name":"roofing_provider_connections_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"roofing_provider_connections_tenant_id_provider_category_pr_key","definition":"UNIQUE (tenant_id, provider_category, provider_code)"}]},{"table":"route_configs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"routes","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_route_configs_active","definition":"CREATE INDEX idx_route_configs_active ON public.route_configs USING btree (is_active)"},{"name":"idx_route_configs_role","definition":"CREATE INDEX idx_route_configs_role ON public.route_configs USING btree (role)"},{"name":"route_configs_pkey","definition":"CREATE UNIQUE INDEX route_configs_pkey ON public.route_configs USING btree (id)"},{"name":"route_configs_role_key","definition":"CREATE UNIQUE INDEX route_configs_role_key ON public.route_configs USING btree (role)"}],"policies":[{"cmd":"SELECT","qual":"(is_active = true)","roles":["authenticated"],"tablename":"route_configs","permissive":"PERMISSIVE","policyname":"Authenticated users can view active route configs","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"route_configs","permissive":"PERMISSIVE","policyname":"platform_admin_manage_route_configs","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"route_configs_pkey","definition":"PRIMARY KEY (id)"},{"name":"route_configs_role_key","definition":"UNIQUE (role)"}]},{"table":"route_session_stops","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"route_session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"door_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"stop_order","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"arrived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_rss_door","definition":"CREATE INDEX idx_rss_door ON public.route_session_stops USING btree (door_id)"},{"name":"idx_rss_session","definition":"CREATE INDEX idx_rss_session ON public.route_session_stops USING btree (route_session_id, stop_order)"},{"name":"route_session_stops_pkey","definition":"CREATE UNIQUE INDEX route_session_stops_pkey ON public.route_session_stops USING btree (id)"},{"name":"route_session_stops_route_session_id_stop_order_key","definition":"CREATE UNIQUE INDEX route_session_stops_route_session_id_stop_order_key ON public.route_session_stops USING btree (route_session_id, stop_order)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"route_session_stops","permissive":"PERMISSIVE","policyname":"rss_insert","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) AND (EXISTS ( SELECT 1\n   FROM route_sessions rs\n  WHERE ((rs.id = route_session_stops.route_session_id) AND (rs.user_id = uid())))))"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_org_id) AND (EXISTS ( SELECT 1\n   FROM route_sessions rs\n  WHERE ((rs.id = route_session_stops.route_session_id) AND ((rs.user_id = uid()) OR is_manager_or_higher(uid(), rs.tenant_org_id) OR is_system_admin(uid()))))))","roles":["authenticated"],"tablename":"route_session_stops","permissive":"PERMISSIVE","policyname":"rss_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(uid(), tenant_org_id) AND (EXISTS ( SELECT 1\n   FROM route_sessions rs\n  WHERE ((rs.id = route_session_stops.route_session_id) AND ((rs.user_id = uid()) OR is_system_admin(uid()))))))","roles":["authenticated"],"tablename":"route_session_stops","permissive":"PERMISSIVE","policyname":"rss_update","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_org_id)"}],"triggers":[{"name":"trg_rss_updated","definition":"CREATE TRIGGER trg_rss_updated BEFORE UPDATE ON route_session_stops FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"route_session_stops_pkey","definition":"PRIMARY KEY (id)"},{"name":"route_session_stops_route_session_id_stop_order_key","definition":"UNIQUE (route_session_id, stop_order)"}]},{"table":"route_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"total_doors","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"doors_completed","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"estimated_minutes","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"total_distance_meters","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"start_lat","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"start_lng","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"ended_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_route_sessions_active","definition":"CREATE INDEX idx_route_sessions_active ON public.route_sessions USING btree (tenant_org_id, status) WHERE (status = 'active'::text)"},{"name":"idx_route_sessions_tenant_user","definition":"CREATE INDEX idx_route_sessions_tenant_user ON public.route_sessions USING btree (tenant_org_id, user_id, started_at DESC)"},{"name":"route_sessions_pkey","definition":"CREATE UNIQUE INDEX route_sessions_pkey ON public.route_sessions USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"route_sessions","permissive":"PERMISSIVE","policyname":"rs_insert","schemaname":"public","with_check":"(is_tenant_member(uid(), tenant_org_id) AND (user_id = uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_org_id) AND ((user_id = uid()) OR is_manager_or_higher(uid(), tenant_org_id) OR is_system_admin(uid())))","roles":["authenticated"],"tablename":"route_sessions","permissive":"PERMISSIVE","policyname":"rs_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(uid(), tenant_org_id) AND ((user_id = uid()) OR is_system_admin(uid())))","roles":["authenticated"],"tablename":"route_sessions","permissive":"PERMISSIVE","policyname":"rs_update","schemaname":"public","with_check":"is_tenant_member(uid(), tenant_org_id)"}],"triggers":[{"name":"trg_route_sessions_updated","definition":"CREATE TRIGGER trg_route_sessions_updated BEFORE UPDATE ON route_sessions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"route_sessions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"scheduled_callbacks","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"promised_to_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"due_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_scheduled_callbacks_contact","definition":"CREATE INDEX idx_scheduled_callbacks_contact ON public.scheduled_callbacks USING btree (contact_id)"},{"name":"idx_scheduled_callbacks_due","definition":"CREATE INDEX idx_scheduled_callbacks_due ON public.scheduled_callbacks USING btree (tenant_org_id, status, due_at)"},{"name":"scheduled_callbacks_pkey","definition":"CREATE UNIQUE INDEX scheduled_callbacks_pkey ON public.scheduled_callbacks USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"(is_system_admin(uid()) OR is_tenant_member(tenant_org_id))","roles":["authenticated"],"tablename":"scheduled_callbacks","permissive":"PERMISSIVE","policyname":"system admins can delete scheduled callbacks","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"scheduled_callbacks","permissive":"PERMISSIVE","policyname":"tenant members can insert scheduled callbacks","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"},{"cmd":"UPDATE","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"scheduled_callbacks","permissive":"PERMISSIVE","policyname":"tenant members can update scheduled callbacks","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"scheduled_callbacks","permissive":"PERMISSIVE","policyname":"tenant members can view scheduled callbacks","schemaname":"public","with_check":null}],"triggers":[{"name":"scheduled_callbacks_set_updated_at","definition":"CREATE TRIGGER scheduled_callbacks_set_updated_at BEFORE UPDATE ON scheduled_callbacks FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"scheduled_callbacks_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"scheduled_emails","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"from_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_address","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scheduled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_scheduled_emails_status","definition":"CREATE INDEX idx_scheduled_emails_status ON public.scheduled_emails USING btree (status, scheduled_at)"},{"name":"scheduled_emails_pkey","definition":"CREATE UNIQUE INDEX scheduled_emails_pkey ON public.scheduled_emails USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"scheduled_emails","permissive":"PERMISSIVE","policyname":"Tenant isolation for scheduled_emails","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"scheduled_emails_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"scheduled_emails_pkey","definition":"PRIMARY KEY (id)"},{"name":"scheduled_emails_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'sending'::text, 'sent'::text, 'failed'::text, 'cancelled'::text]))"}]},{"table":"scheduled_reports","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"report_definition_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"character varying(255)","default":null,"identity":"","not_null":true,"generated":""},{"name":"schedule_type","type":"character varying(20)","default":null,"identity":"","not_null":true,"generated":""},{"name":"schedule_config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"recipients","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"format","type":"character varying(20)","default":"'pdf'::character varying","identity":"","not_null":false,"generated":""},{"name":"last_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_run_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"scheduled_reports_pkey","definition":"CREATE UNIQUE INDEX scheduled_reports_pkey ON public.scheduled_reports USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"scheduled_reports","permissive":"PERMISSIVE","policyname":"Users can manage scheduled reports","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"scheduled_reports","permissive":"PERMISSIVE","policyname":"Users can view own tenant scheduled reports","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"scheduled_reports_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"scheduled_sms","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"scheduled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_scheduled_sms_status","definition":"CREATE INDEX idx_scheduled_sms_status ON public.scheduled_sms USING btree (status, scheduled_at)"},{"name":"scheduled_sms_pkey","definition":"CREATE UNIQUE INDEX scheduled_sms_pkey ON public.scheduled_sms USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"scheduled_sms","permissive":"PERMISSIVE","policyname":"Tenant isolation for scheduled_sms","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"scheduled_sms_pkey","definition":"PRIMARY KEY (id)"},{"name":"scheduled_sms_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'sending'::text, 'sent'::text, 'failed'::text, 'cancelled'::text]))"}]},{"table":"score_audit_log","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"score_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"subject_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"previous_value","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_value","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_score_audit_event_type","definition":"CREATE INDEX idx_score_audit_event_type ON public.score_audit_log USING btree (event_type, created_at DESC)"},{"name":"idx_score_audit_subject","definition":"CREATE INDEX idx_score_audit_subject ON public.score_audit_log USING btree (subject_type, subject_id, created_at DESC)"},{"name":"idx_score_audit_tenant_time","definition":"CREATE INDEX idx_score_audit_tenant_time ON public.score_audit_log USING btree (tenant_org_id, created_at DESC)"},{"name":"score_audit_log_pkey","definition":"CREATE UNIQUE INDEX score_audit_log_pkey ON public.score_audit_log USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"score_audit_log","permissive":"PERMISSIVE","policyname":"score_audit_insert_admin","schemaname":"public","with_check":"(is_system_admin(uid()) OR is_admin_or_higher(uid(), (tenant_org_id)::uuid) OR (actor_user_id = uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["public"],"tablename":"score_audit_log","permissive":"PERMISSIVE","policyname":"score_audit_select_member","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"score_audit_log_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"score_dismissals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"score_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"dismissed_until","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_score_dismissals_subject","definition":"CREATE INDEX idx_score_dismissals_subject ON public.score_dismissals USING btree (subject_type, subject_id)"},{"name":"idx_score_dismissals_user","definition":"CREATE INDEX idx_score_dismissals_user ON public.score_dismissals USING btree (user_id, score_type)"},{"name":"score_dismissals_pkey","definition":"CREATE UNIQUE INDEX score_dismissals_pkey ON public.score_dismissals USING btree (id)"},{"name":"score_dismissals_unique","definition":"CREATE UNIQUE INDEX score_dismissals_unique ON public.score_dismissals USING btree (user_id, score_type, subject_type, subject_id)"}],"policies":[{"cmd":"DELETE","qual":"((user_id = uid()) OR is_system_admin(uid()) OR is_admin_or_higher(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"score_dismissals","permissive":"PERMISSIVE","policyname":"score_dismissals_delete_own_or_admin","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"score_dismissals","permissive":"PERMISSIVE","policyname":"score_dismissals_insert_self","schemaname":"public","with_check":"((user_id = uid()) AND is_tenant_member(tenant_org_id))"},{"cmd":"SELECT","qual":"((user_id = uid()) OR is_system_admin(uid()) OR is_admin_or_higher(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"score_dismissals","permissive":"PERMISSIVE","policyname":"score_dismissals_select_own_or_admin","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"score_dismissals_pkey","definition":"PRIMARY KEY (id)"},{"name":"score_dismissals_unique","definition":"UNIQUE (user_id, score_type, subject_type, subject_id)"}]},{"table":"score_models","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"score_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"weights","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"thresholds","type":"jsonb","default":"'{\"hot\": 90, \"worth\": 60, \"strong\": 75}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"min_visibility_score","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"weights_locked","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_score_models_lookup","definition":"CREATE INDEX idx_score_models_lookup ON public.score_models USING btree (score_type, tenant_org_id)"},{"name":"score_models_pkey","definition":"CREATE UNIQUE INDEX score_models_pkey ON public.score_models USING btree (id)"},{"name":"score_models_unique_per_tenant","definition":"CREATE UNIQUE INDEX score_models_unique_per_tenant ON public.score_models USING btree (tenant_org_id, score_type)"}],"policies":[{"cmd":"DELETE","qual":"is_system_admin(uid())","roles":["public"],"tablename":"score_models","permissive":"PERMISSIVE","policyname":"score_models_delete_admin","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"score_models","permissive":"PERMISSIVE","policyname":"score_models_insert_admin","schemaname":"public","with_check":"(is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)))"},{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR is_tenant_member(tenant_org_id) OR is_system_admin(uid()))","roles":["public"],"tablename":"score_models","permissive":"PERMISSIVE","policyname":"score_models_select_global_or_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)))","roles":["public"],"tablename":"score_models","permissive":"PERMISSIVE","policyname":"score_models_update_admin","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_score_models_updated_at","definition":"CREATE TRIGGER trg_score_models_updated_at BEFORE UPDATE ON score_models FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"score_models_pkey","definition":"PRIMARY KEY (id)"},{"name":"score_models_unique_per_tenant","definition":"UNIQUE (tenant_org_id, score_type)"}]},{"table":"security_alerts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"alert_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"severity","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"acknowledged_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"acknowledged_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolution_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_security_alerts_created","definition":"CREATE INDEX idx_security_alerts_created ON public.security_alerts USING btree (created_at DESC)"},{"name":"idx_security_alerts_severity","definition":"CREATE INDEX idx_security_alerts_severity ON public.security_alerts USING btree (severity)"},{"name":"idx_security_alerts_type","definition":"CREATE INDEX idx_security_alerts_type ON public.security_alerts USING btree (alert_type)"},{"name":"security_alerts_pkey","definition":"CREATE UNIQUE INDEX security_alerts_pkey ON public.security_alerts USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"security_alerts","permissive":"PERMISSIVE","policyname":"platform_admin_manage_security_alerts","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"security_alerts_pkey","definition":"PRIMARY KEY (id)"},{"name":"security_alerts_severity_check","definition":"CHECK (severity = ANY (ARRAY['low'::text, 'medium'::text, 'high'::text, 'critical'::text]))"}]},{"table":"security_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"success","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"failure_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"severity","type":"text","default":"'medium'::text","identity":"","not_null":false,"generated":""},{"name":"timestamp","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_security_events_email","definition":"CREATE INDEX idx_security_events_email ON public.security_events USING btree (email)"},{"name":"idx_security_events_severity","definition":"CREATE INDEX idx_security_events_severity ON public.security_events USING btree (severity)"},{"name":"idx_security_events_timestamp","definition":"CREATE INDEX idx_security_events_timestamp ON public.security_events USING btree (\"timestamp\" DESC)"},{"name":"idx_security_events_type","definition":"CREATE INDEX idx_security_events_type ON public.security_events USING btree (event_type)"},{"name":"idx_security_events_user_id","definition":"CREATE INDEX idx_security_events_user_id ON public.security_events USING btree (user_id)"},{"name":"security_events_pkey","definition":"CREATE UNIQUE INDEX security_events_pkey ON public.security_events USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"security_events","permissive":"PERMISSIVE","policyname":"platform_admin_view_security_events","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"security_events","permissive":"PERMISSIVE","policyname":"users_insert_own_security_events","schemaname":"public","with_check":"((user_id = uid()) OR is_system_admin(uid()))"}],"triggers":[],"constraints":[{"name":"security_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"security_events_severity_check","definition":"CHECK (severity = ANY (ARRAY['low'::text, 'medium'::text, 'high'::text, 'critical'::text]))"}]},{"table":"seminole_parcel_syncs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'running'::text","identity":"","not_null":true,"generated":""},{"name":"records_processed","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"records_added","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"records_updated","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"seminole_parcel_syncs_pkey","definition":"CREATE UNIQUE INDEX seminole_parcel_syncs_pkey ON public.seminole_parcel_syncs USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"seminole_parcel_syncs","permissive":"PERMISSIVE","policyname":"Admins can view sync history","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"seminole_parcel_syncs","permissive":"PERMISSIVE","policyname":"Service role can manage sync history","schemaname":"public","with_check":"true"}],"triggers":[],"constraints":[{"name":"seminole_parcel_syncs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"seminole_parcels","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"parcel_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"owner_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"site_address","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"site_city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"site_zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"square_feet","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"year_built","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"assessed_value","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"market_value","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"bedrooms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"bathrooms","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"lot_size_sqft","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"centroid_lat","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"centroid_lng","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_seminole_parcels_coords","definition":"CREATE INDEX idx_seminole_parcels_coords ON public.seminole_parcels USING btree (centroid_lat, centroid_lng) WHERE ((centroid_lat IS NOT NULL) AND (centroid_lng IS NOT NULL))"},{"name":"idx_seminole_parcels_parcel_id","definition":"CREATE INDEX idx_seminole_parcels_parcel_id ON public.seminole_parcels USING btree (parcel_id)"},{"name":"idx_seminole_parcels_site_address","definition":"CREATE INDEX idx_seminole_parcels_site_address ON public.seminole_parcels USING gin (to_tsvector('english'::regconfig, site_address))"},{"name":"idx_seminole_parcels_zip","definition":"CREATE INDEX idx_seminole_parcels_zip ON public.seminole_parcels USING btree (site_zip)"},{"name":"seminole_parcels_pkey","definition":"CREATE UNIQUE INDEX seminole_parcels_pkey ON public.seminole_parcels USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"true","roles":["service_role"],"tablename":"seminole_parcels","permissive":"PERMISSIVE","policyname":"Service role can manage Seminole parcels","schemaname":"public","with_check":"true"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"seminole_parcels","permissive":"PERMISSIVE","policyname":"seminole_parcels_select_admin_only","schemaname":"public","with_check":null}],"triggers":[{"name":"update_seminole_parcels_updated_at","definition":"CREATE TRIGGER update_seminole_parcels_updated_at BEFORE UPDATE ON seminole_parcels FOR EACH ROW EXECUTE FUNCTION update_seminole_parcels_updated_at()"}],"constraints":[{"name":"seminole_parcels_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"sequence_enrollment_progress","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"enrollment_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"step_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"executed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"result","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"sequence_enrollment_progress_pkey","definition":"CREATE UNIQUE INDEX sequence_enrollment_progress_pkey ON public.sequence_enrollment_progress USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"((EXISTS ( SELECT 1\n   FROM (sequence_enrollments se\n     JOIN communication_sequences cs ON ((cs.id = se.sequence_id)))\n  WHERE ((se.id = sequence_enrollment_progress.enrollment_id) AND is_tenant_member((cs.tenant_org_id)::text)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"sequence_enrollment_progress","permissive":"PERMISSIVE","policyname":"Tenant members can manage enrollment progress","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM (sequence_enrollments se\n     JOIN communication_sequences cs ON ((cs.id = se.sequence_id)))\n  WHERE ((se.id = sequence_enrollment_progress.enrollment_id) AND is_tenant_member((cs.tenant_org_id)::text)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM (sequence_enrollments se\n     JOIN communication_sequences cs ON ((cs.id = se.sequence_id)))\n  WHERE ((se.id = sequence_enrollment_progress.enrollment_id) AND is_tenant_member((cs.tenant_org_id)::text)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"sequence_enrollment_progress","permissive":"PERMISSIVE","policyname":"Tenant members can read enrollment progress","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"sequence_enrollment_progress_pkey","definition":"PRIMARY KEY (id)"},{"name":"sequence_enrollment_progress_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'in_progress'::text, 'completed'::text, 'skipped'::text, 'failed'::text]))"}]},{"table":"sequence_enrollments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"sequence_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"current_step","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":false,"generated":""},{"name":"enrolled_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"enrolled_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"paused_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"unsubscribed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_action_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"step_history","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_sequence_enrollments_contact","definition":"CREATE INDEX idx_sequence_enrollments_contact ON public.sequence_enrollments USING btree (contact_id)"},{"name":"idx_sequence_enrollments_next_action","definition":"CREATE INDEX idx_sequence_enrollments_next_action ON public.sequence_enrollments USING btree (next_action_at) WHERE (status = 'active'::text)"},{"name":"sequence_enrollments_pkey","definition":"CREATE UNIQUE INDEX sequence_enrollments_pkey ON public.sequence_enrollments USING btree (id)"},{"name":"sequence_enrollments_sequence_id_contact_id_key","definition":"CREATE UNIQUE INDEX sequence_enrollments_sequence_id_contact_id_key ON public.sequence_enrollments USING btree (sequence_id, contact_id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"sequence_enrollments","permissive":"PERMISSIVE","policyname":"Tenant isolation for sequence_enrollments","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"sequence_enrollments_pkey","definition":"PRIMARY KEY (id)"},{"name":"sequence_enrollments_sequence_id_contact_id_key","definition":"UNIQUE (sequence_id, contact_id)"},{"name":"sequence_enrollments_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'paused'::text, 'completed'::text, 'unsubscribed'::text, 'bounced'::text, 'failed'::text]))"}]},{"table":"settlement_invoices_migration_20260917","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"invoice_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"invoice_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"due_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_tone","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"homeowner_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"property_address","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"insurance_carrier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"settlement_amount","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"deposit_amount","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"remaining_balance","type":"numeric","default":null,"identity":"","not_null":true,"generated":""},{"name":"payment_terms","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"invoice_html","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":false,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"paid_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"original_total","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"insurance_payment","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"settlement_discount","type":"numeric","default":"0","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_settlement_invoices_contact","definition":"CREATE INDEX idx_settlement_invoices_contact ON public.settlement_invoices_migration_20260917 USING btree (contact_id)"},{"name":"idx_settlement_invoices_invoice_number","definition":"CREATE INDEX idx_settlement_invoices_invoice_number ON public.settlement_invoices_migration_20260917 USING btree (invoice_number)"},{"name":"idx_settlement_invoices_status","definition":"CREATE INDEX idx_settlement_invoices_status ON public.settlement_invoices_migration_20260917 USING btree (status)"},{"name":"idx_settlement_invoices_tenant","definition":"CREATE INDEX idx_settlement_invoices_tenant ON public.settlement_invoices_migration_20260917 USING btree (tenant_org_id)"},{"name":"settlement_invoices_pkey","definition":"CREATE UNIQUE INDEX settlement_invoices_pkey ON public.settlement_invoices_migration_20260917 USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"Users create tenant invoices","schemaname":"public","with_check":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) AND (created_by_user_id = uid()))"},{"cmd":"DELETE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"Users delete tenant invoices","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"Users update tenant invoices","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"Users view tenant invoices","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"si_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"si_insert","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin())"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"si_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"si_update","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (settlement_invoices_migration_20260917.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"tenant_users_delete_settlement_invoices","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"tenant_users_insert_settlement_invoices","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (settlement_invoices_migration_20260917.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (settlement_invoices_migration_20260917.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"tenant_users_update_settlement_invoices","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (settlement_invoices_migration_20260917.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (settlement_invoices_migration_20260917.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"settlement_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"tenant_users_view_settlement_invoices","schemaname":"public","with_check":null}],"triggers":[{"name":"settlement_invoices_business_activity","definition":"CREATE TRIGGER settlement_invoices_business_activity AFTER INSERT OR UPDATE OF status, settlement_amount, remaining_balance, paid_at ON settlement_invoices_migration_20260917 FOR EACH ROW EXECUTE FUNCTION project_settlement_invoice_business_activity()"},{"name":"settlement_invoices_updated_at","definition":"CREATE TRIGGER settlement_invoices_updated_at BEFORE UPDATE ON settlement_invoices_migration_20260917 FOR EACH ROW EXECUTE FUNCTION update_settlement_invoices_updated_at()"}],"constraints":[{"name":"settlement_invoices_pkey","definition":"PRIMARY KEY (id)"},{"name":"settlement_invoices_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'sent'::text, 'paid'::text, 'overdue'::text, 'cancelled'::text]))"},{"name":"settlement_invoices_template_tone_check","definition":"CHECK (template_tone = ANY (ARRAY['Friendly'::text, 'Standard'::text, 'Stern'::text]))"}]},{"table":"share_packets","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"referral_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"data","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"share_packets_pkey","definition":"CREATE UNIQUE INDEX share_packets_pkey ON public.share_packets USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"share_packets","permissive":"PERMISSIVE","policyname":"referral_creators_insert_packets","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM referrals r\n  WHERE ((r.id = share_packets.referral_id) AND is_tenant_member((r.from_tenant_id)::text))))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM referrals r\n  WHERE ((r.id = share_packets.referral_id) AND (is_tenant_member((r.from_tenant_id)::text) OR is_tenant_member((r.to_tenant_id)::text))))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"share_packets","permissive":"PERMISSIVE","policyname":"referral_participants_view_packets","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"share_packets_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"shared_claim_activity","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"shared_claim_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"activity_type","type":"text","default":"'stage_change'::text","identity":"","not_null":true,"generated":""},{"name":"field_changed","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"old_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"new_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_shared_claim_activity_claim","definition":"CREATE INDEX idx_shared_claim_activity_claim ON public.shared_claim_activity USING btree (shared_claim_id)"},{"name":"idx_shared_claim_activity_created","definition":"CREATE INDEX idx_shared_claim_activity_created ON public.shared_claim_activity USING btree (created_at DESC)"},{"name":"shared_claim_activity_pkey","definition":"CREATE UNIQUE INDEX shared_claim_activity_pkey ON public.shared_claim_activity USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_claim_participant(shared_claim_id, uid())","roles":["authenticated"],"tablename":"shared_claim_activity","permissive":"PERMISSIVE","policyname":"participants_view_activity","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"shared_claim_activity","permissive":"PERMISSIVE","policyname":"system_insert_activity","schemaname":"public","with_check":"is_claim_participant(shared_claim_id, uid())"}],"triggers":[],"constraints":[{"name":"shared_claim_activity_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"shared_claim_participants","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"shared_claim_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"role","type":"shared_claim_role","default":"'other'::shared_claim_role","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"jobs_stage","type":"text","default":"'Not Started'::text","identity":"","not_null":false,"generated":""},{"name":"status","type":"shared_claim_status","default":"'invited'::shared_claim_status","identity":"","not_null":true,"generated":""},{"name":"invited_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"accepted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_shared_claim_participants_claim","definition":"CREATE INDEX idx_shared_claim_participants_claim ON public.shared_claim_participants USING btree (shared_claim_id)"},{"name":"idx_shared_claim_participants_contact","definition":"CREATE INDEX idx_shared_claim_participants_contact ON public.shared_claim_participants USING btree (contact_id)"},{"name":"idx_shared_claim_participants_status","definition":"CREATE INDEX idx_shared_claim_participants_status ON public.shared_claim_participants USING btree (status)"},{"name":"idx_shared_claim_participants_tenant","definition":"CREATE INDEX idx_shared_claim_participants_tenant ON public.shared_claim_participants USING btree (tenant_id)"},{"name":"shared_claim_participants_pkey","definition":"CREATE UNIQUE INDEX shared_claim_participants_pkey ON public.shared_claim_participants USING btree (id)"},{"name":"shared_claim_participants_shared_claim_id_tenant_id_key","definition":"CREATE UNIQUE INDEX shared_claim_participants_shared_claim_id_tenant_id_key ON public.shared_claim_participants USING btree (shared_claim_id, tenant_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"shared_claim_participants","permissive":"PERMISSIVE","policyname":"Claim creators can invite participants","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM shared_claims sc\n  WHERE ((sc.id = shared_claim_participants.shared_claim_id) AND (sc.created_by_user_id = uid())))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = shared_claim_participants.tenant_id) AND (utm.status = 'active'::text)))) OR (EXISTS ( SELECT 1\n   FROM shared_claims sc\n  WHERE ((sc.id = shared_claim_participants.shared_claim_id) AND (sc.created_by_user_id = uid())))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"shared_claim_participants","permissive":"PERMISSIVE","policyname":"Participants can update their own record","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = shared_claim_participants.tenant_id) AND (utm.status = 'active'::text)))) OR (EXISTS ( SELECT 1\n   FROM shared_claims sc\n  WHERE ((sc.id = shared_claim_participants.shared_claim_id) AND (sc.created_by_user_id = uid())))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"is_claim_participant_any_status(shared_claim_id, uid())","roles":["authenticated"],"tablename":"shared_claim_participants","permissive":"PERMISSIVE","policyname":"Users can view participants of their shared claims","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_log_shared_claim_stage_change","definition":"CREATE TRIGGER trg_log_shared_claim_stage_change AFTER UPDATE ON shared_claim_participants FOR EACH ROW EXECUTE FUNCTION log_shared_claim_stage_change()"},{"name":"update_shared_claim_participants_updated_at","definition":"CREATE TRIGGER update_shared_claim_participants_updated_at BEFORE UPDATE ON shared_claim_participants FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"shared_claim_participants_pkey","definition":"PRIMARY KEY (id)"},{"name":"shared_claim_participants_shared_claim_id_tenant_id_key","definition":"UNIQUE (shared_claim_id, tenant_id)"}]},{"table":"shared_claims","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"claim_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"carrier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"date_of_loss","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"customer_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_stage","type":"text","default":"'New'::text","identity":"","not_null":true,"generated":""},{"name":"created_by_tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_shared_claims_created_by_tenant","definition":"CREATE INDEX idx_shared_claims_created_by_tenant ON public.shared_claims USING btree (created_by_tenant_id)"},{"name":"shared_claims_pkey","definition":"CREATE UNIQUE INDEX shared_claims_pkey ON public.shared_claims USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"shared_claims","permissive":"PERMISSIVE","policyname":"Authenticated users can create shared claims","schemaname":"public","with_check":"(created_by_user_id = uid())"},{"cmd":"UPDATE","qual":"is_claim_participant(id, uid())","roles":["authenticated"],"tablename":"shared_claims","permissive":"PERMISSIVE","policyname":"Participants can update shared claim stage","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"is_claim_participant_any_status(id, uid())","roles":["authenticated"],"tablename":"shared_claims","permissive":"PERMISSIVE","policyname":"Users can view shared claims they participate in","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_log_shared_claim_claim_stage_change","definition":"CREATE TRIGGER trg_log_shared_claim_claim_stage_change AFTER UPDATE ON shared_claims FOR EACH ROW EXECUTE FUNCTION log_shared_claim_claim_stage_change()"},{"name":"update_shared_claims_updated_at","definition":"CREATE TRIGGER update_shared_claims_updated_at BEFORE UPDATE ON shared_claims FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"shared_claims_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"short_stay_reservations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"unit_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"guest_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"guest_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"guest_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":"'manual'::text","identity":"","not_null":true,"generated":""},{"name":"external_booking_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"check_in","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"check_out","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'confirmed'::text","identity":"","not_null":true,"generated":""},{"name":"guest_count","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"total_amount","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"amount_paid","type":"numeric(12,2)","default":"0","identity":"","not_null":true,"generated":""},{"name":"payment_status","type":"text","default":"'unpaid'::text","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"short_stay_reservations_external_idx","definition":"CREATE UNIQUE INDEX short_stay_reservations_external_idx ON public.short_stay_reservations USING btree (tenant_id, source, external_booking_id) WHERE (external_booking_id IS NOT NULL)"},{"name":"short_stay_reservations_pkey","definition":"CREATE UNIQUE INDEX short_stay_reservations_pkey ON public.short_stay_reservations USING btree (id)"},{"name":"short_stay_reservations_tenant_dates_idx","definition":"CREATE INDEX short_stay_reservations_tenant_dates_idx ON public.short_stay_reservations USING btree (tenant_id, check_in, check_out)"},{"name":"vista_short_stay_no_overlap","definition":"CREATE INDEX vista_short_stay_no_overlap ON public.short_stay_reservations USING gist (tenant_id, unit_name, daterange(check_in, check_out, '[)'::text)) WHERE ((tenant_id = '71b397ba-b9ad-496b-914c-985d97dbb12e'::uuid) AND (status = ANY (ARRAY['confirmed'::text, 'checked_in'::text])))"}],"policies":[{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = short_stay_reservations.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))) OR (EXISTS ( SELECT 1\n   FROM user_roles r\n  WHERE ((r.user_id = uid()) AND (r.tenant_id = short_stay_reservations.tenant_id)))))","roles":["authenticated"],"tablename":"short_stay_reservations","permissive":"PERMISSIVE","policyname":"short_stay_reservations_member_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"short_stay_reservations","permissive":"PERMISSIVE","policyname":"short_stay_reservations_member_insert","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = short_stay_reservations.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))) OR (EXISTS ( SELECT 1\n   FROM user_roles r\n  WHERE ((r.user_id = uid()) AND (r.tenant_id = short_stay_reservations.tenant_id)))))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = short_stay_reservations.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))) OR (EXISTS ( SELECT 1\n   FROM user_roles r\n  WHERE ((r.user_id = uid()) AND (r.tenant_id = short_stay_reservations.tenant_id)))))","roles":["authenticated"],"tablename":"short_stay_reservations","permissive":"PERMISSIVE","policyname":"short_stay_reservations_member_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = short_stay_reservations.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))) OR (EXISTS ( SELECT 1\n   FROM user_roles r\n  WHERE ((r.user_id = uid()) AND (r.tenant_id = short_stay_reservations.tenant_id)))))","roles":["authenticated"],"tablename":"short_stay_reservations","permissive":"PERMISSIVE","policyname":"short_stay_reservations_member_update","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = short_stay_reservations.tenant_id) AND (COALESCE(m.status, 'active'::text) = 'active'::text)))) OR (EXISTS ( SELECT 1\n   FROM user_roles r\n  WHERE ((r.user_id = uid()) AND (r.tenant_id = short_stay_reservations.tenant_id)))))"}],"triggers":[],"constraints":[{"name":"short_stay_reservations_check","definition":"CHECK (check_out > check_in)"},{"name":"short_stay_reservations_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"short_stay_reservations_guest_count_check","definition":"CHECK (guest_count > 0)"},{"name":"short_stay_reservations_payment_status_check","definition":"CHECK (payment_status = ANY (ARRAY['unpaid'::text, 'partial'::text, 'paid'::text, 'refunded'::text]))"},{"name":"short_stay_reservations_pkey","definition":"PRIMARY KEY (id)"},{"name":"short_stay_reservations_status_check","definition":"CHECK (status = ANY (ARRAY['inquiry'::text, 'confirmed'::text, 'checked_in'::text, 'checked_out'::text, 'cancelled'::text]))"},{"name":"short_stay_reservations_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"vista_short_stay_no_overlap","definition":"EXCLUDE USING gist (tenant_id WITH =, unit_name WITH =, daterange(check_in, check_out, '[)'::text) WITH &&) WHERE (tenant_id = '71b397ba-b9ad-496b-914c-985d97dbb12e'::uuid AND (status = ANY (ARRAY['confirmed'::text, 'checked_in'::text])))"}]},{"table":"signed_agreements","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"pending_signup_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"agreement_version","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"agreement_html","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"signature","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"gear_election","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"workers_comp_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"esign_consent","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"signed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"signed_ip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pdf_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pdf_drive_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreement_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"user_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_version_at_signing","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"assent_checkbox_accepted","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"electronic_records_consent","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"session_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"superseded_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"effective_date_at_signing","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"signer_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"declined_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"decline_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'signed'::text","identity":"","not_null":true,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_signed_agreements_pending_id","definition":"CREATE INDEX idx_signed_agreements_pending_id ON public.signed_agreements USING btree (pending_signup_id)"},{"name":"idx_signed_agreements_signed_at","definition":"CREATE INDEX idx_signed_agreements_signed_at ON public.signed_agreements USING btree (signed_at)"},{"name":"idx_signed_agreements_status","definition":"CREATE INDEX idx_signed_agreements_status ON public.signed_agreements USING btree (status) WHERE (status = 'signed'::text)"},{"name":"idx_signed_agreements_template_id","definition":"CREATE INDEX idx_signed_agreements_template_id ON public.signed_agreements USING btree (template_id)"},{"name":"idx_signed_agreements_type","definition":"CREATE INDEX idx_signed_agreements_type ON public.signed_agreements USING btree (agreement_type)"},{"name":"idx_signed_agreements_user_id","definition":"CREATE INDEX idx_signed_agreements_user_id ON public.signed_agreements USING btree (user_id)"},{"name":"idx_signed_agreements_user_tenant","definition":"CREATE INDEX idx_signed_agreements_user_tenant ON public.signed_agreements USING btree (user_id, tenant_id)"},{"name":"signed_agreements_event_booking_idx","definition":"CREATE INDEX signed_agreements_event_booking_idx ON public.signed_agreements USING btree (event_booking_id)"},{"name":"signed_agreements_pkey","definition":"CREATE UNIQUE INDEX signed_agreements_pkey ON public.signed_agreements USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(user_id = uid())","roles":["public"],"tablename":"signed_agreements","permissive":"PERMISSIVE","policyname":"Users can view own agreements","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"signed_agreements","permissive":"PERMISSIVE","policyname":"agreements_godmode_select","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((tenant_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_id))","roles":["public"],"tablename":"signed_agreements","permissive":"PERMISSIVE","policyname":"agreements_tenant_owner_select","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"signed_agreements","permissive":"PERMISSIVE","policyname":"agreements_user_insert_self","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"SELECT","qual":"(user_id = uid())","roles":["public"],"tablename":"signed_agreements","permissive":"PERMISSIVE","policyname":"agreements_user_select_own","schemaname":"public","with_check":null}],"triggers":[{"name":"signed_agreements_business_activity","definition":"CREATE TRIGGER signed_agreements_business_activity AFTER INSERT OR UPDATE ON signed_agreements FOR EACH ROW EXECUTE FUNCTION project_signed_agreement_business_activity()"},{"name":"tg_activate_proposal_operating_contract","definition":"CREATE TRIGGER tg_activate_proposal_operating_contract AFTER INSERT ON signed_agreements FOR EACH ROW EXECUTE FUNCTION activate_proposal_operating_contract_from_signed_agreement()"},{"name":"trg_signed_agreements_no_delete","definition":"CREATE TRIGGER trg_signed_agreements_no_delete BEFORE DELETE ON signed_agreements FOR EACH ROW EXECUTE FUNCTION block_mutation_append_only()"},{"name":"trg_signed_work_auth_to_job_request_ins","definition":"CREATE TRIGGER trg_signed_work_auth_to_job_request_ins AFTER INSERT ON signed_agreements FOR EACH ROW EXECUTE FUNCTION tg_create_job_request_from_signed_work_auth()"},{"name":"trg_signed_work_auth_to_job_request_upd","definition":"CREATE TRIGGER trg_signed_work_auth_to_job_request_upd AFTER UPDATE OF status ON signed_agreements FOR EACH ROW WHEN (new.status = 'signed'::text AND old.status IS DISTINCT FROM 'signed'::text) EXECUTE FUNCTION tg_create_job_request_from_signed_work_auth()"}],"constraints":[{"name":"chk_user_or_pending","definition":"CHECK (user_id IS NOT NULL AND pending_signup_id IS NULL OR user_id IS NULL AND pending_signup_id IS NOT NULL OR user_id IS NULL AND pending_signup_id IS NULL AND tenant_id IS NOT NULL AND signer_role IS NOT NULL)"},{"name":"signed_agreements_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"signed_agreements_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"site_config","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"config_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"config_value","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_config_key","definition":"CREATE INDEX idx_config_key ON public.site_config USING btree (config_key)"},{"name":"site_config_key_tenant_unique","definition":"CREATE UNIQUE INDEX site_config_key_tenant_unique ON public.site_config USING btree (config_key, tenant_org_id)"},{"name":"site_config_pkey","definition":"CREATE UNIQUE INDEX site_config_pkey ON public.site_config USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"((uid() IS NOT NULL) AND ((tenant_org_id IS NULL) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.tenant_id = (site_config.tenant_org_id)::uuid))))))","roles":["public"],"tablename":"site_config","permissive":"PERMISSIVE","policyname":"Authenticated users view configs","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"site_config","permissive":"PERMISSIVE","policyname":"platform_admin_manage_site_config","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid) AND (category = 'workflow_overrides'::text) AND (config_key ~~ 'workflow_overrides_%'::text))","roles":["authenticated"],"tablename":"site_config","permissive":"PERMISSIVE","policyname":"tenant_owner_admin_manage_workflow_overrides_site_config","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid) AND (category = 'workflow_overrides'::text) AND (config_key ~~ 'workflow_overrides_%'::text))"}],"triggers":[{"name":"update_site_config_updated_at","definition":"CREATE TRIGGER update_site_config_updated_at BEFORE UPDATE ON site_config FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"site_config_key_tenant_unique","definition":"UNIQUE (config_key, tenant_org_id)"},{"name":"site_config_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"sms_history","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"direction","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"to_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'sent'::text","identity":"","not_null":false,"generated":""},{"name":"twilio_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_sms_history_contact","definition":"CREATE INDEX idx_sms_history_contact ON public.sms_history USING btree (contact_id)"},{"name":"idx_sms_history_created","definition":"CREATE INDEX idx_sms_history_created ON public.sms_history USING btree (created_at DESC)"},{"name":"idx_sms_history_tenant","definition":"CREATE INDEX idx_sms_history_tenant ON public.sms_history USING btree (tenant_id)"},{"name":"sms_history_pkey","definition":"CREATE UNIQUE INDEX sms_history_pkey ON public.sms_history USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"sms_history","permissive":"PERMISSIVE","policyname":"Users can create SMS history for their tenant","schemaname":"public","with_check":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"sms_history","permissive":"PERMISSIVE","policyname":"Users can view SMS history for their tenant","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_owner_capture_unknown_inbound_sms_contact","definition":"CREATE TRIGGER trg_owner_capture_unknown_inbound_sms_contact BEFORE INSERT ON sms_history FOR EACH ROW EXECUTE FUNCTION owner_capture_unknown_inbound_sms_contact()"},{"name":"trg_owner_sms_history_dedupe_sid_guard","definition":"CREATE TRIGGER trg_owner_sms_history_dedupe_sid_guard BEFORE INSERT ON sms_history FOR EACH ROW EXECUTE FUNCTION owner_sms_history_dedupe_sid_guard()"}],"constraints":[{"name":"sms_history_direction_check","definition":"CHECK (direction = ANY (ARRAY['inbound'::text, 'outbound'::text]))"},{"name":"sms_history_pkey","definition":"PRIMARY KEY (id)"},{"name":"sms_history_status_check","definition":"CHECK (status = ANY (ARRAY['queued'::text, 'sent'::text, 'delivered'::text, 'failed'::text, 'received'::text]))"}]},{"table":"sms_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'general'::text","identity":"","not_null":false,"generated":""},{"name":"variables","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_sms_templates_active","definition":"CREATE INDEX idx_sms_templates_active ON public.sms_templates USING btree (tenant_id, is_active)"},{"name":"idx_sms_templates_tenant","definition":"CREATE INDEX idx_sms_templates_tenant ON public.sms_templates USING btree (tenant_id)"},{"name":"sms_templates_pkey","definition":"CREATE UNIQUE INDEX sms_templates_pkey ON public.sms_templates USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"sms_templates","permissive":"PERMISSIVE","policyname":"Users can create SMS templates for their tenant","schemaname":"public","with_check":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))"},{"cmd":"DELETE","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"sms_templates","permissive":"PERMISSIVE","policyname":"Users can delete SMS templates for their tenant","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"sms_templates","permissive":"PERMISSIVE","policyname":"Users can update SMS templates for their tenant","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"sms_templates","permissive":"PERMISSIVE","policyname":"Users can view SMS templates for their tenant","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"sms_templates_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"sql_execution_history","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"executed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"executed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"query_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"execution_status","type":"text","default":"'success'::text","identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rows_affected","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"execution_time_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"sql_execution_history_pkey","definition":"CREATE UNIQUE INDEX sql_execution_history_pkey ON public.sql_execution_history USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"sql_execution_history","permissive":"PERMISSIVE","policyname":"platform_admin_manage_sql_history","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"sql_execution_history_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"storm_attribution_links","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"storm_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"storm_zone_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"entity_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"entity_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"attribution_method","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"confidence_score","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"evidence_json","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by_module","type":"text","default":"'storm-attribution'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"storm_attribution_links_entity_idx","definition":"CREATE INDEX storm_attribution_links_entity_idx ON public.storm_attribution_links USING btree (tenant_id, entity_type, entity_id)"},{"name":"storm_attribution_links_pkey","definition":"CREATE UNIQUE INDEX storm_attribution_links_pkey ON public.storm_attribution_links USING btree (id)"},{"name":"storm_attribution_links_storm_idx","definition":"CREATE INDEX storm_attribution_links_storm_idx ON public.storm_attribution_links USING btree (tenant_id, storm_id, created_at DESC) WHERE (storm_id IS NOT NULL)"},{"name":"storm_attribution_links_zone_idx","definition":"CREATE INDEX storm_attribution_links_zone_idx ON public.storm_attribution_links USING btree (tenant_id, storm_zone_id, created_at DESC) WHERE (storm_zone_id IS NOT NULL)"}],"policies":[{"cmd":"SELECT","qual":"ai_user_in_tenant(tenant_id)","roles":["authenticated"],"tablename":"storm_attribution_links","permissive":"PERMISSIVE","policyname":"storm_attribution_links_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"storm_attribution_links_attribution_method_check","definition":"CHECK (attribution_method = ANY (ARRAY['address_match'::text, 'zip_match'::text, 'geo_match'::text, 'campaign_match'::text, 'manual'::text, 'rep_assignment'::text, 'call_source'::text, 'lead_source'::text, 'appointment_location'::text, 'job_location'::text]))"},{"name":"storm_attribution_links_confidence_score_check","definition":"CHECK (confidence_score IS NULL OR confidence_score >= 0::numeric AND confidence_score <= 1::numeric)"},{"name":"storm_attribution_links_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"storm_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"county","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"state","type":"text","default":"'FL'::text","identity":"","not_null":true,"generated":""},{"name":"zip_prefix","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_date","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"wind_mph","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"hail_inches","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"storm_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"qualifies","type":"boolean","default":"((wind_mph >= (60)::numeric) OR (hail_inches >= 0.75))","identity":"","not_null":false,"generated":"s"},{"name":"raw_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"lat","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"lng","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"location_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"storm_direction_deg","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"storm_speed_mph","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_minutes","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"affected_polygon","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"path_width_miles","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"geometry_source","type":"text","default":"'none'::text","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_storm_events_coordinates","definition":"CREATE INDEX idx_storm_events_coordinates ON public.storm_events USING btree (lat, lng) WHERE ((lat IS NOT NULL) AND (lng IS NOT NULL))"},{"name":"idx_storm_events_county","definition":"CREATE INDEX idx_storm_events_county ON public.storm_events USING btree (county, state)"},{"name":"idx_storm_events_county_date","definition":"CREATE INDEX idx_storm_events_county_date ON public.storm_events USING btree (county, event_date DESC)"},{"name":"idx_storm_events_date","definition":"CREATE INDEX idx_storm_events_date ON public.storm_events USING btree (event_date DESC)"},{"name":"idx_storm_events_qualifies","definition":"CREATE INDEX idx_storm_events_qualifies ON public.storm_events USING btree (qualifies) WHERE (qualifies = true)"},{"name":"idx_storm_events_unique","definition":"CREATE UNIQUE INDEX idx_storm_events_unique ON public.storm_events USING btree (county, event_date, COALESCE(wind_mph, (0)::numeric), COALESCE(hail_inches, (0)::numeric))"},{"name":"idx_storm_events_zip_prefix","definition":"CREATE INDEX idx_storm_events_zip_prefix ON public.storm_events USING btree (zip_prefix)"},{"name":"storm_events_pkey","definition":"CREATE UNIQUE INDEX storm_events_pkey ON public.storm_events USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"storm_events","permissive":"PERMISSIVE","policyname":"Admins can manage storm events","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"true","roles":["public"],"tablename":"storm_events","permissive":"PERMISSIVE","policyname":"Storm events are publicly readable","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_mark_scores_stale_on_storm","definition":"CREATE TRIGGER trg_mark_scores_stale_on_storm AFTER INSERT ON storm_events FOR EACH ROW EXECUTE FUNCTION mark_scores_stale_on_storm()"},{"name":"trg_storm_events_mark_scores_stale","definition":"CREATE TRIGGER trg_storm_events_mark_scores_stale AFTER INSERT ON storm_events FOR EACH ROW EXECUTE FUNCTION mark_scores_stale_on_storm_event()"},{"name":"update_storm_events_updated_at","definition":"CREATE TRIGGER update_storm_events_updated_at BEFORE UPDATE ON storm_events FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"storm_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"storm_report_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"report_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"details","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_storm_report_audit_report","definition":"CREATE INDEX idx_storm_report_audit_report ON public.storm_report_audit USING btree (report_id, created_at DESC)"},{"name":"storm_report_audit_pkey","definition":"CREATE UNIQUE INDEX storm_report_audit_pkey ON public.storm_report_audit USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"storm_report_audit","permissive":"PERMISSIVE","policyname":"Tenant members can insert audit","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) AND (actor_id = uid()))"},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"storm_report_audit","permissive":"PERMISSIVE","policyname":"Tenant members can view audit","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"storm_report_audit_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"storm_report_deliveries","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"report_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"channel","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"recipient","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'queued'::text","identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sent_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_storm_report_deliveries_report","definition":"CREATE INDEX idx_storm_report_deliveries_report ON public.storm_report_deliveries USING btree (report_id)"},{"name":"idx_storm_report_deliveries_tenant","definition":"CREATE INDEX idx_storm_report_deliveries_tenant ON public.storm_report_deliveries USING btree (tenant_org_id)"},{"name":"storm_report_deliveries_pkey","definition":"CREATE UNIQUE INDEX storm_report_deliveries_pkey ON public.storm_report_deliveries USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = (storm_report_deliveries.tenant_org_id)::uuid) AND (user_roles.role = ANY (ARRAY['Admin'::app_role, 'GodMode'::app_role, 'Owner'::app_role]))))) OR is_system_admin(uid()))","roles":["public"],"tablename":"storm_report_deliveries","permissive":"PERMISSIVE","policyname":"Admins delete storm report deliveries","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"storm_report_deliveries","permissive":"PERMISSIVE","policyname":"Tenant members insert storm report deliveries","schemaname":"public","with_check":"(((tenant_org_id)::uuid IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(((tenant_org_id)::uuid IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) OR is_system_admin(uid()))","roles":["public"],"tablename":"storm_report_deliveries","permissive":"PERMISSIVE","policyname":"Tenant members view storm report deliveries","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"storm_report_deliveries_channel_check","definition":"CHECK (channel = ANY (ARRAY['email'::text, 'sms'::text]))"},{"name":"storm_report_deliveries_pkey","definition":"PRIMARY KEY (id)"},{"name":"storm_report_deliveries_status_check","definition":"CHECK (status = ANY (ARRAY['queued'::text, 'sent'::text, 'failed'::text]))"}]},{"table":"storm_report_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"report_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"share_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_timestamp","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"device_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"browser","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_storm_report_events_report","definition":"CREATE INDEX idx_storm_report_events_report ON public.storm_report_events USING btree (report_id, event_timestamp DESC)"},{"name":"idx_storm_report_events_tenant","definition":"CREATE INDEX idx_storm_report_events_tenant ON public.storm_report_events USING btree (tenant_org_id, event_timestamp DESC)"},{"name":"idx_storm_report_events_type","definition":"CREATE INDEX idx_storm_report_events_type ON public.storm_report_events USING btree (report_id, event_type)"},{"name":"storm_report_events_pkey","definition":"CREATE UNIQUE INDEX storm_report_events_pkey ON public.storm_report_events USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"storm_report_events","permissive":"PERMISSIVE","policyname":"tenant_members_read_storm_report_events","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"storm_report_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"storm_report_questions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"report_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"share_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"question","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"resolved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_storm_report_questions_report","definition":"CREATE INDEX idx_storm_report_questions_report ON public.storm_report_questions USING btree (report_id, created_at DESC)"},{"name":"storm_report_questions_pkey","definition":"CREATE UNIQUE INDEX storm_report_questions_pkey ON public.storm_report_questions USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"storm_report_questions","permissive":"PERMISSIVE","policyname":"tenant_members_read_storm_report_questions","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"storm_report_questions","permissive":"PERMISSIVE","policyname":"tenant_members_update_storm_report_questions","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"}],"triggers":[],"constraints":[{"name":"storm_report_questions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"storm_reports","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"storage_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"file_size_bytes","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"photo_ids","type":"uuid[]","default":"'{}'::uuid[]","identity":"","not_null":false,"generated":""},{"name":"storm_event_ids","type":"uuid[]","default":"'{}'::uuid[]","identity":"","not_null":false,"generated":""},{"name":"ai_summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ai_concern_level","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"generated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"generated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"shared_with_homeowner_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"share_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"view_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"last_viewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"primary_storm_event_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tone","type":"text","default":"'strict'::text","identity":"","not_null":true,"generated":""},{"name":"ai_summary_override","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"photo_caption_overrides","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"hidden_photo_ids","type":"uuid[]","default":"'{}'::uuid[]","identity":"","not_null":true,"generated":""},{"name":"hidden_storm_event_ids","type":"uuid[]","default":"'{}'::uuid[]","identity":"","not_null":true,"generated":""},{"name":"concern_level_override","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"approved_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"approved_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"revoked_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"share_requires_approval","type":"boolean","default":"true","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_storm_reports_contact","definition":"CREATE INDEX idx_storm_reports_contact ON public.storm_reports USING btree (contact_id)"},{"name":"idx_storm_reports_generated_at","definition":"CREATE INDEX idx_storm_reports_generated_at ON public.storm_reports USING btree (generated_at DESC)"},{"name":"idx_storm_reports_tenant","definition":"CREATE INDEX idx_storm_reports_tenant ON public.storm_reports USING btree (tenant_org_id)"},{"name":"storm_reports_pkey","definition":"CREATE UNIQUE INDEX storm_reports_pkey ON public.storm_reports USING btree (id)"},{"name":"storm_reports_share_token_key","definition":"CREATE UNIQUE INDEX storm_reports_share_token_key ON public.storm_reports USING btree (share_token)"}],"policies":[{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND (user_roles.tenant_id = (storm_reports.tenant_org_id)::uuid) AND (user_roles.role = ANY (ARRAY['Admin'::app_role, 'GodMode'::app_role, 'Owner'::app_role]))))) OR is_system_admin(uid()))","roles":["public"],"tablename":"storm_reports","permissive":"PERMISSIVE","policyname":"Admins can delete storm reports","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"storm_reports","permissive":"PERMISSIVE","policyname":"Tenant members can create storm reports","schemaname":"public","with_check":"(((tenant_org_id)::uuid IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"(((tenant_org_id)::uuid IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) OR is_system_admin(uid()))","roles":["public"],"tablename":"storm_reports","permissive":"PERMISSIVE","policyname":"Tenant members can update storm reports","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(((tenant_org_id)::uuid IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) OR is_system_admin(uid()))","roles":["public"],"tablename":"storm_reports","permissive":"PERMISSIVE","policyname":"Tenant members can view storm reports","schemaname":"public","with_check":null}],"triggers":[{"name":"update_storm_reports_updated_at","definition":"CREATE TRIGGER update_storm_reports_updated_at BEFORE UPDATE ON storm_reports FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"storm_reports_ai_concern_level_check","definition":"CHECK (ai_concern_level = ANY (ARRAY['low'::text, 'medium'::text, 'high'::text]))"},{"name":"storm_reports_concern_level_override_check","definition":"CHECK (concern_level_override IS NULL OR (concern_level_override = ANY (ARRAY['low'::text, 'medium'::text, 'high'::text, 'all_clear'::text])))"},{"name":"storm_reports_pkey","definition":"PRIMARY KEY (id)"},{"name":"storm_reports_share_token_key","definition":"UNIQUE (share_token)"},{"name":"storm_reports_tone_check","definition":"CHECK (tone = ANY (ARRAY['strict'::text, 'type_hinted'::text]))"}]},{"table":"stripe_webhook_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"stripe_event_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"environment","type":"text","default":"'sandbox'::text","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"processed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"stripe_webhook_events_pkey","definition":"CREATE UNIQUE INDEX stripe_webhook_events_pkey ON public.stripe_webhook_events USING btree (id)"},{"name":"stripe_webhook_events_stripe_event_id_key","definition":"CREATE UNIQUE INDEX stripe_webhook_events_stripe_event_id_key ON public.stripe_webhook_events USING btree (stripe_event_id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"stripe_webhook_events","permissive":"PERMISSIVE","policyname":"Only system admins can read webhook events","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"stripe_webhook_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"stripe_webhook_events_stripe_event_id_key","definition":"UNIQUE (stripe_event_id)"}]},{"table":"subscription_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_plan_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_plan_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"payload","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_subscription_events_tenant","definition":"CREATE INDEX idx_subscription_events_tenant ON public.subscription_events USING btree (tenant_id, created_at DESC)"},{"name":"subscription_events_pkey","definition":"CREATE UNIQUE INDEX subscription_events_pkey ON public.subscription_events USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"subscription_events","permissive":"PERMISSIVE","policyname":"Only system admins write subscription events","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = subscription_events.tenant_id) AND (m.status = 'active'::text)))))","roles":["public"],"tablename":"subscription_events","permissive":"PERMISSIVE","policyname":"Tenant members read subscription events","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"subscription_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"suppressed_emails","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_suppressed_emails_email","definition":"CREATE INDEX idx_suppressed_emails_email ON public.suppressed_emails USING btree (email)"},{"name":"suppressed_emails_email_key","definition":"CREATE UNIQUE INDEX suppressed_emails_email_key ON public.suppressed_emails USING btree (email)"},{"name":"suppressed_emails_pkey","definition":"CREATE UNIQUE INDEX suppressed_emails_pkey ON public.suppressed_emails USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["service_role"],"tablename":"suppressed_emails","permissive":"PERMISSIVE","policyname":"Service role can insert suppressed emails","schemaname":"public","with_check":"true"},{"cmd":"SELECT","qual":"true","roles":["service_role"],"tablename":"suppressed_emails","permissive":"PERMISSIVE","policyname":"Service role can read suppressed emails","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"suppressed_emails_email_key","definition":"UNIQUE (email)"},{"name":"suppressed_emails_pkey","definition":"PRIMARY KEY (id)"},{"name":"suppressed_emails_reason_check","definition":"CHECK (reason = ANY (ARRAY['unsubscribe'::text, 'bounce'::text, 'complaint'::text]))"}]},{"table":"system_health_metrics","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"metric_category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metric_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"value","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'healthy'::text","identity":"","not_null":false,"generated":""},{"name":"details","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"timestamp","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_system_health_category","definition":"CREATE INDEX idx_system_health_category ON public.system_health_metrics USING btree (metric_category)"},{"name":"idx_system_health_timestamp","definition":"CREATE INDEX idx_system_health_timestamp ON public.system_health_metrics USING btree (\"timestamp\" DESC)"},{"name":"system_health_metrics_pkey","definition":"CREATE UNIQUE INDEX system_health_metrics_pkey ON public.system_health_metrics USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"system_health_metrics","permissive":"PERMISSIVE","policyname":"admins_insert_health_metrics","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"system_health_metrics","permissive":"PERMISSIVE","policyname":"platform_admin_view_system_health","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"system_health_metrics_pkey","definition":"PRIMARY KEY (id)"},{"name":"system_health_metrics_status_check","definition":"CHECK (status = ANY (ARRAY['healthy'::text, 'degraded'::text, 'critical'::text]))"}]},{"table":"system_variable_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenancy_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"variable_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"variable_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"variable_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"variable_type","type":"variable_type","default":"'text'::variable_type","identity":"","not_null":true,"generated":""},{"name":"scope","type":"variable_scope","default":"'workflow'::variable_scope","identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_system_variable_templates_category","definition":"CREATE INDEX idx_system_variable_templates_category ON public.system_variable_templates USING btree (category)"},{"name":"idx_system_variable_templates_scope","definition":"CREATE INDEX idx_system_variable_templates_scope ON public.system_variable_templates USING btree (scope)"},{"name":"idx_system_variable_templates_tenancy","definition":"CREATE INDEX idx_system_variable_templates_tenancy ON public.system_variable_templates USING btree (tenancy_type)"},{"name":"system_variable_templates_pkey","definition":"CREATE UNIQUE INDEX system_variable_templates_pkey ON public.system_variable_templates USING btree (id)"},{"name":"system_variable_templates_tenancy_type_variable_key_key","definition":"CREATE UNIQUE INDEX system_variable_templates_tenancy_type_variable_key_key ON public.system_variable_templates USING btree (tenancy_type, variable_key)"}],"policies":[{"cmd":"SELECT","qual":"(is_active = true)","roles":["authenticated"],"tablename":"system_variable_templates","permissive":"PERMISSIVE","policyname":"Authenticated users can view system variable templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"system_variable_templates","permissive":"PERMISSIVE","policyname":"platform_admin_manage_system_variable_templates","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[{"name":"update_system_variable_templates_updated_at","definition":"CREATE TRIGGER update_system_variable_templates_updated_at BEFORE UPDATE ON system_variable_templates FOR EACH ROW EXECUTE FUNCTION update_system_variable_templates_updated_at()"}],"constraints":[{"name":"system_variable_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"system_variable_templates_tenancy_type_variable_key_key","definition":"UNIQUE (tenancy_type, variable_key)"}]},{"table":"tarping_invoices_migration_20260917","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"invoice_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"invoice_date","type":"date","default":"CURRENT_DATE","identity":"","not_null":true,"generated":""},{"name":"terms","type":"text","default":"'Upon Receipt'::text","identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":false,"generated":""},{"name":"insured_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"insured_poa","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_address","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"insurance_carrier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"materials_items","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"labor_items","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"materials_subtotal","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"labor_subtotal","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"grand_total","type":"numeric","default":"0","identity":"","not_null":false,"generated":""},{"name":"service_description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"important_notice","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"photo_urls","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"pdf_file_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pdf_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"paid_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"job_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"crew_size","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"anchor_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"distance_note","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"special_conditions","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"trip_miles","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"trip_hours","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"date_of_loss","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_tarping_invoices_contact","definition":"CREATE INDEX idx_tarping_invoices_contact ON public.tarping_invoices_migration_20260917 USING btree (contact_id)"},{"name":"idx_tarping_invoices_invoice_number","definition":"CREATE INDEX idx_tarping_invoices_invoice_number ON public.tarping_invoices_migration_20260917 USING btree (invoice_number)"},{"name":"idx_tarping_invoices_status","definition":"CREATE INDEX idx_tarping_invoices_status ON public.tarping_invoices_migration_20260917 USING btree (status)"},{"name":"idx_tarping_invoices_tenant","definition":"CREATE INDEX idx_tarping_invoices_tenant ON public.tarping_invoices_migration_20260917 USING btree (tenant_org_id)"},{"name":"tarping_invoices_pkey","definition":"CREATE UNIQUE INDEX tarping_invoices_pkey ON public.tarping_invoices_migration_20260917 USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"Users create tenant tarping invoices","schemaname":"public","with_check":"((tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid()))) AND (created_by = uid()))"},{"cmd":"DELETE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"Users delete tenant tarping invoices","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"Users update tenant tarping invoices","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"Users view tenant tarping invoices","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (tarping_invoices_migration_20260917.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"tenant_users_delete_tarping_invoices","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"tenant_users_insert_tarping_invoices","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (tarping_invoices_migration_20260917.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"UPDATE","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (tarping_invoices_migration_20260917.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"tenant_users_update_tarping_invoices","schemaname":"public","with_check":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (tarping_invoices_migration_20260917.tenant_org_id)::uuid)))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = (tarping_invoices_migration_20260917.tenant_org_id)::uuid)))) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"tenant_users_view_tarping_invoices","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"ti_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"ti_insert","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) OR is_system_admin())"},{"cmd":"SELECT","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"ti_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"tarping_invoices_migration_20260917","permissive":"PERMISSIVE","policyname":"ti_update","schemaname":"public","with_check":null}],"triggers":[{"name":"tarping_invoices_updated_at","definition":"CREATE TRIGGER tarping_invoices_updated_at BEFORE UPDATE ON tarping_invoices_migration_20260917 FOR EACH ROW EXECUTE FUNCTION update_tarping_invoices_updated_at()"}],"constraints":[{"name":"tarping_invoices_pkey","definition":"PRIMARY KEY (id)"},{"name":"tarping_invoices_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'sent'::text, 'paid'::text, 'cancelled'::text]))"}]},{"table":"tasks","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assigned_to","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority","type":"text","default":"'medium'::text","identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"due_date","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"reminder_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"claim_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_kind","type":"text","default":"(metadata ->> 'source_kind'::text)","identity":"","not_null":false,"generated":"s"},{"name":"source_id","type":"text","default":"(metadata ->> 'source_id'::text)","identity":"","not_null":false,"generated":"s"},{"name":"canonical_contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_tasks_assigned_to","definition":"CREATE INDEX idx_tasks_assigned_to ON public.tasks USING btree (assigned_to)"},{"name":"idx_tasks_contact_id","definition":"CREATE INDEX idx_tasks_contact_id ON public.tasks USING btree (contact_id)"},{"name":"idx_tasks_due_date","definition":"CREATE INDEX idx_tasks_due_date ON public.tasks USING btree (due_date)"},{"name":"idx_tasks_status","definition":"CREATE INDEX idx_tasks_status ON public.tasks USING btree (status)"},{"name":"idx_tasks_tenant_claim","definition":"CREATE INDEX idx_tasks_tenant_claim ON public.tasks USING btree (tenant_id, claim_id) WHERE (claim_id IS NOT NULL)"},{"name":"idx_tasks_tenant_id","definition":"CREATE INDEX idx_tasks_tenant_id ON public.tasks USING btree (tenant_id)"},{"name":"tasks_pkey","definition":"CREATE UNIQUE INDEX tasks_pkey ON public.tasks USING btree (id)"},{"name":"tasks_tenant_source_columns_uidx","definition":"CREATE UNIQUE INDEX tasks_tenant_source_columns_uidx ON public.tasks USING btree (tenant_id, source_kind, source_id) WHERE ((source_kind IS NOT NULL) AND (source_id IS NOT NULL))"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"tasks","permissive":"PERMISSIVE","policyname":"Users create tenant tasks","schemaname":"public","with_check":"((uid() = user_id) AND (is_tenant_member(tenant_id) OR is_system_admin()))"},{"cmd":"DELETE","qual":"(((uid() = user_id) OR (uid() = assigned_to)) AND (is_tenant_member(tenant_id) OR is_system_admin()))","roles":["public"],"tablename":"tasks","permissive":"PERMISSIVE","policyname":"Users delete their tasks","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((( SELECT uid() AS uid) IS NOT NULL) AND is_tenant_member(tenant_id) AND ((( SELECT uid() AS uid) = user_id) OR (( SELECT uid() AS uid) = assigned_to)))","roles":["authenticated"],"tablename":"tasks","permissive":"PERMISSIVE","policyname":"Users update their tasks","schemaname":"public","with_check":"((( SELECT uid() AS uid) IS NOT NULL) AND is_tenant_member(tenant_id) AND ((( SELECT uid() AS uid) = user_id) OR (( SELECT uid() AS uid) = assigned_to)))"},{"cmd":"SELECT","qual":"((uid() = assigned_to) OR (uid() = user_id) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = tasks.tenant_id)))))","roles":["public"],"tablename":"tasks","permissive":"PERMISSIVE","policyname":"Users view assigned tasks","schemaname":"public","with_check":null}],"triggers":[{"name":"task_calendar_projection","definition":"CREATE TRIGGER task_calendar_projection AFTER INSERT OR DELETE OR UPDATE ON tasks FOR EACH ROW EXECUTE FUNCTION sync_task_calendar_projection()"},{"name":"tasks_assignment_canonical_notification","definition":"CREATE TRIGGER tasks_assignment_canonical_notification AFTER INSERT OR UPDATE OF assigned_to ON tasks FOR EACH ROW EXECUTE FUNCTION notify_task_assignment()"},{"name":"tasks_business_activity","definition":"CREATE TRIGGER tasks_business_activity AFTER INSERT OR UPDATE ON tasks FOR EACH ROW EXECUTE FUNCTION project_task_business_activity()"},{"name":"tasks_coordination_scope","definition":"CREATE TRIGGER tasks_coordination_scope BEFORE INSERT OR UPDATE OF tenant_id, user_id, assigned_to ON tasks FOR EACH ROW EXECUTE FUNCTION enforce_task_coordination_scope()"},{"name":"tasks_updated_at","definition":"CREATE TRIGGER tasks_updated_at BEFORE UPDATE ON tasks FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"},{"name":"trg_enforce_task_claim_context","definition":"CREATE TRIGGER trg_enforce_task_claim_context BEFORE INSERT OR UPDATE OF claim_id, contact_id, tenant_id ON tasks FOR EACH ROW EXECUTE FUNCTION enforce_task_claim_context()"}],"constraints":[{"name":"tasks_canonical_contact_fkey","definition":"FOREIGN KEY (canonical_contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"tasks_claim_id_fkey","definition":"FOREIGN KEY (claim_id) REFERENCES contact_claims(id) ON DELETE SET NULL"},{"name":"tasks_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"template_studio_publish_receipts","schema":"public","columns":[{"name":"id","type":"bigint","default":null,"identity":"d","not_null":true,"generated":""},{"name":"template_version_id","type":"bigint","default":null,"identity":"","not_null":true,"generated":""},{"name":"receipt_status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"receipt","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":"uid()","identity":"","not_null":false,"generated":""},{"name":"created_by_label","type":"text","default":"'GodMode'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_template_studio_receipts_version","definition":"CREATE INDEX idx_template_studio_receipts_version ON public.template_studio_publish_receipts USING btree (template_version_id, created_at DESC)"},{"name":"template_studio_publish_receipts_pkey","definition":"CREATE UNIQUE INDEX template_studio_publish_receipts_pkey ON public.template_studio_publish_receipts USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"can_manage_experience_studio()","roles":["authenticated"],"tablename":"template_studio_publish_receipts","permissive":"PERMISSIVE","policyname":"experience studio admins manage receipts","schemaname":"public","with_check":"can_manage_experience_studio()"},{"cmd":"ALL","qual":"is_manager_pm_or_higher(uid(), NULL::uuid)","roles":["authenticated"],"tablename":"template_studio_publish_receipts","permissive":"PERMISSIVE","policyname":"template studio godmode all receipts","schemaname":"public","with_check":"is_manager_pm_or_higher(uid(), NULL::uuid)"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"template_studio_publish_receipts","permissive":"PERMISSIVE","policyname":"template studio platform admin insert receipts","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"template_studio_publish_receipts","permissive":"PERMISSIVE","policyname":"template studio platform admin read receipts","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"template_studio_publish_receipts_pkey","definition":"PRIMARY KEY (id)"},{"name":"template_studio_publish_receipts_receipt_status_check","definition":"CHECK (receipt_status = ANY (ARRAY['LOCAL_DRAFT'::text, 'VALIDATED_DRAFT'::text, 'BLOCKED_DRAFT'::text, 'PUBLISHED'::text, 'RETIRED'::text]))"},{"name":"template_studio_publish_receipts_template_version_id_fkey","definition":"FOREIGN KEY (template_version_id) REFERENCES template_studio_template_versions(id) ON DELETE CASCADE"}]},{"table":"template_studio_template_versions","schema":"public","columns":[{"name":"id","type":"bigint","default":null,"identity":"d","not_null":true,"generated":""},{"name":"template_id","type":"bigint","default":null,"identity":"","not_null":true,"generated":""},{"name":"version","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"version_status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"schema_version","type":"text","default":"'template-studio.v1'::text","identity":"","not_null":true,"generated":""},{"name":"payload","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"validation_receipt","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":"uid()","identity":"","not_null":false,"generated":""},{"name":"created_by_label","type":"text","default":"'GodMode'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"published_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"published_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_template_studio_versions_template","definition":"CREATE INDEX idx_template_studio_versions_template ON public.template_studio_template_versions USING btree (template_id, version_status, created_at DESC)"},{"name":"template_studio_template_versions_pkey","definition":"CREATE UNIQUE INDEX template_studio_template_versions_pkey ON public.template_studio_template_versions USING btree (id)"},{"name":"template_studio_template_versions_template_id_version_key","definition":"CREATE UNIQUE INDEX template_studio_template_versions_template_id_version_key ON public.template_studio_template_versions USING btree (template_id, version)"}],"policies":[{"cmd":"ALL","qual":"can_manage_experience_studio()","roles":["authenticated"],"tablename":"template_studio_template_versions","permissive":"PERMISSIVE","policyname":"experience studio admins manage versions","schemaname":"public","with_check":"can_manage_experience_studio()"},{"cmd":"ALL","qual":"is_manager_pm_or_higher(uid(), NULL::uuid)","roles":["authenticated"],"tablename":"template_studio_template_versions","permissive":"PERMISSIVE","policyname":"template studio godmode all versions","schemaname":"public","with_check":"is_manager_pm_or_higher(uid(), NULL::uuid)"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"template_studio_template_versions","permissive":"PERMISSIVE","policyname":"template studio platform admin insert versions","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"template_studio_template_versions","permissive":"PERMISSIVE","policyname":"template studio platform admin read versions","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"template_studio_template_versions","permissive":"PERMISSIVE","policyname":"template studio platform admin update versions","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"template_studio_template_versions_pkey","definition":"PRIMARY KEY (id)"},{"name":"template_studio_template_versions_template_id_fkey","definition":"FOREIGN KEY (template_id) REFERENCES template_studio_templates(id) ON DELETE CASCADE"},{"name":"template_studio_template_versions_template_id_version_key","definition":"UNIQUE (template_id, version)"},{"name":"template_studio_template_versions_version_status_check","definition":"CHECK (version_status = ANY (ARRAY['LOCAL_DRAFT'::text, 'VALIDATED_DRAFT'::text, 'BLOCKED_DRAFT'::text, 'PUBLISHED'::text, 'RETIRED'::text]))"}]},{"table":"template_studio_templates","schema":"public","columns":[{"name":"id","type":"bigint","default":null,"identity":"d","not_null":true,"generated":""},{"name":"template_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_template_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"domain","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"vertical","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lane","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lifecycle_status","type":"text","default":"'DRAFT'::text","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":"uid()","identity":"","not_null":false,"generated":""},{"name":"created_by_label","type":"text","default":"'GodMode'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_template_studio_templates_source","definition":"CREATE INDEX idx_template_studio_templates_source ON public.template_studio_templates USING btree (source_template_id)"},{"name":"idx_template_studio_templates_status","definition":"CREATE INDEX idx_template_studio_templates_status ON public.template_studio_templates USING btree (lifecycle_status)"},{"name":"template_studio_templates_pkey","definition":"CREATE UNIQUE INDEX template_studio_templates_pkey ON public.template_studio_templates USING btree (id)"},{"name":"template_studio_templates_template_key_key","definition":"CREATE UNIQUE INDEX template_studio_templates_template_key_key ON public.template_studio_templates USING btree (template_key)"}],"policies":[{"cmd":"ALL","qual":"can_manage_experience_studio()","roles":["authenticated"],"tablename":"template_studio_templates","permissive":"PERMISSIVE","policyname":"experience studio admins manage templates","schemaname":"public","with_check":"can_manage_experience_studio()"},{"cmd":"ALL","qual":"is_manager_pm_or_higher(uid(), NULL::uuid)","roles":["authenticated"],"tablename":"template_studio_templates","permissive":"PERMISSIVE","policyname":"template studio godmode all templates","schemaname":"public","with_check":"is_manager_pm_or_higher(uid(), NULL::uuid)"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"template_studio_templates","permissive":"PERMISSIVE","policyname":"template studio platform admin insert templates","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"template_studio_templates","permissive":"PERMISSIVE","policyname":"template studio platform admin read templates","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"template_studio_templates","permissive":"PERMISSIVE","policyname":"template studio platform admin update templates","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"template_studio_templates_lifecycle_status_check","definition":"CHECK (lifecycle_status = ANY (ARRAY['DRAFT'::text, 'ACTIVE'::text, 'RETIRED'::text]))"},{"name":"template_studio_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"template_studio_templates_template_key_key","definition":"UNIQUE (template_key)"}]},{"table":"template_studio_tenant_applications","schema":"public","columns":[{"name":"id","type":"bigint","default":null,"identity":"d","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_version_id","type":"bigint","default":null,"identity":"","not_null":true,"generated":""},{"name":"application_status","type":"text","default":"'STAGED'::text","identity":"","not_null":true,"generated":""},{"name":"apply_receipt","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"applied_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"applied_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"rolled_back_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"rolled_back_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"scope_type","type":"text","default":"'tenant'::text","identity":"","not_null":true,"generated":""},{"name":"scope_id","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_template_studio_applications_scope","definition":"CREATE INDEX idx_template_studio_applications_scope ON public.template_studio_tenant_applications USING btree (scope_type, scope_id, application_status)"},{"name":"idx_template_studio_applications_tenant","definition":"CREATE INDEX idx_template_studio_applications_tenant ON public.template_studio_tenant_applications USING btree (tenant_id, application_status)"},{"name":"template_studio_tenant_applic_tenant_id_template_version_id_key","definition":"CREATE UNIQUE INDEX template_studio_tenant_applic_tenant_id_template_version_id_key ON public.template_studio_tenant_applications USING btree (tenant_id, template_version_id)"},{"name":"template_studio_tenant_applications_pkey","definition":"CREATE UNIQUE INDEX template_studio_tenant_applications_pkey ON public.template_studio_tenant_applications USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"can_manage_experience_studio()","roles":["authenticated"],"tablename":"template_studio_tenant_applications","permissive":"PERMISSIVE","policyname":"experience studio admins manage applications","schemaname":"public","with_check":"can_manage_experience_studio()"},{"cmd":"ALL","qual":"is_manager_pm_or_higher(uid(), tenant_id)","roles":["authenticated"],"tablename":"template_studio_tenant_applications","permissive":"PERMISSIVE","policyname":"template studio godmode all applications","schemaname":"public","with_check":"is_manager_pm_or_higher(uid(), tenant_id)"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"template_studio_tenant_applications","permissive":"PERMISSIVE","policyname":"template studio platform admin insert applications","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"template_studio_tenant_applications","permissive":"PERMISSIVE","policyname":"template studio platform admin read applications","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"template_studio_tenant_applications","permissive":"PERMISSIVE","policyname":"template studio platform admin update applications","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"template_studio_tenant_applic_tenant_id_template_version_id_key","definition":"UNIQUE (tenant_id, template_version_id)"},{"name":"template_studio_tenant_applications_application_status_check","definition":"CHECK (application_status = ANY (ARRAY['STAGED'::text, 'APPLIED'::text, 'ROLLED_BACK'::text, 'RETIRED'::text]))"},{"name":"template_studio_tenant_applications_pkey","definition":"PRIMARY KEY (id)"},{"name":"template_studio_tenant_applications_scope_type_check","definition":"CHECK (scope_type = ANY (ARRAY['tenant'::text, 'god_mode'::text, 'admin'::text, 'platform'::text]))"},{"name":"template_studio_tenant_applications_template_version_id_fkey","definition":"FOREIGN KEY (template_version_id) REFERENCES template_studio_template_versions(id)"}]},{"table":"tenant_ad_analytics_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"utm_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"utm_medium","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"utm_campaign","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"utm_content","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"landing_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"referrer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"session_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_ad_analytics_events_campaign_idx","definition":"CREATE INDEX tenant_ad_analytics_events_campaign_idx ON public.tenant_ad_analytics_events USING btree (tenant_org_id, utm_source, utm_campaign, utm_content, occurred_at DESC)"},{"name":"tenant_ad_analytics_events_pkey","definition":"CREATE UNIQUE INDEX tenant_ad_analytics_events_pkey ON public.tenant_ad_analytics_events USING btree (id)"},{"name":"tenant_ad_analytics_events_session_dedupe_idx","definition":"CREATE UNIQUE INDEX tenant_ad_analytics_events_session_dedupe_idx ON public.tenant_ad_analytics_events USING btree (tenant_org_id, event_type, session_key, COALESCE(utm_source, ''::text), COALESCE(utm_campaign, ''::text), COALESCE(utm_content, ''::text)) WHERE (session_key IS NOT NULL)"},{"name":"tenant_ad_analytics_events_tenant_time_idx","definition":"CREATE INDEX tenant_ad_analytics_events_tenant_time_idx ON public.tenant_ad_analytics_events USING btree (tenant_org_id, occurred_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"tenant_ad_analytics_events","permissive":"PERMISSIVE","policyname":"tenant members can read ad analytics","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"tenant_ad_analytics_events_event_type_check","definition":"CHECK (event_type = 'landing_view'::text)"},{"name":"tenant_ad_analytics_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_ad_analytics_events_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"tenant_applications","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"application_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"installed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"settings","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"bootstrap_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_applications_app_idx","definition":"CREATE INDEX tenant_applications_app_idx ON public.tenant_applications USING btree (application_id)"},{"name":"tenant_applications_pkey","definition":"CREATE UNIQUE INDEX tenant_applications_pkey ON public.tenant_applications USING btree (id)"},{"name":"tenant_applications_tenant_id_application_id_key","definition":"CREATE UNIQUE INDEX tenant_applications_tenant_id_application_id_key ON public.tenant_applications USING btree (tenant_id, application_id)"},{"name":"tenant_applications_tenant_idx","definition":"CREATE INDEX tenant_applications_tenant_idx ON public.tenant_applications USING btree (tenant_id)"}],"policies":[{"cmd":"SELECT","qual":"(is_platform_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM user_tenant_access uta\n  WHERE ((uta.user_id = uid()) AND (uta.tenant_id = tenant_applications.tenant_id) AND (COALESCE(uta.membership_status, 'active'::text) = 'active'::text)))))","roles":["authenticated"],"tablename":"tenant_applications","permissive":"PERMISSIVE","policyname":"tenant_applications_member_read","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_tenant_applications_manifest_stale","definition":"CREATE TRIGGER trg_tenant_applications_manifest_stale AFTER INSERT OR DELETE OR UPDATE OF application_id, enabled ON tenant_applications FOR EACH ROW EXECUTE FUNCTION mark_tenant_application_manifest_stale()"}],"constraints":[{"name":"tenant_applications_application_id_fkey","definition":"FOREIGN KEY (application_id) REFERENCES application_catalog(id) ON DELETE CASCADE"},{"name":"tenant_applications_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_applications_tenant_id_application_id_key","definition":"UNIQUE (tenant_id, application_id)"},{"name":"tenant_applications_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"tenant_capability_delegations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"capability","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"principal_key","type":"text","default":"'command_center'::text","identity":"","not_null":true,"generated":""},{"name":"delegated_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"granted_by_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_capability_delegations_lookup_idx","definition":"CREATE INDEX tenant_capability_delegations_lookup_idx ON public.tenant_capability_delegations USING btree (tenant_id, capability, principal_key, enabled, expires_at)"},{"name":"tenant_capability_delegations_pkey","definition":"CREATE UNIQUE INDEX tenant_capability_delegations_pkey ON public.tenant_capability_delegations USING btree (id)"},{"name":"tenant_capability_delegations_tenant_id_capability_principa_key","definition":"CREATE UNIQUE INDEX tenant_capability_delegations_tenant_id_capability_principa_key ON public.tenant_capability_delegations USING btree (tenant_id, capability, principal_key)"}],"policies":[],"triggers":[],"constraints":[{"name":"tenant_capability_delegations_capability_check","definition":"CHECK (capability ~ '^[a-z][a-z0-9_]*\\.[a-z][a-z0-9_]*$'::text)"},{"name":"tenant_capability_delegations_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_capability_delegations_principal_key_check","definition":"CHECK (principal_key = 'command_center'::text)"},{"name":"tenant_capability_delegations_tenant_id_capability_principa_key","definition":"UNIQUE (tenant_id, capability, principal_key)"}]},{"table":"tenant_capability_providers","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"capability","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"adapter_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"connection_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"priority","type":"integer","default":"100","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_capability_providers_pkey","definition":"CREATE UNIQUE INDEX tenant_capability_providers_pkey ON public.tenant_capability_providers USING btree (id)"},{"name":"tenant_capability_providers_resolution_idx","definition":"CREATE INDEX tenant_capability_providers_resolution_idx ON public.tenant_capability_providers USING btree (tenant_id, capability, enabled, priority, created_at)"},{"name":"tenant_capability_providers_tenant_id_capability_provider_k_key","definition":"CREATE UNIQUE INDEX tenant_capability_providers_tenant_id_capability_provider_k_key ON public.tenant_capability_providers USING btree (tenant_id, capability, provider_key)"}],"policies":[],"triggers":[],"constraints":[{"name":"tenant_capability_providers_adapter_key_check","definition":"CHECK (length(TRIM(BOTH FROM adapter_key)) > 0)"},{"name":"tenant_capability_providers_capability_check","definition":"CHECK (capability ~ '^[a-z][a-z0-9_]*\\.[a-z][a-z0-9_]*$'::text)"},{"name":"tenant_capability_providers_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_capability_providers_priority_check","definition":"CHECK (priority >= 0 AND priority <= 10000)"},{"name":"tenant_capability_providers_provider_key_check","definition":"CHECK (length(TRIM(BOTH FROM provider_key)) > 0)"},{"name":"tenant_capability_providers_tenant_id_capability_provider_k_key","definition":"UNIQUE (tenant_id, capability, provider_key)"}]},{"table":"tenant_compliance_profiles","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"brokerage_legal_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"broker_of_record","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"broker_license_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"team_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"approved_disclaimer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"approved_call_script","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"approved_sms_disclaimer","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"template_approval_required","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"campaign_approval_required","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_compliance_profiles_pkey","definition":"CREATE UNIQUE INDEX tenant_compliance_profiles_pkey ON public.tenant_compliance_profiles USING btree (id)"},{"name":"tenant_compliance_profiles_tenant_id_key","definition":"CREATE UNIQUE INDEX tenant_compliance_profiles_tenant_id_key ON public.tenant_compliance_profiles USING btree (tenant_id)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"tenant_compliance_profiles","permissive":"PERMISSIVE","policyname":"compliance_delete_owner","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"tenant_compliance_profiles","permissive":"PERMISSIVE","policyname":"compliance_insert_owner","schemaname":"public","with_check":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())"},{"cmd":"SELECT","qual":"(is_tenant_member(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"tenant_compliance_profiles","permissive":"PERMISSIVE","policyname":"compliance_select_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())","roles":["authenticated"],"tablename":"tenant_compliance_profiles","permissive":"PERMISSIVE","policyname":"compliance_update_owner","schemaname":"public","with_check":"(is_tenant_owner(uid(), tenant_id) OR is_system_admin())"}],"triggers":[{"name":"trg_compliance_updated","definition":"CREATE TRIGGER trg_compliance_updated BEFORE UPDATE ON tenant_compliance_profiles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"tenant_compliance_profiles_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_compliance_profiles_tenant_id_key","definition":"UNIQUE (tenant_id)"}]},{"table":"tenant_content_integrity_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"content_table","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"content_row_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"scope_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"action_taken","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"details","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_content_integrity_events_pkey","definition":"CREATE UNIQUE INDEX tenant_content_integrity_events_pkey ON public.tenant_content_integrity_events USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"tenant_content_integrity_events","permissive":"PERMISSIVE","policyname":"authenticated tenant users may record tenant content integrity ","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = tenant_content_integrity_events.tenant_org_id))))))"},{"cmd":"SELECT","qual":"(((tenant_org_id IS NULL) AND is_system_admin(uid())) OR ((tenant_org_id IS NOT NULL) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = tenant_content_integrity_events.tenant_org_id)))))))","roles":["authenticated"],"tablename":"tenant_content_integrity_events","permissive":"PERMISSIVE","policyname":"tenant content integrity events are admin-auditable","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"tenant_content_integrity_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_content_integrity_events_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE SET NULL"}]},{"table":"tenant_drive_folders","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"root_folder_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"templates_folder_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"agreements_folder_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"signed_agreements_folder_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"documents_folder_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"provisioned_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"provisioned_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"provisioning_status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"provisioning_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_tenant_drive_folders_status","definition":"CREATE INDEX idx_tenant_drive_folders_status ON public.tenant_drive_folders USING btree (provisioning_status)"},{"name":"idx_tenant_drive_folders_tenant","definition":"CREATE INDEX idx_tenant_drive_folders_tenant ON public.tenant_drive_folders USING btree (tenant_id)"},{"name":"tenant_drive_folders_pkey","definition":"CREATE UNIQUE INDEX tenant_drive_folders_pkey ON public.tenant_drive_folders USING btree (id)"},{"name":"uq_tenant_drive_folder","definition":"CREATE UNIQUE INDEX uq_tenant_drive_folder ON public.tenant_drive_folders USING btree (tenant_id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.tenant_id = tenant_drive_folders.tenant_id))))","roles":["public"],"tablename":"tenant_drive_folders","permissive":"PERMISSIVE","policyname":"Users can view tenant folders","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"tenant_drive_folders","permissive":"PERMISSIVE","policyname":"platform_admin_manage_tenant_drive_folders","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"tenant_drive_folders_pkey","definition":"PRIMARY KEY (id)"},{"name":"uq_tenant_drive_folder","definition":"UNIQUE (tenant_id)"}]},{"table":"tenant_feature_entitlements","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"feature_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"feature_entitlement_status","default":"'default'::feature_entitlement_status","identity":"","not_null":true,"generated":""},{"name":"source","type":"feature_entitlement_source","default":"'default'::feature_entitlement_source","identity":"","not_null":true,"generated":""},{"name":"plan_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"enabled_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"enabled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"disabled_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"disabled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_tfe_feature","definition":"CREATE INDEX idx_tfe_feature ON public.tenant_feature_entitlements USING btree (feature_key)"},{"name":"idx_tfe_tenant","definition":"CREATE INDEX idx_tfe_tenant ON public.tenant_feature_entitlements USING btree (tenant_org_id)"},{"name":"tenant_feature_entitlements_pkey","definition":"CREATE UNIQUE INDEX tenant_feature_entitlements_pkey ON public.tenant_feature_entitlements USING btree (id)"},{"name":"tenant_feature_entitlements_tenant_org_id_feature_key_key","definition":"CREATE UNIQUE INDEX tenant_feature_entitlements_tenant_org_id_feature_key_key ON public.tenant_feature_entitlements USING btree (tenant_org_id, feature_key)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"tenant_feature_entitlements","permissive":"PERMISSIVE","policyname":"tfe system admin all","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"tenant_feature_entitlements","permissive":"PERMISSIVE","policyname":"tfe tenant members read","schemaname":"public","with_check":null}],"triggers":[{"name":"tfe_set_updated_at","definition":"CREATE TRIGGER tfe_set_updated_at BEFORE UPDATE ON tenant_feature_entitlements FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"tenant_feature_entitlements_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_feature_entitlements_tenant_org_id_feature_key_key","definition":"UNIQUE (tenant_org_id, feature_key)"}]},{"table":"tenant_google_workspace_connections","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"account_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"account_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"connection_role","type":"text","default":"'secondary'::text","identity":"","not_null":true,"generated":""},{"name":"is_primary","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"ciphertext","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"iv","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"key_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"credential_status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"verification_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"provider_account_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"actor_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"granted_scopes","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_google_workspace_connections_one_primary_uq","definition":"CREATE UNIQUE INDEX tenant_google_workspace_connections_one_primary_uq ON public.tenant_google_workspace_connections USING btree (tenant_id) WHERE ((is_primary = true) AND (credential_status = 'active'::text))"},{"name":"tenant_google_workspace_connections_pkey","definition":"CREATE UNIQUE INDEX tenant_google_workspace_connections_pkey ON public.tenant_google_workspace_connections USING btree (id)"},{"name":"tenant_google_workspace_connections_scopes_gin","definition":"CREATE INDEX tenant_google_workspace_connections_scopes_gin ON public.tenant_google_workspace_connections USING gin (granted_scopes)"},{"name":"tenant_google_workspace_connections_tenant_actor_idx","definition":"CREATE INDEX tenant_google_workspace_connections_tenant_actor_idx ON public.tenant_google_workspace_connections USING btree (tenant_id, actor_user_id)"},{"name":"tenant_google_workspace_connections_tenant_email_uq","definition":"CREATE UNIQUE INDEX tenant_google_workspace_connections_tenant_email_uq ON public.tenant_google_workspace_connections USING btree (tenant_id, lower(account_email)) WHERE (account_email IS NOT NULL)"},{"name":"tenant_google_workspace_connections_tenant_idx","definition":"CREATE INDEX tenant_google_workspace_connections_tenant_idx ON public.tenant_google_workspace_connections USING btree (tenant_id, credential_status)"},{"name":"tenant_google_workspace_connections_tenant_provider_account_uid","definition":"CREATE UNIQUE INDEX tenant_google_workspace_connections_tenant_provider_account_uid ON public.tenant_google_workspace_connections USING btree (tenant_id, provider_account_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"tenant_google_workspace_connections_connection_role_check","definition":"CHECK (connection_role = ANY (ARRAY['primary'::text, 'secondary'::text, 'legacy'::text, 'import_source'::text]))"},{"name":"tenant_google_workspace_connections_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"tenant_handoff_policy","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"policy","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"enrolled_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_handoff_policy_pkey","definition":"CREATE UNIQUE INDEX tenant_handoff_policy_pkey ON public.tenant_handoff_policy USING btree (tenant_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"tenant_handoff_policy_pkey","definition":"PRIMARY KEY (tenant_id)"},{"name":"tenant_handoff_policy_policy_check","definition":"CHECK (policy = ANY (ARRAY['legacy_exempt'::text, 'verification_required'::text]))"},{"name":"tenant_handoff_policy_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"tenant_handoff_verified_receipts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"check_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"proof_gate","type":"text","default":"'claim_matched_live_canary_verified'::text","identity":"","not_null":true,"generated":""},{"name":"source_sha","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"runtime_sha","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"issuer","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"evidence","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"verified_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":"(now() + '30 days'::interval)","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_handoff_proofs_current","definition":"CREATE INDEX tenant_handoff_proofs_current ON public.tenant_handoff_verified_receipts USING btree (tenant_id, source_sha, runtime_sha, check_id, verified_at DESC)"},{"name":"tenant_handoff_verified_receipts_pkey","definition":"CREATE UNIQUE INDEX tenant_handoff_verified_receipts_pkey ON public.tenant_handoff_verified_receipts USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"tenant_handoff_proof_expiry_valid","definition":"CHECK (expires_at > verified_at AND expires_at <= (verified_at + '30 days'::interval))"},{"name":"tenant_handoff_verified_receipts_check_id_check","definition":"CHECK (check_id = ANY (ARRAY['tenant-isolation'::text, 'owner-access'::text, 'storage-integrity'::text, 'route-and-mobile'::text, 'intake_or_upload_enabled'::text, 'public_website_enabled'::text, 'ai_processing_enabled'::text, 'external_connector_configured'::text, 'billing_or_messaging_enabled'::text]))"},{"name":"tenant_handoff_verified_receipts_evidence_check","definition":"CHECK (jsonb_typeof(evidence) = 'object'::text AND evidence ? 'verification_kind'::text AND evidence ? 'subject_tenant_id'::text)"},{"name":"tenant_handoff_verified_receipts_issuer_check","definition":"CHECK (issuer = ANY (ARRAY['tenant-handoff-auditor'::text, 'canonical-visual-witness'::text, 'canonical-provider-witness'::text, 'canonical-db-rls-probe'::text]))"},{"name":"tenant_handoff_verified_receipts_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_handoff_verified_receipts_proof_gate_check","definition":"CHECK (proof_gate = 'claim_matched_live_canary_verified'::text)"},{"name":"tenant_handoff_verified_receipts_runtime_sha_check","definition":"CHECK (length(runtime_sha) >= 12 AND length(runtime_sha) <= 128)"},{"name":"tenant_handoff_verified_receipts_source_sha_check","definition":"CHECK (length(source_sha) >= 24 AND length(source_sha) <= 128)"},{"name":"tenant_handoff_verified_receipts_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"tenant_mail_continuity","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"business_email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"fallback_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"fallback_identity_verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_verification_status","type":"text","default":"'unconfigured'::text","identity":"","not_null":true,"generated":""},{"name":"provider_verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_forward_enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"provider_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_user_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_account_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mailbox_ready","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"mail_launched","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"desired_mode","type":"text","default":"'prelaunch'::text","identity":"","not_null":true,"generated":""},{"name":"effective_mode","type":"text","default":"'normal'::text","identity":"","not_null":true,"generated":""},{"name":"activation_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"degraded_since","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"recovered_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_provider_reconciled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_mail_reconciled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_mail_continuity_mode_idx","definition":"CREATE INDEX tenant_mail_continuity_mode_idx ON public.tenant_mail_continuity USING btree (desired_mode, provider_forward_enabled)"},{"name":"tenant_mail_continuity_pkey","definition":"CREATE UNIQUE INDEX tenant_mail_continuity_pkey ON public.tenant_mail_continuity USING btree (id)"},{"name":"tenant_mail_continuity_tenant_id_business_email_key","definition":"CREATE UNIQUE INDEX tenant_mail_continuity_tenant_id_business_email_key ON public.tenant_mail_continuity USING btree (tenant_id, business_email)"},{"name":"tenant_mail_continuity_tenant_idx","definition":"CREATE INDEX tenant_mail_continuity_tenant_idx ON public.tenant_mail_continuity USING btree (tenant_id)"}],"policies":[],"triggers":[],"constraints":[{"name":"tenant_mail_continuity_check","definition":"CHECK (fallback_email IS NULL OR lower(btrim(fallback_email)) <> lower(btrim(business_email)))"},{"name":"tenant_mail_continuity_desired_mode_check","definition":"CHECK (desired_mode = ANY (ARRAY['normal'::text, 'prelaunch'::text, 'degraded'::text]))"},{"name":"tenant_mail_continuity_effective_mode_check","definition":"CHECK (effective_mode = ANY (ARRAY['normal'::text, 'prelaunch'::text, 'degraded'::text]))"},{"name":"tenant_mail_continuity_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_mail_continuity_provider_verification_status_check","definition":"CHECK (provider_verification_status = ANY (ARRAY['unconfigured'::text, 'pending'::text, 'verified'::text, 'error'::text, 'prerequisite_required'::text]))"},{"name":"tenant_mail_continuity_tenant_id_business_email_key","definition":"UNIQUE (tenant_id, business_email)"},{"name":"tenant_mail_continuity_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"tenant_mailboxes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":"'zoho_mail360'::text","identity":"","not_null":true,"generated":""},{"name":"account_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"email_address","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mailbox_kind","type":"text","default":"'native'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"last_sync_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_mailboxes_account_key_idx","definition":"CREATE INDEX tenant_mailboxes_account_key_idx ON public.tenant_mailboxes USING btree (account_key)"},{"name":"tenant_mailboxes_one_default_per_tenant_idx","definition":"CREATE UNIQUE INDEX tenant_mailboxes_one_default_per_tenant_idx ON public.tenant_mailboxes USING btree (tenant_org_id) WHERE ((is_default = true) AND (status = 'active'::text))"},{"name":"tenant_mailboxes_pkey","definition":"CREATE UNIQUE INDEX tenant_mailboxes_pkey ON public.tenant_mailboxes USING btree (id)"},{"name":"tenant_mailboxes_tenant_org_id_account_key_key","definition":"CREATE UNIQUE INDEX tenant_mailboxes_tenant_org_id_account_key_key ON public.tenant_mailboxes USING btree (tenant_org_id, account_key)"},{"name":"tenant_mailboxes_tenant_status_idx","definition":"CREATE INDEX tenant_mailboxes_tenant_status_idx ON public.tenant_mailboxes USING btree (tenant_org_id, status)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"tenant_mailboxes","permissive":"PERMISSIVE","policyname":"tenant_mailboxes_member_read","schemaname":"public","with_check":null}],"triggers":[{"name":"tenant_mailbox_continuity_sync","definition":"CREATE TRIGGER tenant_mailbox_continuity_sync AFTER INSERT OR UPDATE OF account_key, email_address, status, provider ON tenant_mailboxes FOR EACH ROW EXECUTE FUNCTION sync_mail_continuity_mailbox()"}],"constraints":[{"name":"tenant_mailboxes_mailbox_kind_check","definition":"CHECK (mailbox_kind = ANY (ARRAY['native'::text, 'sync'::text]))"},{"name":"tenant_mailboxes_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_mailboxes_provider_check","definition":"CHECK (provider = 'zoho_mail'::text)"},{"name":"tenant_mailboxes_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'setup_required'::text, 'disabled'::text, 'error'::text]))"},{"name":"tenant_mailboxes_tenant_org_id_account_key_key","definition":"UNIQUE (tenant_org_id, account_key)"},{"name":"tenant_mailboxes_tenant_org_id_fkey","definition":"FOREIGN KEY (tenant_org_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"tenant_marketing_unsubscribe_tokens","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"token","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"used_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_tenant_marketing_unsubscribe_tokens_created","definition":"CREATE INDEX idx_tenant_marketing_unsubscribe_tokens_created ON public.tenant_marketing_unsubscribe_tokens USING btree (created_at)"},{"name":"idx_tenant_marketing_unsubscribe_tokens_tenant_email","definition":"CREATE INDEX idx_tenant_marketing_unsubscribe_tokens_tenant_email ON public.tenant_marketing_unsubscribe_tokens USING btree (tenant_id, lower(email))"},{"name":"tenant_marketing_unsubscribe_tokens_pkey","definition":"CREATE UNIQUE INDEX tenant_marketing_unsubscribe_tokens_pkey ON public.tenant_marketing_unsubscribe_tokens USING btree (id)"},{"name":"tenant_marketing_unsubscribe_tokens_token_key","definition":"CREATE UNIQUE INDEX tenant_marketing_unsubscribe_tokens_token_key ON public.tenant_marketing_unsubscribe_tokens USING btree (token)"}],"policies":[],"triggers":[],"constraints":[{"name":"tenant_marketing_unsubscribe_tokens_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_marketing_unsubscribe_tokens_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"tenant_marketing_unsubscribe_tokens_token_key","definition":"UNIQUE (token)"}]},{"table":"tenant_media_assets","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"collection_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"bucket_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"original_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"derived_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"original_content_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"derived_content_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_kind","type":"text","default":"'upload'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'ready'::text","identity":"","not_null":true,"generated":""},{"name":"review_status","type":"text","default":"'unreviewed'::text","identity":"","not_null":true,"generated":""},{"name":"enhance_consent","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"enhancement_model","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"published","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"is_primary","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"enhanced_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"reviewed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"mime_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"size_bytes","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"storage_provider","type":"text","default":"'r2'::text","identity":"","not_null":true,"generated":""},{"name":"storage_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"tenant_media_assets_library_idx","definition":"CREATE INDEX tenant_media_assets_library_idx ON public.tenant_media_assets USING btree (tenant_id, collection_key, created_at DESC) WHERE (deleted_at IS NULL)"},{"name":"tenant_media_assets_pkey","definition":"CREATE UNIQUE INDEX tenant_media_assets_pkey ON public.tenant_media_assets USING btree (id)"},{"name":"tenant_media_assets_provider_idx","definition":"CREATE INDEX tenant_media_assets_provider_idx ON public.tenant_media_assets USING btree (storage_provider, bucket_name, storage_key) WHERE (deleted_at IS NULL)"},{"name":"tenant_media_assets_public_idx","definition":"CREATE INDEX tenant_media_assets_public_idx ON public.tenant_media_assets USING btree (tenant_id, collection_key, published) WHERE (published = true)"},{"name":"tenant_media_assets_singleton_primary_role_idx","definition":"CREATE UNIQUE INDEX tenant_media_assets_singleton_primary_role_idx ON public.tenant_media_assets USING btree (tenant_id, collection_key) WHERE ((is_primary = true) AND (deleted_at IS NULL) AND (collection_key = ANY (ARRAY['branding'::text, 'backgrounds'::text])))"},{"name":"tenant_media_assets_tenant_collection_idx","definition":"CREATE INDEX tenant_media_assets_tenant_collection_idx ON public.tenant_media_assets USING btree (tenant_id, collection_key, created_at DESC)"},{"name":"tenant_media_assets_tenant_id_bucket_name_original_key_key","definition":"CREATE UNIQUE INDEX tenant_media_assets_tenant_id_bucket_name_original_key_key ON public.tenant_media_assets USING btree (tenant_id, bucket_name, original_key)"}],"policies":[{"cmd":"DELETE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = tenant_media_assets.tenant_id)))))","roles":["authenticated"],"tablename":"tenant_media_assets","permissive":"PERMISSIVE","policyname":"tenant_media_assets_tenant_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"tenant_media_assets","permissive":"PERMISSIVE","policyname":"tenant_media_assets_tenant_insert","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = tenant_media_assets.tenant_id)))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = tenant_media_assets.tenant_id)))))","roles":["authenticated"],"tablename":"tenant_media_assets","permissive":"PERMISSIVE","policyname":"tenant_media_assets_tenant_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = tenant_media_assets.tenant_id)))))","roles":["authenticated"],"tablename":"tenant_media_assets","permissive":"PERMISSIVE","policyname":"tenant_media_assets_tenant_update","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text) AND (m.tenant_id = tenant_media_assets.tenant_id)))))"}],"triggers":[{"name":"trg_sync_primary_tenant_logo_pointer","definition":"CREATE TRIGGER trg_sync_primary_tenant_logo_pointer AFTER INSERT OR UPDATE OF is_primary, deleted_at, updated_at, storage_key, original_key ON tenant_media_assets FOR EACH ROW EXECUTE FUNCTION sync_primary_tenant_logo_pointer()"}],"constraints":[{"name":"tenant_media_assets_active_audio_chk","definition":"CHECK (deleted_at IS NOT NULL OR lower(COALESCE(mime_type, ''::text)) !~~ 'audio/%'::text)"},{"name":"tenant_media_assets_created_by_fkey","definition":"FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"tenant_media_assets_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_media_assets_review_status_check","definition":"CHECK (review_status = ANY (ARRAY['unreviewed'::text, 'pending'::text, 'approved'::text, 'rejected'::text]))"},{"name":"tenant_media_assets_reviewed_by_fkey","definition":"FOREIGN KEY (reviewed_by) REFERENCES users(id) ON DELETE SET NULL"},{"name":"tenant_media_assets_source_kind_check","definition":"CHECK (source_kind = ANY (ARRAY['upload'::text, 'existing'::text, 'default_pack'::text]))"},{"name":"tenant_media_assets_status_check","definition":"CHECK (status = ANY (ARRAY['ready'::text, 'enhancing'::text, 'pending_review'::text, 'failed'::text]))"},{"name":"tenant_media_assets_tenant_id_bucket_name_original_key_key","definition":"UNIQUE (tenant_id, bucket_name, original_key)"},{"name":"tenant_media_assets_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"tenant_messaging_settings","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":"'none'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'not_configured'::text","identity":"","not_null":true,"generated":""},{"name":"sms_enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"email_enabled","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sending_domain","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"brand_registration_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"consent_required","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"configured_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"amd_unknown_treated_as_machine","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"voicemail_silence_drop_seconds","type":"integer","default":"7","identity":"","not_null":true,"generated":""},{"name":"voicemail_drop_requires_amd_unknown_or_timeout","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"rep_confirm_human_window_ms","type":"integer","default":"7000","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_tms_tenant","definition":"CREATE INDEX idx_tms_tenant ON public.tenant_messaging_settings USING btree (tenant_id)"},{"name":"tenant_messaging_settings_pkey","definition":"CREATE UNIQUE INDEX tenant_messaging_settings_pkey ON public.tenant_messaging_settings USING btree (id)"},{"name":"tenant_messaging_settings_tenant_id_key","definition":"CREATE UNIQUE INDEX tenant_messaging_settings_tenant_id_key ON public.tenant_messaging_settings USING btree (tenant_id)"}],"policies":[{"cmd":"DELETE","qual":"is_system_admin(uid())","roles":["public"],"tablename":"tenant_messaging_settings","permissive":"PERMISSIVE","policyname":"tms_delete_admin","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"tenant_messaging_settings","permissive":"PERMISSIVE","policyname":"tms_insert_owner","schemaname":"public","with_check":"(is_tenant_owner_for(uid(), (tenant_id)::text) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_member((tenant_id)::text) OR is_system_admin(uid()))","roles":["public"],"tablename":"tenant_messaging_settings","permissive":"PERMISSIVE","policyname":"tms_select_members","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_owner_for(uid(), (tenant_id)::text) OR is_system_admin(uid()))","roles":["public"],"tablename":"tenant_messaging_settings","permissive":"PERMISSIVE","policyname":"tms_update_owner","schemaname":"public","with_check":"(is_tenant_owner_for(uid(), (tenant_id)::text) OR is_system_admin(uid()))"}],"triggers":[{"name":"trg_tms_updated_at","definition":"CREATE TRIGGER trg_tms_updated_at BEFORE UPDATE ON tenant_messaging_settings FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"tenant_messaging_settings_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_messaging_settings_provider_check","definition":"CHECK (provider = ANY (ARRAY['none'::text, 'twilio'::text, 'other'::text]))"},{"name":"tenant_messaging_settings_status_check","definition":"CHECK (status = ANY (ARRAY['not_configured'::text, 'pending_setup'::text, 'active'::text, 'disabled'::text, 'rejected'::text]))"},{"name":"tenant_messaging_settings_tenant_id_key","definition":"UNIQUE (tenant_id)"}]},{"table":"tenant_notification_policies","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"channel","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"mode","type":"text","default":"'recommend'::text","identity":"","not_null":true,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_notification_policies_pkey","definition":"CREATE UNIQUE INDEX tenant_notification_policies_pkey ON public.tenant_notification_policies USING btree (tenant_id, category)"}],"policies":[{"cmd":"DELETE","qual":"((uid() IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_id))","roles":["authenticated"],"tablename":"tenant_notification_policies","permissive":"PERMISSIVE","policyname":"tenant_notification_policy_owner_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"tenant_notification_policies","permissive":"PERMISSIVE","policyname":"tenant_notification_policy_owner_insert","schemaname":"public","with_check":"((uid() IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_id))"},{"cmd":"UPDATE","qual":"((uid() IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_id))","roles":["authenticated"],"tablename":"tenant_notification_policies","permissive":"PERMISSIVE","policyname":"tenant_notification_policy_owner_update","schemaname":"public","with_check":"((uid() IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_id))"},{"cmd":"SELECT","qual":"((uid() IS NOT NULL) AND is_tenant_member(uid(), tenant_id))","roles":["authenticated"],"tablename":"tenant_notification_policies","permissive":"PERMISSIVE","policyname":"tenant_notification_policy_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"tenant_notification_enforced_not_off","definition":"CHECK (mode <> 'enforce'::text OR channel <> 'off'::text)"},{"name":"tenant_notification_policies_category_check","definition":"CHECK (category = ANY (ARRAY['messages'::text, 'assigned'::text, 'deadlines'::text, 'billing'::text, 'updates'::text]))"},{"name":"tenant_notification_policies_channel_check","definition":"CHECK (channel = ANY (ARRAY['push'::text, 'email'::text, 'in_app'::text, 'off'::text]))"},{"name":"tenant_notification_policies_mode_check","definition":"CHECK (mode = ANY (ARRAY['recommend'::text, 'enforce'::text]))"},{"name":"tenant_notification_policies_pkey","definition":"PRIMARY KEY (tenant_id, category)"},{"name":"tenant_notification_policies_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"tenant_outreach_send_attempts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"queue_item_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"campaign_property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"channel","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"failure_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_message_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_tosa_queue_item","definition":"CREATE INDEX idx_tosa_queue_item ON public.tenant_outreach_send_attempts USING btree (queue_item_id)"},{"name":"idx_tosa_tenant_created","definition":"CREATE INDEX idx_tosa_tenant_created ON public.tenant_outreach_send_attempts USING btree (tenant_id, created_at DESC)"},{"name":"tenant_outreach_send_attempts_pkey","definition":"CREATE UNIQUE INDEX tenant_outreach_send_attempts_pkey ON public.tenant_outreach_send_attempts USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(is_tenant_member((tenant_id)::text) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"tenant_outreach_send_attempts","permissive":"PERMISSIVE","policyname":"tosa_select_members","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"tenant_outreach_send_attempts_channel_check","definition":"CHECK (channel = ANY (ARRAY['sms_preview'::text, 'email_preview'::text, 'sms'::text, 'email'::text]))"},{"name":"tenant_outreach_send_attempts_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_outreach_send_attempts_status_check","definition":"CHECK (status = ANY (ARRAY['blocked'::text, 'attempted'::text, 'sent'::text, 'failed'::text]))"}]},{"table":"tenant_phone_numbers","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"twilio_number_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"friendly_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"capabilities","type":"jsonb","default":"'{\"mms\": true, \"sms\": true, \"voice\": true}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_tenant_phone_numbers_default","definition":"CREATE INDEX idx_tenant_phone_numbers_default ON public.tenant_phone_numbers USING btree (tenant_org_id, is_default) WHERE (is_default = true)"},{"name":"idx_tenant_phone_numbers_tenant","definition":"CREATE INDEX idx_tenant_phone_numbers_tenant ON public.tenant_phone_numbers USING btree (tenant_org_id)"},{"name":"tenant_phone_numbers_pkey","definition":"CREATE UNIQUE INDEX tenant_phone_numbers_pkey ON public.tenant_phone_numbers USING btree (id)"},{"name":"tenant_phone_numbers_unique_number","definition":"CREATE UNIQUE INDEX tenant_phone_numbers_unique_number ON public.tenant_phone_numbers USING btree (phone_number)"}],"policies":[{"cmd":"ALL","qual":"(is_platform_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = tenant_phone_numbers.tenant_org_id) AND (m.is_owner = true) AND (m.status = 'active'::text)))))","roles":["authenticated"],"tablename":"tenant_phone_numbers","permissive":"PERMISSIVE","policyname":"Owners and admins can manage tenant phone numbers","schemaname":"public","with_check":"(is_platform_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = tenant_phone_numbers.tenant_org_id) AND (m.is_owner = true) AND (m.status = 'active'::text)))))"},{"cmd":"SELECT","qual":"((tenant_org_id IN ( SELECT user_tenant_memberships.tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.status = 'active'::text)))) OR is_platform_admin(uid()))","roles":["authenticated"],"tablename":"tenant_phone_numbers","permissive":"PERMISSIVE","policyname":"Tenant members can read their phone numbers","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_tenant_phone_numbers_updated","definition":"CREATE TRIGGER trg_tenant_phone_numbers_updated BEFORE UPDATE ON tenant_phone_numbers FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"tenant_phone_numbers_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_phone_numbers_unique_number","definition":"UNIQUE (phone_number)"}]},{"table":"tenant_price_overrides","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"zip3","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"item_code","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"unit_price","type":"numeric(12,2)","default":null,"identity":"","not_null":true,"generated":""},{"name":"effective_date","type":"date","default":"CURRENT_DATE","identity":"","not_null":true,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_tenant_price_overrides_lookup","definition":"CREATE INDEX idx_tenant_price_overrides_lookup ON public.tenant_price_overrides USING btree (tenant_org_id, zip3, item_code, effective_date DESC)"},{"name":"tenant_price_overrides_pkey","definition":"CREATE UNIQUE INDEX tenant_price_overrides_pkey ON public.tenant_price_overrides USING btree (id)"},{"name":"tenant_price_overrides_tenant_org_id_zip3_item_code_effecti_key","definition":"CREATE UNIQUE INDEX tenant_price_overrides_tenant_org_id_zip3_item_code_effecti_key ON public.tenant_price_overrides USING btree (tenant_org_id, zip3, item_code, effective_date)"}],"policies":[{"cmd":"DELETE","qual":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))","roles":["authenticated"],"tablename":"tenant_price_overrides","permissive":"PERMISSIVE","policyname":"tenant members delete price overrides","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"tenant_price_overrides","permissive":"PERMISSIVE","policyname":"tenant members insert price overrides","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))"},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))","roles":["authenticated"],"tablename":"tenant_price_overrides","permissive":"PERMISSIVE","policyname":"tenant members read price overrides","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))","roles":["authenticated"],"tablename":"tenant_price_overrides","permissive":"PERMISSIVE","policyname":"tenant members update price overrides","schemaname":"public","with_check":"(tenant_org_id IN ( SELECT m.tenant_id\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.status = 'active'::text))))"}],"triggers":[{"name":"update_tenant_price_overrides_updated_at","definition":"CREATE TRIGGER update_tenant_price_overrides_updated_at BEFORE UPDATE ON tenant_price_overrides FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"tenant_price_overrides_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_price_overrides_tenant_org_id_zip3_item_code_effecti_key","definition":"UNIQUE (tenant_org_id, zip3, item_code, effective_date)"},{"name":"tenant_price_overrides_zip3_check","definition":"CHECK (length(zip3) = 3)"}]},{"table":"tenant_provider_credentials","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"credential_status","type":"text","default":"'missing'::text","identity":"","not_null":true,"generated":""},{"name":"credential_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"sending_domain","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"verification_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_tpc_tenant","definition":"CREATE INDEX idx_tpc_tenant ON public.tenant_provider_credentials USING btree (tenant_id)"},{"name":"tenant_provider_credentials_pkey","definition":"CREATE UNIQUE INDEX tenant_provider_credentials_pkey ON public.tenant_provider_credentials USING btree (id)"},{"name":"tenant_provider_credentials_tenant_id_provider_key","definition":"CREATE UNIQUE INDEX tenant_provider_credentials_tenant_id_provider_key ON public.tenant_provider_credentials USING btree (tenant_id, provider)"}],"policies":[{"cmd":"DELETE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"tenant_provider_credentials","permissive":"PERMISSIVE","policyname":"tpc_delete_admin","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"tenant_provider_credentials","permissive":"PERMISSIVE","policyname":"tpc_insert_owner_admin","schemaname":"public","with_check":"(is_tenant_owner_for(uid(), (tenant_id)::text) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"(is_tenant_owner_for(uid(), (tenant_id)::text) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"tenant_provider_credentials","permissive":"PERMISSIVE","policyname":"tpc_select_owner_admin","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_tenant_owner_for(uid(), (tenant_id)::text) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"tenant_provider_credentials","permissive":"PERMISSIVE","policyname":"tpc_update_owner_admin","schemaname":"public","with_check":"(is_tenant_owner_for(uid(), (tenant_id)::text) OR is_system_admin(uid()))"}],"triggers":[{"name":"trg_tpc_updated_at","definition":"CREATE TRIGGER trg_tpc_updated_at BEFORE UPDATE ON tenant_provider_credentials FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"tenant_provider_credentials_credential_status_check","definition":"CHECK (credential_status = ANY (ARRAY['missing'::text, 'pending'::text, 'active'::text, 'disabled'::text, 'invalid'::text]))"},{"name":"tenant_provider_credentials_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_provider_credentials_provider_check","definition":"CHECK (provider = ANY (ARRAY['twilio'::text, 'resend'::text, 'stripe'::text, 'square'::text, 'zoho_mail'::text, 'zoho_mail_admin'::text, 'google_workspace'::text, 'google_search_console'::text, 'microsoft_365'::text, 'monday'::text, 'quickbooks'::text, 'slack'::text, 'dropbox'::text, 'hubspot'::text, 'docusign'::text, 'other'::text, 'irslogiqs'::text, 'cloudflare_r2'::text, 'squarespace'::text]))"},{"name":"tenant_provider_credentials_tenant_id_provider_key","definition":"UNIQUE (tenant_id, provider)"}]},{"table":"tenant_provider_oauth_states","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"state_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"return_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"code_verifier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"consumed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"operator_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_tenant_provider_oauth_states_expiry","definition":"CREATE INDEX idx_tenant_provider_oauth_states_expiry ON public.tenant_provider_oauth_states USING btree (expires_at)"},{"name":"tenant_provider_oauth_states_pkey","definition":"CREATE UNIQUE INDEX tenant_provider_oauth_states_pkey ON public.tenant_provider_oauth_states USING btree (id)"},{"name":"tenant_provider_oauth_states_state_hash_key","definition":"CREATE UNIQUE INDEX tenant_provider_oauth_states_state_hash_key ON public.tenant_provider_oauth_states USING btree (state_hash)"}],"policies":[],"triggers":[],"constraints":[{"name":"tenant_provider_oauth_states_operator_user_id_fkey","definition":"FOREIGN KEY (operator_user_id) REFERENCES users(id) ON DELETE SET NULL"},{"name":"tenant_provider_oauth_states_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_provider_oauth_states_provider_check","definition":"CHECK (provider = ANY (ARRAY['google_workspace'::text, 'google_search_console'::text, 'microsoft_365'::text, 'monday'::text, 'quickbooks'::text, 'slack'::text, 'dropbox'::text, 'hubspot'::text, 'docusign'::text, 'stripe'::text]))"},{"name":"tenant_provider_oauth_states_state_hash_key","definition":"UNIQUE (state_hash)"}]},{"table":"tenant_provider_secrets","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"account_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"from_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"from_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"from_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ciphertext","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"iv","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"key_version","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"verification_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_provider_secrets_pkey","definition":"CREATE UNIQUE INDEX tenant_provider_secrets_pkey ON public.tenant_provider_secrets USING btree (id)"},{"name":"tenant_provider_secrets_tenant_id_provider_key","definition":"CREATE UNIQUE INDEX tenant_provider_secrets_tenant_id_provider_key ON public.tenant_provider_secrets USING btree (tenant_id, provider)"},{"name":"tenant_provider_secrets_tenant_provider_idx","definition":"CREATE INDEX tenant_provider_secrets_tenant_provider_idx ON public.tenant_provider_secrets USING btree (tenant_id, provider)"}],"policies":[],"triggers":[{"name":"trg_tenant_provider_secrets_updated_at","definition":"CREATE TRIGGER trg_tenant_provider_secrets_updated_at BEFORE UPDATE ON tenant_provider_secrets FOR EACH ROW EXECUTE FUNCTION tenant_provider_secrets_touch_updated_at()"}],"constraints":[{"name":"tenant_provider_secrets_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_provider_secrets_provider_check","definition":"CHECK (provider = ANY (ARRAY['twilio'::text, 'resend'::text, 'stripe'::text, 'square'::text, 'zoho_mail'::text, 'zoho_mail_admin'::text, 'google_workspace'::text, 'google_search_console'::text, 'microsoft_365'::text, 'monday'::text, 'quickbooks'::text, 'slack'::text, 'dropbox'::text, 'hubspot'::text, 'docusign'::text, 'irslogiqs'::text, 'cloudflare_r2'::text, 'squarespace'::text]))"},{"name":"tenant_provider_secrets_tenant_id_provider_key","definition":"UNIQUE (tenant_id, provider)"}]},{"table":"tenant_readiness_checks","schema":"public","columns":[{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"check_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"detail","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"tenant_readiness_checks_pkey","definition":"CREATE UNIQUE INDEX tenant_readiness_checks_pkey ON public.tenant_readiness_checks USING btree (tenant_id, check_key)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = tenant_readiness_checks.tenant_id) AND (membership.status = 'active'::text)))))","roles":["authenticated"],"tablename":"tenant_readiness_checks","permissive":"PERMISSIVE","policyname":"tenant_readiness_checks_read","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"tenant_readiness_checks_pkey","definition":"PRIMARY KEY (tenant_id, check_key)"},{"name":"tenant_readiness_checks_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'ready'::text, 'needs_input'::text, 'blocked'::text, 'not_applicable'::text]))"},{"name":"tenant_readiness_checks_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"tenant_rebuttals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenancy_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"objection_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"short_rebuttal","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"normal_rebuttal","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"long_rebuttal","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'Other'::text","identity":"","not_null":true,"generated":""},{"name":"tags","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_template","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"derived_from_template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"adopted_admin_version","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_tenant_rebuttals_category","definition":"CREATE INDEX idx_tenant_rebuttals_category ON public.tenant_rebuttals USING btree (tenancy_type, category, order_index)"},{"name":"idx_tenant_rebuttals_derived","definition":"CREATE INDEX idx_tenant_rebuttals_derived ON public.tenant_rebuttals USING btree (derived_from_template_id)"},{"name":"idx_tenant_rebuttals_tenancy_type","definition":"CREATE INDEX idx_tenant_rebuttals_tenancy_type ON public.tenant_rebuttals USING btree (tenancy_type, order_index)"},{"name":"idx_tenant_rebuttals_tenant","definition":"CREATE INDEX idx_tenant_rebuttals_tenant ON public.tenant_rebuttals USING btree (tenant_org_id)"},{"name":"tenant_rebuttals_pkey","definition":"CREATE UNIQUE INDEX tenant_rebuttals_pkey ON public.tenant_rebuttals USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"tenant_rebuttals","permissive":"PERMISSIVE","policyname":"tenant_rebuttals_godmode","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR is_tenant_member(uid(), tenant_org_id))","roles":["public"],"tablename":"tenant_rebuttals","permissive":"PERMISSIVE","policyname":"tenant_rebuttals_tenant_member_read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_org_id))","roles":["public"],"tablename":"tenant_rebuttals","permissive":"PERMISSIVE","policyname":"tenant_rebuttals_tenant_owner_manage","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), tenant_org_id))"}],"triggers":[{"name":"tenant_rebuttals_isolation_contract","definition":"CREATE TRIGGER tenant_rebuttals_isolation_contract BEFORE INSERT OR UPDATE OF tenant_org_id, tenancy_type, is_template, derived_from_template_id ON tenant_rebuttals FOR EACH ROW EXECUTE FUNCTION enforce_tenant_rebuttal_isolation()"},{"name":"tenant_rebuttals_updated_at","definition":"CREATE TRIGGER tenant_rebuttals_updated_at BEFORE UPDATE ON tenant_rebuttals FOR EACH ROW EXECUTE FUNCTION update_tenant_rebuttals_updated_at()"}],"constraints":[{"name":"tenant_rebuttals_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_rebuttals_tenancy_type_check","definition":"CHECK (tenancy_type = ANY (ARRAY['mitigation'::text, 'roofing'::text, 'public_adjuster'::text, 'realtor'::text]))"}]},{"table":"tenant_service_areas","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"slug","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"zip_codes","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"neighborhoods","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"lat","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"lng","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"tenant_service_areas_pkey","definition":"CREATE UNIQUE INDEX tenant_service_areas_pkey ON public.tenant_service_areas USING btree (id)"},{"name":"tenant_service_areas_tenant_org_id_slug_key","definition":"CREATE UNIQUE INDEX tenant_service_areas_tenant_org_id_slug_key ON public.tenant_service_areas USING btree (tenant_org_id, slug)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.tenant_id = tenant_service_areas.tenant_org_id) AND (user_tenant_memberships.status = 'active'::text))))","roles":["authenticated"],"tablename":"tenant_service_areas","permissive":"PERMISSIVE","policyname":"Members can view service areas","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.tenant_id = tenant_service_areas.tenant_org_id) AND (user_tenant_memberships.status = 'active'::text) AND (user_tenant_memberships.is_owner = true))))","roles":["authenticated"],"tablename":"tenant_service_areas","permissive":"PERMISSIVE","policyname":"Owners can delete service areas","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"tenant_service_areas","permissive":"PERMISSIVE","policyname":"Owners can insert service areas","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.tenant_id = tenant_service_areas.tenant_org_id) AND (user_tenant_memberships.status = 'active'::text) AND (user_tenant_memberships.is_owner = true))))"},{"cmd":"UPDATE","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.tenant_id = tenant_service_areas.tenant_org_id) AND (user_tenant_memberships.status = 'active'::text) AND (user_tenant_memberships.is_owner = true))))","roles":["authenticated"],"tablename":"tenant_service_areas","permissive":"PERMISSIVE","policyname":"Owners can update service areas","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = tenant_service_areas.tenant_org_id) AND (m.status = 'active'::text) AND (m.is_owner = true))))"}],"triggers":[],"constraints":[{"name":"tenant_service_areas_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_service_areas_tenant_org_id_slug_key","definition":"UNIQUE (tenant_org_id, slug)"}]},{"table":"tenant_subscriptions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"plan_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'trial'::text","identity":"","not_null":true,"generated":""},{"name":"trial_ends_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_period_start","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_period_end","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"paddle_subscription_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"paddle_customer_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"seat_count","type":"integer","default":"1","identity":"","not_null":true,"generated":""},{"name":"seat_overage","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"cancel_at_period_end","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"billing_cycle","type":"text","default":"'monthly'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"stripe_customer_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_subscription_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_price_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"stripe_environment","type":"text","default":"'sandbox'::text","identity":"","not_null":false,"generated":""},{"name":"cancel_at_period_end_synced_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_tenant_subscriptions_status","definition":"CREATE INDEX idx_tenant_subscriptions_status ON public.tenant_subscriptions USING btree (status)"},{"name":"idx_tenant_subscriptions_tenant","definition":"CREATE INDEX idx_tenant_subscriptions_tenant ON public.tenant_subscriptions USING btree (tenant_id)"},{"name":"tenant_subscriptions_pkey","definition":"CREATE UNIQUE INDEX tenant_subscriptions_pkey ON public.tenant_subscriptions USING btree (id)"},{"name":"tenant_subscriptions_stripe_sub_idx","definition":"CREATE UNIQUE INDEX tenant_subscriptions_stripe_sub_idx ON public.tenant_subscriptions USING btree (stripe_subscription_id) WHERE (stripe_subscription_id IS NOT NULL)"},{"name":"tenant_subscriptions_tenant_id_key","definition":"CREATE UNIQUE INDEX tenant_subscriptions_tenant_id_key ON public.tenant_subscriptions USING btree (tenant_id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"tenant_subscriptions","permissive":"PERMISSIVE","policyname":"Only system admins modify subscriptions","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = tenant_subscriptions.tenant_id) AND (m.status = 'active'::text)))))","roles":["public"],"tablename":"tenant_subscriptions","permissive":"PERMISSIVE","policyname":"Tenant members read their subscription","schemaname":"public","with_check":null}],"triggers":[{"name":"update_tenant_subscriptions_updated_at","definition":"CREATE TRIGGER update_tenant_subscriptions_updated_at BEFORE UPDATE ON tenant_subscriptions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"tenant_subscriptions_billing_cycle_check","definition":"CHECK (billing_cycle = ANY (ARRAY['monthly'::text, 'annual'::text]))"},{"name":"tenant_subscriptions_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenant_subscriptions_status_check","definition":"CHECK (status = ANY (ARRAY['trial'::text, 'active'::text, 'past_due'::text, 'cancelled'::text, 'expired'::text, 'trial_expired'::text]))"},{"name":"tenant_subscriptions_tenant_id_key","definition":"UNIQUE (tenant_id)"}]},{"table":"tenant_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_tenant_templates_tenant_type","definition":"CREATE INDEX idx_tenant_templates_tenant_type ON public.tenant_templates USING btree (tenant_type)"},{"name":"tenant_templates_name_key","definition":"CREATE UNIQUE INDEX tenant_templates_name_key ON public.tenant_templates USING btree (name)"},{"name":"tenant_templates_pkey","definition":"CREATE UNIQUE INDEX tenant_templates_pkey ON public.tenant_templates USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"tenant_templates","permissive":"PERMISSIVE","policyname":"platform_admin_manage_tenant_templates","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"tenant_templates_name_key","definition":"UNIQUE (name)"},{"name":"tenant_templates_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"tenants","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"owner_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"google_drive_root_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"master_registry_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"settings","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"drive_provisioned_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"drive_provisioning_status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"drive_provisioning_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_slug","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"drive_map","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"company_legal_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_dba_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_logo_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"letterhead_config","type":"jsonb","default":"'{\"logo_size\": \"medium\", \"header_color\": \"hsl(var(--primary))\", \"show_tagline\": true, \"tagline_text\": \"\", \"logo_position\": \"left\"}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"company_email_domain","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_trial","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"trial_account_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_descriptor","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"realtor_license_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"realtor_license_state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"realtor_license_expires_at","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"secondary_color","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"disclaimer_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_facing_title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"branded_sender_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_website","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"company_mailing_address","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_tenants_is_trial","definition":"CREATE INDEX idx_tenants_is_trial ON public.tenants USING btree (is_trial) WHERE (is_trial = true)"},{"name":"idx_tenants_owner","definition":"CREATE INDEX idx_tenants_owner ON public.tenants USING btree (owner_id)"},{"name":"idx_tenants_status","definition":"CREATE INDEX idx_tenants_status ON public.tenants USING btree (status)"},{"name":"tenants_company_slug_unique","definition":"CREATE UNIQUE INDEX tenants_company_slug_unique ON public.tenants USING btree (company_slug) WHERE (company_slug IS NOT NULL)"},{"name":"tenants_pkey","definition":"CREATE UNIQUE INDEX tenants_pkey ON public.tenants USING btree (id)"},{"name":"tenants_storage_bucket_unique_idx","definition":"CREATE UNIQUE INDEX tenants_storage_bucket_unique_idx ON public.tenants USING btree (NULLIF(TRIM(BOTH FROM COALESCE((settings ->> 'storage_bucket'::text), ''::text)), ''::text)) WHERE (NULLIF(TRIM(BOTH FROM COALESCE((settings ->> 'storage_bucket'::text), ''::text)), ''::text) IS NOT NULL)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"tenants","permissive":"PERMISSIVE","policyname":"Authenticated users can create tenants","schemaname":"public","with_check":"((uid() IS NOT NULL) AND (owner_id = uid()))"},{"cmd":"UPDATE","qual":"(owner_id = uid())","roles":["authenticated"],"tablename":"tenants","permissive":"PERMISSIVE","policyname":"Owners can update their tenants","schemaname":"public","with_check":"(owner_id = uid())"},{"cmd":"SELECT","qual":"(id IN ( SELECT get_partner_tenant_ids() AS get_partner_tenant_ids))","roles":["authenticated"],"tablename":"tenants","permissive":"PERMISSIVE","policyname":"Users can view partner tenant names","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.tenant_id = tenants.id) AND (user_roles.user_id = uid()))))","roles":["public"],"tablename":"tenants","permissive":"PERMISSIVE","policyname":"Users can view their tenants via roles","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"tenants","permissive":"PERMISSIVE","policyname":"platform_admin_delete_tenants","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"tenants","permissive":"PERMISSIVE","policyname":"platform_admin_update_tenants","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"tenants","permissive":"PERMISSIVE","policyname":"platform_admin_view_tenants","schemaname":"public","with_check":null}],"triggers":[{"name":"aa0_prepare_handyman_modes","definition":"CREATE TRIGGER aa0_prepare_handyman_modes BEFORE INSERT OR UPDATE OF tenant_type, settings ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION prepare_handyman_modes_bootstrap()"},{"name":"aaa_prepare_declared_tenant_blueprint","definition":"CREATE TRIGGER aaa_prepare_declared_tenant_blueprint BEFORE INSERT ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION prepare_declared_tenant_blueprint()"},{"name":"aaa_prepare_mobile_catering_first_class","definition":"CREATE TRIGGER aaa_prepare_mobile_catering_first_class BEFORE INSERT OR UPDATE ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION prepare_mobile_catering_first_class()"},{"name":"aab_tenant_business_blueprint_authority","definition":"CREATE TRIGGER aab_tenant_business_blueprint_authority BEFORE INSERT OR UPDATE OF tenant_type, settings ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION enforce_tenant_business_blueprint_authority()"},{"name":"aac_tenant_public_presence_contract","definition":"CREATE TRIGGER aac_tenant_public_presence_contract BEFORE INSERT OR UPDATE OF company_slug, settings ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION ensure_tenant_public_presence_contract()"},{"name":"bootstrap_call_center_tenant_on_create","definition":"CREATE TRIGGER bootstrap_call_center_tenant_on_create AFTER INSERT ON tenants FOR EACH ROW EXECUTE FUNCTION bootstrap_call_center_tenant_after_insert()"},{"name":"bootstrap_tenant_applications_trigger","definition":"CREATE TRIGGER bootstrap_tenant_applications_trigger AFTER INSERT ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION bootstrap_tenant_applications_after_insert()"},{"name":"opportunity_radar_tenant_lifecycle_seed","definition":"CREATE TRIGGER opportunity_radar_tenant_lifecycle_seed AFTER INSERT OR UPDATE OF tenant_type, company_city, company_state, company_zip, settings ON tenants FOR EACH ROW EXECUTE FUNCTION queue_opportunity_radar_lifecycle_seed()"},{"name":"tenant_modes_storage_reconcile","definition":"CREATE TRIGGER tenant_modes_storage_reconcile AFTER INSERT OR UPDATE OF tenant_type, settings ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION enqueue_modes_storage_reconcile_trigger()"},{"name":"tenants_business_activity","definition":"CREATE TRIGGER tenants_business_activity AFTER INSERT OR UPDATE OF status, is_active, is_trial ON tenants FOR EACH ROW EXECUTE FUNCTION project_tenant_business_activity()"},{"name":"tenants_enforce_experience_family","definition":"CREATE TRIGGER tenants_enforce_experience_family BEFORE INSERT OR UPDATE OF settings, tenant_type ON tenants FOR EACH ROW EXECUTE FUNCTION enforce_tenant_experience_family()"},{"name":"tenants_enforce_modes_capability","definition":"CREATE TRIGGER tenants_enforce_modes_capability BEFORE INSERT OR UPDATE OF settings, tenant_type ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION enforce_modes_tenant_capability_contract()"},{"name":"tenants_ensure_owner_relationship","definition":"CREATE TRIGGER tenants_ensure_owner_relationship AFTER INSERT ON tenants FOR EACH ROW EXECUTE FUNCTION ensure_owner_tenant_relationship()"},{"name":"tenants_normalize_logo_ingest_base64","definition":"CREATE TRIGGER tenants_normalize_logo_ingest_base64 BEFORE INSERT OR UPDATE OF settings ON tenants FOR EACH ROW EXECUTE FUNCTION normalize_tenant_logo_ingest_base64()"},{"name":"trg_assign_readable_tenant_storage_bucket","definition":"CREATE TRIGGER trg_assign_readable_tenant_storage_bucket BEFORE INSERT OR UPDATE OF company_slug, settings ON tenants FOR EACH ROW EXECUTE FUNCTION kl_assign_readable_tenant_storage_bucket()"},{"name":"trg_bootstrap_tenant_applications_after_insert","definition":"CREATE TRIGGER trg_bootstrap_tenant_applications_after_insert AFTER INSERT ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION bootstrap_tenant_applications_after_insert()"},{"name":"trg_seed_default_automation_on_tenant_create","definition":"CREATE TRIGGER trg_seed_default_automation_on_tenant_create AFTER INSERT ON tenants FOR EACH ROW EXECUTE FUNCTION seed_default_automation_on_tenant_create()"},{"name":"trg_seed_roofing_invoice_templates","definition":"CREATE TRIGGER trg_seed_roofing_invoice_templates AFTER INSERT ON tenants FOR EACH ROW EXECUTE FUNCTION seed_roofing_invoice_templates()"},{"name":"update_tenants_updated_at","definition":"CREATE TRIGGER update_tenants_updated_at BEFORE UPDATE ON tenants FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"},{"name":"zz_modes_default_media_contract","definition":"CREATE TRIGGER zz_modes_default_media_contract BEFORE INSERT OR UPDATE OF settings ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION apply_mode_default_media_to_tenant()"},{"name":"zzz_tenant_blueprint_finalize","definition":"CREATE TRIGGER zzz_tenant_blueprint_finalize AFTER INSERT ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION finalize_tenant_blueprint_insert()"},{"name":"zzzz_tenant_public_presence_readiness","definition":"CREATE TRIGGER zzzz_tenant_public_presence_readiness AFTER INSERT OR UPDATE OF company_slug, settings ON tenants FOR EACH ROW WHEN (NOT is_platform_owner_tenant(new.tenant_type, new.settings, new.company_slug)) EXECUTE FUNCTION sync_tenant_public_presence_readiness()"}],"constraints":[{"name":"tenants_experience_family_valid","definition":"CHECK (COALESCE(settings ->> 'experience_family'::text, ''::text) = ANY (ARRAY['standard'::text, 'modes'::text]))"},{"name":"tenants_pkey","definition":"PRIMARY KEY (id)"},{"name":"tenants_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'inactive'::text, 'suspended'::text, 'archived'::text]))"},{"name":"tenants_storage_bucket_not_full_uuid","definition":"CHECK (COALESCE(settings ->> 'storage_bucket'::text, ''::text) !~ '^(tenant|demo)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'::text)"},{"name":"tenants_tenant_type_check","definition":"CHECK (tenant_type = normalize_declared_business_type(tenant_type))"}]},{"table":"territories","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"polygon_geojson","type":"jsonb","default":null,"identity":"","not_null":true,"generated":""},{"name":"color","type":"text","default":"'#3b82f6'::text","identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_territories_tenant","definition":"CREATE INDEX idx_territories_tenant ON public.territories USING btree (tenant_org_id)"},{"name":"territories_pkey","definition":"CREATE UNIQUE INDEX territories_pkey ON public.territories USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM (security_active_user_tenant_memberships utm\n     JOIN user_roles ur ON (((ur.user_id = utm.user_id) AND (ur.tenant_id = utm.tenant_id))))\n  WHERE ((utm.user_id = uid()) AND (ur.role = ANY (ARRAY['Admin'::app_role, 'Owner'::app_role, 'GodMode'::app_role])))))","roles":["public"],"tablename":"territories","permissive":"PERMISSIVE","policyname":"Admins can manage territories","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"territories","permissive":"PERMISSIVE","policyname":"Users can view territories in their tenant","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"territories","permissive":"PERMISSIVE","policyname":"Users view tenant territories","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"territories","permissive":"PERMISSIVE","policyname":"platform_admin_manage_territories","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) OR is_system_admin())","roles":["public"],"tablename":"territories","permissive":"PERMISSIVE","policyname":"ter_all","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"territories_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"territory_analytics","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"territory_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"calculated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"time_range","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"visit_density","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"conversion_rate","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"roi_score","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"saturation_level","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"hot_zones","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"recommendations","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"metrics","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_territory_analytics_territory","definition":"CREATE INDEX idx_territory_analytics_territory ON public.territory_analytics USING btree (territory_id)"},{"name":"territory_analytics_pkey","definition":"CREATE UNIQUE INDEX territory_analytics_pkey ON public.territory_analytics USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = territory_analytics.tenant_org_id))))","roles":["public"],"tablename":"territory_analytics","permissive":"PERMISSIVE","policyname":"Tenant members view territory analytics","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"territory_analytics_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"territory_assignments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"territory_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assigned_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_territory_assignments_tenant","definition":"CREATE INDEX idx_territory_assignments_tenant ON public.territory_assignments USING btree (tenant_org_id)"},{"name":"idx_territory_assignments_territory","definition":"CREATE INDEX idx_territory_assignments_territory ON public.territory_assignments USING btree (territory_id)"},{"name":"idx_territory_assignments_user","definition":"CREATE INDEX idx_territory_assignments_user ON public.territory_assignments USING btree (user_id)"},{"name":"territory_assignments_pkey","definition":"CREATE UNIQUE INDEX territory_assignments_pkey ON public.territory_assignments USING btree (id)"},{"name":"territory_assignments_territory_id_user_id_key","definition":"CREATE UNIQUE INDEX territory_assignments_territory_id_user_id_key ON public.territory_assignments USING btree (territory_id, user_id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM (security_active_user_tenant_memberships utm\n     JOIN user_roles ur ON (((ur.user_id = utm.user_id) AND (ur.tenant_id = utm.tenant_id))))\n  WHERE ((utm.user_id = uid()) AND (ur.role = ANY (ARRAY['Admin'::app_role, 'Owner'::app_role, 'GodMode'::app_role])))))","roles":["public"],"tablename":"territory_assignments","permissive":"PERMISSIVE","policyname":"Admins can manage territory assignments","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((user_id = uid()) OR (tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM (security_active_user_tenant_memberships utm\n     JOIN user_roles ur ON (((ur.user_id = utm.user_id) AND (ur.tenant_id = utm.tenant_id))))\n  WHERE ((utm.user_id = uid()) AND (ur.role = ANY (ARRAY['Admin'::app_role, 'Owner'::app_role, 'GodMode'::app_role]))))))","roles":["public"],"tablename":"territory_assignments","permissive":"PERMISSIVE","policyname":"Users can view their territory assignments","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"territory_assignments","permissive":"PERMISSIVE","policyname":"Users view tenant assignments","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"territory_assignments","permissive":"PERMISSIVE","policyname":"platform_admin_manage_territory_assignments","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[],"constraints":[{"name":"territory_assignments_pkey","definition":"PRIMARY KEY (id)"},{"name":"territory_assignments_territory_id_user_id_key","definition":"UNIQUE (territory_id, user_id)"}]},{"table":"test_account_audit","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"action","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"performed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"test_account_audit_pkey","definition":"CREATE UNIQUE INDEX test_account_audit_pkey ON public.test_account_audit USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"test_account_audit","permissive":"PERMISSIVE","policyname":"test account audit caller scoped insert","schemaname":"public","with_check":"((performed_by = uid()) AND (is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_member(tenant_org_id))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR ((tenant_org_id IS NOT NULL) AND is_tenant_member(tenant_org_id)))","roles":["authenticated"],"tablename":"test_account_audit","permissive":"PERMISSIVE","policyname":"test account audit scoped select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"test_account_audit_action_check","definition":"CHECK (action = ANY (ARRAY['marked'::text, 'unmarked'::text, 'static_seeded'::text, 'static_attempted_modify'::text, 'static_attempted_delete'::text]))"},{"name":"test_account_audit_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"trial_accounts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"client_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"market_state","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"market_county","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"trial_status","type":"text","default":"'active'::text","identity":"","not_null":true,"generated":""},{"name":"trial_start_date","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"trial_end_date","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"allowed_regions","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"allowed_counties","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"allowed_zip_codes","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"allowed_map_bounds","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"county_polygon_geojson","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"default_center","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"converted_to_full_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"converted_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"feature_overrides","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_trial_accounts_status","definition":"CREATE INDEX idx_trial_accounts_status ON public.trial_accounts USING btree (trial_status)"},{"name":"idx_trial_accounts_tenant","definition":"CREATE INDEX idx_trial_accounts_tenant ON public.trial_accounts USING btree (tenant_id)"},{"name":"trial_accounts_pkey","definition":"CREATE UNIQUE INDEX trial_accounts_pkey ON public.trial_accounts USING btree (id)"},{"name":"trial_accounts_tenant_id_key","definition":"CREATE UNIQUE INDEX trial_accounts_tenant_id_key ON public.trial_accounts USING btree (tenant_id)"}],"policies":[{"cmd":"DELETE","qual":"is_global_admin(uid())","roles":["authenticated"],"tablename":"trial_accounts","permissive":"PERMISSIVE","policyname":"trial_accounts_admin_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"trial_accounts","permissive":"PERMISSIVE","policyname":"trial_accounts_admin_insert","schemaname":"public","with_check":"is_global_admin(uid())"},{"cmd":"UPDATE","qual":"is_global_admin(uid())","roles":["authenticated"],"tablename":"trial_accounts","permissive":"PERMISSIVE","policyname":"trial_accounts_admin_update","schemaname":"public","with_check":"is_global_admin(uid())"},{"cmd":"SELECT","qual":"(is_global_admin(uid()) OR is_tenant_member(uid(), tenant_id))","roles":["authenticated"],"tablename":"trial_accounts","permissive":"PERMISSIVE","policyname":"trial_accounts_select","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_sync_tenant_is_trial","definition":"CREATE TRIGGER trg_sync_tenant_is_trial AFTER INSERT OR DELETE ON trial_accounts FOR EACH ROW EXECUTE FUNCTION sync_tenant_is_trial()"},{"name":"trg_trial_accounts_updated_at","definition":"CREATE TRIGGER trg_trial_accounts_updated_at BEFORE UPDATE ON trial_accounts FOR EACH ROW EXECUTE FUNCTION touch_trial_accounts_updated_at()"}],"constraints":[{"name":"trial_accounts_pkey","definition":"PRIMARY KEY (id)"},{"name":"trial_accounts_tenant_id_key","definition":"UNIQUE (tenant_id)"},{"name":"trial_accounts_trial_status_check","definition":"CHECK (trial_status = ANY (ARRAY['active'::text, 'expired'::text, 'disabled'::text]))"}]},{"table":"trial_aha_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"parcels_scanned","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"permits_found","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"aging_roofs_found","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"storms_found","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"scan_payload","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"shown_to_user_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"trial_aha_runs_pkey","definition":"CREATE UNIQUE INDEX trial_aha_runs_pkey ON public.trial_aha_runs USING btree (id)"},{"name":"trial_aha_runs_tenant_id_key","definition":"CREATE UNIQUE INDEX trial_aha_runs_tenant_id_key ON public.trial_aha_runs USING btree (tenant_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"trial_aha_runs","permissive":"PERMISSIVE","policyname":"Only system admins insert aha runs","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"UPDATE","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = trial_aha_runs.tenant_id) AND (m.status = 'active'::text))))","roles":["public"],"tablename":"trial_aha_runs","permissive":"PERMISSIVE","policyname":"Tenant members can mark aha run shown","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = trial_aha_runs.tenant_id) AND (m.status = 'active'::text)))))","roles":["public"],"tablename":"trial_aha_runs","permissive":"PERMISSIVE","policyname":"Tenant members read their aha run","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"trial_aha_runs_pkey","definition":"PRIMARY KEY (id)"},{"name":"trial_aha_runs_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'running'::text, 'completed'::text, 'failed'::text]))"},{"name":"trial_aha_runs_tenant_id_key","definition":"UNIQUE (tenant_id)"}]},{"table":"trial_lifecycle_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"subscription_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"milestone","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"trial_lifecycle_events_pkey","definition":"CREATE UNIQUE INDEX trial_lifecycle_events_pkey ON public.trial_lifecycle_events USING btree (id)"},{"name":"trial_lifecycle_events_sub_idx","definition":"CREATE INDEX trial_lifecycle_events_sub_idx ON public.trial_lifecycle_events USING btree (subscription_id)"},{"name":"trial_lifecycle_events_unique","definition":"CREATE UNIQUE INDEX trial_lifecycle_events_unique ON public.trial_lifecycle_events USING btree (subscription_id, milestone)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"trial_lifecycle_events","permissive":"PERMISSIVE","policyname":"Admins can read trial lifecycle events","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"trial_lifecycle_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"trial_lifecycle_events_unique","definition":"UNIQUE (subscription_id, milestone)"}]},{"table":"ui_table_configs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"module","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"columns","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"sort","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"density","type":"text","default":"'comfortable'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_ui_table_configs_module","definition":"CREATE INDEX idx_ui_table_configs_module ON public.ui_table_configs USING btree (module)"},{"name":"idx_ui_table_configs_user_tenant","definition":"CREATE INDEX idx_ui_table_configs_user_tenant ON public.ui_table_configs USING btree (user_id, tenant_org_id)"},{"name":"ui_table_configs_pkey","definition":"CREATE UNIQUE INDEX ui_table_configs_pkey ON public.ui_table_configs USING btree (id)"},{"name":"ui_table_configs_user_id_tenant_org_id_module_key","definition":"CREATE UNIQUE INDEX ui_table_configs_user_id_tenant_org_id_module_key ON public.ui_table_configs USING btree (user_id, tenant_org_id, module)"}],"policies":[{"cmd":"DELETE","qual":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.tenant_id = ui_table_configs.tenant_org_id)))))","roles":["public"],"tablename":"ui_table_configs","permissive":"PERMISSIVE","policyname":"Users can delete own configs in their tenants","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"ui_table_configs","permissive":"PERMISSIVE","policyname":"Users can insert own configs in their tenants","schemaname":"public","with_check":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.tenant_id = ui_table_configs.tenant_org_id)))))"},{"cmd":"UPDATE","qual":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.tenant_id = ui_table_configs.tenant_org_id)))))","roles":["public"],"tablename":"ui_table_configs","permissive":"PERMISSIVE","policyname":"Users can update own configs in their tenants","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND (user_tenant_memberships.tenant_id = ui_table_configs.tenant_org_id)))))","roles":["public"],"tablename":"ui_table_configs","permissive":"PERMISSIVE","policyname":"Users can view own configs in their tenants","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"ui_table_configs_density_check","definition":"CHECK (density = ANY (ARRAY['compact'::text, 'comfortable'::text, 'spacious'::text]))"},{"name":"ui_table_configs_module_check","definition":"CHECK (module = ANY (ARRAY['contacts'::text, 'leads'::text, 'jobs'::text, 'invoices'::text]))"},{"name":"ui_table_configs_pkey","definition":"PRIMARY KEY (id)"},{"name":"ui_table_configs_user_id_tenant_org_id_module_key","definition":"UNIQUE (user_id, tenant_org_id, module)"}]},{"table":"unified_contacts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"first_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address2","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address3","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"address4","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"state","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"zip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"carrier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"carrier_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number2","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number3","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"policy_number4","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_number2","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_number3","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_number4","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"dol","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"second_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"insurance_claim_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"adjuster_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_estimator","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"estimator_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"roof_age","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"estimate_status","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"job_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"salesperson_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"work_classification","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_rep","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_user","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_to","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"appt_date","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"appt_time","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes2","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes3","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes4","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"additional_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"last_contact","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_touched_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"priority","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"deleted_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"deletion_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_data","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"permit_scanned_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"has_recent_roof_permit","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"roof_permit_finaled_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"jobs_stage","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_stage","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_data","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"property_square_feet","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_parcel_id","type":"character varying(100)","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_data_fetched_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_owner_name","type":"character varying(255)","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_assessed_value","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_bedrooms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_bathrooms","type":"numeric(3,1)","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_year_built","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_lot_size","type":"numeric(10,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_data_jurisdiction","type":"character varying(100)","default":null,"identity":"","not_null":false,"generated":""},{"name":"normalized_phone","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"normalized_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"normalized_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_tags","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"quality_score","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_data_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_zoning","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_land_use","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_market_value","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_tax_amount","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_last_sale_date","type":"date","default":null,"identity":"","not_null":false,"generated":""},{"name":"property_last_sale_price","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_stage","type":"text","default":"'New / Unassigned'::text","identity":"","not_null":false,"generated":""},{"name":"graduated_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"lat","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"lng","type":"double precision","default":null,"identity":"","not_null":false,"generated":""},{"name":"geocoded_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"geocode_confidence","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"lost_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"dnc_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"engagement_score","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"recency_score","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"last_served_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"data_quality_flags","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"partner_types","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"referral_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"referral_partner_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"portal_token","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"link_group_id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":false,"generated":""},{"name":"is_dnc","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"dnc_checked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"dnc_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_origin","type":"text","default":"'system'::text","identity":"","not_null":true,"generated":""},{"name":"created_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"legacy_lead_deck_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"deletion_reason_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"voicemail_attempt_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"last_voicemail_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"last_voicemail_outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_callback_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"booking_rep_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"booked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"appt_starts_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"gcal_event_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"appt_outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"appt_outcome_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"appt_outcome_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"confirmation_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"reminder_24h_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"reminder_1h_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_notified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"lane_state","type":"lead_lane_state","default":"'cold'::lead_lane_state","identity":"","not_null":true,"generated":""},{"name":"source_batch_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_batch_row_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_source_ids","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"additional_phones","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"additional_emails","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"homeowner_attributes","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_created_date","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"secondary_owner_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"import_source","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"compliance_metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"insurance_carrier","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_filed_date","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_test_account","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"test_account_static","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"test_account_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"test_account_marked_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"test_account_marked_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"route_contact_number","type":"text","default":"lpad(((((10000000)::double precision + floor((random() * (90000000)::double precision))))::bigint)::text, 8, '0'::text)","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_contacts_assigned_deleted","definition":"CREATE INDEX idx_contacts_assigned_deleted ON public.unified_contacts USING btree (assigned_to, deleted_at)"},{"name":"idx_contacts_created_priority","definition":"CREATE INDEX idx_contacts_created_priority ON public.unified_contacts USING btree (created_at DESC, priority)"},{"name":"idx_contacts_quality_score","definition":"CREATE INDEX idx_contacts_quality_score ON public.unified_contacts USING btree (quality_score DESC) WHERE (quality_score IS NOT NULL)"},{"name":"idx_contacts_search","definition":"CREATE INDEX idx_contacts_search ON public.unified_contacts USING gin (to_tsvector('english'::regconfig, ((((((((((COALESCE(name, ''::text) || ' '::text) || COALESCE(email, ''::text)) || ' '::text) || COALESCE(phone, ''::text)) || ' '::text) || COALESCE(address, ''::text)) || ' '::text) || COALESCE(city, ''::text)) || ' '::text) || COALESCE(notes, ''::text))))"},{"name":"idx_contacts_tenant_status","definition":"CREATE INDEX idx_contacts_tenant_status ON public.unified_contacts USING btree (tenant_org_id, status)"},{"name":"idx_uc_appt_outcome","definition":"CREATE INDEX idx_uc_appt_outcome ON public.unified_contacts USING btree (appt_outcome) WHERE (appt_outcome IS NOT NULL)"},{"name":"idx_uc_appt_starts","definition":"CREATE INDEX idx_uc_appt_starts ON public.unified_contacts USING btree (appt_starts_at) WHERE (appt_starts_at IS NOT NULL)"},{"name":"idx_uc_booking_rep","definition":"CREATE INDEX idx_uc_booking_rep ON public.unified_contacts USING btree (booking_rep_id) WHERE (booking_rep_id IS NOT NULL)"},{"name":"idx_unified_contacts_active_tenant_updated","definition":"CREATE INDEX idx_unified_contacts_active_tenant_updated ON public.unified_contacts USING btree (tenant_org_id, updated_at DESC) WHERE ((deleted_at IS NULL) AND (archived_at IS NULL) AND (graduated_at IS NULL))"},{"name":"idx_unified_contacts_additional_phones","definition":"CREATE INDEX idx_unified_contacts_additional_phones ON public.unified_contacts USING gin (additional_phones)"},{"name":"idx_unified_contacts_assigned_to","definition":"CREATE INDEX idx_unified_contacts_assigned_to ON public.unified_contacts USING btree (assigned_to)"},{"name":"idx_unified_contacts_claim_stage","definition":"CREATE INDEX idx_unified_contacts_claim_stage ON public.unified_contacts USING btree (claim_stage) WHERE (deleted_at IS NULL)"},{"name":"idx_unified_contacts_compliance_metadata_gin","definition":"CREATE INDEX idx_unified_contacts_compliance_metadata_gin ON public.unified_contacts USING gin (compliance_metadata) WHERE (compliance_metadata IS NOT NULL)"},{"name":"idx_unified_contacts_coordinates","definition":"CREATE INDEX idx_unified_contacts_coordinates ON public.unified_contacts USING btree (lat, lng) WHERE ((lat IS NOT NULL) AND (lng IS NOT NULL))"},{"name":"idx_unified_contacts_created_at","definition":"CREATE INDEX idx_unified_contacts_created_at ON public.unified_contacts USING btree (created_at DESC)"},{"name":"idx_unified_contacts_created_by_user_id","definition":"CREATE INDEX idx_unified_contacts_created_by_user_id ON public.unified_contacts USING btree (created_by_user_id) WHERE ((deleted_at IS NULL) AND (created_by_user_id IS NOT NULL))"},{"name":"idx_unified_contacts_deleted_at","definition":"CREATE INDEX idx_unified_contacts_deleted_at ON public.unified_contacts USING btree (deleted_at) WHERE (deleted_at IS NOT NULL)"},{"name":"idx_unified_contacts_external_source_ids","definition":"CREATE INDEX idx_unified_contacts_external_source_ids ON public.unified_contacts USING gin (external_source_ids)"},{"name":"idx_unified_contacts_import_source","definition":"CREATE INDEX idx_unified_contacts_import_source ON public.unified_contacts USING btree (tenant_org_id, import_source) WHERE (import_source IS NOT NULL)"},{"name":"idx_unified_contacts_is_dnc","definition":"CREATE INDEX idx_unified_contacts_is_dnc ON public.unified_contacts USING btree (is_dnc) WHERE (is_dnc = false)"},{"name":"idx_unified_contacts_jobs_stage","definition":"CREATE INDEX idx_unified_contacts_jobs_stage ON public.unified_contacts USING btree (jobs_stage) WHERE (deleted_at IS NULL)"},{"name":"idx_unified_contacts_last_served_at","definition":"CREATE INDEX idx_unified_contacts_last_served_at ON public.unified_contacts USING btree (tenant_org_id, last_served_at NULLS FIRST) WHERE ((deleted_at IS NULL) AND (graduated_at IS NULL))"},{"name":"idx_unified_contacts_last_touched_at","definition":"CREATE INDEX idx_unified_contacts_last_touched_at ON public.unified_contacts USING btree (last_touched_at DESC)"},{"name":"idx_unified_contacts_lead_id","definition":"CREATE INDEX idx_unified_contacts_lead_id ON public.unified_contacts USING btree (lead_id)"},{"name":"idx_unified_contacts_lead_origin","definition":"CREATE INDEX idx_unified_contacts_lead_origin ON public.unified_contacts USING btree (lead_origin) WHERE (deleted_at IS NULL)"},{"name":"idx_unified_contacts_lead_stage","definition":"CREATE INDEX idx_unified_contacts_lead_stage ON public.unified_contacts USING btree (lead_stage) WHERE (deleted_at IS NULL)"},{"name":"idx_unified_contacts_legacy_lead_deck_id","definition":"CREATE INDEX idx_unified_contacts_legacy_lead_deck_id ON public.unified_contacts USING btree (legacy_lead_deck_id) WHERE (legacy_lead_deck_id IS NOT NULL)"},{"name":"idx_unified_contacts_norm_addr","definition":"CREATE INDEX idx_unified_contacts_norm_addr ON public.unified_contacts USING btree (tenant_org_id, normalize_address(address, zip)) WHERE (address IS NOT NULL)"},{"name":"idx_unified_contacts_normalized_address","definition":"CREATE INDEX idx_unified_contacts_normalized_address ON public.unified_contacts USING btree (normalized_address)"},{"name":"idx_unified_contacts_normalized_email","definition":"CREATE INDEX idx_unified_contacts_normalized_email ON public.unified_contacts USING btree (normalized_email)"},{"name":"idx_unified_contacts_normalized_phone","definition":"CREATE INDEX idx_unified_contacts_normalized_phone ON public.unified_contacts USING btree (normalized_phone)"},{"name":"idx_unified_contacts_partner_types","definition":"CREATE INDEX idx_unified_contacts_partner_types ON public.unified_contacts USING gin (partner_types)"},{"name":"idx_unified_contacts_permit_scan","definition":"CREATE INDEX idx_unified_contacts_permit_scan ON public.unified_contacts USING btree (permit_scanned_at)"},{"name":"idx_unified_contacts_phone_email","definition":"CREATE INDEX idx_unified_contacts_phone_email ON public.unified_contacts USING btree (phone, email) WHERE ((deleted_at IS NULL) AND (phone IS NOT NULL) AND (email IS NOT NULL))"},{"name":"idx_unified_contacts_property_fetched","definition":"CREATE INDEX idx_unified_contacts_property_fetched ON public.unified_contacts USING btree (property_data_fetched_at)"},{"name":"idx_unified_contacts_property_parcel","definition":"CREATE INDEX idx_unified_contacts_property_parcel ON public.unified_contacts USING btree (property_parcel_id)"},{"name":"idx_unified_contacts_quality_flags","definition":"CREATE INDEX idx_unified_contacts_quality_flags ON public.unified_contacts USING gin (data_quality_flags)"},{"name":"idx_unified_contacts_recent_roof","definition":"CREATE INDEX idx_unified_contacts_recent_roof ON public.unified_contacts USING btree (has_recent_roof_permit) WHERE (has_recent_roof_permit = true)"},{"name":"idx_unified_contacts_ref","definition":"CREATE INDEX idx_unified_contacts_ref ON public.unified_contacts USING btree (contact_ref)"},{"name":"idx_unified_contacts_referral","definition":"CREATE INDEX idx_unified_contacts_referral ON public.unified_contacts USING btree (referral_source) WHERE (referral_source IS NOT NULL)"},{"name":"idx_unified_contacts_secondary_owner_name","definition":"CREATE INDEX idx_unified_contacts_secondary_owner_name ON public.unified_contacts USING btree (lower(secondary_owner_name)) WHERE (secondary_owner_name IS NOT NULL)"},{"name":"idx_unified_contacts_source_batch","definition":"CREATE INDEX idx_unified_contacts_source_batch ON public.unified_contacts USING btree (source_batch_id)"},{"name":"idx_unified_contacts_status","definition":"CREATE INDEX idx_unified_contacts_status ON public.unified_contacts USING btree (status)"},{"name":"idx_unified_contacts_tenant_assigned","definition":"CREATE INDEX idx_unified_contacts_tenant_assigned ON public.unified_contacts USING btree (tenant_org_id, assigned_to) WHERE (deleted_at IS NULL)"},{"name":"idx_unified_contacts_tenant_claim_number","definition":"CREATE INDEX idx_unified_contacts_tenant_claim_number ON public.unified_contacts USING btree (tenant_org_id, claim_number) WHERE ((claim_number IS NOT NULL) AND (deleted_at IS NULL))"},{"name":"idx_unified_contacts_tenant_insurance_carrier","definition":"CREATE INDEX idx_unified_contacts_tenant_insurance_carrier ON public.unified_contacts USING btree (tenant_org_id, insurance_carrier) WHERE ((insurance_carrier IS NOT NULL) AND (deleted_at IS NULL))"},{"name":"idx_unified_contacts_tenant_lead_score","definition":"CREATE INDEX idx_unified_contacts_tenant_lead_score ON public.unified_contacts USING btree (tenant_org_id, lead_score DESC NULLS LAST) WHERE (deleted_at IS NULL)"},{"name":"idx_unified_contacts_tenant_org","definition":"CREATE INDEX idx_unified_contacts_tenant_org ON public.unified_contacts USING btree (tenant_org_id) WHERE (deleted_at IS NULL)"},{"name":"idx_unified_contacts_tenant_org_id","definition":"CREATE INDEX idx_unified_contacts_tenant_org_id ON public.unified_contacts USING btree (tenant_org_id)"},{"name":"idx_unified_contacts_tenant_pipelines","definition":"CREATE INDEX idx_unified_contacts_tenant_pipelines ON public.unified_contacts USING btree (tenant_org_id, jobs_stage, claim_stage) WHERE (deleted_at IS NULL)"},{"name":"idx_unified_contacts_tenant_policy_number","definition":"CREATE INDEX idx_unified_contacts_tenant_policy_number ON public.unified_contacts USING btree (tenant_org_id, policy_number) WHERE ((policy_number IS NOT NULL) AND (deleted_at IS NULL))"},{"name":"idx_unified_contacts_tenant_state_present","definition":"CREATE INDEX idx_unified_contacts_tenant_state_present ON public.unified_contacts USING btree (tenant_org_id, state) WHERE (state IS NOT NULL)"},{"name":"idx_unified_contacts_test_account","definition":"CREATE INDEX idx_unified_contacts_test_account ON public.unified_contacts USING btree (tenant_org_id) WHERE (is_test_account = true)"},{"name":"unified_contacts_contact_id_key","definition":"CREATE UNIQUE INDEX unified_contacts_contact_id_key ON public.unified_contacts USING btree (contact_id)"},{"name":"unified_contacts_lane_state_idx","definition":"CREATE INDEX unified_contacts_lane_state_idx ON public.unified_contacts USING btree (tenant_org_id, lane_state)"},{"name":"unified_contacts_pkey","definition":"CREATE UNIQUE INDEX unified_contacts_pkey ON public.unified_contacts USING btree (id)"},{"name":"unified_contacts_tenant_route_contact_number_uidx","definition":"CREATE UNIQUE INDEX unified_contacts_tenant_route_contact_number_uidx ON public.unified_contacts USING btree (tenant_org_id, route_contact_number) WHERE ((tenant_org_id IS NOT NULL) AND (route_contact_number IS NOT NULL) AND (deleted_at IS NULL))"}],"policies":[{"cmd":"ALL","qual":"(((tenant_org_id IS NOT NULL) AND (tenant_org_id ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'::text) AND ((tenant_org_id)::uuid = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[])))) OR ( SELECT is_system_admin(uid()) AS is_system_admin))","roles":["authenticated"],"tablename":"unified_contacts","permissive":"PERMISSIVE","policyname":"tenant_members_all_contacts","schemaname":"public","with_check":"(((tenant_org_id IS NOT NULL) AND (tenant_org_id ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'::text) AND ((tenant_org_id)::uuid = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[])))) OR ( SELECT is_system_admin(uid()) AS is_system_admin))"},{"cmd":"ALL","qual":"((tenant_org_id IS DISTINCT FROM '669daee1-57e8-4960-937c-ce397106f32e'::text) OR (assigned_user = (( SELECT uid() AS uid))::text) OR (assigned_to = (( SELECT uid() AS uid))::text) OR (lower(COALESCE(assigned_to, ''::text)) = lower(COALESCE(( SELECT current_user_email() AS current_user_email), ''::text))) OR (lower(COALESCE(assigned_rep, ''::text)) = lower(COALESCE(( SELECT current_user_email() AS current_user_email), ''::text))) OR (EXISTS ( SELECT 1\n   FROM (admin_action_logs started\n     JOIN profiles target_profile ON ((target_profile.id = started.target_user_id)))\n  WHERE ((started.admin_user_id = ( SELECT uid() AS uid)) AND (started.action_type = 'impersonation_started'::text) AND (started.target_tenant_id = '669daee1-57e8-4960-937c-ce397106f32e'::uuid) AND ((unified_contacts.assigned_user = (started.target_user_id)::text) OR (unified_contacts.assigned_to = (started.target_user_id)::text) OR (lower(COALESCE(unified_contacts.assigned_to, ''::text)) = lower(COALESCE(target_profile.email, ''::text))) OR (lower(COALESCE(unified_contacts.assigned_rep, ''::text)) = lower(COALESCE(target_profile.email, ''::text)))) AND (NOT (EXISTS ( SELECT 1\n           FROM admin_action_logs stopped\n          WHERE ((stopped.admin_user_id = started.admin_user_id) AND (stopped.target_user_id = started.target_user_id) AND (stopped.action_type = 'impersonation_stopped'::text) AND (COALESCE(stopped.\"timestamp\", stopped.created_at) > COALESCE(started.\"timestamp\", started.created_at))))))))))","roles":["authenticated"],"tablename":"unified_contacts","permissive":"RESTRICTIVE","policyname":"tennex_user_contact_exclusivity","schemaname":"public","with_check":"((tenant_org_id IS DISTINCT FROM '669daee1-57e8-4960-937c-ce397106f32e'::text) OR (assigned_user = (( SELECT uid() AS uid))::text) OR (assigned_to = (( SELECT uid() AS uid))::text) OR (lower(COALESCE(assigned_to, ''::text)) = lower(COALESCE(( SELECT current_user_email() AS current_user_email), ''::text))) OR (lower(COALESCE(assigned_rep, ''::text)) = lower(COALESCE(( SELECT current_user_email() AS current_user_email), ''::text))) OR (EXISTS ( SELECT 1\n   FROM (admin_action_logs started\n     JOIN profiles target_profile ON ((target_profile.id = started.target_user_id)))\n  WHERE ((started.admin_user_id = ( SELECT uid() AS uid)) AND (started.action_type = 'impersonation_started'::text) AND (started.target_tenant_id = '669daee1-57e8-4960-937c-ce397106f32e'::uuid) AND ((unified_contacts.assigned_user = (started.target_user_id)::text) OR (unified_contacts.assigned_to = (started.target_user_id)::text) OR (lower(COALESCE(unified_contacts.assigned_to, ''::text)) = lower(COALESCE(target_profile.email, ''::text))) OR (lower(COALESCE(unified_contacts.assigned_rep, ''::text)) = lower(COALESCE(target_profile.email, ''::text)))) AND (NOT (EXISTS ( SELECT 1\n           FROM admin_action_logs stopped\n          WHERE ((stopped.admin_user_id = started.admin_user_id) AND (stopped.target_user_id = started.target_user_id) AND (stopped.action_type = 'impersonation_stopped'::text) AND (COALESCE(stopped.\"timestamp\", stopped.created_at) > COALESCE(started.\"timestamp\", started.created_at))))))))))"},{"cmd":"SELECT","qual":"(((tenant_org_id IS NOT NULL) AND (tenant_org_id ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'::text) AND ((tenant_org_id)::uuid = ANY (COALESCE(( SELECT current_user_tenant_ids() AS current_user_tenant_ids), ARRAY[]::uuid[])))) OR ( SELECT is_system_admin(uid()) AS is_system_admin) OR (assigned_to = (( SELECT uid() AS uid))::text) OR (lower(assigned_to) = lower(( SELECT current_user_email() AS current_user_email))))","roles":["public"],"tablename":"unified_contacts","permissive":"PERMISSIVE","policyname":"uc_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((assigned_to IS NOT NULL) AND ((assigned_to = (( SELECT uid() AS uid))::text) OR (lower(assigned_to) = lower(( SELECT current_user_email() AS current_user_email)))))","roles":["authenticated"],"tablename":"unified_contacts","permissive":"PERMISSIVE","policyname":"uc_user_assigned_update","schemaname":"public","with_check":"((assigned_to IS NOT NULL) AND ((assigned_to = (( SELECT uid() AS uid))::text) OR (lower(assigned_to) = lower(( SELECT current_user_email() AS current_user_email)))))"}],"triggers":[{"name":"aaa_validate_tenant_org_id","definition":"CREATE TRIGGER aaa_validate_tenant_org_id BEFORE INSERT OR UPDATE OF tenant_org_id ON unified_contacts FOR EACH ROW EXECUTE FUNCTION aaa_validate_tenant_org_id_fn()"},{"name":"audit_trigger_unified_contacts","definition":"CREATE TRIGGER audit_trigger_unified_contacts AFTER INSERT OR DELETE OR UPDATE ON unified_contacts FOR EACH ROW EXECUTE FUNCTION comprehensive_audit_trigger_fn()"},{"name":"automation_dispatch_unified_contacts","definition":"CREATE TRIGGER automation_dispatch_unified_contacts AFTER UPDATE OF status, lead_stage, jobs_stage, claim_stage, assigned_to ON unified_contacts FOR EACH ROW EXECUTE FUNCTION automation_dispatch_on_update()"},{"name":"tr_record_score_change","definition":"CREATE TRIGGER tr_record_score_change AFTER UPDATE OF lead_score ON unified_contacts FOR EACH ROW EXECUTE FUNCTION record_score_change()"},{"name":"trg_apply_configured_lead_source_routing","definition":"CREATE TRIGGER trg_apply_configured_lead_source_routing BEFORE INSERT OR UPDATE OF tenant_org_id, source ON unified_contacts FOR EACH ROW EXECUTE FUNCTION apply_configured_lead_source_routing()"},{"name":"trg_auto_route_new_roof_lead","definition":"CREATE TRIGGER trg_auto_route_new_roof_lead BEFORE INSERT OR UPDATE OF roof_permit_finaled_date, property_year_built, has_recent_roof_permit, deleted_at ON unified_contacts FOR EACH ROW WHEN (new.deleted_at IS NULL) EXECUTE FUNCTION auto_route_new_roof_lead()"},{"name":"trg_dispatch_homeowner_update_on_stage_change","definition":"CREATE TRIGGER trg_dispatch_homeowner_update_on_stage_change AFTER UPDATE OF lead_stage, claim_stage, jobs_stage ON unified_contacts FOR EACH ROW EXECUTE FUNCTION dispatch_homeowner_stage_update()"},{"name":"trg_enforce_assigned_user_tenant_match","definition":"CREATE TRIGGER trg_enforce_assigned_user_tenant_match BEFORE INSERT OR UPDATE OF assigned_user, assigned_to, tenant_org_id ON unified_contacts FOR EACH ROW EXECUTE FUNCTION enforce_assigned_user_tenant_match()"},{"name":"trg_enforce_test_account_rules_iud","definition":"CREATE TRIGGER trg_enforce_test_account_rules_iud BEFORE INSERT OR DELETE OR UPDATE ON unified_contacts FOR EACH ROW EXECUTE FUNCTION enforce_test_account_rules()"},{"name":"trg_ensure_unique_route_contact_number","definition":"CREATE TRIGGER trg_ensure_unique_route_contact_number BEFORE INSERT OR UPDATE OF tenant_org_id, route_contact_number ON unified_contacts FOR EACH ROW EXECUTE FUNCTION ensure_unique_route_contact_number()"},{"name":"trg_log_realtor_assignment_change","definition":"CREATE TRIGGER trg_log_realtor_assignment_change AFTER UPDATE OF assigned_user ON unified_contacts FOR EACH ROW EXECUTE FUNCTION log_realtor_assignment_change()"},{"name":"trg_mark_score_stale_on_contact","definition":"CREATE TRIGGER trg_mark_score_stale_on_contact AFTER UPDATE ON unified_contacts FOR EACH ROW EXECUTE FUNCTION mark_score_stale_on_contact_change()"},{"name":"trg_notify_owner_appointment","definition":"CREATE TRIGGER trg_notify_owner_appointment AFTER INSERT OR UPDATE ON unified_contacts FOR EACH ROW EXECUTE FUNCTION notify_tenant_owner_on_appointment()"},{"name":"trg_revoke_portal_links_on_archive","definition":"CREATE TRIGGER trg_revoke_portal_links_on_archive AFTER UPDATE OF archived_at ON unified_contacts FOR EACH ROW EXECUTE FUNCTION revoke_portal_links_on_archive()"},{"name":"trg_scrub_unified_contacts_dnc","definition":"CREATE TRIGGER trg_scrub_unified_contacts_dnc BEFORE INSERT OR UPDATE OF phone ON unified_contacts FOR EACH ROW EXECUTE FUNCTION scrub_lead_against_dnc()"},{"name":"trg_sync_linked_contacts","definition":"CREATE TRIGGER trg_sync_linked_contacts AFTER UPDATE ON unified_contacts FOR EACH ROW EXECUTE FUNCTION sync_linked_contacts()"},{"name":"trg_unified_contacts_autofill_name","definition":"CREATE TRIGGER trg_unified_contacts_autofill_name BEFORE INSERT OR UPDATE OF first_name, last_name, name ON unified_contacts FOR EACH ROW EXECUTE FUNCTION unified_contacts_autofill_name()"},{"name":"trg_unified_contacts_mark_scores_stale","definition":"CREATE TRIGGER trg_unified_contacts_mark_scores_stale AFTER UPDATE ON unified_contacts FOR EACH ROW EXECUTE FUNCTION mark_scores_stale_for_contact()"},{"name":"trg_validate_assigned_to_uc","definition":"CREATE TRIGGER trg_validate_assigned_to_uc BEFORE INSERT OR UPDATE OF assigned_to ON unified_contacts FOR EACH ROW EXECUTE FUNCTION validate_assigned_to_uuid()"},{"name":"unified_contacts_auto_graduate","definition":"CREATE TRIGGER unified_contacts_auto_graduate BEFORE UPDATE ON unified_contacts FOR EACH ROW EXECUTE FUNCTION auto_graduate_lead()"},{"name":"unified_contacts_business_activity","definition":"CREATE TRIGGER unified_contacts_business_activity AFTER INSERT OR UPDATE OF source, lead_origin, referral_source, lead_stage, status, contact_status, service_status, assigned_to, assigned_user, assigned_rep, graduated_at, lost_at ON unified_contacts FOR EACH ROW EXECUTE FUNCTION project_contact_business_activity()"},{"name":"unified_contacts_mirror_assigned","definition":"CREATE TRIGGER unified_contacts_mirror_assigned BEFORE INSERT OR UPDATE OF assigned_to, assigned_user ON unified_contacts FOR EACH ROW EXECUTE FUNCTION tg_unified_contacts_mirror_assigned()"},{"name":"unified_contacts_quality_score","definition":"CREATE TRIGGER unified_contacts_quality_score BEFORE INSERT OR UPDATE ON unified_contacts FOR EACH ROW EXECUTE FUNCTION update_quality_score()"},{"name":"unified_contacts_updated_at","definition":"CREATE TRIGGER unified_contacts_updated_at BEFORE UPDATE ON unified_contacts FOR EACH ROW EXECUTE FUNCTION update_unified_contacts_updated_at()"}],"constraints":[{"name":"unified_contacts_contact_id_key","definition":"UNIQUE (contact_id)"},{"name":"unified_contacts_lead_origin_check","definition":"CHECK (lead_origin = ANY (ARRAY['system'::text, 'personal'::text]))"},{"name":"unified_contacts_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"unified_contacts_insert_violations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"violation_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"attempted_tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"attempted_lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"auth_uid","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"application_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"client_addr","type":"inet","default":null,"identity":"","not_null":false,"generated":""},{"name":"raw_row","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_uc_insert_violations_occurred_at","definition":"CREATE INDEX idx_uc_insert_violations_occurred_at ON public.unified_contacts_insert_violations USING btree (occurred_at DESC)"},{"name":"idx_uc_insert_violations_type","definition":"CREATE INDEX idx_uc_insert_violations_type ON public.unified_contacts_insert_violations USING btree (violation_type)"},{"name":"unified_contacts_insert_violations_pkey","definition":"CREATE UNIQUE INDEX unified_contacts_insert_violations_pkey ON public.unified_contacts_insert_violations USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"unified_contacts_insert_violations","permissive":"PERMISSIVE","policyname":"system_admins_read_uc_insert_violations","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"unified_contacts_insert_violations_pkey","definition":"PRIMARY KEY (id)"},{"name":"unified_contacts_insert_violations_violation_type_check","definition":"CHECK (violation_type = ANY (ARRAY['null_tenant'::text, 'orphan_tenant'::text]))"}]},{"table":"unified_inbox","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"channel","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"direction","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"subject","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"body","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"preview","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"from_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"thread_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_read","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"is_starred","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"is_archived","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"labels","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"received_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_unified_inbox_channel","definition":"CREATE INDEX idx_unified_inbox_channel ON public.unified_inbox USING btree (channel)"},{"name":"idx_unified_inbox_contact","definition":"CREATE INDEX idx_unified_inbox_contact ON public.unified_inbox USING btree (contact_id)"},{"name":"idx_unified_inbox_tenant","definition":"CREATE INDEX idx_unified_inbox_tenant ON public.unified_inbox USING btree (tenant_id)"},{"name":"idx_unified_inbox_unread","definition":"CREATE INDEX idx_unified_inbox_unread ON public.unified_inbox USING btree (tenant_id, is_read, is_archived)"},{"name":"unified_inbox_pkey","definition":"CREATE UNIQUE INDEX unified_inbox_pkey ON public.unified_inbox USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(tenant_id IN ( SELECT user_roles.tenant_id\n   FROM user_roles\n  WHERE (user_roles.user_id = uid())))","roles":["public"],"tablename":"unified_inbox","permissive":"PERMISSIVE","policyname":"Tenant isolation for unified_inbox","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"unified_inbox_channel_check","definition":"CHECK (channel = ANY (ARRAY['email'::text, 'sms'::text, 'call'::text, 'voicemail'::text, 'chat'::text, 'social'::text]))"},{"name":"unified_inbox_contact_id_fkey","definition":"FOREIGN KEY (contact_id) REFERENCES unified_contacts(id) ON DELETE SET NULL"},{"name":"unified_inbox_direction_check","definition":"CHECK (direction = ANY (ARRAY['inbound'::text, 'outbound'::text]))"},{"name":"unified_inbox_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"usage_counters","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"feature_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_start","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"count","type":"bigint","default":"0","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_usage_counters_tenant_period","definition":"CREATE INDEX idx_usage_counters_tenant_period ON public.usage_counters USING btree (tenant_id, period_start DESC)"},{"name":"usage_counters_pkey","definition":"CREATE UNIQUE INDEX usage_counters_pkey ON public.usage_counters USING btree (id)"},{"name":"usage_counters_tenant_id_feature_key_period_start_key","definition":"CREATE UNIQUE INDEX usage_counters_tenant_id_feature_key_period_start_key ON public.usage_counters USING btree (tenant_id, feature_key, period_start)"}],"policies":[{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"usage_counters","permissive":"PERMISSIVE","policyname":"Only system admins write usage counters","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = usage_counters.tenant_id) AND (m.status = 'active'::text)))))","roles":["public"],"tablename":"usage_counters","permissive":"PERMISSIVE","policyname":"Tenant members read usage counters","schemaname":"public","with_check":null}],"triggers":[{"name":"update_usage_counters_updated_at","definition":"CREATE TRIGGER update_usage_counters_updated_at BEFORE UPDATE ON usage_counters FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"usage_counters_pkey","definition":"PRIMARY KEY (id)"},{"name":"usage_counters_tenant_id_feature_key_period_start_key","definition":"UNIQUE (tenant_id, feature_key, period_start)"}]},{"table":"user_achievements","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"achievement_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"earned_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"progress","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"notified","type":"boolean","default":"false","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_user_achievements_tenant","definition":"CREATE INDEX idx_user_achievements_tenant ON public.user_achievements USING btree (tenant_org_id)"},{"name":"idx_user_achievements_user_id","definition":"CREATE INDEX idx_user_achievements_user_id ON public.user_achievements USING btree (user_id)"},{"name":"user_achievements_pkey","definition":"CREATE UNIQUE INDEX user_achievements_pkey ON public.user_achievements USING btree (id)"},{"name":"user_achievements_user_id_achievement_id_key","definition":"CREATE UNIQUE INDEX user_achievements_user_id_achievement_id_key ON public.user_achievements USING btree (user_id, achievement_id)"}],"policies":[{"cmd":"SELECT","qual":"(uid() = user_id)","roles":["public"],"tablename":"user_achievements","permissive":"PERMISSIVE","policyname":"Users view own achievements","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"user_achievements_pkey","definition":"PRIMARY KEY (id)"},{"name":"user_achievements_user_id_achievement_id_key","definition":"UNIQUE (user_id, achievement_id)"}]},{"table":"user_activity_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"session_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"route_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"route_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"action_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"human_summary","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"device_family","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"occurred_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"user_activity_events_pkey","definition":"CREATE UNIQUE INDEX user_activity_events_pkey ON public.user_activity_events USING btree (id)"},{"name":"user_activity_events_route_time_idx","definition":"CREATE INDEX user_activity_events_route_time_idx ON public.user_activity_events USING btree (route_path, occurred_at DESC) WHERE (event_type = 'page_view'::text)"},{"name":"user_activity_events_tenant_time_idx","definition":"CREATE INDEX user_activity_events_tenant_time_idx ON public.user_activity_events USING btree (tenant_id, occurred_at DESC)"},{"name":"user_activity_events_type_time_idx","definition":"CREATE INDEX user_activity_events_type_time_idx ON public.user_activity_events USING btree (event_type, occurred_at DESC)"},{"name":"user_activity_events_user_time_idx","definition":"CREATE INDEX user_activity_events_user_time_idx ON public.user_activity_events USING btree (user_id, occurred_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_activity_events","permissive":"PERMISSIVE","policyname":"user_activity_events_insert_own","schemaname":"public","with_check":"((user_id = ( SELECT uid() AS uid)) AND ((tenant_id IS NULL) OR is_tenant_member(tenant_id)))"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"user_activity_events","permissive":"PERMISSIVE","policyname":"user_activity_events_platform_admin_read","schemaname":"public","with_check":null}],"triggers":[{"name":"user_activity_events_business_projection","definition":"CREATE TRIGGER user_activity_events_business_projection AFTER INSERT ON user_activity_events FOR EACH ROW EXECUTE FUNCTION project_user_presence_business_activity()"}],"constraints":[{"name":"user_activity_events_event_type_check","definition":"CHECK (event_type = ANY (ARRAY['login'::text, 'session_start'::text, 'page_view'::text, 'interaction'::text]))"},{"name":"user_activity_events_pkey","definition":"PRIMARY KEY (id)"},{"name":"user_activity_events_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"user_activity_presence","schema":"public","columns":[{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"session_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"current_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_label","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"device_family","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_seen_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"user_activity_presence_last_seen_idx","definition":"CREATE INDEX user_activity_presence_last_seen_idx ON public.user_activity_presence USING btree (last_seen_at DESC)"},{"name":"user_activity_presence_pkey","definition":"CREATE UNIQUE INDEX user_activity_presence_pkey ON public.user_activity_presence USING btree (user_id)"},{"name":"user_activity_presence_tenant_seen_idx","definition":"CREATE INDEX user_activity_presence_tenant_seen_idx ON public.user_activity_presence USING btree (tenant_id, last_seen_at DESC)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_activity_presence","permissive":"PERMISSIVE","policyname":"user_activity_presence_insert_own","schemaname":"public","with_check":"((user_id = ( SELECT uid() AS uid)) AND ((tenant_id IS NULL) OR is_tenant_member(tenant_id)))"},{"cmd":"SELECT","qual":"is_platform_admin(uid())","roles":["authenticated"],"tablename":"user_activity_presence","permissive":"PERMISSIVE","policyname":"user_activity_presence_platform_admin_read","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(( SELECT uid() AS uid) = user_id)","roles":["authenticated"],"tablename":"user_activity_presence","permissive":"PERMISSIVE","policyname":"user_activity_presence_select_own","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((tenant_id IS NOT NULL) AND is_tenant_owner_for(( SELECT uid() AS uid), tenant_id) AND (EXISTS ( SELECT 1\n   FROM user_tenant_memberships member\n  WHERE ((member.user_id = user_activity_presence.user_id) AND ((member.tenant_id)::text = user_activity_presence.tenant_id) AND (member.status = 'active'::text)))))","roles":["authenticated"],"tablename":"user_activity_presence","permissive":"PERMISSIVE","policyname":"user_activity_presence_tenant_owner_read","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(user_id = ( SELECT uid() AS uid))","roles":["authenticated"],"tablename":"user_activity_presence","permissive":"PERMISSIVE","policyname":"user_activity_presence_update_own","schemaname":"public","with_check":"((user_id = ( SELECT uid() AS uid)) AND ((tenant_id IS NULL) OR is_tenant_member(tenant_id)))"}],"triggers":[],"constraints":[{"name":"user_activity_presence_pkey","definition":"PRIMARY KEY (user_id)"},{"name":"user_activity_presence_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"user_calendar_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"assigned_to","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"claim_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_type","type":"text","default":"'appointment'::text","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'scheduled'::text","identity":"","not_null":true,"generated":""},{"name":"pipeline","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pipeline_stage","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"start_time","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"end_time","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"location","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"reminder_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_auto_generated","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"all_day","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"recurrence_rule","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"series_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"event_booking_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_uce_assigned","definition":"CREATE INDEX idx_uce_assigned ON public.user_calendar_events USING btree (assigned_to)"},{"name":"idx_uce_contact","definition":"CREATE INDEX idx_uce_contact ON public.user_calendar_events USING btree (contact_id)"},{"name":"idx_uce_start","definition":"CREATE INDEX idx_uce_start ON public.user_calendar_events USING btree (start_time)"},{"name":"idx_uce_status","definition":"CREATE INDEX idx_uce_status ON public.user_calendar_events USING btree (status)"},{"name":"idx_uce_tenant","definition":"CREATE INDEX idx_uce_tenant ON public.user_calendar_events USING btree (tenant_org_id)"},{"name":"idx_uce_user","definition":"CREATE INDEX idx_uce_user ON public.user_calendar_events USING btree (user_id)"},{"name":"user_calendar_events_event_booking_idx","definition":"CREATE INDEX user_calendar_events_event_booking_idx ON public.user_calendar_events USING btree (event_booking_id)"},{"name":"user_calendar_events_pkey","definition":"CREATE UNIQUE INDEX user_calendar_events_pkey ON public.user_calendar_events USING btree (id)"},{"name":"user_calendar_events_series_idx","definition":"CREATE INDEX user_calendar_events_series_idx ON public.user_calendar_events USING btree (tenant_org_id, series_id) WHERE (series_id IS NOT NULL)"},{"name":"user_calendar_events_task_projection_uidx","definition":"CREATE UNIQUE INDEX user_calendar_events_task_projection_uidx ON public.user_calendar_events USING btree (tenant_org_id, ((metadata ->> 'task_id'::text))) WHERE (((metadata ->> 'source_kind'::text) = 'task'::text) AND (metadata ? 'task_id'::text))"},{"name":"user_calendar_events_tenant_start_idx","definition":"CREATE INDEX user_calendar_events_tenant_start_idx ON public.user_calendar_events USING btree (tenant_org_id, start_time)"}],"policies":[{"cmd":"DELETE","qual":"((uid() = user_id) OR uce_is_owner_or_admin(tenant_org_id))","roles":["authenticated"],"tablename":"user_calendar_events","permissive":"PERMISSIVE","policyname":"uce_delete_owner_or_admin","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_calendar_events","permissive":"PERMISSIVE","policyname":"uce_insert_tenant_member","schemaname":"public","with_check":"(((uid() = user_id) AND (uce_is_member(tenant_org_id) OR uce_is_owner_or_admin(tenant_org_id))) OR is_system_admin(uid()))"},{"cmd":"SELECT","qual":"((uid() = user_id) OR (assigned_to = ( SELECT profiles.email\n   FROM profiles\n  WHERE (profiles.id = uid()))) OR uce_is_owner_or_admin(tenant_org_id))","roles":["authenticated"],"tablename":"user_calendar_events","permissive":"PERMISSIVE","policyname":"uce_select_own_or_assigned","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((uid() = user_id) OR (assigned_to = ( SELECT profiles.email\n   FROM profiles\n  WHERE (profiles.id = uid()))) OR uce_is_owner_or_admin(tenant_org_id))","roles":["authenticated"],"tablename":"user_calendar_events","permissive":"PERMISSIVE","policyname":"uce_update_owner_or_assigned_or_admin","schemaname":"public","with_check":"((uid() = user_id) OR (assigned_to = ( SELECT p.email\n   FROM profiles p\n  WHERE (p.id = uid()))) OR uce_is_owner_or_admin(tenant_org_id))"}],"triggers":[{"name":"trg_enforce_calendar_claim_context","definition":"CREATE TRIGGER trg_enforce_calendar_claim_context BEFORE INSERT OR UPDATE OF claim_id, contact_id, tenant_org_id ON user_calendar_events FOR EACH ROW EXECUTE FUNCTION enforce_calendar_claim_context()"},{"name":"trg_uce_updated_at","definition":"CREATE TRIGGER trg_uce_updated_at BEFORE UPDATE ON user_calendar_events FOR EACH ROW EXECUTE FUNCTION tg_uce_updated_at()"}],"constraints":[{"name":"user_calendar_events_event_booking_id_fkey","definition":"FOREIGN KEY (event_booking_id) REFERENCES event_bookings(id) ON DELETE SET NULL"},{"name":"user_calendar_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"user_changelog_reads","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"changelog_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"read_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_user_changelog_reads_user","definition":"CREATE INDEX idx_user_changelog_reads_user ON public.user_changelog_reads USING btree (user_id)"},{"name":"user_changelog_reads_pkey","definition":"CREATE UNIQUE INDEX user_changelog_reads_pkey ON public.user_changelog_reads USING btree (id)"},{"name":"user_changelog_reads_user_id_changelog_id_key","definition":"CREATE UNIQUE INDEX user_changelog_reads_user_id_changelog_id_key ON public.user_changelog_reads USING btree (user_id, changelog_id)"}],"policies":[{"cmd":"DELETE","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"user_changelog_reads","permissive":"PERMISSIVE","policyname":"Users delete their own changelog reads","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_changelog_reads","permissive":"PERMISSIVE","policyname":"Users insert their own changelog reads","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"SELECT","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"user_changelog_reads","permissive":"PERMISSIVE","policyname":"Users view their own changelog reads","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"user_changelog_reads_pkey","definition":"PRIMARY KEY (id)"},{"name":"user_changelog_reads_user_id_changelog_id_key","definition":"UNIQUE (user_id, changelog_id)"}]},{"table":"user_extensions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"extension","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"ring_strategy","type":"text","default":"'device_then_phone'::text","identity":"","not_null":true,"generated":""},{"name":"voicemail_fallback","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"display_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_user_extensions_tenant","definition":"CREATE INDEX idx_user_extensions_tenant ON public.user_extensions USING btree (tenant_org_id)"},{"name":"idx_user_extensions_user","definition":"CREATE INDEX idx_user_extensions_user ON public.user_extensions USING btree (user_id)"},{"name":"user_extensions_pkey","definition":"CREATE UNIQUE INDEX user_extensions_pkey ON public.user_extensions USING btree (id)"},{"name":"user_extensions_tenant_org_id_extension_key","definition":"CREATE UNIQUE INDEX user_extensions_tenant_org_id_extension_key ON public.user_extensions USING btree (tenant_org_id, extension)"},{"name":"user_extensions_tenant_org_id_user_id_key","definition":"CREATE UNIQUE INDEX user_extensions_tenant_org_id_user_id_key ON public.user_extensions USING btree (tenant_org_id, user_id)"}],"policies":[{"cmd":"DELETE","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"user_extensions","permissive":"PERMISSIVE","policyname":"Managers+ can delete extensions","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_extensions","permissive":"PERMISSIVE","policyname":"Managers+ can insert extensions","schemaname":"public","with_check":"is_manager_or_higher(uid(), tenant_org_id)"},{"cmd":"UPDATE","qual":"is_manager_or_higher(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"user_extensions","permissive":"PERMISSIVE","policyname":"Managers+ can update extensions","schemaname":"public","with_check":"is_manager_or_higher(uid(), tenant_org_id)"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"user_extensions","permissive":"PERMISSIVE","policyname":"Tenant members can view extensions","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_user_extensions_updated","definition":"CREATE TRIGGER trg_user_extensions_updated BEFORE UPDATE ON user_extensions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"user_extensions_extension_check","definition":"CHECK (extension ~ '^[0-9]{3,5}$'::text)"},{"name":"user_extensions_pkey","definition":"PRIMARY KEY (id)"},{"name":"user_extensions_ring_strategy_check","definition":"CHECK (ring_strategy = ANY (ARRAY['device_only'::text, 'phone_only'::text, 'device_then_phone'::text, 'simultaneous'::text]))"},{"name":"user_extensions_tenant_org_id_extension_key","definition":"UNIQUE (tenant_org_id, extension)"},{"name":"user_extensions_tenant_org_id_user_id_key","definition":"UNIQUE (tenant_org_id, user_id)"}]},{"table":"user_feature_overrides","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"feature_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"user_feature_override_status","default":"'inherit'::user_feature_override_status","identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'manual_override'::text","identity":"","not_null":true,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_ufo_feature","definition":"CREATE INDEX idx_ufo_feature ON public.user_feature_overrides USING btree (feature_key)"},{"name":"idx_ufo_tenant_user","definition":"CREATE INDEX idx_ufo_tenant_user ON public.user_feature_overrides USING btree (tenant_org_id, user_id)"},{"name":"user_feature_overrides_pkey","definition":"CREATE UNIQUE INDEX user_feature_overrides_pkey ON public.user_feature_overrides USING btree (id)"},{"name":"user_feature_overrides_tenant_org_id_user_id_feature_key_key","definition":"CREATE UNIQUE INDEX user_feature_overrides_tenant_org_id_user_id_feature_key_key ON public.user_feature_overrides USING btree (tenant_org_id, user_id, feature_key)"}],"policies":[{"cmd":"SELECT","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"user_feature_overrides","permissive":"PERMISSIVE","policyname":"ufo self read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"user_feature_overrides","permissive":"PERMISSIVE","policyname":"ufo system admin all","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[{"name":"ufo_set_updated_at","definition":"CREATE TRIGGER ufo_set_updated_at BEFORE UPDATE ON user_feature_overrides FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"user_feature_overrides_pkey","definition":"PRIMARY KEY (id)"},{"name":"user_feature_overrides_tenant_org_id_user_id_feature_key_key","definition":"UNIQUE (tenant_org_id, user_id, feature_key)"}]},{"table":"user_invitations","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"role","type":"text","default":"'user'::text","identity":"","not_null":false,"generated":""},{"name":"invited_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"invited_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"accepted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":"(now() + '7 days'::interval)","identity":"","not_null":false,"generated":""},{"name":"invitation_token","type":"text","default":"encode(gen_random_bytes(32), 'hex'::text)","identity":"","not_null":false,"generated":""},{"name":"email_opens_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"last_opened_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_user_invitations_email","definition":"CREATE INDEX idx_user_invitations_email ON public.user_invitations USING btree (email)"},{"name":"idx_user_invitations_phone","definition":"CREATE INDEX idx_user_invitations_phone ON public.user_invitations USING btree (phone) WHERE (phone IS NOT NULL)"},{"name":"idx_user_invitations_status","definition":"CREATE INDEX idx_user_invitations_status ON public.user_invitations USING btree (status)"},{"name":"idx_user_invitations_tenant_id","definition":"CREATE INDEX idx_user_invitations_tenant_id ON public.user_invitations USING btree (tenant_id)"},{"name":"idx_user_invitations_token","definition":"CREATE INDEX idx_user_invitations_token ON public.user_invitations USING btree (invitation_token)"},{"name":"user_invitations_invitation_token_key","definition":"CREATE UNIQUE INDEX user_invitations_invitation_token_key ON public.user_invitations USING btree (invitation_token)"},{"name":"user_invitations_pkey","definition":"CREATE UNIQUE INDEX user_invitations_pkey ON public.user_invitations USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_invitations","permissive":"PERMISSIVE","policyname":"invitation_managers_insert","schemaname":"public","with_check":"((status = 'pending'::text) AND ((is_system_admin(uid()) AND (role = ANY (ARRAY['Tenant Owner'::text, 'Manager'::text, 'Office Staff'::text, 'Rep'::text, 'Crew'::text, 'PM'::text, 'PA'::text, 'Roofer'::text, 'Broker'::text, 'Agent'::text, 'Listing Agent'::text, 'Buyer Agent'::text, 'ISA'::text, 'Showing Agent'::text, 'TC'::text]))) OR ((EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN security_active_user_tenant_memberships utm ON (((utm.user_id = ur.user_id) AND (utm.tenant_id = ur.tenant_id))))\n  WHERE ((ur.user_id = uid()) AND (ur.tenant_id = user_invitations.tenant_id) AND (utm.status = 'active'::text) AND ((ur.role)::text = ANY (ARRAY['Owner'::text, 'Tenant Owner'::text, 'Admin'::text, 'GodMode'::text, 'Manager'::text]))))) AND (role = ANY (ARRAY['Manager'::text, 'Office Staff'::text, 'Rep'::text, 'Crew'::text, 'PM'::text, 'PA'::text, 'Roofer'::text, 'Broker'::text, 'Agent'::text, 'Listing Agent'::text, 'Buyer Agent'::text, 'ISA'::text, 'Showing Agent'::text, 'TC'::text])))))"},{"cmd":"SELECT","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN security_active_user_tenant_memberships utm ON (((utm.user_id = ur.user_id) AND (utm.tenant_id = ur.tenant_id))))\n  WHERE ((ur.user_id = uid()) AND (ur.tenant_id = user_invitations.tenant_id) AND (utm.status = 'active'::text) AND ((ur.role)::text = ANY (ARRAY['Owner'::text, 'Tenant Owner'::text, 'Admin'::text, 'GodMode'::text, 'Manager'::text]))))))","roles":["authenticated"],"tablename":"user_invitations","permissive":"PERMISSIVE","policyname":"invitation_managers_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN security_active_user_tenant_memberships utm ON (((utm.user_id = ur.user_id) AND (utm.tenant_id = ur.tenant_id))))\n  WHERE ((ur.user_id = uid()) AND (ur.tenant_id = user_invitations.tenant_id) AND (utm.status = 'active'::text) AND ((ur.role)::text = ANY (ARRAY['Owner'::text, 'Tenant Owner'::text, 'Admin'::text, 'GodMode'::text, 'Manager'::text]))))))","roles":["authenticated"],"tablename":"user_invitations","permissive":"PERMISSIVE","policyname":"invitation_managers_update","schemaname":"public","with_check":"((status = ANY (ARRAY['pending'::text, 'expired'::text, 'cancelled'::text])) AND ((is_system_admin(uid()) AND (role = ANY (ARRAY['Tenant Owner'::text, 'Manager'::text, 'Office Staff'::text, 'Rep'::text, 'Crew'::text, 'PM'::text, 'PA'::text, 'Roofer'::text, 'Broker'::text, 'Agent'::text, 'Listing Agent'::text, 'Buyer Agent'::text, 'ISA'::text, 'Showing Agent'::text, 'TC'::text]))) OR ((EXISTS ( SELECT 1\n   FROM (user_roles ur\n     JOIN security_active_user_tenant_memberships utm ON (((utm.user_id = ur.user_id) AND (utm.tenant_id = user_invitations.tenant_id))))\n  WHERE ((ur.user_id = uid()) AND (ur.tenant_id = user_invitations.tenant_id) AND (utm.status = 'active'::text) AND ((ur.role)::text = ANY (ARRAY['Owner'::text, 'Tenant Owner'::text, 'Admin'::text, 'GodMode'::text, 'Manager'::text]))))) AND (role = ANY (ARRAY['Manager'::text, 'Office Staff'::text, 'Rep'::text, 'Crew'::text, 'PM'::text, 'PA'::text, 'Roofer'::text, 'Broker'::text, 'Agent'::text, 'Listing Agent'::text, 'Buyer Agent'::text, 'ISA'::text, 'Showing Agent'::text, 'TC'::text])))))"}],"triggers":[{"name":"protect_accepted_user_invitations","definition":"CREATE TRIGGER protect_accepted_user_invitations BEFORE UPDATE ON user_invitations FOR EACH ROW EXECUTE FUNCTION prevent_accepted_invitation_mutation()"},{"name":"update_user_invitations_updated_at","definition":"CREATE TRIGGER update_user_invitations_updated_at BEFORE UPDATE ON user_invitations FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"},{"name":"user_invitations_capture_owner_history","definition":"CREATE TRIGGER user_invitations_capture_owner_history AFTER INSERT OR UPDATE OF status, accepted_at, email, name, role ON user_invitations FOR EACH ROW EXECUTE FUNCTION capture_owner_invitation_history()"}],"constraints":[{"name":"user_invitations_accepted_timestamp_consistent","definition":"CHECK (status = 'accepted'::text AND accepted_at IS NOT NULL OR status <> 'accepted'::text AND accepted_at IS NULL)"},{"name":"user_invitations_identity_required","definition":"CHECK (NULLIF(btrim(email), ''::text) IS NOT NULL OR NULLIF(btrim(phone), ''::text) IS NOT NULL)"},{"name":"user_invitations_invitation_token_key","definition":"UNIQUE (invitation_token)"},{"name":"user_invitations_pkey","definition":"PRIMARY KEY (id)"},{"name":"user_invitations_status_check","definition":"CHECK (status = ANY (ARRAY['pending'::text, 'sent'::text, 'opened'::text, 'accepted'::text, 'expired'::text, 'cancelled'::text, 'failed'::text]))"}]},{"table":"user_lead_pointer","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"current_lead_index","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"last_lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_user_lead_pointer_user_tenant","definition":"CREATE INDEX idx_user_lead_pointer_user_tenant ON public.user_lead_pointer USING btree (user_id, tenant_id)"},{"name":"user_lead_pointer_pkey","definition":"CREATE UNIQUE INDEX user_lead_pointer_pkey ON public.user_lead_pointer USING btree (id)"},{"name":"user_lead_pointer_user_id_tenant_id_key","definition":"CREATE UNIQUE INDEX user_lead_pointer_user_id_tenant_id_key ON public.user_lead_pointer USING btree (user_id, tenant_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_lead_pointer","permissive":"PERMISSIVE","policyname":"Users can insert own pointer","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"UPDATE","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"user_lead_pointer","permissive":"PERMISSIVE","policyname":"Users can update own pointer","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"SELECT","qual":"(user_id = uid())","roles":["authenticated"],"tablename":"user_lead_pointer","permissive":"PERMISSIVE","policyname":"Users can view own pointer","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"user_lead_pointer_pkey","definition":"PRIMARY KEY (id)"},{"name":"user_lead_pointer_user_id_tenant_id_key","definition":"UNIQUE (user_id, tenant_id)"}]},{"table":"user_permission_overrides","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"permission_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"granted","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"reason","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"user_permission_overrides_pkey","definition":"CREATE UNIQUE INDEX user_permission_overrides_pkey ON public.user_permission_overrides USING btree (id)"},{"name":"user_permission_overrides_user_id_permission_key_tenant_id_key","definition":"CREATE UNIQUE INDEX user_permission_overrides_user_id_permission_key_tenant_id_key ON public.user_permission_overrides USING btree (user_id, permission_key, tenant_id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"user_permission_overrides","permissive":"PERMISSIVE","policyname":"platform_admin_view_permission_overrides","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"user_permission_overrides_pkey","definition":"PRIMARY KEY (id)"},{"name":"user_permission_overrides_user_id_permission_key_tenant_id_key","definition":"UNIQUE (user_id, permission_key, tenant_id)"}]},{"table":"user_roles","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"role","type":"app_role","default":null,"identity":"","not_null":true,"generated":""},{"name":"assigned_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"bypass_tcpa_hours","type":"boolean","default":"false","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_user_roles_tenant","definition":"CREATE INDEX idx_user_roles_tenant ON public.user_roles USING btree (tenant_id)"},{"name":"user_roles_one_platform_godmode_per_user","definition":"CREATE UNIQUE INDEX user_roles_one_platform_godmode_per_user ON public.user_roles USING btree (user_id) WHERE ((tenant_id IS NULL) AND (role = 'GodMode'::app_role))"},{"name":"user_roles_pkey","definition":"CREATE UNIQUE INDEX user_roles_pkey ON public.user_roles USING btree (id)"},{"name":"user_roles_user_id_tenant_id_role_key","definition":"CREATE UNIQUE INDEX user_roles_user_id_tenant_id_role_key ON public.user_roles USING btree (user_id, tenant_id, role)"},{"name":"user_roles_user_tenant_unique","definition":"CREATE UNIQUE INDEX user_roles_user_tenant_unique ON public.user_roles USING btree (user_id, tenant_id)"}],"policies":[{"cmd":"DELETE","qual":"(is_system_admin(uid()) OR ((tenant_id IS NOT NULL) AND is_tenant_owner(uid(), tenant_id) AND ((role)::text <> 'GodMode'::text)) OR ((tenant_id IS NOT NULL) AND is_admin_or_higher(uid(), tenant_id) AND ((role)::text = ANY (ARRAY['Admin'::text, 'Manager'::text, 'Assistant'::text, 'Rep'::text]))))","roles":["authenticated"],"tablename":"user_roles","permissive":"PERMISSIVE","policyname":"Authorized role managers can delete roles","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_roles","permissive":"PERMISSIVE","policyname":"Authorized role managers can insert roles","schemaname":"public","with_check":"(is_system_admin(uid()) OR ((tenant_id IS NOT NULL) AND is_tenant_owner(uid(), tenant_id) AND ((role)::text <> 'GodMode'::text)) OR ((tenant_id IS NOT NULL) AND is_admin_or_higher(uid(), tenant_id) AND ((role)::text = ANY (ARRAY['Admin'::text, 'Manager'::text, 'Assistant'::text, 'Rep'::text]))))"},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR ((tenant_id IS NOT NULL) AND is_tenant_owner(uid(), tenant_id) AND ((role)::text <> 'GodMode'::text)) OR ((tenant_id IS NOT NULL) AND is_admin_or_higher(uid(), tenant_id) AND ((role)::text = ANY (ARRAY['Admin'::text, 'Manager'::text, 'Assistant'::text, 'Rep'::text]))))","roles":["authenticated"],"tablename":"user_roles","permissive":"PERMISSIVE","policyname":"Authorized role managers can update roles","schemaname":"public","with_check":"(is_system_admin(uid()) OR ((tenant_id IS NOT NULL) AND is_tenant_owner(uid(), tenant_id) AND ((role)::text <> 'GodMode'::text)) OR ((tenant_id IS NOT NULL) AND is_admin_or_higher(uid(), tenant_id) AND ((role)::text = ANY (ARRAY['Admin'::text, 'Manager'::text, 'Assistant'::text, 'Rep'::text]))))"},{"cmd":"SELECT","qual":"((user_id = ( SELECT uid() AS uid)) OR ( SELECT is_system_admin(uid()) AS is_system_admin) OR is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_manager_pm_or_higher(( SELECT uid() AS uid), tenant_id) OR is_tenant_owner_membership(( SELECT uid() AS uid), tenant_id) OR is_tenant_owner_for(( SELECT uid() AS uid), (tenant_id)::text))","roles":["authenticated"],"tablename":"user_roles","permissive":"PERMISSIVE","policyname":"Visible tenant user roles","schemaname":"public","with_check":null}],"triggers":[{"name":"audit_trigger_user_roles","definition":"CREATE TRIGGER audit_trigger_user_roles AFTER INSERT OR DELETE OR UPDATE ON user_roles FOR EACH ROW EXECUTE FUNCTION comprehensive_audit_trigger_fn()"},{"name":"trg_reconcile_default_role_insert","definition":"CREATE TRIGGER trg_reconcile_default_role_insert BEFORE INSERT ON user_roles FOR EACH ROW EXECUTE FUNCTION reconcile_default_role_insert()"},{"name":"trg_sync_profile_role_del","definition":"CREATE TRIGGER trg_sync_profile_role_del AFTER DELETE ON user_roles FOR EACH ROW EXECUTE FUNCTION sync_profile_role_from_user_roles()"},{"name":"trg_sync_profile_role_ins","definition":"CREATE TRIGGER trg_sync_profile_role_ins AFTER INSERT ON user_roles FOR EACH ROW EXECUTE FUNCTION sync_profile_role_from_user_roles()"},{"name":"trg_sync_profile_role_upd","definition":"CREATE TRIGGER trg_sync_profile_role_upd AFTER UPDATE ON user_roles FOR EACH ROW EXECUTE FUNCTION sync_profile_role_from_user_roles()"},{"name":"trg_sync_role_to_membership","definition":"CREATE TRIGGER trg_sync_role_to_membership AFTER INSERT OR UPDATE OF role, user_id, tenant_id ON user_roles FOR EACH ROW EXECUTE FUNCTION sync_role_to_membership()"},{"name":"zz_security_validate_role_scope_update","definition":"CREATE TRIGGER zz_security_validate_role_scope_update BEFORE INSERT OR UPDATE OF user_id, tenant_id ON user_roles FOR EACH ROW EXECUTE FUNCTION security_validate_role_scope_update()"}],"constraints":[{"name":"user_roles_pkey","definition":"PRIMARY KEY (id)"},{"name":"user_roles_platform_role_scope","definition":"CHECK (tenant_id IS NULL AND role::text = 'GodMode'::text OR tenant_id IS NOT NULL AND role::text <> 'GodMode'::text)"},{"name":"user_roles_user_id_tenant_id_role_key","definition":"UNIQUE (user_id, tenant_id, role)"},{"name":"user_roles_user_tenant_unique","definition":"UNIQUE (user_id, tenant_id)"}]},{"table":"user_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"session_token_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_address","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_agent","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"device_info","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"location_info","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"last_activity_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"ended_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"end_reason","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"current_page","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_page_title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_user_sessions_active","definition":"CREATE INDEX idx_user_sessions_active ON public.user_sessions USING btree (is_active, last_activity_at)"},{"name":"idx_user_sessions_user","definition":"CREATE INDEX idx_user_sessions_user ON public.user_sessions USING btree (user_id, is_active)"},{"name":"idx_user_sessions_user_active","definition":"CREATE INDEX idx_user_sessions_user_active ON public.user_sessions USING btree (user_id, is_active) WHERE (is_active = true)"},{"name":"user_sessions_pkey","definition":"CREATE UNIQUE INDEX user_sessions_pkey ON public.user_sessions USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"((user_id = uid()) OR is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (security_active_user_tenant_memberships target_membership\n     JOIN user_roles admin_role ON (((admin_role.tenant_id = target_membership.tenant_id) AND (admin_role.user_id = uid()) AND ((admin_role.role)::text = ANY (ARRAY['Admin'::text, 'Owner'::text, 'Tenant Owner'::text])))))\n  WHERE ((target_membership.user_id = user_sessions.user_id) AND (target_membership.status = 'active'::text)))))","roles":["authenticated"],"tablename":"user_sessions","permissive":"PERMISSIVE","policyname":"Tenant admins can view scoped sessions","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((uid() = user_id) OR is_system_admin(uid()))","roles":["authenticated"],"tablename":"user_sessions","permissive":"PERMISSIVE","policyname":"Users and admins can view sessions","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_sessions","permissive":"PERMISSIVE","policyname":"Users can insert own sessions","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"UPDATE","qual":"(uid() = user_id)","roles":["authenticated"],"tablename":"user_sessions","permissive":"PERMISSIVE","policyname":"Users can update own sessions","schemaname":"public","with_check":"(uid() = user_id)"}],"triggers":[],"constraints":[{"name":"user_sessions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"user_tenant_memberships","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":false,"generated":""},{"name":"invited_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"joined_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_accessed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"is_owner","type":"boolean","default":"false","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_memberships_status","definition":"CREATE INDEX idx_memberships_status ON public.user_tenant_memberships USING btree (status)"},{"name":"idx_memberships_tenant","definition":"CREATE INDEX idx_memberships_tenant ON public.user_tenant_memberships USING btree (tenant_id)"},{"name":"idx_memberships_user","definition":"CREATE INDEX idx_memberships_user ON public.user_tenant_memberships USING btree (user_id)"},{"name":"idx_user_tenant_memberships_user_tenant","definition":"CREATE INDEX idx_user_tenant_memberships_user_tenant ON public.user_tenant_memberships USING btree (user_id, tenant_id, status)"},{"name":"user_tenant_memberships_pkey","definition":"CREATE UNIQUE INDEX user_tenant_memberships_pkey ON public.user_tenant_memberships USING btree (id)"},{"name":"user_tenant_memberships_user_id_tenant_id_key","definition":"CREATE UNIQUE INDEX user_tenant_memberships_user_id_tenant_id_key ON public.user_tenant_memberships USING btree (user_id, tenant_id)"}],"policies":[{"cmd":"DELETE","qual":"(is_system_admin(uid()) OR is_tenant_owner(uid(), tenant_id) OR (is_admin_or_higher(uid(), tenant_id) AND (COALESCE(is_owner, false) = false)))","roles":["authenticated"],"tablename":"user_tenant_memberships","permissive":"PERMISSIVE","policyname":"Authorized membership managers can delete memberships","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_tenant_memberships","permissive":"PERMISSIVE","policyname":"Authorized membership managers can insert memberships","schemaname":"public","with_check":"(is_system_admin(uid()) OR is_tenant_owner(uid(), tenant_id) OR (is_admin_or_higher(uid(), tenant_id) AND (COALESCE(is_owner, false) = false)))"},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR is_tenant_owner(uid(), tenant_id) OR (is_admin_or_higher(uid(), tenant_id) AND (COALESCE(is_owner, false) = false)))","roles":["authenticated"],"tablename":"user_tenant_memberships","permissive":"PERMISSIVE","policyname":"Authorized membership managers can update memberships","schemaname":"public","with_check":"(is_system_admin(uid()) OR is_tenant_owner(uid(), tenant_id) OR (is_admin_or_higher(uid(), tenant_id) AND (COALESCE(is_owner, false) = false)))"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_tenant_memberships","permissive":"PERMISSIVE","policyname":"Users can request to join tenants","schemaname":"public","with_check":"((user_id = uid()) AND (status = 'pending'::text) AND (COALESCE(is_owner, false) = false) AND (invited_by IS NULL))"},{"cmd":"SELECT","qual":"((user_id = ( SELECT uid() AS uid)) OR ( SELECT is_system_admin(uid()) AS is_system_admin) OR is_admin_or_higher(( SELECT uid() AS uid), tenant_id) OR is_manager_pm_or_higher(( SELECT uid() AS uid), tenant_id))","roles":["public"],"tablename":"user_tenant_memberships","permissive":"PERMISSIVE","policyname":"Visible tenant memberships","schemaname":"public","with_check":null}],"triggers":[{"name":"throttle_membership_access_touch","definition":"CREATE TRIGGER throttle_membership_access_touch BEFORE UPDATE OF last_accessed_at ON user_tenant_memberships FOR EACH ROW EXECUTE FUNCTION throttle_membership_access_touch()"},{"name":"trg_auto_enroll_onboarding","definition":"CREATE TRIGGER trg_auto_enroll_onboarding AFTER INSERT OR UPDATE OF status, tenant_id ON user_tenant_memberships FOR EACH ROW EXECUTE FUNCTION auto_enroll_academy_onboarding()"},{"name":"trg_reconcile_configured_lead_source_routing_on_membership","definition":"CREATE TRIGGER trg_reconcile_configured_lead_source_routing_on_membership AFTER INSERT OR UPDATE OF status ON user_tenant_memberships FOR EACH ROW EXECUTE FUNCTION reconcile_configured_lead_source_routing_on_membership()"},{"name":"trg_sync_membership_to_role","definition":"CREATE TRIGGER trg_sync_membership_to_role AFTER INSERT OR UPDATE OF status, is_owner ON user_tenant_memberships FOR EACH ROW EXECUTE FUNCTION sync_membership_to_role()"},{"name":"zz_security_remove_roles_for_inactive_membership","definition":"CREATE TRIGGER zz_security_remove_roles_for_inactive_membership AFTER DELETE OR UPDATE OF status ON user_tenant_memberships FOR EACH ROW EXECUTE FUNCTION security_remove_roles_for_inactive_membership()"}],"constraints":[{"name":"user_tenant_memberships_pkey","definition":"PRIMARY KEY (id)"},{"name":"user_tenant_memberships_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'pending'::text, 'suspended'::text]))"},{"name":"user_tenant_memberships_user_id_tenant_id_key","definition":"UNIQUE (user_id, tenant_id)"}]},{"table":"user_tenant_tutorial_progress","schema":"public","columns":[{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tutorial_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tutorial_version","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"prompted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completion_kind","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"user_tenant_tutorial_progress_lookup_idx","definition":"CREATE INDEX user_tenant_tutorial_progress_lookup_idx ON public.user_tenant_tutorial_progress USING btree (tenant_id, user_id, tutorial_key)"},{"name":"user_tenant_tutorial_progress_pkey","definition":"CREATE UNIQUE INDEX user_tenant_tutorial_progress_pkey ON public.user_tenant_tutorial_progress USING btree (user_id, tenant_id, tutorial_key, tutorial_version)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_tenant_tutorial_progress","permissive":"PERMISSIVE","policyname":"Users can create their tenant tutorial progress","schemaname":"public","with_check":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = user_tenant_tutorial_progress.tenant_id) AND (membership.status = 'active'::text)))))"},{"cmd":"SELECT","qual":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = user_tenant_tutorial_progress.tenant_id) AND (membership.status = 'active'::text)))))","roles":["authenticated"],"tablename":"user_tenant_tutorial_progress","permissive":"PERMISSIVE","policyname":"Users can read their tenant tutorial progress","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = user_tenant_tutorial_progress.tenant_id) AND (membership.status = 'active'::text)))))","roles":["authenticated"],"tablename":"user_tenant_tutorial_progress","permissive":"PERMISSIVE","policyname":"Users can update their tenant tutorial progress","schemaname":"public","with_check":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = user_tenant_tutorial_progress.tenant_id) AND (membership.status = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"user_tenant_tutorial_progress_completion_kind_check","definition":"CHECK (completion_kind IS NULL OR (completion_kind = ANY (ARRAY['done'::text, 'skipped'::text])))"},{"name":"user_tenant_tutorial_progress_pkey","definition":"PRIMARY KEY (user_id, tenant_id, tutorial_key, tutorial_version)"},{"name":"user_tenant_tutorial_progress_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"user_tenant_tutorial_progress_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"user_tenant_tutorial_state","schema":"public","columns":[{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"completion_kind","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tour_version","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"user_tenant_tutorial_state_pkey","definition":"CREATE UNIQUE INDEX user_tenant_tutorial_state_pkey ON public.user_tenant_tutorial_state USING btree (user_id, tenant_id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"user_tenant_tutorial_state","permissive":"PERMISSIVE","policyname":"Users can create their tenant tutorial state","schemaname":"public","with_check":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = user_tenant_tutorial_state.tenant_id) AND (membership.status = 'active'::text)))))"},{"cmd":"SELECT","qual":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = user_tenant_tutorial_state.tenant_id) AND (membership.status = 'active'::text)))))","roles":["authenticated"],"tablename":"user_tenant_tutorial_state","permissive":"PERMISSIVE","policyname":"Users can read their tenant tutorial state","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = user_tenant_tutorial_state.tenant_id) AND (membership.status = 'active'::text)))))","roles":["authenticated"],"tablename":"user_tenant_tutorial_state","permissive":"PERMISSIVE","policyname":"Users can update their tenant tutorial state","schemaname":"public","with_check":"((uid() = user_id) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = user_tenant_tutorial_state.tenant_id) AND (membership.status = 'active'::text)))))"}],"triggers":[],"constraints":[{"name":"user_tenant_tutorial_state_completion_kind_check","definition":"CHECK (completion_kind = ANY (ARRAY['done'::text, 'skipped'::text]))"},{"name":"user_tenant_tutorial_state_pkey","definition":"PRIMARY KEY (user_id, tenant_id)"},{"name":"user_tenant_tutorial_state_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"},{"name":"user_tenant_tutorial_state_user_id_fkey","definition":"FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"}]},{"table":"vehicle_lockout_requests","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"customer_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"phone","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_location","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"city","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"vehicle_year","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"vehicle_make","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"vehicle_model","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"vehicle_color","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"license_plate","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"keys_location","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'requested'::text","identity":"","not_null":true,"generated":""},{"name":"ownership_confirmed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"authorization_consented","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"authorization_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"authorization_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"proof_storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"proof_filename","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"technician_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"amount_due","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"amount_paid","type":"numeric(12,2)","default":null,"identity":"","not_null":false,"generated":""},{"name":"payment_status","type":"text","default":"'unpaid'::text","identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":"'public_site'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"en_route_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"on_scene_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"canceled_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_evidence_storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"service_evidence_filename","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"authority_verified","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"authority_verification_method","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"authority_verified_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"completion_acknowledged","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"completion_acknowledgement_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"completion_acknowledged_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"identity_document_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"identity_proof_storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"identity_proof_filename","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"identity_deferred","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"authority_basis","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"authority_document_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"authority_proof_storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"authority_proof_filename","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"terms_version","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"authorization_agreement_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"authorization_signed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_vehicle_lockout_requests_authorization_agreement","definition":"CREATE INDEX idx_vehicle_lockout_requests_authorization_agreement ON public.vehicle_lockout_requests USING btree (authorization_agreement_id) WHERE (authorization_agreement_id IS NOT NULL)"},{"name":"vehicle_lockout_requests_pkey","definition":"CREATE UNIQUE INDEX vehicle_lockout_requests_pkey ON public.vehicle_lockout_requests USING btree (id)"},{"name":"vehicle_lockout_requests_tenant_status_created_idx","definition":"CREATE INDEX vehicle_lockout_requests_tenant_status_created_idx ON public.vehicle_lockout_requests USING btree (tenant_id, status, created_at DESC)"}],"policies":[{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = vehicle_lockout_requests.tenant_id) AND (m.status = 'active'::text))))","roles":["authenticated"],"tablename":"vehicle_lockout_requests","permissive":"PERMISSIVE","policyname":"vehicle_lockout_requests_member_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = vehicle_lockout_requests.tenant_id) AND (m.status = 'active'::text))))","roles":["authenticated"],"tablename":"vehicle_lockout_requests","permissive":"PERMISSIVE","policyname":"vehicle_lockout_requests_member_update","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = vehicle_lockout_requests.tenant_id) AND (m.status = 'active'::text))))"},{"cmd":"INSERT","qual":null,"roles":["anon","authenticated"],"tablename":"vehicle_lockout_requests","permissive":"PERMISSIVE","policyname":"vehicle_lockout_requests_public_insert","schemaname":"public","with_check":"((tenant_id = 'd60e3c27-73ed-4a5f-a49b-c37636455daf'::uuid) AND (ownership_confirmed = true) AND (authorization_consented = true) AND (NULLIF(btrim(authorization_name), ''::text) IS NOT NULL) AND (char_length(btrim(authorization_name)) <= 120) AND ((char_length(btrim(customer_name)) >= 1) AND (char_length(btrim(customer_name)) <= 120)) AND ((char_length(btrim(phone)) >= 5) AND (char_length(btrim(phone)) <= 40)) AND ((char_length(regexp_replace(phone, '\\D'::text, ''::text, 'g'::text)) >= 7) AND (char_length(regexp_replace(phone, '\\D'::text, ''::text, 'g'::text)) <= 15)) AND ((email IS NULL) OR (char_length(email) <= 254)) AND ((char_length(btrim(service_location)) >= 3) AND (char_length(btrim(service_location)) <= 500)) AND ((city IS NULL) OR (char_length(city) <= 120)) AND ((vehicle_year IS NULL) OR (char_length(vehicle_year) <= 12)) AND ((char_length(btrim(vehicle_make)) >= 1) AND (char_length(btrim(vehicle_make)) <= 80)) AND ((char_length(btrim(vehicle_model)) >= 1) AND (char_length(btrim(vehicle_model)) <= 80)) AND ((vehicle_color IS NULL) OR (char_length(vehicle_color) <= 80)) AND ((license_plate IS NULL) OR (char_length(license_plate) <= 32)) AND ((keys_location IS NULL) OR (char_length(keys_location) <= 240)) AND ((customer_notes IS NULL) OR (char_length(customer_notes) <= 2000)) AND (status = 'requested'::text) AND (payment_status = 'unpaid'::text) AND (source = 'public_site'::text) AND (amount_due IS NULL) AND (amount_paid IS NULL) AND (technician_notes IS NULL) AND (authority_verified = false) AND (authority_verification_method IS NULL) AND (authority_verified_at IS NULL) AND (service_evidence_storage_path IS NULL) AND (completion_acknowledged = false))"}],"triggers":[{"name":"vehicle_lockout_request_record_guard","definition":"CREATE TRIGGER vehicle_lockout_request_record_guard BEFORE INSERT OR UPDATE ON vehicle_lockout_requests FOR EACH ROW EXECUTE FUNCTION vehicle_lockout_request_record_guard()"},{"name":"vehicle_lockout_sync_customer","definition":"CREATE TRIGGER vehicle_lockout_sync_customer AFTER INSERT OR UPDATE OF status, customer_name, phone, email, service_location, city ON vehicle_lockout_requests FOR EACH ROW EXECUTE FUNCTION vehicle_lockout_sync_customer()"}],"constraints":[{"name":"vehicle_lockout_requests_amount_due_check","definition":"CHECK (amount_due IS NULL OR amount_due >= 0::numeric)"},{"name":"vehicle_lockout_requests_amount_paid_check","definition":"CHECK (amount_paid IS NULL OR amount_paid >= 0::numeric)"},{"name":"vehicle_lockout_requests_authority_verification_check","definition":"CHECK (authority_verified = false OR NULLIF(btrim(authority_verification_method), ''::text) IS NOT NULL AND authority_verified_at IS NOT NULL)"},{"name":"vehicle_lockout_requests_authorization_agreement_id_fkey","definition":"FOREIGN KEY (authorization_agreement_id) REFERENCES pending_agreements(id) ON DELETE SET NULL"},{"name":"vehicle_lockout_requests_completed_record_check","definition":"CHECK (status <> 'completed'::text OR authority_verified = true AND NULLIF(btrim(authority_verification_method), ''::text) IS NOT NULL AND authority_verified_at IS NOT NULL AND completion_acknowledged = true AND NULLIF(btrim(completion_acknowledgement_name), ''::text) IS NOT NULL AND completion_acknowledged_at IS NOT NULL)"},{"name":"vehicle_lockout_requests_completion_ack_check","definition":"CHECK (completion_acknowledged = false OR NULLIF(btrim(completion_acknowledgement_name), ''::text) IS NOT NULL AND completion_acknowledged_at IS NOT NULL)"},{"name":"vehicle_lockout_requests_payment_status_check","definition":"CHECK (payment_status = ANY (ARRAY['unpaid'::text, 'partial'::text, 'paid'::text]))"},{"name":"vehicle_lockout_requests_pkey","definition":"PRIMARY KEY (id)"},{"name":"vehicle_lockout_requests_status_check","definition":"CHECK (status = ANY (ARRAY['awaiting_signature'::text, 'agreement_prepared'::text, 'requested'::text, 'en_route'::text, 'on_scene'::text, 'completed'::text, 'canceled'::text]))"},{"name":"vehicle_lockout_requests_tenant_id_fkey","definition":"FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE"}]},{"table":"vertical_template_packs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"pack_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"version","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'draft'::text","identity":"","not_null":true,"generated":""},{"name":"config_json","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_vertical_template_packs_config_gin","definition":"CREATE INDEX idx_vertical_template_packs_config_gin ON public.vertical_template_packs USING gin (config_json)"},{"name":"idx_vertical_template_packs_status","definition":"CREATE INDEX idx_vertical_template_packs_status ON public.vertical_template_packs USING btree (status)"},{"name":"idx_vertical_template_packs_tenant_type","definition":"CREATE INDEX idx_vertical_template_packs_tenant_type ON public.vertical_template_packs USING btree (tenant_type)"},{"name":"vertical_template_packs_pkey","definition":"CREATE UNIQUE INDEX vertical_template_packs_pkey ON public.vertical_template_packs USING btree (id)"},{"name":"vertical_template_packs_tenant_type_pack_key_version_key","definition":"CREATE UNIQUE INDEX vertical_template_packs_tenant_type_pack_key_version_key ON public.vertical_template_packs USING btree (tenant_type, pack_key, version)"}],"policies":[],"triggers":[],"constraints":[{"name":"vertical_template_packs_pkey","definition":"PRIMARY KEY (id)"},{"name":"vertical_template_packs_status_check","definition":"CHECK (status = ANY (ARRAY['draft'::text, 'active'::text, 'deprecated'::text, 'archived'::text]))"},{"name":"vertical_template_packs_tenant_type_pack_key_version_key","definition":"UNIQUE (tenant_type, pack_key, version)"}]},{"table":"voice_notes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"audio_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"transcription","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"transcription_status","type":"text","default":"'pending'::text","identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_voice_notes_contact_id","definition":"CREATE INDEX idx_voice_notes_contact_id ON public.voice_notes USING btree (contact_id)"},{"name":"idx_voice_notes_tenant_id","definition":"CREATE INDEX idx_voice_notes_tenant_id ON public.voice_notes USING btree (tenant_id)"},{"name":"idx_voice_notes_user_id","definition":"CREATE INDEX idx_voice_notes_user_id ON public.voice_notes USING btree (user_id)"},{"name":"voice_notes_pkey","definition":"CREATE UNIQUE INDEX voice_notes_pkey ON public.voice_notes USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"voice_notes","permissive":"PERMISSIVE","policyname":"Users create voice notes","schemaname":"public","with_check":"(uid() = user_id)"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = voice_notes.tenant_id))))","roles":["public"],"tablename":"voice_notes","permissive":"PERMISSIVE","policyname":"Users view tenant voice notes","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"voice_notes_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"voicemail_audio_cache","schema":"public","columns":[{"name":"cache_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"voice_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rendered_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"audio_storage_path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"audio_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_sec","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"character_count","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"use_count","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"last_used_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_voicemail_audio_cache_last_used","definition":"CREATE INDEX idx_voicemail_audio_cache_last_used ON public.voicemail_audio_cache USING btree (last_used_at)"},{"name":"idx_voicemail_audio_cache_rep","definition":"CREATE INDEX idx_voicemail_audio_cache_rep ON public.voicemail_audio_cache USING btree (rep_id)"},{"name":"idx_voicemail_audio_cache_tenant","definition":"CREATE INDEX idx_voicemail_audio_cache_tenant ON public.voicemail_audio_cache USING btree (tenant_org_id)"},{"name":"voicemail_audio_cache_pkey","definition":"CREATE UNIQUE INDEX voicemail_audio_cache_pkey ON public.voicemail_audio_cache USING btree (cache_key)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"voicemail_audio_cache","permissive":"PERMISSIVE","policyname":"tenant_members_read_voicemail_audio_cache","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"voicemail_audio_cache_pkey","definition":"PRIMARY KEY (cache_key)"}]},{"table":"voicemail_boxes","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"ring_group_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"routing_profile_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"greeting_mode","type":"text","default":"'tts'::text","identity":"","not_null":true,"generated":""},{"name":"greeting_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"greeting_audio_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"max_seconds","type":"integer","default":"120","identity":"","not_null":true,"generated":""},{"name":"transcribe","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"ai_analyze","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"notify_user_ids","type":"uuid[]","default":"'{}'::uuid[]","identity":"","not_null":true,"generated":""},{"name":"notify_emails","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_vm_boxes_profile","definition":"CREATE INDEX idx_vm_boxes_profile ON public.voicemail_boxes USING btree (routing_profile_id) WHERE (routing_profile_id IS NOT NULL)"},{"name":"idx_vm_boxes_ring_group","definition":"CREATE INDEX idx_vm_boxes_ring_group ON public.voicemail_boxes USING btree (ring_group_id) WHERE (ring_group_id IS NOT NULL)"},{"name":"idx_vm_boxes_tenant","definition":"CREATE INDEX idx_vm_boxes_tenant ON public.voicemail_boxes USING btree (tenant_org_id)"},{"name":"idx_vm_boxes_user","definition":"CREATE INDEX idx_vm_boxes_user ON public.voicemail_boxes USING btree (user_id) WHERE (user_id IS NOT NULL)"},{"name":"voicemail_boxes_pkey","definition":"CREATE UNIQUE INDEX voicemail_boxes_pkey ON public.voicemail_boxes USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(is_tenant_member(tenant_org_id) AND is_manager_or_higher(uid(), (tenant_org_id)::uuid))","roles":["authenticated"],"tablename":"voicemail_boxes","permissive":"PERMISSIVE","policyname":"managers_write_vm_boxes","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) AND is_manager_or_higher(uid(), (tenant_org_id)::uuid))"},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"voicemail_boxes","permissive":"PERMISSIVE","policyname":"tenant_members_read_vm_boxes","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_vm_boxes_updated","definition":"CREATE TRIGGER trg_vm_boxes_updated BEFORE UPDATE ON voicemail_boxes FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"vm_box_owner_check","definition":"CHECK (((ring_group_id IS NOT NULL)::integer + (routing_profile_id IS NOT NULL)::integer + (user_id IS NOT NULL)::integer) = 1)"},{"name":"voicemail_boxes_greeting_mode_check","definition":"CHECK (greeting_mode = ANY (ARRAY['tts'::text, 'audio'::text]))"},{"name":"voicemail_boxes_max_seconds_check","definition":"CHECK (max_seconds >= 15 AND max_seconds <= 600)"},{"name":"voicemail_boxes_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"voicemail_drop_attempts","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"call_mode","type":"text","default":"'unknown'::text","identity":"","not_null":true,"generated":""},{"name":"trigger","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"slot_requested","type":"smallint","default":null,"identity":"","not_null":false,"generated":""},{"name":"slot_played","type":"smallint","default":null,"identity":"","not_null":false,"generated":""},{"name":"amd_result","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"silence_watchdog_fired","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"inject_success","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"inject_error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"drop_requested_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"timing_mode","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rep_leg_released","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"source_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"playback_started_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"playback_completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"twilio_update_status","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"pending_drop_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"slot_selection_mode","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"slot_resolved","type":"smallint","default":null,"identity":"","not_null":false,"generated":""},{"name":"attempt_basis","type":"integer","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_vm_drop_attempts_lead","definition":"CREATE INDEX idx_vm_drop_attempts_lead ON public.voicemail_drop_attempts USING btree (lead_id)"},{"name":"idx_vm_drop_attempts_session","definition":"CREATE INDEX idx_vm_drop_attempts_session ON public.voicemail_drop_attempts USING btree (session_id)"},{"name":"idx_vm_drop_attempts_tenant_created","definition":"CREATE INDEX idx_vm_drop_attempts_tenant_created ON public.voicemail_drop_attempts USING btree (tenant_org_id, created_at DESC)"},{"name":"voicemail_drop_attempts_pkey","definition":"CREATE UNIQUE INDEX voicemail_drop_attempts_pkey ON public.voicemail_drop_attempts USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"voicemail_drop_attempts","permissive":"PERMISSIVE","policyname":"vm_drop_attempts_select_tenant_members","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"voicemail_drop_attempts_call_mode_check","definition":"CHECK (call_mode = ANY (ARRAY['browser'::text, 'cell_bridge'::text, 'external_native'::text, 'unknown'::text]))"},{"name":"voicemail_drop_attempts_pkey","definition":"PRIMARY KEY (id)"},{"name":"voicemail_drop_attempts_trigger_check","definition":"CHECK (trigger = ANY (ARRAY['auto_amd'::text, 'manual_browser'::text, 'silence_watchdog'::text, 'dtmf'::text, 'mobile_link'::text, 'fallback_delay'::text, 'unknown'::text]))"}]},{"table":"voicemail_drop_history","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"phone_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"preset_slot","type":"smallint","default":null,"identity":"","not_null":false,"generated":""},{"name":"voicemail_template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"dropped_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"month_bucket","type":"text","default":"to_char((now() AT TIME ZONE 'UTC'::text), 'YYYY-MM'::text)","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_vm_drop_hist_rep_contact_month","definition":"CREATE INDEX idx_vm_drop_hist_rep_contact_month ON public.voicemail_drop_history USING btree (rep_id, phone_number, month_bucket)"},{"name":"idx_vm_drop_hist_tenant","definition":"CREATE INDEX idx_vm_drop_hist_tenant ON public.voicemail_drop_history USING btree (tenant_org_id, dropped_at DESC)"},{"name":"voicemail_drop_history_pkey","definition":"CREATE UNIQUE INDEX voicemail_drop_history_pkey ON public.voicemail_drop_history USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"voicemail_drop_history","permissive":"PERMISSIVE","policyname":"vm_drop_hist_insert_service","schemaname":"public","with_check":"((rep_id = uid()) AND is_tenant_member(tenant_org_id))"},{"cmd":"SELECT","qual":"((rep_id = uid()) OR is_tenant_member(tenant_org_id))","roles":["authenticated"],"tablename":"voicemail_drop_history","permissive":"PERMISSIVE","policyname":"vm_drop_hist_select_own","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_vm_drop_month_bucket","definition":"CREATE TRIGGER trg_vm_drop_month_bucket BEFORE INSERT OR UPDATE OF dropped_at ON voicemail_drop_history FOR EACH ROW EXECUTE FUNCTION set_vm_drop_month_bucket()"}],"constraints":[{"name":"voicemail_drop_history_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"voicemail_dtmf_tokens","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"active_call_session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"rep_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"token_hash","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"expires_at","type":"timestamp with time zone","default":null,"identity":"","not_null":true,"generated":""},{"name":"consumed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"consumed_slot","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_vm_dtmf_tokens_expires","definition":"CREATE INDEX idx_vm_dtmf_tokens_expires ON public.voicemail_dtmf_tokens USING btree (expires_at)"},{"name":"idx_vm_dtmf_tokens_rep","definition":"CREATE INDEX idx_vm_dtmf_tokens_rep ON public.voicemail_dtmf_tokens USING btree (rep_user_id)"},{"name":"idx_vm_dtmf_tokens_session","definition":"CREATE INDEX idx_vm_dtmf_tokens_session ON public.voicemail_dtmf_tokens USING btree (active_call_session_id)"},{"name":"voicemail_dtmf_tokens_pkey","definition":"CREATE UNIQUE INDEX voicemail_dtmf_tokens_pkey ON public.voicemail_dtmf_tokens USING btree (id)"},{"name":"voicemail_dtmf_tokens_token_hash_key","definition":"CREATE UNIQUE INDEX voicemail_dtmf_tokens_token_hash_key ON public.voicemail_dtmf_tokens USING btree (token_hash)"}],"policies":[{"cmd":"SELECT","qual":"(rep_user_id = uid())","roles":["authenticated"],"tablename":"voicemail_dtmf_tokens","permissive":"PERMISSIVE","policyname":"rep_read_own_dtmf_tokens","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_voicemail_dtmf_tokens_validate","definition":"CREATE TRIGGER trg_voicemail_dtmf_tokens_validate BEFORE INSERT ON voicemail_dtmf_tokens FOR EACH ROW EXECUTE FUNCTION voicemail_dtmf_tokens_validate()"}],"constraints":[{"name":"voicemail_dtmf_tokens_pkey","definition":"PRIMARY KEY (id)"},{"name":"voicemail_dtmf_tokens_token_hash_key","definition":"UNIQUE (token_hash)"}]},{"table":"voicemail_messages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"voicemail_box_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"ring_group_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"routing_profile_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"caller_number","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"to_number","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_sid","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recording_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_seconds","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"transcript_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"transcript_status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"ai_summary","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ai_sentiment","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ai_topics","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"ai_callback_requested","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"ai_priority","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_read","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"read_by_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"read_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_vm_msgs_box","definition":"CREATE INDEX idx_vm_msgs_box ON public.voicemail_messages USING btree (voicemail_box_id, created_at DESC)"},{"name":"idx_vm_msgs_caller","definition":"CREATE INDEX idx_vm_msgs_caller ON public.voicemail_messages USING btree (caller_number)"},{"name":"idx_vm_msgs_tenant_unread","definition":"CREATE INDEX idx_vm_msgs_tenant_unread ON public.voicemail_messages USING btree (tenant_org_id, is_read, created_at DESC)"},{"name":"voicemail_messages_pkey","definition":"CREATE UNIQUE INDEX voicemail_messages_pkey ON public.voicemail_messages USING btree (id)"},{"name":"voicemail_messages_recording_sid_key","definition":"CREATE UNIQUE INDEX voicemail_messages_recording_sid_key ON public.voicemail_messages USING btree (recording_sid)"}],"policies":[{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) AND is_manager_or_higher(uid(), (tenant_org_id)::uuid))","roles":["authenticated"],"tablename":"voicemail_messages","permissive":"PERMISSIVE","policyname":"managers_delete_vm_msgs","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"voicemail_messages","permissive":"PERMISSIVE","policyname":"tenant_members_read_vm_msgs","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"voicemail_messages","permissive":"PERMISSIVE","policyname":"tenant_members_update_vm_msgs","schemaname":"public","with_check":"is_tenant_member(tenant_org_id)"}],"triggers":[],"constraints":[{"name":"voicemail_messages_ai_priority_check","definition":"CHECK ((ai_priority = ANY (ARRAY['low'::text, 'normal'::text, 'high'::text, 'urgent'::text])) OR ai_priority IS NULL)"},{"name":"voicemail_messages_ai_sentiment_check","definition":"CHECK ((ai_sentiment = ANY (ARRAY['positive'::text, 'neutral'::text, 'negative'::text, 'urgent'::text])) OR ai_sentiment IS NULL)"},{"name":"voicemail_messages_pkey","definition":"PRIMARY KEY (id)"},{"name":"voicemail_messages_recording_sid_key","definition":"UNIQUE (recording_sid)"},{"name":"voicemail_messages_transcript_status_check","definition":"CHECK (transcript_status = ANY (ARRAY['pending'::text, 'processing'::text, 'complete'::text, 'failed'::text, 'skipped'::text]))"}]},{"table":"voicemail_preset_slot_config","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"slot","type":"smallint","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":"'First Touch'::text","identity":"","not_null":true,"generated":""},{"name":"rep_guidance","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"script_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"target_seconds","type":"smallint","default":"8","identity":"","not_null":true,"generated":""},{"name":"updated_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_vmpsc_tenant","definition":"CREATE INDEX idx_vmpsc_tenant ON public.voicemail_preset_slot_config USING btree (tenant_org_id, slot)"},{"name":"voicemail_preset_slot_config_pkey","definition":"CREATE UNIQUE INDEX voicemail_preset_slot_config_pkey ON public.voicemail_preset_slot_config USING btree (id)"},{"name":"voicemail_preset_slot_config_tenant_org_id_slot_key","definition":"CREATE UNIQUE INDEX voicemail_preset_slot_config_tenant_org_id_slot_key ON public.voicemail_preset_slot_config USING btree (tenant_org_id, slot)"}],"policies":[{"cmd":"DELETE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (security_active_user_tenant_memberships m\n     JOIN user_roles ur ON (((ur.user_id = m.user_id) AND (ur.tenant_id = m.tenant_id))))\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = voicemail_preset_slot_config.tenant_org_id) AND (m.status = 'active'::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'Manager'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"voicemail_preset_slot_config","permissive":"PERMISSIVE","policyname":"vmpsc_delete_owner","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"voicemail_preset_slot_config","permissive":"PERMISSIVE","policyname":"vmpsc_insert_owner","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (security_active_user_tenant_memberships m\n     JOIN user_roles ur ON (((ur.user_id = m.user_id) AND (ur.tenant_id = m.tenant_id))))\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = voicemail_preset_slot_config.tenant_org_id) AND (m.status = 'active'::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'Manager'::app_role, 'GodMode'::app_role]))))))"},{"cmd":"SELECT","qual":"is_tenant_member(tenant_org_id)","roles":["authenticated"],"tablename":"voicemail_preset_slot_config","permissive":"PERMISSIVE","policyname":"vmpsc_select_member","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (security_active_user_tenant_memberships m\n     JOIN user_roles ur ON (((ur.user_id = m.user_id) AND (ur.tenant_id = m.tenant_id))))\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = voicemail_preset_slot_config.tenant_org_id) AND (m.status = 'active'::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'Manager'::app_role, 'GodMode'::app_role]))))))","roles":["authenticated"],"tablename":"voicemail_preset_slot_config","permissive":"PERMISSIVE","policyname":"vmpsc_update_owner","schemaname":"public","with_check":"(is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (security_active_user_tenant_memberships m\n     JOIN user_roles ur ON (((ur.user_id = m.user_id) AND (ur.tenant_id = m.tenant_id))))\n  WHERE ((m.user_id = uid()) AND ((m.tenant_id)::text = voicemail_preset_slot_config.tenant_org_id) AND (m.status = 'active'::text) AND (ur.role = ANY (ARRAY['Owner'::app_role, 'Tenant Owner'::app_role, 'Admin'::app_role, 'Manager'::app_role, 'GodMode'::app_role]))))))"}],"triggers":[{"name":"trg_touch_vmpsc_updated_at","definition":"CREATE TRIGGER trg_touch_vmpsc_updated_at BEFORE UPDATE ON voicemail_preset_slot_config FOR EACH ROW EXECUTE FUNCTION touch_vmpsc_updated_at()"}],"constraints":[{"name":"voicemail_preset_slot_config_pkey","definition":"PRIMARY KEY (id)"},{"name":"voicemail_preset_slot_config_slot_check","definition":"CHECK (slot >= 1 AND slot <= 4)"},{"name":"voicemail_preset_slot_config_tenant_org_id_slot_key","definition":"UNIQUE (tenant_org_id, slot)"}]},{"table":"voicemail_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"audio_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"audio_storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"audio_duration_sec","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"transcript","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_campaign_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_rep_ids","type":"uuid[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"script_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"external_template_code","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"recommended_for_dropdown","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"owner_user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"direction","type":"text","default":"'outbound'::text","identity":"","not_null":true,"generated":""},{"name":"scope","type":"text","default":"'tenant'::text","identity":"","not_null":true,"generated":""},{"name":"preset_slot","type":"smallint","default":null,"identity":"","not_null":false,"generated":""},{"name":"delivery_mode","type":"text","default":"'cloned_tts'::text","identity":"","not_null":true,"generated":""},{"name":"intro_audio_storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"intro_audio_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"outro_audio_storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"outro_audio_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"dynamic_slot_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"prosody_profile","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"voice_settings_override","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"intro_transcript","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"outro_transcript","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"intro_content_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"outro_content_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"intro_duration_sec","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"outro_duration_sec","type":"numeric","default":null,"identity":"","not_null":false,"generated":""},{"name":"audio_twilio_compatible","type":"boolean","default":"\nCASE\n    WHEN (delivery_mode = 'hybrid_splice'::text) THEN ((intro_audio_storage_path IS NOT NULL) AND (outro_audio_storage_path IS NOT NULL) AND (intro_audio_storage_path ~* '\\.(mp3|wav|wave|aiff|aif|gsm|ulaw)$'::text) AND (outro_audio_storage_path ~* '\\.(mp3|wav|wave|aiff|aif|gsm|ulaw)$'::text))\n    WHEN (delivery_mode = 'static_audio'::text) THEN ((audio_storage_path IS NOT NULL) AND (audio_storage_path ~* '\\.(mp3|wav|wave|aiff|aif|gsm|ulaw)$'::text))\n    ELSE false\nEND","identity":"","not_null":false,"generated":"s"},{"name":"legacy_intro_audio_storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"legacy_outro_audio_storage_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"legacy_intro_audio_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"legacy_outro_audio_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"legacy_intro_content_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"legacy_outro_content_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"repaired_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_vm_templates_owner_slot_compat","definition":"CREATE INDEX idx_vm_templates_owner_slot_compat ON public.voicemail_templates USING btree (owner_user_id, preset_slot) WHERE ((scope = 'personal'::text) AND (is_active = true))"},{"name":"idx_vmt_owner","definition":"CREATE INDEX idx_vmt_owner ON public.voicemail_templates USING btree (owner_user_id) WHERE (owner_user_id IS NOT NULL)"},{"name":"idx_vmt_tenant","definition":"CREATE INDEX idx_vmt_tenant ON public.voicemail_templates USING btree (tenant_org_id) WHERE (is_active = true)"},{"name":"idx_vmt_tenant_direction","definition":"CREATE INDEX idx_vmt_tenant_direction ON public.voicemail_templates USING btree (tenant_org_id, direction) WHERE (is_active = true)"},{"name":"uq_vmt_tenant_external_code","definition":"CREATE UNIQUE INDEX uq_vmt_tenant_external_code ON public.voicemail_templates USING btree (tenant_org_id, external_template_code) WHERE (external_template_code IS NOT NULL)"},{"name":"uq_voicemail_owner_preset_slot","definition":"CREATE UNIQUE INDEX uq_voicemail_owner_preset_slot ON public.voicemail_templates USING btree (owner_user_id, preset_slot) WHERE (preset_slot IS NOT NULL)"},{"name":"voicemail_templates_pkey","definition":"CREATE UNIQUE INDEX voicemail_templates_pkey ON public.voicemail_templates USING btree (id)"}],"policies":[{"cmd":"DELETE","qual":"((is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())","roles":["public"],"tablename":"voicemail_templates","permissive":"PERMISSIVE","policyname":"vmt_admin_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"voicemail_templates","permissive":"PERMISSIVE","policyname":"vmt_admin_insert","schemaname":"public","with_check":"((is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())"},{"cmd":"UPDATE","qual":"((is_tenant_member(tenant_org_id) AND is_admin_or_higher(uid(), (tenant_org_id)::uuid)) OR is_system_admin())","roles":["public"],"tablename":"voicemail_templates","permissive":"PERMISSIVE","policyname":"vmt_admin_update","schemaname":"public","with_check":null},{"cmd":"DELETE","qual":"(is_tenant_member(tenant_org_id) AND (scope = 'personal'::text) AND (owner_user_id = uid()))","roles":["public"],"tablename":"voicemail_templates","permissive":"PERMISSIVE","policyname":"vmt_personal_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"voicemail_templates","permissive":"PERMISSIVE","policyname":"vmt_personal_insert","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) AND (scope = 'personal'::text) AND (owner_user_id = uid()))"},{"cmd":"UPDATE","qual":"(is_tenant_member(tenant_org_id) AND (scope = 'personal'::text) AND (owner_user_id = uid()))","roles":["public"],"tablename":"voicemail_templates","permissive":"PERMISSIVE","policyname":"vmt_personal_update","schemaname":"public","with_check":"(is_tenant_member(tenant_org_id) AND (scope = 'personal'::text) AND (owner_user_id = uid()))"},{"cmd":"SELECT","qual":"(is_system_admin() OR (is_tenant_member(tenant_org_id) AND ((scope = 'tenant'::text) OR (owner_user_id = uid()) OR is_admin_or_higher(uid(), (tenant_org_id)::uuid))))","roles":["public"],"tablename":"voicemail_templates","permissive":"PERMISSIVE","policyname":"vmt_select_visible","schemaname":"public","with_check":null}],"triggers":[{"name":"trg_validate_voicemail_preset_slot","definition":"CREATE TRIGGER trg_validate_voicemail_preset_slot BEFORE INSERT OR UPDATE ON voicemail_templates FOR EACH ROW EXECUTE FUNCTION validate_voicemail_preset_slot()"},{"name":"trg_vmt_updated_at","definition":"CREATE TRIGGER trg_vmt_updated_at BEFORE UPDATE ON voicemail_templates FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"voicemail_templates_delivery_mode_check","definition":"CHECK (delivery_mode = ANY (ARRAY['cloned_tts'::text, 'static_audio'::text, 'hybrid_splice'::text]))"},{"name":"voicemail_templates_direction_chk","definition":"CHECK (direction = ANY (ARRAY['outbound'::text, 'inbound_greeting'::text]))"},{"name":"voicemail_templates_owner_scope_chk","definition":"CHECK (scope = 'personal'::text AND owner_user_id IS NOT NULL OR scope = 'tenant'::text)"},{"name":"voicemail_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"voicemail_templates_scope_chk","definition":"CHECK (scope = ANY (ARRAY['tenant'::text, 'personal'::text]))"}]},{"table":"website_lead_submissions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_system","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"source_submission_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"integration_key_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'received'::text","identity":"","not_null":true,"generated":""},{"name":"duplicate_of","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"missing_information","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"priority","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ready_for_booking","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"callback_needed","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"raw_payload","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"error","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"request_ip","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_website_lead_submissions_contact","definition":"CREATE INDEX idx_website_lead_submissions_contact ON public.website_lead_submissions USING btree (contact_id)"},{"name":"idx_website_lead_submissions_tenant_created","definition":"CREATE INDEX idx_website_lead_submissions_tenant_created ON public.website_lead_submissions USING btree (tenant_org_id, created_at DESC)"},{"name":"uq_website_lead_submission_idem","definition":"CREATE UNIQUE INDEX uq_website_lead_submission_idem ON public.website_lead_submissions USING btree (tenant_org_id, source_system, source_submission_id)"},{"name":"website_lead_submissions_pkey","definition":"CREATE UNIQUE INDEX website_lead_submissions_pkey ON public.website_lead_submissions USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(is_system_admin() OR is_tenant_member(tenant_org_id))","roles":["authenticated"],"tablename":"website_lead_submissions","permissive":"PERMISSIVE","policyname":"Tenant members can view website lead submissions","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"website_lead_submissions_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"weekly_call_report_runs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_start","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"period_end","type":"date","default":null,"identity":"","not_null":true,"generated":""},{"name":"reps_included","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"total_calls","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"appointments_booked","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"emails_sent","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"emails_failed","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"storage_paths","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"status","type":"text","default":"'pending'::text","identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_weekly_report_runs_tenant_period","definition":"CREATE INDEX idx_weekly_report_runs_tenant_period ON public.weekly_call_report_runs USING btree (tenant_org_id, period_end DESC)"},{"name":"weekly_call_report_runs_pkey","definition":"CREATE UNIQUE INDEX weekly_call_report_runs_pkey ON public.weekly_call_report_runs USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_owner(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"weekly_call_report_runs","permissive":"PERMISSIVE","policyname":"Tenant owners view weekly report runs","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"weekly_call_report_runs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"weekly_call_report_settings","schema":"public","columns":[{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"owner_email","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"send_day_of_week","type":"integer","default":"6","identity":"","not_null":true,"generated":""},{"name":"send_hour_local","type":"integer","default":"8","identity":"","not_null":true,"generated":""},{"name":"timezone","type":"text","default":"'America/New_York'::text","identity":"","not_null":true,"generated":""},{"name":"include_rep_emails","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"include_owner_combined","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"last_sent_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"weekly_call_report_settings_pkey","definition":"CREATE UNIQUE INDEX weekly_call_report_settings_pkey ON public.weekly_call_report_settings USING btree (tenant_org_id)"}],"policies":[{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"weekly_call_report_settings","permissive":"PERMISSIVE","policyname":"Tenant members view weekly report settings","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_tenant_owner(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"weekly_call_report_settings","permissive":"PERMISSIVE","policyname":"Tenant owners manage weekly report settings","schemaname":"public","with_check":"is_tenant_owner(uid(), tenant_org_id)"}],"triggers":[{"name":"trg_weekly_call_report_settings_updated_at","definition":"CREATE TRIGGER trg_weekly_call_report_settings_updated_at BEFORE UPDATE ON weekly_call_report_settings FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"weekly_call_report_settings_pkey","definition":"PRIMARY KEY (tenant_org_id)"}]},{"table":"wmp_connections","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"owner_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"provider","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"model","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"connection_ref","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"endpoint_url","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"enabled","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'prerequisite_required'::text","identity":"","not_null":true,"generated":""},{"name":"capabilities","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"wmp_connections_owner_idx","definition":"CREATE INDEX wmp_connections_owner_idx ON public.wmp_connections USING btree (owner_user_id, updated_at DESC)"},{"name":"wmp_connections_pkey","definition":"CREATE UNIQUE INDEX wmp_connections_pkey ON public.wmp_connections USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(owner_user_id = uid())","roles":["authenticated"],"tablename":"wmp_connections","permissive":"PERMISSIVE","policyname":"wmp_connections_owner_all","schemaname":"public","with_check":"(owner_user_id = uid())"}],"triggers":[],"constraints":[{"name":"wmp_connections_label_check","definition":"CHECK (char_length(label) >= 1 AND char_length(label) <= 120)"},{"name":"wmp_connections_pkey","definition":"PRIMARY KEY (id)"},{"name":"wmp_connections_provider_check","definition":"CHECK (provider = ANY (ARRAY['openai'::text, 'codex'::text, 'anthropic'::text, 'gemini'::text, 'webhook'::text]))"},{"name":"wmp_connections_status_check","definition":"CHECK (status = ANY (ARRAY['ready'::text, 'prerequisite_required'::text, 'disabled'::text, 'error'::text]))"}]},{"table":"wmp_mission_metadata","schema":"public","columns":[{"name":"mission_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"owner_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"title","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"pipeline_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"provider_connection_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"pipeline_stage","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tags","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"wmp_mission_metadata_owner_idx","definition":"CREATE INDEX wmp_mission_metadata_owner_idx ON public.wmp_mission_metadata USING btree (owner_user_id, updated_at DESC)"},{"name":"wmp_mission_metadata_pkey","definition":"CREATE UNIQUE INDEX wmp_mission_metadata_pkey ON public.wmp_mission_metadata USING btree (mission_id)"}],"policies":[{"cmd":"ALL","qual":"(owner_user_id = uid())","roles":["authenticated"],"tablename":"wmp_mission_metadata","permissive":"PERMISSIVE","policyname":"wmp_mission_metadata_owner_all","schemaname":"public","with_check":"(owner_user_id = uid())"}],"triggers":[],"constraints":[{"name":"wmp_mission_metadata_mission_id_fkey","definition":"FOREIGN KEY (mission_id) REFERENCES command_center_events(id) ON DELETE CASCADE"},{"name":"wmp_mission_metadata_pipeline_id_fkey","definition":"FOREIGN KEY (pipeline_id) REFERENCES wmp_pipelines(id) ON DELETE SET NULL"},{"name":"wmp_mission_metadata_pkey","definition":"PRIMARY KEY (mission_id)"},{"name":"wmp_mission_metadata_provider_connection_id_fkey","definition":"FOREIGN KEY (provider_connection_id) REFERENCES wmp_connections(id) ON DELETE SET NULL"}]},{"table":"wmp_pipelines","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"owner_user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"slug","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"is_default","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"stages","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"wmp_pipelines_owner_idx","definition":"CREATE INDEX wmp_pipelines_owner_idx ON public.wmp_pipelines USING btree (owner_user_id, updated_at DESC)"},{"name":"wmp_pipelines_owner_user_id_slug_key","definition":"CREATE UNIQUE INDEX wmp_pipelines_owner_user_id_slug_key ON public.wmp_pipelines USING btree (owner_user_id, slug)"},{"name":"wmp_pipelines_pkey","definition":"CREATE UNIQUE INDEX wmp_pipelines_pkey ON public.wmp_pipelines USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(owner_user_id = uid())","roles":["authenticated"],"tablename":"wmp_pipelines","permissive":"PERMISSIVE","policyname":"wmp_pipelines_owner_all","schemaname":"public","with_check":"(owner_user_id = uid())"}],"triggers":[],"constraints":[{"name":"wmp_pipelines_name_check","definition":"CHECK (char_length(name) >= 1 AND char_length(name) <= 120)"},{"name":"wmp_pipelines_owner_user_id_slug_key","definition":"UNIQUE (owner_user_id, slug)"},{"name":"wmp_pipelines_pkey","definition":"PRIMARY KEY (id)"},{"name":"wmp_pipelines_slug_check","definition":"CHECK (char_length(slug) >= 1 AND char_length(slug) <= 120)"}]},{"table":"workflow_analytics","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"step_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"card_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"exit_path","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"duration_ms","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"session_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_workflow_analytics_created","definition":"CREATE INDEX idx_workflow_analytics_created ON public.workflow_analytics USING btree (created_at DESC)"},{"name":"idx_workflow_analytics_step","definition":"CREATE INDEX idx_workflow_analytics_step ON public.workflow_analytics USING btree (step_id)"},{"name":"idx_workflow_analytics_tenant","definition":"CREATE INDEX idx_workflow_analytics_tenant ON public.workflow_analytics USING btree (tenant_id)"},{"name":"idx_workflow_analytics_user","definition":"CREATE INDEX idx_workflow_analytics_user ON public.workflow_analytics USING btree (user_id)"},{"name":"workflow_analytics_pkey","definition":"CREATE UNIQUE INDEX workflow_analytics_pkey ON public.workflow_analytics USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"workflow_analytics","permissive":"PERMISSIVE","policyname":"tenant_members_insert_analytics","schemaname":"public","with_check":"is_tenant_member((tenant_id)::text)"},{"cmd":"SELECT","qual":"is_tenant_member((tenant_id)::text)","roles":["authenticated"],"tablename":"workflow_analytics","permissive":"PERMISSIVE","policyname":"tenant_members_view_analytics","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"workflow_analytics_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"workflow_automation_triggers","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"trigger_event","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"from_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"to_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"action_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"action_config","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"conditions","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":false,"generated":""},{"name":"priority","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"execution_count","type":"integer","default":"0","identity":"","not_null":false,"generated":""},{"name":"last_executed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_wat_event","definition":"CREATE INDEX idx_wat_event ON public.workflow_automation_triggers USING btree (trigger_event, is_active)"},{"name":"idx_wat_tenant","definition":"CREATE INDEX idx_wat_tenant ON public.workflow_automation_triggers USING btree (tenant_org_id)"},{"name":"workflow_automation_triggers_pkey","definition":"CREATE UNIQUE INDEX workflow_automation_triggers_pkey ON public.workflow_automation_triggers USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = workflow_automation_triggers.tenant_org_id))))","roles":["authenticated"],"tablename":"workflow_automation_triggers","permissive":"PERMISSIVE","policyname":"Tenant members can manage automation triggers","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = workflow_automation_triggers.tenant_org_id))))"}],"triggers":[],"constraints":[{"name":"workflow_automation_triggers_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"workflow_dialogue_stages","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"workflow_id","type":"text","default":"'default'::text","identity":"","not_null":true,"generated":""},{"name":"stage_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage_order","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"script_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"prompts","type":"text[]","default":"'{}'::text[]","identity":"","not_null":false,"generated":""},{"name":"next_stage_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"tenancy_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_template","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"derived_from_template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"pa_referral_dropdown","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_workflow_dialogue_stages_order","definition":"CREATE INDEX idx_workflow_dialogue_stages_order ON public.workflow_dialogue_stages USING btree (tenant_org_id, workflow_id, stage_order)"},{"name":"idx_workflow_dialogue_stages_tenant","definition":"CREATE INDEX idx_workflow_dialogue_stages_tenant ON public.workflow_dialogue_stages USING btree (tenant_org_id)"},{"name":"idx_workflow_dialogue_stages_workflow","definition":"CREATE INDEX idx_workflow_dialogue_stages_workflow ON public.workflow_dialogue_stages USING btree (tenant_org_id, workflow_id)"},{"name":"idx_workflow_dialogue_template","definition":"CREATE INDEX idx_workflow_dialogue_template ON public.workflow_dialogue_stages USING btree (is_template, tenancy_type) WHERE (is_template = true)"},{"name":"workflow_dialogue_stages_pkey","definition":"CREATE UNIQUE INDEX workflow_dialogue_stages_pkey ON public.workflow_dialogue_stages USING btree (id)"},{"name":"workflow_dialogue_stages_tenant_org_id_workflow_id_stage_or_key","definition":"CREATE UNIQUE INDEX workflow_dialogue_stages_tenant_org_id_workflow_id_stage_or_key ON public.workflow_dialogue_stages USING btree (tenant_org_id, workflow_id, stage_order)"}],"policies":[{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND ((user_roles.tenant_id)::text = workflow_dialogue_stages.tenant_org_id) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))","roles":["public"],"tablename":"workflow_dialogue_stages","permissive":"PERMISSIVE","policyname":"Tenant admins manage workflow dialogues","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND ((user_roles.tenant_id)::text = workflow_dialogue_stages.tenant_org_id) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE ((user_tenant_memberships.user_id = uid()) AND ((user_tenant_memberships.tenant_id)::text = workflow_dialogue_stages.tenant_org_id))))","roles":["public"],"tablename":"workflow_dialogue_stages","permissive":"PERMISSIVE","policyname":"Users view tenant workflow dialogues","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"workflow_dialogue_stages_pkey","definition":"PRIMARY KEY (id)"},{"name":"workflow_dialogue_stages_tenant_org_id_workflow_id_stage_or_key","definition":"UNIQUE (tenant_org_id, workflow_id, stage_order)"}]},{"table":"workflow_dialogue_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenancy_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"role","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"script_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"prompts","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"next_stage_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_workflow_dialogue_templates_role","definition":"CREATE INDEX idx_workflow_dialogue_templates_role ON public.workflow_dialogue_templates USING btree (role)"},{"name":"idx_workflow_dialogue_templates_tenancy","definition":"CREATE INDEX idx_workflow_dialogue_templates_tenancy ON public.workflow_dialogue_templates USING btree (tenancy_type)"},{"name":"workflow_dialogue_templates_pkey","definition":"CREATE UNIQUE INDEX workflow_dialogue_templates_pkey ON public.workflow_dialogue_templates USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"(is_active = true)","roles":["authenticated"],"tablename":"workflow_dialogue_templates","permissive":"PERMISSIVE","policyname":"Authenticated users can view dialogue templates","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"workflow_dialogue_templates","permissive":"PERMISSIVE","policyname":"platform_admin_manage_dialogue_templates","schemaname":"public","with_check":"is_system_admin(uid())"}],"triggers":[{"name":"update_workflow_dialogue_templates_updated_at","definition":"CREATE TRIGGER update_workflow_dialogue_templates_updated_at BEFORE UPDATE ON workflow_dialogue_templates FOR EACH ROW EXECUTE FUNCTION update_workflow_dialogue_templates_updated_at()"}],"constraints":[{"name":"workflow_dialogue_templates_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"workflow_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"session_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"event_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"stage_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"stage_name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"performed_by","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"outcome","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_workflow_events_created","definition":"CREATE INDEX idx_workflow_events_created ON public.workflow_events USING btree (created_at DESC)"},{"name":"idx_workflow_events_session","definition":"CREATE INDEX idx_workflow_events_session ON public.workflow_events USING btree (session_id)"},{"name":"workflow_events_pkey","definition":"CREATE UNIQUE INDEX workflow_events_pkey ON public.workflow_events USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"workflow_events","permissive":"PERMISSIVE","policyname":"Admins see all workflow events","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(session_id IN ( SELECT workflow_sessions.id\n   FROM workflow_sessions\n  WHERE (workflow_sessions.tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n           FROM security_active_user_tenant_memberships user_tenant_memberships\n          WHERE (user_tenant_memberships.user_id = uid())))))","roles":["public"],"tablename":"workflow_events","permissive":"PERMISSIVE","policyname":"Tenant members see session events","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"workflow_events","permissive":"PERMISSIVE","policyname":"Users insert events from their sessions","schemaname":"public","with_check":"((session_id IN ( SELECT workflow_sessions.id\n   FROM workflow_sessions\n  WHERE (workflow_sessions.user_id = uid()))) AND (performed_by = uid()))"}],"triggers":[],"constraints":[{"name":"workflow_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"workflow_publish_events","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_version_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"action","type":"workflow_publish_action","default":null,"identity":"","not_null":true,"generated":""},{"name":"performed_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"actor_role","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"ip_address","type":"inet","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_wpe_created_at","definition":"CREATE INDEX idx_wpe_created_at ON public.workflow_publish_events USING btree (created_at DESC)"},{"name":"idx_wpe_template_id","definition":"CREATE INDEX idx_wpe_template_id ON public.workflow_publish_events USING btree (template_id)"},{"name":"idx_wpe_version_id","definition":"CREATE INDEX idx_wpe_version_id ON public.workflow_publish_events USING btree (template_version_id)"},{"name":"uq_workflow_publish_events_seed","definition":"CREATE UNIQUE INDEX uq_workflow_publish_events_seed ON public.workflow_publish_events USING btree (template_id, template_version_id, action) WHERE (action = 'draft_created'::workflow_publish_action)"},{"name":"workflow_publish_events_pkey","definition":"CREATE UNIQUE INDEX workflow_publish_events_pkey ON public.workflow_publish_events USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"workflow_publish_events","permissive":"PERMISSIVE","policyname":"wpe_admin_insert","schemaname":"public","with_check":"is_workflow_template_admin(uid())"},{"cmd":"SELECT","qual":"is_workflow_template_admin(uid())","roles":["authenticated"],"tablename":"workflow_publish_events","permissive":"PERMISSIVE","policyname":"wpe_admin_select","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"workflow_publish_events","permissive":"PERMISSIVE","policyname":"wpe_tenant_owner_insert","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM workflow_templates t\n  WHERE ((t.id = workflow_publish_events.template_id) AND (t.scope = 'tenant'::workflow_template_scope) AND (t.owner_tenant_org_id IS NOT NULL) AND is_tenant_owner(uid(), t.owner_tenant_org_id))))"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM workflow_templates t\n  WHERE ((t.id = workflow_publish_events.template_id) AND (t.scope = 'tenant'::workflow_template_scope) AND (t.owner_tenant_org_id IS NOT NULL) AND is_tenant_owner(uid(), t.owner_tenant_org_id))))","roles":["authenticated"],"tablename":"workflow_publish_events","permissive":"PERMISSIVE","policyname":"wpe_tenant_owner_select","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"workflow_publish_events_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"workflow_rebuttals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"workflow_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"objection","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"response","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"one_liner","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_workflow_rebuttals_order","definition":"CREATE INDEX idx_workflow_rebuttals_order ON public.workflow_rebuttals USING btree (tenant_org_id, workflow_id, order_index)"},{"name":"idx_workflow_rebuttals_tenant","definition":"CREATE INDEX idx_workflow_rebuttals_tenant ON public.workflow_rebuttals USING btree (tenant_org_id)"},{"name":"idx_workflow_rebuttals_workflow","definition":"CREATE INDEX idx_workflow_rebuttals_workflow ON public.workflow_rebuttals USING btree (tenant_org_id, workflow_id)"},{"name":"workflow_rebuttals_pkey","definition":"CREATE UNIQUE INDEX workflow_rebuttals_pkey ON public.workflow_rebuttals USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"((is_active = true) AND ((tenant_org_id IS NULL) OR (tenant_org_id IN ( SELECT (utm.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships utm\n  WHERE ((utm.user_id = uid()) AND (utm.status = 'active'::text)))) OR is_system_admin(uid())))","roles":["authenticated"],"tablename":"workflow_rebuttals","permissive":"PERMISSIVE","policyname":"Tenant members view their rebuttals + globals","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_system_admin(uid())","roles":["public"],"tablename":"workflow_rebuttals","permissive":"PERMISSIVE","policyname":"workflow_rebuttals_godmode","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"SELECT","qual":"((tenant_org_id IS NULL) OR is_tenant_member(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"workflow_rebuttals","permissive":"PERMISSIVE","policyname":"workflow_rebuttals_tenant_member_read","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))","roles":["public"],"tablename":"workflow_rebuttals","permissive":"PERMISSIVE","policyname":"workflow_rebuttals_tenant_owner_manage","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_tenant_owner_or_admin(uid(), (tenant_org_id)::uuid))"}],"triggers":[],"constraints":[{"name":"workflow_rebuttals_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"workflow_resolution_parity_logs","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"workflow_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"workflow_source_flag","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"returned_source","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"db_template_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"db_template_version_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"json_card_count","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"db_card_count","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"json_rebuttal_count","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"db_rebuttal_count","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"json_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"db_hash","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"equal","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"customer_facing_text_equal","type":"boolean","default":null,"identity":"","not_null":false,"generated":""},{"name":"mismatched_card_ids","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"mismatched_choice_next_or_exit","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"db_lint_blocking_count","type":"integer","default":null,"identity":"","not_null":false,"generated":""},{"name":"fallback_used","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"error_message","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"runtime_context","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_wrpl_equal","definition":"CREATE INDEX idx_wrpl_equal ON public.workflow_resolution_parity_logs USING btree (equal)"},{"name":"idx_wrpl_fallback","definition":"CREATE INDEX idx_wrpl_fallback ON public.workflow_resolution_parity_logs USING btree (fallback_used)"},{"name":"idx_wrpl_recent","definition":"CREATE INDEX idx_wrpl_recent ON public.workflow_resolution_parity_logs USING btree (created_at DESC)"},{"name":"idx_wrpl_tenant_workflow_recent","definition":"CREATE INDEX idx_wrpl_tenant_workflow_recent ON public.workflow_resolution_parity_logs USING btree (tenant_org_id, workflow_type, created_at DESC)"},{"name":"idx_wrpl_version","definition":"CREATE INDEX idx_wrpl_version ON public.workflow_resolution_parity_logs USING btree (db_template_version_id)"},{"name":"workflow_resolution_parity_logs_pkey","definition":"CREATE UNIQUE INDEX workflow_resolution_parity_logs_pkey ON public.workflow_resolution_parity_logs USING btree (id)"}],"policies":[{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"workflow_resolution_parity_logs","permissive":"PERMISSIVE","policyname":"wrpl_insert_system_admin","schemaname":"public","with_check":"is_system_admin(uid())"},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"workflow_resolution_parity_logs","permissive":"PERMISSIVE","policyname":"wrpl_insert_tenant_manager","schemaname":"public","with_check":"((tenant_org_id IS NOT NULL) AND is_manager_or_higher(uid(), tenant_org_id))"},{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["authenticated"],"tablename":"workflow_resolution_parity_logs","permissive":"PERMISSIVE","policyname":"wrpl_select_system_admin","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((tenant_org_id IS NOT NULL) AND is_manager_or_higher(uid(), tenant_org_id))","roles":["authenticated"],"tablename":"workflow_resolution_parity_logs","permissive":"PERMISSIVE","policyname":"wrpl_select_tenant_manager","schemaname":"public","with_check":null}],"triggers":[],"constraints":[{"name":"workflow_resolution_parity_logs_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"workflow_sessions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"user_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"lead_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"contact_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"current_stage_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"workflow_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"text","default":"'active'::text","identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":false,"generated":""},{"name":"started_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"completed_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_workflow_sessions_lead","definition":"CREATE INDEX idx_workflow_sessions_lead ON public.workflow_sessions USING btree (lead_id)"},{"name":"idx_workflow_sessions_status","definition":"CREATE INDEX idx_workflow_sessions_status ON public.workflow_sessions USING btree (status)"},{"name":"idx_workflow_sessions_tenant","definition":"CREATE INDEX idx_workflow_sessions_tenant ON public.workflow_sessions USING btree (tenant_org_id)"},{"name":"idx_workflow_sessions_user","definition":"CREATE INDEX idx_workflow_sessions_user ON public.workflow_sessions USING btree (user_id)"},{"name":"workflow_sessions_pkey","definition":"CREATE UNIQUE INDEX workflow_sessions_pkey ON public.workflow_sessions USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"is_system_admin(uid())","roles":["public"],"tablename":"workflow_sessions","permissive":"PERMISSIVE","policyname":"Admins see all workflow sessions","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["public"],"tablename":"workflow_sessions","permissive":"PERMISSIVE","policyname":"Tenant members see tenant sessions","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["public"],"tablename":"workflow_sessions","permissive":"PERMISSIVE","policyname":"Users create sessions","schemaname":"public","with_check":"(user_id = uid())"},{"cmd":"UPDATE","qual":"(user_id = uid())","roles":["public"],"tablename":"workflow_sessions","permissive":"PERMISSIVE","policyname":"Users update own sessions","schemaname":"public","with_check":"(user_id = uid())"}],"triggers":[{"name":"workflow_sessions_updated_at","definition":"CREATE TRIGGER workflow_sessions_updated_at BEFORE UPDATE ON workflow_sessions FOR EACH ROW EXECUTE FUNCTION update_workflow_sessions_updated_at()"}],"constraints":[{"name":"workflow_sessions_pkey","definition":"PRIMARY KEY (id)"},{"name":"workflow_sessions_status_check","definition":"CHECK (status = ANY (ARRAY['active'::text, 'paused'::text, 'completed'::text, 'abandoned'::text]))"}]},{"table":"workflow_template_rebuttals","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"template_version_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"objection_label","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"short_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"normal_text","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"long_text","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"tags","type":"text[]","default":"'{}'::text[]","identity":"","not_null":true,"generated":""},{"name":"order_index","type":"integer","default":"0","identity":"","not_null":true,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"linked_card_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"source_rebuttal_id","type":"text","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_wtr_category","definition":"CREATE INDEX idx_wtr_category ON public.workflow_template_rebuttals USING btree (category) WHERE (category IS NOT NULL)"},{"name":"idx_wtr_linked_card","definition":"CREATE INDEX idx_wtr_linked_card ON public.workflow_template_rebuttals USING btree (linked_card_id) WHERE (linked_card_id IS NOT NULL)"},{"name":"idx_wtr_source_rebuttal_id","definition":"CREATE INDEX idx_wtr_source_rebuttal_id ON public.workflow_template_rebuttals USING btree (source_rebuttal_id) WHERE (source_rebuttal_id IS NOT NULL)"},{"name":"idx_wtr_version","definition":"CREATE INDEX idx_wtr_version ON public.workflow_template_rebuttals USING btree (template_version_id)"},{"name":"workflow_template_rebuttals_pkey","definition":"CREATE UNIQUE INDEX workflow_template_rebuttals_pkey ON public.workflow_template_rebuttals USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_workflow_template_admin(uid())","roles":["authenticated"],"tablename":"workflow_template_rebuttals","permissive":"PERMISSIVE","policyname":"wtr_admin_all","schemaname":"public","with_check":"is_workflow_template_admin(uid())"},{"cmd":"SELECT","qual":"((is_active = true) AND (EXISTS ( SELECT 1\n   FROM (workflow_template_versions v\n     JOIN workflow_template_tenant_assignments a ON ((a.template_id = v.template_id)))\n  WHERE ((v.id = workflow_template_rebuttals.template_version_id) AND (v.status = 'published'::workflow_template_version_status) AND (a.is_active = true) AND is_tenant_member(uid(), a.tenant_org_id)))))","roles":["authenticated"],"tablename":"workflow_template_rebuttals","permissive":"PERMISSIVE","policyname":"wtr_member_read_assigned_published","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"(EXISTS ( SELECT 1\n   FROM (workflow_template_versions v\n     JOIN workflow_templates t ON ((t.id = v.template_id)))\n  WHERE ((v.id = workflow_template_rebuttals.template_version_id) AND (t.scope = 'tenant'::workflow_template_scope) AND (t.owner_tenant_org_id IS NOT NULL) AND is_tenant_owner(uid(), t.owner_tenant_org_id))))","roles":["authenticated"],"tablename":"workflow_template_rebuttals","permissive":"PERMISSIVE","policyname":"wtr_tenant_owner_manage","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM (workflow_template_versions v\n     JOIN workflow_templates t ON ((t.id = v.template_id)))\n  WHERE ((v.id = workflow_template_rebuttals.template_version_id) AND (t.scope = 'tenant'::workflow_template_scope) AND (t.owner_tenant_org_id IS NOT NULL) AND is_tenant_owner(uid(), t.owner_tenant_org_id))))"}],"triggers":[{"name":"trg_wtr_updated_at","definition":"CREATE TRIGGER trg_wtr_updated_at BEFORE UPDATE ON workflow_template_rebuttals FOR EACH ROW EXECUTE FUNCTION tg_workflow_template_set_updated_at()"}],"constraints":[{"name":"workflow_template_rebuttals_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"workflow_template_tenant_assignments","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"pinned_version_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"assigned_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"assigned_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"workflow_type","type":"text","default":null,"identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_wtta_template_id","definition":"CREATE INDEX idx_wtta_template_id ON public.workflow_template_tenant_assignments USING btree (template_id)"},{"name":"idx_wtta_tenant_workflow_type","definition":"CREATE INDEX idx_wtta_tenant_workflow_type ON public.workflow_template_tenant_assignments USING btree (tenant_org_id, workflow_type)"},{"name":"uq_wtta_one_active_per_tenant_workflow_type","definition":"CREATE UNIQUE INDEX uq_wtta_one_active_per_tenant_workflow_type ON public.workflow_template_tenant_assignments USING btree (tenant_org_id, workflow_type) WHERE (is_active = true)"},{"name":"workflow_template_tenant_assignme_tenant_org_id_template_id_key","definition":"CREATE UNIQUE INDEX workflow_template_tenant_assignme_tenant_org_id_template_id_key ON public.workflow_template_tenant_assignments USING btree (tenant_org_id, template_id)"},{"name":"workflow_template_tenant_assignments_pkey","definition":"CREATE UNIQUE INDEX workflow_template_tenant_assignments_pkey ON public.workflow_template_tenant_assignments USING btree (id)"}],"policies":[{"cmd":"ALL","qual":"is_workflow_template_admin(uid())","roles":["authenticated"],"tablename":"workflow_template_tenant_assignments","permissive":"PERMISSIVE","policyname":"wtta_admin_all","schemaname":"public","with_check":"is_workflow_template_admin(uid())"},{"cmd":"SELECT","qual":"is_tenant_member(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"workflow_template_tenant_assignments","permissive":"PERMISSIVE","policyname":"wtta_tenant_member_select","schemaname":"public","with_check":null},{"cmd":"ALL","qual":"is_tenant_owner(uid(), tenant_org_id)","roles":["authenticated"],"tablename":"workflow_template_tenant_assignments","permissive":"PERMISSIVE","policyname":"wtta_tenant_owner_manage","schemaname":"public","with_check":"is_tenant_owner(uid(), tenant_org_id)"}],"triggers":[{"name":"trg_wtta_updated_at","definition":"CREATE TRIGGER trg_wtta_updated_at BEFORE UPDATE ON workflow_template_tenant_assignments FOR EACH ROW EXECUTE FUNCTION tg_workflow_template_set_updated_at()"}],"constraints":[{"name":"workflow_template_tenant_assignme_tenant_org_id_template_id_key","definition":"UNIQUE (tenant_org_id, template_id)"},{"name":"workflow_template_tenant_assignments_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"workflow_template_versions","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"template_id","type":"uuid","default":null,"identity":"","not_null":true,"generated":""},{"name":"version_number","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"status","type":"workflow_template_version_status","default":"'draft'::workflow_template_version_status","identity":"","not_null":true,"generated":""},{"name":"cards","type":"jsonb","default":"'[]'::jsonb","identity":"","not_null":true,"generated":""},{"name":"metadata","type":"jsonb","default":"'{}'::jsonb","identity":"","not_null":true,"generated":""},{"name":"lint_report","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"notes","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"published_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"published_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"rollback_parent_version_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_wtv_rollback_parent","definition":"CREATE INDEX idx_wtv_rollback_parent ON public.workflow_template_versions USING btree (rollback_parent_version_id) WHERE (rollback_parent_version_id IS NOT NULL)"},{"name":"idx_wtv_status","definition":"CREATE INDEX idx_wtv_status ON public.workflow_template_versions USING btree (status)"},{"name":"idx_wtv_template_id","definition":"CREATE INDEX idx_wtv_template_id ON public.workflow_template_versions USING btree (template_id)"},{"name":"idx_wtv_template_status","definition":"CREATE INDEX idx_wtv_template_status ON public.workflow_template_versions USING btree (template_id, status)"},{"name":"workflow_template_versions_pkey","definition":"CREATE UNIQUE INDEX workflow_template_versions_pkey ON public.workflow_template_versions USING btree (id)"},{"name":"workflow_template_versions_template_id_version_number_key","definition":"CREATE UNIQUE INDEX workflow_template_versions_template_id_version_number_key ON public.workflow_template_versions USING btree (template_id, version_number)"}],"policies":[{"cmd":"ALL","qual":"is_workflow_template_admin(uid())","roles":["authenticated"],"tablename":"workflow_template_versions","permissive":"PERMISSIVE","policyname":"wtv_admin_all","schemaname":"public","with_check":"is_workflow_template_admin(uid())"},{"cmd":"SELECT","qual":"((status = 'published'::workflow_template_version_status) AND (EXISTS ( SELECT 1\n   FROM workflow_template_tenant_assignments a\n  WHERE ((a.template_id = workflow_template_versions.template_id) AND (a.is_active = true) AND is_tenant_member(uid(), a.tenant_org_id)))))","roles":["authenticated"],"tablename":"workflow_template_versions","permissive":"PERMISSIVE","policyname":"wtv_member_read_assigned_published","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"workflow_template_versions","permissive":"PERMISSIVE","policyname":"wtv_tenant_owner_insert","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM workflow_templates t\n  WHERE ((t.id = workflow_template_versions.template_id) AND (t.scope = 'tenant'::workflow_template_scope) AND (t.owner_tenant_org_id IS NOT NULL) AND is_tenant_owner(uid(), t.owner_tenant_org_id))))"},{"cmd":"SELECT","qual":"(EXISTS ( SELECT 1\n   FROM workflow_templates t\n  WHERE ((t.id = workflow_template_versions.template_id) AND (t.scope = 'tenant'::workflow_template_scope) AND (t.owner_tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), t.owner_tenant_org_id))))","roles":["authenticated"],"tablename":"workflow_template_versions","permissive":"PERMISSIVE","policyname":"wtv_tenant_owner_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"(EXISTS ( SELECT 1\n   FROM workflow_templates t\n  WHERE ((t.id = workflow_template_versions.template_id) AND (t.scope = 'tenant'::workflow_template_scope) AND (t.owner_tenant_org_id IS NOT NULL) AND is_tenant_owner(uid(), t.owner_tenant_org_id))))","roles":["authenticated"],"tablename":"workflow_template_versions","permissive":"PERMISSIVE","policyname":"wtv_tenant_owner_update","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM workflow_templates t\n  WHERE ((t.id = workflow_template_versions.template_id) AND (t.scope = 'tenant'::workflow_template_scope) AND (t.owner_tenant_org_id IS NOT NULL) AND is_tenant_owner(uid(), t.owner_tenant_org_id))))"}],"triggers":[{"name":"trg_wtv_immutable","definition":"CREATE TRIGGER trg_wtv_immutable BEFORE UPDATE ON workflow_template_versions FOR EACH ROW EXECUTE FUNCTION tg_wtv_immutable_when_published()"}],"constraints":[{"name":"workflow_template_versions_pkey","definition":"PRIMARY KEY (id)"},{"name":"workflow_template_versions_template_id_version_number_key","definition":"UNIQUE (template_id, version_number)"}]},{"table":"workflow_templates","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"slug","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"scope","type":"workflow_template_scope","default":null,"identity":"","not_null":true,"generated":""},{"name":"tenant_type","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_tenant_org_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_active","type":"boolean","default":"true","identity":"","not_null":true,"generated":""},{"name":"current_published_version_id","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"workflow_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_workflow_templates_owner_tenant","definition":"CREATE INDEX idx_workflow_templates_owner_tenant ON public.workflow_templates USING btree (owner_tenant_org_id) WHERE (owner_tenant_org_id IS NOT NULL)"},{"name":"idx_workflow_templates_scope","definition":"CREATE INDEX idx_workflow_templates_scope ON public.workflow_templates USING btree (scope)"},{"name":"idx_workflow_templates_scope_workflow_type","definition":"CREATE INDEX idx_workflow_templates_scope_workflow_type ON public.workflow_templates USING btree (scope, workflow_type)"},{"name":"idx_workflow_templates_tenant_type","definition":"CREATE INDEX idx_workflow_templates_tenant_type ON public.workflow_templates USING btree (tenant_type) WHERE (tenant_type IS NOT NULL)"},{"name":"idx_workflow_templates_tenant_workflow_type","definition":"CREATE INDEX idx_workflow_templates_tenant_workflow_type ON public.workflow_templates USING btree (owner_tenant_org_id, workflow_type) WHERE (owner_tenant_org_id IS NOT NULL)"},{"name":"idx_workflow_templates_workflow_type","definition":"CREATE INDEX idx_workflow_templates_workflow_type ON public.workflow_templates USING btree (workflow_type)"},{"name":"workflow_templates_pkey","definition":"CREATE UNIQUE INDEX workflow_templates_pkey ON public.workflow_templates USING btree (id)"},{"name":"workflow_templates_slug_key","definition":"CREATE UNIQUE INDEX workflow_templates_slug_key ON public.workflow_templates USING btree (slug)"}],"policies":[{"cmd":"DELETE","qual":"is_workflow_template_admin(uid())","roles":["authenticated"],"tablename":"workflow_templates","permissive":"PERMISSIVE","policyname":"wt_admin_delete","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"workflow_templates","permissive":"PERMISSIVE","policyname":"wt_admin_insert","schemaname":"public","with_check":"is_workflow_template_admin(uid())"},{"cmd":"SELECT","qual":"is_workflow_template_admin(uid())","roles":["authenticated"],"tablename":"workflow_templates","permissive":"PERMISSIVE","policyname":"wt_admin_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"is_workflow_template_admin(uid())","roles":["authenticated"],"tablename":"workflow_templates","permissive":"PERMISSIVE","policyname":"wt_admin_update","schemaname":"public","with_check":"is_workflow_template_admin(uid())"},{"cmd":"SELECT","qual":"((scope = ANY (ARRAY['global'::workflow_template_scope, 'tenant_type'::workflow_template_scope])) AND (is_active = true))","roles":["authenticated"],"tablename":"workflow_templates","permissive":"PERMISSIVE","policyname":"wt_authenticated_read_catalog","schemaname":"public","with_check":null},{"cmd":"SELECT","qual":"((scope = 'tenant'::workflow_template_scope) AND (owner_tenant_org_id IS NOT NULL) AND is_tenant_member(uid(), owner_tenant_org_id))","roles":["authenticated"],"tablename":"workflow_templates","permissive":"PERMISSIVE","policyname":"wt_tenant_owner_select","schemaname":"public","with_check":null},{"cmd":"UPDATE","qual":"((scope = 'tenant'::workflow_template_scope) AND (owner_tenant_org_id IS NOT NULL) AND is_tenant_owner(uid(), owner_tenant_org_id))","roles":["authenticated"],"tablename":"workflow_templates","permissive":"PERMISSIVE","policyname":"wt_tenant_owner_update","schemaname":"public","with_check":"((scope = 'tenant'::workflow_template_scope) AND (owner_tenant_org_id IS NOT NULL) AND is_tenant_owner(uid(), owner_tenant_org_id))"}],"triggers":[{"name":"trg_wt_updated_at","definition":"CREATE TRIGGER trg_wt_updated_at BEFORE UPDATE ON workflow_templates FOR EACH ROW EXECUTE FUNCTION tg_workflow_template_set_updated_at()"}],"constraints":[{"name":"workflow_templates_pkey","definition":"PRIMARY KEY (id)"},{"name":"workflow_templates_scope_consistency","definition":"CHECK (scope = 'global'::workflow_template_scope AND tenant_type IS NULL AND owner_tenant_org_id IS NULL OR scope = 'tenant_type'::workflow_template_scope AND tenant_type IS NOT NULL AND owner_tenant_org_id IS NULL OR scope = 'tenant'::workflow_template_scope AND owner_tenant_org_id IS NOT NULL)"},{"name":"workflow_templates_slug_key","definition":"UNIQUE (slug)"}]},{"table":"workflow_variables","schema":"public","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"tenant_org_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"variable_name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"variable_key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"variable_value","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"description","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"example","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"variable_type","type":"variable_type","default":"'text'::variable_type","identity":"","not_null":true,"generated":""},{"name":"scope","type":"variable_scope","default":"'global'::variable_scope","identity":"","not_null":true,"generated":""},{"name":"category","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_workflow_variables_category","definition":"CREATE INDEX idx_workflow_variables_category ON public.workflow_variables USING btree (category)"},{"name":"idx_workflow_variables_scope","definition":"CREATE INDEX idx_workflow_variables_scope ON public.workflow_variables USING btree (scope)"},{"name":"idx_workflow_variables_tenant","definition":"CREATE INDEX idx_workflow_variables_tenant ON public.workflow_variables USING btree (tenant_org_id)"},{"name":"workflow_variables_pkey","definition":"CREATE UNIQUE INDEX workflow_variables_pkey ON public.workflow_variables USING btree (id)"},{"name":"workflow_variables_tenant_org_id_variable_key_key","definition":"CREATE UNIQUE INDEX workflow_variables_tenant_org_id_variable_key_key ON public.workflow_variables USING btree (tenant_org_id, variable_key)"}],"policies":[{"cmd":"DELETE","qual":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND ((user_roles.tenant_id)::text = workflow_variables.tenant_org_id) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))","roles":["authenticated"],"tablename":"workflow_variables","permissive":"PERMISSIVE","policyname":"Admins can delete tenant variables","schemaname":"public","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"workflow_variables","permissive":"PERMISSIVE","policyname":"Admins can insert tenant variables","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND ((user_roles.tenant_id)::text = workflow_variables.tenant_org_id) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))"},{"cmd":"UPDATE","qual":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND ((user_roles.tenant_id)::text = workflow_variables.tenant_org_id) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))","roles":["authenticated"],"tablename":"workflow_variables","permissive":"PERMISSIVE","policyname":"Admins can update tenant variables","schemaname":"public","with_check":"(EXISTS ( SELECT 1\n   FROM user_roles\n  WHERE ((user_roles.user_id = uid()) AND ((user_roles.tenant_id)::text = workflow_variables.tenant_org_id) AND (user_roles.role = ANY (ARRAY['Owner'::app_role, 'Admin'::app_role, 'GodMode'::app_role])))))"},{"cmd":"SELECT","qual":"(tenant_org_id IN ( SELECT (user_tenant_memberships.tenant_id)::text AS tenant_id\n   FROM security_active_user_tenant_memberships user_tenant_memberships\n  WHERE (user_tenant_memberships.user_id = uid())))","roles":["authenticated"],"tablename":"workflow_variables","permissive":"PERMISSIVE","policyname":"Users can view tenant variables","schemaname":"public","with_check":null}],"triggers":[{"name":"update_workflow_variables_updated_at","definition":"CREATE TRIGGER update_workflow_variables_updated_at BEFORE UPDATE ON workflow_variables FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()"}],"constraints":[{"name":"workflow_variables_pkey","definition":"PRIMARY KEY (id)"},{"name":"workflow_variables_tenant_org_id_variable_key_key","definition":"UNIQUE (tenant_org_id, variable_key)"}]},{"table":"buckets","schema":"storage","columns":[{"name":"id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"owner","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"public","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"avif_autodetection","type":"boolean","default":"false","identity":"","not_null":false,"generated":""},{"name":"file_size_limit","type":"bigint","default":null,"identity":"","not_null":false,"generated":""},{"name":"allowed_mime_types","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"type","type":"buckettype","default":"'STANDARD'::buckettype","identity":"","not_null":true,"generated":""},{"name":"versioning_status","type":"text","default":"'DISABLED'::text","identity":"","not_null":true,"generated":""},{"name":"lifecycle_configuration","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"lifecycle_configuration_generation","type":"uuid","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"bname","definition":"CREATE UNIQUE INDEX bname ON storage.buckets USING btree (name)"},{"name":"buckets_pkey","definition":"CREATE UNIQUE INDEX buckets_pkey ON storage.buckets USING btree (id)"}],"policies":[],"triggers":[{"name":"enforce_bucket_name_length_trigger","definition":"CREATE TRIGGER enforce_bucket_name_length_trigger BEFORE INSERT OR UPDATE OF name ON buckets FOR EACH ROW EXECUTE FUNCTION enforce_bucket_name_length()"},{"name":"protect_bucket_control_insert","definition":"CREATE TRIGGER protect_bucket_control_insert BEFORE INSERT ON buckets FOR EACH ROW EXECUTE FUNCTION protect_bucket_control_columns('service_role')"},{"name":"protect_bucket_control_update","definition":"CREATE TRIGGER protect_bucket_control_update BEFORE UPDATE OF lifecycle_configuration, lifecycle_configuration_generation ON buckets FOR EACH ROW EXECUTE FUNCTION protect_bucket_control_columns()"},{"name":"protect_bucket_control_update_role","definition":"CREATE TRIGGER protect_bucket_control_update_role AFTER UPDATE OF lifecycle_configuration, lifecycle_configuration_generation ON buckets FOR EACH ROW EXECUTE FUNCTION enforce_bucket_lifecycle_service_role('service_role')"},{"name":"protect_buckets_delete","definition":"CREATE TRIGGER protect_buckets_delete BEFORE DELETE ON buckets FOR EACH STATEMENT EXECUTE FUNCTION protect_delete()"}],"constraints":[{"name":"buckets_lifecycle_configuration_pair_check","definition":"CHECK ((lifecycle_configuration IS NULL) = (lifecycle_configuration_generation IS NULL))"},{"name":"buckets_lifecycle_configuration_shape_check","definition":"CHECK (lifecycle_configuration IS NULL OR jsonb_typeof(lifecycle_configuration) = 'object'::text AND lifecycle_configuration ? 'rules'::text AND\nCASE\n    WHEN jsonb_typeof(lifecycle_configuration -> 'rules'::text) = 'array'::text THEN jsonb_array_length(lifecycle_configuration -> 'rules'::text) >= 1 AND jsonb_array_length(lifecycle_configuration -> 'rules'::text) <= 1000\n    ELSE false\nEND)"},{"name":"buckets_lifecycle_configuration_standard_only_check","definition":"CHECK (type = 'STANDARD'::buckettype OR lifecycle_configuration IS NULL AND lifecycle_configuration_generation IS NULL)"},{"name":"buckets_pkey","definition":"PRIMARY KEY (id)"},{"name":"buckets_versioning_dark_check","definition":"CHECK (versioning_status = 'DISABLED'::text)"},{"name":"buckets_versioning_standard_only_check","definition":"CHECK (type = 'STANDARD'::buckettype OR versioning_status = 'DISABLED'::text)"},{"name":"buckets_versioning_status_check","definition":"CHECK (versioning_status = ANY (ARRAY['DISABLED'::text, 'ENABLED'::text, 'SUSPENDED'::text]))"}]},{"table":"buckets_analytics","schema":"storage","columns":[{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"type","type":"buckettype","default":"'ANALYTICS'::buckettype","identity":"","not_null":true,"generated":""},{"name":"format","type":"text","default":"'ICEBERG'::text","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"deleted_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"buckets_analytics_pkey","definition":"CREATE UNIQUE INDEX buckets_analytics_pkey ON storage.buckets_analytics USING btree (id)"},{"name":"buckets_analytics_unique_name_idx","definition":"CREATE UNIQUE INDEX buckets_analytics_unique_name_idx ON storage.buckets_analytics USING btree (name) WHERE (deleted_at IS NULL)"}],"policies":[],"triggers":[],"constraints":[{"name":"buckets_analytics_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"buckets_vectors","schema":"storage","columns":[{"name":"id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"type","type":"buckettype","default":"'VECTOR'::buckettype","identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"buckets_vectors_pkey","definition":"CREATE UNIQUE INDEX buckets_vectors_pkey ON storage.buckets_vectors USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"buckets_vectors_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"migrations","schema":"storage","columns":[{"name":"id","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"name","type":"character varying(100)","default":null,"identity":"","not_null":true,"generated":""},{"name":"hash","type":"character varying(40)","default":null,"identity":"","not_null":true,"generated":""},{"name":"executed_at","type":"timestamp without time zone","default":"CURRENT_TIMESTAMP","identity":"","not_null":false,"generated":""}],"indexes":[{"name":"migrations_name_key","definition":"CREATE UNIQUE INDEX migrations_name_key ON storage.migrations USING btree (name)"},{"name":"migrations_pkey","definition":"CREATE UNIQUE INDEX migrations_pkey ON storage.migrations USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"migrations_name_key","definition":"UNIQUE (name)"},{"name":"migrations_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"objects","schema":"storage","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"bucket_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner","type":"uuid","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"last_accessed_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"path_tokens","type":"text[]","default":"string_to_array(name, '/'::text)","identity":"","not_null":false,"generated":"s"},{"name":"version","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"owner_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"user_metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"archived_at","type":"timestamp with time zone","default":null,"identity":"","not_null":false,"generated":""},{"name":"is_delete_marker","type":"boolean","default":"false","identity":"","not_null":true,"generated":""},{"name":"is_versioned","type":"boolean","default":"false","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"idx_objects_bucket_id_name","definition":"CREATE INDEX idx_objects_bucket_id_name ON storage.objects USING btree (bucket_id, name COLLATE \"C\")"},{"name":"idx_objects_bucket_id_name_lower","definition":"CREATE INDEX idx_objects_bucket_id_name_lower ON storage.objects USING btree (bucket_id, lower(name) COLLATE \"C\")"},{"name":"idx_objects_current_version","definition":"CREATE UNIQUE INDEX idx_objects_current_version ON storage.objects USING btree (bucket_id, name COLLATE \"C\") WHERE (archived_at IS NULL)"},{"name":"idx_objects_delete_markers","definition":"CREATE INDEX idx_objects_delete_markers ON storage.objects USING btree (bucket_id, name COLLATE \"C\") WHERE is_delete_marker"},{"name":"idx_objects_null_version","definition":"CREATE UNIQUE INDEX idx_objects_null_version ON storage.objects USING btree (bucket_id, name COLLATE \"C\") WHERE (NOT is_versioned)"},{"name":"name_prefix_search","definition":"CREATE INDEX name_prefix_search ON storage.objects USING btree (name text_pattern_ops)"},{"name":"objects_bucket_id_name_version_key","definition":"CREATE UNIQUE INDEX objects_bucket_id_name_version_key ON storage.objects USING btree (bucket_id, name COLLATE \"C\", version) NULLS NOT DISTINCT"},{"name":"objects_pkey","definition":"CREATE UNIQUE INDEX objects_pkey ON storage.objects USING btree (id)"}],"policies":[{"cmd":"SELECT","qual":"((bucket_id = 'command-center-visual-witness'::text) AND ((foldername(name))[1] = 'tenant'::text) AND ((foldername(name))[2] IS NOT NULL) AND is_command_agent(uid(), ((foldername(name))[2])::uuid))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"Command agents can read visual witness screenshots","schemaname":"storage","with_check":null},{"cmd":"DELETE","qual":"((bucket_id = 'voice-notes'::text) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM voice_notes vn\n  WHERE ((vn.user_id = uid()) AND (vn.audio_path = objects.name))))))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"Users can delete own voice notes","schemaname":"storage","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"Users can upload own voice notes","schemaname":"storage","with_check":"((bucket_id = 'voice-notes'::text) AND (is_system_admin(uid()) OR ((foldername(name))[1] = (uid())::text)))"},{"cmd":"SELECT","qual":"((bucket_id = 'voice-notes'::text) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM voice_notes vn\n  WHERE ((vn.user_id = uid()) AND (vn.audio_path = objects.name))))))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"Users can view own voice notes","schemaname":"storage","with_check":null},{"cmd":"DELETE","qual":"((bucket_id = 'cafe-menu-media'::text) AND (is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND ((membership.tenant_id)::text = (foldername(objects.name))[1]) AND (COALESCE(membership.status, 'active'::text) = 'active'::text))))))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"cafe_menu_media_owner_delete","schemaname":"storage","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"cafe_menu_media_owner_insert","schemaname":"storage","with_check":"((bucket_id = 'cafe-menu-media'::text) AND (is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND ((membership.tenant_id)::text = (foldername(objects.name))[1]) AND (COALESCE(membership.status, 'active'::text) = 'active'::text))))))"},{"cmd":"UPDATE","qual":"((bucket_id = 'cafe-menu-media'::text) AND (is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND ((membership.tenant_id)::text = (foldername(objects.name))[1]) AND (COALESCE(membership.status, 'active'::text) = 'active'::text))))))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"cafe_menu_media_owner_update","schemaname":"storage","with_check":"((bucket_id = 'cafe-menu-media'::text) AND (is_system_admin(( SELECT uid() AS uid)) OR (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = ( SELECT uid() AS uid)) AND ((membership.tenant_id)::text = (foldername(objects.name))[1]) AND (COALESCE(membership.status, 'active'::text) = 'active'::text))))))"},{"cmd":"SELECT","qual":"(bucket_id = 'cafe-menu-media'::text)","roles":["public"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"cafe_menu_media_public_read","schemaname":"storage","with_check":null},{"cmd":"DELETE","qual":"((bucket_id = 'message-attachments'::text) AND ((foldername(name))[3] = (uid())::text) AND can_access_message_conversation(message_storage_conversation_id(name), uid()))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"message_attachments_storage_delete","schemaname":"storage","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"message_attachments_storage_insert","schemaname":"storage","with_check":"((bucket_id = 'message-attachments'::text) AND ((foldername(name))[1] = 'messages'::text) AND ((foldername(name))[3] = (uid())::text) AND can_access_message_conversation(message_storage_conversation_id(name), uid()))"},{"cmd":"SELECT","qual":"((bucket_id = 'message-attachments'::text) AND can_access_message_attachment_storage(name, uid()))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"message_attachments_storage_select","schemaname":"storage","with_check":null},{"cmd":"DELETE","qual":"((bucket_id = 'paul-attachments'::text) AND ((foldername(name))[1] = (uid())::text))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"paul_attachments_storage_delete","schemaname":"storage","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"paul_attachments_storage_insert","schemaname":"storage","with_check":"((bucket_id = 'paul-attachments'::text) AND ((foldername(name))[1] = (uid())::text))"},{"cmd":"SELECT","qual":"((bucket_id = 'paul-attachments'::text) AND ((foldername(name))[1] = (uid())::text))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"paul_attachments_storage_select","schemaname":"storage","with_check":null},{"cmd":"UPDATE","qual":"((bucket_id = 'paul-attachments'::text) AND ((foldername(name))[1] = (uid())::text))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"paul_attachments_storage_update","schemaname":"storage","with_check":"((bucket_id = 'paul-attachments'::text) AND ((foldername(name))[1] = (uid())::text))"},{"cmd":"SELECT","qual":"((name ~~ 'Documents/Proposals/%'::text) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (tenants t\n     JOIN security_active_user_tenant_memberships m ON ((m.tenant_id = t.id)))\n  WHERE ((m.user_id = uid()) AND (COALESCE(m.status, 'active'::text) = 'active'::text) AND (objects.bucket_id = NULLIF(btrim(COALESCE((t.settings ->> 'storage_bucket'::text), ''::text)), ''::text)))))))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"proposal_documents_tenant_select","schemaname":"storage","with_check":null},{"cmd":"DELETE","qual":"((name ~~ 'apps/proposal-editor/%'::text) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (tenants t\n     JOIN security_active_user_tenant_memberships m ON ((m.tenant_id = t.id)))\n  WHERE ((m.user_id = uid()) AND (COALESCE(m.status, 'active'::text) = 'active'::text) AND (objects.bucket_id = NULLIF(btrim(COALESCE((t.settings ->> 'storage_bucket'::text), ''::text)), ''::text)))))))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"proposal_editor_tenant_assets_delete","schemaname":"storage","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"proposal_editor_tenant_assets_insert","schemaname":"storage","with_check":"((name ~~ 'apps/proposal-editor/%'::text) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (tenants t\n     JOIN security_active_user_tenant_memberships m ON ((m.tenant_id = t.id)))\n  WHERE ((m.user_id = uid()) AND (COALESCE(m.status, 'active'::text) = 'active'::text) AND (objects.bucket_id = NULLIF(btrim(COALESCE((t.settings ->> 'storage_bucket'::text), ''::text)), ''::text)))))))"},{"cmd":"SELECT","qual":"((name ~~ 'apps/proposal-editor/%'::text) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (tenants t\n     JOIN security_active_user_tenant_memberships m ON ((m.tenant_id = t.id)))\n  WHERE ((m.user_id = uid()) AND (COALESCE(m.status, 'active'::text) = 'active'::text) AND (objects.bucket_id = NULLIF(btrim(COALESCE((t.settings ->> 'storage_bucket'::text), ''::text)), ''::text)))))))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"proposal_editor_tenant_assets_select","schemaname":"storage","with_check":null},{"cmd":"UPDATE","qual":"((name ~~ 'apps/proposal-editor/%'::text) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (tenants t\n     JOIN security_active_user_tenant_memberships m ON ((m.tenant_id = t.id)))\n  WHERE ((m.user_id = uid()) AND (COALESCE(m.status, 'active'::text) = 'active'::text) AND (objects.bucket_id = NULLIF(btrim(COALESCE((t.settings ->> 'storage_bucket'::text), ''::text)), ''::text)))))))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"proposal_editor_tenant_assets_update","schemaname":"storage","with_check":"((name ~~ 'apps/proposal-editor/%'::text) AND (is_system_admin(uid()) OR (EXISTS ( SELECT 1\n   FROM (tenants t\n     JOIN security_active_user_tenant_memberships m ON ((m.tenant_id = t.id)))\n  WHERE ((m.user_id = uid()) AND (COALESCE(m.status, 'active'::text) = 'active'::text) AND (objects.bucket_id = NULLIF(btrim(COALESCE((t.settings ->> 'storage_bucket'::text), ''::text)), ''::text)))))))"},{"cmd":"SELECT","qual":"((bucket_id = kl_tenant_storage_bucket('d60e3c27-73ed-4a5f-a49b-c37636455daf'::uuid)) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships m\n  WHERE ((m.user_id = uid()) AND (m.tenant_id = 'd60e3c27-73ed-4a5f-a49b-c37636455daf'::uuid) AND (m.status = 'active'::text)))))","roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"vehicle_lockout_member_proof_read","schemaname":"storage","with_check":null},{"cmd":"INSERT","qual":null,"roles":["authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"vehicle_lockout_member_service_evidence_insert","schemaname":"storage","with_check":"((bucket_id = kl_tenant_storage_bucket('d60e3c27-73ed-4a5f-a49b-c37636455daf'::uuid)) AND (name ~~ 'service-evidence/%'::text) AND (lower(extension(name)) = ANY (ARRAY['jpg'::text, 'jpeg'::text, 'png'::text, 'webp'::text, 'pdf'::text])) AND (EXISTS ( SELECT 1\n   FROM security_active_user_tenant_memberships membership\n  WHERE ((membership.user_id = uid()) AND (membership.tenant_id = 'd60e3c27-73ed-4a5f-a49b-c37636455daf'::uuid) AND (membership.status = 'active'::text)))))"},{"cmd":"INSERT","qual":null,"roles":["anon","authenticated"],"tablename":"objects","permissive":"PERMISSIVE","policyname":"vehicle_lockout_public_proof_upload","schemaname":"storage","with_check":"((bucket_id = private.kl_tenant_storage_bucket('d60e3c27-73ed-4a5f-a49b-c37636455daf'::uuid)) AND (name ~~ 'public-intake/%'::text) AND (lower(extension(name)) = ANY (ARRAY['jpg'::text, 'jpeg'::text, 'png'::text, 'webp'::text, 'pdf'::text])) AND private.auto_unlock_upload_ticket_allows(name, metadata))"}],"triggers":[{"name":"kl_sync_tenant_media_storage_object","definition":"CREATE TRIGGER kl_sync_tenant_media_storage_object AFTER INSERT OR DELETE OR UPDATE ON objects FOR EACH ROW EXECUTE FUNCTION kl_sync_tenant_media_storage_object()"},{"name":"protect_objects_delete","definition":"CREATE TRIGGER protect_objects_delete BEFORE DELETE ON objects FOR EACH STATEMENT EXECUTE FUNCTION protect_delete()"},{"name":"update_objects_updated_at","definition":"CREATE TRIGGER update_objects_updated_at BEFORE UPDATE ON objects FOR EACH ROW EXECUTE FUNCTION storage.update_updated_at_column()"}],"constraints":[{"name":"objects_bucketId_fkey","definition":"FOREIGN KEY (bucket_id) REFERENCES buckets(id)"},{"name":"objects_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"s3_multipart_uploads","schema":"storage","columns":[{"name":"id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"in_progress_size","type":"bigint","default":"0","identity":"","not_null":true,"generated":""},{"name":"upload_signature","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"bucket_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"version","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"owner_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"user_metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"metadata","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"idx_multipart_uploads_list","definition":"CREATE INDEX idx_multipart_uploads_list ON storage.s3_multipart_uploads USING btree (bucket_id, key, created_at)"},{"name":"s3_multipart_uploads_pkey","definition":"CREATE UNIQUE INDEX s3_multipart_uploads_pkey ON storage.s3_multipart_uploads USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"s3_multipart_uploads_bucket_id_fkey","definition":"FOREIGN KEY (bucket_id) REFERENCES buckets(id)"},{"name":"s3_multipart_uploads_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"s3_multipart_uploads_parts","schema":"storage","columns":[{"name":"id","type":"uuid","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"upload_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"size","type":"bigint","default":"0","identity":"","not_null":true,"generated":""},{"name":"part_number","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"bucket_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"key","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"etag","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"owner_id","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"version","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"s3_multipart_uploads_parts_pkey","definition":"CREATE UNIQUE INDEX s3_multipart_uploads_parts_pkey ON storage.s3_multipart_uploads_parts USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"s3_multipart_uploads_parts_bucket_id_fkey","definition":"FOREIGN KEY (bucket_id) REFERENCES buckets(id)"},{"name":"s3_multipart_uploads_parts_pkey","definition":"PRIMARY KEY (id)"},{"name":"s3_multipart_uploads_parts_upload_id_fkey","definition":"FOREIGN KEY (upload_id) REFERENCES s3_multipart_uploads(id) ON DELETE CASCADE"}]},{"table":"vector_indexes","schema":"storage","columns":[{"name":"id","type":"text","default":"gen_random_uuid()","identity":"","not_null":true,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"bucket_id","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"data_type","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"dimension","type":"integer","default":null,"identity":"","not_null":true,"generated":""},{"name":"distance_metric","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"metadata_configuration","type":"jsonb","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""},{"name":"updated_at","type":"timestamp with time zone","default":"now()","identity":"","not_null":true,"generated":""}],"indexes":[{"name":"vector_indexes_name_bucket_id_idx","definition":"CREATE UNIQUE INDEX vector_indexes_name_bucket_id_idx ON storage.vector_indexes USING btree (name, bucket_id)"},{"name":"vector_indexes_pkey","definition":"CREATE UNIQUE INDEX vector_indexes_pkey ON storage.vector_indexes USING btree (id)"}],"policies":[],"triggers":[],"constraints":[{"name":"vector_indexes_bucket_id_fkey","definition":"FOREIGN KEY (bucket_id) REFERENCES buckets_vectors(id)"},{"name":"vector_indexes_pkey","definition":"PRIMARY KEY (id)"}]},{"table":"schema_migrations","schema":"supabase_migrations","columns":[{"name":"version","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"statements","type":"text[]","default":null,"identity":"","not_null":false,"generated":""},{"name":"name","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"created_by","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"idempotency_key","type":"text","default":null,"identity":"","not_null":false,"generated":""},{"name":"rollback","type":"text[]","default":null,"identity":"","not_null":false,"generated":""}],"indexes":[{"name":"schema_migrations_idempotency_key_key","definition":"CREATE UNIQUE INDEX schema_migrations_idempotency_key_key ON supabase_migrations.schema_migrations USING btree (idempotency_key)"},{"name":"schema_migrations_pkey","definition":"CREATE UNIQUE INDEX schema_migrations_pkey ON supabase_migrations.schema_migrations USING btree (version)"}],"policies":[],"triggers":[],"constraints":[{"name":"schema_migrations_idempotency_key_key","definition":"UNIQUE (idempotency_key)"},{"name":"schema_migrations_pkey","definition":"PRIMARY KEY (version)"}]},{"table":"seed_files","schema":"supabase_migrations","columns":[{"name":"path","type":"text","default":null,"identity":"","not_null":true,"generated":""},{"name":"hash","type":"text","default":null,"identity":"","not_null":true,"generated":""}],"indexes":[{"name":"seed_files_pkey","definition":"CREATE UNIQUE INDEX seed_files_pkey ON supabase_migrations.seed_files USING btree (path)"}],"policies":[],"triggers":[],"constraints":[{"name":"seed_files_pkey","definition":"PRIMARY KEY (path)"}]}],"database":"postgres","routines":[{"name":"auto_unlock_upload_ticket_allows","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.auto_unlock_upload_ticket_allows(p_path text, p_metadata jsonb)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  select exists (\n    select 1\n    from public.auto_unlock_upload_tickets t\n    where t.object_path = p_path\n      and t.consumed_at is null\n      and t.expires_at > now()\n      and coalesce((p_metadata->>'size')::bigint,0) > 0\n      and coalesce((p_metadata->>'size')::bigint,0) <= t.declared_size\n      and lower(coalesce(p_metadata->>'mimetype','')) = lower(t.declared_mime)\n  )\n$function$\n","identity_arguments":"p_path text, p_metadata jsonb"},{"name":"current_user_email","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.current_user_email()\n RETURNS text\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\n  select p.email from public.profiles p\n  where p.id = (select auth.uid())\n  limit 1;\n$function$\n","identity_arguments":""},{"name":"current_user_tenant_ids","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.current_user_tenant_ids()\n RETURNS uuid[]\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\n  select coalesce(array_agg(distinct tenant_id), array[]::uuid[])\n  from (\n    select m.tenant_id\n    from public.user_tenant_memberships m\n    where m.user_id = (select auth.uid()) and m.status = 'active'\n    union\n    select r.tenant_id\n    from public.user_roles r\n    where r.user_id = (select auth.uid()) and r.tenant_id is not null\n  ) s;\n$function$\n","identity_arguments":""},{"name":"dedupe_page_view_insert","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.dedupe_page_view_insert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_catalog'\nAS $function$\ndeclare\n  lock_key bigint;\nbegin\n  lock_key := pg_catalog.hashtextextended(\n    new.user_id::text || '|' || coalesce(new.tenant_id, '') || '|' || new.page_path,\n    0\n  );\n  perform pg_catalog.pg_advisory_xact_lock(lock_key);\n\n  if exists (\n    select 1\n    from public.page_views pv\n    where pv.user_id = new.user_id\n      and coalesce(pv.tenant_id, '') = coalesce(new.tenant_id, '')\n      and pv.page_path = new.page_path\n      and pv.page_title is not distinct from new.page_title\n      and coalesce(pv.metadata, '{}'::jsonb) = coalesce(new.metadata, '{}'::jsonb)\n      and pv.entered_at >= new.entered_at - interval '1 second'\n      and pv.entered_at <= new.entered_at + interval '1 second'\n    order by pv.entered_at desc\n    limit 1\n  ) then\n    return null;\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enqueue_modes_storage_reconcile_trigger","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.enqueue_modes_storage_reconcile_trigger()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'private', 'public'\nAS $function$\ndeclare\n  v_new_family text;\n  v_new_shell text;\n  v_new_type text;\n  v_new_modes boolean;\n  v_old_family text;\n  v_old_shell text;\n  v_old_type text;\n  v_old_modes boolean;\n  v_new_cards_semantic jsonb;\n  v_old_cards_semantic jsonb;\nbegin\n  v_new_family := lower(coalesce(new.settings->>'experience_family',''));\n  v_new_shell := upper(coalesce(new.settings->>'shell_template',''));\n  v_new_type := upper(replace(coalesce(new.tenant_type,''),'-','_'));\n  v_new_modes := v_new_family = 'modes'\n    or (v_new_family <> 'standard' and (v_new_shell = 'MODES' or v_new_type = 'PORTFOLIO_CONTROL_CENTER'));\n\n  if not v_new_modes then\n    return new;\n  end if;\n\n  if tg_op = 'INSERT' then\n    perform private.modes_storage_edge_request(new.id);\n    return new;\n  end if;\n\n  v_old_family := lower(coalesce(old.settings->>'experience_family',''));\n  v_old_shell := upper(coalesce(old.settings->>'shell_template',''));\n  v_old_type := upper(replace(coalesce(old.tenant_type,''),'-','_'));\n  v_old_modes := v_old_family = 'modes'\n    or (v_old_family <> 'standard' and (v_old_shell = 'MODES' or v_old_type = 'PORTFOLIO_CONTROL_CENTER'));\n\n  select coalesce(jsonb_agg(card - 'image_updated_at' order by ord), '[]'::jsonb)\n    into v_new_cards_semantic\n    from jsonb_array_elements(coalesce(new.settings#>'{modes,cards}','[]'::jsonb)) with ordinality as x(card,ord);\n\n  select coalesce(jsonb_agg(card - 'image_updated_at' order by ord), '[]'::jsonb)\n    into v_old_cards_semantic\n    from jsonb_array_elements(coalesce(old.settings#>'{modes,cards}','[]'::jsonb)) with ordinality as x(card,ord);\n\n  if not v_old_modes\n     or v_old_cards_semantic is distinct from v_new_cards_semantic\n     or coalesce(old.settings->>'storage_bucket','') is distinct from coalesce(new.settings->>'storage_bucket','') then\n    perform private.modes_storage_edge_request(new.id);\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"expire_stale_user_sessions","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.expire_stale_user_sessions(_cutoff interval DEFAULT '01:00:00'::interval)\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_catalog'\nAS $function$\ndeclare\n  expired_count integer := 0;\nbegin\n  if _cutoff is null or _cutoff < interval '5 minutes' then\n    raise exception 'session_expiration_cutoff_too_small';\n  end if;\n\n  update public.user_sessions\n     set is_active = false,\n         ended_at = coalesce(ended_at, last_activity_at, started_at, now()),\n         end_reason = coalesce(nullif(end_reason, ''), 'expired_inactivity')\n   where is_active is true\n     and coalesce(last_activity_at, started_at) < now() - _cutoff;\n\n  get diagnostics expired_count = row_count;\n  return expired_count;\nend;\n$function$\n","identity_arguments":"_cutoff interval"},{"name":"generate_call_center_weekly_reports","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.generate_call_center_weekly_reports(p_period_end timestamp with time zone DEFAULT date_trunc('week'::text, now()))\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'private'\nAS $function$\ndeclare\n  t record;\n  c record;\n  p_start timestamptz := p_period_end - interval '7 days';\n  metrics jsonb;\n  generated integer := 0;\nbegin\n  for t in select id from public.tenants loop\n    select jsonb_build_object(\n      'calls_attempted', count(*),\n      'calls_completed', count(*) filter (where s.status='completed'),\n      'answered_count', count(*) filter (where s.answered_at is not null),\n      'completion_rate', case when count(*)>0 then round((count(*) filter (where s.status='completed'))::numeric*100/count(*),1) else null end,\n      'answer_rate', case when count(*)>0 and count(*) filter (where s.answered_at is not null)>0 then round((count(*) filter (where s.answered_at is not null))::numeric*100/count(*),1) else null end,\n      'average_duration_seconds', round(avg(s.duration_seconds) filter (where s.duration_seconds is not null),1),\n      'follow_ups_created', count(*) filter (where s.follow_up_at is not null),\n      'dispositions', coalesce((select jsonb_object_agg(x.disposition_key,x.cnt) from (select coalesce(s2.disposition_key,'unclassified') disposition_key,count(*) cnt from public.call_center_sessions s2 where s2.tenant_id=t.id and s2.started_at>=p_start and s2.started_at<p_period_end group by 1) x),'{}'::jsonb),\n      'agents', coalesce((select jsonb_object_agg(x.agent_key,x.cnt) from (select coalesce(s3.agent_user_id::text,'unassigned') agent_key,count(*) cnt from public.call_center_sessions s3 where s3.tenant_id=t.id and s3.started_at>=p_start and s3.started_at<p_period_end group by 1) x),'{}'::jsonb),\n      'campaigns', coalesce((select jsonb_object_agg(x.campaign_key,x.cnt) from (select coalesce(s4.campaign_id::text,'uncampaigned') campaign_key,count(*) cnt from public.call_center_sessions s4 where s4.tenant_id=t.id and s4.started_at>=p_start and s4.started_at<p_period_end group by 1) x),'{}'::jsonb),\n      'follow_ups_due', (select count(*) from public.call_center_queue q where q.tenant_id=t.id and q.next_action_at>=p_start and q.next_action_at<p_period_end)\n    ) into metrics\n    from public.call_center_sessions s\n    where s.tenant_id=t.id and s.started_at>=p_start and s.started_at<p_period_end;\n\n    insert into public.call_center_weekly_reports(tenant_id,campaign_id,report_scope,scope_key,period_start,period_end,report_data,generated_at)\n    values(t.id,null,'tenant','tenant',p_start,p_period_end,coalesce(metrics,'{}'::jsonb),now())\n    on conflict(tenant_id,scope_key,period_start,period_end) do update set report_data=excluded.report_data,generated_at=now();\n    generated := generated + 1;\n\n    for c in select id,name from public.call_center_campaigns where tenant_id=t.id loop\n      select jsonb_build_object(\n        'campaign_name', c.name,\n        'calls_attempted', count(*),\n        'calls_completed', count(*) filter (where s.status='completed'),\n        'answered_count', count(*) filter (where s.answered_at is not null),\n        'completion_rate', case when count(*)>0 then round((count(*) filter (where s.status='completed'))::numeric*100/count(*),1) else null end,\n        'answer_rate', case when count(*)>0 and count(*) filter (where s.answered_at is not null)>0 then round((count(*) filter (where s.answered_at is not null))::numeric*100/count(*),1) else null end,\n        'average_duration_seconds', round(avg(s.duration_seconds) filter (where s.duration_seconds is not null),1),\n        'follow_ups_created', count(*) filter (where s.follow_up_at is not null),\n        'dispositions', coalesce((select jsonb_object_agg(x.disposition_key,x.cnt) from (select coalesce(s2.disposition_key,'unclassified') disposition_key,count(*) cnt from public.call_center_sessions s2 where s2.tenant_id=t.id and s2.campaign_id=c.id and s2.started_at>=p_start and s2.started_at<p_period_end group by 1) x),'{}'::jsonb),\n        'agents', coalesce((select jsonb_object_agg(x.agent_key,x.cnt) from (select coalesce(s3.agent_user_id::text,'unassigned') agent_key,count(*) cnt from public.call_center_sessions s3 where s3.tenant_id=t.id and s3.campaign_id=c.id and s3.started_at>=p_start and s3.started_at<p_period_end group by 1) x),'{}'::jsonb),\n        'member_count', (select count(*) from public.call_center_campaign_members m where m.tenant_id=t.id and m.campaign_id=c.id),\n        'follow_ups_due', (select count(*) from public.call_center_queue q where q.tenant_id=t.id and q.campaign_id=c.id and q.next_action_at>=p_start and q.next_action_at<p_period_end)\n      ) into metrics\n      from public.call_center_sessions s\n      where s.tenant_id=t.id and s.campaign_id=c.id and s.started_at>=p_start and s.started_at<p_period_end;\n\n      insert into public.call_center_weekly_reports(tenant_id,campaign_id,report_scope,scope_key,period_start,period_end,report_data,generated_at)\n      values(t.id,c.id,'campaign',c.id::text,p_start,p_period_end,coalesce(metrics,'{}'::jsonb),now())\n      on conflict(tenant_id,scope_key,period_start,period_end) do update set report_data=excluded.report_data,generated_at=now();\n      generated := generated + 1;\n    end loop;\n  end loop;\n  return generated;\nend;\n$function$\n","identity_arguments":"p_period_end timestamp with time zone"},{"name":"kl_tenant_storage_bucket","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.kl_tenant_storage_bucket(p_tenant_id uuid)\n RETURNS text\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  select coalesce(\n    nullif(trim(coalesce(t.settings->>'storage_bucket','')),''),\n    public.kl_readable_tenant_storage_bucket(\n      t.id,\n      t.company_slug,\n      coalesce(t.company_dba_name,t.company_legal_name,t.name),\n      coalesce(t.settings,'{}'::jsonb)\n    )\n  )\n  from public.tenants t\n  where t.id=p_tenant_id\n  limit 1\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"mail_continuity_edge_request","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.mail_continuity_edge_request()\n RETURNS bigint\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'private', 'vault', 'net'\nAS $function$\ndeclare\n  v_token text;\n  v_request_id bigint;\nbegin\n  select decrypted_secret into v_token from vault.decrypted_secrets where name='knocklaunch_mail_continuity_trigger' limit 1;\n  if v_token is null then raise exception 'mail_continuity_trigger_secret_missing'; end if;\n  select net.http_post(\n    url:='https://ymntrajfubicyxwwdxxa.supabase.co/functions/v1/mail-continuity',\n    body:='{\"action\":\"health_tick\",\"source\":\"pg_cron\"}'::jsonb,\n    headers:=jsonb_build_object('Content-Type','application/json','x-mail-continuity-token',v_token),\n    timeout_milliseconds:=10000\n  ) into v_request_id;\n  return v_request_id;\nend;\n$function$\n","identity_arguments":""},{"name":"modes_storage_edge_request","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.modes_storage_edge_request(p_tenant_id uuid DEFAULT NULL::uuid)\n RETURNS bigint\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'private', 'vault', 'net', 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_token text;\n  v_request_id bigint;\n  v_scope_key text := case when p_tenant_id is null then 'all-tenants' else 'tenant:' || p_tenant_id::text end;\n  v_cooldown_seconds integer := case when p_tenant_id is null then 1800 else 300 end;\n  v_now timestamptz := clock_timestamp();\n  v_last_dispatched_at timestamptz;\n  v_last_blocked_at timestamptz;\n  v_retry_after_seconds integer;\nbegin\n  -- Collapse concurrent copies immediately instead of making them wait and fan out.\n  if not pg_try_advisory_xact_lock(hashtextextended('modes-storage-egress-guard:' || v_scope_key, 0)) then\n    return 0;\n  end if;\n\n  insert into private.modes_storage_reconcile_guard(scope_key, updated_at)\n  values (v_scope_key, v_now)\n  on conflict (scope_key) do nothing;\n\n  select last_dispatched_at, last_blocked_at\n    into v_last_dispatched_at, v_last_blocked_at\n    from private.modes_storage_reconcile_guard\n   where scope_key = v_scope_key\n   for update;\n\n  if v_last_dispatched_at is not null\n     and v_now < v_last_dispatched_at + make_interval(secs => v_cooldown_seconds) then\n    v_retry_after_seconds := greatest(\n      1,\n      ceil(extract(epoch from ((v_last_dispatched_at + make_interval(secs => v_cooldown_seconds)) - v_now)))::integer\n    );\n\n    -- Emit at most one loud notice per cooldown window. Do not create a second log storm.\n    if v_last_blocked_at is null\n       or v_now >= v_last_blocked_at + make_interval(secs => v_cooldown_seconds) then\n      update private.modes_storage_reconcile_guard\n         set last_blocked_at = v_now,\n             last_reason = 'automatic_modes_reconcile_debounced',\n             blocked_notice_count = blocked_notice_count + 1,\n             updated_at = v_now\n       where scope_key = v_scope_key;\n\n      raise warning 'SUPABASE_EGRESS_SAFETY_STOP scope=% reason=automatic_modes_reconcile_debounced retry_after_seconds=% cached_egress_ceiling_gb=250',\n        v_scope_key, v_retry_after_seconds;\n    end if;\n\n    return 0;\n  end if;\n\n  update private.modes_storage_reconcile_guard\n     set last_dispatched_at = v_now,\n         last_reason = null,\n         updated_at = v_now\n   where scope_key = v_scope_key;\n\n  select decrypted_secret into v_token\n    from vault.decrypted_secrets\n   where name = 'knocklaunch_modes_storage_reconcile_trigger'\n   limit 1;\n\n  if v_token is null then\n    raise exception 'modes_storage_reconcile_secret_missing';\n  end if;\n\n  select net.http_post(\n    url := 'https://ymntrajfubicyxwwdxxa.supabase.co/functions/v1/tenant-media-library',\n    body := jsonb_strip_nulls(jsonb_build_object('action','reconcile_modes_internal','tenantId',p_tenant_id)),\n    headers := jsonb_build_object(\n      'Content-Type','application/json',\n      'x-modes-storage-token',v_token,\n      'x-knocklaunch-egress-guard','automatic-admitted'\n    ),\n    timeout_milliseconds := 30000\n  ) into v_request_id;\n\n  return v_request_id;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"next_card_grading_cert_number","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.next_card_grading_cert_number(p_tenant_id uuid, p_grader_user_id uuid)\n RETURNS text\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'private', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_prefix smallint;\n  v_suffix integer;\n  v_candidate text;\nbegin\n  if auth.uid() is null or not (\n    public.is_system_admin(auth.uid())\n    or exists (\n      select 1\n      from public.security_active_user_tenant_memberships m\n      where m.user_id=auth.uid()\n        and m.tenant_id=p_tenant_id\n        and m.status='active'\n    )\n  ) then\n    raise exception 'Card grading workspace access required' using errcode='42501';\n  end if;\n  -- PCG slabs already have printed numbers; this allocator is never valid for PCG.\n  if p_tenant_id = '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid then\n    raise exception 'pcg_physical_slab_cert_required_no_generation';\n  end if;\n\n  select a.cert_prefix\n    into v_prefix\n  from public.card_grading_cert_prefix_assignments a\n  where a.tenant_id=p_tenant_id\n    and a.grader_user_id=p_grader_user_id\n    and a.active=true;\n\n  if v_prefix is null then\n    raise exception 'No PCG cert prefix is assigned to this grader';\n  end if;\n\n  insert into private.card_grading_cert_counters(tenant_id,cert_prefix,next_suffix)\n  values (p_tenant_id,v_prefix,1)\n  on conflict (tenant_id,cert_prefix) do nothing;\n\n  select c.next_suffix\n    into v_suffix\n  from private.card_grading_cert_counters c\n  where c.tenant_id=p_tenant_id and c.cert_prefix=v_prefix\n  for update;\n\n  while v_suffix <= 9999 loop\n    v_candidate := v_prefix::text || lpad(v_suffix::text,4,'0');\n\n    if not exists (\n      select 1 from public.card_grading_cards c\n      where c.tenant_id=p_tenant_id and c.cert_number=v_candidate\n    )\n    and not exists (\n      select 1 from public.card_grading_certificates cc\n      where cc.tenant_id=p_tenant_id and cc.cert_number=v_candidate\n    )\n    and not exists (\n      select 1 from public.pcg_import_rows r\n      where r.tenant_id=p_tenant_id\n        and (r.normalized_payload->>'cert_number') ~ '^0[0-9]{4}$'\n        and right(r.normalized_payload->>'cert_number',4)=right(v_candidate,4)\n    ) then\n      update private.card_grading_cert_counters\n         set next_suffix=v_suffix+1, updated_at=now()\n       where tenant_id=p_tenant_id and cert_prefix=v_prefix;\n      return v_candidate;\n    end if;\n\n    v_suffix := v_suffix + 1;\n  end loop;\n\n  raise exception 'PCG cert range %xxxx is exhausted', v_prefix;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_grader_user_id uuid"},{"name":"paul_scheduler_edge_request","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.paul_scheduler_edge_request()\n RETURNS bigint\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'private', 'vault', 'net'\nAS $function$\ndeclare v_token text; v_request_id bigint;\nbegin\n  select decrypted_secret into v_token from vault.decrypted_secrets where name='knocklaunch_paul_scheduler_trigger' limit 1;\n  if v_token is null then raise exception 'paul_scheduler_trigger_secret_missing'; end if;\n  select net.http_post(\n    url:='https://ymntrajfubicyxwwdxxa.supabase.co/functions/v1/paul-scheduler',\n    body:=jsonb_build_object('action','dispatch_due'),\n    headers:=jsonb_build_object('Content-Type','application/json','x-paul-scheduler-token',v_token),\n    timeout_milliseconds:=120000\n  ) into v_request_id;\n  return v_request_id;\nend;\n$function$\n","identity_arguments":""},{"name":"profile_authority_unchanged","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.profile_authority_unchanged(_user_id uuid, _role text, _tenant_org_id text)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select exists (\n    select 1 from public.profiles p\n    where p.id = _user_id\n      and p.role is not distinct from _role\n      and p.tenant_org_id is not distinct from _tenant_org_id\n  );\n$function$\n","identity_arguments":"_user_id uuid, _role text, _tenant_org_id text"},{"name":"prune_call_lifecycle_debug_events","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.prune_call_lifecycle_debug_events(_retention interval DEFAULT '7 days'::interval)\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_catalog'\nAS $function$\ndeclare\n  deleted_count integer := 0;\nbegin\n  if _retention is null or _retention < interval '1 day' then\n    raise exception 'call_lifecycle_debug_retention_too_small';\n  end if;\n\n  delete from public.call_lifecycle_events\n   where created_at < now() - _retention\n     and (\n       event = 'auth.event'\n       or event like 'refresh_blackbox.%'\n     );\n\n  get diagnostics deleted_count = row_count;\n  return deleted_count;\nend;\n$function$\n","identity_arguments":"_retention interval"},{"name":"seed_mail_continuity_from_email_setup","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.seed_mail_continuity_from_email_setup()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'private', 'auth'\nAS $function$\ndeclare\n  v_business text;\n  v_owner_id uuid;\n  v_fallback text;\n  v_confirmed timestamptz;\nbegin\n  if new.channel <> 'email' then return new; end if;\n  select lower(btrim(coalesce(new.requested_value,t.company_email,''))), t.owner_id\n    into v_business, v_owner_id\n  from public.tenants t where t.id=new.tenant_id;\n  if v_business is null or v_business='' then return new; end if;\n  select lower(btrim(u.email)), u.email_confirmed_at into v_fallback, v_confirmed\n  from auth.users u where u.id=v_owner_id;\n  insert into public.tenant_mail_continuity(\n    tenant_id,business_email,fallback_email,fallback_identity_verified_at,\n    desired_mode,effective_mode,activation_reason,mail_launched,updated_at\n  ) values (\n    new.tenant_id,v_business,\n    case when v_confirmed is not null and v_fallback is not null and v_fallback<>v_business then v_fallback else null end,\n    case when v_confirmed is not null and v_fallback is not null and v_fallback<>v_business then v_confirmed else null end,\n    'prelaunch','normal','mail_not_launched',false,now()\n  )\n  on conflict (tenant_id,business_email) do update set\n    fallback_email=case when excluded.fallback_email is not null then excluded.fallback_email else public.tenant_mail_continuity.fallback_email end,\n    fallback_identity_verified_at=case when excluded.fallback_email is not null then excluded.fallback_identity_verified_at else public.tenant_mail_continuity.fallback_identity_verified_at end,\n    updated_at=now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"sync_mail_continuity_mailbox","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.sync_mail_continuity_mailbox()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'private'\nAS $function$\nbegin\n  insert into public.tenant_mail_continuity(\n    tenant_id,business_email,provider_account_id,mailbox_ready,mail_launched,\n    desired_mode,effective_mode,activation_reason,updated_at\n  ) values (\n    new.tenant_org_id,lower(btrim(new.email_address)),new.account_key,new.status='active',false,\n    'prelaunch','normal','mail_not_launched',now()\n  )\n  on conflict (tenant_id,business_email) do update set\n    provider_account_id=excluded.provider_account_id,\n    mailbox_ready=excluded.mailbox_ready,\n    updated_at=now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"system_backup_assert_recent_verified","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.system_backup_assert_recent_verified(p_max_age interval DEFAULT '36:00:00'::interval)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'private'\nAS $function$\ndeclare\n  v_health jsonb;\nbegin\n  v_health := private.system_backup_health(p_max_age);\n  if coalesce((v_health->>'healthy')::boolean,false) is not true then\n    raise exception 'recent_verified_system_backup_required' using detail=v_health::text;\n  end if;\nend;\n$function$\n","identity_arguments":"p_max_age interval"},{"name":"system_backup_edge_request","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.system_backup_edge_request(p_action text, p_reason text DEFAULT NULL::text, p_source_main_sha text DEFAULT NULL::text, p_force boolean DEFAULT false)\n RETURNS bigint\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'private', 'vault', 'net'\nAS $function$\ndeclare\n  v_token text;\n  v_request_id bigint;\nbegin\n  select decrypted_secret\n  into v_token\n  from vault.decrypted_secrets\n  where name='knocklaunch_system_backup_trigger'\n  limit 1;\n\n  if v_token is null then\n    raise exception 'system_backup_trigger_secret_missing';\n  end if;\n\n  select net.http_post(\n    url:='https://ymntrajfubicyxwwdxxa.supabase.co/functions/v1/system-backup',\n    body:=jsonb_build_object(\n      'action',coalesce(nullif(trim(p_action),''),'resume'),\n      'reason',coalesce(nullif(trim(p_reason),''),'scheduled'),\n      'sourceMainSha',nullif(trim(coalesce(p_source_main_sha,'')),''),\n      'force',coalesce(p_force,false)\n    ),\n    headers:=jsonb_build_object(\n      'Content-Type','application/json',\n      'x-backup-token',v_token\n    ),\n    timeout_milliseconds:=120000\n  )\n  into v_request_id;\n\n  return v_request_id;\nend;\n$function$\n","identity_arguments":"p_action text, p_reason text, p_source_main_sha text, p_force boolean"},{"name":"system_backup_edge_request_at_local_hour","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.system_backup_edge_request_at_local_hour(p_local_hour integer, p_action text DEFAULT 'start'::text, p_reason text DEFAULT 'daily'::text, p_source_main_sha text DEFAULT NULL::text, p_force boolean DEFAULT false)\n RETURNS bigint\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'private'\nAS $function$\ndeclare\n  v_local timestamp;\nbegin\n  if p_local_hour < 0 or p_local_hour > 23 then\n    raise exception 'system_backup_local_hour_invalid';\n  end if;\n  v_local := now() at time zone 'America/New_York';\n  if extract(hour from v_local)::integer <> p_local_hour then\n    return null;\n  end if;\n  return private.system_backup_edge_request(p_action,p_reason,p_source_main_sha,p_force);\nend;\n$function$\n","identity_arguments":"p_local_hour integer, p_action text, p_reason text, p_source_main_sha text, p_force boolean"},{"name":"system_backup_health","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.system_backup_health(p_max_age interval DEFAULT '36:00:00'::interval)\n RETURNS jsonb\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public', 'private'\nAS $function$\n  with latest as (\n    select id,status,requested_at,completed_at,failed_items,manifest_key,metadata,error\n    from public.system_backup_runs\n    order by requested_at desc\n    limit 1\n  ), success as (\n    select id,completed_at,failed_items,manifest_key,metadata\n    from public.system_backup_runs\n    where status='completed'\n      and failed_items=0\n      and manifest_key is not null\n      and coalesce((metadata->>'verified')::boolean,false)=true\n    order by completed_at desc\n    limit 1\n  )\n  select jsonb_build_object(\n    'healthy', exists(select 1 from success where completed_at >= now()-p_max_age),\n    'maxAgeSeconds', extract(epoch from p_max_age)::bigint,\n    'lastSuccessfulRunId', (select id from success),\n    'lastSuccessfulAt', (select completed_at from success),\n    'latestRunId', (select id from latest),\n    'latestStatus', (select status from latest),\n    'latestError', (select error from latest)\n  );\n$function$\n","identity_arguments":"p_max_age interval"},{"name":"throttle_membership_access_touch","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.throttle_membership_access_touch()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nbegin\n  if (to_jsonb(new) - 'last_accessed_at') is not distinct from\n     (to_jsonb(old) - 'last_accessed_at')\n     and coalesce(old.last_accessed_at, '-infinity'::timestamptz) >= now() - interval '15 minutes'\n  then return null;\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"throttle_profile_login_touch","schema":"private","definition":"CREATE OR REPLACE FUNCTION private.throttle_profile_login_touch()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nbegin\n  if (to_jsonb(new) - 'last_login' - 'last_login_at') is not distinct from\n     (to_jsonb(old) - 'last_login' - 'last_login_at')\n     and greatest(\n       coalesce(old.last_login_at, '-infinity'::timestamptz),\n       coalesce(old.last_login, '-infinity'::timestamptz)\n     ) >= now() - interval '15 minutes'\n  then return null;\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"_can_view_claim_payment_status","schema":"public","definition":"CREATE OR REPLACE FUNCTION public._can_view_claim_payment_status(_tenant uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  SELECT public.is_system_admin(auth.uid()) OR EXISTS (SELECT 1 FROM public.user_tenant_memberships m\n    LEFT JOIN public.user_roles ur ON ur.user_id=m.user_id AND ur.tenant_id=m.tenant_id\n    WHERE m.user_id=auth.uid() AND m.tenant_id=_tenant AND m.status='active'\n      AND (m.is_owner=true OR ur.role::text IN ('Owner','Tenant Owner','Admin','Manager','PM','GodMode')));\n$function$\n","identity_arguments":"_tenant uuid"},{"name":"_classify_trigger","schema":"public","definition":"CREATE OR REPLACE FUNCTION public._classify_trigger(_name text, _fn text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  SELECT CASE\n    WHEN _fn = 'update_updated_at_column' OR _name ILIKE '%updated_at%' THEN 'timestamp'\n    WHEN _fn ILIKE '%audit%' OR _name ILIKE '%audit%' THEN 'audit'\n    WHEN _fn ILIKE '%dnc%' OR _fn ILIKE '%quarantine%' OR _fn ILIKE '%compliance%' OR _fn ILIKE '%prevent_%' THEN 'security'\n    WHEN _fn ILIKE 'auto_%' OR _fn ILIKE '%automation%' OR _fn ILIKE '%dispatch%' OR _fn ILIKE '%send_%' OR _fn ILIKE '%notify%' OR _fn ILIKE '%enqueue%' OR _fn ILIKE '%propagate%' OR _fn ILIKE '%sync%' THEN 'automation'\n    ELSE 'business'\n  END;\n$function$\n","identity_arguments":"_name text, _fn text"},{"name":"_is_admin_caller","schema":"public","definition":"CREATE OR REPLACE FUNCTION public._is_admin_caller()\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$ SELECT public.is_system_admin(auth.uid()); $function$\n","identity_arguments":""},{"name":"_is_manager_or_higher_in_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public._is_manager_or_higher_in_tenant(_tenant uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  SELECT public.is_manager_or_higher(auth.uid(), _tenant);\n$function$\n","identity_arguments":"_tenant uuid"},{"name":"aaa_validate_tenant_org_id_fn","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.aaa_validate_tenant_org_id_fn()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  -- Allow service role / migrations to bypass (no JWT)\n  IF auth.uid() IS NULL THEN\n    RETURN NEW;\n  END IF;\n\n  -- On UPDATE, only validate when tenant_org_id actually changes\n  IF TG_OP = 'UPDATE' AND NEW.tenant_org_id IS NOT DISTINCT FROM OLD.tenant_org_id THEN\n    RETURN NEW;\n  END IF;\n\n  IF NEW.tenant_org_id IS NULL OR NEW.tenant_org_id = '' THEN\n    RAISE EXCEPTION 'unified_contacts.tenant_org_id is required for authenticated writes'\n      USING ERRCODE = 'check_violation';\n  END IF;\n\n  IF NOT EXISTS (\n    SELECT 1 FROM public.tenant_organizations t\n    WHERE t.id::text = NEW.tenant_org_id\n  ) THEN\n    RAISE EXCEPTION 'unified_contacts.tenant_org_id % does not match any tenant_organizations row', NEW.tenant_org_id\n      USING ERRCODE = 'foreign_key_violation';\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"academy_course_completion_status","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.academy_course_completion_status(_user_id uuid, _course_id uuid)\n RETURNS TABLE(total_lessons integer, completed_lessons integer, progress_percent integer)\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  WITH authorized AS (\n    SELECT (\n      coalesce(auth.role(), '') = 'service_role'\n      OR auth.uid() = _user_id\n      OR public.is_system_admin(auth.uid())\n      OR public.can_view_tenant_member_academy(auth.uid(), _user_id)\n    ) AS ok\n  ),\n  course_lessons AS (\n    SELECT l.id\n    FROM public.academy_units u\n    JOIN public.academy_lessons l ON l.unit_id = u.id\n    WHERE u.course_id = _course_id\n  ),\n  counted AS (\n    SELECT count(*)::int AS total_lessons,\n           count(p.lesson_id)::int AS completed_lessons\n    FROM course_lessons cl\n    LEFT JOIN public.academy_trainee_progress p\n      ON p.lesson_id = cl.id\n     AND p.course_id = _course_id\n     AND p.user_id = _user_id\n     AND p.status = 'completed'\n  )\n  SELECT c.total_lessons,\n         c.completed_lessons,\n         CASE WHEN c.total_lessons = 0 THEN 0\n              ELSE round((c.completed_lessons::numeric / c.total_lessons::numeric) * 100)::int\n         END\n  FROM counted c, authorized a\n  WHERE a.ok;\n$function$\n","identity_arguments":"_user_id uuid, _course_id uuid"},{"name":"academy_course_visible","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.academy_course_visible(p_tenant_org_id text, p_is_published boolean)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  select coalesce(p_is_published,false) and (\n    p_tenant_org_id='00000000-0000-0000-0000-000000000000'\n    or public.is_tenant_member(p_tenant_org_id)\n    or public.is_system_admin(auth.uid())\n  )\n$function$\n","identity_arguments":"p_tenant_org_id text, p_is_published boolean"},{"name":"academy_issue_certificate","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.academy_issue_certificate(_user_id uuid, _course_id uuid, _tenant_org_id text DEFAULT NULL::text, _source text DEFAULT 'course_completion'::text)\n RETURNS uuid\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$ WITH v_course AS (SELECT * FROM public.academy_courses WHERE id = _course_id), v_status AS (SELECT * FROM public.academy_course_completion_status(_user_id, _course_id)), upserted AS (INSERT INTO public.academy_certificates (tenant_org_id, user_id, course_id, certificate_title, score, issued_by, metadata) SELECT COALESCE(_tenant_org_id, c.tenant_org_id), _user_id, _course_id, COALESCE(c.certificate_title, c.title || ' Certificate'), s.progress_percent, auth.uid(), jsonb_build_object('source', _source, 'total_lessons', s.total_lessons, 'completed_lessons', s.completed_lessons, 'course_scope', c.scope, 'tenant_track', c.tenant_track, 'issued_from', 'academy_v2_foundation') FROM v_course c CROSS JOIN v_status s WHERE (auth.uid() = _user_id OR public.is_tenant_owner_for(auth.uid(), COALESCE(_tenant_org_id, c.tenant_org_id)) OR public.is_system_admin(auth.uid())) AND COALESCE(s.total_lessons, 0) > 0 AND COALESCE(s.progress_percent, 0) = 100 ON CONFLICT (tenant_org_id, user_id, course_id) DO UPDATE SET score = EXCLUDED.score, certificate_title = EXCLUDED.certificate_title, metadata = EXCLUDED.metadata, issued_at = now() RETURNING id), rec_user AS (INSERT INTO public.academy_certificate_recipients (certificate_id, recipient_role, recipient_user_id) SELECT u.id, 'user', _user_id FROM upserted u CROSS JOIN v_course c WHERE COALESCE(c.certificate_email_user, true) ON CONFLICT DO NOTHING RETURNING id), rec_owner AS (INSERT INTO public.academy_certificate_recipients (certificate_id, recipient_role) SELECT u.id, 'tenant_owner' FROM upserted u CROSS JOIN v_course c WHERE COALESCE(c.certificate_email_owner, true) ON CONFLICT DO NOTHING RETURNING id) SELECT id FROM upserted $function$\n","identity_arguments":"_user_id uuid, _course_id uuid, _tenant_org_id text, _source text"},{"name":"academy_track_for_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.academy_track_for_tenant(p_tenant_id uuid)\n RETURNS text\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_type text;\n  v_uid uuid := auth.uid();\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       v_uid IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(v_uid), false)\n         AND NOT coalesce(public.is_tenant_member(v_uid, p_tenant_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'academy tenant access denied' USING ERRCODE = '42501';\n  END IF;\n\n  SELECT coalesce(t.tenant_type, o.tenant_type)\n    INTO v_type\n  FROM public.tenants t\n  LEFT JOIN public.tenant_organizations o ON o.id = t.id\n  WHERE t.id = p_tenant_id;\n\n  IF v_type IS NULL THEN\n    SELECT tenant_type INTO v_type\n    FROM public.tenant_organizations\n    WHERE id = p_tenant_id;\n  END IF;\n\n  RETURN public.academy_track_for_type(v_type);\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"academy_track_for_type","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.academy_track_for_type(p_tenant_type text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  select case\n    when upper(coalesce(p_tenant_type,'')) in ('MITIGATION','WATER_MITIGATION','TARPING') then 'mitigation'\n    when upper(coalesce(p_tenant_type,'')) in ('ROOFING','ROOFER','ROOFING_COMPANY','GENERAL_CONTRACTOR','HYBRID_CONTRACTOR','CONTRACTOR') then 'roofing'\n    when upper(coalesce(p_tenant_type,'')) in ('PUBLIC_ADJUSTER','PUBLIC_ADJUSTER_FIRM','PA') then 'public_adjuster'\n    when upper(coalesce(p_tenant_type,'')) in ('REALTOR','REAL_ESTATE','REAL_ESTATE_AGENT') then 'realtor'\n    when upper(coalesce(p_tenant_type,'')) in ('LAWN_CARE','LANDSCAPING') then 'lawn_care'\n    else 'universal'\n  end\n$function$\n","identity_arguments":"p_tenant_type text"},{"name":"activate_proposal_operating_contract","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.activate_proposal_operating_contract(p_proposal_id uuid, p_signed_agreement_id uuid, p_pending_agreement_id uuid DEFAULT NULL::uuid, p_signed_pdf_path text DEFAULT NULL::text, p_signed_at timestamp with time zone DEFAULT now())\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_contract public.proposal_operating_contracts%rowtype;\n  v_owner_proposal_id uuid;\n  v_signed_at timestamptz:=coalesce(p_signed_at,now());\n  v_settings_entry jsonb;\nbegin\n  select * into v_contract from public.proposal_operating_contracts where proposal_id=p_proposal_id for update;\n  if not found then raise exception 'proposal_operating_contract_not_found'; end if;\n  if v_contract.signed_agreement_id is not null and v_contract.lifecycle_status='activated' then return v_contract.id; end if;\n\n  update public.proposals set status='accepted',accepted_at=coalesce(accepted_at,v_signed_at),updated_at=now()\n  where id=p_proposal_id and current_version=v_contract.proposal_version and status not in ('declined','void');\n  if not found then raise exception 'proposal_version_or_status_not_activatable'; end if;\n\n  update public.proposal_operating_contracts set lifecycle_status='activated',pending_agreement_id=coalesce(p_pending_agreement_id,pending_agreement_id),signed_agreement_id=p_signed_agreement_id,signed_pdf_path=coalesce(p_signed_pdf_path,signed_pdf_path),signed_at=coalesce(signed_at,v_signed_at),accepted_at=coalesce(accepted_at,v_signed_at),activated_at=coalesce(activated_at,v_signed_at),updated_at=now() where id=v_contract.id;\n\n  update public.proposal_operating_commitments set status=case when status='proposed' then 'active' else status end,activated_at=coalesce(activated_at,v_signed_at),review_at=coalesce(review_at,case when coalesce((terms->>'offset_days')::integer,0)>0 then v_signed_at+make_interval(days=>(terms->>'offset_days')::integer) else null end),updated_at=now() where contract_id=v_contract.id;\n\n  insert into public.proposal_operating_contract_events(contract_id,proposal_id,event_type,source_type,source_id,event_data,occurred_at,dedupe_key) values\n  (v_contract.id,p_proposal_id,'received','signed_agreement',p_signed_agreement_id::text,jsonb_build_object('pending_agreement_id',p_pending_agreement_id,'signed_pdf_path',p_signed_pdf_path),v_signed_at,v_contract.id::text||':received'),\n  (v_contract.id,p_proposal_id,'accepted','signed_agreement',p_signed_agreement_id::text,'{}'::jsonb,v_signed_at,v_contract.id::text||':accepted'),\n  (v_contract.id,p_proposal_id,'activated','signed_agreement',p_signed_agreement_id::text,'{}'::jsonb,v_signed_at,v_contract.id::text||':activated') on conflict(dedupe_key) do nothing;\n\n  select id into v_owner_proposal_id from public.owner_relationship_proposals where canonical_proposal_id=p_proposal_id order by version desc limit 1;\n  if v_owner_proposal_id is not null then\n    update public.owner_relationship_proposals set status='accepted',accepted_at=coalesce(accepted_at,v_signed_at),updated_at=now() where id=v_owner_proposal_id and status not in ('declined','superseded');\n    update public.owner_compensation_terms set status='active',effective_start=coalesce(effective_start,v_signed_at::date),updated_at=now() where proposal_id=v_owner_proposal_id and status='proposed';\n  end if;\n\n  insert into public.owner_relationship_followups(relationship_id,tenant_id,title,due_at,status,related_proposal_id,metadata)\n  select rp.relationship_id,rp.tenant_id,c.title,c.review_at,'open',rp.id,jsonb_build_object('proposal_operating_contract_id',v_contract.id,'proposal_commitment_id',c.id,'source','accepted_proposal')\n  from public.proposal_operating_commitments c join public.owner_relationship_proposals rp on rp.id=v_owner_proposal_id\n  where c.contract_id=v_contract.id and c.party_role in ('issuer','shared') and c.review_at is not null\n    and not exists(select 1 from public.owner_relationship_followups f where f.metadata->>'proposal_commitment_id'=c.id::text);\n\n  insert into public.tasks(tenant_id,user_id,assigned_to,title,description,priority,status,due_date,metadata)\n  select c.responsible_tenant_id::text,u.user_id,u.user_id,c.title,c.description,'medium','pending',coalesce(c.due_at,c.review_at),\n    jsonb_build_object('proposal_id',c.proposal_id,'proposal_version',c.proposal_version,'proposal_operating_contract_id',v_contract.id,'proposal_commitment_id',c.id,'party_role',c.party_role,'category',c.category,'cadence',c.cadence,'source','accepted_proposal','source_kind','accepted_proposal_commitment','source_id',c.id::text)\n  from public.proposal_operating_commitments c\n  join lateral (\n    select vu.user_id from public.v_active_tenant_users vu\n    where vu.tenant_id=c.responsible_tenant_id and coalesce(vu.is_owner,false)=true and coalesce(vu.profile_active,true)=true and coalesce(vu.membership_status,'active')='active'\n    order by vu.joined_at nulls last,vu.user_id limit 1\n  ) u on true\n  where c.contract_id=v_contract.id and c.status='active' and c.responsible_tenant_id is not null\n    and not exists(select 1 from public.tasks t where t.source_kind='accepted_proposal_commitment' and t.source_id=c.id::text);\n\n  v_settings_entry:=jsonb_build_object('proposalId',p_proposal_id,'contractId',v_contract.id,'status','active','proposalVersion',v_contract.proposal_version,'activatedAt',v_signed_at);\n  update public.tenants set settings=jsonb_set(coalesce(settings,'{}'::jsonb),'{operating_contracts}',coalesce(settings->'operating_contracts','{}'::jsonb)||jsonb_build_object(v_contract.id::text,v_settings_entry||jsonb_build_object('role',case when id=v_contract.issuer_tenant_id then 'issuer' else 'acceptor' end,'counterpartyTenantId',case when id=v_contract.issuer_tenant_id then v_contract.acceptor_tenant_id else v_contract.issuer_tenant_id end)),true)\n  where id=v_contract.issuer_tenant_id or id=v_contract.acceptor_tenant_id;\n  return v_contract.id;\nend;\n$function$\n","identity_arguments":"p_proposal_id uuid, p_signed_agreement_id uuid, p_pending_agreement_id uuid, p_signed_pdf_path text, p_signed_at timestamp with time zone"},{"name":"activate_proposal_operating_contract_from_signed_agreement","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.activate_proposal_operating_contract_from_signed_agreement()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_vars jsonb := coalesce(new.metadata->'source_variables', '{}'::jsonb);\n  v_proposal_id_text text;\n  v_proposal_id uuid;\n  v_contract public.proposal_operating_contracts%rowtype;\n  v_pending_id_text text;\n  v_pending_id uuid;\n  v_filled_pdf_path text;\n  v_pending public.pending_agreements%rowtype;\nbegin\n  if lower(coalesce(v_vars->>'PROPOSAL_OPERATING_CONTRACT', v_vars->>'proposal_operating_contract', '')) not in ('true', '1', 'yes') then\n    return new;\n  end if;\n\n  if coalesce(new.esign_consent, false) is not true then\n    raise exception 'proposal_operating_contract_esign_consent_required';\n  end if;\n\n  v_proposal_id_text := coalesce(v_vars->>'PROPOSAL_ID', v_vars->>'proposal_id', '');\n  if v_proposal_id_text !~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$' then\n    raise exception 'proposal_operating_contract_proposal_id_invalid';\n  end if;\n  v_proposal_id := v_proposal_id_text::uuid;\n\n  select * into v_contract\n  from public.proposal_operating_contracts\n  where proposal_id = v_proposal_id;\n  if not found then\n    raise exception 'proposal_operating_contract_not_found';\n  end if;\n  if new.tenant_id is distinct from v_contract.issuer_tenant_id then\n    raise exception 'proposal_operating_contract_issuer_mismatch';\n  end if;\n  if coalesce(v_vars->>'PROPOSAL_VERSION', v_vars->>'proposal_version', '') <> v_contract.proposal_version::text then\n    raise exception 'proposal_operating_contract_version_mismatch';\n  end if;\n  if nullif(coalesce(v_vars->>'PROPOSAL_CONTRACT_ID', v_vars->>'proposal_contract_id', ''), '') is not null\n     and coalesce(v_vars->>'PROPOSAL_CONTRACT_ID', v_vars->>'proposal_contract_id', '') <> v_contract.id::text then\n    raise exception 'proposal_operating_contract_contract_id_mismatch';\n  end if;\n\n  v_pending_id_text := coalesce(new.metadata->>'pending_agreement_id', '');\n  if v_pending_id_text !~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$' then\n    raise exception 'proposal_operating_contract_pending_agreement_id_invalid';\n  end if;\n  v_pending_id := v_pending_id_text::uuid;\n\n  v_filled_pdf_path := nullif(btrim(coalesce(new.metadata->>'filled_pdf_path', '')), '');\n  if v_filled_pdf_path is null then\n    raise exception 'proposal_operating_contract_signed_pdf_required';\n  end if;\n\n  select * into v_pending\n  from public.pending_agreements\n  where id = v_pending_id;\n  if not found then\n    raise exception 'proposal_operating_contract_pending_agreement_not_found';\n  end if;\n  if v_pending.tenant_id is distinct from v_contract.issuer_tenant_id then\n    raise exception 'proposal_operating_contract_pending_agreement_tenant_mismatch';\n  end if;\n  if v_pending.status <> 'signed'\n     or coalesce(v_pending.signed_pdf_status, '') <> 'ready'\n     or v_pending.signed_pdf_path is distinct from v_filled_pdf_path then\n    raise exception 'proposal_operating_contract_signed_pdf_not_ready';\n  end if;\n  if lower(coalesce(v_pending.completed_fields->>'esign_consent', '')) <> 'true' then\n    raise exception 'proposal_operating_contract_server_consent_required';\n  end if;\n\n  perform public.activate_proposal_operating_contract(\n    v_proposal_id,\n    new.id,\n    v_pending_id,\n    v_filled_pdf_path,\n    new.signed_at\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"activity_timeline_normalize_insert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.activity_timeline_normalize_insert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nbegin\n  new.event_domain := coalesce(nullif(btrim(new.event_domain), ''), 'activity');\n  if nullif(btrim(coalesce(new.source_channel, '')), '') is not null then\n    new.source_channel := public.normalize_business_source(new.source_channel, coalesce(new.metadata, '{}'::jsonb));\n  end if;\n  new.touch_channel := nullif(btrim(coalesce(new.touch_channel, '')), '');\n  new.currency := upper(coalesce(nullif(btrim(new.currency), ''), 'USD'));\n  new.source_system := coalesce(nullif(btrim(new.source_system), ''), 'knocklaunch');\n  new.recorded_at := coalesce(new.recorded_at, now());\n  if nullif(new.actor_role, '') is null and new.user_id is not null then\n    select ur.role::text into new.actor_role\n    from public.user_tenant_memberships m\n    join public.user_roles ur on ur.user_id = m.user_id and ur.tenant_id = m.tenant_id\n    where m.user_id = new.user_id and m.tenant_id = new.tenant_org_id and m.status = 'active'\n    order by m.is_owner desc nulls last, ur.assigned_at desc nulls last\n    limit 1;\n  end if;\n  new.actor_role := coalesce(new.actor_role, case when new.is_system_generated then 'system' else 'member' end);\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"add_platform_message_group_members","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.add_platform_message_group_members(p_conversation_id uuid, p_member_ids uuid[])\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if not public.can_manage_message_group(p_conversation_id,auth.uid()) then raise exception 'group_manage_denied'; end if;\n  insert into public.message_conversation_members(conversation_id,user_id,role)\n    select p_conversation_id,u,'member' from unnest(coalesce(p_member_ids,array[]::uuid[])) u\n    join public.profiles p on p.id=u and p.active is true\n    on conflict(conversation_id,user_id) do nothing;\n  update public.message_conversations set key_rotation_required=true,updated_at=now() where id=p_conversation_id;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_member_ids uuid[]"},{"name":"adjust_mobile_vendor_inventory","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.adjust_mobile_vendor_inventory(p_tenant_org_id uuid, p_item_id uuid, p_quantity_delta numeric, p_movement_type text, p_event_booking_id uuid DEFAULT NULL::uuid, p_note text DEFAULT NULL::text)\n RETURNS mobile_vendor_inventory_items\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\ndeclare\n  current_item public.mobile_vendor_inventory_items%rowtype;\n  updated_item public.mobile_vendor_inventory_items%rowtype;\n  next_quantity numeric(12,2);\nbegin\n  if p_quantity_delta is null or p_quantity_delta = 0 then\n    raise exception 'Inventory adjustment must be non-zero.';\n  end if;\n  if p_movement_type not in ('purchase','adjustment','event_usage','waste') then\n    raise exception 'Unsupported inventory movement type.';\n  end if;\n\n  select * into current_item\n  from public.mobile_vendor_inventory_items\n  where id = p_item_id and tenant_org_id = p_tenant_org_id\n  for update;\n\n  if not found then\n    raise exception 'Inventory item not found.';\n  end if;\n\n  if p_event_booking_id is not null and not exists (\n    select 1 from public.event_bookings\n    where id = p_event_booking_id\n      and tenant_org_id = p_tenant_org_id::text\n  ) then\n    raise exception 'Event booking does not belong to this workspace.';\n  end if;\n\n  next_quantity := current_item.quantity_on_hand + p_quantity_delta;\n  if next_quantity < 0 then\n    raise exception 'Inventory cannot go below zero.';\n  end if;\n\n  update public.mobile_vendor_inventory_items\n  set quantity_on_hand = next_quantity,\n      updated_at = now()\n  where id = current_item.id\n  returning * into updated_item;\n\n  insert into public.mobile_vendor_inventory_movements (\n    tenant_org_id, inventory_item_id, event_booking_id, movement_type,\n    quantity_delta, balance_after, unit_cost_snapshot, note, created_by, metadata\n  ) values (\n    p_tenant_org_id, current_item.id, p_event_booking_id, p_movement_type,\n    p_quantity_delta, next_quantity, current_item.unit_cost,\n    nullif(trim(coalesce(p_note, '')), ''), auth.uid(),\n    jsonb_build_object('inventory_version','v1')\n  );\n\n  return updated_item;\nend;\n$function$\n","identity_arguments":"p_tenant_org_id uuid, p_item_id uuid, p_quantity_delta numeric, p_movement_type text, p_event_booking_id uuid, p_note text"},{"name":"admin_list_db_triggers","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.admin_list_db_triggers()\n RETURNS TABLE(trigger_name text, table_name text, function_name text, event text, timing text, enabled boolean, enabled_state text, category text, definition text, function_source text)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_catalog'\nAS $function$\nBEGIN\n  IF NOT public._is_admin_caller() THEN\n    RAISE EXCEPTION 'admin only' USING ERRCODE = '42501';\n  END IF;\n\n  RETURN QUERY\n  SELECT\n    t.tgname::text                         AS trigger_name,\n    c.relname::text                        AS table_name,\n    p.proname::text                        AS function_name,\n    CASE\n      WHEN (t.tgtype::int & 4)  = 4  THEN 'INSERT'\n      WHEN (t.tgtype::int & 8)  = 8  THEN 'DELETE'\n      WHEN (t.tgtype::int & 16) = 16 THEN 'UPDATE'\n      WHEN (t.tgtype::int & 32) = 32 THEN 'TRUNCATE'\n      ELSE 'MULTI'\n    END                                     AS event,\n    CASE WHEN (t.tgtype::int & 2) = 2 THEN 'BEFORE' ELSE 'AFTER' END AS timing,\n    (t.tgenabled = 'O')                     AS enabled,\n    CASE t.tgenabled\n      WHEN 'O' THEN 'enabled'\n      WHEN 'D' THEN 'disabled'\n      WHEN 'R' THEN 'replica'\n      WHEN 'A' THEN 'always'\n    END                                     AS enabled_state,\n    public._classify_trigger(t.tgname::text, p.proname::text) AS category,\n    pg_get_triggerdef(t.oid)                AS definition,\n    pg_get_functiondef(p.oid)               AS function_source\n  FROM pg_trigger t\n  JOIN pg_class      c ON c.oid = t.tgrelid\n  JOIN pg_namespace  n ON n.oid = c.relnamespace\n  JOIN pg_proc       p ON p.oid = t.tgfoid\n  WHERE NOT t.tgisinternal\n    AND n.nspname = 'public'\n  ORDER BY c.relname, t.tgname;\nEND;\n$function$\n","identity_arguments":""},{"name":"admin_test_db_trigger","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.admin_test_db_trigger(_trigger_name text, _table_name text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_catalog'\nAS $function$\nDECLARE\n  v_event   text;\n  v_timing  text;\n  v_func    text;\n  v_started timestamptz := clock_timestamp();\n  v_fired   boolean := false;\n  v_error   text;\n  v_detail  text;\nBEGIN\n  IF NOT public._is_admin_caller() THEN\n    RAISE EXCEPTION 'admin only' USING ERRCODE = '42501';\n  END IF;\n\n  -- Look up trigger metadata\n  SELECT\n    CASE\n      WHEN (t.tgtype::int & 4)  = 4  THEN 'INSERT'\n      WHEN (t.tgtype::int & 8)  = 8  THEN 'DELETE'\n      WHEN (t.tgtype::int & 16) = 16 THEN 'UPDATE'\n      ELSE 'MULTI'\n    END,\n    CASE WHEN (t.tgtype::int & 2) = 2 THEN 'BEFORE' ELSE 'AFTER' END,\n    p.proname\n  INTO v_event, v_timing, v_func\n  FROM pg_trigger t\n  JOIN pg_class c     ON c.oid = t.tgrelid\n  JOIN pg_namespace n ON n.oid = c.relnamespace\n  JOIN pg_proc p      ON p.oid = t.tgfoid\n  WHERE n.nspname = 'public'\n    AND c.relname = _table_name\n    AND t.tgname  = _trigger_name\n    AND NOT t.tgisinternal;\n\n  IF v_event IS NULL THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'trigger not found');\n  END IF;\n\n  -- Wrap everything in a savepoint we always release/rollback\n  BEGIN\n    EXECUTE format(\n      'SAVEPOINT trig_test'\n    );\n\n    -- Synthetic operation: copy a row, mutate or insert, see if function ran.\n    -- We use a temporary marker row inserted then deleted inside the savepoint.\n    -- Detection: count tuples written to a per-session marker via temp table.\n    CREATE TEMP TABLE IF NOT EXISTS _trig_test_marker (fired boolean) ON COMMIT DROP;\n    DELETE FROM _trig_test_marker;\n\n    -- Call the trigger function in a controlled way using EXECUTE on the table.\n    -- We attempt event-appropriate no-op against an existing row when possible.\n    BEGIN\n      IF v_event = 'INSERT' THEN\n        EXECUTE format(\n          'INSERT INTO public.%I DEFAULT VALUES RETURNING true',\n          _table_name\n        );\n        v_fired := true;\n      ELSIF v_event = 'UPDATE' THEN\n        EXECUTE format(\n          'UPDATE public.%I SET %I = %I WHERE false',\n          _table_name,\n          (SELECT a.attname\n             FROM pg_attribute a\n             JOIN pg_class c ON c.oid = a.attrelid\n            WHERE c.relname = _table_name\n              AND a.attnum > 0\n              AND NOT a.attisdropped\n            ORDER BY a.attnum\n            LIMIT 1),\n          (SELECT a.attname\n             FROM pg_attribute a\n             JOIN pg_class c ON c.oid = a.attrelid\n            WHERE c.relname = _table_name\n              AND a.attnum > 0\n              AND NOT a.attisdropped\n            ORDER BY a.attnum\n            LIMIT 1)\n        );\n        -- WHERE false → no rows matched, but parser+planner validates the trigger wiring.\n        v_fired := true;\n      ELSIF v_event = 'DELETE' THEN\n        EXECUTE format('DELETE FROM public.%I WHERE false', _table_name);\n        v_fired := true;\n      ELSE\n        v_fired := false;\n        v_detail := 'multi-event trigger; manual review only';\n      END IF;\n    EXCEPTION WHEN OTHERS THEN\n      v_error := SQLERRM;\n      v_detail := SQLSTATE;\n    END;\n\n    -- ALWAYS roll back so production data is untouched\n    EXECUTE 'ROLLBACK TO SAVEPOINT trig_test';\n    EXECUTE 'RELEASE SAVEPOINT trig_test';\n  EXCEPTION WHEN OTHERS THEN\n    v_error := COALESCE(v_error, SQLERRM);\n  END;\n\n  RETURN jsonb_build_object(\n    'ok', v_error IS NULL,\n    'trigger', _trigger_name,\n    'table',   _table_name,\n    'event',   v_event,\n    'timing',  v_timing,\n    'function', v_func,\n    'fired',   v_fired,\n    'rolled_back', true,\n    'duration_ms', extract(milliseconds FROM clock_timestamp() - v_started)::int,\n    'error',   v_error,\n    'detail',  v_detail\n  );\nEND;\n$function$\n","identity_arguments":"_trigger_name text, _table_name text"},{"name":"advance_card_grading_submission","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.advance_card_grading_submission(p_tenant_id uuid, p_submission_id uuid, p_status text)\n RETURNS void\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nbegin\n  if p_status not in ('received','intake_imaging','authentication','grading','encapsulation','qa','ready','shipped','picked_up') then\n    raise exception 'Invalid grading status';\n  end if;\n\n  update public.card_grading_submissions\n     set status = p_status,\n         completed_at = case when p_status in ('shipped','picked_up') then now() else completed_at end,\n         updated_at = now()\n   where id = p_submission_id\n     and tenant_id = p_tenant_id;\n\n  if not found then\n    raise exception 'Submission unavailable';\n  end if;\n\n  update public.card_grading_cards\n     set status = p_status,\n         updated_at = now()\n   where submission_id = p_submission_id\n     and tenant_id = p_tenant_id;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_submission_id uuid, p_status text"},{"name":"advance_pcg_grading_submission","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.advance_pcg_grading_submission(p_tenant_id uuid, p_submission_id uuid, p_status text)\n RETURNS void\n LANGUAGE plpgsql\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_current_status text;\n  v_is_pcg boolean := false;\n  v_card_count integer := 0;\n  v_missing_count integer := 0;\n  v_tracking_out text;\n  v_allowed boolean := false;\nbegin\n  if current_user <> 'service_role' then\n    if auth.uid() is null or not public.is_tenant_member(p_tenant_id::text) then\n      raise exception 'PCG workspace access required' using errcode = '42501';\n    end if;\n  end if;\n\n  select coalesce(t.company_slug, '') = 'pcg'\n    into v_is_pcg\n  from public.tenants t\n  where t.id = p_tenant_id;\n  if not coalesce(v_is_pcg, false) then\n    raise exception 'PCG workspace required' using errcode = '42501';\n  end if;\n\n  select s.status, s.tracking_out\n    into v_current_status, v_tracking_out\n  from public.card_grading_submissions s\n  where s.id = p_submission_id and s.tenant_id = p_tenant_id;\n  if v_current_status is null then raise exception 'Submission unavailable'; end if;\n  if p_status = v_current_status then return; end if;\n  if p_status not in ('received','intake_imaging','authentication','grading','encapsulation','qa','ready','shipped','picked_up') then\n    raise exception 'Invalid grading status';\n  end if;\n\n  v_allowed := case v_current_status\n    when 'received' then p_status = 'intake_imaging'\n    when 'intake_imaging' then p_status = 'authentication'\n    when 'authentication' then p_status = 'grading'\n    when 'grading' then p_status = 'encapsulation'\n    when 'encapsulation' then p_status = 'qa'\n    when 'qa' then p_status = 'ready'\n    when 'ready' then p_status in ('shipped','picked_up')\n    else false\n  end;\n  if not v_allowed then raise exception 'PCG grading stages must advance in canonical order'; end if;\n\n  if exists (\n    select 1 from public.card_grading_exceptions e\n    where e.tenant_id = p_tenant_id\n      and e.status = 'open'\n      and e.kind in ('hold','escalation')\n      and (e.submission_id = p_submission_id or e.card_id in (\n        select c.id from public.card_grading_cards c\n        where c.tenant_id = p_tenant_id and c.submission_id = p_submission_id\n      ))\n  ) then\n    raise exception 'Resolve open hold or escalation before advancing this PCG order';\n  end if;\n\n  select count(*)::integer into v_card_count\n  from public.card_grading_cards c\n  where c.tenant_id = p_tenant_id and c.submission_id = p_submission_id;\n\n  if p_status in ('authentication','encapsulation','qa','ready') and v_card_count = 0 then\n    raise exception 'Add cards before advancing this PCG order';\n  end if;\n\n  if p_status = 'authentication' then\n    select count(*)::integer into v_missing_count\n    from public.card_grading_cards c\n    where c.tenant_id = p_tenant_id and c.submission_id = p_submission_id\n      and (nullif(btrim(coalesce(c.front_image_url,'')),'') is null\n        or nullif(btrim(coalesce(c.back_image_url,'')),'') is null);\n    if v_missing_count > 0 then\n      raise exception '% card(s) need saved front and back intake imagery before authentication', v_missing_count;\n    end if;\n  elsif p_status = 'encapsulation' then\n    select count(*)::integer into v_missing_count\n    from public.card_grading_cards c\n    where c.tenant_id = p_tenant_id and c.submission_id = p_submission_id and c.grade is null;\n    if v_missing_count > 0 then\n      raise exception '% card(s) need a saved grade before encapsulation', v_missing_count;\n    end if;\n  elsif p_status = 'qa' then\n    select count(*)::integer into v_missing_count\n    from public.card_grading_cards c\n    where c.tenant_id = p_tenant_id and c.submission_id = p_submission_id\n      and (c.grade is null or nullif(btrim(coalesce(c.cert_number,'')),'') is null);\n    if v_missing_count > 0 then\n      raise exception '% card(s) need a saved grade and Cert Number before QA', v_missing_count;\n    end if;\n  elsif p_status = 'ready' then\n    select count(*)::integer into v_missing_count\n    from public.card_grading_cards c\n    where c.tenant_id = p_tenant_id and c.submission_id = p_submission_id\n      and (\n        c.grade is null\n        or nullif(btrim(coalesce(c.cert_number,'')),'') is null\n        or nullif(btrim(coalesce(c.slab_image_url,'')),'') is null\n        or not exists (\n          select 1 from public.card_grading_qc_reviews q\n          where q.tenant_id = p_tenant_id and q.card_id = c.id and q.outcome = 'approved'\n            and q.reviewed_at = (\n              select max(q2.reviewed_at) from public.card_grading_qc_reviews q2\n              where q2.tenant_id = p_tenant_id and q2.card_id = c.id\n            )\n        )\n      );\n    if v_missing_count > 0 then\n      raise exception '% card(s) need saved grade, Cert Number, final image, and approved QA before Ready', v_missing_count;\n    end if;\n  elsif p_status = 'shipped' then\n    if nullif(btrim(coalesce(v_tracking_out,'')),'') is null then\n      raise exception 'Save outbound tracking before marking this PCG order shipped';\n    end if;\n  end if;\n\n  update public.card_grading_submissions\n     set status = p_status,\n         completed_at = case when p_status in ('shipped','picked_up') then now() else completed_at end,\n         updated_at = now()\n   where id = p_submission_id and tenant_id = p_tenant_id;\n  if not found then raise exception 'Submission unavailable'; end if;\n\n  update public.card_grading_cards\n     set status = p_status, updated_at = now()\n   where submission_id = p_submission_id and tenant_id = p_tenant_id;\n\n  if p_status = 'ready' then\n    insert into public.card_grading_certificates(\n      tenant_id, card_id, cert_number, category, year, manufacturer, set_name, brand_set, subset,\n      player_character, card_number, variation, serial_number, autograph_present, relic_present,\n      final_grade, grade_label, final_image_url, finalized_at, published_at, created_by\n    )\n    select\n      c.tenant_id, c.id, c.cert_number, c.category, c.year, c.manufacturer, c.set_name, c.brand_set, c.subset,\n      c.player_character, c.card_number, c.variation, c.serial_number, c.autograph_present, c.relic_present,\n      c.grade, c.grade_label, c.slab_image_url, now(), now(), auth.uid()\n    from public.card_grading_cards c\n    where c.tenant_id = p_tenant_id and c.submission_id = p_submission_id\n    on conflict (card_id) do update set\n      category = excluded.category,\n      year = excluded.year,\n      manufacturer = excluded.manufacturer,\n      set_name = excluded.set_name,\n      brand_set = excluded.brand_set,\n      subset = excluded.subset,\n      player_character = excluded.player_character,\n      card_number = excluded.card_number,\n      variation = excluded.variation,\n      serial_number = excluded.serial_number,\n      autograph_present = excluded.autograph_present,\n      relic_present = excluded.relic_present,\n      final_grade = excluded.final_grade,\n      grade_label = excluded.grade_label,\n      final_image_url = excluded.final_image_url,\n      finalized_at = coalesce(card_grading_certificates.finalized_at, now()),\n      published_at = coalesce(card_grading_certificates.published_at, now()),\n      updated_at = now();\n\n    update public.card_grading_cards\n       set finalized_at = coalesce(finalized_at, now()), updated_at = now()\n     where tenant_id = p_tenant_id and submission_id = p_submission_id;\n  end if;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_submission_id uuid, p_status text"},{"name":"ai_is_tenant_admin","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ai_is_tenant_admin(_tenant_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  SELECT public.is_system_admin(auth.uid()) OR EXISTS (SELECT 1 FROM public.user_tenant_memberships m\n    LEFT JOIN public.user_roles ur ON ur.user_id=m.user_id AND ur.tenant_id=m.tenant_id\n    WHERE m.user_id=auth.uid() AND m.tenant_id=_tenant_id AND m.status='active'\n      AND (m.is_owner=true OR ur.role::text IN ('Owner','Tenant Owner','Admin','GodMode')));\n$function$\n","identity_arguments":"_tenant_id uuid"},{"name":"ai_touch_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ai_touch_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"ai_user_in_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ai_user_in_tenant(_tenant_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$ SELECT public.is_tenant_member(auth.uid(), _tenant_id); $function$\n","identity_arguments":"_tenant_id uuid"},{"name":"allocate_pcg_cert_after_slab","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.allocate_pcg_cert_after_slab(_tenant_id uuid, _card_id uuid)\n RETURNS text\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _existing text;\nBEGIN\n  IF auth.uid() IS NULL OR NOT public.is_tenant_member(auth.uid(), _tenant_id) THEN\n    RAISE EXCEPTION 'tenant_membership_required';\n  END IF;\n  PERFORM pg_advisory_xact_lock(hashtextextended('pcg-cert-'||_tenant_id::text||'-'||_card_id::text,0));\n  SELECT cert_number INTO _existing\n  FROM public.card_grading_cards\n  WHERE tenant_id=_tenant_id AND id=_card_id\n  FOR UPDATE;\n  IF NOT FOUND THEN RAISE EXCEPTION 'pcg_card_not_found'; END IF;\n  IF coalesce(btrim(_existing),'')='' THEN\n    RAISE EXCEPTION 'pcg_certificate_requires_acceptance: use the canonical acceptance flow; do not generate a new post-slab certificate';\n  END IF;\n  IF _existing !~ '^[0-9]{5}$' AND _existing !~ '^[0-9]{11}$' THEN\n    RAISE EXCEPTION 'pcg_invalid_existing_certificate_format';\n  END IF;\n  RETURN _existing;\nEND;\n$function$\n","identity_arguments":"_tenant_id uuid, _card_id uuid"},{"name":"allocate_pcg_cert_on_acceptance","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.allocate_pcg_cert_on_acceptance(_card_id uuid, _grader_user_id uuid, _tenant_id uuid)\n RETURNS text\n LANGUAGE plpgsql\n SET search_path TO ''\nAS $function$\nbegin\n  if auth.uid() is null or auth.uid() is distinct from _grader_user_id then\n    raise exception 'grader_identity_mismatch' using errcode = '42501';\n  end if;\n  return public.allocate_pcg_cert_on_acceptance(_tenant_id, _card_id);\nend;\n$function$\n","identity_arguments":"_card_id uuid, _grader_user_id uuid, _tenant_id uuid"},{"name":"allocate_pcg_cert_on_acceptance","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.allocate_pcg_cert_on_acceptance(_tenant_id uuid, _card_id uuid)\n RETURNS text\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  _uid uuid:=auth.uid(); _existing text; _grade_label text; _slab text; _prefix smallint;\n  _suffix integer; _cert text; _max_existing integer; _direction integer:=1;\nbegin\n  if _uid is null or not public.is_tenant_member(_uid,_tenant_id) then raise exception 'tenant_membership_required'; end if;\n  perform pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended('pcg-cert-'||_tenant_id::text||'-'||_card_id::text,0));\n  select cert_number,grade_label into _existing,_grade_label\n    from public.card_grading_cards where tenant_id=_tenant_id and id=_card_id for update;\n  if not found then raise exception 'pcg_card_not_found'; end if;\n  if coalesce(btrim(_grade_label),'')='' then raise exception 'official_grade_required'; end if;\n  -- PCG certification uses the literal five digits transcribed from the uploaded slab.\n  -- Never use prefix, grader counter or order number as a substitute.\n  if _tenant_id = '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid then\n    select c.metadata #>> '{slab_cert_provenance,cert_number}'\n      into _slab from public.card_grading_cards c\n      where c.tenant_id = _tenant_id and c.id = _card_id;\n    if coalesce(btrim(_slab),'') !~ '^[0-9]{5}$'\n       or not exists (\n         select 1 from public.card_grading_cards c\n         where c.tenant_id = _tenant_id and c.id = _card_id\n           and c.metadata #>> '{slab_cert_provenance,authority}' = 'physical_slab_label'\n           and c.metadata #>> '{slab_cert_provenance,cert_number}' = _slab\n           and nullif(btrim(coalesce(c.front_image_url,'')), '') is not null\n       ) then\n      raise exception 'pcg_slab_cert_requires_photo_verified_evidence';\n    end if;\n    if coalesce(btrim(_existing),'') <> '' and _existing <> _slab then\n      raise exception 'pcg_existing_cert_conflicts_with_physical_slab';\n    end if;\n    if coalesce(btrim(_existing),'') = '' then\n      update public.card_grading_cards set cert_number = _slab, updated_at = now()\n      where tenant_id = _tenant_id and id = _card_id;\n      _existing := _slab;\n    end if;\n  end if;\n  if coalesce(btrim(_existing),'')<>'' then _cert:=_existing;\n  else\n    select prefix into _prefix from public.pcg_grader_cert_prefixes\n      where tenant_id=_tenant_id and user_id=_uid and active=true;\n    if _prefix is null then raise exception 'pcg_grader_prefix_not_assigned'; end if;\n    perform pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended('pcg-cert-registration-'||_tenant_id::text,0));\n    select coalesce(max(substring(cert_number from 2 for 4)::integer),0)\n      into _max_existing from public.card_grading_cards\n      where tenant_id=_tenant_id and cert_number~('^'||_prefix::text||'[0-9]{4}$');\n    insert into public.pcg_cert_sequences(tenant_id,prefix,next_suffix,updated_at)\n      values(_tenant_id,_prefix,case when _direction=-1 then 9999 else greatest(_max_existing+1,1) end,now())\n      on conflict(tenant_id,prefix) do nothing;\n    select next_suffix into _suffix from public.pcg_cert_sequences\n      where tenant_id=_tenant_id and prefix=_prefix for update;\n    loop\n      if _suffix is null or _suffix<1 or _suffix>9999 then raise exception 'pcg_cert_range_exhausted'; end if;\n      _cert:=_prefix::text||lpad(_suffix::text,4,'0');\n      exit when not exists(select 1 from public.card_grading_cards\n                           where tenant_id=_tenant_id and cert_number=_cert);\n      _suffix:=_suffix+_direction;\n    end loop;\n    update public.pcg_cert_sequences set next_suffix=greatest(1,_suffix+_direction),updated_at=now()\n      where tenant_id=_tenant_id and prefix=_prefix;\n    update public.card_grading_cards\n    set cert_number=_cert,finalized_at=coalesce(finalized_at,now()),\n        publish_to_website=true,publish_intent_updated_at=coalesce(publish_intent_updated_at,now()),\n        updated_at=now(),metadata=coalesce(metadata,'{}'::jsonb)||\n          jsonb_build_object('certification',coalesce(metadata->'certification','{}'::jsonb)||\n            jsonb_build_object('generated_at',now(),'trigger','official_grade_acceptance',\n              'format','grader_prefix_5_digit','grader_prefix',_prefix,'grader_user_id',_uid,\n              'direction',case when _direction=-1 then 'descending' else 'ascending' end))\n    where tenant_id=_tenant_id and id=_card_id;\n  end if;\n  insert into public.card_grading_certificates(\n    tenant_id,card_id,cert_number,category,year,manufacturer,set_name,brand_set,subset,\n    player_character,card_number,variation,serial_number,autograph_present,relic_present,\n    final_grade,grade_label,final_image_url,finalized_at,published_at,created_by)\n  select c.tenant_id,c.id,c.cert_number,c.category,c.year,c.manufacturer,c.set_name,c.brand_set,\n         c.subset,c.player_character,c.card_number,c.variation,c.serial_number,c.autograph_present,\n         c.relic_present,c.grade,c.grade_label,coalesce(c.slab_image_url,c.front_image_url),\n         coalesce(c.finalized_at,now()),now(),_uid\n  from public.card_grading_cards c where c.tenant_id=_tenant_id and c.id=_card_id\n  on conflict(card_id) do update\n    set cert_number=excluded.cert_number,category=excluded.category,year=excluded.year,\n        manufacturer=excluded.manufacturer,set_name=excluded.set_name,brand_set=excluded.brand_set,\n        subset=excluded.subset,player_character=excluded.player_character,\n        card_number=excluded.card_number,variation=excluded.variation,\n        serial_number=excluded.serial_number,autograph_present=excluded.autograph_present,\n        relic_present=excluded.relic_present,final_grade=excluded.final_grade,\n        grade_label=excluded.grade_label,final_image_url=excluded.final_image_url,\n        finalized_at=coalesce(public.card_grading_certificates.finalized_at,excluded.finalized_at),\n        published_at=coalesce(public.card_grading_certificates.published_at,excluded.published_at),\n        updated_at=now();\n  update public.card_grading_cards set publish_to_website=true,\n    publish_intent_updated_at=coalesce(publish_intent_updated_at,now()),updated_at=now()\n    where tenant_id=_tenant_id and id=_card_id;\n  return _cert;\nend;\n$function$\n","identity_arguments":"_tenant_id uuid, _card_id uuid"},{"name":"allocate_pcg_submission_number","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.allocate_pcg_submission_number(_tenant_id uuid, _card_id uuid)\n RETURNS text\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare _existing text; _next integer; _number text; _year integer := extract(year from current_date)::integer;\nbegin\n  if auth.uid() is null or not public.is_tenant_member(auth.uid(), _tenant_id) then raise exception 'tenant_membership_required'; end if;\n  perform pg_advisory_xact_lock(hashtextextended('pcg-submission-' || _tenant_id::text, 0));\n  select pcg_submission_number into _existing from public.card_grading_cards where tenant_id=_tenant_id and id=_card_id for update;\n  if not found then raise exception 'pcg_card_not_found'; end if;\n  if coalesce(btrim(_existing),'')<>'' then return _existing; end if;\n  select greatest(\n    coalesce((select max(pcg_submission_number::integer) from public.card_grading_cards where tenant_id=_tenant_id and pcg_submission_number ~ '^[0-9]{5}$'),0),\n    coalesce((select max(right(cert_number,5)::integer) from public.card_grading_cards where tenant_id=_tenant_id and cert_number ~ '^[0-9]{4}000[0-9]{5}$'),0)\n  )+1 into _next;\n  if _next>99999 then raise exception 'pcg_submission_range_exhausted'; end if;\n  _number:=lpad(_next::text,5,'0');\n  update public.card_grading_cards\n  set pcg_submission_number=_number,\n      pcg_submission_year=_year,\n      updated_at=now(),\n      metadata=coalesce(metadata,'{}'::jsonb)||jsonb_build_object('pcg_submission',jsonb_build_object('number',_number,'year',_year,'generated_at',now(),'trigger','pre_slab_front_back_stored'))\n  where tenant_id=_tenant_id and id=_card_id;\n  return _number;\nend;$function$\n","identity_arguments":"_tenant_id uuid, _card_id uuid"},{"name":"append_command_center_receipt","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.append_command_center_receipt(_event_id uuid, _step_id uuid, _receipt_type text, _source text, _status text, _proof_gate text, _external_id text, _source_sha text, _payload jsonb, _idempotency_key text)\n RETURNS command_center_receipts\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _tenant_id uuid;\n  _receipt public.command_center_receipts;\nBEGIN\n  SELECT tenant_id INTO _tenant_id FROM public.command_center_events WHERE id = _event_id;\n  IF _tenant_id IS NULL THEN RAISE EXCEPTION 'mission_not_found'; END IF;\n\n  INSERT INTO public.command_center_receipts (\n    tenant_id, command_center_event_id, mission_step_id, receipt_type, source,\n    status, proof_gate, external_id, source_sha, payload, idempotency_key\n  ) VALUES (\n    _tenant_id, _event_id, _step_id, _receipt_type, _source,\n    _status, _proof_gate, _external_id, _source_sha, coalesce(_payload, '{}'::jsonb), _idempotency_key\n  )\n  ON CONFLICT (idempotency_key) DO UPDATE SET payload = EXCLUDED.payload\n  RETURNING * INTO _receipt;\n\n  UPDATE public.command_center_events\n  SET last_progress_at = now(), lease_expires_at = now() + interval '90 seconds'\n  WHERE id = _event_id;\n  RETURN _receipt;\nEND;\n$function$\n","identity_arguments":"_event_id uuid, _step_id uuid, _receipt_type text, _source text, _status text, _proof_gate text, _external_id text, _source_sha text, _payload jsonb, _idempotency_key text"},{"name":"append_console_session_turn","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.append_console_session_turn(_session_id uuid, _context_tenant_id uuid, _user_message text, _assistant_message text, _route text DEFAULT NULL::text, _tenant_ref text DEFAULT NULL::text, _context jsonb DEFAULT '{}'::jsonb, _witness jsonb DEFAULT '{}'::jsonb)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_session_id uuid := _session_id;\n  v_event_tenant_id uuid;\n  v_payload jsonb;\n  v_title text;\nbegin\n  if auth.uid() is null or not public.is_system_admin(auth.uid()) then\n    raise exception 'Platform owner required' using errcode = '42501';\n  end if;\n\n  select t.id\n  into v_event_tenant_id\n  from public.tenants t\n  where t.company_slug = 'knocklaunch-crm'\n    and coalesce(t.status, 'active') = 'active'\n  limit 1;\n\n  if v_event_tenant_id is null then\n    v_event_tenant_id := _context_tenant_id;\n  end if;\n  if v_event_tenant_id is null then\n    raise exception 'Console session tenant unavailable';\n  end if;\n\n  if v_session_id is null then\n    v_title := 'Console · ' || left(regexp_replace(trim(coalesce(_user_message, 'New session')), '\\s+', ' ', 'g'), 96);\n    insert into public.command_center_events (\n      tenant_id,\n      created_by_user_id,\n      created_by_role,\n      source_module,\n      event_type,\n      priority,\n      title,\n      message,\n      status,\n      actor_type,\n      actor_display_name,\n      owner_authorized,\n      authorization_scope,\n      mission_context\n    ) values (\n      v_event_tenant_id,\n      auth.uid(),\n      'GodMode',\n      'ai',\n      'sidekick_conversation_log',\n      'info',\n      v_title,\n      left(coalesce(_user_message, ''), 500),\n      'in_progress',\n      'human',\n      'KNOCKLAUNCH Console',\n      true,\n      'platform_admins:console',\n      jsonb_build_object(\n        'console_session', true,\n        'session_version', 'sidekick-v3-history-v1',\n        'context_tenant_id', _context_tenant_id,\n        'last_tenant_ref', nullif(_tenant_ref, ''),\n        'last_route', nullif(_route, '')\n      )\n    )\n    returning id into v_session_id;\n  else\n    select e.tenant_id\n    into v_event_tenant_id\n    from public.command_center_events e\n    where e.id = v_session_id\n      and e.event_type = 'sidekick_conversation_log';\n\n    if v_event_tenant_id is null then\n      raise exception 'Console session not found' using errcode = 'P0002';\n    end if;\n  end if;\n\n  v_payload := jsonb_build_object(\n    'type', 'sidekick_conversation',\n    'actor_user_id', auth.uid(),\n    'actor_role', 'GodMode',\n    'sidekick_mode', 'godmode',\n    'visibility_scope', 'platform_admins',\n    'context_tenant_id', _context_tenant_id,\n    'tenant_ref', nullif(_tenant_ref, ''),\n    'route', nullif(_route, ''),\n    'user_message', coalesce(_user_message, ''),\n    'assistant_message', coalesce(_assistant_message, ''),\n    'metadata', coalesce(_context, '{}'::jsonb),\n    'witness', coalesce(_witness, '{}'::jsonb),\n    'created_at', now()\n  );\n\n  insert into public.command_center_messages (\n    tenant_id,\n    command_center_event_id,\n    sender_user_id,\n    sender_role,\n    message,\n    actor_type,\n    actor_display_name\n  ) values (\n    v_event_tenant_id,\n    v_session_id,\n    auth.uid(),\n    'GodMode',\n    v_payload::text,\n    'human',\n    'KNOCKLAUNCH Console'\n  );\n\n  update public.command_center_events\n  set\n    status = 'in_progress',\n    updated_at = now(),\n    mission_context = coalesce(mission_context, '{}'::jsonb) || jsonb_build_object(\n      'console_session', true,\n      'session_version', 'sidekick-v3-history-v1',\n      'context_tenant_id', _context_tenant_id,\n      'last_tenant_ref', nullif(_tenant_ref, ''),\n      'last_route', nullif(_route, ''),\n      'last_witness', coalesce(_witness, '{}'::jsonb)\n    )\n  where id = v_session_id;\n\n  return v_session_id;\nend;\n$function$\n","identity_arguments":"_session_id uuid, _context_tenant_id uuid, _user_message text, _assistant_message text, _route text, _tenant_ref text, _context jsonb, _witness jsonb"},{"name":"append_live_edit_sidekick_turn","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.append_live_edit_sidekick_turn(_session_id uuid, _context_tenant_id uuid, _user_message text, _assistant_message text, _route text, _context jsonb DEFAULT '{}'::jsonb)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_session_id uuid := _session_id;\n  v_actor_role text;\n  v_payload jsonb;\n  v_title text;\n  v_route text := left(trim(coalesce(_route, '')), 240);\nbegin\n  if auth.uid() is null or not public.can_use_live_edit_sidekick_memory(auth.uid(), _context_tenant_id) then\n    raise exception 'Live Edit Sidekick memory access denied' using errcode = '42501';\n  end if;\n  if v_route = '' then\n    raise exception 'Live Edit Sidekick route required' using errcode = '22023';\n  end if;\n\n  v_actor_role := case when public.is_system_admin(auth.uid()) then 'GodMode' else 'Owner' end;\n\n  if v_session_id is null then\n    v_title := 'Live Edit · ' || left(regexp_replace(trim(coalesce(_user_message, 'New design direction')), '\\s+', ' ', 'g'), 96);\n    insert into public.command_center_events (\n      tenant_id,\n      created_by_user_id,\n      created_by_role,\n      source_module,\n      event_type,\n      priority,\n      title,\n      message,\n      status,\n      actor_type,\n      actor_display_name,\n      owner_authorized,\n      authorization_scope,\n      mission_context\n    ) values (\n      _context_tenant_id,\n      auth.uid(),\n      v_actor_role,\n      'ai',\n      'sidekick_conversation_log',\n      'info',\n      v_title,\n      left(coalesce(_user_message, ''), 500),\n      'in_progress',\n      'human',\n      'KNOCKLAUNCH Live Edit',\n      true,\n      'tenant:live-edit',\n      jsonb_build_object(\n        'console_session', true,\n        'session_version', 'sidekick-live-edit-memory-v1',\n        'sidekick_surface', 'live-edit',\n        'context_tenant_id', _context_tenant_id,\n        'last_route', v_route,\n        'actor_user_id', auth.uid()\n      )\n    )\n    returning id into v_session_id;\n  else\n    perform 1\n    from public.command_center_events e\n    where e.id = v_session_id\n      and e.event_type = 'sidekick_conversation_log'\n      and e.created_by_user_id = auth.uid()\n      and coalesce(e.mission_context->>'sidekick_surface', '') = 'live-edit'\n      and coalesce(e.mission_context->>'context_tenant_id', '') = _context_tenant_id::text\n      and coalesce(e.mission_context->>'last_route', '') = v_route;\n    if not found then\n      raise exception 'Live Edit Sidekick memory session not found' using errcode = 'P0002';\n    end if;\n  end if;\n\n  v_payload := jsonb_build_object(\n    'type', 'sidekick_conversation',\n    'actor_user_id', auth.uid(),\n    'actor_role', v_actor_role,\n    'sidekick_mode', 'live-edit',\n    'visibility_scope', 'actor_tenant_route',\n    'context_tenant_id', _context_tenant_id,\n    'tenant_ref', _context_tenant_id::text,\n    'route', v_route,\n    'user_message', coalesce(_user_message, ''),\n    'assistant_message', coalesce(_assistant_message, ''),\n    'metadata', coalesce(_context, '{}'::jsonb) || jsonb_build_object('sidekickSurface', 'live-edit'),\n    'witness', '{}'::jsonb,\n    'created_at', now()\n  );\n\n  insert into public.command_center_messages (\n    tenant_id,\n    command_center_event_id,\n    sender_user_id,\n    sender_role,\n    message,\n    actor_type,\n    actor_display_name\n  ) values (\n    _context_tenant_id,\n    v_session_id,\n    auth.uid(),\n    v_actor_role,\n    v_payload::text,\n    'human',\n    'KNOCKLAUNCH Live Edit'\n  );\n\n  update public.command_center_events\n  set\n    status = 'in_progress',\n    updated_at = now(),\n    mission_context = coalesce(mission_context, '{}'::jsonb) || jsonb_build_object(\n      'console_session', true,\n      'session_version', 'sidekick-live-edit-memory-v1',\n      'sidekick_surface', 'live-edit',\n      'context_tenant_id', _context_tenant_id,\n      'last_route', v_route,\n      'actor_user_id', auth.uid()\n    )\n  where id = v_session_id;\n\n  return v_session_id;\nend;\n$function$\n","identity_arguments":"_session_id uuid, _context_tenant_id uuid, _user_message text, _assistant_message text, _route text, _context jsonb"},{"name":"apply_configured_lead_source_routing","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.apply_configured_lead_source_routing()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare v_tenant_id uuid; v_rule jsonb; v_email text; v_user_id uuid;\nbegin\n  if new.tenant_org_id is null or nullif(btrim(coalesce(new.source, '')), '') is null then return new; end if;\n  begin v_tenant_id := new.tenant_org_id::uuid; exception when invalid_text_representation then return new; end;\n  select coalesce(t.settings->'lead_source_routing'->new.source,t.settings->'lead_source_routing'->lower(new.source)) into v_rule from public.tenants t where t.id = v_tenant_id;\n  v_email := nullif(btrim(coalesce(v_rule->>'assignee_email', '')), '');\n  if v_email is null then return new; end if;\n  select p.id into v_user_id from public.profiles p join public.user_tenant_memberships m on m.user_id=p.id and m.tenant_id=v_tenant_id and m.status='active' where lower(p.email)=lower(v_email) order by m.is_owner desc,m.joined_at nulls last limit 1;\n  if v_user_id is null then new.assigned_to:=null; new.assigned_user:=null; else new.assigned_to:=v_user_id::text; new.assigned_user:=v_user_id::text; end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"apply_lawn_service_exception","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.apply_lawn_service_exception(p_tenant_id uuid, p_visit_id uuid, p_exception_type text, p_note text DEFAULT NULL::text, p_reschedule_date date DEFAULT NULL::date)\n RETURNS uuid\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nDECLARE source_visit public.lawn_service_visits%ROWTYPE; new_visit_id uuid;\nBEGIN\n  SELECT * INTO source_visit FROM public.lawn_service_visits WHERE id = p_visit_id AND tenant_id = p_tenant_id;\n  IF source_visit.id IS NULL THEN RAISE EXCEPTION 'visit not found'; END IF;\n  UPDATE public.lawn_service_visits\n  SET status = CASE WHEN p_reschedule_date IS NULL THEN 'blocked' ELSE 'rescheduled' END,\n      exception_type = p_exception_type,\n      exception_note = p_note\n  WHERE id = source_visit.id;\n  IF p_reschedule_date IS NOT NULL THEN\n    INSERT INTO public.lawn_service_visits (tenant_id, service_plan_id, contact_id, service_date, stop_order, status, assigned_crew_id, metadata)\n    VALUES (p_tenant_id, source_visit.service_plan_id, source_visit.contact_id, p_reschedule_date, source_visit.stop_order, 'scheduled', source_visit.assigned_crew_id, jsonb_build_object('rescheduled_from', source_visit.id, 'reason', p_exception_type))\n    ON CONFLICT (tenant_id, contact_id, service_date) DO UPDATE SET status = 'scheduled', metadata = public.lawn_service_visits.metadata || excluded.metadata\n    RETURNING id INTO new_visit_id;\n  END IF;\n  RETURN coalesce(new_visit_id, source_visit.id);\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_visit_id uuid, p_exception_type text, p_note text, p_reschedule_date date"},{"name":"apply_mode_default_media_to_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.apply_mode_default_media_to_tenant()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN NEW.settings := public.kl_apply_mode_default_media(NEW.settings); RETURN NEW; END;\n$function$\n","identity_arguments":""},{"name":"apply_modes_tenant_capability_contract","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.apply_modes_tenant_capability_contract(p_settings jsonb, p_tenant_type text)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_settings jsonb := coalesce(p_settings, '{}'::jsonb);\n  v_modes jsonb := coalesce(p_settings -> 'modes', '{}'::jsonb);\n  v_family text := public.canonical_tenant_experience_family(p_settings, p_tenant_type);\n  v_default_count integer := 0;\n  v_ready boolean := false;\n  v_normalized_type text;\n  v_cards jsonb;\n  v_has_cards_array boolean := jsonb_typeof(coalesce(p_settings -> 'modes', '{}'::jsonb) -> 'cards') = 'array';\n  v_is_generic_seed boolean := false;\n  v_namespaces jsonb;\nbegin\n  v_settings := jsonb_set(v_settings, '{experience_family}', to_jsonb(v_family), true);\n  if v_family <> 'modes' then\n    return v_settings;\n  end if;\n\n  v_normalized_type := public.normalize_declared_business_type(coalesce(\n    v_settings #>> '{business_operating_blueprint,businessTypeKey}',\n    v_settings ->> 'declared_business_type',\n    v_settings ->> 'business_type',\n    p_tenant_type\n  ));\n\n  if v_has_cards_array then\n    v_cards := v_modes -> 'cards';\n    if jsonb_array_length(v_cards) = 4 then\n      select count(*) = 4\n        into v_is_generic_seed\n        from jsonb_array_elements(v_cards) with ordinality as c(card, ord)\n       where (ord = 1 and coalesce(card->>'key','') = 'today' and coalesce(card->>'title','') = 'Today')\n          or (ord = 2 and coalesce(card->>'key','') = 'operations' and coalesce(card->>'title','') = 'Operations')\n          or (ord = 3 and coalesce(card->>'key','') = 'opportunities' and coalesce(card->>'title','') = 'Opportunities')\n          or (ord = 4 and coalesce(card->>'key','') = 'performance' and coalesce(card->>'title','') = 'Performance');\n    end if;\n  end if;\n\n  if v_normalized_type = 'MOBILE_CATERING'\n     and (not v_has_cards_array or jsonb_array_length(v_cards) = 0 or v_is_generic_seed) then\n    v_cards := jsonb_build_array(\n      jsonb_build_object(\n        'key','plan','title','Plan & Book',\n        'subtitle','Find catering leads, food-truck events, festivals, and turn them into booked work.',\n        'storage_slug','plan','default_image_key','planning','color','#18b8ff',\n        'primary_applications',jsonb_build_array('opportunity-radar','booking','calendar','proposals','contacts','communications')\n      ),\n      jsonb_build_object(\n        'key','prep','title','Kitchen Prep',\n        'subtitle','Turn booked work into prep lists, production tasks, documents, and a ready kitchen.',\n        'storage_slug','kitchen-prep','default_image_key','planning','color','#13ed86',\n        'primary_applications',jsonb_build_array('jobs','tasks','documents','calendar','contacts','communications')\n      ),\n      jsonb_build_object(\n        'key','events','title','Catering & Events',\n        'subtitle','Run private catering, food-truck festivals, pop-ups, and booked mobile events.',\n        'storage_slug','catering-events','default_image_key','events','color','#ff7b22',\n        'primary_applications',jsonb_build_array('booking','calendar','jobs','tasks','documents','communications')\n      ),\n      jsonb_build_object(\n        'key','office','title','Back Office',\n        'subtitle','Build proposals, create flyers, send invoices, collect payments, follow up, and watch the numbers.',\n        'storage_slug','back-office','default_image_key','back-office','color','#ff3f97',\n        'primary_applications',jsonb_build_array('creative-studio','invoices','payments','proposals','analytics','documents','communications')\n      )\n    );\n    v_has_cards_array := true;\n  end if;\n\n  if to_regclass('public.platform_mode_default_media') is not null then\n    select count(distinct mode_key)\n      into v_default_count\n      from public.platform_mode_default_media\n     where active = true\n       and mode_key = any(array['operations','planning','growth','financials','back-office','field','rentals','events','activations','vendors']);\n  end if;\n\n  if v_has_cards_array and jsonb_array_length(v_cards) > 0 then\n    select coalesce(jsonb_agg(namespace order by namespace), '[]'::jsonb)\n      into v_namespaces\n      from (\n        select distinct 'media/modes/' || trim(both '-' from regexp_replace(\n          lower(coalesce(nullif(card ->> 'storage_slug',''), nullif(card ->> 'key',''), nullif(card ->> 'title',''))),\n          '[^a-z0-9]+','-','g'\n        )) as namespace\n        from jsonb_array_elements(v_cards) as card\n      ) prepared\n     where namespace <> 'media/modes/';\n  else\n    v_namespaces := jsonb_build_array(\n      'media/modes/today',\n      'media/modes/operations',\n      'media/modes/opportunities',\n      'media/modes/performance'\n    );\n  end if;\n\n  v_ready := v_default_count = 10;\n  v_modes := v_modes || jsonb_build_object(\n    'version', 4,\n    'capability_contract', 'MODES_TENANT_V1',\n    'default_media_contract', 'MODE_DEFAULT_MEDIA_V2',\n    'activation_state', case when v_ready then 'ready' else 'prerequisite_required' end,\n    'storage_namespaces', v_namespaces,\n    'reconciled_at', now()\n  );\n  if v_has_cards_array then\n    v_modes := v_modes || jsonb_build_object('cards', v_cards);\n  end if;\n\n  return v_settings || jsonb_build_object('experience_family','modes','modes',v_modes);\nend;\n$function$\n","identity_arguments":"p_settings jsonb, p_tenant_type text"},{"name":"apply_pcg_internal_inventory_defaults","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.apply_pcg_internal_inventory_defaults()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_is_inventory boolean := false;\nbegin\n  select exists(\n    select 1\n    from public.card_grading_submissions s\n    where s.id=new.submission_id\n      and s.tenant_id=new.tenant_id\n      and s.submission_number='PCG-INVENTORY'\n  ) into v_is_inventory;\n\n  if v_is_inventory then\n    new.publish_to_website := true;\n    new.publish_to_ebay := coalesce(new.publish_to_ebay,false);\n    new.publish_intent_updated_at := coalesce(new.publish_intent_updated_at,now());\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"apply_revocation_to_dnc","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.apply_revocation_to_dnc()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.auto_suppressed THEN\n    INSERT INTO public.dnc_list (tenant_org_id, phone, phone_normalized, source, reason, added_by)\n    VALUES (NEW.tenant_org_id, NEW.phone_number, NEW.phone_normalized,\n      'revocation_' || NEW.channel,\n      'Auto-suppressed via revocation: \"' || COALESCE(NEW.matched_keyword, NEW.trigger_text, 'opt-out') || '\"',\n      'system_revocation_trigger')\n    ON CONFLICT DO NOTHING;\n  END IF;\n  RETURN NEW;\nEND; $function$\n","identity_arguments":""},{"name":"apply_tenant_public_presence_contract","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.apply_tenant_public_presence_contract(p_settings jsonb, p_slug text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_settings jsonb := coalesce(p_settings, '{}'::jsonb);\n  v_slug text := lower(trim(coalesce(p_slug, '')));\n  v_progress_url text;\n  v_booking_url text;\n  v_customer_presence jsonb;\n  v_presence jsonb;\nbegin\n  if v_slug = '' then return v_settings; end if;\n  v_progress_url := 'https://whatsmyprogress.com/' || v_slug || '/';\n  v_booking_url := 'https://bookmedirectly.com/' || v_slug || '/';\n  v_customer_presence := jsonb_build_object(\n    'required', true,\n    'contract', 'TENANT_PUBLIC_PRESENCE_V1',\n    'surfaces', jsonb_build_array(\n      jsonb_build_object('key','bookmedirectly','url',v_booking_url,'purpose','booking'),\n      jsonb_build_object('key','whatsmyprogress','url',v_progress_url,'purpose','customer_progress')\n    )\n  );\n  v_presence := jsonb_build_object(\n    'version',1,\n    'contract','TENANT_PUBLIC_PRESENCE_V1',\n    'required',true,\n    'canonical_slug',v_slug,\n    'bookmedirectly',jsonb_build_object('url',v_booking_url,'status','provisioned'),\n    'whatsmyprogress',jsonb_build_object('url',v_progress_url,'status','provisioned')\n  );\n  v_settings := v_settings || jsonb_build_object(\n    'canonical_public_route',v_progress_url,\n    'canonical_booking_route',v_booking_url,\n    'public_presence',v_presence\n  );\n  if jsonb_typeof(v_settings->'business_operating_blueprint')='object' then\n    v_settings := jsonb_set(\n      v_settings,\n      '{business_operating_blueprint,bootstrapRequirements}',\n      coalesce(v_settings#>'{business_operating_blueprint,bootstrapRequirements}','{}'::jsonb)\n        || jsonb_build_object('customerFacingPresence',v_customer_presence),\n      true\n    );\n  end if;\n  if jsonb_typeof(v_settings#>'{tenant_manifest,businessOperatingBlueprint}')='object' then\n    v_settings := jsonb_set(\n      v_settings,\n      '{tenant_manifest,businessOperatingBlueprint,bootstrapRequirements}',\n      coalesce(v_settings#>'{tenant_manifest,businessOperatingBlueprint,bootstrapRequirements}','{}'::jsonb)\n        || jsonb_build_object('customerFacingPresence',v_customer_presence),\n      true\n    );\n  end if;\n  if jsonb_typeof(v_settings#>'{onboarding_contract,business_operating_blueprint}')='object' then\n    v_settings := jsonb_set(\n      v_settings,\n      '{onboarding_contract,business_operating_blueprint,bootstrapRequirements}',\n      coalesce(v_settings#>'{onboarding_contract,business_operating_blueprint,bootstrapRequirements}','{}'::jsonb)\n        || jsonb_build_object('customerFacingPresence',v_customer_presence),\n      true\n    );\n  end if;\n  return v_settings;\nend;\n$function$\n","identity_arguments":"p_settings jsonb, p_slug text"},{"name":"assert_event_rental_booking_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.assert_event_rental_booking_tenant()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NOT EXISTS(SELECT 1 FROM public.event_bookings b WHERE b.id=NEW.event_booking_id AND b.tenant_org_id=NEW.tenant_id::text) THEN RAISE EXCEPTION 'Event booking does not belong to the event-rental tenant' USING ERRCODE='23514'; END IF;\n  RETURN NEW;\nEND; $function$\n","identity_arguments":""},{"name":"assert_event_rental_vendor_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.assert_event_rental_vendor_tenant()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NOT EXISTS(SELECT 1 FROM public.event_rental_vendors v WHERE v.id=NEW.vendor_id AND v.tenant_id=NEW.tenant_id) THEN RAISE EXCEPTION 'Event vendor does not belong to the event-rental tenant' USING ERRCODE='23514'; END IF;\n  RETURN NEW;\nEND; $function$\n","identity_arguments":""},{"name":"assign_card_grading_certificate","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.assign_card_grading_certificate(p_tenant_id uuid, p_card_id uuid, p_cert_number text)\n RETURNS uuid\n LANGUAGE plpgsql\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_card public.card_grading_cards%rowtype;\n  v_certificate_id uuid;\n  v_cert text := btrim(coalesce(p_cert_number,''));\nbegin\n  if auth.uid() is null or not (\n    public.is_system_admin(auth.uid())\n    or exists (\n      select 1 from public.security_active_user_tenant_memberships m\n      where m.user_id = auth.uid() and m.status = 'active' and m.tenant_id = p_tenant_id\n    )\n  ) then\n    raise exception 'Card grading workspace access required' using errcode = '42501';\n  end if;\n\n  if nullif(v_cert,'') is null then\n    raise exception 'Cert Number is required';\n  end if;\n\n  select * into v_card\n  from public.card_grading_cards\n  where id = p_card_id and tenant_id = p_tenant_id\n  for update;\n\n  if v_card.id is null then raise exception 'Card unavailable'; end if;\n  if v_card.grade is null then raise exception 'Save the card grade before assigning a Cert Number'; end if;\n  -- The PCG operator cannot invent an alternate number in the QC route.\n  if p_tenant_id = '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid and (\n    v_cert !~ '^[0-9]{5}$'\n    or v_card.metadata #>> '{slab_cert_provenance,authority}' is distinct from 'physical_slab_label'\n    or v_card.metadata #>> '{slab_cert_provenance,cert_number}' is distinct from v_cert\n    or nullif(btrim(coalesce(v_card.front_image_url,'')), '') is null\n  ) then\n    raise exception 'pcg_certificate_must_match_verified_physical_slab';\n  end if;\n\n  if nullif(btrim(coalesce(v_card.cert_number,'')),'') is not null\n     and btrim(v_card.cert_number) <> v_cert then\n    raise exception 'This card already has Cert Number % and it cannot be replaced', v_card.cert_number;\n  end if;\n\n  insert into public.card_grading_certificates(\n    tenant_id, card_id, cert_number, category, year, manufacturer, set_name, brand_set, subset,\n    player_character, card_number, variation, serial_number, autograph_present, relic_present,\n    final_grade, grade_label, final_image_url, finalized_at, created_by\n  ) values (\n    p_tenant_id, v_card.id, v_cert, v_card.category, v_card.year, v_card.manufacturer,\n    v_card.set_name, v_card.brand_set, v_card.subset, v_card.player_character, v_card.card_number,\n    v_card.variation, v_card.serial_number, v_card.autograph_present, v_card.relic_present,\n    v_card.grade, v_card.grade_label, nullif(btrim(coalesce(v_card.slab_image_url,'')),''),\n    v_card.finalized_at, auth.uid()\n  )\n  on conflict (card_id) do update set\n    category = excluded.category,\n    year = excluded.year,\n    manufacturer = excluded.manufacturer,\n    set_name = excluded.set_name,\n    brand_set = excluded.brand_set,\n    subset = excluded.subset,\n    player_character = excluded.player_character,\n    card_number = excluded.card_number,\n    variation = excluded.variation,\n    serial_number = excluded.serial_number,\n    autograph_present = excluded.autograph_present,\n    relic_present = excluded.relic_present,\n    final_grade = excluded.final_grade,\n    grade_label = excluded.grade_label,\n    final_image_url = excluded.final_image_url,\n    finalized_at = coalesce(public.card_grading_certificates.finalized_at, excluded.finalized_at),\n    updated_at = now()\n  returning id into v_certificate_id;\n\n  update public.card_grading_cards\n     set cert_number = coalesce(nullif(btrim(cert_number),''),v_cert),\n         updated_at = now()\n   where id = p_card_id and tenant_id = p_tenant_id;\n\n  if v_card.cert_number is null or btrim(v_card.cert_number)='' then\n    insert into public.card_grading_workflow_events(\n      tenant_id, submission_id, card_id, event_type, actor_user_id, metadata\n    ) values (\n      p_tenant_id, v_card.submission_id, v_card.id, 'certificate_assigned', auth.uid(),\n      jsonb_build_object('cert_number',v_cert)\n    );\n  end if;\n\n  return v_certificate_id;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_card_id uuid, p_cert_number text"},{"name":"attach_mobile_vendor_loyalty_referral","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.attach_mobile_vendor_loyalty_referral(_tenant_org_id uuid, _friend_member_id uuid, _referral_code text, _landing_ref text DEFAULT NULL::text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_friend public.mobile_vendor_loyalty_members%rowtype;\n  v_referrer public.mobile_vendor_loyalty_members%rowtype;\n  v_referral public.mobile_vendor_loyalty_referrals%rowtype;\n  v_code text := upper(nullif(btrim(coalesce(_referral_code, '')), ''));\nbegin\n  if v_code is null then\n    return jsonb_build_object('ok', true, 'attached', false, 'reason', 'no_referral_code');\n  end if;\n\n  select * into v_friend\n  from public.mobile_vendor_loyalty_members\n  where tenant_org_id = _tenant_org_id and id = _friend_member_id\n  for update;\n  if not found then raise exception 'Loyalty member not found'; end if;\n\n  select * into v_referral\n  from public.mobile_vendor_loyalty_referrals\n  where tenant_org_id = _tenant_org_id and friend_member_id = v_friend.id\n  for update;\n  if found then\n    return jsonb_build_object('ok', true, 'attached', true, 'existing', true, 'referral_id', v_referral.id, 'status', v_referral.status);\n  end if;\n\n  select * into v_referrer\n  from public.mobile_vendor_loyalty_members\n  where tenant_org_id = _tenant_org_id and referral_code = v_code and status = 'active'\n  for update;\n  if not found or v_referrer.id = v_friend.id then\n    return jsonb_build_object('ok', true, 'attached', false, 'reason', 'invalid_referral');\n  end if;\n\n  insert into public.mobile_vendor_loyalty_referrals (\n    tenant_org_id, referrer_member_id, friend_member_id, referral_code,\n    status, welcome_reward_status, metadata\n  ) values (\n    _tenant_org_id, v_referrer.id, v_friend.id, v_code,\n    'joined', 'pending_return',\n    jsonb_build_object('source', 'member_referral_link', 'landing_ref', nullif(btrim(coalesce(_landing_ref, '')), ''))\n  ) returning * into v_referral;\n\n  insert into public.mobile_vendor_loyalty_activity (\n    tenant_org_id, member_id, contact_id, activity_type, stamps_delta, balance_after,\n    points_delta, points_balance_after, source, source_ref, metadata\n  ) values (\n    _tenant_org_id, v_referrer.id, v_referrer.contact_id, 'referral_joined', 0, coalesce(v_referrer.stamp_balance, 0),\n    0, coalesce(v_referrer.points_balance, 0), 'bring_a_friend', v_referral.id::text,\n    jsonb_build_object('friend_member_id', v_friend.id, 'landing_ref', nullif(btrim(coalesce(_landing_ref, '')), ''))\n  );\n\n  return jsonb_build_object('ok', true, 'attached', true, 'existing', false, 'referral_id', v_referral.id, 'status', v_referral.status);\nend;\n$function$\n","identity_arguments":"_tenant_org_id uuid, _friend_member_id uuid, _referral_code text, _landing_ref text"},{"name":"audit_lead_deck_write","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.audit_lead_deck_write()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_changed text[] := NULL;\n  v_uid uuid := NULL;\nBEGIN\n  BEGIN\n    v_uid := auth.uid();\n  EXCEPTION WHEN OTHERS THEN\n    v_uid := NULL;\n  END;\n\n  IF TG_OP = 'UPDATE' THEN\n    SELECT COALESCE(array_agg(key), '{}')\n      INTO v_changed\n    FROM (\n      SELECT key\n      FROM jsonb_each(to_jsonb(NEW)) n\n      JOIN jsonb_each(to_jsonb(OLD)) o USING (key)\n      WHERE n.value IS DISTINCT FROM o.value\n    ) diff;\n  END IF;\n\n  INSERT INTO public.lead_deck_write_audit (\n    op, lead_deck_id, lead_id, tenant_org_id,\n    db_user, auth_uid, source_hint, changed_columns\n  ) VALUES (\n    TG_OP,\n    COALESCE((NEW).id, (OLD).id),\n    COALESCE((NEW).lead_id, (OLD).lead_id),\n    COALESCE((NEW).tenant_org_id, (OLD).tenant_org_id),\n    current_user,\n    v_uid,\n    current_setting('application_name', true),\n    v_changed\n  );\n\n  RETURN COALESCE(NEW, OLD);\nEXCEPTION WHEN OTHERS THEN\n  -- Never block the underlying write because of audit failure.\n  RETURN COALESCE(NEW, OLD);\nEND;\n$function$\n","identity_arguments":""},{"name":"audit_owner_receivable_change","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.audit_owner_receivable_change()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$ declare v_event_type text; v_amount numeric(14,2); begin if tg_op = 'INSERT' then v_event_type := 'created'; v_amount := new.expected_amount; elsif new.stage is distinct from old.stage then v_event_type := 'stage_changed'; v_amount := new.paid_amount; elsif new.paid_amount is distinct from old.paid_amount then v_event_type := 'payment_updated'; v_amount := new.paid_amount; else v_event_type := 'updated'; v_amount := new.paid_amount; end if; insert into public.owner_receivable_events (receivable_id, tenant_id, event_type, stage, amount, snapshot, created_by) values (new.id, new.tenant_id, v_event_type, new.stage, v_amount, to_jsonb(new), auth.uid()); return new; end; $function$\n","identity_arguments":""},{"name":"audit_phone_change","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.audit_phone_change()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _old text;\n  _new text;\n  _kind text;\n  _target_user uuid;\nBEGIN\n  IF TG_TABLE_NAME = 'profiles' THEN\n    _kind := 'personal_cell';\n    _target_user := NEW.id;\n    _old := OLD.phone;\n    _new := NEW.phone;\n  ELSIF TG_TABLE_NAME = 'rep_verified_caller_ids' THEN\n    _kind := 'forward_to_phone';\n    _target_user := NEW.user_id;\n    _old := OLD.forward_to_phone;\n    _new := NEW.forward_to_phone;\n  ELSE\n    RETURN NEW;\n  END IF;\n\n  IF coalesce(_old,'') = coalesce(_new,'') THEN\n    RETURN NEW;\n  END IF;\n\n  INSERT INTO public.comprehensive_audit_logs\n    (event_type, user_id, success, summary, payload)\n  VALUES (\n    'phone_identity_change',\n    _target_user,\n    true,\n    format('%s changed from %s to %s', _kind, coalesce(_old,'(empty)'), coalesce(_new,'(empty)')),\n    jsonb_build_object(\n      'kind', _kind,\n      'table', TG_TABLE_NAME,\n      'old', _old,\n      'new', _new,\n      'changed_by', auth.uid()\n    )\n  );\n  RETURN NEW;\nEXCEPTION WHEN OTHERS THEN\n  -- never block the underlying write because of audit failure\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"audit_trigger_func","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.audit_trigger_func()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_old_data JSONB;\n  v_new_data JSONB;\n  v_user_id UUID;\n  v_tenant_id UUID;\n  v_resource_id TEXT;\nBEGIN\n  BEGIN\n    v_user_id := auth.uid();\n  EXCEPTION WHEN OTHERS THEN\n    v_user_id := NULL;\n  END;\n\n  IF TG_OP = 'DELETE' THEN\n    v_old_data := to_jsonb(OLD);\n    v_new_data := NULL;\n    v_resource_id := OLD.id::TEXT;\n  ELSIF TG_OP = 'INSERT' THEN\n    v_old_data := NULL;\n    v_new_data := to_jsonb(NEW);\n    v_resource_id := NEW.id::TEXT;\n  ELSE\n    v_old_data := to_jsonb(OLD);\n    v_new_data := to_jsonb(NEW);\n    v_resource_id := NEW.id::TEXT;\n  END IF;\n\n  BEGIN\n    IF TG_OP = 'DELETE' THEN\n      v_tenant_id := (v_old_data->>'tenant_org_id')::UUID;\n      IF v_tenant_id IS NULL THEN\n        v_tenant_id := (v_old_data->>'tenant_id')::UUID;\n      END IF;\n    ELSE\n      v_tenant_id := (v_new_data->>'tenant_org_id')::UUID;\n      IF v_tenant_id IS NULL THEN\n        v_tenant_id := (v_new_data->>'tenant_id')::UUID;\n      END IF;\n    END IF;\n  EXCEPTION WHEN OTHERS THEN\n    v_tenant_id := NULL;\n  END;\n\n  INSERT INTO comprehensive_audit_logs (\n    user_id, tenant_id, event_type, event_category, event_action,\n    resource_type, resource_id, old_value, new_value, metadata, severity\n  ) VALUES (\n    v_user_id, v_tenant_id,\n    CASE TG_OP WHEN 'INSERT' THEN 'data_create' WHEN 'UPDATE' THEN 'data_update' WHEN 'DELETE' THEN 'data_delete' END,\n    'data', lower(TG_OP) || '_' || TG_TABLE_NAME,\n    TG_TABLE_NAME, COALESCE(v_resource_id, 'unknown'),\n    v_old_data, v_new_data,\n    jsonb_build_object('table_schema', TG_TABLE_SCHEMA, 'trigger_name', TG_NAME, 'operation', TG_OP),\n    CASE WHEN TG_OP = 'DELETE' THEN 'warn' ELSE 'info' END\n  );\n\n  IF TG_OP = 'DELETE' THEN RETURN OLD; ELSE RETURN NEW; END IF;\nEND;\n$function$\n","identity_arguments":""},{"name":"auto_create_recontact","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.auto_create_recontact()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF NEW.result_status IN ('not_home', 'callback_later', 'interested') THEN\n    INSERT INTO canvassing_recontacts (tenant_org_id, door_id, assigned_to, scheduled_for, reason, priority, created_by, notes)\n    VALUES (\n      NEW.tenant_org_id, NEW.door_id, NEW.user_id,\n      CASE \n        WHEN NEW.result_status = 'interested' THEN NOW() + INTERVAL '2 hours'\n        WHEN NEW.result_status = 'callback_later' THEN NOW() + INTERVAL '4 hours'\n        ELSE NOW() + INTERVAL '1 day'\n      END,\n      NEW.result_status,\n      CASE WHEN NEW.result_status = 'interested' THEN 3 \n           WHEN NEW.result_status = 'callback_later' THEN 2 \n           ELSE 1 END,\n      NEW.user_id, NEW.notes\n    );\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"auto_enroll_academy_onboarding","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.auto_enroll_academy_onboarding()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if new.status = 'active' and (tg_op = 'INSERT' or old.status is distinct from new.status or old.tenant_id is distinct from new.tenant_id) then\n    perform public.ensure_academy_onboarding_for_member(new.user_id, new.tenant_id, new.invited_by);\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"auto_graduate_lead","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.auto_graduate_lead()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.lead_stage = 'Appointment Set' AND OLD.lead_stage IS DISTINCT FROM 'Appointment Set' THEN\n    NEW.graduated_at := NOW();\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"auto_route_new_roof_lead","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.auto_route_new_roof_lead()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_under_5_years BOOLEAN := false;\n  v_reason TEXT := 'AUTO_ROUTED_<5YR_ROOF';\n  v_queue_lead_id TEXT;\n  v_permit_age_years NUMERIC;\n  v_tenant_type TEXT;\n  v_has_active_claim_or_job BOOLEAN := false;\nBEGIN\n  IF NEW.deleted_at IS NOT NULL THEN\n    RETURN NEW;\n  END IF;\n\n  IF NEW.tenant_org_id IS NOT NULL THEN\n    SELECT tenant_type INTO v_tenant_type\n    FROM public.tenants\n    WHERE id::text = NEW.tenant_org_id;\n    IF v_tenant_type = 'REALTOR' THEN\n      RETURN NEW;\n    END IF;\n  END IF;\n\n  v_has_active_claim_or_job :=\n    NULLIF(TRIM(COALESCE(NEW.claim_stage, '')), '') IS NOT NULL OR\n    NULLIF(TRIM(COALESCE(NEW.jobs_stage, '')), '') IS NOT NULL OR\n    NULLIF(TRIM(COALESCE(NEW.claim_number, '')), '') IS NOT NULL OR\n    NULLIF(TRIM(COALESCE(NEW.claim_number2, '')), '') IS NOT NULL OR\n    NULLIF(TRIM(COALESCE(NEW.claim_number3, '')), '') IS NOT NULL OR\n    NULLIF(TRIM(COALESCE(NEW.claim_number4, '')), '') IS NOT NULL OR\n    NULLIF(TRIM(COALESCE(NEW.job_value, '')), '') IS NOT NULL OR\n    LOWER(COALESCE(NEW.claim_stage, '')) = 'adjuster assigned';\n\n  IF v_has_active_claim_or_job THEN\n    RETURN NEW;\n  END IF;\n\n  IF NEW.roof_permit_finaled_date IS NOT NULL\n     AND NEW.roof_permit_finaled_date > (CURRENT_DATE - INTERVAL '5 years') THEN\n    v_under_5_years := true;\n    v_permit_age_years := EXTRACT(EPOCH FROM (now() - NEW.roof_permit_finaled_date::timestamp)) / (60*60*24*365.25);\n  ELSIF NEW.roof_permit_finaled_date IS NULL\n        AND NEW.property_year_built IS NOT NULL\n        AND NEW.property_year_built > (EXTRACT(YEAR FROM CURRENT_DATE)::int - 5) THEN\n    v_under_5_years := true;\n    v_permit_age_years := EXTRACT(YEAR FROM CURRENT_DATE)::int - NEW.property_year_built;\n  END IF;\n\n  IF NOT v_under_5_years THEN\n    RETURN NEW;\n  END IF;\n\n  v_queue_lead_id := NULLIF(TRIM(COALESCE(NEW.lead_id, '')), '');\n  IF v_queue_lead_id IS NULL THEN\n    v_queue_lead_id := NEW.id::text;\n  END IF;\n\n  INSERT INTO public.new_roofs_queue (\n    lead_id, tenant_org_id, contact_id, name, phone, email,\n    address, city, state, zip,\n    permit_finaled_date, permit_age_years, permit_data,\n    moved_to_queue_at, reason, status, notes\n  ) VALUES (\n    v_queue_lead_id, NEW.tenant_org_id, NEW.id, NEW.name, NEW.phone, NEW.email,\n    NEW.address, NEW.city, NEW.state, NEW.zip,\n    NEW.roof_permit_finaled_date, v_permit_age_years, NEW.permit_data,\n    now(), v_reason, 'queued', 'Auto-routed: roof under 5 years old'\n  )\n  ON CONFLICT (lead_id, tenant_org_id) DO UPDATE SET\n    contact_id = COALESCE(EXCLUDED.contact_id, new_roofs_queue.contact_id),\n    permit_finaled_date = COALESCE(EXCLUDED.permit_finaled_date, new_roofs_queue.permit_finaled_date),\n    permit_age_years = COALESCE(EXCLUDED.permit_age_years, new_roofs_queue.permit_age_years),\n    permit_data = COALESCE(EXCLUDED.permit_data, new_roofs_queue.permit_data),\n    updated_at = now();\n\n  NEW.archived_at := COALESCE(NEW.archived_at, now());\n  NEW.status := 'New Roof Queue';\n  NEW.lead_stage := 'New Roof Queue';\n  NEW.updated_at := now();\n\n  UPDATE public.lead_deck\n  SET archived_at = COALESCE(archived_at, now()),\n      status = 'New Roof Queue',\n      lead_stage = 'New Roof Queue',\n      updated_at = now()\n  WHERE tenant_org_id = NEW.tenant_org_id\n    AND lead_id = v_queue_lead_id\n    AND deleted_at IS NULL;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"auto_send_portal_welcome_on_signed_agreement","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.auto_send_portal_welcome_on_signed_agreement()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _portal_token TEXT;\n  _existing_link RECORD;\n  _contact RECORD;\n  _tenant RECORD;\n  _company_name TEXT;\n  _vertical TEXT;\n  _portal_url TEXT;\n  _base_url TEXT := 'https://app.knocklaunch.app';\n  _service_key TEXT;\n  _supabase_url TEXT;\n  _auto_send BOOLEAN := true;\n  _request_id BIGINT;\nBEGIN\n  -- Only fire when transitioning to signed\n  IF NEW.signed_at IS NULL THEN\n    RETURN NEW;\n  END IF;\n  IF OLD.signed_at IS NOT NULL THEN\n    RETURN NEW;\n  END IF;\n\n  -- Need contact + email + tenant\n  IF NEW.contact_id IS NULL OR NEW.recipient_email IS NULL OR NEW.tenant_id IS NULL THEN\n    RETURN NEW;\n  END IF;\n\n  -- Look up contact\n  SELECT id, full_name, archived_at, portal_token\n    INTO _contact\n    FROM public.unified_contacts\n   WHERE id = NEW.contact_id\n   LIMIT 1;\n\n  IF _contact IS NULL OR _contact.archived_at IS NOT NULL THEN\n    RETURN NEW;\n  END IF;\n\n  -- Look up tenant + check opt-out flag in tenants.settings\n  SELECT id,\n         COALESCE(company_dba_name, company_legal_name, name) AS display_name,\n         tenant_type,\n         COALESCE((settings->>'auto_send_portal_welcome')::boolean, true) AS auto_flag\n    INTO _tenant\n    FROM public.tenants\n   WHERE id::text = NEW.tenant_id::text\n   LIMIT 1;\n\n  IF _tenant IS NULL THEN\n    RETURN NEW;\n  END IF;\n\n  IF _tenant.auto_flag = false THEN\n    RETURN NEW;\n  END IF;\n\n  _company_name := COALESCE(_tenant.display_name, 'Your team');\n\n  -- Map tenant_type -> vertical (mirrors customer-portal edge function)\n  IF UPPER(COALESCE(_tenant.tenant_type, '')) LIKE '%PUBLIC%'\n     OR UPPER(COALESCE(_tenant.tenant_type, '')) LIKE '%ADJUSTER%' THEN\n    _vertical := 'public_adjuster';\n  ELSIF UPPER(COALESCE(_tenant.tenant_type, '')) LIKE '%ROOF%' THEN\n    _vertical := 'roofer';\n  ELSE\n    _vertical := 'mitigation';\n  END IF;\n\n  -- Reuse existing active portal link or mint a new one\n  SELECT token INTO _existing_link\n    FROM public.portal_links\n   WHERE contact_id = NEW.contact_id\n     AND is_active = true\n   ORDER BY created_at DESC\n   LIMIT 1;\n\n  IF _existing_link IS NOT NULL THEN\n    _portal_token := _existing_link.token;\n  ELSE\n    _portal_token := public.generate_portal_token() || public.generate_portal_token();\n    INSERT INTO public.portal_links (contact_id, tenant_org_id, token, expires_at, created_by, is_active)\n    VALUES (NEW.contact_id, NEW.tenant_id::text, _portal_token, NULL, NEW.sent_by_user_id, true);\n  END IF;\n\n  -- Mirror token onto contact for quick lookup\n  IF _contact.portal_token IS DISTINCT FROM _portal_token THEN\n    UPDATE public.unified_contacts\n       SET portal_token = _portal_token\n     WHERE id = NEW.contact_id;\n  END IF;\n\n  _portal_url := _base_url || '/portal/' || _portal_token;\n\n  -- Read vaulted service role key + project URL to call send-transactional-email\n  BEGIN\n    SELECT decrypted_secret INTO _service_key\n      FROM vault.decrypted_secrets\n     WHERE name = 'email_queue_service_role_key'\n     LIMIT 1;\n  EXCEPTION WHEN OTHERS THEN\n    _service_key := NULL;\n  END;\n\n  BEGIN\n    SELECT decrypted_secret INTO _supabase_url\n      FROM vault.decrypted_secrets\n     WHERE name = 'project_url'\n     LIMIT 1;\n  EXCEPTION WHEN OTHERS THEN\n    _supabase_url := NULL;\n  END;\n\n  -- Hardcoded fallback URL based on project ref (vault may not have project_url)\n  IF _supabase_url IS NULL OR _supabase_url = '' THEN\n    _supabase_url := 'https://ymntrajfubicyxwwdxxa.supabase.co';\n  END IF;\n\n  IF _service_key IS NULL OR _service_key = '' THEN\n    -- Without service key we cannot invoke the function; skip silently\n    RAISE NOTICE 'auto_send_portal_welcome: no service key in vault, skipping email';\n    RETURN NEW;\n  END IF;\n\n  -- Fire and forget — pg_net is async; signing latency is unaffected\n  SELECT net.http_post(\n    url := _supabase_url || '/functions/v1/send-transactional-email',\n    headers := jsonb_build_object(\n      'Content-Type', 'application/json',\n      'Authorization', 'Bearer ' || _service_key\n    ),\n    body := jsonb_build_object(\n      'templateName', 'portal-welcome',\n      'recipientEmail', NEW.recipient_email,\n      'idempotencyKey', 'portal-welcome-' || NEW.id::text,\n      'templateData', jsonb_build_object(\n        'recipientName', COALESCE(NEW.recipient_name, _contact.full_name, ''),\n        'companyName', _company_name,\n        'portalUrl', _portal_url,\n        'vertical', _vertical\n      )\n    )\n  ) INTO _request_id;\n\n  RETURN NEW;\nEXCEPTION WHEN OTHERS THEN\n  -- Never block agreement signing on email/portal failure\n  RAISE NOTICE 'auto_send_portal_welcome failed: %', SQLERRM;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"auto_stamp_claim_check_issued","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.auto_stamp_claim_check_issued()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.check_issued_at IS NULL THEN\n    IF NEW.settlement_date IS NOT NULL THEN\n      NEW.check_issued_at := NEW.settlement_date::timestamptz;\n    ELSIF NEW.settlement_amount IS NOT NULL AND NEW.settlement_amount > 0 THEN\n      NEW.check_issued_at := now();\n    END IF;\n  END IF;\n\n  IF NEW.check_issued_amount IS NULL AND NEW.settlement_amount IS NOT NULL THEN\n    NEW.check_issued_amount := NEW.settlement_amount;\n  END IF;\n\n  IF NEW.check_issued_at IS NOT NULL AND NEW.check_issued_by IS NULL THEN\n    NEW.check_issued_by := auth.uid();\n  END IF;\n\n  IF NEW.settlement_date IS NULL\n     AND (NEW.settlement_amount IS NULL OR NEW.settlement_amount = 0)\n     AND NEW.check_received_by_homeowner_at IS NULL THEN\n    NEW.check_issued_at := NULL;\n    NEW.check_issued_amount := NULL;\n    NEW.check_issued_by := NULL;\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"auto_unlock_upload_ticket_allows","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.auto_unlock_upload_ticket_allows(p_path text, p_metadata jsonb)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  select exists (\n    select 1\n    from public.auto_unlock_upload_tickets t\n    where t.object_path = p_path\n      and t.consumed_at is null\n      and t.expires_at > now()\n      and coalesce((p_metadata->>'size')::bigint,0) > 0\n      and coalesce((p_metadata->>'size')::bigint,0) <= t.declared_size\n      and lower(coalesce(p_metadata->>'mimetype','')) = lower(t.declared_mime)\n  );\n$function$\n","identity_arguments":"p_path text, p_metadata jsonb"},{"name":"automation_dispatch_on_update","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.automation_dispatch_on_update()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_changed_field TEXT;\n  v_trigger_type TEXT;\n  v_supabase_url TEXT;\n  v_anon_key TEXT;\nBEGIN\n  -- Determine what changed\n  IF OLD.status IS DISTINCT FROM NEW.status THEN\n    v_changed_field := 'status';\n    v_trigger_type := 'status_change';\n  ELSIF OLD.lead_stage IS DISTINCT FROM NEW.lead_stage THEN\n    v_changed_field := 'lead_stage';\n    v_trigger_type := 'stage_change';\n  ELSIF OLD.jobs_stage IS DISTINCT FROM NEW.jobs_stage THEN\n    v_changed_field := 'jobs_stage';\n    v_trigger_type := 'stage_change';\n  ELSIF OLD.claim_stage IS DISTINCT FROM NEW.claim_stage THEN\n    v_changed_field := 'claim_stage';\n    v_trigger_type := 'stage_change';\n  ELSIF OLD.assigned_to IS DISTINCT FROM NEW.assigned_to THEN\n    v_changed_field := 'assigned_to';\n    v_trigger_type := 'assignment_change';\n  ELSE\n    -- No automation-relevant field changed\n    RETURN NEW;\n  END IF;\n\n  -- Get Supabase URL from vault or config\n  v_supabase_url := current_setting('app.settings.supabase_url', true);\n  v_anon_key := current_setting('app.settings.anon_key', true);\n\n  -- Only fire if we have config (won't fire in dev without settings)\n  IF v_supabase_url IS NOT NULL AND v_anon_key IS NOT NULL THEN\n    PERFORM extensions.http_post(\n      url := v_supabase_url || '/functions/v1/pipeline-automation',\n      headers := jsonb_build_object(\n        'Content-Type', 'application/json',\n        'Authorization', 'Bearer ' || v_anon_key\n      ),\n      body := jsonb_build_object(\n        'action', 'trigger',\n        'event', jsonb_build_object(\n          'type', v_trigger_type,\n          'contactId', NEW.id::text,\n          'tenantId', COALESCE(NEW.tenant_org_id, ''),\n          'field', v_changed_field,\n          'oldValue', CASE v_changed_field\n            WHEN 'status' THEN OLD.status\n            WHEN 'lead_stage' THEN OLD.lead_stage\n            WHEN 'jobs_stage' THEN OLD.jobs_stage\n            WHEN 'claim_stage' THEN OLD.claim_stage\n            WHEN 'assigned_to' THEN OLD.assigned_to\n          END,\n          'newValue', CASE v_changed_field\n            WHEN 'status' THEN NEW.status\n            WHEN 'lead_stage' THEN NEW.lead_stage\n            WHEN 'jobs_stage' THEN NEW.jobs_stage\n            WHEN 'claim_stage' THEN NEW.claim_stage\n            WHEN 'assigned_to' THEN NEW.assigned_to\n          END\n        )\n      )\n    );\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"barbershop_tenant_access","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.barbershop_tenant_access(target_tenant uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select exists(select 1 from public.user_tenant_memberships m where m.tenant_id=target_tenant and m.user_id=auth.uid() and coalesce(m.status,'active')='active');\n$function$\n","identity_arguments":"target_tenant uuid"},{"name":"barbershop_tenant_owner","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.barbershop_tenant_owner(target_tenant uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select exists(select 1 from public.user_tenant_memberships m where m.tenant_id=target_tenant and m.user_id=auth.uid() and coalesce(m.status,'active')='active' and m.is_owner=true)\n  or exists(select 1 from public.user_roles r where r.tenant_id=target_tenant and r.user_id=auth.uid() and r.role::text in ('Owner','Tenant Owner','Admin','GodMode'));\n$function$\n","identity_arguments":"target_tenant uuid"},{"name":"block_mutation_append_only","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.block_mutation_append_only()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  RAISE EXCEPTION\n    'Table %.% is append-only. Mutations and deletions are not permitted. Use supersession instead.',\n    TG_TABLE_SCHEMA, TG_TABLE_NAME\n    USING ERRCODE = 'insufficient_privilege';\nEND;\n$function$\n","identity_arguments":""},{"name":"bootstrap_call_center_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.bootstrap_call_center_tenant(target_tenant uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  workflow_uuid uuid;\n  v_apps jsonb;\nbegin\n  insert into public.call_center_workflows (tenant_id,name,active,is_default)\n  values (target_tenant,'Guided Call Workflow',true,true)\n  on conflict (tenant_id,name) do update set active=true,is_default=true,updated_at=now()\n  returning id into workflow_uuid;\n\n  insert into public.call_center_stages (tenant_id,workflow_id,stage_key,label,prompt,sort_order)\n  select target_tenant,workflow_uuid,s.stage_key,s.label,s.prompt,s.sort_order\n  from (values\n    ('open','Open','Introduce yourself, confirm who you reached, and earn permission to continue.',10),\n    ('discover','Discover','Ask focused questions and listen for the customer''s real need, timing, and constraints.',20),\n    ('help','Help','Connect what you learned to the clearest next step your company can actually provide.',30),\n    ('commit','Commit','Ask for the next action: appointment, transfer, follow-up, payment, or another concrete commitment.',40),\n    ('close','Close','Confirm the details, set expectations, document the outcome, and leave the customer knowing what happens next.',50)\n  ) as s(stage_key,label,prompt,sort_order)\n  on conflict (workflow_id,stage_key) do update set label=excluded.label,prompt=excluded.prompt,sort_order=excluded.sort_order,active=true,updated_at=now();\n\n  insert into public.call_center_dispositions (tenant_id,key,label,requires_follow_up,sort_order)\n  select target_tenant,d.key,d.label,d.requires_follow_up,d.sort_order\n  from (values\n    ('appointment_set','Appointment set',false,10),\n    ('callback','Callback requested',true,20),\n    ('no_answer','No answer',true,30),\n    ('voicemail','Left voicemail',true,40),\n    ('not_interested','Not interested',false,50),\n    ('wrong_number','Wrong number',false,60),\n    ('do_not_call','Do not call',false,70)\n  ) as d(key,label,requires_follow_up,sort_order)\n  on conflict (tenant_id,key) do update set label=excluded.label,requires_follow_up=excluded.requires_follow_up,sort_order=excluded.sort_order,active=true,updated_at=now();\n\n  perform public.reconcile_tenant_business_blueprint(target_tenant, false);\n\n  select public.merge_tenant_application_ids(\n      coalesce(settings#>'{business_operating_blueprint,applications}', '[]'::jsonb),\n      jsonb_build_array('call-center')\n    )\n    into v_apps\n  from public.tenants\n  where id = target_tenant\n  for update;\n\n  if v_apps is null then\n    raise exception 'call_center_tenant_blueprint_unavailable';\n  end if;\n\n  update public.tenants\n  set settings = jsonb_set(coalesce(settings, '{}'::jsonb), '{business_operating_blueprint,applications}', v_apps, true),\n      updated_at = now()\n  where id = target_tenant;\n\n  perform public.reconcile_tenant_business_blueprint(target_tenant, false);\n\n  update public.tenant_applications\n  set enabled = true,\n      settings = coalesce(settings, '{}'::jsonb) || jsonb_build_object(\n        'assignment_source', 'explicit-call-center-bootstrap',\n        'availability_policy', 'assigned'\n      ),\n      updated_at = now()\n  where tenant_id = target_tenant\n    and application_id = 'call-center';\nend;\n$function$\n","identity_arguments":"target_tenant uuid"},{"name":"bootstrap_call_center_tenant_after_insert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.bootstrap_call_center_tenant_after_insert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  perform public.bootstrap_call_center_tenant(new.id);\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"bootstrap_roofing_project_ops","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.bootstrap_roofing_project_ops()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  is_roofing boolean;\n  next_phase text;\n  next_funding text;\nbegin\n  select exists (\n    select 1 from public.tenants t\n    where t.id = new.tenant_id\n      and upper(replace(coalesce(t.tenant_type, ''), ' ', '_')) = 'ROOFING_COMPANY'\n  ) into is_roofing;\n  if not is_roofing then return new; end if;\n\n  next_phase := case\n    when new.status in ('scheduled','acknowledged','dispatched') then 'scheduled'\n    when new.status in ('on_site','in_progress') then 'production'\n    when new.status in ('crew_completed','pm_verifying','pm_verified','manager_review','manager_approved','payroll_ready','submitted','completed','verified') then 'closeout'\n    when new.status = 'paid' then 'complete'\n    else 'preproduction'\n  end;\n  next_funding := case when coalesce(new.funding_type, 'retail') = 'insurance' then 'insurance' else 'retail' end;\n\n  insert into public.roofing_project_ops (\n    tenant_id, job_id, contact_id, project_phase, funding_type,\n    insurance_status, financing_status\n  ) values (\n    new.tenant_id, new.id, new.contact_id, next_phase, next_funding,\n    case when next_funding = 'insurance' then 'intake' else 'not_applicable' end,\n    case when coalesce(new.financing_mode, 'none') = 'none' then 'not_applicable' else 'draft' end\n  )\n  on conflict (job_id) do update set\n    contact_id = coalesce(excluded.contact_id, public.roofing_project_ops.contact_id),\n    project_phase = excluded.project_phase,\n    funding_type = excluded.funding_type,\n    updated_at = now();\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"bootstrap_tenant_applications","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.bootstrap_tenant_applications(target_tenant_id uuid)\n RETURNS void\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  insert into public.tenant_applications(tenant_id, application_id, enabled)\n  select target_tenant_id, c.id, true\n  from public.application_catalog c\n  join public.tenants t on t.id = target_tenant_id\n  where c.audience = 'tenant-user'\n    and (\n      c.default_installed = true\n      or (\n        c.bootstrap_mode = 'vertical'\n        and jsonb_array_length(coalesce(c.supported_tenant_types, '[]'::jsonb)) > 0\n        and c.supported_tenant_types ? coalesce(t.tenant_type::text, '')\n      )\n    )\n  on conflict (tenant_id, application_id) do nothing;\n$function$\n","identity_arguments":"target_tenant_id uuid"},{"name":"bootstrap_tenant_applications_after_insert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.bootstrap_tenant_applications_after_insert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  perform public.bootstrap_tenant_applications_for_tenant(new.id);\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"bootstrap_tenant_applications_for_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.bootstrap_tenant_applications_for_tenant(p_tenant_id uuid)\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_count integer;\nbegin\n  perform public.reconcile_tenant_business_blueprint(p_tenant_id, false);\n  select count(*) into v_count\n  from public.tenant_applications\n  where tenant_id = p_tenant_id and enabled = true;\n  return v_count;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"bridge_background_job_to_canonical_notifications","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.bridge_background_job_to_canonical_notifications()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_dedupe_key text;\n  v_severity text;\nbegin\n  if old.status is not distinct from new.status\n     or new.status not in ('completed', 'failed', 'needs_attention') then\n    return new;\n  end if;\n\n  v_dedupe_key := 'background-job:' || new.id::text || ':' || new.status;\n  v_severity := case when new.status = 'completed' then 'success' else 'warning' end;\n\n  insert into public.notifications (user_id, tenant_id, type, title, message, link, metadata)\n  select\n    new.user_id, new.tenant_id::text,\n    'background_job.' || new.status,\n    new.title || case when new.status = 'completed' then ' ready'\n                     when new.status = 'failed' then ' failed'\n                     else ' needs attention' end,\n    coalesce(nullif(new.error_message,''), nullif(new.detail,''), nullif(new.progress_label,'')),\n    new.destination_path,\n    jsonb_build_object(\n      'dedupe_key', v_dedupe_key,\n      'source_app', new.source_app,\n      'severity', v_severity,\n      'background_job_id', new.id,\n      'job_status', new.status,\n      'entity_type', new.entity_type,\n      'entity_id', new.entity_id\n    )\n  where not exists (\n    select 1 from public.notifications n\n    where n.user_id = new.user_id\n      and n.tenant_id = new.tenant_id::text\n      and n.metadata->>'dedupe_key' = v_dedupe_key\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"bridge_invitation_outcome_to_notifications","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.bridge_invitation_outcome_to_notifications()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_dedupe_key text;\nbegin\n  if new.source <> 'user_invitations'\n    or new.event_type not in ('invitation_accepted', 'invitation_failed')\n    or new.tenant_id is null\n    or new.source_id is null then\n    return new;\n  end if;\n\n  v_dedupe_key := 'invitation-outcome:' || new.id::text;\n\n  -- Notification delivery is non-critical; never roll back the verified\n  -- acceptance or the durable owner relationship event if this projection fails.\n  begin\n    insert into public.notifications (\n      user_id, tenant_id, type, title, message, link, metadata\n    )\n    select\n      member.user_id,\n      new.tenant_id::text,\n      case when new.event_type = 'invitation_accepted'\n        then 'invitation.accepted' else 'invitation.failed' end,\n      new.title,\n      case when new.event_type = 'invitation_accepted'\n        then 'A team member joined your workspace.'\n        else 'A team invitation could not be sent.' end,\n      '/users',\n      jsonb_build_object(\n        'source_app', 'system',\n        'severity', case when new.event_type = 'invitation_accepted' then 'success' else 'warning' end,\n        'source', 'owner_relationship_events',\n        'owner_relationship_event_id', new.id,\n        'invitation_id', new.metadata->>'invitation_id',\n        'dedupe_key', v_dedupe_key\n      )\n    from public.user_tenant_memberships member\n    join public.profiles owner_profile\n      on owner_profile.id = member.user_id\n    left join public.app_notification_preferences prefs\n      on prefs.user_id = member.user_id and prefs.tenant_id = member.tenant_id\n    where member.tenant_id = new.tenant_id\n      and member.status = 'active'\n      and member.is_owner = true\n      and owner_profile.active = true\n      and prefs.in_app_enabled is distinct from false\n      and coalesce(prefs.source_preferences->>'system', 'true') <> 'false'\n      -- Do not notify someone that they accepted their own invitation.\n      and not exists (\n        select 1\n        from public.user_invitations invited\n        join auth.users accepting_user on lower(accepting_user.email) = lower(invited.email)\n        where invited.id::text = new.metadata->>'invitation_id'\n          and accepting_user.id = member.user_id\n      )\n      and not exists (\n        select 1 from public.notifications existing\n        where existing.user_id = member.user_id\n          and existing.tenant_id = new.tenant_id::text\n          and existing.metadata->>'dedupe_key' = v_dedupe_key\n      );\n  exception when others then\n    raise warning 'invitation outcome notification projection failed (event %, SQLSTATE %)', new.id, sqlstate;\n  end;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"build_tenant_business_blueprint","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.build_tenant_business_blueprint(p_business_type text, p_settings jsonb, p_name text)\n RETURNS jsonb\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_type text := public.normalize_declared_business_type(p_business_type);\n  v_model text := public.tenant_operating_model_for(p_business_type, p_settings);\n  v_existing jsonb := coalesce(p_settings->'business_operating_blueprint', p_settings#>'{tenant_manifest,businessOperatingBlueprint}', '{}'::jsonb);\n  v_apps jsonb;\n  v_modules jsonb;\n  v_stages jsonb;\n  v_work text;\nBEGIN\n  IF v_type IS NULL THEN RAISE EXCEPTION 'Declared business type is required'; END IF;\n  IF v_model IS NULL THEN RAISE EXCEPTION 'Operating model is required for declared business type %', v_type USING ERRCODE='22023'; END IF;\n  IF jsonb_typeof(v_existing)='object' AND v_existing <> '{}'::jsonb AND nullif(v_existing->>'operatingModel','') IS NOT NULL THEN\n    RETURN v_existing || jsonb_build_object('businessTypeKey',v_type,'operatingModel',v_model);\n  END IF;\n  v_apps := public.tenant_blueprint_applications(v_model);\n  IF v_model='appointments' THEN\n    v_modules := '[{\"id\":\"today\",\"path\":\"dashboard\",\"label\":\"Today\",\"emphasis\":\"primary\"},{\"id\":\"booking\",\"path\":\"calendar\",\"label\":\"Booking\"},{\"id\":\"queue\",\"path\":\"dashboard\",\"label\":\"Queue\"},{\"id\":\"contacts\",\"path\":\"contacts\",\"label\":\"Customers\"},{\"id\":\"communications\",\"path\":\"communications\",\"label\":\"Messages\"},{\"id\":\"invoices\",\"path\":\"billing\",\"label\":\"Billing & Payments\"},{\"id\":\"documents\",\"path\":\"documents\",\"label\":\"Documents\"},{\"id\":\"analytics\",\"path\":\"analytics\",\"label\":\"Reports\"},{\"id\":\"settings\",\"path\":\"settings\",\"label\":\"Settings\"},{\"id\":\"opportunity-radar\",\"path\":\"opportunity-radar\",\"label\":\"Opportunity Radar\"}]'::jsonb;\n    v_stages := '[\"Inquiry\",\"Booked\",\"Checked In\",\"Waiting\",\"In Service\",\"Complete\",\"Follow-up\",\"Paid\"]'::jsonb; v_work := 'Appointment';\n  ELSIF v_model='recurring_routes' THEN\n    v_modules := '[{\"id\":\"today\",\"path\":\"dashboard\",\"label\":\"Today\",\"emphasis\":\"primary\"},{\"id\":\"route\",\"path\":\"route\",\"label\":\"Route\"},{\"id\":\"contacts\",\"path\":\"contacts\",\"label\":\"Customers\"},{\"id\":\"calendar\",\"path\":\"calendar\",\"label\":\"Schedule\"},{\"id\":\"communications\",\"path\":\"communications\",\"label\":\"Messages\"},{\"id\":\"invoices\",\"path\":\"billing\",\"label\":\"Billing & Payments\"},{\"id\":\"documents\",\"path\":\"documents\",\"label\":\"Documents\"},{\"id\":\"analytics\",\"path\":\"analytics\",\"label\":\"Reports\"},{\"id\":\"settings\",\"path\":\"settings\",\"label\":\"Settings\"},{\"id\":\"opportunity-radar\",\"path\":\"opportunity-radar\",\"label\":\"Opportunity Radar\"}]'::jsonb;\n    v_stages := '[\"Inquiry\",\"Plan\",\"Scheduled\",\"Service Visit\",\"Complete\",\"Next Visit\"]'::jsonb; v_work := 'Service Visit';\n  ELSIF v_model='events' THEN\n    v_modules := '[{\"id\":\"today\",\"path\":\"dashboard\",\"label\":\"Today\",\"emphasis\":\"primary\"},{\"id\":\"booking\",\"path\":\"calendar\",\"label\":\"Bookings\"},{\"id\":\"contacts\",\"path\":\"contacts\",\"label\":\"Customers\"},{\"id\":\"calendar\",\"path\":\"calendar\",\"label\":\"Calendar\"},{\"id\":\"communications\",\"path\":\"communications\",\"label\":\"Messages\"},{\"id\":\"invoices\",\"path\":\"billing\",\"label\":\"Billing & Payments\"},{\"id\":\"documents\",\"path\":\"documents\",\"label\":\"Documents\"},{\"id\":\"analytics\",\"path\":\"analytics\",\"label\":\"Reports\"},{\"id\":\"settings\",\"path\":\"settings\",\"label\":\"Settings\"},{\"id\":\"opportunity-radar\",\"path\":\"opportunity-radar\",\"label\":\"Opportunity Radar\"}]'::jsonb;\n    v_stages := '[\"Inquiry\",\"Proposal\",\"Booked\",\"Prep\",\"Event\",\"Paid\"]'::jsonb; v_work := 'Booking';\n  ELSIF v_model='orders' THEN\n    v_modules := '[{\"id\":\"today\",\"path\":\"dashboard\",\"label\":\"Today\",\"emphasis\":\"primary\"},{\"id\":\"orders\",\"path\":\"jobs\",\"label\":\"Orders\"},{\"id\":\"contacts\",\"path\":\"contacts\",\"label\":\"Customers\"},{\"id\":\"communications\",\"path\":\"communications\",\"label\":\"Messages\"},{\"id\":\"invoices\",\"path\":\"billing\",\"label\":\"Payments\"},{\"id\":\"documents\",\"path\":\"documents\",\"label\":\"Documents\"},{\"id\":\"analytics\",\"path\":\"analytics\",\"label\":\"Reports\"},{\"id\":\"settings\",\"path\":\"settings\",\"label\":\"Settings\"},{\"id\":\"opportunity-radar\",\"path\":\"opportunity-radar\",\"label\":\"Opportunity Radar\"}]'::jsonb;\n    v_stages := '[\"Inquiry\",\"Order\",\"Fulfillment\",\"Complete\",\"Paid\",\"Repeat\"]'::jsonb; v_work := 'Order';\n  ELSIF v_model='professional_cases' THEN\n    v_modules := '[{\"id\":\"today\",\"path\":\"dashboard\",\"label\":\"Today\",\"emphasis\":\"primary\"},{\"id\":\"contacts\",\"path\":\"contacts\",\"label\":\"Clients\"},{\"id\":\"calendar\",\"path\":\"calendar\",\"label\":\"Schedule\"},{\"id\":\"communications\",\"path\":\"communications\",\"label\":\"Messages\"},{\"id\":\"documents\",\"path\":\"documents\",\"label\":\"Documents\"},{\"id\":\"tasks\",\"path\":\"tasks\",\"label\":\"Tasks\"},{\"id\":\"analytics\",\"path\":\"analytics\",\"label\":\"Reports\"},{\"id\":\"settings\",\"path\":\"settings\",\"label\":\"Settings\"},{\"id\":\"opportunity-radar\",\"path\":\"opportunity-radar\",\"label\":\"Opportunity Radar\"}]'::jsonb;\n    v_stages := '[\"Inquiry\",\"Consultation\",\"Active Work\",\"Documents\",\"Follow-up\",\"Complete\"]'::jsonb; v_work := 'Matter';\n  ELSE\n    v_modules := '[{\"id\":\"today\",\"path\":\"dashboard\",\"label\":\"Today\",\"emphasis\":\"primary\"},{\"id\":\"contacts\",\"path\":\"contacts\",\"label\":\"Customers\"},{\"id\":\"operations\",\"path\":\"jobs\",\"label\":\"Operations\"},{\"id\":\"calendar\",\"path\":\"calendar\",\"label\":\"Schedule\"},{\"id\":\"communications\",\"path\":\"communications\",\"label\":\"Messages\"},{\"id\":\"invoices\",\"path\":\"billing\",\"label\":\"Billing & Payments\"},{\"id\":\"documents\",\"path\":\"documents\",\"label\":\"Documents\"},{\"id\":\"tasks\",\"path\":\"tasks\",\"label\":\"Tasks\"},{\"id\":\"analytics\",\"path\":\"analytics\",\"label\":\"Reports\"},{\"id\":\"settings\",\"path\":\"settings\",\"label\":\"Settings\"},{\"id\":\"opportunity-radar\",\"path\":\"opportunity-radar\",\"label\":\"Opportunity Radar\"}]'::jsonb;\n    v_stages := CASE WHEN v_model='general' THEN '[\"Intake\",\"Active\",\"Waiting\",\"Complete\",\"Closed\"]'::jsonb ELSE '[\"Inquiry\",\"Estimate\",\"Scheduled\",\"In Progress\",\"Complete\",\"Paid\"]'::jsonb END;\n    v_work := CASE WHEN v_model='general' THEN 'Work Item' ELSE 'Service Job' END;\n  END IF;\n  RETURN jsonb_build_object('version',1,'businessTypeKey',v_type,'businessType',coalesce(nullif(p_settings->>'business_type',''),p_name,v_type),'businessDescription',coalesce(nullif(p_settings->>'business_description',''),p_name,v_type),'operatingModel',v_model,'primaryRelationship',jsonb_build_object('singular',CASE WHEN v_model='professional_cases' THEN 'Client' ELSE 'Customer' END,'plural',CASE WHEN v_model='professional_cases' THEN 'Clients' ELSE 'Customers' END,'kind',CASE WHEN v_model='professional_cases' THEN 'client' ELSE 'customer' END),'workObjects',jsonb_build_array(jsonb_build_object('singular',v_work,'plural',v_work||'s','kind',v_model)),'workflowStages',v_stages,'applications',v_apps,'capabilities',v_apps,'modules',v_modules,'vocabulary',jsonb_build_object('workspace',coalesce(p_name,v_type)||' Operations','work',v_work,'workPlural',v_work||'s'),'schedulingModel',v_model,'billingModel',CASE WHEN v_model='appointments' THEN 'appointment_billing' ELSE 'invoice' END,'recurrenceModel',CASE WHEN v_model='appointments' THEN 'appointment_and_rebook' WHEN v_model='recurring_routes' THEN 'scheduled_recurrence' ELSE 'repeat_business' END,'dashboardPriorities','[]'::jsonb,'assumptions','[]'::jsonb);\nEND;\n$function$\n","identity_arguments":"p_business_type text, p_settings jsonb, p_name text"},{"name":"business_activity_assert_tenant_access","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_activity_assert_tenant_access(_tenant_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nbegin\n  if coalesce(auth.role(), '') = 'service_role' then return; end if;\n  if auth.uid() is null then raise exception 'business_activity_authentication_required' using errcode = '42501'; end if;\n  if public.is_platform_admin(auth.uid()) or public.ai_user_in_tenant(_tenant_id) then return; end if;\n  raise exception 'business_activity_tenant_access_denied' using errcode = '42501';\nend;\n$function$\n","identity_arguments":"_tenant_id uuid"},{"name":"business_activity_project","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_activity_project(_tenant_id uuid, _activity_type text, _title text, _event jsonb DEFAULT '{}'::jsonb)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_id uuid;\n  v_contact uuid := public.business_activity_safe_uuid(_event->>'contact_id');\n  v_actor uuid := public.business_activity_safe_uuid(_event->>'actor_user_id');\n  v_related uuid := public.business_activity_safe_uuid(_event->>'related_entity_id');\n  v_correction uuid := public.business_activity_safe_uuid(_event->>'corrects_event_id');\n  v_money numeric := case when nullif(_event->>'monetary_value','') is null then null else (_event->>'monetary_value')::numeric end;\n  v_occurred timestamptz := case when nullif(_event->>'occurred_at','') is null then now() else (_event->>'occurred_at')::timestamptz end;\nbegin\n  if nullif(btrim(coalesce(_activity_type,'')), '') is null then raise exception 'business_activity_type_required'; end if;\n  if nullif(btrim(coalesce(_title,'')), '') is null then raise exception 'business_activity_title_required'; end if;\n  if v_correction is not null and not exists (select 1 from public.activity_timeline where id=v_correction and tenant_org_id=_tenant_id) then\n    raise exception 'business_activity_correction_target_invalid';\n  end if;\n  insert into public.activity_timeline (\n    tenant_org_id, contact_id, user_id, activity_type, title, description, metadata,\n    related_entity_type, related_entity_id, importance, is_system_generated, event_domain,\n    source_channel, touch_channel, source_detail, source_campaign, source_referrer,\n    source_system, source_record_type, source_record_id, correlation_key, actor_role,\n    previous_state, new_state, reason_code, monetary_value, currency, outcome,\n    corrects_event_id, dedupe_key, created_at\n  ) values (\n    _tenant_id, v_contact, v_actor, _activity_type, _title, _event->>'description', coalesce(_event->'metadata','{}'::jsonb),\n    _event->>'related_entity_type', v_related, coalesce(nullif(_event->>'importance',''),'normal'), coalesce((_event->>'is_system_generated')::boolean,true), coalesce(nullif(_event->>'event_domain',''),'activity'),\n    nullif(_event->>'source_channel',''), nullif(_event->>'touch_channel',''), nullif(_event->>'source_detail',''), nullif(_event->>'source_campaign',''), nullif(_event->>'source_referrer',''),\n    coalesce(nullif(_event->>'source_system',''),'knocklaunch'), nullif(_event->>'source_record_type',''), nullif(_event->>'source_record_id',''), nullif(_event->>'correlation_key',''), nullif(_event->>'actor_role',''),\n    nullif(_event->>'previous_state',''), nullif(_event->>'new_state',''), nullif(_event->>'reason_code',''), v_money, coalesce(nullif(_event->>'currency',''),'USD'), nullif(_event->>'outcome',''),\n    v_correction, nullif(_event->>'dedupe_key',''), v_occurred\n  ) on conflict (tenant_org_id,dedupe_key) where dedupe_key is not null do nothing returning id into v_id;\n  if v_id is null and nullif(_event->>'dedupe_key','') is not null then\n    select id into v_id from public.activity_timeline where tenant_org_id=_tenant_id and dedupe_key=_event->>'dedupe_key' order by created_at desc limit 1;\n  end if;\n  return v_id;\nend;\n$function$\n","identity_arguments":"_tenant_id uuid, _activity_type text, _title text, _event jsonb"},{"name":"business_activity_safe_uuid","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_activity_safe_uuid(_value text)\n RETURNS uuid\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  if nullif(btrim(coalesce(_value, '')), '') is null then return null; end if;\n  return _value::uuid;\nexception when invalid_text_representation then return null;\nend;\n$function$\n","identity_arguments":"_value text"},{"name":"business_apply_opportunity_transition","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_apply_opportunity_transition(_opportunity_id uuid, _dimension text, _to_state text, _reason_code text, _metadata jsonb DEFAULT '{}'::jsonb)\n RETURNS business_opportunities\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\ndeclare\n  o public.business_opportunities%rowtype;\n  final_o public.business_opportunities%rowtype;\n  current_state text;\n  allowed_states text[];\n  proposal_hours integer;\n  deposit_hours integer;\n  balance_hours integer;\nbegin\n  select * into o from public.business_opportunities where id = _opportunity_id for update;\n  if not found then raise exception 'business_opportunity_not_found'; end if;\n  perform public.business_engine_assert_access(o.tenant_id);\n\n  if nullif(btrim(coalesce(_reason_code, '')), '') is null then\n    raise exception 'business_transition_reason_required';\n  end if;\n  if _dimension not in ('lifecycle','proposal','payment','fulfillment') then\n    raise exception 'business_transition_dimension_invalid:%', _dimension;\n  end if;\n\n  current_state := case _dimension\n    when 'lifecycle' then o.lifecycle_state\n    when 'proposal' then o.proposal_state\n    when 'payment' then o.payment_state\n    when 'fulfillment' then o.fulfillment_state\n  end;\n\n  if current_state = _to_state then\n    return o;\n  end if;\n\n  allowed_states := case\n    when _dimension = 'lifecycle' and current_state = 'captured' then array['qualified','won','lost','cancelled']\n    when _dimension = 'lifecycle' and current_state = 'qualified' then array['won','lost','cancelled']\n    when _dimension = 'lifecycle' and current_state = 'won' then array['cancelled']\n    when _dimension = 'proposal' and current_state = 'not_started' then array['draft','sent','accepted','void']\n    when _dimension = 'proposal' and current_state = 'draft' then array['sent','accepted','void']\n    when _dimension = 'proposal' and current_state = 'sent' then array['accepted','declined','void']\n    when _dimension = 'proposal' and current_state = 'declined' then array['draft','void']\n    when _dimension = 'proposal' and current_state = 'accepted' then array['void']\n    when _dimension = 'payment' and current_state = 'not_required' then array['deposit_due','balance_due','paid','void']\n    when _dimension = 'payment' and current_state = 'deposit_due' then array['deposit_paid','deposit_overdue','balance_due','void']\n    when _dimension = 'payment' and current_state = 'deposit_overdue' then array['deposit_paid','balance_due','void']\n    when _dimension = 'payment' and current_state = 'deposit_paid' then array['balance_due','paid','refunded','void']\n    when _dimension = 'payment' and current_state = 'balance_due' then array['paid','balance_overdue','void']\n    when _dimension = 'payment' and current_state = 'balance_overdue' then array['paid','void']\n    when _dimension = 'payment' and current_state = 'paid' then array['refunded']\n    when _dimension = 'fulfillment' and current_state = 'not_scheduled' then array['scheduled','in_progress','completed','cancelled']\n    when _dimension = 'fulfillment' and current_state = 'scheduled' then array['in_progress','completed','cancelled']\n    when _dimension = 'fulfillment' and current_state = 'in_progress' then array['completed','cancelled']\n    else array[]::text[]\n  end;\n\n  if not (_to_state = any(allowed_states)) then\n    raise exception 'business_transition_not_allowed:%:%->%', _dimension, current_state, _to_state;\n  end if;\n\n  select p.proposal_followup_hours, p.deposit_due_hours, p.balance_due_hours\n    into proposal_hours, deposit_hours, balance_hours\n    from public.business_workflow_policies p where p.tenant_id = o.tenant_id;\n  proposal_hours := coalesce(proposal_hours, 48);\n  deposit_hours := coalesce(deposit_hours, 72);\n  balance_hours := coalesce(balance_hours, 24);\n\n  update public.business_opportunities\n     set lifecycle_state = case when _dimension = 'lifecycle' then _to_state else lifecycle_state end,\n         proposal_state = case when _dimension = 'proposal' then _to_state else proposal_state end,\n         payment_state = case when _dimension = 'payment' then _to_state else payment_state end,\n         fulfillment_state = case when _dimension = 'fulfillment' then _to_state else fulfillment_state end,\n         proposal_sent_at = case when _dimension = 'proposal' and _to_state = 'sent' then coalesce(proposal_sent_at, now()) else proposal_sent_at end,\n         proposal_followup_due_at = case when _dimension = 'proposal' and _to_state = 'sent' then coalesce(proposal_followup_due_at, now() + make_interval(hours => proposal_hours)) else proposal_followup_due_at end,\n         accepted_at = case when _dimension = 'proposal' and _to_state = 'accepted' then coalesce(accepted_at, now()) else accepted_at end,\n         deposit_due_at = case when _dimension = 'payment' and _to_state = 'deposit_due' then coalesce(deposit_due_at, now() + make_interval(hours => deposit_hours)) else deposit_due_at end,\n         deposit_paid_at = case when _dimension = 'payment' and _to_state = 'deposit_paid' then coalesce(deposit_paid_at, now()) else deposit_paid_at end,\n         balance_due_at = case when _dimension = 'payment' and _to_state = 'balance_due' then coalesce(balance_due_at, now() + make_interval(hours => balance_hours)) else balance_due_at end,\n         paid_at = case when _dimension = 'payment' and _to_state = 'paid' then coalesce(paid_at, now()) else paid_at end,\n         fulfillment_completed_at = case when _dimension = 'fulfillment' and _to_state = 'completed' then coalesce(fulfillment_completed_at, now()) else fulfillment_completed_at end,\n         lost_at = case when _dimension = 'lifecycle' and _to_state = 'lost' then coalesce(lost_at, now()) else lost_at end,\n         cancelled_at = case when (_dimension = 'lifecycle' and _to_state = 'cancelled') or (_dimension = 'fulfillment' and _to_state = 'cancelled') then coalesce(cancelled_at, now()) else cancelled_at end,\n         metadata = metadata || coalesce(_metadata, '{}'::jsonb),\n         updated_at = now()\n   where id = o.id;\n\n  insert into public.business_opportunity_events\n    (tenant_id, opportunity_id, dimension, from_state, to_state, reason_code, actor_user_id, metadata)\n  values\n    (o.tenant_id, o.id, _dimension, current_state, _to_state, _reason_code, auth.uid(), coalesce(_metadata, '{}'::jsonb));\n\n  if _dimension = 'proposal' and _to_state = 'accepted' and o.lifecycle_state in ('captured','qualified') then\n    update public.business_opportunities set lifecycle_state = 'won', updated_at = now() where id = o.id;\n    insert into public.business_opportunity_events\n      (tenant_id, opportunity_id, dimension, from_state, to_state, reason_code, actor_user_id, metadata)\n    values\n      (o.tenant_id, o.id, 'lifecycle', o.lifecycle_state, 'won', 'proposal_accepted', auth.uid(), '{}'::jsonb);\n  end if;\n\n  select * into final_o from public.business_opportunities where id = o.id;\n  return final_o;\nend;\n$function$\n","identity_arguments":"_opportunity_id uuid, _dimension text, _to_state text, _reason_code text, _metadata jsonb"},{"name":"business_blueprint_module_tenant_type","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_blueprint_module_tenant_type(p_business_type text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  select case public.normalize_declared_business_type(p_business_type)\n    when 'MITIGATION' then 'MITIGATION'\n    when 'ROOFING_COMPANY' then 'ROOFING_COMPANY'\n    when 'PUBLIC_ADJUSTER_FIRM' then 'PUBLIC_ADJUSTER_FIRM'\n    when 'REALTOR' then 'REALTOR'\n    when 'LAWN_CARE' then 'LAWN_CARE'\n    when 'TIRE_SHOP' then 'TIRE_SHOP'\n    when 'AUTO_DETAILING' then 'AUTO_DETAILING'\n    when 'CAFE_QSR' then 'CAFE_QSR'\n    when 'MOBILE_VENDOR' then 'MOBILE_VENDOR'\n    when 'MOBILE_CATERING' then 'MOBILE_CATERING'\n    when 'SHORT_TERM_RENTAL' then 'SHORT_TERM_RENTAL'\n    when 'HANDYMAN' then 'HANDYMAN'\n    when 'EVENT_RENTALS' then 'EVENT_RENTALS'\n    when 'PORTFOLIO_CONTROL_CENTER' then 'PORTFOLIO_CONTROL_CENTER'\n    when 'PLATFORM_ADMIN' then 'PLATFORM_ADMIN'\n    when 'MISC' then 'MISC'\n    else 'CUSTOM_BLUEPRINT'\n  end;\n$function$\n","identity_arguments":"p_business_type text"},{"name":"business_engine_assert_access","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_engine_assert_access(_tenant_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\nbegin\n  if coalesce(auth.role(), '') = 'service_role' then\n    return;\n  end if;\n  if not public.ai_user_in_tenant(_tenant_id) then\n    raise exception 'business_engine_tenant_access_denied' using errcode = '42501';\n  end if;\nend;\n$function$\n","identity_arguments":"_tenant_id uuid"},{"name":"business_engine_attention_trigger","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_engine_attention_trigger()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\nbegin\n  perform public.business_engine_refresh_attention(new.id);\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"business_engine_refresh_attention","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_engine_refresh_attention(_opportunity_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\ndeclare\n  o public.business_opportunities%rowtype;\n  key_prefix text;\nbegin\n  select * into o from public.business_opportunities where id = _opportunity_id;\n  if not found then\n    raise exception 'business_opportunity_not_found';\n  end if;\n  perform public.business_engine_assert_access(o.tenant_id);\n  key_prefix := o.id::text || ':';\n\n  update public.business_attention_items a\n     set state = 'resolved', resolved_at = now(), updated_at = now()\n   where a.opportunity_id = o.id\n     and a.state in ('open','acknowledged')\n     and (\n       (a.kind = 'opportunity_response_due' and not (o.lifecycle_state = 'captured' and o.response_due_at is not null)) or\n       (a.kind = 'proposal_followup_due' and not (o.proposal_state = 'sent' and o.proposal_followup_due_at is not null)) or\n       (a.kind = 'deposit_due' and not (o.payment_state in ('deposit_due','deposit_overdue'))) or\n       (a.kind = 'scheduling_needed' and not (o.lifecycle_state = 'won' and o.fulfillment_state = 'not_scheduled')) or\n       (a.kind = 'balance_due' and not (o.payment_state in ('balance_due','balance_overdue')))\n     );\n\n  if o.lifecycle_state = 'captured' and o.response_due_at is not null then\n    insert into public.business_attention_items\n      (tenant_id, opportunity_id, kind, priority, deterministic_key, title, summary, due_at, source_state)\n    values\n      (o.tenant_id, o.id, 'opportunity_response_due', 'high', key_prefix || 'opportunity_response_due',\n       'Respond to new opportunity', o.title, o.response_due_at, o.lifecycle_state)\n    on conflict (tenant_id, deterministic_key) do update set\n      title = excluded.title,\n      summary = excluded.summary,\n      due_at = excluded.due_at,\n      source_state = excluded.source_state,\n      state = case when business_attention_items.state = 'resolved' then 'open' else business_attention_items.state end,\n      resolved_at = case when business_attention_items.state = 'resolved' then null else business_attention_items.resolved_at end,\n      updated_at = now();\n  end if;\n\n  if o.proposal_state = 'sent' and o.proposal_followup_due_at is not null then\n    insert into public.business_attention_items\n      (tenant_id, opportunity_id, kind, priority, deterministic_key, title, summary, due_at, source_state)\n    values\n      (o.tenant_id, o.id, 'proposal_followup_due', 'high', key_prefix || 'proposal_followup_due',\n       'Proposal needs follow-up', o.title, o.proposal_followup_due_at, o.proposal_state)\n    on conflict (tenant_id, deterministic_key) do update set\n      title = excluded.title,\n      summary = excluded.summary,\n      due_at = excluded.due_at,\n      source_state = excluded.source_state,\n      state = case when business_attention_items.state = 'resolved' then 'open' else business_attention_items.state end,\n      resolved_at = case when business_attention_items.state = 'resolved' then null else business_attention_items.resolved_at end,\n      updated_at = now();\n  end if;\n\n  if o.payment_state in ('deposit_due','deposit_overdue') then\n    insert into public.business_attention_items\n      (tenant_id, opportunity_id, kind, priority, deterministic_key, title, summary, due_at, source_state)\n    values\n      (o.tenant_id, o.id, 'deposit_due', case when o.payment_state = 'deposit_overdue' then 'urgent' else 'high' end,\n       key_prefix || 'deposit_due', 'Deposit needs attention', o.title, o.deposit_due_at, o.payment_state)\n    on conflict (tenant_id, deterministic_key) do update set\n      priority = excluded.priority,\n      title = excluded.title,\n      summary = excluded.summary,\n      due_at = excluded.due_at,\n      source_state = excluded.source_state,\n      state = case when business_attention_items.state = 'resolved' then 'open' else business_attention_items.state end,\n      resolved_at = case when business_attention_items.state = 'resolved' then null else business_attention_items.resolved_at end,\n      updated_at = now();\n  end if;\n\n  if o.lifecycle_state = 'won' and o.fulfillment_state = 'not_scheduled' then\n    insert into public.business_attention_items\n      (tenant_id, opportunity_id, kind, priority, deterministic_key, title, summary, due_at, source_state)\n    values\n      (o.tenant_id, o.id, 'scheduling_needed', 'high', key_prefix || 'scheduling_needed',\n       'Won opportunity needs scheduling', o.title, o.fulfillment_due_at, o.fulfillment_state)\n    on conflict (tenant_id, deterministic_key) do update set\n      title = excluded.title,\n      summary = excluded.summary,\n      due_at = excluded.due_at,\n      source_state = excluded.source_state,\n      state = case when business_attention_items.state = 'resolved' then 'open' else business_attention_items.state end,\n      resolved_at = case when business_attention_items.state = 'resolved' then null else business_attention_items.resolved_at end,\n      updated_at = now();\n  end if;\n\n  if o.payment_state in ('balance_due','balance_overdue') then\n    insert into public.business_attention_items\n      (tenant_id, opportunity_id, kind, priority, deterministic_key, title, summary, due_at, source_state)\n    values\n      (o.tenant_id, o.id, 'balance_due', case when o.payment_state = 'balance_overdue' then 'urgent' else 'high' end,\n       key_prefix || 'balance_due', 'Outstanding balance needs attention', o.title, o.balance_due_at, o.payment_state)\n    on conflict (tenant_id, deterministic_key) do update set\n      priority = excluded.priority,\n      title = excluded.title,\n      summary = excluded.summary,\n      due_at = excluded.due_at,\n      source_state = excluded.source_state,\n      state = case when business_attention_items.state = 'resolved' then 'open' else business_attention_items.state end,\n      resolved_at = case when business_attention_items.state = 'resolved' then null else business_attention_items.resolved_at end,\n      updated_at = now();\n  end if;\nend;\n$function$\n","identity_arguments":"_opportunity_id uuid"},{"name":"business_engine_touch_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_engine_touch_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nbegin\n  new.updated_at := now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"business_intelligence_event_after_insert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_intelligence_event_after_insert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\nbegin\n  if lower(new.event_type) in ('opportunity_detected','business_opportunity_detected') then\n    perform public.business_materialize_opportunity_from_intelligence(new.id);\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"business_materialize_opportunity_from_intelligence","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_materialize_opportunity_from_intelligence(_event_id uuid)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\ndeclare\n  e public.intelligence_events%rowtype;\n  auto_create boolean;\n  min_conf numeric;\n  response_minutes integer;\n  opportunity_id uuid;\n  normalized_dedupe text;\n  normalized_contact uuid;\nbegin\n  select * into e from public.intelligence_events where id = _event_id;\n  if not found then\n    raise exception 'intelligence_event_not_found';\n  end if;\n  perform public.business_engine_assert_access(e.tenant_id);\n\n  if lower(e.event_type) not in ('opportunity_detected','business_opportunity_detected') then\n    return null;\n  end if;\n\n  select p.auto_create_from_intelligence, p.opportunity_auto_create_min_confidence, p.response_due_minutes\n    into auto_create, min_conf, response_minutes\n    from public.business_workflow_policies p\n   where p.tenant_id = e.tenant_id;\n\n  auto_create := coalesce(auto_create, true);\n  min_conf := coalesce(min_conf, 0.8000);\n  response_minutes := coalesce(response_minutes, 60);\n\n  if not auto_create or coalesce(e.confidence_score, 0) < min_conf then\n    return null;\n  end if;\n\n  normalized_dedupe := coalesce(nullif(btrim(e.dedupe_key), ''),\n    concat_ws(':', e.source_module, coalesce(e.source_entity_type, 'event'), coalesce(e.source_entity_id::text, e.id::text)));\n\n  normalized_contact := e.related_contact_id;\n  if normalized_contact is not null and not exists (\n    select 1 from public.unified_contacts c\n     where c.id = normalized_contact and c.tenant_org_id = e.tenant_id::text\n  ) then\n    normalized_contact := null;\n  end if;\n\n  insert into public.business_opportunities (\n    tenant_id, contact_id, source_event_id, source_module, source_entity_type, source_entity_id,\n    dedupe_key, title, summary, confidence_score, lifecycle_state, response_due_at, created_by, metadata\n  ) values (\n    e.tenant_id, normalized_contact, e.id, e.source_module, e.source_entity_type, e.source_entity_id,\n    normalized_dedupe, e.title, e.summary, e.confidence_score, 'captured',\n    coalesce(e.detected_at, now()) + make_interval(mins => response_minutes), auth.uid(),\n    jsonb_build_object(\n      'why_it_matters', e.why_it_matters,\n      'recommended_action', e.recommended_action,\n      'evidence', e.evidence_json,\n      'normalized_from', 'intelligence_events'\n    )\n  )\n  on conflict (tenant_id, dedupe_key) do update set\n    contact_id = coalesce(business_opportunities.contact_id, excluded.contact_id),\n    source_event_id = excluded.source_event_id,\n    source_module = excluded.source_module,\n    source_entity_type = coalesce(excluded.source_entity_type, business_opportunities.source_entity_type),\n    source_entity_id = coalesce(excluded.source_entity_id, business_opportunities.source_entity_id),\n    summary = coalesce(excluded.summary, business_opportunities.summary),\n    confidence_score = greatest(coalesce(business_opportunities.confidence_score, 0), coalesce(excluded.confidence_score, 0)),\n    metadata = business_opportunities.metadata || excluded.metadata,\n    updated_at = now()\n  returning id into opportunity_id;\n\n  insert into public.business_opportunity_events (\n    tenant_id, opportunity_id, dimension, from_state, to_state, reason_code, actor_user_id, source_event_id, metadata\n  ) values (\n    e.tenant_id, opportunity_id, 'materialization', null, 'captured', 'intelligence_event_materialized',\n    auth.uid(), e.id, jsonb_build_object('dedupe_key', normalized_dedupe, 'confidence_score', e.confidence_score)\n  );\n\n  perform public.business_engine_refresh_attention(opportunity_id);\n  return opportunity_id;\nend;\n$function$\n","identity_arguments":"_event_id uuid"},{"name":"business_now_label","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_now_label()\n RETURNS text\n LANGUAGE sql\n STABLE\n SET search_path TO 'pg_catalog', 'public'\nRETURN to_business_time_label(now())\n","identity_arguments":""},{"name":"business_set_attention_state","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_set_attention_state(_attention_id uuid, _state text)\n RETURNS business_attention_items\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\ndeclare\n  a public.business_attention_items%rowtype;\n  final_a public.business_attention_items%rowtype;\nbegin\n  select * into a from public.business_attention_items where id = _attention_id for update;\n  if not found then raise exception 'business_attention_item_not_found'; end if;\n  perform public.business_engine_assert_access(a.tenant_id);\n  if _state not in ('open','acknowledged','resolved','dismissed') then\n    raise exception 'business_attention_state_invalid:%', _state;\n  end if;\n\n  update public.business_attention_items\n     set state = _state,\n         acknowledged_at = case when _state = 'acknowledged' then now() when _state = 'open' then null else acknowledged_at end,\n         resolved_at = case when _state = 'resolved' then now() when _state = 'open' then null else resolved_at end,\n         dismissed_at = case when _state = 'dismissed' then now() when _state = 'open' then null else dismissed_at end,\n         updated_at = now()\n   where id = a.id;\n  select * into final_a from public.business_attention_items where id = a.id;\n  return final_a;\nend;\n$function$\n","identity_arguments":"_attention_id uuid, _state text"},{"name":"business_timezone","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_timezone()\n RETURNS text\n LANGUAGE sql\n STABLE\n SET search_path TO 'pg_catalog', 'public'\nRETURN 'America/New_York'::text\n","identity_arguments":""},{"name":"business_timezone_label","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_timezone_label()\n RETURNS text\n LANGUAGE sql\n STABLE\n SET search_path TO 'pg_catalog', 'public'\nRETURN 'ET'::text\n","identity_arguments":""},{"name":"business_update_opportunity_terms","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.business_update_opportunity_terms(_opportunity_id uuid, _patch jsonb)\n RETURNS business_opportunities\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\ndeclare\n  o public.business_opportunities%rowtype;\n  final_o public.business_opportunities%rowtype;\n  allowed_keys constant text[] := array[\n    'contact_id','title','summary','category','estimated_value','quoted_amount','deposit_amount','balance_amount',\n    'response_due_at','proposal_followup_due_at','deposit_due_at','fulfillment_due_at','balance_due_at',\n    'event_booking_id','invoice_id','calendar_event_id','metadata'\n  ];\n  unknown_keys text[];\n  linked_id uuid;\nbegin\n  if _patch is null or jsonb_typeof(_patch) <> 'object' then\n    raise exception 'business_terms_patch_object_required';\n  end if;\n\n  select * into o from public.business_opportunities where id = _opportunity_id for update;\n  if not found then raise exception 'business_opportunity_not_found'; end if;\n  perform public.business_engine_assert_access(o.tenant_id);\n\n  select array_agg(k) into unknown_keys\n    from jsonb_object_keys(_patch) as k\n   where not (k = any(allowed_keys));\n  if coalesce(cardinality(unknown_keys), 0) > 0 then\n    raise exception 'business_terms_patch_unknown_keys:%', array_to_string(unknown_keys, ',');\n  end if;\n\n  if _patch ? 'title' and nullif(btrim(coalesce(_patch->>'title','')), '') is null then\n    raise exception 'business_opportunity_title_required';\n  end if;\n  if _patch ? 'metadata' and jsonb_typeof(_patch->'metadata') not in ('object','null') then\n    raise exception 'business_terms_metadata_object_required';\n  end if;\n\n  if _patch ? 'contact_id' and jsonb_typeof(_patch->'contact_id') <> 'null' then\n    linked_id := (_patch->>'contact_id')::uuid;\n    if not exists (select 1 from public.unified_contacts c where c.id = linked_id and c.tenant_org_id = o.tenant_id::text) then\n      raise exception 'business_terms_contact_tenant_mismatch';\n    end if;\n  end if;\n\n  if _patch ? 'event_booking_id' and jsonb_typeof(_patch->'event_booking_id') <> 'null' then\n    linked_id := (_patch->>'event_booking_id')::uuid;\n    if not exists (select 1 from public.event_bookings b where b.id = linked_id and b.tenant_org_id = o.tenant_id::text) then\n      raise exception 'business_terms_event_booking_tenant_mismatch';\n    end if;\n  end if;\n\n  if _patch ? 'invoice_id' and jsonb_typeof(_patch->'invoice_id') <> 'null' then\n    linked_id := (_patch->>'invoice_id')::uuid;\n    if not exists (select 1 from public.invoices i where i.id = linked_id and i.tenant_org_id = o.tenant_id::text) then\n      raise exception 'business_terms_invoice_tenant_mismatch';\n    end if;\n  end if;\n\n  if _patch ? 'calendar_event_id' and jsonb_typeof(_patch->'calendar_event_id') <> 'null' then\n    linked_id := (_patch->>'calendar_event_id')::uuid;\n    if not exists (select 1 from public.user_calendar_events c where c.id = linked_id and c.tenant_org_id = o.tenant_id::text) then\n      raise exception 'business_terms_calendar_event_tenant_mismatch';\n    end if;\n  end if;\n\n  update public.business_opportunities\n     set contact_id = case when _patch ? 'contact_id' then (_patch->>'contact_id')::uuid else contact_id end,\n         title = case when _patch ? 'title' then btrim(_patch->>'title') else title end,\n         summary = case when _patch ? 'summary' then _patch->>'summary' else summary end,\n         category = case when _patch ? 'category' then _patch->>'category' else category end,\n         estimated_value = case when _patch ? 'estimated_value' then (_patch->>'estimated_value')::numeric else estimated_value end,\n         quoted_amount = case when _patch ? 'quoted_amount' then (_patch->>'quoted_amount')::numeric else quoted_amount end,\n         deposit_amount = case when _patch ? 'deposit_amount' then (_patch->>'deposit_amount')::numeric else deposit_amount end,\n         balance_amount = case when _patch ? 'balance_amount' then (_patch->>'balance_amount')::numeric else balance_amount end,\n         response_due_at = case when _patch ? 'response_due_at' then (_patch->>'response_due_at')::timestamptz else response_due_at end,\n         proposal_followup_due_at = case when _patch ? 'proposal_followup_due_at' then (_patch->>'proposal_followup_due_at')::timestamptz else proposal_followup_due_at end,\n         deposit_due_at = case when _patch ? 'deposit_due_at' then (_patch->>'deposit_due_at')::timestamptz else deposit_due_at end,\n         fulfillment_due_at = case when _patch ? 'fulfillment_due_at' then (_patch->>'fulfillment_due_at')::timestamptz else fulfillment_due_at end,\n         balance_due_at = case when _patch ? 'balance_due_at' then (_patch->>'balance_due_at')::timestamptz else balance_due_at end,\n         event_booking_id = case when _patch ? 'event_booking_id' then (_patch->>'event_booking_id')::uuid else event_booking_id end,\n         invoice_id = case when _patch ? 'invoice_id' then (_patch->>'invoice_id')::uuid else invoice_id end,\n         calendar_event_id = case when _patch ? 'calendar_event_id' then (_patch->>'calendar_event_id')::uuid else calendar_event_id end,\n         metadata = case when _patch ? 'metadata' and jsonb_typeof(_patch->'metadata') = 'object' then metadata || (_patch->'metadata') else metadata end,\n         updated_at = now()\n   where id = o.id;\n\n  insert into public.business_opportunity_events\n    (tenant_id, opportunity_id, dimension, from_state, to_state, reason_code, actor_user_id, metadata)\n  values\n    (o.tenant_id, o.id, 'terms', null, null, 'terms_updated', auth.uid(), _patch);\n\n  select * into final_o from public.business_opportunities where id = o.id;\n  return final_o;\nend;\n$function$\n","identity_arguments":"_opportunity_id uuid, _patch jsonb"},{"name":"calculate_quality_score","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.calculate_quality_score(p_name text, p_phone text, p_email text, p_address text, p_city text, p_state text, p_zip text)\n RETURNS integer\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_score INTEGER := 0;\nBEGIN\n  IF p_name IS NOT NULL AND LENGTH(TRIM(p_name)) > 2 THEN v_score := v_score + 15; END IF;\n  IF p_phone IS NOT NULL AND LENGTH(REGEXP_REPLACE(p_phone, '[^0-9]', '', 'g')) >= 10 THEN v_score := v_score + 25; END IF;\n  IF p_email IS NOT NULL AND p_email ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}$' THEN v_score := v_score + 15; END IF;\n  IF p_address IS NOT NULL AND LENGTH(TRIM(p_address)) > 5 AND NOT (TRIM(p_address) ~ '^[A-Z]{2}$') THEN v_score := v_score + 20; END IF;\n  IF p_city IS NOT NULL AND LENGTH(TRIM(p_city)) > 2 AND NOT (TRIM(p_city) ~ '^[A-Z]{2}$') THEN v_score := v_score + 15; END IF;\n  IF p_zip IS NOT NULL AND LENGTH(REGEXP_REPLACE(p_zip, '[^0-9]', '', 'g')) >= 5 THEN v_score := v_score + 10; END IF;\n  RETURN v_score;\nEND;\n$function$\n","identity_arguments":"p_name text, p_phone text, p_email text, p_address text, p_city text, p_state text, p_zip text"},{"name":"call_center_tenant_access","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.call_center_tenant_access(target_tenant uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select exists (\n    select 1 from public.user_tenant_memberships tm\n    where tm.tenant_id = target_tenant\n      and tm.user_id = auth.uid()\n      and coalesce(tm.status,'active') = 'active'\n  );\n$function$\n","identity_arguments":"target_tenant uuid"},{"name":"can_access_message_attachment_storage","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.can_access_message_attachment_storage(p_name text, p_user_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'storage'\nAS $function$\n  select\n    p_user_id is not null\n    and (\n      p_user_id = auth.uid()\n      or public.is_system_admin(auth.uid())\n      or coalesce(auth.jwt() ->> 'role', '') = 'service_role'\n    )\n    and exists(\n      select 1\n      from public.message_attachments a\n      join public.messages m on m.id = a.message_id\n      where a.storage_path = p_name\n        and (\n          (m.deleted_at is null and public.can_access_message_conversation(m.conversation_id, p_user_id))\n          or\n          (m.deleted_at is not null and public.can_review_deleted_message_conversation(m.conversation_id, p_user_id))\n        )\n    );\n$function$\n","identity_arguments":"p_name text, p_user_id uuid"},{"name":"can_access_message_conversation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.can_access_message_conversation(p_conversation_id uuid, p_user_id uuid DEFAULT uid())\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select\n    p_user_id is not null\n    and (\n      p_user_id = auth.uid()\n      or public.is_system_admin(auth.uid())\n      or coalesce(auth.jwt() ->> 'role', '') = 'service_role'\n    )\n    and exists (\n      select 1\n      from public.message_conversation_members m\n      where m.conversation_id = p_conversation_id\n        and m.user_id = p_user_id\n    );\n$function$\n","identity_arguments":"p_conversation_id uuid, p_user_id uuid"},{"name":"can_contact","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.can_contact(p_tenant_id uuid, p_contact_id uuid, p_channel text)\n RETURNS boolean\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_prefs record;\n  v_unsubscribed boolean;\n  v_uid uuid := auth.uid();\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       v_uid IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(v_uid), false)\n         AND NOT coalesce(public.is_tenant_member(v_uid, p_tenant_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'contact compliance access denied' USING ERRCODE = '42501';\n  END IF;\n\n  IF p_channel = 'email' THEN\n    SELECT EXISTS(\n      SELECT 1 FROM public.email_unsubscribes\n      WHERE tenant_id = p_tenant_id\n        AND contact_id = p_contact_id\n        AND resubscribed_at IS NULL\n    ) INTO v_unsubscribed;\n    IF v_unsubscribed THEN RETURN false; END IF;\n  END IF;\n\n  SELECT * INTO v_prefs\n  FROM public.contact_communication_preferences\n  WHERE tenant_id = p_tenant_id AND contact_id = p_contact_id;\n\n  IF NOT FOUND THEN RETURN true; END IF;\n  IF v_prefs.do_not_contact_until IS NOT NULL AND v_prefs.do_not_contact_until > now() THEN\n    RETURN false;\n  END IF;\n\n  CASE p_channel\n    WHEN 'email' THEN RETURN coalesce(v_prefs.email_enabled, true);\n    WHEN 'sms' THEN RETURN coalesce(v_prefs.sms_enabled, true);\n    WHEN 'call' THEN RETURN coalesce(v_prefs.call_enabled, true);\n    ELSE RETURN true;\n  END CASE;\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_contact_id uuid, p_channel text"},{"name":"can_manage_experience_studio","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.can_manage_experience_studio()\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$ SELECT public.is_system_admin(auth.uid()); $function$\n","identity_arguments":""},{"name":"can_manage_message_group","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.can_manage_message_group(p_conversation_id uuid, p_user_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select\n    p_user_id is not null\n    and (\n      p_user_id = auth.uid()\n      or public.is_system_admin(auth.uid())\n      or coalesce(auth.jwt() ->> 'role', '') = 'service_role'\n    )\n    and exists (\n      select 1\n      from public.message_conversations c\n      join public.message_conversation_members m\n        on m.conversation_id = c.id\n      where c.id = p_conversation_id\n        and c.kind = 'group'\n        and m.user_id = p_user_id\n        and m.role in ('owner','admin')\n    );\n$function$\n","identity_arguments":"p_conversation_id uuid, p_user_id uuid"},{"name":"can_manage_page_override","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.can_manage_page_override(_user_id uuid, _tenant_scope text)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_tenant_id uuid;\n  v_caller uuid := auth.uid();\nbegin\n  if _user_id is null or _tenant_scope is null then return false; end if;\n  if not (\n    coalesce(auth.jwt()->>'role','')='service_role'\n    or v_caller=_user_id\n    or coalesce(public.is_system_admin(v_caller),false)\n  ) then return false; end if;\n\n  if public.is_platform_admin(_user_id) then return true; end if;\n  begin v_tenant_id := _tenant_scope::uuid;\n  exception when invalid_text_representation then return false;\n  end;\n  return public.is_tenant_owner_or_admin(_user_id, v_tenant_id);\nend;\n$function$\n","identity_arguments":"_user_id uuid, _tenant_scope text"},{"name":"can_review_deleted_message_conversation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.can_review_deleted_message_conversation(p_conversation_id uuid, p_user_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select\n    p_user_id is not null\n    and (\n      p_user_id = auth.uid()\n      or public.is_system_admin(auth.uid())\n      or coalesce(auth.jwt() ->> 'role', '') = 'service_role'\n    )\n    and (\n      public.is_platform_admin(p_user_id)\n      or public.is_system_admin(p_user_id)\n      or exists(\n        select 1\n        from public.message_conversations c\n        where c.id = p_conversation_id\n          and c.tenant_id is not null\n          and public.is_tenant_owner_or_admin(p_user_id, c.tenant_id)\n      )\n    );\n$function$\n","identity_arguments":"p_conversation_id uuid, p_user_id uuid"},{"name":"can_use_live_edit_sidekick_memory","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.can_use_live_edit_sidekick_memory(_user_id uuid, _tenant_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _user_id is not null\n    and _tenant_id is not null\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or auth.uid()=_user_id\n      or public.is_system_admin(auth.uid())\n    )\n    and (\n      public.is_system_admin(_user_id)\n      or public.is_tenant_owner_or_admin(_user_id,_tenant_id)\n      or exists (\n        select 1 from public.user_tenant_access uta\n        where uta.user_id=_user_id\n          and uta.tenant_id=_tenant_id\n          and uta.membership_status='active'\n          and (\n            coalesce(uta.is_owner,false)\n            or lower(coalesce(uta.effective_role,'')) in ('owner','tenant owner','admin')\n          )\n      )\n    );\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"can_view_tenant_member_academy","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.can_view_tenant_member_academy(_viewer uuid, _target uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _viewer is not null\n    and _target is not null\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or auth.uid()=_viewer\n      or public.is_system_admin(auth.uid())\n    )\n    and (\n      _viewer = _target\n      or public.is_system_admin(_viewer)\n      or exists (\n        select 1\n        from public.user_tenant_memberships m_target\n        join public.user_tenant_memberships m_viewer\n          on m_viewer.tenant_id = m_target.tenant_id\n         and m_viewer.user_id = _viewer\n         and m_viewer.status = 'active'\n        where m_target.user_id = _target\n          and m_target.status = 'active'\n          and (\n            m_viewer.is_owner = true\n            or public.is_tenant_owner(_viewer, m_target.tenant_id)\n            or exists (\n              select 1\n              from public.user_roles ur\n              where ur.user_id = _viewer\n                and ur.tenant_id = m_target.tenant_id\n                and ur.role in ('Owner'::app_role, 'Admin'::app_role, 'Tenant Owner'::app_role)\n            )\n          )\n      )\n    );\n$function$\n","identity_arguments":"_viewer uuid, _target uuid"},{"name":"canonical_tenant_application_ids","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.canonical_tenant_application_ids(p_apps jsonb)\n RETURNS jsonb\n LANGUAGE sql\n STABLE\n SET search_path TO 'public'\nAS $function$\nwith source as (\n  select value, ordinality\n  from jsonb_array_elements_text(\n    case when jsonb_typeof(p_apps) = 'array' then p_apps else '[]'::jsonb end\n  ) with ordinality as x(value, ordinality)\n), mapped as (\n  select\n    case value\n      when 'operations' then 'jobs'\n      when 'pipeline' then 'opportunity-radar'\n      when 'queue' then 'booking'\n      when 'orders' then 'jobs'\n      when 'route' then 'route-service-operations'\n      when 'settings' then null\n      else value\n    end as application_id,\n    ordinality\n  from source\n), valid as (\n  select m.application_id, min(m.ordinality) as ordinality\n  from mapped m\n  join public.application_catalog c on c.id = m.application_id\n  where m.application_id is not null\n  group by m.application_id\n)\nselect coalesce(jsonb_agg(application_id order by ordinality), '[]'::jsonb)\nfrom valid;\n$function$\n","identity_arguments":"p_apps jsonb"},{"name":"canonical_tenant_experience_family","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.canonical_tenant_experience_family(p_settings jsonb, p_tenant_type text)\n RETURNS text\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_settings jsonb := coalesce(p_settings, '{}'::jsonb);\n  v_explicit text := lower(trim(coalesce(v_settings ->> 'experience_family', '')));\n  v_type text := upper(regexp_replace(trim(coalesce(p_tenant_type, '')), '[\\s-]+', '_', 'g'));\n  v_legacy_shell text := upper(trim(coalesce(\n    v_settings ->> 'shell_template',\n    v_settings ->> 'shellTemplate',\n    v_settings ->> 'tenant_shell_template',\n    ''\n  )));\nbegin\n  if v_explicit in ('standard', 'modes') then\n    return v_explicit;\n  end if;\n  if v_type = 'PORTFOLIO_CONTROL_CENTER' or v_legacy_shell = 'MODES' then\n    return 'modes';\n  end if;\n  return 'standard';\nend;\n$function$\n","identity_arguments":"p_settings jsonb, p_tenant_type text"},{"name":"canonical_tenant_type","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.canonical_tenant_type(p_value text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$ SELECT public.normalize_declared_business_type(p_value); $function$\n","identity_arguments":"p_value text"},{"name":"capture_owner_invitation_history","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.capture_owner_invitation_history()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_relationship_id uuid;\n  v_display_name text;\nbegin\n  insert into public.owner_tenant_relationships (tenant_id)\n  values (new.tenant_id)\n  on conflict (tenant_id) do nothing;\n\n  select id into v_relationship_id\n  from public.owner_tenant_relationships\n  where tenant_id = new.tenant_id;\n\n  v_display_name := coalesce(nullif(new.name, ''), nullif(new.email, ''), 'Tenant user');\n\n  if lower(coalesce(new.status, '')) = 'sent'\n     and (tg_op = 'INSERT' or lower(coalesce(old.status, '')) is distinct from 'sent') then\n    insert into public.owner_relationship_events (\n      relationship_id, tenant_id, event_type, channel, direction, title, summary,\n      participants, source, source_id, metadata, occurred_at, created_by\n    ) values (\n      v_relationship_id, new.tenant_id, 'invitation_sent', 'platform', 'outbound',\n      'Invitation sent to ' || v_display_name,\n      concat_ws(' • ', nullif(new.email,''), nullif(new.role,'')),\n      jsonb_build_array(jsonb_build_object('name', new.name, 'email', new.email, 'role', new.role)),\n      'user_invitations', new.id::text || ':sent',\n      jsonb_build_object('invitation_id', new.id, 'status', new.status, 'delivery_receipt', new.metadata->'delivery_receipt'),\n      coalesce((new.metadata->>'sent_at')::timestamptz, new.updated_at, now()), new.invited_by\n    )\n    on conflict (tenant_id, source, source_id) where source_id is not null do nothing;\n  end if;\n\n  if lower(coalesce(new.status, '')) = 'failed'\n     and (tg_op = 'INSERT' or lower(coalesce(old.status, '')) is distinct from 'failed') then\n    insert into public.owner_relationship_events (\n      relationship_id, tenant_id, event_type, channel, direction, title, summary,\n      participants, source, source_id, metadata, occurred_at, created_by\n    ) values (\n      v_relationship_id, new.tenant_id, 'invitation_failed', 'platform', 'outbound',\n      'Invitation delivery failed for ' || v_display_name,\n      concat_ws(' • ', nullif(new.email,''), nullif(new.role,'')),\n      jsonb_build_array(jsonb_build_object('name', new.name, 'email', new.email, 'role', new.role)),\n      'user_invitations', new.id::text || ':failed',\n      jsonb_build_object('invitation_id', new.id, 'status', new.status, 'delivery_error', new.metadata->'delivery_error'),\n      new.updated_at, new.invited_by\n    )\n    on conflict (tenant_id, source, source_id) where source_id is not null do nothing;\n  end if;\n\n  if new.accepted_at is not null or lower(coalesce(new.status,'')) = 'accepted' then\n    insert into public.owner_relationship_events (\n      relationship_id, tenant_id, event_type, channel, direction, title, summary,\n      participants, source, source_id, metadata, occurred_at, created_by\n    ) values (\n      v_relationship_id, new.tenant_id, 'invitation_accepted', 'platform', 'inbound',\n      'Invitation accepted by ' || v_display_name,\n      concat_ws(' • ', nullif(new.email,''), nullif(new.role,'')),\n      jsonb_build_array(jsonb_build_object('name', new.name, 'email', new.email, 'role', new.role)),\n      'user_invitations', new.id::text || ':accepted',\n      jsonb_build_object('invitation_id', new.id, 'status', new.status),\n      coalesce(new.accepted_at, new.updated_at, now()), new.invited_by\n    )\n    on conflict (tenant_id, source, source_id) where source_id is not null do nothing;\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"card_grading_audit_status_change","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.card_grading_audit_status_change()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nbegin\n  if new.status is distinct from old.status then\n    if tg_table_name = 'card_grading_submissions' then\n      insert into public.card_grading_workflow_events(\n        tenant_id, submission_id, card_id, event_type, from_status, to_status, actor_user_id\n      ) values (\n        new.tenant_id,\n        new.id,\n        null,\n        'submission_status_changed',\n        old.status,\n        new.status,\n        auth.uid()\n      );\n    elsif tg_table_name = 'card_grading_cards' then\n      insert into public.card_grading_workflow_events(\n        tenant_id, submission_id, card_id, event_type, from_status, to_status, actor_user_id\n      ) values (\n        new.tenant_id,\n        new.submission_id,\n        new.id,\n        'card_status_changed',\n        old.status,\n        new.status,\n        auth.uid()\n      );\n    else\n      raise exception 'Unsupported table for PCG status audit: %', tg_table_name;\n    end if;\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"card_grading_protect_finalized_card","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.card_grading_protect_finalized_card()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  if current_setting('app.card_grading_cert_correction', true) = 'allowed' then\n    return new;\n  end if;\n  if exists (\n    select 1 from public.card_grading_certificates cc\n    where cc.card_id = old.id and cc.published_at is not null\n  ) and (\n    new.cert_number is distinct from old.cert_number\n    or new.grade is distinct from old.grade\n    or new.grade_label is distinct from old.grade_label\n    or new.category is distinct from old.category\n    or new.year is distinct from old.year\n    or new.manufacturer is distinct from old.manufacturer\n    or new.set_name is distinct from old.set_name\n    or new.brand_set is distinct from old.brand_set\n    or new.subset is distinct from old.subset\n    or new.player_character is distinct from old.player_character\n    or new.card_number is distinct from old.card_number\n    or new.variation is distinct from old.variation\n    or new.serial_number is distinct from old.serial_number\n    or new.autograph_present is distinct from old.autograph_present\n    or new.relic_present is distinct from old.relic_present\n  ) then\n    raise exception 'Finalized PCG card identity and grade are immutable; use the audited correction flow';\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"card_grading_protect_published_certificate","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.card_grading_protect_published_certificate()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  if old.published_at is not null\n     and current_setting('app.card_grading_cert_correction', true) <> 'allowed' then\n    raise exception 'Published PCG certificates are immutable; use the audited correction flow';\n  end if;\n  new.updated_at := now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"cc_scrub_text","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.cc_scrub_text(t text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  SELECT CASE\n    WHEN t IS NULL THEN NULL\n    ELSE regexp_replace(\n      t,\n      '(\\+?\\d[\\d\\s().-]{8,}\\d)',\n      '[redacted-phone]',\n      'g'\n    )\n  END\n$function$\n","identity_arguments":"t text"},{"name":"cce_apply_approval_gate","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.cce_apply_approval_gate()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF TG_OP = 'INSERT' THEN\n    IF NEW.requires_approval = false AND public.command_event_requires_approval(NEW.event_type) THEN\n      NEW.requires_approval := true;\n    END IF;\n    IF NEW.requires_approval = true THEN\n      NEW.status := 'pending_approval';\n      NEW.approval_status := 'pending';\n    END IF;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"cce_dispatch_owner_alert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.cce_dispatch_owner_alert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_should_fire boolean := false;\n  v_supabase_url text := 'https://ymntrajfubicyxwwdxxa.supabase.co';\n  v_service_key text;\n  v_event_type text;\n  v_headers jsonb;\nBEGIN\n  -- cc-agent/report invokes cc-notify-owner directly after create/dedupe.\n  -- This trigger is a fallback for system/direct DB event creation only.\n  IF NEW.actor_type = 'agent' THEN\n    RETURN NEW;\n  END IF;\n\n  v_event_type := lower(coalesce(NEW.event_type, ''));\n\n  IF lower(coalesce(NEW.priority, '')) IN ('urgent','blocker') THEN\n    v_should_fire := true;\n  ELSIF NEW.requires_approval = true OR NEW.approval_status = 'pending' THEN\n    v_should_fire := true;\n  ELSIF v_event_type LIKE '%deploy%' THEN\n    v_should_fire := true;\n  END IF;\n\n  IF TG_OP = 'UPDATE' THEN\n    IF (lower(coalesce(OLD.priority,'')) IN ('urgent','blocker'))\n       OR OLD.requires_approval = true\n       OR OLD.approval_status = 'pending'\n       OR lower(coalesce(OLD.event_type,'')) LIKE '%deploy%' THEN\n      RETURN NEW;\n    END IF;\n  END IF;\n\n  IF NOT v_should_fire THEN\n    RETURN NEW;\n  END IF;\n\n  BEGIN\n    SELECT decrypted_secret INTO v_service_key\n    FROM vault.decrypted_secrets WHERE name = 'SUPABASE_SERVICE_ROLE_KEY' LIMIT 1;\n  EXCEPTION WHEN OTHERS THEN\n    NULL;\n  END;\n\n  v_headers := jsonb_build_object('Content-Type','application/json');\n  IF v_service_key IS NOT NULL THEN\n    v_headers := v_headers || jsonb_build_object(\n      'Authorization','Bearer ' || v_service_key,\n      'apikey', v_service_key\n    );\n  END IF;\n\n  PERFORM net.http_post(\n    url := v_supabase_url || '/functions/v1/cc-notify-owner',\n    headers := v_headers,\n    body := jsonb_build_object('event_id', NEW.id)\n  );\n\n  RETURN NEW;\nEXCEPTION WHEN OTHERS THEN\n  INSERT INTO public.command_center_activity_log (\n    tenant_id,\n    command_center_event_id,\n    actor_user_id,\n    actor_role,\n    actor_type,\n    actor_display_name,\n    action_type,\n    new_value,\n    notes\n  ) VALUES (\n    NEW.tenant_id,\n    NEW.id,\n    NULL,\n    'system:cce_dispatch_owner_alert',\n    'system',\n    'Command Center Owner Alert Trigger',\n    'owner_notify_failed',\n    'trigger_exception',\n    'Database trigger failed before invoking cc-notify-owner: ' || SQLERRM\n  );\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"cce_on_insert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.cce_on_insert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nBEGIN\n  INSERT INTO public.command_center_activity_log\n    (tenant_id, command_center_event_id, actor_user_id, actor_role, action_type, new_value, notes)\n  VALUES (NEW.tenant_id, NEW.id, NEW.created_by_user_id, NEW.created_by_role, 'created', NEW.status, NEW.title);\n\n  IF coalesce(NEW.mission_context->>'silent', 'false') <> 'true' THEN\n    INSERT INTO public.notifications (user_id, tenant_id, type, title, message, link, metadata)\n    SELECT DISTINCT ur.user_id, NEW.tenant_id::text, 'command_center',\n           CASE WHEN NEW.priority IN ('urgent','blocker') THEN '🚨 ' ELSE '' END || NEW.title,\n           COALESCE(LEFT(NEW.message, 200), ''),\n           '/command-center/' || NEW.id::text,\n           jsonb_build_object('event_id', NEW.id, 'priority', NEW.priority,\n                              'source_module', NEW.source_module, 'created_by_role', NEW.created_by_role)\n    FROM public.user_roles ur\n    LEFT JOIN public.user_tenant_memberships m\n      ON m.user_id=ur.user_id AND m.tenant_id=ur.tenant_id\n    WHERE ur.user_id <> NEW.created_by_user_id\n      AND (\n        public.is_system_admin(ur.user_id)\n        OR (\n          ur.tenant_id = NEW.tenant_id\n          AND m.status='active'\n          AND ur.role::text IN ('GodMode','Admin','Owner','Tenant Owner','Manager','command_agent')\n        )\n      );\n  END IF;\n  RETURN NEW;\nEND\n$function$\n","identity_arguments":""},{"name":"cce_on_update","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.cce_on_update()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nDECLARE\n  _actor uuid := auth.uid();\n  _role text;\nBEGIN\n  IF _actor IS NOT NULL AND public.is_system_admin(_actor) THEN\n    _role := 'PlatformAdmin';\n  ELSE\n    SELECT ur.role::text INTO _role\n    FROM public.user_tenant_memberships m\n    JOIN public.user_roles ur ON ur.user_id=m.user_id AND ur.tenant_id=m.tenant_id\n    WHERE m.user_id=_actor\n      AND m.tenant_id=NEW.tenant_id\n      AND m.status='active'\n    LIMIT 1;\n  END IF;\n\n  IF NEW.status IS DISTINCT FROM OLD.status THEN\n    INSERT INTO public.command_center_activity_log\n      (tenant_id, command_center_event_id, actor_user_id, actor_role, action_type, old_value, new_value)\n    VALUES (NEW.tenant_id, NEW.id, _actor, _role,\n      CASE NEW.status WHEN 'acknowledged' THEN 'acknowledged' WHEN 'resolved' THEN 'resolved'\n                      WHEN 'closed' THEN 'closed' ELSE 'status_changed' END,\n      OLD.status, NEW.status);\n  END IF;\n\n  IF NEW.assigned_to_user_id IS DISTINCT FROM OLD.assigned_to_user_id THEN\n    INSERT INTO public.command_center_activity_log\n      (tenant_id, command_center_event_id, actor_user_id, actor_role, action_type, old_value, new_value)\n    VALUES (NEW.tenant_id, NEW.id, _actor, _role, 'assigned',\n            OLD.assigned_to_user_id::text, NEW.assigned_to_user_id::text);\n  END IF;\n  RETURN NEW;\nEND\n$function$\n","identity_arguments":""},{"name":"ccm_on_insert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ccm_on_insert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  INSERT INTO public.command_center_activity_log (tenant_id, command_center_event_id, actor_user_id, actor_role, action_type, notes)\n  VALUES (NEW.tenant_id, NEW.command_center_event_id, NEW.sender_user_id, NEW.sender_role, 'replied', LEFT(NEW.message, 200));\n  RETURN NEW;\nEND $function$\n","identity_arguments":""},{"name":"check_account_lockout","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.check_account_lockout(p_email text)\n RETURNS TABLE(is_locked boolean, unlock_at timestamp with time zone, attempts_count integer)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE v_failed_count INT; v_last_attempt TIMESTAMPTZ;\nBEGIN\n  SELECT COUNT(*)::INT, MAX(created_at) INTO v_failed_count, v_last_attempt\n  FROM login_attempts WHERE email = lower(p_email) AND success = false AND created_at > now() - interval '15 minutes';\n  IF v_failed_count >= 5 THEN RETURN QUERY SELECT true, v_last_attempt + interval '15 minutes', v_failed_count;\n  ELSE RETURN QUERY SELECT false, NULL::TIMESTAMPTZ, v_failed_count; END IF;\nEND; $function$\n","identity_arguments":"p_email text"},{"name":"check_event_rental_allocation_capacity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.check_event_rental_allocation_capacity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE v_total integer; v_lifecycle text; v_committed integer;\nBEGIN\n  SELECT a.total_quantity,a.lifecycle_status INTO v_total,v_lifecycle FROM public.event_rental_assets a WHERE a.id=NEW.asset_id AND a.tenant_id=NEW.tenant_id FOR UPDATE;\n  IF NOT FOUND THEN RAISE EXCEPTION 'Event-rental asset does not belong to tenant' USING ERRCODE='23514'; END IF;\n  IF NEW.status IN('reserved','deployed') AND v_lifecycle IN('damaged','repair','retired') THEN RAISE EXCEPTION 'Asset is not allocatable while status is %',v_lifecycle USING ERRCODE='23514'; END IF;\n  IF NEW.status IN('reserved','deployed') THEN\n    SELECT coalesce(sum(x.quantity),0)::integer INTO v_committed FROM public.event_rental_asset_allocations x WHERE x.asset_id=NEW.asset_id AND x.tenant_id=NEW.tenant_id AND x.status IN('reserved','deployed') AND x.id IS DISTINCT FROM NEW.id AND tstzrange(x.starts_at,x.ends_at,'[)')&&tstzrange(NEW.starts_at,NEW.ends_at,'[)');\n    IF v_committed+NEW.quantity>v_total THEN RAISE EXCEPTION 'Asset allocation exceeds available quantity for the requested time window' USING ERRCODE='23514'; END IF;\n  END IF;\n  RETURN NEW;\nEND; $function$\n","identity_arguments":""},{"name":"check_frequency_cap","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.check_frequency_cap(p_tenant_id text, p_phone_normalized text, p_window_days integer DEFAULT 30, p_max_attempts integer DEFAULT 3)\n RETURNS TABLE(allowed boolean, attempts_in_window integer, next_allowed_at timestamp with time zone)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_count int;\n  v_oldest timestamptz;\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT coalesce(public.is_tenant_member(p_tenant_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'frequency cap access denied' USING ERRCODE = '42501';\n  END IF;\n\n  SELECT count(*), min(created_at)\n    INTO v_count, v_oldest\n  FROM public.call_attempts_log\n  WHERE tenant_org_id = p_tenant_id\n    AND phone_normalized = p_phone_normalized\n    AND was_inbound = false\n    AND created_at > now() - (p_window_days || ' days')::interval;\n\n  IF v_count < p_max_attempts THEN\n    RETURN QUERY SELECT true, v_count, NULL::timestamptz;\n  ELSE\n    RETURN QUERY SELECT false, v_count, v_oldest + (p_window_days || ' days')::interval;\n  END IF;\nEND;\n$function$\n","identity_arguments":"p_tenant_id text, p_phone_normalized text, p_window_days integer, p_max_attempts integer"},{"name":"check_public_event_rental_availability","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.check_public_event_rental_availability(p_tenant_slug text, p_event_date date, p_start_time time without time zone, p_end_time time without time zone, p_requested_assets jsonb)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant record;\n  v_start timestamptz;\n  v_end timestamptz;\n  v_result jsonb;\nbegin\n  if p_event_date is null then raise exception 'event_date_required'; end if;\n  if p_event_date < (now() at time zone 'America/New_York')::date then raise exception 'event_date_past'; end if;\n  if p_start_time is null then raise exception 'start_time_required'; end if;\n  if p_end_time is null then raise exception 'end_time_required'; end if;\n\n  v_start := (p_event_date + p_start_time) at time zone 'America/New_York';\n  v_end := (p_event_date + p_end_time) at time zone 'America/New_York';\n  if v_end <= v_start then raise exception 'end_time_invalid'; end if;\n\n  if jsonb_typeof(coalesce(p_requested_assets,'[]'::jsonb)) <> 'array'\n    or jsonb_array_length(coalesce(p_requested_assets,'[]'::jsonb)) = 0\n  then\n    raise exception 'requested_assets_required';\n  end if;\n\n  if exists (\n    select 1\n    from jsonb_array_elements(p_requested_assets) item\n    where coalesce(item->>'asset_id','') !~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'\n      or coalesce(item->>'quantity','') !~ '^[0-9]+$'\n      or (item->>'quantity')::integer < 1\n  ) then\n    raise exception 'requested_asset_quantity_invalid';\n  end if;\n\n  select id,tenant_type,settings,is_active,status into v_tenant\n  from public.tenants\n  where lower(company_slug)=lower(trim(p_tenant_slug))\n  limit 1;\n\n  if v_tenant.id is null then raise exception 'tenant_not_found'; end if;\n  if coalesce(v_tenant.is_active,false) is not true or coalesce(v_tenant.status,'') <> 'active' then raise exception 'tenant_unavailable'; end if;\n  if upper(replace(replace(coalesce(v_tenant.tenant_type,''),'-','_'),' ','_')) not in ('EVENT_RENTAL','EVENT_RENTALS','PARTY_RENTAL','PARTY_RENTALS') then raise exception 'tenant_type_not_supported'; end if;\n  if coalesce(v_tenant.settings->'public_presence'->>'required','false')::boolean is not true then raise exception 'public_presence_unavailable'; end if;\n\n  if exists (\n    select 1\n    from jsonb_array_elements(p_requested_assets) item\n    left join public.event_rental_assets a\n      on a.id=(item->>'asset_id')::uuid\n     and a.tenant_id=v_tenant.id\n     and coalesce(a.lifecycle_status,'available') not in ('retired','deleted','unavailable')\n    where a.id is null\n  ) then\n    raise exception 'requested_asset_invalid';\n  end if;\n\n  with requested as (\n    select (item->>'asset_id')::uuid as asset_id,\n           sum((item->>'quantity')::integer)::integer as requested_quantity\n    from jsonb_array_elements(p_requested_assets) item\n    group by (item->>'asset_id')::uuid\n  ),\n  availability as (\n    select\n      a.id as asset_id,\n      coalesce(nullif(a.metadata->>'public_title',''),a.name) as name,\n      a.total_quantity,\n      r.requested_quantity,\n      coalesce((\n        select sum(x.quantity)\n        from public.event_rental_asset_allocations x\n        where x.tenant_id=v_tenant.id\n          and x.asset_id=a.id\n          and x.status in ('reserved','deployed')\n          and x.starts_at < v_end\n          and x.ends_at > v_start\n      ),0)::integer as committed_quantity\n    from requested r\n    join public.event_rental_assets a on a.id=r.asset_id and a.tenant_id=v_tenant.id\n  )\n  select jsonb_build_object(\n    'available',coalesce(bool_and(requested_quantity <= greatest(total_quantity-committed_quantity,0)),false),\n    'starts_at',v_start,\n    'ends_at',v_end,\n    'assets',coalesce(jsonb_agg(jsonb_build_object(\n      'asset_id',asset_id,\n      'name',name,\n      'requested_quantity',requested_quantity,\n      'total_quantity',total_quantity,\n      'committed_quantity',committed_quantity,\n      'available_quantity',greatest(total_quantity-committed_quantity,0),\n      'available',requested_quantity <= greatest(total_quantity-committed_quantity,0)\n    ) order by name),'[]'::jsonb)\n  ) into v_result\n  from availability;\n\n  return v_result;\nend;\n$function$\n","identity_arguments":"p_tenant_slug text, p_event_date date, p_start_time time without time zone, p_end_time time without time zone, p_requested_assets jsonb"},{"name":"check_public_event_rental_availability_v2","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.check_public_event_rental_availability_v2(p_tenant_slug text, p_event_date date, p_start_time time without time zone, p_end_time time without time zone, p_requested_assets jsonb)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant record;\n  v_start timestamptz;\n  v_end timestamptz;\n  v_blocked_start timestamptz;\n  v_blocked_end timestamptz;\n  v_buffer_minutes integer := 0;\n  v_result jsonb;\nbegin\n  if p_event_date is null then raise exception 'event_date_required'; end if;\n  if p_event_date < (now() at time zone 'America/New_York')::date then raise exception 'event_date_past'; end if;\n  if p_start_time is null then raise exception 'start_time_required'; end if;\n  if p_end_time is null then raise exception 'end_time_required'; end if;\n\n  v_start := (p_event_date + p_start_time) at time zone 'America/New_York';\n  v_end := (p_event_date + p_end_time) at time zone 'America/New_York';\n  if v_end <= v_start then raise exception 'end_time_invalid'; end if;\n\n  if jsonb_typeof(coalesce(p_requested_assets,'[]'::jsonb)) <> 'array'\n    or jsonb_array_length(coalesce(p_requested_assets,'[]'::jsonb)) = 0\n  then\n    raise exception 'requested_assets_required';\n  end if;\n\n  if exists (\n    select 1\n    from jsonb_array_elements(p_requested_assets) item\n    where coalesce(item->>'asset_id','') !~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'\n      or coalesce(item->>'quantity','') !~ '^[0-9]+$'\n      or (item->>'quantity')::integer < 1\n  ) then\n    raise exception 'requested_asset_quantity_invalid';\n  end if;\n\n  select id,tenant_type,settings,is_active,status into v_tenant\n  from public.tenants\n  where lower(company_slug)=lower(trim(p_tenant_slug))\n  limit 1;\n\n  if v_tenant.id is null then raise exception 'tenant_not_found'; end if;\n  if coalesce(v_tenant.is_active,false) is not true or coalesce(v_tenant.status,'') <> 'active' then raise exception 'tenant_unavailable'; end if;\n  if upper(replace(replace(coalesce(v_tenant.tenant_type,''),'-','_'),' ','_')) not in ('EVENT_RENTAL','EVENT_RENTALS','PARTY_RENTAL','PARTY_RENTALS') then raise exception 'tenant_type_not_supported'; end if;\n  if coalesce(v_tenant.settings->'public_presence'->>'required','false')::boolean is not true then raise exception 'public_presence_unavailable'; end if;\n\n  if coalesce(v_tenant.settings#>>'{book_me_directly,event_rental_buffer_minutes}','') ~ '^[0-9]{1,4}$' then\n    v_buffer_minutes := least(greatest((v_tenant.settings#>>'{book_me_directly,event_rental_buffer_minutes}')::integer,0),1440);\n  end if;\n  v_blocked_start := v_start - make_interval(mins => v_buffer_minutes);\n  v_blocked_end := v_end + make_interval(mins => v_buffer_minutes);\n\n  if exists (\n    select 1\n    from jsonb_array_elements(p_requested_assets) item\n    left join public.event_rental_assets a\n      on a.id=(item->>'asset_id')::uuid\n     and a.tenant_id=v_tenant.id\n     and coalesce(a.lifecycle_status,'available') not in ('retired','deleted','unavailable')\n    where a.id is null\n  ) then\n    raise exception 'requested_asset_invalid';\n  end if;\n\n  with requested as (\n    select (item->>'asset_id')::uuid as asset_id,\n           sum((item->>'quantity')::integer)::integer as requested_quantity\n    from jsonb_array_elements(p_requested_assets) item\n    group by (item->>'asset_id')::uuid\n  ),\n  availability as (\n    select\n      a.id as asset_id,\n      coalesce(nullif(a.metadata->>'public_title',''),a.name) as name,\n      a.total_quantity,\n      r.requested_quantity,\n      coalesce((\n        select sum(x.quantity)\n        from public.event_rental_asset_allocations x\n        where x.tenant_id=v_tenant.id\n          and x.asset_id=a.id\n          and x.status in ('reserved','deployed')\n          and x.starts_at < v_blocked_end\n          and x.ends_at > v_blocked_start\n      ),0)::integer as committed_quantity\n    from requested r\n    join public.event_rental_assets a on a.id=r.asset_id and a.tenant_id=v_tenant.id\n  )\n  select jsonb_build_object(\n    'available',coalesce(bool_and(requested_quantity <= greatest(total_quantity-committed_quantity,0)),false),\n    'starts_at',v_start,\n    'ends_at',v_end,\n    'blocked_starts_at',v_blocked_start,\n    'blocked_ends_at',v_blocked_end,\n    'buffer_minutes',v_buffer_minutes,\n    'assets',coalesce(jsonb_agg(jsonb_build_object(\n      'asset_id',asset_id,\n      'name',name,\n      'requested_quantity',requested_quantity,\n      'total_quantity',total_quantity,\n      'committed_quantity',committed_quantity,\n      'available_quantity',greatest(total_quantity-committed_quantity,0),\n      'available',requested_quantity <= greatest(total_quantity-committed_quantity,0)\n    ) order by name),'[]'::jsonb)\n  ) into v_result\n  from availability;\n\n  return v_result;\nend;\n$function$\n","identity_arguments":"p_tenant_slug text, p_event_date date, p_start_time time without time zone, p_end_time time without time zone, p_requested_assets jsonb"},{"name":"claim_auto_unlock_upload_tickets","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.claim_auto_unlock_upload_tickets(p_ip_hash text, p_paths text[])\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_catalog', 'pg_temp'\nAS $function$\nDECLARE\n  v_expected integer;\n  v_claimed integer;\nBEGIN\n  IF coalesce(auth.role(),'') <> 'service_role' THEN\n    RAISE EXCEPTION 'service role required' USING ERRCODE='42501';\n  END IF;\n  v_expected := cardinality(p_paths);\n  IF p_ip_hash !~ '^[0-9a-f]{64}$' OR v_expected IS NULL OR v_expected < 1 OR v_expected > 2 THEN\n    RAISE EXCEPTION 'upload_ticket_invalid' USING ERRCODE='22023';\n  END IF;\n  UPDATE public.auto_unlock_upload_tickets\n     SET consumed_at=now()\n   WHERE ip_hash=p_ip_hash\n     AND object_path=ANY(p_paths)\n     AND consumed_at IS NULL\n     AND expires_at > now();\n  GET DIAGNOSTICS v_claimed = ROW_COUNT;\n  IF v_claimed <> v_expected THEN\n    RAISE EXCEPTION 'upload_ticket_invalid' USING ERRCODE='P0001';\n  END IF;\n  RETURN v_claimed;\nEND;\n$function$\n","identity_arguments":"p_ip_hash text, p_paths text[]"},{"name":"claim_due_pending_voicemail_drops","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.claim_due_pending_voicemail_drops(_limit integer DEFAULT 50)\n RETURNS TABLE(id uuid, tenant_id uuid, rep_id uuid, voicemail_template_id uuid, active_call_session_id uuid, homeowner_call_sid text, slot_requested smallint, rep_release_requested boolean)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  RETURN QUERY\n  WITH due AS (\n    SELECT pvd.id\n    FROM public.pending_voicemail_drops pvd\n    WHERE pvd.status = 'armed'\n      AND pvd.fire_at <= now()\n      AND pvd.playback_started_at IS NULL\n    ORDER BY pvd.fire_at ASC\n    LIMIT _limit\n    FOR UPDATE SKIP LOCKED\n  )\n  UPDATE public.pending_voicemail_drops pvd\n  SET status = 'playback_started',\n      playback_started_at = now(),\n      timing_mode = COALESCE(pvd.timing_mode, 'fallback_delay')\n  FROM due\n  WHERE pvd.id = due.id\n  RETURNING\n    pvd.id,\n    pvd.tenant_id,\n    pvd.rep_id,\n    pvd.voicemail_template_id,\n    pvd.active_call_session_id,\n    pvd.homeowner_call_sid,\n    pvd.slot_requested,\n    pvd.rep_release_requested;\nEND;\n$function$\n","identity_arguments":"_limit integer"},{"name":"claim_next_command_center_mission","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.claim_next_command_center_mission(_worker text, _lease_seconds integer DEFAULT 90)\n RETURNS SETOF command_center_events\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  update public.command_center_events\n  set mission_status = 'superseded',\n      status = 'resolved',\n      last_progress_at = now(),\n      updated_at = now(),\n      mission_context = coalesce(mission_context, '{}'::jsonb) || jsonb_build_object(\n        'superseded_at', now(),\n        'superseded_reason', 'legacy_autopilot_stale_mission_guard',\n        'previous_mission_status', mission_status\n      )\n  where mission_status in ('accepted','queued','pending','running','waiting','retryable')\n    and owner_authorized = true\n    and coalesce(mission_context->>'supervisor_owner','') <> 'cc-execution'\n    and (lease_expires_at is null or lease_expires_at < now())\n    and coalesce(last_progress_at, created_at) < now() - interval '6 hours'\n    and (\n      coalesce(execution_deadline, queue_deadline) is null\n      or coalesce(execution_deadline, queue_deadline) < now()\n    );\n\n  return query\n  with candidate as (\n    select id\n    from public.command_center_events\n    where mission_status in ('accepted','queued','pending','running','waiting','retryable')\n      and owner_authorized = true\n      and coalesce(mission_context->>'supervisor_owner', '') <> 'cc-execution'\n      and (lease_expires_at is null or lease_expires_at < now())\n      and (\n        coalesce(last_progress_at, created_at) >= now() - interval '6 hours'\n        or coalesce(execution_deadline, queue_deadline) >= now()\n      )\n    order by priority desc, created_at\n    for update skip locked\n    limit 1\n  )\n  update public.command_center_events e\n  set leased_by = _worker,\n      lease_expires_at = now() + make_interval(secs => greatest(30, least(_lease_seconds, 300))),\n      mission_status = 'running',\n      mission_phase = coalesce(e.mission_phase, 'preflight'),\n      started_at = coalesce(e.started_at, now()),\n      last_progress_at = now(),\n      attempt_count = e.attempt_count + 1\n  from candidate\n  where e.id = candidate.id\n  returning e.*;\nend;\n$function$\n","identity_arguments":"_worker text, _lease_seconds integer"},{"name":"claim_opportunity_radar_seed","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.claim_opportunity_radar_seed(_tenant_id uuid, _fingerprint text)\n RETURNS boolean\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  affected integer := 0;\nbegin\n  if _tenant_id is null or nullif(btrim(_fingerprint), '') is null then\n    return false;\n  end if;\n\n  insert into public.opportunity_radar_seed_state(\n    tenant_id, fingerprint, status, last_error, last_attempt_at, completed_at, updated_at\n  ) values (\n    _tenant_id, _fingerprint, 'running', null, now(), null, now()\n  )\n  on conflict (tenant_id) do update\n  set fingerprint = excluded.fingerprint,\n      status = 'running',\n      last_error = null,\n      last_attempt_at = now(),\n      completed_at = null,\n      updated_at = now()\n  where public.opportunity_radar_seed_state.fingerprint is distinct from excluded.fingerprint\n     or public.opportunity_radar_seed_state.status in ('failed','waiting_for_location','profile_not_configured')\n     or (public.opportunity_radar_seed_state.status = 'running' and coalesce(public.opportunity_radar_seed_state.last_attempt_at, '-infinity'::timestamptz) < now() - interval '15 minutes');\n\n  get diagnostics affected = row_count;\n  return affected > 0;\nend;\n$function$\n","identity_arguments":"_tenant_id uuid, _fingerprint text"},{"name":"claim_payment_label","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.claim_payment_label(_status claim_payment_lifecycle)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  SELECT CASE _status\n    WHEN 'not_started' THEN 'Not started'\n    WHEN 'claim_info_needed' THEN 'Claim info needed'\n    WHEN 'ready_to_invoice' THEN 'Ready to invoice'\n    WHEN 'invoice_sent' THEN 'Invoice sent'\n    WHEN 'submitted_to_carrier' THEN 'Submitted to carrier'\n    WHEN 'payment_pending' THEN 'Payment pending'\n    WHEN 'check_sent_to_carrier' THEN 'Check sent to carrier'\n    WHEN 'check_sent_direct_to_homeowner' THEN 'Check sent direct to Homeowner'\n    WHEN 'paid' THEN 'Paid'\n    WHEN 'denied' THEN 'Denied'\n    WHEN 'follow_up_needed' THEN 'Follow-up needed'\n  END\n$function$\n","identity_arguments":"_status claim_payment_lifecycle"},{"name":"claim_platform_message_push_jobs","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.claim_platform_message_push_jobs(p_limit integer DEFAULT 30, p_message_id uuid DEFAULT NULL::uuid)\n RETURNS SETOF message_push_outbox\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\n  with picked as (\n    select id from public.message_push_outbox\n    where ( (state in ('pending','retry') and next_attempt_at <= now())\n         or (state='processing' and lease_expires_at < now()) )\n      and (p_message_id is null or message_id=p_message_id)\n    order by created_at\n    for update skip locked\n    limit least(greatest(coalesce(p_limit,30),1),50)\n  )\n  update public.message_push_outbox o\n     set state='processing',attempt_count=o.attempt_count+1,lease_token=gen_random_uuid(),\n         lease_expires_at=now()+interval '120 seconds',updated_at=now()\n    from picked p where o.id=p.id\n  returning o.*;\n$function$\n","identity_arguments":"p_limit integer, p_message_id uuid"},{"name":"classify_lead_origin","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.classify_lead_origin(_source text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  SELECT CASE\n    WHEN _source IS NULL OR _source = '' THEN 'system'\n    WHEN lower(_source) IN (\n      'door canvassing', 'door_canvassing', 'canvassing',\n      'rep_added', 'rep added',\n      'referral',\n      'customer_added', 'customer added',\n      'manual create', 'manual_create', 'manual',\n      'document scan', 'document_scan', 'doc scan'\n    ) THEN 'personal'\n    WHEN lower(_source) IN (\n      'import', 'csv', 'csv_import', 'manual csv upload',\n      'mojo leadstore', 'mojo_leadstore', 'mojo',\n      'skip tracer', 'skip_tracer', 'skiptrace',\n      'batch scanner', 'batch_scanner', 'batch upload',\n      'space coast transfer', 'space_coast_transfer',\n      'integration', 'api'\n    ) THEN 'system'\n    ELSE 'system'\n  END\n$function$\n","identity_arguments":"_source text"},{"name":"clone_onboarding_templates_internal","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.clone_onboarding_templates_internal(p_tenant_id uuid, p_canonical_type text, p_track text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_stages int := 0;\n  v_scripts int := 0;\n  v_dialogues int := 0;\nbegin\n  insert into public.pipeline_stages(\n    tenant_org_id,tenancy_type,pipeline_kind,name,color,order_index,is_active,is_closed,is_won,is_template\n  )\n  select p_tenant_id::text,p_canonical_type,pipeline_kind,name,color,order_index,is_active,is_closed,is_won,false\n  from public.pipeline_stages\n  where is_template=true and tenant_org_id is null\n    and lower(tenancy_type) in (lower(p_canonical_type),lower(p_track))\n  on conflict do nothing;\n  get diagnostics v_stages=row_count;\n\n  insert into public.call_scripts(\n    tenant_org_id,tenancy_type,script_name,script_type,script_content,prompts,is_template,is_active,order_index\n  )\n  select p_tenant_id::text,p_canonical_type,script_name,script_type,script_content,prompts,false,is_active,order_index\n  from public.call_scripts\n  where is_template=true and tenant_org_id is null\n    and lower(tenancy_type) in (lower(p_canonical_type),lower(p_track))\n  on conflict do nothing;\n  get diagnostics v_scripts=row_count;\n\n  insert into public.workflow_dialogue_stages(\n    tenant_org_id,tenancy_type,workflow_id,stage_name,stage_order,script_text,prompts,is_active,is_template\n  )\n  select p_tenant_id::text,p_canonical_type,workflow_id,stage_name,stage_order,script_text,prompts,is_active,false\n  from public.workflow_dialogue_stages\n  where is_template=true and tenant_org_id is null\n    and lower(tenancy_type) in (lower(p_canonical_type),lower(p_track))\n  on conflict do nothing;\n  get diagnostics v_dialogues=row_count;\n\n  return jsonb_build_object('ok',true,'stages',v_stages,'scripts',v_scripts,'dialogues',v_dialogues);\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_canonical_type text, p_track text"},{"name":"close_console_session","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.close_console_session(_session_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\nbegin\n  if auth.uid() is null or not public.is_system_admin(auth.uid()) then\n    raise exception 'Platform owner required' using errcode = '42501';\n  end if;\n\n  update public.command_center_events\n  set status = 'closed', updated_at = now()\n  where id = _session_id\n    and event_type = 'sidekick_conversation_log';\n\n  return found;\nend;\n$function$\n","identity_arguments":"_session_id uuid"},{"name":"command_center_mission_graph","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.command_center_mission_graph(_mission_id uuid, _receipt_limit integer DEFAULT 12, _include_receipts boolean DEFAULT true)\n RETURNS jsonb\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select case when e.id is null then null else jsonb_build_object(\n    'mission', to_jsonb(e),\n    'steps', coalesce((\n      select jsonb_agg(to_jsonb(s) order by s.step_order)\n      from public.command_center_mission_steps s\n      where s.command_center_event_id = e.id\n    ), '[]'::jsonb),\n    'receipts', case when _include_receipts then coalesce((\n      select jsonb_agg(to_jsonb(r) order by r.created_at desc)\n      from (\n        select *\n        from public.command_center_receipts\n        where command_center_event_id = e.id\n        order by created_at desc\n        limit greatest(0, least(coalesce(_receipt_limit,12),100))\n      ) r\n    ), '[]'::jsonb) else '[]'::jsonb end\n  ) end\n  from public.command_center_events e\n  where e.id = _mission_id;\n$function$\n","identity_arguments":"_mission_id uuid, _receipt_limit integer, _include_receipts boolean"},{"name":"command_center_normalize_tenant_ref","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.command_center_normalize_tenant_ref(_value text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE PARALLEL SAFE\n SET search_path TO ''\nAS $function$\n select btrim(regexp_replace(regexp_replace(lower(coalesce(_value,'')), '[^a-z0-9]+',' ','g'),'\\s+',' ','g'));\n$function$\n","identity_arguments":"_value text"},{"name":"command_center_tenant_acronym","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.command_center_tenant_acronym(_value text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE PARALLEL SAFE\n SET search_path TO 'public', 'pg_catalog'\nAS $function$\n with words as (\n  select token, ord from regexp_split_to_table(public.command_center_normalize_tenant_ref(_value),'\\s+') with ordinality as w(token,ord)\n  where token<>'' and token not in ('the','and','of','a','an','inc','llc','ltd','corp','corporation','company','co')\n ) select coalesce(string_agg(left(token,1),'' order by ord),'') from words;\n$function$\n","identity_arguments":"_value text"},{"name":"command_event_requires_approval","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.command_event_requires_approval(_event_type text)\n RETURNS boolean\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  SELECT _event_type = ANY (ARRAY[\n    'comms_drafted',\n    'code_change_proposed',\n    'outbound_customer_message',\n    'code_repo_pr_action',\n    'role_permission_change',\n    'rls_change',\n    'tenant_security_change',\n    'billing_change',\n    'compliance_change',\n    'job_approval',\n    'payment_status_change',\n    'claim_status_change'\n  ]);\n$function$\n","identity_arguments":"_event_type text"},{"name":"compat_settlement_invoices_iud","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.compat_settlement_invoices_iud()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nDECLARE v_row public.invoices;\nBEGIN\n  IF TG_OP = 'DELETE' THEN\n    DELETE FROM public.invoices WHERE id = OLD.id AND tenant_org_id = OLD.tenant_org_id;\n    RETURN OLD;\n  END IF;\n\n  SELECT * INTO v_row FROM public.save_canonical_invoice(\n    NEW.tenant_org_id,\n    jsonb_build_object(\n      'id', NEW.id, 'invoice_id', NEW.invoice_number, 'customer_name', NEW.homeowner_name,\n      'amount', COALESCE(NEW.settlement_amount, NEW.remaining_balance, 0), 'status', NEW.status,\n      'due_date', NEW.due_date, 'contact_id', NEW.contact_id, 'invoice_date', NEW.invoice_date,\n      'notes', NEW.notes, 'payment_terms', NEW.payment_terms, 'insurance_carrier', NEW.insurance_carrier,\n      'claim_number', NEW.claim_number, 'policy_number', NEW.policy_number, 'paid_at', NEW.paid_at,\n      'document_subtype', 'settlement',\n      'document_metadata', jsonb_build_object(\n        'homeowner_name', NEW.homeowner_name, 'property_address', NEW.property_address,\n        'city', NEW.city, 'state', NEW.state, 'zip', NEW.zip,\n        'template_tone', NEW.template_tone, 'invoice_html', NEW.invoice_html,\n        'settlement_amount', NEW.settlement_amount, 'deposit_amount', NEW.deposit_amount,\n        'remaining_balance', NEW.remaining_balance, 'original_total', NEW.original_total,\n        'insurance_payment', NEW.insurance_payment, 'settlement_discount', NEW.settlement_discount,\n        'rep_name', NEW.rep_name, 'rep_phone', NEW.rep_phone, 'rep_email', NEW.rep_email\n      )\n    ),\n    COALESCE(NEW.created_by_user_id::text, auth.uid()::text)\n  );\n  IF NEW.sent_at IS NOT NULL THEN UPDATE public.invoices SET sent_at = NEW.sent_at WHERE id = v_row.id; END IF;\n  NEW.id := v_row.id; NEW.invoice_number := v_row.invoice_id;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"compat_tarping_invoices_iud","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.compat_tarping_invoices_iud()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nDECLARE v_row public.invoices;\nBEGIN\n  IF TG_OP = 'DELETE' THEN\n    DELETE FROM public.invoices WHERE id = OLD.id AND tenant_org_id = OLD.tenant_org_id;\n    RETURN OLD;\n  END IF;\n\n  SELECT * INTO v_row FROM public.save_canonical_invoice(\n    NEW.tenant_org_id,\n    jsonb_build_object(\n      'id', NEW.id, 'invoice_id', NEW.invoice_number, 'customer_name', NEW.insured_name,\n      'customer_email', NEW.customer_email, 'amount', COALESCE(NEW.grand_total, 0),\n      'status', NEW.status, 'contact_id', NEW.contact_id, 'invoice_date', NEW.invoice_date,\n      'payment_terms', NEW.terms, 'insurance_carrier', NEW.insurance_carrier,\n      'claim_number', NEW.claim_number, 'policy_number', NEW.policy_number, 'paid_at', NEW.paid_at,\n      'line_items', COALESCE(NEW.materials_items, '[]'::jsonb) || COALESCE(NEW.labor_items, '[]'::jsonb),\n      'document_subtype', 'emergency_tarping',\n      'document_metadata', jsonb_build_object(\n        'job_number', NEW.job_number, 'insured_name', NEW.insured_name, 'insured_poa', NEW.insured_poa,\n        'property_address', NEW.property_address, 'city', NEW.city, 'state', NEW.state, 'zip', NEW.zip,\n        'customer_phone', NEW.customer_phone, 'date_of_loss', NEW.date_of_loss,\n        'adjuster_name', NEW.adjuster_name, 'adjuster_phone', NEW.adjuster_phone,\n        'materials_items', NEW.materials_items, 'labor_items', NEW.labor_items,\n        'materials_subtotal', NEW.materials_subtotal, 'labor_subtotal', NEW.labor_subtotal,\n        'grand_total', NEW.grand_total, 'service_description', NEW.service_description,\n        'service_date', NEW.service_date, 'crew_size', NEW.crew_size, 'anchor_method', NEW.anchor_method,\n        'distance_note', NEW.distance_note, 'special_conditions', NEW.special_conditions,\n        'trip_miles', NEW.trip_miles, 'trip_hours', NEW.trip_hours,\n        'important_notice', NEW.important_notice, 'photo_urls', NEW.photo_urls\n      )\n    ),\n    COALESCE(NEW.created_by::text, auth.uid()::text)\n  );\n  IF NEW.sent_at IS NOT NULL THEN UPDATE public.invoices SET sent_at = NEW.sent_at WHERE id = v_row.id; END IF;\n  NEW.id := v_row.id; NEW.invoice_number := v_row.invoice_id;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"compile_tenant_business_blueprint_settings","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.compile_tenant_business_blueprint_settings(p_tenant_type text, p_name text, p_settings jsonb, p_merge_legacy boolean DEFAULT false, p_legacy_apps jsonb DEFAULT '[]'::jsonb)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_settings jsonb := coalesce(p_settings,'{}'::jsonb);\n  v_manifest jsonb := case when jsonb_typeof(coalesce(p_settings,'{}'::jsonb)->'tenant_manifest')='object' then coalesce(p_settings,'{}'::jsonb)->'tenant_manifest' else '{}'::jsonb end;\n  v_onboarding jsonb := case when jsonb_typeof(coalesce(p_settings,'{}'::jsonb)->'onboarding_contract')='object' then coalesce(p_settings,'{}'::jsonb)->'onboarding_contract' else '{}'::jsonb end;\n  v_existing_blueprint jsonb; v_generated_blueprint jsonb; v_blueprint jsonb; v_apps jsonb; v_business_type text; v_raw_business_type text; v_model text; v_module_tenant_type text; v_minimal boolean;\nbegin\n  v_existing_blueprint := case when jsonb_typeof(v_settings->'business_operating_blueprint')='object' then v_settings->'business_operating_blueprint' when jsonb_typeof(v_manifest->'businessOperatingBlueprint')='object' then v_manifest->'businessOperatingBlueprint' else '{}'::jsonb end;\n  v_raw_business_type := coalesce(nullif(v_existing_blueprint->>'businessTypeKey',''),nullif(v_manifest#>>'{businessOperatingBlueprint,businessTypeKey}',''),nullif(v_manifest->>'businessTypeKey',''),nullif(v_settings->>'declared_business_type',''),nullif(v_settings->>'business_type',''),nullif(p_tenant_type,''));\n  v_business_type := public.normalize_declared_business_type(v_raw_business_type);\n  if v_business_type is null then if upper(trim(coalesce(v_raw_business_type,''))) in ('PLATFORM','PLATFORM_ADMIN','GODMODE','ADMIN','SYSTEM_ADMIN') then return v_settings; end if; raise exception 'business_blueprint_business_type_required' using errcode='22023'; end if;\n  v_model := coalesce(nullif(v_existing_blueprint->>'operatingModel',''),nullif(v_settings->>'operating_model',''),public.tenant_operating_model_for(v_business_type,v_settings),'general');\n  if jsonb_typeof(v_existing_blueprint)='object' and v_existing_blueprint<>'{}'::jsonb and nullif(v_existing_blueprint->>'operatingModel','') is not null then v_generated_blueprint:='{}'::jsonb; v_blueprint:=v_existing_blueprint; else v_generated_blueprint:=public.build_tenant_business_blueprint(v_business_type,v_settings||jsonb_build_object('declared_business_type',v_business_type,'business_type',v_business_type,'operating_model',v_model),coalesce(nullif(p_name,''),v_business_type)); v_blueprint:=coalesce(v_generated_blueprint,'{}'::jsonb)||v_existing_blueprint; end if;\n  v_apps := public.canonical_tenant_application_ids(v_blueprint->'applications');\n  if p_merge_legacy then v_apps:=public.merge_tenant_application_ids(v_blueprint->'applications',v_settings->'enabled_applications',v_manifest->'applications',v_onboarding->'applications',p_legacy_apps); end if;\n  v_minimal := lower(coalesce(v_settings->>'minimal_workspace','false'))='true';\n  if jsonb_array_length(v_apps)=0 and not v_minimal then v_apps:=public.canonical_tenant_application_ids(public.tenant_blueprint_applications(v_model)); end if;\n  v_module_tenant_type:=public.business_blueprint_module_tenant_type(v_business_type);\n  v_blueprint:=v_blueprint||jsonb_build_object('businessTypeKey',v_business_type,'operatingModel',v_model,'applications',v_apps);\n  v_blueprint:=public.normalize_tenant_business_blueprint_requirements(v_blueprint,v_settings);\n  v_manifest:=v_manifest||jsonb_build_object('businessTypeKey',v_business_type,'moduleTenantType',v_module_tenant_type,'applications',v_apps,'businessOperatingBlueprint',v_blueprint,'source','persisted');\n  v_onboarding:=v_onboarding||jsonb_build_object('declared_tenant_type',v_business_type,'module_tenant_type',v_module_tenant_type,'business_operating_blueprint',v_blueprint,'applications',v_apps);\n  return v_settings||jsonb_build_object('business_type',v_business_type,'declared_business_type',v_business_type,'operating_model',v_model,'business_operating_blueprint',v_blueprint,'enabled_applications',v_apps,'module_tenant_type',v_module_tenant_type,'tenant_manifest',v_manifest,'onboarding_contract',v_onboarding);\nend;\n$function$\n","identity_arguments":"p_tenant_type text, p_name text, p_settings jsonb, p_merge_legacy boolean, p_legacy_apps jsonb"},{"name":"comprehensive_audit_trigger_fn","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.comprehensive_audit_trigger_fn()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_user_id UUID;\n  v_tenant_id UUID;\n  v_resource_id TEXT;\n  v_old_data JSONB;\n  v_new_data JSONB;\n  v_changed JSONB := '{}'::JSONB;\n  v_old_changed JSONB := '{}'::JSONB;\n  v_new_changed JSONB := '{}'::JSONB;\n  v_key TEXT;\n  v_user_name TEXT;\n  v_user_email TEXT;\n  v_resource_name TEXT;\n  v_tenant_name TEXT;\n  v_summary TEXT;\n  v_change_parts TEXT[] := '{}';\n  v_skip_fields TEXT[] := ARRAY['updated_at','created_at','last_touched_at','recency_score','engagement_score','quality_score','property_data_fetched_at','normalized_address','normalized_email','normalized_phone','geocoded_at','geocode_confidence'];\nBEGIN\n  BEGIN\n    v_user_id := auth.uid();\n  EXCEPTION WHEN OTHERS THEN\n    v_user_id := NULL;\n  END;\n\n  IF TG_OP = 'DELETE' THEN\n    v_old_data := to_jsonb(OLD);\n    v_new_data := NULL;\n    v_resource_id := OLD.id::TEXT;\n  ELSIF TG_OP = 'INSERT' THEN\n    v_old_data := NULL;\n    v_new_data := to_jsonb(NEW);\n    v_resource_id := NEW.id::TEXT;\n  ELSE\n    v_old_data := to_jsonb(OLD);\n    v_new_data := to_jsonb(NEW);\n    v_resource_id := NEW.id::TEXT;\n  END IF;\n\n  BEGIN\n    IF TG_OP = 'DELETE' THEN\n      v_tenant_id := COALESCE((v_old_data->>'tenant_org_id')::UUID, (v_old_data->>'tenant_id')::UUID);\n    ELSE\n      v_tenant_id := COALESCE((v_new_data->>'tenant_org_id')::UUID, (v_new_data->>'tenant_id')::UUID);\n    END IF;\n  EXCEPTION WHEN OTHERS THEN\n    v_tenant_id := NULL;\n  END;\n\n  IF v_user_id IS NOT NULL THEN\n    SELECT p.name, p.email INTO v_user_name, v_user_email\n    FROM profiles p WHERE p.id = v_user_id;\n  END IF;\n\n  IF TG_TABLE_NAME = 'unified_contacts' THEN\n    IF TG_OP = 'DELETE' THEN\n      v_resource_name := v_old_data->>'name';\n    ELSE\n      v_resource_name := v_new_data->>'name';\n    END IF;\n  ELSIF TG_TABLE_NAME = 'call_logs' THEN\n    v_resource_name := COALESCE(v_new_data->>'lead_name', v_old_data->>'lead_name');\n  ELSIF TG_TABLE_NAME = 'contact_files' OR TG_TABLE_NAME = 'contact_photos' THEN\n    v_resource_name := COALESCE(v_new_data->>'file_name', v_old_data->>'file_name', v_new_data->>'filename', v_old_data->>'filename');\n  ELSIF TG_TABLE_NAME = 'followups' THEN\n    v_resource_name := COALESCE(v_new_data->>'title', v_old_data->>'title');\n  ELSIF TG_TABLE_NAME = 'profiles' THEN\n    v_resource_name := COALESCE(v_new_data->>'name', v_old_data->>'name');\n  END IF;\n\n  IF v_tenant_id IS NOT NULL THEN\n    SELECT t.name INTO v_tenant_name FROM tenants t WHERE t.id = v_tenant_id;\n  END IF;\n\n  IF TG_OP = 'UPDATE' THEN\n    FOR v_key IN SELECT jsonb_object_keys(v_new_data)\n    LOOP\n      IF v_key = ANY(v_skip_fields) THEN CONTINUE; END IF;\n      IF (v_old_data->v_key)::TEXT IS DISTINCT FROM (v_new_data->v_key)::TEXT THEN\n        v_old_changed := v_old_changed || jsonb_build_object(v_key, v_old_data->v_key);\n        v_new_changed := v_new_changed || jsonb_build_object(v_key, v_new_data->v_key);\n        v_change_parts := v_change_parts || (\n          replace(v_key, '_', ' ') || ': ' ||\n          COALESCE(LEFT(v_old_data->>v_key, 80), '(empty)') || ' -> ' ||\n          COALESCE(LEFT(v_new_data->>v_key, 80), '(empty)')\n        );\n      END IF;\n    END LOOP;\n    IF v_old_changed = '{}'::JSONB THEN\n      RETURN NEW;\n    END IF;\n  ELSE\n    IF TG_OP = 'INSERT' THEN\n      v_new_changed := jsonb_build_object(\n        'name', v_new_data->>'name',\n        'email', v_new_data->>'email',\n        'phone', v_new_data->>'phone',\n        'status', COALESCE(v_new_data->>'contact_status', v_new_data->>'status', v_new_data->>'outcome'),\n        'assigned_to', v_new_data->>'assigned_to',\n        'source', v_new_data->>'source'\n      );\n    ELSIF TG_OP = 'DELETE' THEN\n      v_old_changed := jsonb_build_object(\n        'name', v_old_data->>'name',\n        'email', v_old_data->>'email',\n        'phone', v_old_data->>'phone',\n        'status', COALESCE(v_old_data->>'contact_status', v_old_data->>'status')\n      );\n    END IF;\n  END IF;\n\n  v_summary := COALESCE(v_user_name, v_user_email, 'System') || ' ';\n  IF TG_OP = 'INSERT' THEN\n    v_summary := v_summary || 'created ' || replace(TG_TABLE_NAME, '_', ' ');\n    IF v_resource_name IS NOT NULL THEN v_summary := v_summary || ' \"' || v_resource_name || '\"'; END IF;\n  ELSIF TG_OP = 'UPDATE' THEN\n    v_summary := v_summary || 'updated ' || replace(TG_TABLE_NAME, '_', ' ');\n    IF v_resource_name IS NOT NULL THEN v_summary := v_summary || ' \"' || v_resource_name || '\"'; END IF;\n    IF array_length(v_change_parts, 1) > 0 THEN v_summary := v_summary || ' -- ' || array_to_string(v_change_parts, '; '); END IF;\n  ELSIF TG_OP = 'DELETE' THEN\n    v_summary := v_summary || 'deleted ' || replace(TG_TABLE_NAME, '_', ' ');\n    IF v_resource_name IS NOT NULL THEN v_summary := v_summary || ' \"' || v_resource_name || '\"'; END IF;\n  END IF;\n  IF v_tenant_name IS NOT NULL THEN v_summary := v_summary || ' in ' || v_tenant_name; END IF;\n\n  INSERT INTO comprehensive_audit_logs (\n    user_id, user_email, user_name, tenant_id,\n    event_type, event_category, event_action,\n    resource_type, resource_id, resource_name,\n    old_value, new_value, human_summary, changed_fields,\n    metadata, severity\n  ) VALUES (\n    v_user_id, v_user_email, v_user_name, v_tenant_id,\n    CASE TG_OP WHEN 'INSERT' THEN 'data_create' WHEN 'UPDATE' THEN 'data_update' WHEN 'DELETE' THEN 'data_delete' END,\n    'data',\n    lower(TG_OP) || '_' || TG_TABLE_NAME,\n    TG_TABLE_NAME,\n    COALESCE(v_resource_id, 'unknown'),\n    v_resource_name,\n    CASE WHEN TG_OP = 'UPDATE' THEN v_old_changed WHEN TG_OP = 'DELETE' THEN v_old_changed ELSE NULL END,\n    CASE WHEN TG_OP = 'UPDATE' THEN v_new_changed WHEN TG_OP = 'INSERT' THEN v_new_changed ELSE NULL END,\n    v_summary,\n    CASE WHEN TG_OP = 'UPDATE' THEN\n      (SELECT jsonb_agg(k) FROM jsonb_object_keys(v_old_changed) AS k)\n    ELSE NULL END,\n    jsonb_build_object('table_schema', TG_TABLE_SCHEMA, 'trigger_name', TG_NAME, 'operation', TG_OP, 'tenant_name', v_tenant_name),\n    CASE WHEN TG_OP = 'DELETE' THEN 'warn' ELSE 'info' END\n  );\n\n  IF TG_OP = 'DELETE' THEN RETURN OLD; ELSE RETURN NEW; END IF;\nEND;\n$function$\n","identity_arguments":""},{"name":"compute_primary_role_for_user","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.compute_primary_role_for_user(_user_id uuid)\n RETURNS text\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  SELECT ur.role::text\n  FROM public.user_roles ur\n  WHERE ur.user_id = _user_id\n    AND (\n      coalesce(auth.role(), '') = 'service_role'\n      OR auth.uid() = _user_id\n      OR public.is_system_admin(auth.uid())\n      OR public.shares_tenant_as_manager_pm(auth.uid(), _user_id)\n    )\n  ORDER BY CASE ur.role::text\n    WHEN 'GodMode' THEN 1 WHEN 'Admin' THEN 2 WHEN 'Owner' THEN 3\n    WHEN 'Manager' THEN 4 WHEN 'Rep' THEN 5 ELSE 99 END\n  LIMIT 1;\n$function$\n","identity_arguments":"_user_id uuid"},{"name":"compute_visible_courses","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.compute_visible_courses(_user_id uuid, _tenant_org_id text)\n RETURNS TABLE(course_id uuid, is_required boolean, source text, due_at timestamp with time zone)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT (\n           auth.uid() = _user_id\n           AND coalesce(public.is_tenant_member(_tenant_org_id), false)\n         )\n         AND NOT coalesce(public.can_view_tenant_member_academy(auth.uid(), _user_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'academy visibility access denied' USING ERRCODE = '42501';\n  END IF;\n\n  RETURN QUERY\n  SELECT DISTINCT c.id, r.is_required, 'rule'::text,\n         CASE WHEN r.due_days IS NOT NULL THEN now() + make_interval(days => r.due_days) END\n  FROM public.academy_assignment_rules r\n  JOIN public.academy_courses c ON c.id = r.course_id\n  WHERE r.tenant_org_id = _tenant_org_id\n    AND c.scope = 'tenant'\n    AND c.review_status = 'active'\n    AND c.is_published = true\n    AND EXISTS (\n      SELECT 1 FROM public.user_tenant_access uta\n      WHERE uta.user_id = _user_id\n        AND uta.tenant_id::text = _tenant_org_id\n        AND uta.effective_role = r.role\n    )\n    AND (\n      coalesce(array_length(c.required_module_keys, 1), 0) = 0\n      OR EXISTS (\n        SELECT 1 FROM public.academy_tenant_modules tm\n        WHERE tm.tenant_org_id = _tenant_org_id\n          AND tm.enabled = true\n          AND tm.module_key = ANY (c.required_module_keys)\n      )\n    )\n  UNION\n  SELECT a.course_id, true, 'assignment'::text, a.due_at\n  FROM public.academy_user_assignments a\n  JOIN public.academy_courses c ON c.id = a.course_id\n  WHERE a.tenant_org_id = _tenant_org_id\n    AND a.user_id = _user_id\n    AND c.review_status <> 'retired';\nEND;\n$function$\n","identity_arguments":"_user_id uuid, _tenant_org_id text"},{"name":"consume_capability_delegation_lease","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.consume_capability_delegation_lease(_lease_id uuid, _tenant_id uuid, _capability text, _adapter_key text)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_user_id uuid;\nbegin\n  delete from public.capability_delegation_leases\n  where id = _lease_id\n    and tenant_id = _tenant_id\n    and capability = _capability\n    and adapter_key = _adapter_key\n    and principal_key = 'command_center'\n    and expires_at > now()\n  returning delegated_user_id into v_user_id;\n\n  return v_user_id;\nend;\n$function$\n","identity_arguments":"_lease_id uuid, _tenant_id uuid, _capability text, _adapter_key text"},{"name":"consume_mobile_vendor_loyalty_login_challenge","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.consume_mobile_vendor_loyalty_login_challenge(_tenant_org_id uuid, _challenge_id uuid, _member_id uuid, _expected_attempts integer, _token_hash text, _expires_at timestamp with time zone)\n RETURNS boolean\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_challenge_id uuid;\nbegin\n  update public.mobile_vendor_loyalty_login_challenges\n  set attempts = attempts + 1, consumed_at = now()\n  where tenant_org_id = _tenant_org_id and id = _challenge_id and member_id = _member_id\n    and consumed_at is null and attempts = _expected_attempts and attempts < max_attempts and expires_at > now()\n  returning id into v_challenge_id;\n  if v_challenge_id is null then return false; end if;\n\n  insert into public.mobile_vendor_loyalty_sessions (tenant_org_id, member_id, token_hash, expires_at, last_seen_at)\n  values (_tenant_org_id, _member_id, _token_hash, _expires_at, now());\n  return true;\nend;\n$function$\n","identity_arguments":"_tenant_org_id uuid, _challenge_id uuid, _member_id uuid, _expected_attempts integer, _token_hash text, _expires_at timestamp with time zone"},{"name":"contact_price_overrides_validate_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.contact_price_overrides_validate_tenant()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  if not exists (\n    select 1\n    from public.unified_contacts c\n    where c.id = new.contact_id\n      and c.tenant_org_id = new.tenant_org_id\n      and c.deleted_at is null\n  ) then\n    raise exception 'Contact price override tenant/contact mismatch';\n  end if;\n  new.item_key := lower(regexp_replace(trim(new.item_key), '[^a-zA-Z0-9]+', '_', 'g'));\n  new.currency := upper(coalesce(nullif(trim(new.currency), ''), 'USD'));\n  new.updated_at := now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"copy_templates_to_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.copy_templates_to_tenant(p_tenant_id text, p_tenancy_type text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_copied_stages integer := 0;\n  v_copied_scripts integer := 0;\n  v_copied_dialogues integer := 0;\nbegin\n  perform public.require_platform_operator();\n\n  insert into public.pipeline_stages (\n    tenant_org_id, tenancy_type, pipeline_kind, name, color, order_index,\n    is_active, is_closed, is_won, is_template\n  )\n  select p_tenant_id, p_tenancy_type, pipeline_kind, name, color, order_index,\n    is_active, is_closed, is_won, false\n  from public.pipeline_stages\n  where is_template = true and tenancy_type = p_tenancy_type\n    and tenant_org_id is null\n  on conflict do nothing;\n  get diagnostics v_copied_stages = row_count;\n\n  insert into public.call_scripts (\n    tenant_org_id, tenancy_type, script_name, script_type, script_content,\n    prompts, is_template, is_active, order_index\n  )\n  select p_tenant_id, p_tenancy_type, script_name, script_type, script_content,\n    prompts, false, is_active, order_index\n  from public.call_scripts\n  where is_template = true and tenancy_type = p_tenancy_type\n    and tenant_org_id is null\n  on conflict do nothing;\n  get diagnostics v_copied_scripts = row_count;\n\n  insert into public.workflow_dialogue_stages (\n    tenant_org_id, tenancy_type, workflow_id, stage_name, stage_order,\n    script_text, prompts, is_active, is_template\n  )\n  select p_tenant_id, p_tenancy_type, workflow_id, stage_name, stage_order,\n    script_text, prompts, is_active, false\n  from public.workflow_dialogue_stages\n  where is_template = true and tenancy_type = p_tenancy_type\n    and tenant_org_id is null\n  on conflict do nothing;\n  get diagnostics v_copied_dialogues = row_count;\n\n  return jsonb_build_object(\n    'ok', true,\n    'copied_stages', v_copied_stages,\n    'copied_scripts', v_copied_scripts,\n    'copied_dialogues', v_copied_dialogues,\n    'tenant_id', p_tenant_id,\n    'tenancy_type', p_tenancy_type\n  );\nend;\n$function$\n","identity_arguments":"p_tenant_id text, p_tenancy_type text"},{"name":"correct_card_grading_certificate","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.correct_card_grading_certificate(p_tenant_id uuid, p_cert_number text, p_final_grade numeric, p_grade_label text, p_reason text)\n RETURNS void\n LANGUAGE plpgsql\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_cert public.card_grading_certificates%rowtype;\nbegin\n  if auth.uid() is null or not (\n    public.is_system_admin(auth.uid())\n    or exists (\n      select 1 from public.security_active_user_tenant_memberships m\n      where m.user_id = auth.uid() and m.status = 'active' and m.tenant_id = p_tenant_id and m.is_owner = true\n    )\n  ) then\n    raise exception 'Owner or platform-admin authority required' using errcode = '42501';\n  end if;\n  if nullif(btrim(coalesce(p_reason,'')),'') is null then\n    raise exception 'Correction reason is required';\n  end if;\n\n  select * into v_cert\n  from public.card_grading_certificates\n  where tenant_id = p_tenant_id and cert_number = btrim(p_cert_number)\n  for update;\n  if v_cert.id is null then raise exception 'Certificate unavailable'; end if;\n\n  perform set_config('app.card_grading_cert_correction','allowed',true);\n\n  update public.card_grading_certificates\n     set final_grade = p_final_grade,\n         grade_label = p_grade_label,\n         updated_at = now()\n   where id = v_cert.id;\n\n  update public.card_grading_cards\n     set grade = p_final_grade,\n         grade_label = p_grade_label,\n         updated_at = now()\n   where id = v_cert.card_id and tenant_id = p_tenant_id;\n\n  insert into public.card_grading_workflow_events(\n    tenant_id, card_id, event_type, actor_user_id, reason, metadata\n  ) values (\n    p_tenant_id, v_cert.card_id, 'certificate_corrected', auth.uid(), btrim(p_reason),\n    jsonb_build_object(\n      'cert_number', v_cert.cert_number,\n      'previous_grade', v_cert.final_grade,\n      'previous_grade_label', v_cert.grade_label,\n      'new_grade', p_final_grade,\n      'new_grade_label', p_grade_label\n    )\n  );\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_cert_number text, p_final_grade numeric, p_grade_label text, p_reason text"},{"name":"create_command_center_mission","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.create_command_center_mission(_tenant_id uuid, _objective text, _mission_type text DEFAULT 'platform_operation'::text, _priority text DEFAULT 'task'::text, _context jsonb DEFAULT '{}'::jsonb)\n RETURNS command_center_events\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _uid uuid := auth.uid();\n  _event public.command_center_events;\nBEGIN\n  IF _uid IS NULL OR NOT public.is_command_agent(_uid, _tenant_id) THEN\n    RAISE EXCEPTION 'not_authorized';\n  END IF;\n  IF nullif(trim(_objective), '') IS NULL THEN\n    RAISE EXCEPTION 'objective_required';\n  END IF;\n\n  INSERT INTO public.command_center_events (\n    tenant_id, created_by_user_id, created_by_role, source_module, event_type,\n    priority, title, message, status, requires_response, requires_approval,\n    approval_status, actor_type, actor_display_name, mission_type, mission_phase,\n    mission_status, owner_authorized, authorization_scope, current_step,\n    queue_deadline, execution_deadline, last_progress_at, mission_context\n  ) VALUES (\n    _tenant_id, _uid, 'GodMode', 'system', 'owner_mission',\n    _priority, left(trim(_objective), 140), trim(_objective), 'in_progress', true, false,\n    'approved', 'human', 'Owner', _mission_type, 'objective_received',\n    'accepted', true, 'Owner objective and all reasonably necessary safe supporting work', 0,\n    now() + interval '5 minutes', now() + interval '4 hours', now(), coalesce(_context, '{}'::jsonb)\n  ) RETURNING * INTO _event;\n\n  INSERT INTO public.command_center_mission_steps\n    (tenant_id, command_center_event_id, step_order, step_key, title, lane, status, idempotency_key, input, deadline_at)\n  VALUES\n    (_tenant_id, _event.id, 10, 'preflight', 'Inspect current truth and establish execution plan', 'command-center-autopilot', 'ready', 'mission:' || _event.id || ':preflight', _context, now() + interval '10 minutes'),\n    (_tenant_id, _event.id, 20, 'implementation', 'Prepare the bounded implementation change', 'cc-execution', 'pending', 'mission:' || _event.id || ':implementation', _context, now() + interval '2 hours'),\n    (_tenant_id, _event.id, 30, 'pull_request', 'Open and evaluate the exact pull request', 'cc-execution', 'pending', 'mission:' || _event.id || ':pull_request', _context, now() + interval '2 hours 30 minutes'),\n    (_tenant_id, _event.id, 40, 'release', 'Merge and deploy through the canonical release conductor', 'production-release-conductor', 'pending', 'mission:' || _event.id || ':release', _context, now() + interval '3 hours'),\n    (_tenant_id, _event.id, 50, 'runtime_proof', 'Verify immutable production runtime identity', 'cc-execution', 'pending', 'mission:' || _event.id || ':runtime_proof', _context, now() + interval '3 hours 30 minutes'),\n    (_tenant_id, _event.id, 60, 'visual_proof', 'Run owner-requested authenticated visual acceptance when required', 'onrunner', 'pending', 'mission:' || _event.id || ':visual_proof', _context, now() + interval '4 hours');\n\n  RETURN _event;\nEND;\n$function$\n","identity_arguments":"_tenant_id uuid, _objective text, _mission_type text, _priority text, _context jsonb"},{"name":"create_job_from_contact","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.create_job_from_contact(_contact_id uuid)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_contact public.unified_contacts%ROWTYPE;\n  v_tenant uuid;\n  v_job_id uuid;\n  v_uid uuid := auth.uid();\nBEGIN\n  SELECT * INTO v_contact FROM public.unified_contacts WHERE id = _contact_id;\n  IF NOT FOUND THEN RAISE EXCEPTION 'Contact % not found', _contact_id; END IF;\n\n  v_tenant := v_contact.tenant_org_id::uuid;\n\n  IF NOT (public.is_system_admin(v_uid) OR public.is_manager_or_higher(v_uid, v_tenant)) THEN\n    RAISE EXCEPTION 'Not authorized to create jobs for tenant %', v_tenant;\n  END IF;\n\n  -- Idempotent: return existing if already created\n  SELECT id INTO v_job_id FROM public.jobs\n    WHERE tenant_id = v_tenant AND contact_id = _contact_id\n    ORDER BY created_at ASC LIMIT 1;\n  IF v_job_id IS NOT NULL THEN RETURN v_job_id; END IF;\n\n  INSERT INTO public.jobs (\n    tenant_id, contact_id, customer_name, customer_phone,\n    property_address, city, state, zip,\n    job_type, status,\n    scheduled_date, appointment_date,\n    assigned_crew_id, created_by\n  ) VALUES (\n    v_tenant, _contact_id,\n    COALESCE(NULLIF(v_contact.name,''), trim(coalesce(v_contact.first_name,'')||' '||coalesce(v_contact.last_name,''))),\n    v_contact.phone,\n    COALESCE(v_contact.address, ''), v_contact.city, v_contact.state, v_contact.zip,\n    'tarp', 'scheduled',\n    COALESCE(v_contact.appt_date, CURRENT_DATE), v_contact.appt_date::timestamptz,\n    NULL, v_uid\n  ) RETURNING id INTO v_job_id;\n\n  RETURN v_job_id;\nEND $function$\n","identity_arguments":"_contact_id uuid"},{"name":"create_notification_for_user","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.create_notification_for_user(p_user_id uuid, p_tenant_id uuid, p_type text, p_title text, p_message text DEFAULT NULL::text, p_link text DEFAULT NULL::text, p_metadata jsonb DEFAULT NULL::jsonb)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_caller uuid := auth.uid();\n  v_id uuid;\n  v_service boolean := coalesce(auth.jwt() ->> 'role','') = 'service_role';\n  v_platform_admin boolean := false;\nbegin\n  if not v_service and v_caller is null then\n    raise exception 'not authenticated' using errcode='42501';\n  end if;\n  if p_user_id is null then\n    raise exception 'notification recipient required' using errcode='22023';\n  end if;\n  if not v_service then\n    v_platform_admin := coalesce(public.is_system_admin(v_caller), false);\n    if p_tenant_id is null then\n      if p_user_id <> v_caller and not v_platform_admin then\n        raise exception 'cross-user notification denied' using errcode='42501';\n      end if;\n    else\n      if not public.is_tenant_member(v_caller, p_tenant_id) then\n        raise exception 'caller not a member of tenant' using errcode='42501';\n      end if;\n      if not public.is_tenant_member(p_user_id, p_tenant_id) then\n        raise exception 'recipient not a member of tenant' using errcode='42501';\n      end if;\n    end if;\n  end if;\n  insert into public.notifications(user_id, tenant_id, type, title, message, link, metadata)\n  values(p_user_id, p_tenant_id, p_type, p_title, p_message, p_link, p_metadata)\n  returning id into v_id;\n  return v_id;\nend;\n$function$\n","identity_arguments":"p_user_id uuid, p_tenant_id uuid, p_type text, p_title text, p_message text, p_link text, p_metadata jsonb"},{"name":"create_or_resume_command_center_agent_mission","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.create_or_resume_command_center_agent_mission(_mission_key text, _objective text, _tenant_ref text DEFAULT NULL::text, _mission_type text DEFAULT 'platform_operation'::text, _context jsonb DEFAULT '{}'::jsonb)\n RETURNS command_center_events\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'extensions'\nAS $function$\ndeclare\n  _existing public.command_center_events;\n  _target_tenant_id uuid;\n  _target_tenant_name text;\n  _target_tenant_slug text;\n  _anchor_tenant_id uuid;\n  _anchor_owner_id uuid;\n  _creator_id uuid;\n  _scope text;\n  _merged_context jsonb;\n  _normalized_ref text;\n  _resolution_status text := 'not_requested';\n  _resolution_confidence double precision;\n  _resolution_method text;\n  _resolution_candidates jsonb := '[]'::jsonb;\n  _second_confidence double precision;\nbegin\n  if nullif(trim(_mission_key), '') is null then\n    raise exception 'mission_key_required';\n  end if;\n  if nullif(trim(_objective), '') is null then\n    raise exception 'objective_required';\n  end if;\n\n  select * into _existing\n  from public.command_center_events\n  where event_type = 'owner_mission'\n    and mission_context->>'mission_key' = trim(_mission_key)\n  order by created_at desc\n  limit 1;\n\n  if found then\n    return _existing;\n  end if;\n\n  _normalized_ref := public.command_center_normalize_tenant_ref(_tenant_ref);\n  if _normalized_ref <> '' then\n    with resolved as materialized (\n      select r.tenant_id, r.tenant_name, r.company_slug, r.confidence, r.match_kind\n      from public.resolve_command_center_tenant_reference(_tenant_ref) r\n      order by r.confidence desc, r.tenant_name asc\n      limit 3\n    ), packed as (\n      select coalesce(\n        jsonb_agg(\n          jsonb_build_object(\n            'tenant_id', tenant_id,\n            'name', tenant_name,\n            'slug', company_slug,\n            'confidence', round(confidence::numeric, 4),\n            'match_kind', match_kind\n          ) order by confidence desc, tenant_name asc\n        ),\n        '[]'::jsonb\n      ) as candidates\n      from resolved\n    )\n    select\n      candidates,\n      nullif(candidates->0->>'tenant_id', '')::uuid,\n      candidates->0->>'name',\n      candidates->0->>'slug',\n      nullif(candidates->0->>'confidence', '')::double precision,\n      candidates->0->>'match_kind',\n      nullif(candidates->1->>'confidence', '')::double precision\n    into _resolution_candidates, _target_tenant_id, _target_tenant_name, _target_tenant_slug,\n         _resolution_confidence, _resolution_method, _second_confidence\n    from packed;\n\n    if _target_tenant_id is not null\n       and _resolution_confidence >= 0.88\n       and (_second_confidence is null or _resolution_confidence - _second_confidence >= 0.08)\n    then\n      _resolution_status := 'resolved';\n    else\n      _target_tenant_id := null;\n      _target_tenant_name := null;\n      _target_tenant_slug := null;\n      _resolution_status := case\n        when jsonb_array_length(_resolution_candidates) > 0 then 'ambiguous'\n        else 'unresolved'\n      end;\n    end if;\n  end if;\n\n  if _target_tenant_id is not null then\n    select id, owner_id into _anchor_tenant_id, _anchor_owner_id\n    from public.tenants where id = _target_tenant_id;\n    _scope := 'tenant';\n  else\n    select id, owner_id into _anchor_tenant_id, _anchor_owner_id\n    from public.tenants\n    where company_slug = 'knocklaunch-crm' and status = 'active'\n    order by created_at asc\n    limit 1;\n    if _anchor_tenant_id is null then raise exception 'platform_mission_anchor_unavailable'; end if;\n    _scope := 'platform';\n  end if;\n\n  if _anchor_tenant_id is null then raise exception 'mission_anchor_tenant_unavailable'; end if;\n\n  select id into _creator_id\n  from public.profiles\n  where lower(coalesce(email, '')) = 'info@knocklaunch.app'\n  limit 1;\n  _creator_id := coalesce(_creator_id, _anchor_owner_id);\n  if _creator_id is null then raise exception 'mission_owner_identity_unavailable'; end if;\n\n  if _resolution_status = 'resolved' and _resolution_confidence >= 0.90 and _normalized_ref <> '' then\n    insert into public.command_center_tenant_aliases(\n      tenant_id, alias, normalized_alias, source, confidence, use_count, last_used_at\n    )\n    values(\n      _target_tenant_id, trim(_tenant_ref), _normalized_ref,\n      'adaptive_high_confidence', _resolution_confidence, 1, now()\n    )\n    on conflict(tenant_id, normalized_alias) do update\n    set alias = excluded.alias,\n        confidence = greatest(public.command_center_tenant_aliases.confidence, excluded.confidence),\n        use_count = public.command_center_tenant_aliases.use_count + 1,\n        last_used_at = now();\n  end if;\n\n  _merged_context := coalesce(_context, '{}'::jsonb) || jsonb_strip_nulls(jsonb_build_object(\n    'mission_key', trim(_mission_key), 'scope', _scope,\n    'target_tenant_id', _target_tenant_id, 'target_tenant_name', _target_tenant_name,\n    'target_tenant_slug', _target_tenant_slug,\n    'tenant_reference_input', nullif(trim(_tenant_ref), ''),\n    'tenant_reference_normalized', nullif(_normalized_ref, ''),\n    'tenant_resolution_status', _resolution_status,\n    'tenant_resolution_confidence', _resolution_confidence,\n    'tenant_resolution_method', _resolution_method,\n    'tenant_resolution_candidates', _resolution_candidates,\n    'anchor_tenant_id', _anchor_tenant_id, 'silent', true,\n    'supervisor_owner', 'cc-execution',\n    'conversation_metrics', jsonb_build_object(\n      'tool_call_count', 0, 'repeated_call_count', 0, 'receipt_bytes', 0,\n      'release_count', 0, 'owner_interruption_count', 0, 'tool_call_keys', '[]'::jsonb\n    )\n  ));\n\n  begin\n    insert into public.command_center_events(\n      tenant_id, created_by_user_id, created_by_role, source_module, event_type,\n      priority, title, message, status, requires_response, requires_approval,\n      approval_status, actor_type, actor_display_name, mission_type, mission_phase,\n      mission_status, owner_authorized, authorization_scope, current_step,\n      queue_deadline, execution_deadline, started_at, last_progress_at,\n      leased_by, lease_expires_at, mission_context\n    )\n    values(\n      _anchor_tenant_id, _creator_id, 'GodMode', 'system', 'owner_mission',\n      'task', left(trim(_objective), 140), trim(_objective), 'in_progress', true,\n      false, 'approved', 'human', 'Owner',\n      coalesce(nullif(trim(_mission_type), ''), 'platform_operation'),\n      'objective_received', 'accepted', true,\n      'Owner objective and all reasonably necessary safe supporting work',\n      0, now() + interval '5 minutes', now() + interval '4 hours', now(), now(),\n      'cc-execution-objective-supervisor', now() + interval '4 hours', _merged_context\n    ) returning * into _existing;\n  exception when unique_violation then\n    select * into _existing\n    from public.command_center_events\n    where event_type = 'owner_mission' and mission_context->>'mission_key' = trim(_mission_key)\n    order by created_at desc limit 1;\n  end;\n\n  insert into public.command_center_mission_steps(\n    tenant_id, command_center_event_id, step_order, step_key, title, lane,\n    status, idempotency_key, input, deadline_at\n  ) values\n    (_anchor_tenant_id, _existing.id, 10, 'preflight', 'Inspect current truth and establish execution plan', 'cc-execution', 'ready', 'mission:' || _existing.id || ':preflight', _merged_context, now() + interval '10 minutes'),\n    (_anchor_tenant_id, _existing.id, 20, 'implementation', 'Prepare the bounded implementation change', 'cc-execution', 'pending', 'mission:' || _existing.id || ':implementation', _merged_context, now() + interval '2 hours'),\n    (_anchor_tenant_id, _existing.id, 30, 'pull_request', 'Open and evaluate the exact pull request', 'cc-execution', 'pending', 'mission:' || _existing.id || ':pull_request', _merged_context, now() + interval '2 hours 30 minutes'),\n    (_anchor_tenant_id, _existing.id, 40, 'release', 'Merge and deploy through the canonical release conductor', 'production-release-conductor', 'pending', 'mission:' || _existing.id || ':release', _merged_context, now() + interval '3 hours'),\n    (_anchor_tenant_id, _existing.id, 50, 'runtime_proof', 'Verify immutable production runtime identity', 'cc-execution', 'pending', 'mission:' || _existing.id || ':runtime_proof', _merged_context, now() + interval '3 hours 30 minutes'),\n    (_anchor_tenant_id, _existing.id, 60, 'visual_proof', 'Run owner-requested authenticated visual acceptance when required', 'onrunner', 'pending', 'mission:' || _existing.id || ':visual_proof', _merged_context, now() + interval '4 hours')\n  on conflict(command_center_event_id, step_key) do nothing;\n\n  return _existing;\nend;\n$function$\n","identity_arguments":"_mission_key text, _objective text, _tenant_ref text, _mission_type text, _context jsonb"},{"name":"create_platform_message_conversation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.create_platform_message_conversation(p_kind text, p_member_ids uuid[] DEFAULT ARRAY[]::uuid[], p_tenant_id uuid DEFAULT NULL::uuid, p_title text DEFAULT NULL::text)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  caller uuid := auth.uid();\n  normalized_kind text := lower(trim(coalesce(p_kind,'')));\n  members uuid[];\n  conv_id uuid;\n  key text;\n  invalid_count integer;\nbegin\n  if caller is null then raise exception 'authentication_required'; end if;\n\n  if normalized_kind = 'tenant' then\n    if p_tenant_id is null or not public.is_active_message_tenant_member(p_tenant_id, caller) then\n      raise exception 'tenant_membership_required';\n    end if;\n    select id into conv_id from public.message_conversations\n      where kind='tenant' and tenant_id=p_tenant_id limit 1;\n    if conv_id is null then\n      begin\n        insert into public.message_conversations(kind,tenant_id,title,created_by)\n        values('tenant',p_tenant_id,null,caller) returning id into conv_id;\n      exception when unique_violation then\n        select id into conv_id from public.message_conversations where kind='tenant' and tenant_id=p_tenant_id limit 1;\n      end;\n    end if;\n    insert into public.message_conversation_members(conversation_id,user_id,role)\n      select conv_id, u.user_id, case when u.user_id=caller then 'owner' else 'member' end\n      from (\n        select caller as user_id\n        union\n        select t.owner_id from public.tenants t where t.id=p_tenant_id and t.owner_id is not null\n        union\n        select m.user_id from public.user_tenant_memberships m where m.tenant_id=p_tenant_id and m.status='active'\n      ) u\n      where u.user_id is not null\n      on conflict (conversation_id,user_id) do nothing;\n    return conv_id;\n  end if;\n\n  if normalized_kind not in ('direct','group') then raise exception 'invalid_conversation_kind'; end if;\n  select array_agg(x order by x::text) into members\n  from (select distinct unnest(array_append(coalesce(p_member_ids,array[]::uuid[]), caller)) as x) s\n  where x is not null;\n\n  if normalized_kind='direct' and coalesce(array_length(members,1),0) <> 2 then raise exception 'direct_requires_two_members'; end if;\n  if normalized_kind='group' and (coalesce(array_length(members,1),0) < 2 or array_length(members,1) > 20) then\n    raise exception 'group_member_limit';\n  end if;\n\n  select count(*) into invalid_count\n  from unnest(members) u\n  left join public.profiles p on p.id=u\n  where p.id is null or p.active is false;\n  if invalid_count > 0 then raise exception 'invalid_message_member'; end if;\n\n  if normalized_kind='direct' then\n    key := array_to_string(members,':');\n    insert into public.message_conversations(kind,direct_key,created_by)\n      values('direct',key,caller)\n      on conflict (direct_key) where direct_key is not null\n      do update set updated_at=public.message_conversations.updated_at\n      returning id into conv_id;\n  else\n    insert into public.message_conversations(kind,title,created_by)\n      values('group',nullif(left(trim(coalesce(p_title,'')),120),''),caller)\n      returning id into conv_id;\n  end if;\n\n  insert into public.message_conversation_members(conversation_id,user_id,role)\n    select conv_id, u, case when u=caller then 'owner' else 'member' end from unnest(members) u\n    on conflict (conversation_id,user_id) do nothing;\n  return conv_id;\nend;\n$function$\n","identity_arguments":"p_kind text, p_member_ids uuid[], p_tenant_id uuid, p_title text"},{"name":"create_platform_message_folder","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.create_platform_message_folder(p_name text)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare result uuid;\nbegin\n  if auth.uid() is null then raise exception 'authentication_required'; end if;\n  insert into public.message_folders(user_id,name) values(auth.uid(),left(trim(p_name),80)) returning id into result;\n  return result;\nend;\n$function$\n","identity_arguments":"p_name text"},{"name":"create_security_alert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.create_security_alert(p_alert_type text, p_severity text, p_title text, p_description text DEFAULT NULL::text, p_user_id uuid DEFAULT NULL::uuid, p_user_email text DEFAULT NULL::text, p_tenant_id uuid DEFAULT NULL::uuid, p_ip_address text DEFAULT NULL::text, p_user_agent text DEFAULT NULL::text, p_metadata jsonb DEFAULT '{}'::jsonb)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE v_alert_id UUID;\nBEGIN\n  INSERT INTO security_alerts (alert_type, severity, title, description, user_id, user_email, tenant_id, ip_address, user_agent, metadata)\n  VALUES (p_alert_type, p_severity, p_title, p_description, p_user_id, p_user_email, p_tenant_id, p_ip_address, p_user_agent, p_metadata) RETURNING id INTO v_alert_id;\n  INSERT INTO comprehensive_audit_logs (user_id, tenant_id, event_type, event_category, event_action, resource_type, resource_id, metadata, severity)\n  VALUES (p_user_id, p_tenant_id, 'error', 'system', 'security_alert_created', 'security_alert', v_alert_id::TEXT, jsonb_build_object('alert_type', p_alert_type, 'title', p_title), p_severity);\n  RETURN v_alert_id;\nEND; $function$\n","identity_arguments":"p_alert_type text, p_severity text, p_title text, p_description text, p_user_id uuid, p_user_email text, p_tenant_id uuid, p_ip_address text, p_user_agent text, p_metadata jsonb"},{"name":"decrement_active_enrollments","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.decrement_active_enrollments(p_sequence_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  UPDATE communication_sequences\n  SET active_enrollments = GREATEST(0, COALESCE(active_enrollments, 0) - 1)\n  WHERE id = p_sequence_id;\nEND;\n$function$\n","identity_arguments":"p_sequence_id uuid"},{"name":"delete_email","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.delete_email(queue_name text, message_id bigint)\n RETURNS boolean\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_catalog'\nAS $function$\nBEGIN\n  RETURN pgmq.delete(queue_name, message_id);\nEXCEPTION WHEN undefined_table THEN\n  RETURN FALSE;\nEND;\n$function$\n","identity_arguments":"queue_name text, message_id bigint"},{"name":"delete_platform_message","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.delete_platform_message(p_message_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare conv uuid;\nbegin\n  select conversation_id into conv from public.messages where id=p_message_id and sender_id=auth.uid() and deleted_at is null;\n  if conv is null then raise exception 'message_delete_denied'; end if;\n  update public.messages set body='',context=null,encrypted_payload=null,encryption_nonce=null,deleted_at=now() where id=p_message_id;\n  insert into public.message_user_events(user_id,conversation_id,event_type)\n    select user_id,conv,'message_deleted' from public.message_conversation_members where conversation_id=conv;\nend;\n$function$\n","identity_arguments":"p_message_id uuid"},{"name":"delete_platform_message_folder","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.delete_platform_message_folder(p_folder_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  update public.message_conversation_preferences set folder_id=null,updated_at=now() where folder_id=p_folder_id and user_id=auth.uid();\n  delete from public.message_folders where id=p_folder_id and user_id=auth.uid();\nend;\n$function$\n","identity_arguments":"p_folder_id uuid"},{"name":"delete_platform_message_v3","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.delete_platform_message_v3(p_message_id uuid, p_retention_body text)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  caller uuid:=auth.uid();\n  row_message public.messages%rowtype;\n  conv_tenant uuid;\n  retention_key text;\n  retained_text text;\n  attachment_manifest jsonb;\nbegin\n  if caller is null then raise exception 'authentication_required'; end if;\n  select * into row_message from public.messages where id=p_message_id and sender_id=caller and deleted_at is null;\n  if row_message.id is null then raise exception 'message_delete_denied'; end if;\n  if not public.can_access_message_conversation(row_message.conversation_id,caller) then raise exception 'message_delete_denied'; end if;\n  select tenant_id into conv_tenant from public.message_conversations where id=row_message.conversation_id;\n  select archive_key into retention_key from public.message_retention_config where singleton=true;\n  if retention_key is null then raise exception 'message_retention_key_unavailable'; end if;\n\n  if row_message.encrypted_payload is not null then\n    retained_text:=trim(coalesce(p_retention_body,''));\n    if retained_text='' then raise exception 'deleted_encrypted_message_retention_body_required'; end if;\n  else\n    retained_text:=coalesce(nullif(p_retention_body,''),row_message.body,'');\n  end if;\n\n  select coalesce(jsonb_agg(jsonb_build_object(\n    'id',a.id,'storage_path',a.storage_path,'bucket_name',a.bucket_name,'file_name',a.file_name,\n    'mime_type',a.mime_type,'size_bytes',a.size_bytes,'encrypted_metadata',a.encrypted_metadata,\n    'encryption_nonce',a.encryption_nonce,'key_version',a.key_version,'uploader_id',a.uploader_id\n  ) order by a.created_at),'[]'::jsonb) into attachment_manifest\n  from public.message_attachments a where a.message_id=row_message.id;\n\n  insert into public.message_deleted_retention(\n    message_id,conversation_id,tenant_id,sender_id,deleted_by,deleted_at,original_created_at,original_edited_at,\n    retained_body_cipher,retained_context,original_encrypted_payload,original_encryption_nonce,\n    original_encryption_alg,original_key_version,attachment_manifest\n  ) values(\n    row_message.id,row_message.conversation_id,conv_tenant,row_message.sender_id,caller,now(),\n    row_message.created_at,row_message.edited_at,\n    extensions.pgp_sym_encrypt(retained_text,retention_key,'cipher-algo=aes256'),\n    row_message.context,row_message.encrypted_payload,row_message.encryption_nonce,row_message.encryption_alg,row_message.key_version,\n    coalesce(attachment_manifest,'[]'::jsonb)\n  ) on conflict(message_id) do nothing;\n\n  update public.messages set body='',context=null,encrypted_payload=null,encryption_nonce=null,encryption_alg=null,key_version=null,deleted_at=now()\n  where id=row_message.id;\n\n  insert into public.message_user_events(user_id,conversation_id,event_type)\n    select user_id,row_message.conversation_id,'message_deleted'\n    from public.message_conversation_members where conversation_id=row_message.conversation_id;\nend;\n$function$\n","identity_arguments":"p_message_id uuid, p_retention_body text"},{"name":"derive_onboarding_blueprint","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.derive_onboarding_blueprint(p_session_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE s public.onboarding_sessions%rowtype; v_type text; v_track text; v_model text; v_business jsonb; v_blueprint jsonb;\nBEGIN\n  SELECT * INTO s FROM public.onboarding_sessions WHERE id=p_session_id; IF NOT FOUND THEN RAISE EXCEPTION 'Onboarding session not found'; END IF; IF coalesce(auth.role(),'')<>'service_role' AND (auth.uid() IS NULL OR (s.owner_user_id IS DISTINCT FROM auth.uid() AND NOT public.is_system_admin(auth.uid()))) THEN RAISE EXCEPTION 'Not authorized for this onboarding session' USING ERRCODE='42501'; END IF;\n  v_type:=public.normalize_declared_business_type(s.requested_business_type); IF v_type IS NULL THEN RAISE EXCEPTION 'A declared business type is required' USING ERRCODE='22023'; END IF; v_model:=public.tenant_operating_model_for(v_type,jsonb_build_object('operating_model',coalesce(s.intake_answers->>'operating_model',''))); IF v_model IS NULL THEN RAISE EXCEPTION 'Operating model is required for declared business type %; onboarding will not generalize it to MISC',v_type USING ERRCODE='22023'; END IF;\n  v_business:=public.build_tenant_business_blueprint(v_type,jsonb_build_object('business_type',s.requested_business_type,'operating_model',v_model),s.company_name); v_track:=public.academy_track_for_type(v_type); v_blueprint:=jsonb_build_object('version','knocklaunch.onboarding.blueprint.v3','tenant_type',v_type,'declared_business_type',v_type,'operating_model',v_model,'academy_track',v_track,'service_lines',s.service_lines,'goals',s.goals,'requested_capabilities',s.requested_capabilities,'recommended_capabilities',v_business->'applications','business_operating_blueprint',v_business,'operating_states',to_jsonb(s.operating_states),'service_area',s.service_area,'team_size',s.team_size);\n  UPDATE public.onboarding_sessions SET canonical_tenant_type=v_type,derived_blueprint=v_blueprint,updated_at=now() WHERE id=p_session_id; RETURN v_blueprint;\nEND;\n$function$\n","identity_arguments":"p_session_id uuid"},{"name":"detect_revocation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.detect_revocation(p_text text)\n RETURNS TABLE(revoked boolean, matched_keyword text)\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_clean TEXT;\n  v_keywords TEXT[] := ARRAY['stop','stopall','unsubscribe','cancel','end','quit','revoke','remove me','take me off','do not call','dont call','don''t call','no more calls','no more texts','opt out','opt-out','stop calling','stop texting','leave me alone','never call'];\n  v_kw TEXT;\nBEGIN\n  IF p_text IS NULL OR length(trim(p_text)) = 0 THEN RETURN QUERY SELECT false, NULL::TEXT; RETURN; END IF;\n  v_clean := lower(regexp_replace(trim(p_text), '\\s+', ' ', 'g'));\n  IF v_clean IN ('stop','stopall','unsubscribe','cancel','end','quit','revoke') THEN RETURN QUERY SELECT true, v_clean; RETURN; END IF;\n  FOREACH v_kw IN ARRAY v_keywords LOOP\n    IF position(v_kw IN v_clean) > 0 THEN RETURN QUERY SELECT true, v_kw; RETURN; END IF;\n  END LOOP;\n  RETURN QUERY SELECT false, NULL::TEXT;\nEND; $function$\n","identity_arguments":"p_text text"},{"name":"dispatch_homeowner_claim_stage_update","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.dispatch_homeowner_claim_stage_update()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_url text;\n  v_key text;\n  v_payload jsonb;\nBEGIN\n  IF NEW.claim_status IS NULL OR NEW.claim_status = COALESCE(OLD.claim_status, '') THEN\n    RETURN NEW;\n  END IF;\n\n  IF NOT EXISTS (\n    SELECT 1\n    FROM public.unified_contacts\n    WHERE id::text = NEW.contact_id::text\n  ) THEN\n    RETURN NEW;\n  END IF;\n\n  BEGIN\n    SELECT decrypted_secret INTO v_url FROM vault.decrypted_secrets WHERE name = 'project_url' LIMIT 1;\n    SELECT decrypted_secret INTO v_key FROM vault.decrypted_secrets WHERE name = 'service_role_key' LIMIT 1;\n  EXCEPTION WHEN OTHERS THEN\n    RAISE NOTICE 'dispatch_homeowner_claim_stage_update: vault unavailable, skipping';\n    RETURN NEW;\n  END;\n\n  IF v_url IS NULL OR v_key IS NULL THEN\n    RAISE NOTICE 'dispatch_homeowner_claim_stage_update: missing url/key, skipping';\n    RETURN NEW;\n  END IF;\n\n  v_payload := jsonb_build_object(\n    'action', 'trigger',\n    'event', jsonb_build_object(\n      'type', 'stage_change',\n      'contactId', NEW.contact_id,\n      'tenantId', NEW.tenant_org_id,\n      'oldValue', OLD.claim_status,\n      'newValue', NEW.claim_status,\n      'field', 'claim_stage',\n      'metadata', jsonb_build_object('pipeline_kind', 'CLAIM', 'claim_id', NEW.id)\n    )\n  );\n\n  PERFORM net.http_post(\n    url := v_url || '/functions/v1/pipeline-automation',\n    headers := jsonb_build_object(\n      'Content-Type', 'application/json',\n      'Authorization', 'Bearer ' || v_key\n    ),\n    body := v_payload\n  );\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"dispatch_homeowner_stage_update","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.dispatch_homeowner_stage_update()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_old TEXT;\n  v_new TEXT;\n  v_kind TEXT;\n  v_supabase_url TEXT;\n  v_service_key TEXT;\n  v_payload JSONB;\nBEGIN\n  IF TG_OP <> 'UPDATE' THEN RETURN NEW; END IF;\n\n  IF NEW.lead_stage IS DISTINCT FROM OLD.lead_stage THEN\n    v_old := OLD.lead_stage; v_new := NEW.lead_stage; v_kind := 'LEAD';\n  ELSIF NEW.claim_stage IS DISTINCT FROM OLD.claim_stage THEN\n    v_old := OLD.claim_stage; v_new := NEW.claim_stage; v_kind := 'CLAIM';\n  ELSIF NEW.jobs_stage IS DISTINCT FROM OLD.jobs_stage THEN\n    v_old := OLD.jobs_stage; v_new := NEW.jobs_stage; v_kind := 'JOB';\n  ELSE\n    RETURN NEW;\n  END IF;\n\n  IF v_new IS NULL OR v_new = '' THEN RETURN NEW; END IF;\n\n  IF NOT EXISTS (\n    SELECT 1 FROM public.homeowner_stage_messages\n    WHERE pipeline_kind = v_kind\n      AND stage_name = v_new\n      AND send_to_homeowner = true\n      AND (tenant_org_id = NEW.tenant_org_id OR tenant_org_id IS NULL)\n  ) THEN\n    RETURN NEW;\n  END IF;\n\n  BEGIN\n    SELECT decrypted_secret INTO v_supabase_url FROM vault.decrypted_secrets WHERE name = 'SUPABASE_URL' LIMIT 1;\n    SELECT decrypted_secret INTO v_service_key FROM vault.decrypted_secrets WHERE name = 'SUPABASE_SERVICE_ROLE_KEY' LIMIT 1;\n  EXCEPTION WHEN OTHERS THEN NULL;\n  END;\n\n  IF v_supabase_url IS NULL OR v_service_key IS NULL THEN\n    RAISE NOTICE 'dispatch_homeowner_stage_update: missing supabase url/key, skipping';\n    RETURN NEW;\n  END IF;\n\n  v_payload := jsonb_build_object(\n    'action','trigger',\n    'event', jsonb_build_object(\n      'type','stage_change',\n      'contactId', NEW.id,\n      'tenantId', NEW.tenant_org_id,\n      'oldValue', v_old,\n      'newValue', v_new,\n      'field', lower(v_kind) || '_stage',\n      'metadata', jsonb_build_object(\n        'pipeline_kind', v_kind,\n        'auto_homeowner_notify', true\n      )\n    )\n  );\n\n  PERFORM net.http_post(\n    url := v_supabase_url || '/functions/v1/pipeline-automation',\n    headers := jsonb_build_object(\n      'Content-Type','application/json',\n      'Authorization','Bearer ' || v_service_key\n    ),\n    body := v_payload\n  );\n\n  RETURN NEW;\nEXCEPTION WHEN OTHERS THEN\n  RAISE NOTICE 'dispatch_homeowner_stage_update error: %', SQLERRM;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"dispatch_onboarding_research_task","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.dispatch_onboarding_research_task()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'net'\nAS $function$\nbegin\n  if new.status='pending'\n     and new.provider_key is not null\n     and new.dispatch_token is not null\n     and (tg_op='INSERT' or old.dispatch_token is distinct from new.dispatch_token or old.status is distinct from new.status) then\n    perform net.http_post(\n      url := 'https://ymntrajfubicyxwwdxxa.supabase.co/functions/v1/onboarding-research-runner',\n      body := jsonb_build_object('task_id',new.id,'dispatch_token',new.dispatch_token),\n      headers := jsonb_build_object('Content-Type','application/json'),\n      timeout_milliseconds := 10000\n    );\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"dnc_bulk_upsert_phones","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.dnc_bulk_upsert_phones(_phones text[], _federal boolean, _tenant uuid, _reason text, _added_by text)\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  inserted_count integer := 0;\nBEGIN\n  IF _phones IS NULL OR array_length(_phones, 1) IS NULL THEN\n    RETURN 0;\n  END IF;\n\n  IF _federal THEN\n    WITH ins AS (\n      INSERT INTO public.dnc_federal_numbers (phone, area_code, source)\n      SELECT p, left(p, 3), 'ftc_upload'\n      FROM unnest(_phones) AS p\n      WHERE p ~ '^\\d{10}$'\n      ON CONFLICT (phone) DO NOTHING\n      RETURNING 1\n    )\n    SELECT count(*) INTO inserted_count FROM ins;\n  ELSE\n    IF _tenant IS NULL THEN\n      RAISE EXCEPTION 'tenant_id is required for tenant DNC list imports';\n    END IF;\n    WITH ins AS (\n      INSERT INTO public.dnc_list (phone, phone_normalized, reason, added_by, tenant_org_id)\n      SELECT p, p, COALESCE(_reason, 'Bulk DNC import'), COALESCE(_added_by, 'admin'), _tenant\n      FROM unnest(_phones) AS p\n      WHERE p ~ '^\\d{10}$'\n      ON CONFLICT (phone) DO NOTHING\n      RETURNING 1\n    )\n    SELECT count(*) INTO inserted_count FROM ins;\n  END IF;\n\n  RETURN inserted_count;\nEND;\n$function$\n","identity_arguments":"_phones text[], _federal boolean, _tenant uuid, _reason text, _added_by text"},{"name":"edit_platform_message_v2","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.edit_platform_message_v2(p_message_id uuid, p_encrypted_payload text, p_encryption_nonce text, p_key_version integer)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare conv uuid;\nbegin\n  select conversation_id into conv from public.messages where id=p_message_id and sender_id=auth.uid() and deleted_at is null;\n  if conv is null or not public.can_access_message_conversation(conv,auth.uid()) then raise exception 'message_edit_denied'; end if;\n  if p_key_version<>(select current_key_version from public.message_conversations where id=conv) then raise exception 'message_key_rotation_required'; end if;\n  update public.messages set body='[encrypted]',encrypted_payload=p_encrypted_payload,encryption_nonce=p_encryption_nonce,\n    encryption_alg='AES-GCM-256',key_version=p_key_version,edited_at=now() where id=p_message_id;\n  insert into public.message_user_events(user_id,conversation_id,event_type)\n    select user_id,conv,'message_edited' from public.message_conversation_members where conversation_id=conv;\nend;\n$function$\n","identity_arguments":"p_message_id uuid, p_encrypted_payload text, p_encryption_nonce text, p_key_version integer"},{"name":"enforce_academy_lesson_grounding","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_academy_lesson_grounding()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_scope text;\nBEGIN\n  SELECT c.scope INTO v_scope\n  FROM public.academy_courses c\n  JOIN public.academy_units u ON u.course_id = c.id\n  WHERE u.id = NEW.unit_id;\n\n  IF v_scope = 'tenant' THEN\n    IF NEW.linked_action_key IS NULL\n       AND NEW.module_key IS NULL\n       AND COALESCE(array_length(NEW.role_scope, 1), 0) = 0\n       AND NEW.workflow_key IS NULL\n       AND NEW.sop_category IS NULL THEN\n      RAISE EXCEPTION 'Tenant-scope lessons must declare at least one of linked_action_key, module_key, role_scope, workflow_key, or sop_category (lesson=\"%\")', NEW.title;\n    END IF;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"enforce_assigned_user_tenant_match","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_assigned_user_tenant_match()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_assignment text;\n  v_user_id uuid;\n  v_tenant_id uuid;\nbegin\n  if new.tenant_org_id is null then\n    return new;\n  end if;\n\n  begin\n    v_tenant_id := new.tenant_org_id::uuid;\n  exception when invalid_text_representation then\n    raise exception 'Invalid tenant identifier on contact assignment'\n      using errcode = 'check_violation';\n  end;\n\n  foreach v_assignment in array array[new.assigned_user, new.assigned_to]\n  loop\n    continue when nullif(btrim(coalesce(v_assignment, '')), '') is null;\n\n    begin\n      v_user_id := v_assignment::uuid;\n    exception when invalid_text_representation then\n      raise exception 'Assignment must reference a valid user identifier'\n        using errcode = 'check_violation';\n    end;\n\n    if not exists (\n      select 1\n      from public.user_tenant_memberships m\n      where m.user_id = v_user_id\n        and m.tenant_id = v_tenant_id\n        and m.status = 'active'\n    ) and not exists (\n      select 1\n      from public.user_roles r\n      where r.user_id = v_user_id\n        and r.tenant_id = v_tenant_id\n    ) then\n      raise exception 'Cross-tenant assignment blocked: user % has no active access to tenant %',\n        v_user_id, v_tenant_id\n        using errcode = 'check_violation';\n    end if;\n  end loop;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_calendar_claim_context","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_calendar_claim_context()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\ndeclare\n  claim_row public.contact_claims%rowtype;\nbegin\n  if new.claim_id is null then\n    return new;\n  end if;\n\n  select * into claim_row\n  from public.contact_claims\n  where id = new.claim_id;\n\n  if not found then\n    raise exception 'calendar_claim_not_found';\n  end if;\n\n  if new.tenant_org_id::text is distinct from claim_row.tenant_org_id::text then\n    raise exception 'calendar_claim_tenant_mismatch';\n  end if;\n\n  if new.contact_id is null then\n    new.contact_id := claim_row.contact_id;\n  elsif new.contact_id::text is distinct from claim_row.contact_id::text then\n    raise exception 'calendar_claim_contact_mismatch';\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_contact_assignment_tenant_context","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_contact_assignment_tenant_context()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_contact_tenant text;\nbegin\n  if tg_op = 'UPDATE' and (\n    new.tenant_id is distinct from old.tenant_id\n    or new.contact_id is distinct from old.contact_id\n  ) then\n    raise exception 'contact_assignment_identity_immutable' using errcode = '42501';\n  end if;\n\n  select c.tenant_org_id into v_contact_tenant\n  from public.unified_contacts c where c.id = new.contact_id;\n  if v_contact_tenant is null or v_contact_tenant <> new.tenant_id::text then\n    raise exception 'contact_assignment_tenant_mismatch' using errcode = '42501';\n  end if;\n\n  if not exists (\n    select 1 from public.user_tenant_memberships m\n    where m.tenant_id = new.tenant_id and m.user_id = new.user_id\n      and m.status = 'active'\n  ) then\n    raise exception 'contact_assignment_assignee_not_active_in_tenant' using errcode = '42501';\n  end if;\n\n  if auth.uid() is not null\n    and not coalesce(public.is_system_admin(auth.uid()), false)\n    and not exists (\n      select 1 from public.user_tenant_memberships m\n      where m.tenant_id = new.tenant_id and m.user_id = auth.uid()\n        and m.status = 'active'\n    )\n  then\n    raise exception 'contact_assignment_actor_outside_tenant' using errcode = '42501';\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_dnc_quarantine","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_dnc_quarantine()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_norm TEXT;\n  v_row RECORD;\nBEGIN\n  v_norm := NEW.phone_normalized;\n  IF v_norm IS NULL OR length(v_norm) < 10 THEN\n    RETURN NEW;\n  END IF;\n\n  -- unified_contacts matches\n  FOR v_row IN\n    SELECT * FROM public.unified_contacts\n    WHERE public.normalize_phone_for_dnc(phone) = v_norm\n      AND deleted_at IS NULL\n  LOOP\n    BEGIN\n      IF public.is_existing_client_record(\n        v_row.status, v_row.lead_stage, v_row.jobs_stage, v_row.claim_stage, v_row.graduated_at\n      ) THEN\n        UPDATE public.unified_contacts\n        SET is_dnc = true,\n            dnc_reason = COALESCE(NEW.reason, 'DNC - Existing Client'),\n            dnc_checked_at = now(),\n            updated_at = now()\n        WHERE id = v_row.id;\n      ELSE\n        INSERT INTO public.dnc_quarantine (\n          phone_normalized, original_phone, source_table, source_id, source_lead_id,\n          tenant_org_id, reason, dnc_source, contact_snapshot\n        ) VALUES (\n          v_norm, v_row.phone, 'unified_contacts', v_row.id::text, v_row.lead_id,\n          v_row.tenant_org_id::text, COALESCE(NEW.reason, 'DNC match'), 'internal', to_jsonb(v_row)\n        );\n        DELETE FROM public.unified_contacts WHERE id = v_row.id;\n      END IF;\n    EXCEPTION WHEN OTHERS THEN\n      RAISE WARNING '[enforce_dnc_quarantine] unified_contacts row % failed: %', v_row.id, SQLERRM;\n    END;\n  END LOOP;\n\n  -- lead_deck matches\n  FOR v_row IN\n    SELECT * FROM public.lead_deck\n    WHERE public.normalize_phone_for_dnc(phone) = v_norm\n      AND deleted_at IS NULL\n  LOOP\n    BEGIN\n      IF public.is_existing_client_record(\n        v_row.status, v_row.lead_stage, NULL, NULL, v_row.graduated_at\n      ) THEN\n        UPDATE public.lead_deck\n        SET is_dnc = true,\n            dnc_reason = COALESCE(NEW.reason, 'DNC - Existing Client'),\n            dnc_checked_at = now(),\n            updated_at = now()\n        WHERE id = v_row.id;\n      ELSE\n        INSERT INTO public.dnc_quarantine (\n          phone_normalized, original_phone, source_table, source_id, source_lead_id,\n          tenant_org_id, reason, dnc_source, contact_snapshot\n        ) VALUES (\n          v_norm, v_row.phone, 'lead_deck', v_row.id::text, v_row.lead_id,\n          v_row.tenant_org_id::text, COALESCE(NEW.reason, 'DNC match'), 'internal', to_jsonb(v_row)\n        );\n        DELETE FROM public.lead_deck WHERE id = v_row.id;\n      END IF;\n    EXCEPTION WHEN OTHERS THEN\n      RAISE WARNING '[enforce_dnc_quarantine] lead_deck row % failed: %', v_row.id, SQLERRM;\n    END;\n  END LOOP;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"enforce_job_request_state_machine","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_job_request_state_machine()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  uid uuid := auth.uid();\n  is_elevated boolean := false;\nBEGIN\n  -- Service role / migrations bypass\n  IF uid IS NULL THEN RETURN NEW; END IF;\n\n  -- No status change → nothing to enforce\n  IF NEW.status IS NOT DISTINCT FROM OLD.status THEN RETURN NEW; END IF;\n\n  -- Platform admin / tenant manager+ bypass (audited via standard audit triggers)\n  is_elevated :=\n       public.is_system_admin(uid)\n    OR public.is_manager_or_higher_strict(uid, OLD.tenant_id);\n  IF is_elevated THEN RETURN NEW; END IF;\n\n  -- Terminal states are locked for non-elevated users\n  IF OLD.status IN ('rejected','converted','cancelled') THEN\n    RAISE EXCEPTION 'job_requests.status % is terminal and cannot be changed', OLD.status\n      USING ERRCODE = '42501';\n  END IF;\n\n  -- Legal transitions for non-elevated users\n  IF NOT (\n       (OLD.status = 'pending_review' AND NEW.status IN ('needs_info','approved','rejected','cancelled'))\n    OR (OLD.status = 'needs_info'     AND NEW.status IN ('pending_review','cancelled'))\n    OR (OLD.status = 'approved'       AND NEW.status IN ('converted','cancelled'))\n  ) THEN\n    RAISE EXCEPTION 'illegal job_requests transition % -> %', OLD.status, NEW.status\n      USING ERRCODE = '42501';\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"enforce_job_verify_authority","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_job_verify_authority()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  uid uuid := auth.uid();\n  is_override boolean := COALESCE(NULLIF(current_setting('app.platform_override', true), '')::boolean, false);\n  override_reason text := NULLIF(current_setting('app.platform_override_reason', true), '');\n  actor_email text;\nBEGIN\n  IF NEW.status = 'verified' AND COALESCE(OLD.status, '') <> 'verified' THEN\n    IF uid IS NULL THEN\n      RAISE EXCEPTION 'verify requires authenticated user';\n    END IF;\n\n    -- Strict tenant-scoped authorization (no GodMode-anywhere leakage)\n    IF public.is_manager_or_higher_strict(uid, NEW.tenant_id)\n       OR public.has_acting_pm_grant(uid, NEW.tenant_id) THEN\n      NULL; -- authorized in-tenant\n    ELSIF public.is_platform_admin(uid) AND is_override THEN\n      IF override_reason IS NULL OR length(trim(override_reason)) < 10 THEN\n        RAISE EXCEPTION 'platform override requires reason (>=10 chars)';\n      END IF;\n      SELECT email INTO actor_email FROM auth.users WHERE id = uid;\n      INSERT INTO public.platform_override_log\n        (actor_id, actor_email, tenant_id, action, target_table, target_id, reason, payload)\n      VALUES\n        (uid, actor_email, NEW.tenant_id, 'verify_job', 'jobs', NEW.id::text, override_reason,\n         jsonb_build_object('job_number', NEW.job_number, 'prev_status', OLD.status));\n    ELSE\n      RAISE EXCEPTION 'not authorized to verify jobs in this tenant';\n    END IF;\n\n    NEW.verified_by := COALESCE(NEW.verified_by, uid);\n    NEW.verified_at := COALESCE(NEW.verified_at, now());\n  END IF;\n\n  RETURN NEW;\nEND\n$function$\n","identity_arguments":""},{"name":"enforce_job_verify_checklist","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_job_verify_checklist()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  missing text[] := ARRAY[]::text[];\nBEGIN\n  IF NEW.status = 'verified' AND COALESCE(OLD.status, '') <> 'verified' THEN\n    -- Job must have already been marked completed\n    IF COALESCE(OLD.status, '') <> 'completed' THEN\n      missing := array_append(missing, 'job status must be completed before verification');\n    END IF;\n\n    IF NOT COALESCE(NEW.work_auth_signed, false) THEN\n      missing := array_append(missing, 'Work Authorization signed');\n    END IF;\n\n    IF NOT COALESCE(NEW.photos_uploaded, false) THEN\n      missing := array_append(missing, 'photos uploaded');\n    END IF;\n\n    -- tarp_installed is nullable; only block if explicitly false\n    IF NEW.tarp_installed IS NOT NULL AND NEW.tarp_installed = false THEN\n      missing := array_append(missing, 'tarp installed / work completed');\n    END IF;\n\n    IF NOT COALESCE(NEW.docs_complete, false) THEN\n      missing := array_append(missing, 'docs complete');\n    END IF;\n\n    IF NEW.property_address IS NULL OR length(trim(NEW.property_address)) = 0 THEN\n      missing := array_append(missing, 'property address');\n    END IF;\n\n    IF array_length(missing, 1) > 0 THEN\n      RAISE EXCEPTION 'Cannot verify job: missing required items: %', array_to_string(missing, ', ')\n        USING ERRCODE = '22023';\n    END IF;\n  END IF;\n\n  RETURN NEW;\nEND\n$function$\n","identity_arguments":""},{"name":"enforce_jobs_crew_update_scope","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_jobs_crew_update_scope()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  uid uuid := auth.uid();\n  is_crew_self boolean;\n  is_elevated boolean;\n  bad text[] := ARRAY[]::text[];\n  allowed_status text[] := ARRAY['dispatched','on_site','in_progress','crew_completed'];\nBEGIN\n  IF uid IS NULL THEN RETURN NEW; END IF;\n\n  is_crew_self := (OLD.assigned_crew_id IS NOT NULL AND OLD.assigned_crew_id = uid);\n  IF NOT is_crew_self THEN RETURN NEW; END IF;\n\n  is_elevated :=\n    public.is_system_admin(uid)\n    OR public.is_manager_or_higher_strict(uid, OLD.tenant_id)\n    OR public.has_acting_pm_grant(uid, OLD.tenant_id);\n  IF is_elevated THEN RETURN NEW; END IF;\n\n  IF NEW.tenant_id            IS DISTINCT FROM OLD.tenant_id            THEN bad := array_append(bad,'tenant_id'); END IF;\n  IF NEW.contact_id           IS DISTINCT FROM OLD.contact_id           THEN bad := array_append(bad,'contact_id'); END IF;\n  IF NEW.contact_claim_id     IS DISTINCT FROM OLD.contact_claim_id     THEN bad := array_append(bad,'contact_claim_id'); END IF;\n  IF NEW.appointment_id       IS DISTINCT FROM OLD.appointment_id       THEN bad := array_append(bad,'appointment_id'); END IF;\n  IF NEW.job_number           IS DISTINCT FROM OLD.job_number           THEN bad := array_append(bad,'job_number'); END IF;\n  IF NEW.customer_name        IS DISTINCT FROM OLD.customer_name        THEN bad := array_append(bad,'customer_name'); END IF;\n  IF NEW.customer_phone       IS DISTINCT FROM OLD.customer_phone       THEN bad := array_append(bad,'customer_phone'); END IF;\n  IF NEW.customer_email       IS DISTINCT FROM OLD.customer_email       THEN bad := array_append(bad,'customer_email'); END IF;\n  IF NEW.property_address     IS DISTINCT FROM OLD.property_address     THEN bad := array_append(bad,'property_address'); END IF;\n  IF NEW.city                 IS DISTINCT FROM OLD.city                 THEN bad := array_append(bad,'city'); END IF;\n  IF NEW.state                IS DISTINCT FROM OLD.state                THEN bad := array_append(bad,'state'); END IF;\n  IF NEW.zip                  IS DISTINCT FROM OLD.zip                  THEN bad := array_append(bad,'zip'); END IF;\n  IF NEW.latitude             IS DISTINCT FROM OLD.latitude             THEN bad := array_append(bad,'latitude'); END IF;\n  IF NEW.longitude            IS DISTINCT FROM OLD.longitude            THEN bad := array_append(bad,'longitude'); END IF;\n  IF NEW.job_type             IS DISTINCT FROM OLD.job_type             THEN bad := array_append(bad,'job_type'); END IF;\n  IF NEW.priority             IS DISTINCT FROM OLD.priority             THEN bad := array_append(bad,'priority'); END IF;\n  IF NEW.assigned_crew_id     IS DISTINCT FROM OLD.assigned_crew_id     THEN bad := array_append(bad,'assigned_crew_id'); END IF;\n  IF NEW.assigned_crew_email  IS DISTINCT FROM OLD.assigned_crew_email  THEN bad := array_append(bad,'assigned_crew_email'); END IF;\n  IF NEW.assigned_pm_id       IS DISTINCT FROM OLD.assigned_pm_id       THEN bad := array_append(bad,'assigned_pm_id'); END IF;\n  IF NEW.assigned_pm_email    IS DISTINCT FROM OLD.assigned_pm_email    THEN bad := array_append(bad,'assigned_pm_email'); END IF;\n  IF NEW.scheduled_date       IS DISTINCT FROM OLD.scheduled_date       THEN bad := array_append(bad,'scheduled_date'); END IF;\n  IF NEW.scheduled_time       IS DISTINCT FROM OLD.scheduled_time       THEN bad := array_append(bad,'scheduled_time'); END IF;\n  IF NEW.appointment_date     IS DISTINCT FROM OLD.appointment_date     THEN bad := array_append(bad,'appointment_date'); END IF;\n  IF NEW.verified_at          IS DISTINCT FROM OLD.verified_at          THEN bad := array_append(bad,'verified_at'); END IF;\n  IF NEW.verified_by          IS DISTINCT FROM OLD.verified_by          THEN bad := array_append(bad,'verified_by'); END IF;\n  IF NEW.carrier_name         IS DISTINCT FROM OLD.carrier_name         THEN bad := array_append(bad,'carrier_name'); END IF;\n  IF NEW.policy_number        IS DISTINCT FROM OLD.policy_number        THEN bad := array_append(bad,'policy_number'); END IF;\n  IF NEW.claim_number         IS DISTINCT FROM OLD.claim_number         THEN bad := array_append(bad,'claim_number'); END IF;\n  IF NEW.adjuster_name        IS DISTINCT FROM OLD.adjuster_name        THEN bad := array_append(bad,'adjuster_name'); END IF;\n  IF NEW.adjuster_phone       IS DISTINCT FROM OLD.adjuster_phone       THEN bad := array_append(bad,'adjuster_phone'); END IF;\n  IF NEW.adjuster_email       IS DISTINCT FROM OLD.adjuster_email       THEN bad := array_append(bad,'adjuster_email'); END IF;\n  IF NEW.work_auth_signed     IS DISTINCT FROM OLD.work_auth_signed     THEN bad := array_append(bad,'work_auth_signed'); END IF;\n  IF NEW.docs_complete        IS DISTINCT FROM OLD.docs_complete        THEN bad := array_append(bad,'docs_complete'); END IF;\n  IF NEW.notes                IS DISTINCT FROM OLD.notes                THEN bad := array_append(bad,'notes'); END IF;\n  IF NEW.special_instructions IS DISTINCT FROM OLD.special_instructions THEN bad := array_append(bad,'special_instructions'); END IF;\n  IF NEW.pm_notes             IS DISTINCT FROM OLD.pm_notes             THEN bad := array_append(bad,'pm_notes'); END IF;\n  IF NEW.created_by           IS DISTINCT FROM OLD.created_by           THEN bad := array_append(bad,'created_by'); END IF;\n  IF NEW.created_at           IS DISTINCT FROM OLD.created_at           THEN bad := array_append(bad,'created_at'); END IF;\n  IF NEW.manager_approved_at  IS DISTINCT FROM OLD.manager_approved_at  THEN bad := array_append(bad,'manager_approved_at'); END IF;\n  IF NEW.manager_approved_by  IS DISTINCT FROM OLD.manager_approved_by  THEN bad := array_append(bad,'manager_approved_by'); END IF;\n  IF NEW.archived_at          IS DISTINCT FROM OLD.archived_at          THEN bad := array_append(bad,'archived_at'); END IF;\n  IF NEW.source_job_request_id IS DISTINCT FROM OLD.source_job_request_id THEN bad := array_append(bad,'source_job_request_id'); END IF;\n  IF NEW.source_signed_agreement_id IS DISTINCT FROM OLD.source_signed_agreement_id THEN bad := array_append(bad,'source_signed_agreement_id'); END IF;\n  IF NEW.claim_payment_status IS DISTINCT FROM OLD.claim_payment_status THEN bad := array_append(bad,'claim_payment_status'); END IF;\n  IF NEW.claim_payment_status_v2 IS DISTINCT FROM OLD.claim_payment_status_v2 THEN bad := array_append(bad,'claim_payment_status_v2'); END IF;\n  IF NEW.claim_payment_status_v2_updated_at IS DISTINCT FROM OLD.claim_payment_status_v2_updated_at THEN bad := array_append(bad,'claim_payment_status_v2_updated_at'); END IF;\n  IF NEW.tarping_invoice_id   IS DISTINCT FROM OLD.tarping_invoice_id   THEN bad := array_append(bad,'tarping_invoice_id'); END IF;\n  IF NEW.invoice_sent_at      IS DISTINCT FROM OLD.invoice_sent_at      THEN bad := array_append(bad,'invoice_sent_at'); END IF;\n  IF NEW.submitted_to_carrier_at IS DISTINCT FROM OLD.submitted_to_carrier_at THEN bad := array_append(bad,'submitted_to_carrier_at'); END IF;\n  IF NEW.check_sent_to_homeowner_at IS DISTINCT FROM OLD.check_sent_to_homeowner_at THEN bad := array_append(bad,'check_sent_to_homeowner_at'); END IF;\n  IF NEW.paid_at              IS DISTINCT FROM OLD.paid_at              THEN bad := array_append(bad,'paid_at'); END IF;\n  IF NEW.claim_payment_notes  IS DISTINCT FROM OLD.claim_payment_notes  THEN bad := array_append(bad,'claim_payment_notes'); END IF;\n  IF NEW.claim_payment_updated_at IS DISTINCT FROM OLD.claim_payment_updated_at THEN bad := array_append(bad,'claim_payment_updated_at'); END IF;\n  IF NEW.claim_payment_updated_by IS DISTINCT FROM OLD.claim_payment_updated_by THEN bad := array_append(bad,'claim_payment_updated_by'); END IF;\n\n  IF array_length(bad, 1) > 0 THEN\n    RAISE EXCEPTION 'crew not authorized to modify field(s): %', array_to_string(bad, ', ')\n      USING ERRCODE = '42501';\n  END IF;\n\n  IF NEW.status IS DISTINCT FROM OLD.status THEN\n    IF NOT (NEW.status = ANY(allowed_status)) THEN\n      RAISE EXCEPTION 'crew cannot set status to %', NEW.status USING ERRCODE = '42501';\n    END IF;\n    IF NOT (\n         (OLD.status = 'dispatched'   AND NEW.status = 'on_site')\n      OR (OLD.status = 'on_site'      AND NEW.status = 'in_progress')\n      OR (OLD.status = 'in_progress'  AND NEW.status = 'crew_completed')\n      OR (OLD.status = 'scheduled'    AND NEW.status = 'on_site')\n    ) THEN\n      RAISE EXCEPTION 'crew status transition % -> % not permitted', OLD.status, NEW.status\n        USING ERRCODE = '42501';\n    END IF;\n  END IF;\n\n  RETURN NEW;\nEND\n$function$\n","identity_arguments":""},{"name":"enforce_modes_tenant_capability_contract","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_modes_tenant_capability_contract()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  new.settings := public.apply_modes_tenant_capability_contract(new.settings, new.tenant_type);\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_pa_rights_before_lor","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_pa_rights_before_lor()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_tenant_type text;\n  v_document_type text;\n  v_claim_id text;\n  v_rights_provided boolean := false;\nBEGIN\n  v_document_type := lower(coalesce(\n    nullif(NEW.variables ->> 'DOCUMENT_TYPE', ''),\n    nullif(NEW.variables ->> 'document_type', ''),\n    ''\n  ));\n\n  IF v_document_type <> 'pa_lor' THEN\n    RETURN NEW;\n  END IF;\n\n  SELECT tenant_type\n  INTO v_tenant_type\n  FROM public.tenants\n  WHERE id = NEW.tenant_id;\n\n  IF coalesce(v_tenant_type, '') <> 'PUBLIC_ADJUSTER_FIRM' THEN\n    RETURN NEW;\n  END IF;\n\n  v_claim_id := coalesce(\n    nullif(NEW.variables ->> 'CLAIM_ID', ''),\n    nullif(NEW.variables ->> 'claim_id', '')\n  );\n\n  IF NEW.tenant_id IS NULL OR NEW.contact_id IS NULL OR v_claim_id IS NULL THEN\n    RAISE EXCEPTION 'PA LOR requires tenant, policyholder, and claim context before sending'\n      USING ERRCODE = '23514';\n  END IF;\n\n  SELECT EXISTS (\n    SELECT 1\n    FROM public.pending_agreements rights\n    WHERE rights.tenant_id = NEW.tenant_id\n      AND rights.contact_id = NEW.contact_id\n      AND coalesce(\n        nullif(rights.variables ->> 'CLAIM_ID', ''),\n        nullif(rights.variables ->> 'claim_id', '')\n      ) = v_claim_id\n      AND lower(coalesce(\n        nullif(rights.variables ->> 'DOCUMENT_TYPE', ''),\n        nullif(rights.variables ->> 'document_type', ''),\n        ''\n      )) = 'pa_statement_of_rights'\n      AND rights.status IN ('sent', 'viewed', 'signed')\n  ) INTO v_rights_provided;\n\n  IF NOT v_rights_provided THEN\n    RAISE EXCEPTION 'Provide the Policyholder Statement of Rights before sending the Letter of Representation'\n      USING ERRCODE = '23514';\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"enforce_platform_notification_delivery_identity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_platform_notification_delivery_identity()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  if new.notification_id is distinct from old.notification_id\n     or new.tenant_id is distinct from old.tenant_id\n     or new.user_id is distinct from old.user_id\n     or new.category is distinct from old.category\n     or new.channel is distinct from old.channel\n     or new.route_source is distinct from old.route_source then\n    raise exception 'notification_delivery_identity_immutable' using errcode='23514';\n  end if;\n  if new.delivery_state='delivered'\n     and (new.provider_receipt_id is null or new.delivered_at is null)\n     then raise exception 'verified_delivery_receipt_required' using errcode='23514'; end if;\n  new.updated_at := now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_proposal_operating_contract_activation_artifact","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_proposal_operating_contract_activation_artifact()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_signed public.signed_agreements%rowtype;\n  v_pending public.pending_agreements%rowtype;\nbegin\n  if new.lifecycle_status is distinct from 'activated' then\n    return new;\n  end if;\n\n  if new.signed_agreement_id is null then\n    raise exception 'proposal_operating_contract_signed_agreement_required';\n  end if;\n  if new.pending_agreement_id is null then\n    raise exception 'proposal_operating_contract_pending_agreement_required';\n  end if;\n  if nullif(btrim(coalesce(new.signed_pdf_path, '')), '') is null then\n    raise exception 'proposal_operating_contract_signed_pdf_required';\n  end if;\n\n  select * into v_signed\n  from public.signed_agreements\n  where id = new.signed_agreement_id;\n  if not found then\n    raise exception 'proposal_operating_contract_signed_agreement_not_found';\n  end if;\n  if coalesce(v_signed.esign_consent, false) is not true then\n    raise exception 'proposal_operating_contract_esign_consent_required';\n  end if;\n  if coalesce(v_signed.metadata->>'filled_pdf_path', '') <> new.signed_pdf_path then\n    raise exception 'proposal_operating_contract_signed_pdf_mismatch';\n  end if;\n  if coalesce(v_signed.metadata->>'pending_agreement_id', '') <> new.pending_agreement_id::text then\n    raise exception 'proposal_operating_contract_pending_agreement_mismatch';\n  end if;\n\n  select * into v_pending\n  from public.pending_agreements\n  where id = new.pending_agreement_id;\n  if not found then\n    raise exception 'proposal_operating_contract_pending_agreement_not_found';\n  end if;\n  if v_pending.status <> 'signed'\n     or coalesce(v_pending.signed_pdf_status, '') <> 'ready'\n     or v_pending.signed_pdf_path is distinct from new.signed_pdf_path then\n    raise exception 'proposal_operating_contract_signed_pdf_not_ready';\n  end if;\n  if lower(coalesce(v_pending.completed_fields->>'esign_consent', '')) <> 'true' then\n    raise exception 'proposal_operating_contract_server_consent_required';\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_safe_notification_destination","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_safe_notification_destination()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare v_link text;\nbegin\n  if new.link is null then return new; end if;\n  v_link := btrim(new.link);\n  if v_link = '' then new.link := null; return new; end if;\n  if length(v_link)>2048\n     or v_link ~ '[[:cntrl:]]'\n     or position(chr(92) in v_link)>0\n  then\n    raise exception 'notification_destination_unsafe' using errcode='22023';\n  end if;\n\n  if left(v_link,1)='/' and left(v_link,2)<>'//' then\n    new.link := v_link; return new;\n  end if;\n  -- External destinations must be HTTPS and have a real DNS suffix.\n  -- Payment and approved provider deep links remain possible.\n  if v_link ~* '^https://([a-z0-9-]+[.])+[a-z]{2,63}(:443)?([/?#].*)?$' then\n    new.link := v_link; return new;\n  end if;\n  raise exception 'notification_destination_unsafe' using errcode='22023';\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_task_claim_context","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_task_claim_context()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\ndeclare\n  claim_row public.contact_claims%rowtype;\nbegin\n  if new.claim_id is null then\n    return new;\n  end if;\n\n  select * into claim_row\n  from public.contact_claims\n  where id = new.claim_id;\n\n  if not found then\n    raise exception 'task_claim_not_found';\n  end if;\n\n  if new.tenant_id::text is distinct from claim_row.tenant_org_id::text then\n    raise exception 'task_claim_tenant_mismatch';\n  end if;\n\n  if new.contact_id is null then\n    new.contact_id := claim_row.contact_id;\n  elsif new.contact_id::text is distinct from claim_row.contact_id::text then\n    raise exception 'task_claim_contact_mismatch';\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_task_coordination_scope","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_task_coordination_scope()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_tenant uuid := public.business_activity_safe_uuid(new.tenant_id);\n  v_validate_assignee boolean := false;\nbegin\n  if v_tenant is null then\n    raise exception 'task_tenant_invalid' using errcode='23514';\n  end if;\n  if tg_op = 'INSERT' then\n    v_validate_assignee := new.assigned_to is not null;\n  else\n    if new.tenant_id is distinct from old.tenant_id\n      or new.user_id is distinct from old.user_id then\n      raise exception 'task_identity_immutable' using errcode='23514';\n    end if;\n    if new.assigned_to is distinct from old.assigned_to then\n      if auth.uid() is not null and auth.uid() is distinct from old.user_id\n        and not coalesce(public.is_system_admin(auth.uid()),false) then\n        raise exception 'task_assignment_requires_creator' using errcode='42501';\n      end if;\n      v_validate_assignee := new.assigned_to is not null;\n    end if;\n  end if;\n  if v_validate_assignee and not exists (\n    select 1 from public.user_tenant_memberships m\n    join public.profiles p on p.id=m.user_id\n    where m.tenant_id=v_tenant and m.user_id=new.assigned_to\n      and m.status='active' and coalesce(p.active,true)=true\n  ) then\n    raise exception 'task_assignee_not_active_in_tenant' using errcode='42501';\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_tenant_business_blueprint_authority","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_tenant_business_blueprint_authority()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_canonical_type text;\n  v_business_label text;\nbegin\n  new.settings := public.compile_tenant_business_blueprint_settings(\n    new.tenant_type,\n    new.name,\n    coalesce(new.settings, '{}'::jsonb),\n    tg_op = 'INSERT',\n    '[]'::jsonb\n  );\n\n  v_canonical_type := public.normalize_declared_business_type(new.tenant_type);\n  v_business_label := nullif(new.settings #>> '{tenant_manifest,businessOperatingBlueprint,businessType}', '');\n\n  -- A legacy machine token (for example MOBILE_VENDOR) may survive inside a\n  -- rich blueprint after the tenant is promoted to a new first-class type.\n  -- Repair only machine-shaped labels. Human labels intentionally remain owner\n  -- facing and are never normalized away by this authority.\n  if v_canonical_type is not null\n     and v_business_label ~ '^[A-Z][A-Z0-9_]{1,95}$'\n     and public.normalize_declared_business_type(v_business_label) is distinct from v_canonical_type then\n    new.settings := jsonb_set(\n      jsonb_set(\n        jsonb_set(\n          new.settings,\n          '{tenant_manifest,businessOperatingBlueprint,businessType}',\n          to_jsonb(v_canonical_type),\n          true\n        ),\n        '{business_operating_blueprint,businessType}',\n        to_jsonb(v_canonical_type),\n        true\n      ),\n      '{onboarding_contract,business_operating_blueprint,businessType}',\n      to_jsonb(v_canonical_type),\n      true\n    );\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_tenant_experience_family","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_tenant_experience_family()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nbegin\n  new.settings := jsonb_set(\n    coalesce(new.settings, '{}'::jsonb),\n    '{experience_family}',\n    to_jsonb(public.canonical_tenant_experience_family(new.settings, new.tenant_type)),\n    true\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_tenant_rebuttal_isolation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_tenant_rebuttal_isolation()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant_type text;\n  v_expected_scope text;\n  v_parent_tenant uuid;\n  v_parent_scope text;\nbegin\n  if new.tenant_org_id is null then\n    if coalesce(new.is_template, false) is not true then\n      new.is_active := false;\n      insert into public.tenant_content_integrity_events(\n        content_table, content_row_id, scope_value, event_type, action_taken, details\n      ) values (\n        'tenant_rebuttals', new.id, new.tenancy_type,\n        'tenantless_non_template', 'quarantined',\n        jsonb_build_object('reason', 'tenantless rebuttal must be an admin template')\n      );\n    end if;\n    return new;\n  end if;\n\n  select tenant_type into v_tenant_type\n  from public.tenants\n  where id = new.tenant_org_id;\n\n  v_expected_scope := public.expected_rebuttal_tenancy_type(v_tenant_type);\n\n  if v_tenant_type is null or v_expected_scope is null or new.tenancy_type is distinct from v_expected_scope then\n    new.is_active := false;\n    new.is_template := false;\n    insert into public.tenant_content_integrity_events(\n      tenant_org_id, content_table, content_row_id, scope_value, event_type, action_taken, details\n    ) values (\n      new.tenant_org_id, 'tenant_rebuttals', new.id, new.tenancy_type,\n      'tenant_scope_mismatch', 'quarantined',\n      jsonb_build_object('tenant_type', v_tenant_type, 'expected_scope', v_expected_scope)\n    );\n    return new;\n  end if;\n\n  new.is_template := false;\n\n  if new.derived_from_template_id is not null then\n    select tenant_org_id, tenancy_type\n      into v_parent_tenant, v_parent_scope\n    from public.tenant_rebuttals\n    where id = new.derived_from_template_id;\n\n    if not found or v_parent_tenant is not null or v_parent_scope is distinct from new.tenancy_type then\n      new.is_active := false;\n      insert into public.tenant_content_integrity_events(\n        tenant_org_id, content_table, content_row_id, scope_value, event_type, action_taken, details\n      ) values (\n        new.tenant_org_id, 'tenant_rebuttals', new.id, new.tenancy_type,\n        'invalid_template_provenance', 'quarantined',\n        jsonb_build_object('derived_from_template_id', new.derived_from_template_id)\n      );\n    end if;\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"enforce_test_account_rules","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enforce_test_account_rules()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_user uuid := auth.uid();\n  v_tenant text := COALESCE(NEW.tenant_org_id, OLD.tenant_org_id);\n  v_tenant_uuid uuid;\n  v_can_manage boolean := false;\n  v_can_owner boolean := false;\nBEGIN\n  IF v_user IS NULL THEN\n    RETURN CASE WHEN TG_OP = 'DELETE' THEN OLD ELSE NEW END;\n  END IF;\n\n  BEGIN\n    v_tenant_uuid := v_tenant::uuid;\n  EXCEPTION WHEN others THEN\n    v_tenant_uuid := NULL;\n  END;\n\n  v_can_manage := public.is_manager_or_higher(v_user, v_tenant_uuid) OR public.is_system_admin();\n  v_can_owner  := public.is_tenant_owner(v_user, v_tenant_uuid) OR public.is_system_admin();\n\n  IF TG_OP = 'UPDATE' THEN\n    IF OLD.test_account_static = true THEN\n      IF (NEW.is_test_account IS DISTINCT FROM OLD.is_test_account\n          OR NEW.test_account_static IS DISTINCT FROM OLD.test_account_static)\n         AND NOT v_can_owner THEN\n        INSERT INTO public.test_account_audit (contact_id, tenant_org_id, action, performed_by, reason)\n        VALUES (OLD.id, OLD.tenant_org_id, 'static_attempted_modify', v_user, 'blocked: only owner/godmode can modify static test contact');\n        RAISE EXCEPTION 'Static test contact cannot be modified by this role';\n      END IF;\n    END IF;\n\n    IF NEW.is_test_account IS DISTINCT FROM OLD.is_test_account THEN\n      IF NOT v_can_manage THEN\n        RAISE EXCEPTION 'Only Manager or higher can mark/unmark test accounts';\n      END IF;\n      NEW.test_account_marked_by := v_user;\n      NEW.test_account_marked_at := now();\n      INSERT INTO public.test_account_audit (contact_id, tenant_org_id, action, performed_by, reason)\n      VALUES (NEW.id, NEW.tenant_org_id,\n              CASE WHEN NEW.is_test_account THEN 'marked' ELSE 'unmarked' END,\n              v_user, NEW.test_account_reason);\n    END IF;\n\n  ELSIF TG_OP = 'DELETE' THEN\n    IF OLD.test_account_static = true AND NOT v_can_owner THEN\n      INSERT INTO public.test_account_audit (contact_id, tenant_org_id, action, performed_by, reason)\n      VALUES (OLD.id, OLD.tenant_org_id, 'static_attempted_delete', v_user, 'blocked: only owner/godmode can delete static test contact');\n      RAISE EXCEPTION 'Static test contact cannot be deleted by this role';\n    END IF;\n\n  ELSIF TG_OP = 'INSERT' THEN\n    IF NEW.is_test_account = true AND NOT v_can_manage THEN\n      RAISE EXCEPTION 'Only Manager or higher can create test-account contacts';\n    END IF;\n    IF NEW.is_test_account = true THEN\n      NEW.test_account_marked_by := COALESCE(NEW.test_account_marked_by, v_user);\n      NEW.test_account_marked_at := COALESCE(NEW.test_account_marked_at, now());\n    END IF;\n  END IF;\n\n  RETURN CASE WHEN TG_OP = 'DELETE' THEN OLD ELSE NEW END;\nEND;\n$function$\n","identity_arguments":""},{"name":"enqueue_email","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enqueue_email(queue_name text, payload jsonb)\n RETURNS bigint\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_catalog'\nAS $function$\nBEGIN\n  RETURN pgmq.send(queue_name, payload);\nEXCEPTION WHEN undefined_table THEN\n  PERFORM pgmq.create(queue_name);\n  RETURN pgmq.send(queue_name, payload);\nEND;\n$function$\n","identity_arguments":"queue_name text, payload jsonb"},{"name":"enqueue_platform_message_push","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.enqueue_platform_message_push()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare conv_tenant uuid;\nbegin\n  select c.tenant_id into conv_tenant\n  from public.message_conversations c where c.id=new.conversation_id;\n  if not found or new.deleted_at is not null then return new; end if;\n\n  insert into public.message_push_outbox\n    (message_id,conversation_id,tenant_id,recipient_user_id,subscription_id)\n  select new.id,new.conversation_id,conv_tenant,cm.user_id,s.id\n  from public.message_conversation_members cm\n  join public.message_push_subscriptions s\n    on s.user_id=cm.user_id and s.disabled_at is null\n  left join public.app_notification_preferences pref\n    on pref.tenant_id=conv_tenant and pref.user_id=cm.user_id\n  left join public.tenant_notification_policies tp\n    on tp.tenant_id=conv_tenant and tp.category='messages'\n  where cm.conversation_id=new.conversation_id\n    and cm.user_id<>new.sender_id and cm.muted_at is null\n    and not exists(\n      select 1 from public.notification_preferences p\n      where p.user_id=cm.user_id and p.event_type='message_received'\n        and p.push_enabled=false\n    )\n    -- The tenant-enforced policy wins; otherwise a recipient override wins,\n    -- then the tenant recommendation, then the platform's Push default.\n    and (conv_tenant is null or coalesce(\n      case when tp.mode='enforce' then tp.channel end,\n      pref.category_channels->>'messages',\n      tp.channel,\n      'push'\n    )='push')\n    and (conv_tenant is null or exists(\n      select 1 from public.tenants t where t.id=conv_tenant and t.is_active=true\n        and (t.owner_id=cm.user_id or exists(\n          select 1 from public.user_tenant_memberships m\n          where m.tenant_id=conv_tenant\n            and m.user_id=cm.user_id and m.status='active'\n        ))\n    ))\n  on conflict(message_id,subscription_id) do nothing;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"ensure_academy_onboarding_for_member","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ensure_academy_onboarding_for_member(p_user_id uuid, p_tenant_id uuid, p_enrolled_by uuid DEFAULT NULL::uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_track text;\n  v_course record;\n  v_inserted integer := 0;\n  v_seen integer := 0;\n  v_roles text[] := '{}';\n  v_has_module_contract boolean := false;\nbegin\n  if p_user_id is null or p_tenant_id is null then\n    raise exception 'user_id and tenant_id are required';\n  end if;\n\n  if not exists (\n    select 1 from public.user_tenant_memberships\n    where user_id = p_user_id and tenant_id = p_tenant_id and status = 'active'\n  ) then\n    insert into public.academy_provisioning_events(user_id, tenant_id, event_type, status, details)\n    values (p_user_id, p_tenant_id, 'member_onboarding', 'noop', jsonb_build_object('reason','membership_not_active'));\n    return jsonb_build_object('ok', true, 'status', 'noop', 'reason', 'membership_not_active');\n  end if;\n\n  select coalesce(array_agg(distinct lower(ur.role::text)) filter (where ur.role is not null), '{}')\n    into v_roles\n  from public.user_roles ur\n  where ur.user_id = p_user_id and ur.tenant_id = p_tenant_id;\n\n  if exists (\n    select 1 from public.user_tenant_memberships m\n    where m.user_id=p_user_id and m.tenant_id=p_tenant_id and m.status='active' and m.is_owner=true\n  ) then\n    v_roles := array(select distinct x from unnest(v_roles || array['owner','tenant owner']) x);\n  end if;\n\n  select exists(\n    select 1 from public.academy_tenant_modules atm\n    where atm.tenant_org_id = p_tenant_id::text\n  ) into v_has_module_contract;\n\n  v_track := public.academy_track_for_tenant(p_tenant_id);\n\n  for v_course in\n    select c.id, c.tenant_track, c.required_roles, c.required_module_keys\n    from public.academy_courses c\n    where c.is_published = true\n      and c.review_status = 'active'\n      and c.category = 'onboarding'\n      and c.tenant_org_id in ('00000000-0000-0000-0000-000000000000', p_tenant_id::text)\n      and c.tenant_track in ('universal', v_track)\n      and (\n        cardinality(c.required_roles) = 0\n        or exists (\n          select 1 from unnest(c.required_roles) req\n          where lower(req) = any(v_roles)\n        )\n      )\n      and (\n        cardinality(c.required_module_keys) = 0\n        or not v_has_module_contract\n        or not exists (\n          select 1 from unnest(c.required_module_keys) req\n          where not exists (\n            select 1 from public.academy_tenant_modules atm\n            where atm.tenant_org_id = p_tenant_id::text\n              and atm.enabled = true\n              and lower(atm.module_key) = lower(req)\n          )\n        )\n      )\n    order by case when c.tenant_org_id = p_tenant_id::text then 0 else 1 end,\n             case when c.tenant_track = v_track then 0 else 1 end,\n             c.is_required desc,\n             c.created_at asc\n  loop\n    v_seen := v_seen + 1;\n    insert into public.academy_enrollments(course_id, user_id, enrolled_by, status)\n    values (v_course.id, p_user_id, p_enrolled_by, 'active')\n    on conflict (user_id, course_id) do nothing;\n    if found then\n      v_inserted := v_inserted + 1;\n    end if;\n  end loop;\n\n  if v_seen = 0 then\n    insert into public.academy_provisioning_events(user_id, tenant_id, event_type, status, academy_track, details)\n    values (p_user_id, p_tenant_id, 'member_onboarding', 'failed', v_track,\n      jsonb_build_object('reason','no_matching_published_onboarding_course','roles',v_roles,'module_contract',v_has_module_contract));\n    return jsonb_build_object('ok', false, 'status', 'failed', 'track', v_track, 'reason', 'no_matching_published_onboarding_course', 'roles', v_roles);\n  end if;\n\n  insert into public.academy_provisioning_events(user_id, tenant_id, event_type, status, academy_track, details)\n  values (\n    p_user_id,\n    p_tenant_id,\n    'member_onboarding',\n    case when v_inserted > 0 then 'success' else 'noop' end,\n    v_track,\n    jsonb_build_object('courses_matched', v_seen, 'enrollments_created', v_inserted, 'roles', v_roles, 'module_contract', v_has_module_contract)\n  );\n\n  return jsonb_build_object('ok', true, 'status', case when v_inserted > 0 then 'success' else 'noop' end,\n    'track', v_track, 'courses_matched', v_seen, 'enrollments_created', v_inserted, 'roles', v_roles);\nexception when others then\n  begin\n    insert into public.academy_provisioning_events(user_id, tenant_id, event_type, status, academy_track, details)\n    values (p_user_id, p_tenant_id, 'member_onboarding', 'failed', v_track, jsonb_build_object('error', sqlerrm, 'roles', v_roles));\n  exception when others then\n    null;\n  end;\n  return jsonb_build_object('ok', false, 'status', 'failed', 'track', v_track, 'error', sqlerrm, 'roles', v_roles);\nend;\n$function$\n","identity_arguments":"p_user_id uuid, p_tenant_id uuid, p_enrolled_by uuid"},{"name":"ensure_cafe_menu_item_media_stub","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ensure_cafe_menu_item_media_stub()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  insert into public.cafe_menu_item_media (\n    tenant_org_id, menu_item_id, asset_role, status, image_url, alt_text,\n    creative_brief, generation_prompt, source_references, is_primary, sort_order\n  ) values (\n    new.tenant_org_id,\n    new.id,\n    'primary',\n    case when nullif(trim(coalesce(new.image_url,'')),'') is null then 'brief_ready' else 'ready' end,\n    nullif(trim(coalesce(new.image_url,'')),''),\n    new.name || ' product image',\n    jsonb_build_object(\n      'item_name', new.name,\n      'category', new.category,\n      'menu_section', new.menu_section,\n      'flavor_cues', coalesce(new.tags,'[]'::jsonb),\n      'composition', 'single premium menu-card hero product',\n      'logo_rule', 'Use the tenant-approved logo on visible cup or packaging when applicable',\n      'avoid', jsonb_build_array('invented ingredients','invented text','distorted packaging','AI anatomy artifacts')\n    ),\n    'Create a premium realistic commercial menu image for \"' || new.name || '\". Product truth: ' || coalesce(nullif(trim(new.description),''),'Use only verified menu data and the product name.') || ' Category: ' || coalesce(new.category,'menu item') || '. Use the tenant-approved logo on visible cup or packaging when applicable. Do not invent ingredients or text. Keep the product appetizing, realistic, cleanly composed, and menu-card ready.',\n    jsonb_build_array(jsonb_build_object('type','menu_item','external_item_id',new.external_item_id)),\n    true,\n    0\n  ) on conflict do nothing;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"ensure_default_homeowner_stage_rule","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ensure_default_homeowner_stage_rule(p_tenant_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF EXISTS (\n    SELECT 1 FROM public.pipeline_automation_rules\n    WHERE tenant_org_id = p_tenant_id\n      AND name = 'Homeowner Stage Update (Auto)'\n  ) THEN\n    RETURN;\n  END IF;\n\n  INSERT INTO public.pipeline_automation_rules (\n    tenant_org_id, name, description, is_active,\n    trigger_type, trigger_config, conditions, actions, priority\n  ) VALUES (\n    p_tenant_id,\n    'Homeowner Stage Update (Auto)',\n    'Auto-seeded: notifies the homeowner on every pipeline stage change. Customize copy in Owner → Automations → Stage Messaging.',\n    true,\n    'stage_change',\n    '{}'::jsonb,\n    '[]'::jsonb,\n    '[{\"type\":\"send_homeowner_stage_update\",\"config\":{}}]'::jsonb,\n    10\n  );\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"ensure_mobile_vendor_event_workflow","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ensure_mobile_vendor_event_workflow(p_event_booking_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_tenant text;\nbegin\n  select tenant_org_id into v_tenant from public.event_bookings where id = p_event_booking_id;\n  if v_tenant is null then raise exception 'event booking not found'; end if;\n\n  insert into public.event_workflow_steps\n    (tenant_org_id, event_booking_id, phase, step_key, label, sort_order)\n  values\n    (v_tenant, p_event_booking_id, 'Intake', 'confirm_event_details', 'Confirm date, time, venue, attendance, setup, and contact details', 10),\n    (v_tenant, p_event_booking_id, 'Quote', 'prepare_quote', 'Prepare and approve the event quote', 20),\n    (v_tenant, p_event_booking_id, 'Agreement', 'agreement_signed', 'Send the right event agreement and get it signed', 30),\n    (v_tenant, p_event_booking_id, 'Payment', 'deposit_payment', 'Confirm deposit or required payment', 40),\n    (v_tenant, p_event_booking_id, 'Prep', 'venue_requirements', 'Confirm venue access, power, insurance, setup, and vendor requirements', 50),\n    (v_tenant, p_event_booking_id, 'Prep', 'final_headcount', 'Confirm contracted tickets or service quantity, final attendance, and the bid amount', 60),\n    (v_tenant, p_event_booking_id, 'Prep', 'loadout_ready', 'Complete product, supplies, trailer, equipment, staff, food, water, and fuel loadout', 70),\n    (v_tenant, p_event_booking_id, 'Event Day', 'setup_complete', 'Arrive and complete event setup', 80),\n    (v_tenant, p_event_booking_id, 'Event Day', 'service_complete', 'Complete service and account for unused product and reusable gear', 90),\n    (v_tenant, p_event_booking_id, 'Closeout', 'balance_complete', 'Create or close the final invoice and remaining balance', 100),\n    (v_tenant, p_event_booking_id, 'Follow-Up', 'customer_followup', 'Thank the customer, request a review, and schedule repeat-booking follow-up', 110)\n  on conflict (event_booking_id, step_key) do nothing;\nend;\n$function$\n","identity_arguments":"p_event_booking_id uuid"},{"name":"ensure_owner_tenant_relationship","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ensure_owner_tenant_relationship()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$ begin insert into public.owner_tenant_relationships (tenant_id) values (new.id) on conflict (tenant_id) do nothing; return new; end; $function$\n","identity_arguments":""},{"name":"ensure_pcg_submission_wmp_identity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ensure_pcg_submission_wmp_identity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if new.wmp_number is null or btrim(new.wmp_number) = '' then\n    new.wmp_number := 'WMP-' || coalesce(nullif(btrim(new.submission_number), ''), upper(substr(replace(gen_random_uuid()::text,'-',''),1,10)));\n  end if;\n\n  if new.wmp_token is null or btrim(new.wmp_token) = '' then\n    new.wmp_token := replace(gen_random_uuid()::text, '-', '');\n  end if;\n\n  if new.wmp_created_at is null then\n    new.wmp_created_at := now();\n  end if;\n\n  case lower(coalesce(new.status,''))\n    when 'ready' then\n      if coalesce(new.shipping_status,'') in ('','not_ready') then\n        new.shipping_status := case when new.return_shipping_method='pickup' then 'ready_for_pickup' else 'ready_to_ship' end;\n      end if;\n    when 'shipped' then\n      new.shipping_status := 'shipped';\n      new.shipped_at := coalesce(new.shipped_at, now());\n    when 'picked_up' then\n      new.shipping_status := 'picked_up';\n      new.picked_up_at := coalesce(new.picked_up_at, now());\n    when 'delivered' then\n      new.shipping_status := 'delivered';\n      new.delivered_at := coalesce(new.delivered_at, now());\n    when 'closed' then\n      if coalesce(new.shipping_status,'') = '' then\n        new.shipping_status := 'closed';\n      end if;\n    else\n      if new.shipping_status is null or btrim(new.shipping_status) = '' then\n        new.shipping_status := 'not_ready';\n      end if;\n  end case;\n\n  if new.tracking_out is not null and btrim(new.tracking_out) <> '' and (new.shipping_status is null or new.shipping_status in ('','not_ready')) then\n    new.shipping_status := 'tracking_assigned';\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"ensure_tenant_provisioning_foundation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ensure_tenant_provisioning_foundation(p_tenant_id uuid, p_owner_user_id uuid DEFAULT NULL::uuid, p_owner_role text DEFAULT 'Tenant Owner'::text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_caller uuid := auth.uid();\n  v_uid uuid := coalesce(p_owner_user_id,auth.uid());\n  v_tenant public.tenants%rowtype;\n  v_type text;\n  v_membership_id uuid;\n  v_track text;\n  v_authorized boolean := false;\n  v_owner_role text := coalesce(nullif(trim(p_owner_role),''),'Tenant Owner');\nbegin\n  if p_tenant_id is null then raise exception 'Tenant id is required'; end if;\n  select * into v_tenant from public.tenants where id=p_tenant_id;\n  if not found then raise exception 'Tenant not found'; end if;\n  v_authorized := session_user in ('postgres','supabase_admin')\n    or coalesce(auth.role(),'')='service_role'\n    or public.is_system_admin(v_caller)\n    or public.is_admin_or_higher(v_caller,p_tenant_id)\n    or (v_tenant.owner_id=v_caller and coalesce(p_owner_user_id,v_caller)=v_caller);\n  if not v_authorized then raise exception 'Not authorized to provision this tenant' using errcode='42501'; end if;\n  if p_owner_user_id is not null and v_caller is not null and p_owner_user_id<>v_caller\n     and session_user not in ('postgres','supabase_admin')\n     and coalesce(auth.role(),'')<>'service_role'\n     and not public.is_system_admin(v_caller)\n  then raise exception 'Only platform administrators may provision another user as tenant owner' using errcode='42501'; end if;\n  v_type:=public.normalize_declared_business_type(v_tenant.tenant_type);\n  if v_type is null or v_type is distinct from v_tenant.tenant_type then raise exception 'Tenant has unresolved business identity'; end if;\n  if v_uid is null then v_uid:=v_tenant.owner_id; end if;\n  if v_uid is null then raise exception 'Tenant owner is required before provisioning'; end if;\n  update public.tenants set owner_id=coalesce(owner_id,v_uid),updated_at=now() where id=p_tenant_id;\n  insert into public.user_tenant_memberships(user_id,tenant_id,is_owner,status)\n    values(v_uid,p_tenant_id,true,'active')\n    on conflict(user_id,tenant_id)\n    do update set status='active',is_owner=true,last_accessed_at=now()\n    returning id into v_membership_id;\n  if not exists(select 1 from public.user_roles where user_id=v_uid and tenant_id=p_tenant_id) then\n    insert into public.user_roles(user_id,tenant_id,role,assigned_by)\n      values(v_uid,p_tenant_id,v_owner_role::public.app_role,v_caller);\n  end if;\n  v_track:=coalesce(public.academy_track_for_type(v_type),'universal');\n  insert into public.tenant_readiness_checks(tenant_id,check_key,status,detail)\n    values(p_tenant_id,'owner_foundation','ready',jsonb_build_object('owner_id',v_uid,'membership_id',v_membership_id,'academy_track',v_track,'academy_enrollment_mode','existing_course_system'))\n    on conflict(tenant_id,check_key)\n    do update set status='ready',detail=excluded.detail,updated_at=now();\n  return jsonb_build_object('ok',true,'tenant_id',p_tenant_id,'tenant_type',v_type,'owner_id',v_uid,'membership_id',v_membership_id,'academy_track',v_track,'owner_role',v_owner_role);\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_owner_user_id uuid, p_owner_role text"},{"name":"ensure_tenant_public_presence_contract","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ensure_tenant_public_presence_contract()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  new.settings := public.apply_tenant_public_presence_contract(new.settings,new.company_slug);\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"ensure_unique_route_contact_number","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.ensure_unique_route_contact_number()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  attempts integer := 0;\nBEGIN\n  IF NEW.tenant_org_id IS NULL THEN\n    RETURN NEW;\n  END IF;\n\n  WHILE NEW.route_contact_number IS NULL\n     OR EXISTS (\n       SELECT 1\n       FROM public.unified_contacts u\n       WHERE u.tenant_org_id = NEW.tenant_org_id\n         AND u.route_contact_number = NEW.route_contact_number\n         AND u.id IS DISTINCT FROM NEW.id\n     )\n  LOOP\n    NEW.route_contact_number := lpad(\n      (10000000::bigint + floor(random() * 90000000)::bigint)::text,\n      8,\n      '0'\n    );\n    attempts := attempts + 1;\n    IF attempts >= 25 THEN\n      RAISE EXCEPTION 'Could not allocate unique route contact number for tenant %', NEW.tenant_org_id;\n    END IF;\n  END LOOP;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"event_rental_asset_available_quantity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.event_rental_asset_available_quantity(p_tenant_id uuid, p_asset_id uuid, p_starts_at timestamp with time zone, p_ends_at timestamp with time zone, p_exclude_event_booking_id uuid DEFAULT NULL::uuid)\n RETURNS integer\n LANGUAGE sql\n STABLE\n SET search_path TO 'public'\nAS $function$\nSELECT greatest(0,a.total_quantity-coalesce((SELECT sum(x.quantity)::integer FROM public.event_rental_asset_allocations x WHERE x.tenant_id=p_tenant_id AND x.asset_id=p_asset_id AND x.status IN('reserved','deployed') AND(p_exclude_event_booking_id IS NULL OR x.event_booking_id<>p_exclude_event_booking_id) AND tstzrange(x.starts_at,x.ends_at,'[)')&&tstzrange(p_starts_at,p_ends_at,'[)')),0)) FROM public.event_rental_assets a WHERE a.id=p_asset_id AND a.tenant_id=p_tenant_id;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_asset_id uuid, p_starts_at timestamp with time zone, p_ends_at timestamp with time zone, p_exclude_event_booking_id uuid"},{"name":"event_rental_event_readiness_summary","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.event_rental_event_readiness_summary(p_tenant_id uuid, p_event_booking_id uuid)\n RETURNS jsonb\n LANGUAGE sql\n STABLE\n SET search_path TO 'public'\nAS $function$\nWITH items AS(SELECT * FROM public.event_rental_readiness_items r WHERE r.tenant_id=p_tenant_id AND r.event_booking_id=p_event_booking_id), scored AS(SELECT count(*) FILTER(WHERE required AND status<>'not_applicable') AS required_count,count(*) FILTER(WHERE required AND status='ready') AS ready_count,count(*) FILTER(WHERE status='blocked') AS blocker_count,coalesce(jsonb_agg(jsonb_build_object('key',item_key,'label',label,'reason',blocker_reason) ORDER BY label) FILTER(WHERE status='blocked'),'[]'::jsonb) AS blockers FROM items)\nSELECT jsonb_build_object('required',required_count,'ready',ready_count,'blocked',blocker_count,'score',CASE WHEN required_count=0 THEN 100 ELSE round((ready_count::numeric/required_count::numeric)*100)::integer END,'blockers',blockers) FROM scored;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_event_booking_id uuid"},{"name":"event_rentals_operating_contract","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.event_rentals_operating_contract()\n RETURNS jsonb\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\nSELECT $json${\n  \"contractVersion\": 1,\n  \"serviceLevels\": [\n    {\"key\":\"rent_it\",\"label\":\"Rent It\",\"description\":\"Equipment rental with customer-managed event execution.\"},\n    {\"key\":\"set_it_up\",\"label\":\"Set It Up\",\"description\":\"Delivery, setup, breakdown, pickup, return, and inspection.\"},\n    {\"key\":\"activate_my_business\",\"label\":\"Activate My Business\",\"description\":\"Turn a client property into a measurable promotional or community event.\"},\n    {\"key\":\"produce_my_event\",\"label\":\"Produce My Event\",\"description\":\"Full event production with infrastructure, vendors, readiness, execution, and outcomes.\"}\n  ],\n  \"modes\": [\n    {\"key\":\"rentals\",\"label\":\"Rentals\",\"applications\":[\"inventory\",\"availability\",\"quotes_bookings\",\"delivery_pickup\",\"returns\",\"damage_condition\",\"packages\"]},\n    {\"key\":\"events\",\"label\":\"Events\",\"applications\":[\"event_calendar\",\"run_of_show\",\"site_plan\",\"attendance\",\"crew\",\"weather_contingency\",\"setup_teardown\",\"event_readiness\"]},\n    {\"key\":\"activations\",\"label\":\"Activations\",\"applications\":[\"client_account\",\"event_objective\",\"promotion_registration\",\"lead_capture\",\"attendance\",\"sponsors\",\"roi_outcomes\",\"follow_up\"]},\n    {\"key\":\"vendors\",\"label\":\"Vendors\",\"applications\":[\"vendor_directory\",\"assignments\",\"food_service\",\"entertainment\",\"security\",\"decor\",\"compliance_licenses\",\"insurance_coi\",\"documents\",\"performance_history\"]}\n  ],\n  \"assetCategories\": [\"commercial_tents_canopies\",\"chairs\",\"rectangular_tables\",\"round_tables\",\"cocktail_high_top_tables\",\"sidewalls\",\"lighting\",\"linens\",\"signage_backdrops\",\"stanchions_check_in\",\"trash_recycling\",\"coolers_beverage_stations\",\"carts_dollies\",\"storage_bins\",\"cleaning_maintenance\",\"trailers_transportation\",\"custom\"],\n  \"assetLifecycleStatuses\": [\"available\",\"inspection_needed\",\"damaged\",\"repair\",\"retired\"],\n  \"allocationStatuses\": [\"reserved\",\"deployed\",\"returned\",\"cancelled\"],\n  \"deliveryWorkflow\": [\"load_plan\",\"delivery\",\"setup\",\"event_live\",\"breakdown\",\"pickup_return\",\"inspection\",\"cleaning_maintenance\",\"damage_capture\",\"complete\"],\n  \"readinessCategories\": [\"site_authorization\",\"temporary_structure_documents\",\"insurance_coi\",\"permits\",\"weather_contingency\",\"power_electrical\",\"sanitation_trash\",\"emergency_access\",\"security\",\"food_vendor_compliance\",\"alcohol_provider\",\"vendor_confirmations\",\"inventory_allocation\",\"crew_assignments\",\"setup_breakdown_plan\",\"required_documents\"],\n  \"vendorFields\": [\"category\",\"contact_reference\",\"event_assignments\",\"status\",\"license_metadata\",\"document_metadata\",\"insurance_coi_metadata\",\"insurance_expiration\",\"notes\",\"performance_history\"],\n  \"activationMetrics\": [\"registrations\",\"attendance\",\"leads_captured\",\"appointments_or_conversions_entered\",\"sponsor_participation\",\"sponsor_revenue\",\"event_expenses\",\"follow_up_state\"],\n  \"eventOwnershipTypes\": [\"client_event\",\"owned_event\"],\n  \"packageModel\": \"outcome_oriented_with_internal_asset_allocation\",\n  \"financeCategories\": [\"equipment_rental\",\"delivery\",\"setup_breakdown\",\"tent_infrastructure\",\"decor_lighting\",\"event_management_production\",\"vendor_coordination\",\"sponsorship\",\"media_content\",\"signage_branding\",\"deposit\",\"damage_charge\",\"taxes_fees\",\"event_specific_expense\"],\n  \"homePriorities\": [\"upcoming_bookings_events\",\"readiness_risks\",\"inventory_commitments_conflicts_utilization\",\"deliveries_pickups\",\"outstanding_deposits_balances\",\"vendor_compliance_expirations\",\"next_operational_tasks\"]\n}$json$::jsonb;\n$function$\n","identity_arguments":""},{"name":"execute_sql","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.execute_sql(p_sql_query text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NOT public.is_system_admin(auth.uid()) THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'Admin access required');\n  END IF;\n  EXECUTE p_sql_query;\n  RETURN jsonb_build_object('ok', true, 'message', 'SQL executed successfully');\nEXCEPTION WHEN OTHERS THEN\n  RETURN jsonb_build_object('ok', false, 'error', SQLERRM);\nEND;\n$function$\n","identity_arguments":"p_sql_query text"},{"name":"execute_sql_query","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.execute_sql_query(p_sql_query text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_result jsonb;\nBEGIN\n  IF NOT public.is_system_admin(auth.uid()) THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'Admin access required');\n  END IF;\n  EXECUTE 'SELECT jsonb_agg(row_to_json(t.*)) FROM (' || p_sql_query || ') t'\n  INTO v_result;\n  RETURN jsonb_build_object('ok', true, 'data', COALESCE(v_result, '[]'::jsonb));\nEXCEPTION WHEN OTHERS THEN\n  RETURN jsonb_build_object('ok', false, 'error', SQLERRM);\nEND;\n$function$\n","identity_arguments":"p_sql_query text"},{"name":"expected_rebuttal_tenancy_type","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.expected_rebuttal_tenancy_type(p_tenant_type text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  select case upper(coalesce(p_tenant_type, ''))\n    when 'MITIGATION' then 'mitigation'\n    when 'ROOFING_COMPANY' then 'roofing'\n    when 'PUBLIC_ADJUSTER_FIRM' then 'public_adjuster'\n    when 'REALTOR' then 'realtor'\n    else null\n  end\n$function$\n","identity_arguments":"p_tenant_type text"},{"name":"fill_permit_lookup_attempt_attribution","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.fill_permit_lookup_attempt_attribution()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\r\ndeclare\r\n  inferred_tenant uuid;\r\n  tenant_count integer;\r\n  cfg record;\r\n  cfg_count integer;\r\nbegin\r\n  if new.tenant_org_id is null and new.triggered_by is not null then\r\n    select count(distinct uta.tenant_id)\r\n      into tenant_count\r\n    from public.user_tenant_access uta\r\n    where uta.user_id = new.triggered_by\r\n      and coalesce(uta.membership_status, 'active') in ('active', 'accepted')\r\n      and coalesce(uta.has_membership, true) = true;\r\n\r\n    if tenant_count = 1 then\r\n      select uta.tenant_id\r\n        into inferred_tenant\r\n      from public.user_tenant_access uta\r\n      where uta.user_id = new.triggered_by\r\n        and coalesce(uta.membership_status, 'active') in ('active', 'accepted')\r\n        and coalesce(uta.has_membership, true) = true\r\n      limit 1;\r\n\r\n      new.tenant_org_id := inferred_tenant;\r\n    end if;\r\n  end if;\r\n\r\n  if new.tenant_org_id is not null\r\n     and (\r\n       new.searched_source is null or new.searched_source = '' or new.searched_source = 'Unknown'\r\n       or new.searched_jurisdiction is null or new.searched_jurisdiction = '' or new.searched_jurisdiction = 'Unknown'\r\n     ) then\r\n    select count(*)\r\n      into cfg_count\r\n    from public.permit_source_configs psc\r\n    where psc.tenant_org_id = new.tenant_org_id\r\n      and psc.enabled = true;\r\n\r\n    if cfg_count = 1 then\r\n      select psc.source_name, psc.municipality, psc.county, psc.state\r\n        into cfg\r\n      from public.permit_source_configs psc\r\n      where psc.tenant_org_id = new.tenant_org_id\r\n        and psc.enabled = true\r\n      limit 1;\r\n\r\n      if new.searched_source is null or new.searched_source = '' or new.searched_source = 'Unknown' then\r\n        new.searched_source := cfg.source_name;\r\n      end if;\r\n\r\n      if new.searched_jurisdiction is null or new.searched_jurisdiction = '' or new.searched_jurisdiction = 'Unknown' then\r\n        new.searched_jurisdiction := trim(both ', ' from concat_ws(', ', cfg.municipality, cfg.county, cfg.state));\r\n      end if;\r\n    end if;\r\n  end if;\r\n\r\n  return new;\r\nend;\r\n$function$\n","identity_arguments":""},{"name":"finalize_tenant_blueprint_insert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.finalize_tenant_blueprint_insert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$ BEGIN PERFORM public.provision_tenant_blueprint(new.id); RETURN new; END; $function$\n","identity_arguments":""},{"name":"flag_roof_related_permit","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.flag_roof_related_permit()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nDECLARE combined TEXT;\nBEGIN\n  combined := lower(coalesce(NEW.permit_type,'') || ' ' ||\n                    coalesce(NEW.description,'') || ' ' ||\n                    coalesce(NEW.notes,''));\n  NEW.is_roof_related := (combined ~ '(roof|reroof|re-roof|shingle|tile re|tile-re|tarp|tarping)');\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"force_end_call_session","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.force_end_call_session(_session_id uuid, _reason text)\n RETURNS active_call_sessions\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  s public.active_call_sessions;\nBEGIN\n  SELECT * INTO s FROM public.active_call_sessions WHERE id = _session_id;\n  IF s.id IS NULL THEN\n    RAISE EXCEPTION 'Session not found';\n  END IF;\n  IF NOT public.is_manager_or_higher(auth.uid(), s.tenant_org_id::uuid) THEN\n    RAISE EXCEPTION 'Not authorized';\n  END IF;\n\n  UPDATE public.active_call_sessions\n     SET status = 'ended',\n         ended_at = now(),\n         force_ended_by_user_id = auth.uid(),\n         force_ended_reason = COALESCE(NULLIF(trim(_reason), ''), 'Force-ended by manager'),\n         force_ended_at = now()\n   WHERE id = _session_id\n   RETURNING * INTO s;\n\n  RETURN s;\nEND;\n$function$\n","identity_arguments":"_session_id uuid, _reason text"},{"name":"generate_lawn_service_visits","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.generate_lawn_service_visits(p_tenant_id uuid, p_start_date date DEFAULT CURRENT_DATE, p_days integer DEFAULT 42)\n RETURNS integer\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nDECLARE inserted_count integer := 0;\nBEGIN\n  INSERT INTO public.lawn_service_visits (\n    tenant_id, service_plan_id, contact_id, service_date, stop_order,\n    status, assigned_crew_id, metadata\n  )\n  SELECT\n    plan.tenant_id,\n    plan.id,\n    plan.contact_id,\n    day::date,\n    row_number() OVER (PARTITION BY day ORDER BY plan.route_day, plan.created_at, plan.contact_id)::integer,\n    'scheduled',\n    plan.assigned_crew_id,\n    jsonb_build_object(\n      'generated_by', 'recurring_service_engine_v2',\n      'cadence', plan.cadence,\n      'anchor_date', coalesce(plan.next_service_date, plan.created_at::date)\n    )\n  FROM public.lawn_service_plans plan\n  CROSS JOIN LATERAL generate_series(\n    p_start_date,\n    p_start_date + greatest(0, least(p_days, 120)),\n    interval '1 day'\n  ) day\n  WHERE plan.tenant_id = p_tenant_id\n    AND plan.status = 'active'\n    AND plan.route_day IS NOT NULL\n    AND (plan.pause_until IS NULL OR day::date > plan.pause_until)\n    AND trim(to_char(day, 'Day')) = plan.route_day\n    AND day::date >= coalesce(plan.next_service_date, plan.created_at::date)\n    AND CASE plan.cadence\n      WHEN 'weekly' THEN mod(day::date - coalesce(plan.next_service_date, plan.created_at::date), 7) = 0\n      WHEN 'biweekly' THEN mod(day::date - coalesce(plan.next_service_date, plan.created_at::date), 14) = 0\n      WHEN 'monthly' THEN extract(day from day::date) <= 7\n      WHEN 'one_time' THEN day::date = coalesce(plan.next_service_date, plan.created_at::date)\n      ELSE false\n    END\n  ON CONFLICT (tenant_id, contact_id, service_date) DO NOTHING;\n\n  GET DIAGNOSTICS inserted_count = ROW_COUNT;\n\n  UPDATE public.lawn_service_plans plan\n  SET next_service_date = (\n    SELECT min(v.service_date)\n    FROM public.lawn_service_visits v\n    WHERE v.tenant_id = plan.tenant_id\n      AND v.service_plan_id = plan.id\n      AND v.service_date >= current_date\n      AND v.status IN ('scheduled','in_progress','rescheduled')\n  )\n  WHERE plan.tenant_id = p_tenant_id\n    AND EXISTS (\n      SELECT 1\n      FROM public.lawn_service_visits v\n      WHERE v.tenant_id = plan.tenant_id\n        AND v.service_plan_id = plan.id\n        AND v.service_date >= current_date\n        AND v.status IN ('scheduled','in_progress','rescheduled')\n    );\n\n  RETURN inserted_count;\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_start_date date, p_days integer"},{"name":"generate_portal_token","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.generate_portal_token()\n RETURNS text\n LANGUAGE plpgsql\n SET search_path TO 'pg_catalog', 'pg_temp'\nAS $function$\nDECLARE\n  alphabet text := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n  result text := '';\n  i int;\nBEGIN\n  FOR i IN 1..24 LOOP\n    result := result || substr(alphabet, 1 + floor(random() * length(alphabet))::int, 1);\n  END LOOP;\n  RETURN result;\nEND;\n$function$\n","identity_arguments":""},{"name":"get_active_call_floor","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_active_call_floor(p_tenant_org_id text)\n RETURNS TABLE(session_id uuid, rep_id uuid, rep_name text, lead_id uuid, lead_name text, phone_number text, status text, started_at timestamp with time zone, parent_call_sid text, homeowner_call_sid text)\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  SELECT\n    s.id AS session_id,\n    s.rep_id,\n    p.name AS rep_name,\n    s.lead_id,\n    COALESCE(NULLIF(TRIM(CONCAT(uc.first_name, ' ', uc.last_name)), ''), l.name, 'Unknown') AS lead_name,\n    s.phone_number,\n    s.status,\n    s.started_at,\n    s.parent_call_sid,\n    s.homeowner_call_sid\n  FROM public.active_call_sessions s\n  LEFT JOIN public.profiles p ON p.id = s.rep_id\n  LEFT JOIN public.leads l ON l.id = s.lead_id\n  LEFT JOIN public.unified_contacts uc ON uc.id = s.lead_id\n  WHERE s.tenant_org_id = p_tenant_org_id\n    AND s.ended_at IS NULL\n    AND s.status NOT IN ('ended','failed','completed','no-answer','busy')\n    AND (\n      is_admin_or_higher(auth.uid(), p_tenant_org_id::uuid)\n      OR is_system_admin()\n    )\n  ORDER BY s.started_at DESC;\n$function$\n","identity_arguments":"p_tenant_org_id text"},{"name":"get_all_tables","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_all_tables()\n RETURNS TABLE(table_name text)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\nbegin\n  perform public.require_platform_operator();\n  return query\n    select t.tablename::text\n    from pg_catalog.pg_tables t\n    where t.schemaname = 'public'\n    order by t.tablename;\nend;\n$function$\n","identity_arguments":""},{"name":"get_console_session","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_console_session(_session_id uuid)\n RETURNS TABLE(session_id uuid, event_title text, session_status text, ledger_tenant_id uuid, ledger_tenant_name text, ledger_tenant_slug text, created_at timestamp with time zone, updated_at timestamp with time zone, event_context jsonb, turns jsonb, receipts jsonb)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO ''\nAS $function$\nbegin\n  if auth.uid() is null or not public.is_system_admin(auth.uid()) then\n    raise exception 'Platform owner required' using errcode = '42501';\n  end if;\n\n  return query\n  select\n    e.id,\n    e.title,\n    e.status,\n    e.tenant_id,\n    t.name,\n    t.company_slug,\n    e.created_at,\n    e.updated_at,\n    coalesce(e.mission_context, '{}'::jsonb),\n    coalesce((\n      select jsonb_agg(\n        jsonb_build_object(\n          'id', cm.id,\n          'created_at', cm.created_at,\n          'sender_role', cm.sender_role,\n          'actor_type', cm.actor_type,\n          'actor_display_name', cm.actor_display_name,\n          'raw_message', cm.message\n        )\n        order by cm.created_at asc\n      )\n      from public.command_center_messages cm\n      where cm.command_center_event_id = e.id\n    ), '[]'::jsonb),\n    coalesce((\n      select jsonb_agg(\n        jsonb_build_object(\n          'id', cr.id,\n          'created_at', cr.created_at,\n          'receipt_type', cr.receipt_type,\n          'source', cr.source,\n          'status', cr.status,\n          'proof_gate', cr.proof_gate,\n          'external_id', cr.external_id,\n          'source_sha', cr.source_sha,\n          'payload', cr.payload\n        )\n        order by cr.created_at asc\n      )\n      from public.command_center_receipts cr\n      where cr.command_center_event_id = e.id\n    ), '[]'::jsonb)\n  from public.command_center_events e\n  left join public.tenants t on t.id = e.tenant_id\n  where e.id = _session_id\n    and e.event_type = 'sidekick_conversation_log'\n  limit 1;\nend;\n$function$\n","identity_arguments":"_session_id uuid"},{"name":"get_contact_claim_payment_history","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_contact_claim_payment_history(_claim_id uuid)\n RETURNS TABLE(id uuid, claim_id uuid, from_status claim_payment_lifecycle_v4, to_status claim_payment_lifecycle_v4, changed_by uuid, changed_at timestamp with time zone, note text, source text)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _uid uuid := auth.uid();\n  _tenant text;\n  _allowed boolean;\nBEGIN\n  IF _uid IS NULL THEN\n    RAISE EXCEPTION 'unauthenticated' USING ERRCODE = '42501';\n  END IF;\n\n  SELECT cc.tenant_org_id INTO _tenant\n  FROM public.contact_claims cc\n  WHERE cc.id = _claim_id;\n\n  IF _tenant IS NULL THEN\n    RAISE EXCEPTION 'claim not found' USING ERRCODE = 'P0002';\n  END IF;\n\n  SELECT\n    public.is_system_admin(_uid)\n    OR public.is_manager_or_higher(_uid, _tenant::uuid)\n    OR EXISTS (\n      SELECT 1 FROM public.user_roles ur\n      WHERE ur.user_id = _uid\n        AND ur.tenant_id = _tenant::uuid\n        AND ur.role = 'PM'::public.app_role\n    )\n  INTO _allowed;\n\n  IF NOT _allowed THEN\n    RAISE EXCEPTION 'forbidden: claim/payment history not visible to your role'\n      USING ERRCODE = '42501';\n  END IF;\n\n  RETURN QUERY\n  SELECT h.id, h.claim_id, h.from_status, h.to_status, h.changed_by, h.changed_at, h.note, h.source\n  FROM public.claim_payment_status_history h\n  WHERE h.claim_id = _claim_id\n  ORDER BY h.changed_at DESC;\nEND;\n$function$\n","identity_arguments":"_claim_id uuid"},{"name":"get_contact_claim_payment_status","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_contact_claim_payment_status(_claim_id uuid)\n RETURNS TABLE(id uuid, claim_payment_status claim_payment_lifecycle_v4, claim_payment_status_updated_at timestamp with time zone, claim_payment_status_updated_by uuid)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _uid uuid := auth.uid();\n  _tenant text;\n  _allowed boolean;\nBEGIN\n  IF _uid IS NULL THEN\n    RAISE EXCEPTION 'unauthenticated' USING ERRCODE = '42501';\n  END IF;\n\n  SELECT cc.tenant_org_id INTO _tenant\n  FROM public.contact_claims cc\n  WHERE cc.id = _claim_id;\n\n  IF _tenant IS NULL THEN\n    RAISE EXCEPTION 'claim not found' USING ERRCODE = 'P0002';\n  END IF;\n\n  SELECT\n    public.is_system_admin(_uid)\n    OR public.is_manager_or_higher(_uid, _tenant::uuid)\n    OR EXISTS (\n      SELECT 1 FROM public.user_roles ur\n      WHERE ur.user_id = _uid\n        AND ur.tenant_id = _tenant::uuid\n        AND ur.role = 'PM'::public.app_role\n    )\n  INTO _allowed;\n\n  IF NOT _allowed THEN\n    RAISE EXCEPTION 'forbidden: claim/payment status not visible to your role'\n      USING ERRCODE = '42501';\n  END IF;\n\n  RETURN QUERY\n  SELECT cc.id,\n         cc.claim_payment_status,\n         cc.claim_payment_status_updated_at,\n         cc.claim_payment_status_updated_by\n  FROM public.contact_claims cc\n  WHERE cc.id = _claim_id;\nEND;\n$function$\n","identity_arguments":"_claim_id uuid"},{"name":"get_contact_compliance_bypass","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_contact_compliance_bypass(_tenant_org_id text, _contact_id uuid)\n RETURNS TABLE(active boolean, checked_at timestamp with time zone, checked_by uuid, reason text, phone_number text, raw_response jsonb)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_user uuid := auth.uid();\n  v_tenant_uuid uuid;\n  v_can_bypass boolean := false;\nBEGIN\n  IF v_user IS NULL OR _tenant_org_id IS NULL OR _contact_id IS NULL THEN\n    RETURN QUERY SELECT false, NULL::timestamptz, NULL::uuid, NULL::text, NULL::text, NULL::jsonb;\n    RETURN;\n  END IF;\n\n  BEGIN\n    v_tenant_uuid := _tenant_org_id::uuid;\n  EXCEPTION WHEN others THEN\n    v_tenant_uuid := NULL;\n  END;\n\n  v_can_bypass := public.is_system_admin(v_user)\n    OR (v_tenant_uuid IS NOT NULL AND public.is_admin_or_higher(v_user, v_tenant_uuid));\n\n  IF NOT v_can_bypass THEN\n    RETURN QUERY SELECT false, NULL::timestamptz, NULL::uuid, NULL::text, NULL::text, NULL::jsonb;\n    RETURN;\n  END IF;\n\n  IF NOT EXISTS (\n    SELECT 1\n    FROM public.unified_contacts uc\n    WHERE uc.id = _contact_id\n      AND uc.tenant_org_id = _tenant_org_id\n      AND uc.is_test_account = true\n  ) THEN\n    RETURN QUERY SELECT false, NULL::timestamptz, NULL::uuid, NULL::text, NULL::text, NULL::jsonb;\n    RETURN;\n  END IF;\n\n  RETURN QUERY\n  SELECT\n    COALESCE(ce.result = 'bypass_enabled', false) AS active,\n    ce.checked_at,\n    ce.checked_by,\n    ce.reason,\n    ce.phone_number,\n    ce.raw_response\n  FROM public.communication_compliance_events ce\n  WHERE ce.tenant_org_id = _tenant_org_id\n    AND ce.lead_id = _contact_id::text\n    AND ce.check_type = 'owner_bypass'\n  ORDER BY ce.checked_at DESC\n  LIMIT 1;\n\n  IF NOT FOUND THEN\n    RETURN QUERY SELECT false, NULL::timestamptz, NULL::uuid, NULL::text, NULL::text, NULL::jsonb;\n  END IF;\nEND;\n$function$\n","identity_arguments":"_tenant_org_id text, _contact_id uuid"},{"name":"get_current_user_workspace_bootstrap","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_current_user_workspace_bootstrap()\n RETURNS jsonb\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nwith caller as (\n  select auth.uid() as user_id\n), authority as (\n  select c.user_id, coalesce(public.is_system_admin(c.user_id), false) as platform_admin\n  from caller c\n), visible_tenants as (\n  select t.*\n  from public.tenants t\n  cross join authority a\n  where a.user_id is not null\n    and t.status = 'active'\n    and (\n      a.platform_admin\n      or exists (\n        select 1 from public.user_tenant_memberships m\n        where m.user_id = a.user_id\n          and m.tenant_id = t.id\n          and m.status = 'active'\n      )\n      or exists (\n        select 1 from public.user_roles r\n        where r.user_id = a.user_id\n          and r.tenant_id = t.id\n      )\n    )\n), access_rows as (\n  select\n    t.id as tenant_id,\n    jsonb_build_object(\n      'user_id', a.user_id,\n      'tenant_id', t.id,\n      'effective_role', coalesce(\n        role_row.role,\n        case when coalesce(membership_row.is_owner, false) then 'Tenant Owner' end,\n        case when a.platform_admin then 'GodMode' else 'Rep' end\n      ),\n      'is_owner', coalesce(membership_row.is_owner, false),\n      'membership_status', coalesce(membership_row.status, 'active')\n    ) as access_row\n  from visible_tenants t\n  cross join authority a\n  left join lateral (\n    select m.is_owner, m.status\n    from public.user_tenant_memberships m\n    where m.user_id = a.user_id and m.tenant_id = t.id\n    order by m.joined_at desc nulls last\n    limit 1\n  ) membership_row on true\n  left join lateral (\n    select r.role::text as role\n    from public.user_roles r\n    where r.user_id = a.user_id and r.tenant_id = t.id\n    order by case r.role::text\n      when 'Owner' then 1\n      when 'Tenant Owner' then 2\n      when 'Admin' then 3\n      when 'Manager' then 4\n      when 'PM' then 5\n      when 'Rep' then 6\n      else 20\n    end\n    limit 1\n  ) role_row on true\n), tenant_payload as (\n  select jsonb_set(\n    to_jsonb(vt),\n    '{settings}',\n    coalesce(vt.settings, '{}'::jsonb)\n      - 'logo_ingest_b64'\n      - 'tenant_creation_compiler'\n      - 'tenant_readiness'\n      - 'onboarding_contract'\n      - 'messenger_profile'\n      - 'storage_bootstrap',\n    true\n  ) as tenant_row\n  from visible_tenants vt\n)\nselect jsonb_build_object(\n  'user_id', a.user_id,\n  'platform_admin', a.platform_admin,\n  'access', coalesce((select jsonb_agg(ar.access_row order by ar.tenant_id) from access_rows ar), '[]'::jsonb),\n  'tenants', coalesce((select jsonb_agg(tp.tenant_row order by tp.tenant_row->>'company_slug' nulls last, tp.tenant_row->>'name') from tenant_payload tp), '[]'::jsonb)\n)\nfrom authority a;\n$function$\n","identity_arguments":""},{"name":"get_doors_in_territory","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_doors_in_territory(p_territory_id uuid)\n RETURNS SETOF door_objects\n LANGUAGE plpgsql\n STABLE\n SET search_path TO 'public'\nAS $function$\nDECLARE v_polygon JSONB;\nBEGIN\n  SELECT polygon_geojson INTO v_polygon FROM territories WHERE id = p_territory_id;\n  RETURN QUERY SELECT d.* FROM door_objects d\n  WHERE d.territory_id = p_territory_id OR ST_Contains(ST_GeomFromGeoJSON(v_polygon::text), ST_MakePoint(d.lng, d.lat));\nEND;\n$function$\n","identity_arguments":"p_territory_id uuid"},{"name":"get_doors_near_point","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_doors_near_point(p_lat double precision, p_lng double precision, p_radius_miles double precision, p_tenant_org_id text)\n RETURNS SETOF door_objects\n LANGUAGE sql\n STABLE\n SET search_path TO 'public', 'extensions'\nAS $function$\n  SELECT * FROM door_objects WHERE tenant_org_id = p_tenant_org_id\n    AND extensions.earth_distance(extensions.ll_to_earth(lat, lng), extensions.ll_to_earth(p_lat, p_lng)) <= (p_radius_miles * 1609.34)\n  ORDER BY extensions.earth_distance(extensions.ll_to_earth(lat, lng), extensions.ll_to_earth(p_lat, p_lng));\n$function$\n","identity_arguments":"p_lat double precision, p_lng double precision, p_radius_miles double precision, p_tenant_org_id text"},{"name":"get_jobs_package_readiness","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_jobs_package_readiness(_job_id uuid)\n RETURNS TABLE(job_id uuid, tenant_id uuid, contact_claim_id uuid, job_status text, verified_at timestamp with time zone, work_auth_signed boolean, photos_uploaded boolean, docs_complete boolean, invoice_present boolean, carrier_present boolean, policy_present boolean, claim_present boolean, contact_present boolean, package_ready boolean, claim_payment_status claim_payment_lifecycle_v4)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_tenant uuid;\n  v_can_view boolean;\nBEGIN\n  IF auth.uid() IS NULL THEN\n    RAISE EXCEPTION 'unauthenticated' USING ERRCODE='42501';\n  END IF;\n  SELECT j.tenant_id INTO v_tenant FROM public.jobs j WHERE j.id = _job_id;\n  IF v_tenant IS NULL THEN RAISE EXCEPTION 'job not found' USING ERRCODE='02000'; END IF;\n  IF NOT public.is_tenant_member(auth.uid(), v_tenant) AND NOT public.is_system_admin(auth.uid()) THEN\n    RAISE EXCEPTION 'cross-tenant job access denied' USING ERRCODE='42501';\n  END IF;\n  v_can_view := public._can_view_claim_payment_status(v_tenant);\n  RETURN QUERY\n    SELECT\n      j.id, j.tenant_id, j.contact_claim_id, j.status::text, j.verified_at,\n      j.work_auth_signed, j.photos_uploaded, j.docs_complete,\n      (j.tarping_invoice_id IS NOT NULL),\n      (COALESCE(j.carrier_name,'')<>''),\n      (COALESCE(j.policy_number,'')<>''),\n      (COALESCE(j.claim_number,'')<>''),\n      (COALESCE(j.property_address,'')<>'' AND COALESCE(j.customer_name,'')<>''),\n      (j.work_auth_signed AND j.photos_uploaded AND j.docs_complete\n        AND j.verified_at IS NOT NULL AND j.tarping_invoice_id IS NOT NULL\n        AND COALESCE(j.carrier_name,'')<>'' AND COALESCE(j.policy_number,'')<>''\n        AND COALESCE(j.claim_number,'')<>''),\n      CASE WHEN v_can_view AND j.contact_claim_id IS NOT NULL\n        THEN (SELECT cc.claim_payment_status FROM public.contact_claims cc WHERE cc.id = j.contact_claim_id)\n        ELSE NULL\n      END\n    FROM public.jobs j WHERE j.id = _job_id;\nEND;\n$function$\n","identity_arguments":"_job_id uuid"},{"name":"get_knocklaunch_platform_zoho_mail_credentials","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_knocklaunch_platform_zoho_mail_credentials()\n RETURNS TABLE(client_id text, client_secret text)\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\n  select\n    max(case when name = 'knocklaunch_platform_zoho_mail_client_id' then decrypted_secret end)::text as client_id,\n    max(case when name = 'knocklaunch_platform_zoho_mail_client_secret' then decrypted_secret end)::text as client_secret\n  from vault.decrypted_secrets\n  where name in ('knocklaunch_platform_zoho_mail_client_id', 'knocklaunch_platform_zoho_mail_client_secret');\n$function$\n","identity_arguments":""},{"name":"get_last_dnc_scrub","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_last_dnc_scrub(_tenant_id uuid DEFAULT NULL::uuid)\n RETURNS TABLE(last_run_at timestamp with time zone, days_since integer, is_overdue boolean, is_warning boolean, last_batch_id text, last_run_id uuid)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF _tenant_id IS NULL THEN\n    IF coalesce(auth.role(), '') <> 'service_role'\n       AND (auth.uid() IS NULL OR NOT coalesce(public.is_system_admin(auth.uid()), false)) THEN\n      RAISE EXCEPTION 'platform DNC status access denied' USING ERRCODE = '42501';\n    END IF;\n  ELSIF coalesce(auth.role(), '') <> 'service_role'\n        AND (\n          auth.uid() IS NULL\n          OR (\n            NOT coalesce(public.is_system_admin(auth.uid()), false)\n            AND NOT coalesce(public.is_tenant_member(auth.uid(), _tenant_id), false)\n          )\n        ) THEN\n    RAISE EXCEPTION 'tenant DNC status access denied' USING ERRCODE = '42501';\n  END IF;\n\n  RETURN QUERY\n  WITH latest AS (\n    SELECT id, batch_id, created_at\n    FROM public.dnc_scrub_runs\n    WHERE (_tenant_id IS NULL AND scope = 'platform')\n       OR (_tenant_id IS NOT NULL AND (tenant_id = _tenant_id OR scope = 'platform'))\n    ORDER BY created_at DESC\n    LIMIT 1\n  )\n  SELECT l.created_at,\n         coalesce(extract(day from (now() - l.created_at))::integer, 999),\n         coalesce(extract(day from (now() - l.created_at))::integer, 999) >= 31,\n         coalesce(extract(day from (now() - l.created_at))::integer, 999) BETWEEN 25 AND 30,\n         l.batch_id, l.id\n  FROM latest l\n  UNION ALL\n  SELECT NULL::timestamptz, 999, true, false, NULL::text, NULL::uuid\n  WHERE NOT EXISTS (SELECT 1 FROM latest)\n  LIMIT 1;\nEND;\n$function$\n","identity_arguments":"_tenant_id uuid"},{"name":"get_lead_last_call","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_lead_last_call(p_tenant_org_id text, p_lead_id uuid)\n RETURNS TABLE(last_call_at timestamp with time zone, last_outcome text, last_disposition text)\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  SELECT ce.created_at, ce.outcome, ce.disposition\n  FROM public.communication_events ce\n  WHERE public.is_tenant_member(p_tenant_org_id)\n    AND ce.tenant_org_id = p_tenant_org_id\n    AND ce.lead_id = p_lead_id\n    AND ce.event_type IN ('call_completed','call_ended_by_rep','outbound_call','call_no_answer','call_busy')\n  ORDER BY ce.created_at DESC\n  LIMIT 1;\n$function$\n","identity_arguments":"p_tenant_org_id text, p_lead_id uuid"},{"name":"get_lead_timeline","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_lead_timeline(_lead_id text, _limit integer DEFAULT 200)\n RETURNS SETOF lead_timeline\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  SELECT t.*\n  FROM public.lead_timeline t\n  WHERE t.lead_id = _lead_id\n    AND t.tenant_org_id IS NOT NULL\n    AND public.is_tenant_member(auth.uid(), t.tenant_org_id)\n  ORDER BY t.occurred_at DESC\n  LIMIT _limit\n$function$\n","identity_arguments":"_lead_id text, _limit integer"},{"name":"get_live_edit_sidekick_session","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_live_edit_sidekick_session(_session_id uuid, _context_tenant_id uuid, _route text)\n RETURNS TABLE(session_id uuid, created_at timestamp with time zone, updated_at timestamp with time zone, turns jsonb)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_route text := left(trim(coalesce(_route, '')), 240);\nbegin\n  if auth.uid() is null or not public.can_use_live_edit_sidekick_memory(auth.uid(), _context_tenant_id) then\n    raise exception 'Live Edit Sidekick memory access denied' using errcode = '42501';\n  end if;\n\n  return query\n  select\n    e.id,\n    e.created_at,\n    e.updated_at,\n    coalesce((\n      select jsonb_agg(\n        jsonb_build_object(\n          'id', cm.id,\n          'created_at', cm.created_at,\n          'raw_message', cm.message\n        )\n        order by cm.created_at asc\n      )\n      from public.command_center_messages cm\n      where cm.command_center_event_id = e.id\n        and cm.sender_user_id = auth.uid()\n    ), '[]'::jsonb)\n  from public.command_center_events e\n  where e.id = _session_id\n    and e.event_type = 'sidekick_conversation_log'\n    and e.created_by_user_id = auth.uid()\n    and coalesce(e.mission_context->>'sidekick_surface', '') = 'live-edit'\n    and coalesce(e.mission_context->>'context_tenant_id', '') = _context_tenant_id::text\n    and coalesce(e.mission_context->>'last_route', '') = v_route\n  limit 1;\nend;\n$function$\n","identity_arguments":"_session_id uuid, _context_tenant_id uuid, _route text"},{"name":"get_my_onboarding_context","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_my_onboarding_context(p_session_id uuid DEFAULT NULL::uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_uid uuid := auth.uid();\n  s public.onboarding_sessions%rowtype;\n  v_research jsonb := '[]'::jsonb;\n  v_next text;\nbegin\n  if v_uid is null then raise exception 'Authentication required' using errcode='42501'; end if;\n\n  if p_session_id is null then\n    select * into s\n    from public.onboarding_sessions\n    where owner_user_id=v_uid\n    order by updated_at desc\n    limit 1;\n  else\n    select * into s\n    from public.onboarding_sessions\n    where id=p_session_id and (owner_user_id=v_uid or public.is_system_admin(v_uid));\n  end if;\n\n  if not found then\n    return jsonb_build_object('ok',true,'session',null,'research','[]'::jsonb,'next_step','start');\n  end if;\n\n  select coalesce(jsonb_agg(jsonb_build_object(\n      'type',t.research_type,\n      'jurisdiction',t.jurisdiction,\n      'status',t.status,\n      'result',t.result,\n      'source_url',t.source_url,\n      'verified_at',t.verified_at,\n      'message',t.last_error\n    ) order by t.created_at),'[]'::jsonb)\n  into v_research\n  from public.onboarding_research_tasks t\n  where t.session_id=s.id;\n\n  v_next := case\n    when s.status in ('draft','intake','needs_input') then 'answer_unresolved'\n    when s.status in ('researching','validating') then 'reviewing'\n    when s.status='ready_to_provision' then 'review_and_provision'\n    when s.status='provisioning' then 'provisioning'\n    when s.status in ('ready','live') then 'enter_knocklaunch'\n    when s.status='failed' then 'retry'\n    else 'continue'\n  end;\n\n  return jsonb_build_object(\n    'ok',true,\n    'session',to_jsonb(s),\n    'review',jsonb_build_object(\n      'company_name',s.company_name,\n      'business_type',s.canonical_tenant_type,\n      'service_lines',s.service_lines,\n      'operating_states',to_jsonb(s.operating_states),\n      'service_area',s.service_area,\n      'team_size',s.team_size,\n      'blueprint',s.derived_blueprint\n    ),\n    'research',v_research,\n    'unresolved',coalesce(s.readiness->'missing','[]'::jsonb),\n    'next_step',v_next\n  );\nend;\n$function$\n","identity_arguments":"p_session_id uuid"},{"name":"get_next_lead","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_next_lead(p_user_id uuid, p_tenant_id uuid)\n RETURNS TABLE(lead_id text, name text, phone text, email text, address text, city text, state text, zip text, status text, priority text, source text, assigned_to text, notes text)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_caller uuid := auth.uid();\n  v_user_id_text text := p_user_id::text;\n  v_tenant_id_text text := p_tenant_id::text;\n  v_user_email text;\n  v_system_admin boolean := false;\nBEGIN\n  IF v_caller IS NULL THEN\n    RAISE EXCEPTION 'not_authenticated' USING ERRCODE = '42501';\n  END IF;\n  IF p_user_id IS NULL OR p_tenant_id IS NULL THEN\n    RAISE EXCEPTION 'user_and_tenant_required' USING ERRCODE = '22023';\n  END IF;\n  IF NOT public.is_tenant_member(v_caller, p_tenant_id) THEN\n    RAISE EXCEPTION 'tenant_access_denied' USING ERRCODE = '42501';\n  END IF;\n  IF v_caller <> p_user_id AND NOT public.is_manager_or_higher(v_caller, p_tenant_id) THEN\n    RAISE EXCEPTION 'user_scope_denied' USING ERRCODE = '42501';\n  END IF;\n\n  v_system_admin := public.is_system_admin(v_caller);\n  SELECT p.email INTO v_user_email FROM public.profiles p WHERE p.id = p_user_id LIMIT 1;\n\n  RETURN QUERY\n  SELECT\n    ld.lead_id::text,\n    ld.name,\n    ld.phone,\n    ld.email,\n    ld.address,\n    ld.city,\n    ld.state,\n    ld.zip,\n    ld.status,\n    ld.priority,\n    ld.source,\n    ld.assigned_to,\n    ld.notes\n  FROM public.lead_deck ld\n  WHERE ld.deleted_at IS NULL\n    AND (ld.status IS NULL OR ld.status NOT IN ('Completed','Closed','Lost'))\n    AND (\n      (v_system_admin AND ld.tenant_org_id IS NULL AND (ld.assigned_to IS NULL OR ld.assigned_to = ''))\n      OR\n      (\n        ld.tenant_org_id = v_tenant_id_text\n        AND (\n          ld.assigned_to IS NULL\n          OR ld.assigned_to = ''\n          OR ld.assigned_to = v_user_id_text\n          OR lower(ld.assigned_to) = lower(v_user_email)\n        )\n      )\n    )\n  ORDER BY\n    CASE WHEN ld.tenant_org_id = v_tenant_id_text AND (ld.assigned_to IS NULL OR ld.assigned_to = '') THEN 0 ELSE 1 END,\n    random()\n  LIMIT 1;\nEND;\n$function$\n","identity_arguments":"p_user_id uuid, p_tenant_id uuid"},{"name":"get_owner_dashboard_stats","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_owner_dashboard_stats(p_tenant_id text)\n RETURNS jsonb\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  SELECT jsonb_build_object(\n    'total', COUNT(*),\n    'missing_address', COUNT(*) FILTER (WHERE address IS NULL OR trim(address) = ''),\n    'missing_city', COUNT(*) FILTER (WHERE city IS NULL OR trim(city) = ''),\n    'missing_zip', COUNT(*) FILTER (WHERE zip IS NULL OR trim(zip) = ''),\n    'missing_phone', COUNT(*) FILTER (WHERE phone IS NULL OR trim(phone) = ''),\n    'missing_email', COUNT(*) FILTER (WHERE email IS NULL OR trim(email) = ''),\n    'with_address', COUNT(*) FILTER (WHERE address IS NOT NULL AND trim(address) <> ''),\n    'with_property_data', COUNT(*) FILTER (WHERE property_owner_name IS NOT NULL OR property_square_feet IS NOT NULL),\n    'with_roof_year', COUNT(*) FILTER (WHERE property_data->>'lastRoofPermitYear' IS NOT NULL OR property_data->>'roofPermitYear' IS NOT NULL OR property_data->>'last_roof_permit_year' IS NOT NULL),\n    'needs_enrichment', COUNT(*) FILTER (WHERE address IS NOT NULL AND trim(address) <> '' AND property_owner_name IS NULL AND property_square_feet IS NULL)\n  )\n  FROM public.unified_contacts\n  WHERE public.is_tenant_member(p_tenant_id)\n    AND tenant_org_id = p_tenant_id\n    AND deleted_at IS NULL;\n$function$\n","identity_arguments":"p_tenant_id text"},{"name":"get_owner_setup_status","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_owner_setup_status()\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_tenant_id UUID; v_google BOOLEAN := FALSE; v_roles_done BOOLEAN := FALSE; v_team_done BOOLEAN := FALSE; v_scripts_done BOOLEAN := FALSE; v_zones_done BOOLEAN := FALSE; v_tenant_type TEXT; v_canonical_type TEXT; v_result JSONB;\nBEGIN\n  SELECT tenant_org_id INTO v_tenant_id FROM public.profiles WHERE id = auth.uid();\n  SELECT EXISTS(SELECT 1 FROM public.google_integrations WHERE user_id = auth.uid() AND status = 'connected') INTO v_google;\n  SELECT EXISTS(SELECT 1 FROM public.user_roles WHERE tenant_id = v_tenant_id AND role NOT IN ('GodMode','Admin')) INTO v_roles_done;\n  SELECT (COUNT(*) > 1) INTO v_team_done FROM public.profiles p WHERE p.tenant_org_id = v_tenant_id AND p.active = true;\n  SELECT t.tenant_type INTO v_tenant_type FROM public.tenant_organizations t WHERE t.id = v_tenant_id;\n  v_canonical_type := public.canonical_tenant_type(v_tenant_type);\n  IF v_canonical_type IS NOT NULL THEN\n    SELECT EXISTS(SELECT 1 FROM public.rebuttal_scripts rs WHERE rs.tenant_id = v_tenant_id AND rs.script_type = ('workflow_flowcards_' || v_canonical_type) AND rs.active = true) INTO v_scripts_done;\n  ELSE v_scripts_done := FALSE; END IF;\n  SELECT EXISTS(SELECT 1 FROM public.sales_zones sz WHERE sz.tenant_id = v_tenant_id AND sz.active = true) INTO v_zones_done;\n  v_result := jsonb_build_object('google_connected', v_google,'roles_configured', v_roles_done,'team_added', v_team_done,'workflow_scripts', v_scripts_done,'sales_zones', v_zones_done,'all_complete', (v_google AND v_roles_done AND v_team_done AND v_scripts_done AND v_zones_done));\n  RETURN v_result;\nEND;\n$function$\n","identity_arguments":""},{"name":"get_owner_setup_status","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_owner_setup_status(p_tenant_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_tenant_type text;\n  v_team_done boolean;\n  v_areas_done boolean;\n  v_pipelines_done boolean;\n  v_scripts_done boolean;\n  v_import_done boolean;\n  v_storms_done boolean;\nBEGIN\n  IF NOT public.is_tenant_member(p_tenant_id) AND NOT public.is_system_admin() THEN\n    RAISE EXCEPTION 'Access denied to tenant %', p_tenant_id;\n  END IF;\n\n  SELECT tenant_type INTO v_tenant_type\n  FROM public.tenant_organizations\n  WHERE id = p_tenant_id;\n\n  v_team_done := (\n    SELECT COUNT(*) > 1 FROM public.user_roles WHERE tenant_id = p_tenant_id\n  );\n\n  v_areas_done := (\n    SELECT COUNT(*) > 0 FROM public.tenant_service_areas WHERE tenant_org_id = p_tenant_id\n  );\n\n  v_pipelines_done := (\n    SELECT COUNT(*) > 3 FROM public.pipeline_stages\n    WHERE tenant_org_id = p_tenant_id AND is_active = true\n  );\n\n  v_scripts_done := (\n    SELECT EXISTS (\n      SELECT 1 FROM public.site_config\n      WHERE config_key = 'workflow_flowcards_' || COALESCE(v_tenant_type, 'MITIGATION')\n        AND tenant_org_id = p_tenant_id\n        AND config_value IS NOT NULL\n    )\n  );\n\n  v_import_done := (\n    SELECT COUNT(*) > 0 FROM public.unified_contacts\n    WHERE tenant_org_id = p_tenant_id AND deleted_at IS NULL\n  );\n\n  v_storms_done := (\n    SELECT COUNT(*) > 0 FROM public.storm_events WHERE tenant_org_id = p_tenant_id\n  );\n\n  RETURN jsonb_build_object(\n    'team', v_team_done,\n    'service-areas', v_areas_done,\n    'pipelines', v_pipelines_done,\n    'scripts', v_scripts_done,\n    'import', v_import_done,\n    'storms', v_storms_done\n  );\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"get_partner_tenant_ids","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_partner_tenant_ids()\n RETURNS SETOF uuid\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  SELECT DISTINCT uc.tenant_org_id::uuid\n  FROM public.contact_links cl\n  JOIN public.unified_contacts uc ON cl.contact_id = uc.id\n  WHERE cl.link_group_id IN (\n    SELECT DISTINCT cl2.link_group_id\n    FROM public.contact_links cl2\n    JOIN public.unified_contacts uc2 ON cl2.contact_id = uc2.id\n    WHERE uc2.tenant_org_id::uuid IN (\n      SELECT m.tenant_id\n      FROM public.user_tenant_memberships m\n      WHERE m.user_id = auth.uid() AND m.status = 'active'\n    )\n  );\n$function$\n","identity_arguments":""},{"name":"get_profile_role","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_profile_role(_user_id uuid)\n RETURNS text\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  SELECT p.role\n  FROM public.profiles p\n  WHERE p.id = _user_id\n    AND (\n      coalesce(auth.role(), '') = 'service_role'\n      OR auth.uid() = _user_id\n      OR public.is_system_admin(auth.uid())\n      OR public.shares_tenant_as_manager_pm(auth.uid(), _user_id)\n    );\n$function$\n","identity_arguments":"_user_id uuid"},{"name":"get_profile_tenant_org_id","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_profile_tenant_org_id(_user_id uuid)\n RETURNS text\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  SELECT p.tenant_org_id\n  FROM public.profiles p\n  WHERE p.id = _user_id\n    AND (\n      coalesce(auth.role(), '') = 'service_role'\n      OR auth.uid() = _user_id\n      OR public.is_system_admin(auth.uid())\n      OR public.shares_tenant_as_manager_pm(auth.uid(), _user_id)\n    );\n$function$\n","identity_arguments":"_user_id uuid"},{"name":"get_public_321_auto_unlock_brand","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_public_321_auto_unlock_brand()\n RETURNS TABLE(name text, logo_url text, company_phone text, company_email text, video_url text)\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select\n    coalesce(nullif(btrim(t.name), ''), '321 Auto Unlock')::text as name,\n    coalesce(\n      nullif(btrim(t.company_logo_url), ''),\n      case\n        when nullif(btrim(t.settings ->> 'logo_ingest_b64'), '') is not null\n          then 'data:' || coalesce(nullif(btrim(t.settings ->> 'logo_ingest_mime'), ''), 'image/webp') || ';base64,' || (t.settings ->> 'logo_ingest_b64')\n        else null\n      end\n    )::text as logo_url,\n    nullif(btrim(t.company_phone), '')::text as company_phone,\n    nullif(btrim(t.company_email), '')::text as company_email,\n    (\n      select 'https://ymntrajfubicyxwwdxxa.supabase.co/functions/v1/tenant-media-library?mode=asset&id=' || a.id::text\n      from public.tenant_media_assets a\n      where a.tenant_id = t.id\n        and a.deleted_at is null\n        and a.status = 'ready'\n        and a.published = true\n        and a.review_status = 'approved'\n        and lower(a.mime_type) like 'video/%'\n      order by a.is_primary desc, a.created_at desc\n      limit 1\n    )::text as video_url\n  from public.tenants t\n  where t.id = 'd60e3c27-73ed-4a5f-a49b-c37636455daf'::uuid\n    and coalesce(t.status, 'active') = 'active'\n  limit 1;\n$function$\n","identity_arguments":""},{"name":"get_public_book_me_directly_profile","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_public_book_me_directly_profile(p_company_slug text)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant public.tenants%rowtype;\n  v_settings jsonb;\n  v_services_source jsonb := '[]'::jsonb;\n  v_services jsonb := '[]'::jsonb;\n  v_enabled boolean := true;\n  v_address text;\nbegin\n  if nullif(trim(p_company_slug),'') is null then return null; end if;\n  select * into v_tenant\n  from public.tenants\n  where lower(company_slug)=lower(trim(p_company_slug))\n    and coalesce(is_active,true)=true\n    and coalesce(status,'active')='active'\n  limit 1;\n  if not found then return null; end if;\n\n  v_settings := coalesce(v_tenant.settings,'{}'::jsonb);\n  v_enabled := lower(coalesce(v_settings->>'book_me_directly_enabled',v_settings#>>'{customer_channels,book_me_directly,enabled}','true')) not in ('false','0','off','no');\n  v_services_source := coalesce(v_settings->'services',v_settings#>'{business_operating_blueprint,services}',v_settings#>'{tenant_manifest,services}','[]'::jsonb);\n  if jsonb_typeof(v_services_source)='array' then\n    select coalesce(jsonb_agg(label order by ord),'[]'::jsonb)\n      into v_services\n    from (\n      select ord,\n        case when jsonb_typeof(value)='string'\n          then nullif(value #>> '{}','')\n          else coalesce(nullif(value->>'name',''),nullif(value->>'label',''),nullif(value->>'title',''))\n        end as label\n      from jsonb_array_elements(v_services_source) with ordinality as source(value,ord)\n      where ord<=8\n    ) labels\n    where label is not null and label<>'';\n  end if;\n\n  v_address := coalesce(\n    nullif(v_settings->>'public_address',''),\n    nullif(v_settings->>'address',''),\n    nullif(v_tenant.company_address,''),\n    nullif(concat_ws(', ',nullif(v_tenant.company_city,''),nullif(v_tenant.company_state,''),nullif(v_tenant.company_zip,'')),'')\n  );\n\n  return jsonb_build_object(\n    'company_slug',v_tenant.company_slug,\n    'tenant_type',v_tenant.tenant_type,\n    'name',coalesce(nullif(v_tenant.company_dba_name,''),nullif(v_tenant.company_legal_name,''),nullif(v_tenant.name,''),v_tenant.company_slug),\n    'logo_url',nullif(v_tenant.company_logo_url,''),\n    'background_url',coalesce(nullif(v_settings->>'public_background_url',''),nullif(v_settings->>'workspace_background_url',''),nullif(v_settings->>'background_url','')),\n    'phone',coalesce(nullif(v_settings->>'public_phone',''),nullif(v_settings->>'phone',''),nullif(v_tenant.company_phone,'')),\n    'email',coalesce(nullif(v_settings->>'public_email',''),nullif(v_settings->>'email',''),nullif(v_tenant.company_email,'')),\n    'website',coalesce(nullif(v_settings->>'website',''),nullif(v_settings->>'website_url',''),nullif(v_tenant.company_website,'')),\n    'booking_url',coalesce(nullif(v_settings->>'booking_url',''),nullif(v_settings->>'public_booking_url',''),nullif(v_settings->>'book_url','')),\n    'address',v_address,\n    'instagram_url',coalesce(nullif(v_settings#>>'{socials,instagram}',''),nullif(v_settings#>>'{social_links,instagram}',''),nullif(v_settings#>>'{social,instagram}',''),nullif(v_settings->>'instagram_url',''),nullif(v_settings->>'instagram','')),\n    'facebook_url',coalesce(nullif(v_settings#>>'{socials,facebook}',''),nullif(v_settings#>>'{social_links,facebook}',''),nullif(v_settings#>>'{social,facebook}',''),nullif(v_settings->>'facebook_url',''),nullif(v_settings->>'facebook','')),\n    'primary_label',coalesce(nullif(v_settings->>'book_me_directly_primary_label',''),nullif(v_settings->>'booking_cta_label',''),'Book or request service'),\n    'services',v_services,\n    'enabled',v_enabled\n  );\nend;\n$function$\n","identity_arguments":"p_company_slug text"},{"name":"get_public_book_me_directly_profile_v2","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_public_book_me_directly_profile_v2(p_company_slug text)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_profile jsonb;\n  v_settings jsonb := '{}'::jsonb;\n  v_buffer_minutes integer := 0;\n  v_service_area_label text;\n  v_policy_summary text;\n  v_terms_version text;\nbegin\n  v_profile := public.get_public_book_me_directly_profile(p_company_slug);\n  if v_profile is null then return null; end if;\n\n  select coalesce(settings,'{}'::jsonb)\n    into v_settings\n  from public.tenants\n  where lower(company_slug)=lower(trim(p_company_slug))\n    and coalesce(is_active,true)=true\n    and coalesce(status,'active')='active'\n  limit 1;\n\n  if coalesce(v_settings#>>'{book_me_directly,event_rental_buffer_minutes}','') ~ '^[0-9]{1,4}$' then\n    v_buffer_minutes := least(greatest((v_settings#>>'{book_me_directly,event_rental_buffer_minutes}')::integer,0),1440);\n  end if;\n\n  v_service_area_label := coalesce(\n    nullif(v_settings#>>'{book_me_directly,service_area_label}',''),\n    nullif(v_settings->>'public_service_area',''),\n    nullif(v_settings#>>'{service_area,label}','')\n  );\n  v_policy_summary := coalesce(\n    nullif(v_settings#>>'{book_me_directly,policy_summary}',''),\n    'Booking requests are not reservations. Availability, delivery/setup, pricing, site conditions, weather, and final terms are confirmed before equipment is reserved.'\n  );\n  v_terms_version := coalesce(\n    nullif(v_settings#>>'{book_me_directly,terms_version}',''),\n    'event-rental-v1'\n  );\n\n  return v_profile || jsonb_build_object(\n    'service_area_label',v_service_area_label,\n    'event_rental_buffer_minutes',v_buffer_minutes,\n    'booking_policy_summary',v_policy_summary,\n    'booking_terms_version',v_terms_version\n  );\nend;\n$function$\n","identity_arguments":"p_company_slug text"},{"name":"get_public_event_rental_assets","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_public_event_rental_assets(p_tenant_slug text)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant record;\n  v_assets jsonb := '[]'::jsonb;\nbegin\n  if nullif(trim(p_tenant_slug),'') is null then return '[]'::jsonb; end if;\n  select id,tenant_type,settings,is_active,status into v_tenant\n  from public.tenants\n  where lower(company_slug)=lower(trim(p_tenant_slug))\n  limit 1;\n\n  if v_tenant.id is null\n    or coalesce(v_tenant.is_active,false) is not true\n    or coalesce(v_tenant.status,'') <> 'active'\n    or upper(replace(replace(coalesce(v_tenant.tenant_type,''),'-','_'),' ','_')) not in ('EVENT_RENTAL','EVENT_RENTALS','PARTY_RENTAL','PARTY_RENTALS')\n    or coalesce(v_tenant.settings->'public_presence'->>'required','false')::boolean is not true\n  then\n    return '[]'::jsonb;\n  end if;\n\n  select coalesce(\n    jsonb_agg(\n      jsonb_build_object(\n        'id',a.id,\n        'name',coalesce(nullif(a.metadata->>'public_title',''),a.name),\n        'category',a.category,\n        'total_quantity',a.total_quantity,\n        'summary',coalesce(nullif(a.metadata->>'public_summary',''),nullif(a.description,'')),\n        'features',coalesce(a.metadata->'public_features','[]'::jsonb),\n        'safety_notice',coalesce(nullif(a.metadata#>>'{manufacturer_safety_notes,wind_notice}',''),nullif(a.metadata#>>'{manufacturer_safety_notes,local_fire_code_notice}',''))\n      )\n      order by a.category,a.name\n    ),\n    '[]'::jsonb\n  ) into v_assets\n  from public.event_rental_assets a\n  where a.tenant_id=v_tenant.id\n    and coalesce(a.lifecycle_status,'available') not in ('retired','deleted','unavailable')\n    and coalesce(a.total_quantity,0) > 0;\n\n  return v_assets;\nend;\n$function$\n","identity_arguments":"p_tenant_slug text"},{"name":"get_rep_call_velocity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_rep_call_velocity(p_rep_id uuid, p_tenant_org_id text)\n RETURNS TABLE(calls_today integer, connects_today integer, last_contact_at timestamp with time zone)\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    count(*) filter (\n      where event_type in ('call_initiated','outbound_call')\n        and created_at >= date_trunc('day',now() at time zone 'America/New_York')\n    )::int,\n    count(*) filter (\n      where event_type in ('call_completed','call_ended_by_rep','outbound_call')\n        and coalesce(duration_seconds,0)>=20\n        and created_at >= date_trunc('day',now() at time zone 'America/New_York')\n    )::int,\n    max(created_at) filter (\n      where event_type in ('call_completed','call_ended_by_rep','outbound_call')\n        and coalesce(duration_seconds,0)>=20\n    )\n  from public.communication_events\n  where\n    (\n      p_rep_id=auth.uid()\n      or public.is_system_admin(auth.uid())\n      or public.is_manager_or_higher(auth.uid(),public.try_cast_uuid(p_tenant_org_id))\n    )\n    and public.is_tenant_member(auth.uid(),public.try_cast_uuid(p_tenant_org_id))\n    and rep_id=p_rep_id\n    and tenant_org_id=p_tenant_org_id;\n$function$\n","identity_arguments":"p_rep_id uuid, p_tenant_org_id text"},{"name":"get_revenue_pipeline_summary","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_revenue_pipeline_summary(p_tenant_id uuid)\n RETURNS TABLE(stage text, count bigint, amount numeric)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nbegin\n  if not (\n    public.is_system_admin(auth.uid())\n    or public.is_tenant_owner(auth.uid(),p_tenant_id)\n  ) then\n    raise exception 'Owner access required' using errcode='42501';\n  end if;\n\n  return query\n  with contact_stage as (\n    select\n      c.id,\n      case\n        when c.graduated_at is null then 'new_leads'\n        when lower(coalesce(c.jobs_stage,c.claim_stage,'')) ~ 'complete|closed|paid' then 'completed'\n        when lower(coalesce(c.jobs_stage,c.claim_stage,'')) ~ 'sign|contract|approved' then 'signed'\n        else 'in_progress'\n      end as stage_key\n    from public.unified_contacts c\n    where c.tenant_org_id=p_tenant_id\n      and c.deleted_at is null\n  ),\n  claim_amounts as (\n    select\n      cc.contact_id,\n      sum(coalesce(cc.settlement_amount,cc.fee_amount,0)) as total_amount\n    from public.contact_claims cc\n    where cc.tenant_org_id=p_tenant_id\n    group by cc.contact_id\n  )\n  select\n    cs.stage_key::text,\n    count(*)::bigint,\n    coalesce(sum(ca.total_amount),0)::numeric\n  from contact_stage cs\n  left join claim_amounts ca on ca.contact_id=cs.id\n  group by cs.stage_key;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"get_rls_policies","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_rls_policies()\n RETURNS TABLE(schemaname text, tablename text, policyname text, permissive text, roles text[], cmd text, qual text, with_check text)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\nbegin\n  perform public.require_platform_operator();\n  return query\n    select p.schemaname::text, p.tablename::text, p.policyname::text,\n      p.permissive::text, p.roles::text[], p.cmd::text, p.qual::text,\n      p.with_check::text\n    from pg_catalog.pg_policies p\n    where p.schemaname = 'public'\n    order by p.tablename, p.policyname;\nend;\n$function$\n","identity_arguments":""},{"name":"get_table_columns","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_table_columns(p_table_name text)\n RETURNS TABLE(column_name text, data_type text, is_nullable text, column_default text)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\nbegin\n  perform public.require_platform_operator();\n  if not exists (\n    select 1\n    from pg_catalog.pg_class c\n    join pg_catalog.pg_namespace n on n.oid = c.relnamespace\n    where n.nspname = 'public'\n      and c.relname = p_table_name\n      and c.relkind in ('r', 'p', 'v', 'm')\n  ) then\n    raise exception 'unknown public relation' using errcode = '22023';\n  end if;\n\n  return query\n    select c.column_name::text, c.data_type::text, c.is_nullable::text,\n      c.column_default::text\n    from information_schema.columns c\n    where c.table_schema = 'public' and c.table_name = p_table_name\n    order by c.ordinal_position;\nend;\n$function$\n","identity_arguments":"p_table_name text"},{"name":"get_table_data","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_table_data(p_table_name text, p_limit_count integer DEFAULT 100)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_limit integer := greatest(1, least(coalesce(p_limit_count, 100), 500));\n  v_result jsonb;\nbegin\n  perform public.require_platform_operator();\n  if not exists (\n    select 1\n    from pg_catalog.pg_class c\n    join pg_catalog.pg_namespace n on n.oid = c.relnamespace\n    where n.nspname = 'public'\n      and c.relname = p_table_name\n      and c.relkind in ('r', 'p', 'v', 'm')\n  ) then\n    raise exception 'unknown public relation' using errcode = '22023';\n  end if;\n\n  execute format(\n    'select coalesce(jsonb_agg(to_jsonb(t)), ''[]''::jsonb)\n       from (select * from public.%I limit $1) t',\n    p_table_name\n  )\n  into v_result\n  using v_limit;\n\n  return coalesce(v_result, '[]'::jsonb);\nend;\n$function$\n","identity_arguments":"p_table_name text, p_limit_count integer"},{"name":"get_team_pipeline_summary","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_team_pipeline_summary(p_tenant_id uuid)\n RETURNS TABLE(user_id uuid, name text, email text, total_leads bigint, total_clients bigint, stale_count bigint, last_activity timestamp with time zone, stages jsonb)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  seven_days_ago timestamptz := now() - interval '7 days';\nbegin\n  if not (\n    public.is_system_admin(auth.uid())\n    or public.is_manager_or_higher(auth.uid(),p_tenant_id)\n  ) then\n    raise exception 'Manager access required' using errcode='42501';\n  end if;\n\n  return query\n  with assigned as (\n    select\n      c.assigned_to::uuid as uid,\n      c.lead_stage,\n      c.jobs_stage,\n      c.graduated_at,\n      c.updated_at\n    from public.unified_contacts c\n    where c.tenant_org_id=p_tenant_id\n      and c.deleted_at is null\n      and c.assigned_to is not null\n      and c.assigned_to ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'\n  ),\n  per_rep as (\n    select\n      a.uid,\n      count(*) filter (where a.graduated_at is null)::bigint as total_leads,\n      count(*) filter (where a.graduated_at is not null)::bigint as total_clients,\n      count(*) filter (where a.updated_at < seven_days_ago and a.graduated_at is null)::bigint as stale_count,\n      max(a.updated_at) as last_activity,\n      jsonb_object_agg(\n        coalesce(case when a.graduated_at is not null then a.jobs_stage else a.lead_stage end,'No Stage'),\n        cnt\n      ) as stages\n    from (\n      select\n        uid,lead_stage,jobs_stage,graduated_at,updated_at,\n        count(*) over (\n          partition by uid,\n          coalesce(case when graduated_at is not null then jobs_stage else lead_stage end,'No Stage')\n        ) as cnt\n      from assigned\n    ) a\n    group by a.uid\n  )\n  select\n    pr.uid,\n    coalesce(p.name,split_part(p.email,'@',1),'Unknown')::text,\n    coalesce(p.email,'')::text,\n    pr.total_leads,\n    pr.total_clients,\n    pr.stale_count,\n    pr.last_activity,\n    pr.stages\n  from per_rep pr\n  left join public.profiles p on p.id=pr.uid\n  order by (pr.total_leads+pr.total_clients) desc;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"get_user_link_group_ids","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_user_link_group_ids()\n RETURNS SETOF uuid\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  SELECT DISTINCT cl.link_group_id\n  FROM public.contact_links cl\n  JOIN public.unified_contacts uc ON cl.contact_id = uc.id\n  WHERE uc.tenant_org_id::uuid IN (\n    SELECT m.tenant_id\n    FROM public.user_tenant_memberships m\n    WHERE m.user_id = auth.uid() AND m.status = 'active'\n  );\n$function$\n","identity_arguments":""},{"name":"get_user_pending_agreements","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_user_pending_agreements(p_user_id uuid, p_tenant_id uuid)\n RETURNS TABLE(template_id uuid, template_type text, template_name text, template_version integer, effective_date date, display_order integer, short_description text, reason text)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_caller uuid := auth.uid();\n  v_tenant_type text;\n  v_role text;\nBEGIN\n  IF v_caller IS NULL THEN RAISE EXCEPTION 'not_authenticated' USING ERRCODE='42501'; END IF;\n  IF v_caller <> p_user_id\n     AND NOT public.is_system_admin(v_caller)\n     AND NOT public.is_manager_or_higher(v_caller, p_tenant_id) THEN\n    RAISE EXCEPTION 'agreement_access_denied' USING ERRCODE='42501';\n  END IF;\n  IF NOT public.is_tenant_member(v_caller, p_tenant_id) AND NOT public.is_system_admin(v_caller) THEN\n    RAISE EXCEPTION 'tenant_access_denied' USING ERRCODE='42501';\n  END IF;\n\n  SELECT t.tenant_type INTO v_tenant_type FROM public.tenant_organizations t WHERE t.id=p_tenant_id;\n  SELECT ur.role::text INTO v_role\n  FROM public.user_roles ur\n  WHERE ur.user_id=p_user_id AND (ur.tenant_id=p_tenant_id OR ur.tenant_id IS NULL)\n  ORDER BY CASE ur.role::text WHEN 'GodMode' THEN 1 WHEN 'Admin' THEN 2 WHEN 'Owner' THEN 3 WHEN 'Tenant Owner' THEN 3 WHEN 'Manager' THEN 4 WHEN 'Rep' THEN 5 ELSE 9 END\n  LIMIT 1;\n\n  RETURN QUERY\n  WITH applicable_requirements AS (\n    SELECT DISTINCT ON (req.template_type) req.template_type, req.min_version, req.display_order\n    FROM public.agreement_requirements req\n    WHERE req.is_required=true\n      AND (req.tenant_id IS NULL OR req.tenant_id=p_tenant_id)\n      AND (req.tenant_type IS NULL OR req.tenant_type=v_tenant_type)\n      AND (req.role IS NULL OR req.role=v_role)\n    ORDER BY req.template_type, (req.tenant_id IS NOT NULL) DESC, req.min_version DESC\n  ), active_templates AS (\n    SELECT DISTINCT ON (t.template_type) t.id,t.template_type,t.template_name,t.version,t.effective_date,t.short_description,t.requires_reacceptance_on_bump\n    FROM public.agreement_templates t WHERE t.is_active=true ORDER BY t.template_type,t.version DESC\n  ), user_latest_signed AS (\n    SELECT DISTINCT ON (sa.agreement_type) sa.agreement_type AS template_type,sa.template_version_at_signing,sa.signed_at,sa.status\n    FROM public.signed_agreements sa\n    WHERE sa.user_id=p_user_id AND (sa.tenant_id=p_tenant_id OR sa.tenant_id IS NULL) AND sa.status='signed'\n    ORDER BY sa.agreement_type,sa.signed_at DESC\n  )\n  SELECT at.id,at.template_type,at.template_name,at.version,at.effective_date,coalesce(ar.display_order,100),at.short_description,\n    CASE WHEN uls.template_type IS NULL OR uls.template_version_at_signing IS NULL THEN 'never_signed'\n         WHEN uls.template_version_at_signing < at.version AND at.requires_reacceptance_on_bump THEN 'reacceptance_required'\n         WHEN uls.template_version_at_signing < ar.min_version THEN 'version_outdated'\n         ELSE NULL END\n  FROM applicable_requirements ar\n  JOIN active_templates at ON at.template_type=ar.template_type\n  LEFT JOIN user_latest_signed uls ON uls.template_type=ar.template_type\n  WHERE uls.template_type IS NULL OR uls.template_version_at_signing IS NULL OR uls.template_version_at_signing < ar.min_version OR (uls.template_version_at_signing < at.version AND at.requires_reacceptance_on_bump)\n  ORDER BY coalesce(ar.display_order,100),at.template_type;\nEND;\n$function$\n","identity_arguments":"p_user_id uuid, p_tenant_id uuid"},{"name":"get_user_tenant_org_id","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_user_tenant_org_id()\n RETURNS text\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  SELECT tenant_org_id FROM profiles WHERE id = auth.uid() LIMIT 1;\n$function$\n","identity_arguments":""},{"name":"get_zoho_mail_platform_credentials","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.get_zoho_mail_platform_credentials()\n RETURNS TABLE(client_id text, client_secret text)\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\n  select\n    max(case when name = 'knocklaunch_zoho_mail_client_id' then decrypted_secret end)::text as client_id,\n    max(case when name = 'knocklaunch_zoho_mail_client_secret' then decrypted_secret end)::text as client_secret\n  from vault.decrypted_secrets\n  where name in ('knocklaunch_zoho_mail_client_id', 'knocklaunch_zoho_mail_client_secret');\n$function$\n","identity_arguments":""},{"name":"guard_communication_setup_request_update","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.guard_communication_setup_request_update()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if public.is_system_admin() then\n    new.updated_at := now();\n    if new.status in ('connected', 'declined') and old.status is distinct from new.status then\n      new.resolved_at := coalesce(new.resolved_at, now());\n      new.resolved_by := coalesce(new.resolved_by, auth.uid());\n    end if;\n    return new;\n  end if;\n\n  if not public.is_tenant_member(auth.uid(), old.tenant_id) then\n    raise exception 'tenant access denied';\n  end if;\n  if old.status not in ('requested', 'needs_info') then\n    raise exception 'request is already being handled by KnockLaunch';\n  end if;\n  if new.tenant_id is distinct from old.tenant_id\n     or new.channel is distinct from old.channel\n     or new.status is distinct from old.status\n     or new.admin_notes is distinct from old.admin_notes\n     or new.resolved_by is distinct from old.resolved_by\n     or new.resolved_at is distinct from old.resolved_at\n     or new.requested_by is distinct from old.requested_by then\n    raise exception 'only request details can be changed by the tenant';\n  end if;\n\n  new.updated_at := now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"handle_call_designation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.handle_call_designation(p_tenant_id uuid, p_lead_id text, p_user_id uuid DEFAULT NULL::uuid, p_designation text DEFAULT 'NEW'::text, p_notes text DEFAULT NULL::text, p_appt_date text DEFAULT NULL::text, p_appt_time text DEFAULT NULL::text, p_assignee text DEFAULT NULL::text, p_phone_called text DEFAULT NULL::text, p_duration_seconds integer DEFAULT NULL::integer, p_metadata jsonb DEFAULT NULL::jsonb)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_user_id UUID;\n  v_caller_email TEXT;\n  v_status TEXT;\n  v_lead_stage TEXT;  -- NEW: Pre-pipeline stage mapping\n  v_call_outcome call_outcome;\n  v_followup_date DATE;\n  v_call_log_id UUID;\n  v_lead_name TEXT;\n  v_lead_address TEXT;\n  v_lead_city TEXT;\n  v_lead_state TEXT;\n  v_lead_zip TEXT;\n  v_lead_phone TEXT;\n  v_lead_email TEXT;\n  v_contact_id UUID;\n  v_should_delete BOOLEAN := false;\n  v_should_graduate BOOLEAN := false;  -- NEW: Graduation trigger\n  v_move_to_roof_queue BOOLEAN := false;\n  v_roof_queue_reason TEXT;\n  v_result JSONB;\nBEGIN\n  v_user_id := auth.uid();\n\n  IF v_user_id IS NULL THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'Authentication required');\n  END IF;\n\n  IF NOT public.is_tenant_member(v_user_id, p_tenant_id) THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'Tenant access denied');\n  END IF;\n\n  IF p_user_id IS NOT NULL AND p_user_id IS DISTINCT FROM v_user_id THEN\n    IF NOT public.is_manager_or_higher(v_user_id, p_tenant_id) OR NOT public.is_tenant_member(p_user_id, p_tenant_id) THEN\n      RETURN jsonb_build_object('ok', false, 'error', 'User scope denied');\n    END IF;\n    v_user_id := p_user_id;\n  END IF;\n\n  -- Get caller email\n  SELECT email INTO v_caller_email FROM auth.users WHERE id = v_user_id LIMIT 1;\n  IF v_caller_email IS NULL THEN\n    SELECT email INTO v_caller_email FROM profiles WHERE id = v_user_id LIMIT 1;\n  END IF;\n\n  -- Get lead details\n  SELECT name, address, city, state, zip, phone, email \n  INTO v_lead_name, v_lead_address, v_lead_city, v_lead_state, v_lead_zip, v_lead_phone, v_lead_email\n  FROM lead_deck WHERE lead_id = p_lead_id AND tenant_org_id = p_tenant_id::text LIMIT 1;\n\n  -- Map designation to BOTH status AND lead_stage (pre-pipeline stage)\n  CASE p_designation\n    WHEN 'NEW' THEN \n      v_status := 'New'; \n      v_lead_stage := 'New / Unassigned';\n      v_call_outcome := 'interested';\n    WHEN 'APPT_SET' THEN \n      v_status := 'Appointment'; \n      v_lead_stage := 'Appointment Set';\n      v_call_outcome := 'appointment_set';\n      v_should_graduate := true;  -- Graduation trigger!\n    WHEN 'APPT_RESCHEDULE' THEN \n      v_status := 'Appointment'; \n      v_lead_stage := 'Appointment Set';\n      v_call_outcome := 'appointment_set';\n      v_should_graduate := true;\n    WHEN 'APPT_CONFIRMED' THEN \n      v_status := 'Appointment'; \n      v_lead_stage := 'Appointment Set';\n      v_call_outcome := 'appointment_set';\n      v_should_graduate := true;\n    WHEN 'QUALIFIED' THEN \n      v_status := 'Qualified'; \n      v_lead_stage := 'Qualified';\n      v_call_outcome := 'qualified';\n    WHEN 'NOT_QUALIFIED' THEN \n      v_status := 'Not Qualified'; \n      v_lead_stage := 'Not Interested';\n      v_call_outcome := 'not_qualified';\n    WHEN 'CALLBACK', 'CALLBACK_REQ' THEN \n      v_status := 'Needs Follow Up'; \n      v_lead_stage := 'Callback Requested';\n      v_call_outcome := 'callback_requested';\n      v_followup_date := COALESCE(p_appt_date::date, CURRENT_DATE + INTERVAL '7 days');\n    WHEN 'BUSY_RETRY' THEN \n      v_status := 'Needs Follow Up'; \n      v_lead_stage := 'Callback Requested';\n      v_call_outcome := 'callback_requested';\n      v_followup_date := CURRENT_DATE + INTERVAL '1 day';\n    WHEN 'NO_ANSWER' THEN \n      v_status := 'No Answer'; \n      v_lead_stage := 'No Answer';\n      v_call_outcome := 'no_answer';\n    WHEN 'LEFT_VM', 'VOICEMAIL' THEN \n      v_status := 'Voicemail'; \n      v_lead_stage := 'Left Voicemail';\n      v_call_outcome := 'voicemail';\n    WHEN 'TEXT_SENT' THEN \n      v_status := 'Contacted'; \n      v_lead_stage := 'Text Sent';\n      v_call_outcome := 'qualified';\n    WHEN 'EMAIL_SENT' THEN \n      v_status := 'Contacted'; \n      v_lead_stage := 'Email Sent';\n      v_call_outcome := 'qualified';\n    WHEN 'WRONG_NUMBER' THEN \n      v_status := 'Wrong Number'; \n      v_lead_stage := 'Bad Lead';\n      v_call_outcome := 'wrong_number';\n    WHEN 'DISCONNECTED' THEN \n      v_status := 'Disconnected'; \n      v_lead_stage := 'Bad Lead';\n      v_call_outcome := 'wrong_number';\n    WHEN 'DNC', 'DO_NOT_CALL' THEN \n      v_status := 'DNC'; \n      v_lead_stage := 'Do Not Call';\n      v_call_outcome := 'dnc_requested';\n    WHEN 'NOT_INTERESTED' THEN \n      v_status := 'Not Interested'; \n      v_lead_stage := 'Not Interested';\n      v_call_outcome := 'not_interested';\n    WHEN 'BAD_LEAD' THEN \n      v_status := 'Not Qualified'; \n      v_lead_stage := 'Bad Lead';\n      v_call_outcome := 'not_qualified';\n    WHEN 'NEW_ROOF' THEN \n      v_status := 'New Roof Queue'; \n      v_lead_stage := 'New Roof Queue';\n      v_call_outcome := 'not_qualified';\n      v_move_to_roof_queue := true;\n      v_roof_queue_reason := 'NEW_ROOF';\n    WHEN 'METAL_ROOF' THEN \n      v_status := 'Not Qualified - Metal'; \n      v_lead_stage := 'Metal Roof';\n      v_call_outcome := 'not_qualified';\n      v_move_to_roof_queue := true;\n      v_roof_queue_reason := 'METAL_ROOF';\n    WHEN 'INSPECTION_DONE' THEN \n      v_status := 'Inspection Complete'; \n      v_lead_stage := 'Appointment Set';  -- Keep at graduated stage\n      v_call_outcome := 'qualified';\n      v_should_graduate := true;\n    WHEN 'TARPED' THEN \n      v_status := 'Tarped'; \n      v_lead_stage := 'Appointment Set';\n      v_call_outcome := 'qualified';\n      v_should_graduate := true;\n    WHEN 'PA_REFERRAL_OFFERED' THEN \n      v_status := 'PA Referral Offered'; \n      v_lead_stage := 'Qualified';\n      v_call_outcome := 'qualified';\n    WHEN 'PA_REFERRAL_ACCEPTED' THEN \n      v_status := 'PA Referral'; \n      v_lead_stage := 'PA Referral';\n      v_call_outcome := 'qualified';\n    WHEN 'ESCALATE_PA' THEN \n      v_status := 'Escalated to PA'; \n      v_lead_stage := 'PA Referral';\n      v_call_outcome := 'qualified';\n    WHEN 'ESCALATE_ROOFER' THEN \n      v_status := 'Escalated to Roofer'; \n      v_lead_stage := 'Qualified';\n      v_call_outcome := 'qualified';\n    WHEN 'SKIP' THEN \n      v_status := 'Skipped'; \n      v_lead_stage := NULL;  -- Don't change lead_stage on skip\n      v_call_outcome := 'no_answer';\n    ELSE \n      v_status := 'New'; \n      v_lead_stage := 'New / Unassigned';\n      v_call_outcome := 'interested';\n  END CASE;\n\n  -- Log the call\n  INSERT INTO call_logs (user_id, tenant_id, lead_id, phone_called, outcome, notes, callback_date, duration_seconds, lead_name, lead_address, city, state, zip, metadata)\n  VALUES (v_user_id, p_tenant_id, p_lead_id, COALESCE(p_phone_called, ''), v_call_outcome, p_notes, p_appt_date, p_duration_seconds, v_lead_name, v_lead_address, v_lead_city, v_lead_state, v_lead_zip, p_metadata)\n  RETURNING id INTO v_call_log_id;\n\n  -- Handle roof queue routing\n  IF v_move_to_roof_queue THEN\n    INSERT INTO new_roofs_queue (\n      lead_id, tenant_org_id, name, phone, email, address, city, state, zip,\n      moved_by, moved_to_queue_at, reason, status, notes\n    ) VALUES (\n      p_lead_id, p_tenant_id::text, v_lead_name, v_lead_phone, v_lead_email, \n      v_lead_address, v_lead_city, v_lead_state, v_lead_zip,\n      v_caller_email, NOW(), v_roof_queue_reason, 'queued', p_notes\n    ) ON CONFLICT (lead_id, tenant_org_id) DO UPDATE SET\n      moved_by = v_caller_email,\n      moved_to_queue_at = NOW(),\n      reason = v_roof_queue_reason,\n      status = 'queued',\n      notes = COALESCE(new_roofs_queue.notes || E'\\n\\n', '') || '[' || now()::date || '] ' || COALESCE(p_notes, 'Moved to roof queue'),\n      updated_at = NOW();\n    \n    -- Soft delete from main tables\n    UPDATE unified_contacts SET \n      deleted_at = NOW(),\n      deleted_by = v_caller_email,\n      deletion_reason = v_roof_queue_reason || ': ' || COALESCE(p_notes, 'Moved to roof queue'),\n      status = v_status,\n      lead_stage = v_lead_stage,\n      updated_at = NOW()\n    WHERE lead_id = p_lead_id AND tenant_org_id = p_tenant_id::text AND deleted_at IS NULL;\n    \n    UPDATE lead_deck SET \n      deleted_at = NOW(),\n      deleted_by = v_caller_email,\n      deletion_reason = v_roof_queue_reason || ': ' || COALESCE(p_notes, 'Moved to roof queue'),\n      status = v_status,\n      lead_stage = v_lead_stage,\n      updated_at = NOW()\n    WHERE lead_id = p_lead_id AND tenant_org_id = p_tenant_id::text AND deleted_at IS NULL;\n    \n    RETURN jsonb_build_object(\n      'ok', true, \n      'designation', p_designation, \n      'status', v_status, \n      'lead_stage', v_lead_stage,\n      'call_log_id', v_call_log_id, \n      'lead_id', p_lead_id, \n      'assigned_to', v_caller_email, \n      'deleted', true,\n      'moved_to_roof_queue', true,\n      'roof_queue_reason', v_roof_queue_reason,\n      'timestamp', NOW()\n    );\n  END IF;\n\n  -- Check for delete cases\n  v_should_delete := p_designation IN ('DNC', 'DO_NOT_CALL', 'NOT_QUALIFIED', 'BAD_LEAD');\n\n  IF v_should_delete THEN\n    DELETE FROM unified_contacts WHERE lead_id = p_lead_id AND tenant_org_id = p_tenant_id::text;\n    DELETE FROM lead_deck WHERE lead_id = p_lead_id AND tenant_org_id = p_tenant_id::text;\n  ELSE\n    -- Upsert to unified_contacts with BOTH status AND lead_stage\n    INSERT INTO unified_contacts (\n      lead_id, tenant_org_id, name, first_name, last_name, phone, email, address, \n      city, state, zip, contact_status, status, lead_stage, \n      assigned_to, assigned_rep, appt_date, appt_time, notes, \n      graduated_at, jobs_stage, claim_stage,\n      created_at, updated_at\n    )\n    SELECT \n      p_lead_id, p_tenant_id::text, COALESCE(v_lead_name, ''), \n      split_part(COALESCE(v_lead_name, ''), ' ', 1),\n      CASE WHEN position(' ' in COALESCE(v_lead_name, '')) > 0 \n           THEN substring(COALESCE(v_lead_name, '') from position(' ' in COALESCE(v_lead_name, '')) + 1) \n           ELSE '' END,\n      COALESCE(v_lead_phone, ''), COALESCE(v_lead_email, ''), COALESCE(v_lead_address, ''),\n      v_lead_city, v_lead_state, v_lead_zip,\n      v_status, v_status, v_lead_stage,\n      COALESCE(p_assignee, v_caller_email), COALESCE(p_assignee, v_caller_email), \n      p_appt_date, p_appt_time, p_notes,\n      CASE WHEN v_should_graduate THEN NOW() ELSE NULL END,\n      CASE WHEN v_should_graduate THEN 'Appointment Scheduled' ELSE NULL END,\n      CASE WHEN v_should_graduate THEN 'Inspection Scheduled' ELSE NULL END,\n      NOW(), NOW()\n    ON CONFLICT (lead_id, tenant_org_id) DO UPDATE SET\n      contact_status = v_status, \n      status = v_status,\n      lead_stage = COALESCE(v_lead_stage, unified_contacts.lead_stage),  -- Update lead_stage!\n      assigned_to = COALESCE(p_assignee, v_caller_email, unified_contacts.assigned_to),\n      assigned_rep = COALESCE(p_assignee, v_caller_email, unified_contacts.assigned_rep),\n      appt_date = CASE WHEN p_appt_date IS NOT NULL THEN p_appt_date ELSE unified_contacts.appt_date END,\n      appt_time = CASE WHEN p_appt_time IS NOT NULL THEN p_appt_time ELSE unified_contacts.appt_time END,\n      notes = CASE WHEN p_notes IS NOT NULL \n              THEN COALESCE(unified_contacts.notes || E'\\n\\n', '') || '[' || now()::date || '] ' || p_notes \n              ELSE unified_contacts.notes END,\n      -- Handle graduation\n      graduated_at = CASE WHEN v_should_graduate AND unified_contacts.graduated_at IS NULL THEN NOW() ELSE unified_contacts.graduated_at END,\n      jobs_stage = CASE WHEN v_should_graduate AND unified_contacts.jobs_stage IS NULL THEN 'Appointment Scheduled' ELSE unified_contacts.jobs_stage END,\n      claim_stage = CASE WHEN v_should_graduate AND unified_contacts.claim_stage IS NULL THEN 'Inspection Scheduled' ELSE unified_contacts.claim_stage END,\n      updated_at = NOW()\n    RETURNING id INTO v_contact_id;\n\n    -- Also update lead_deck with lead_stage\n    UPDATE lead_deck SET \n      status = v_status, \n      lead_stage = COALESCE(v_lead_stage, lead_stage),  -- Update lead_stage!\n      assigned_to = COALESCE(p_assignee, v_caller_email, assigned_to),\n      notes = CASE WHEN p_notes IS NOT NULL \n              THEN COALESCE(notes || E'\\n\\n', '') || '[' || now()::date || '] ' || p_notes \n              ELSE notes END, \n      -- Handle graduation\n      graduated_at = CASE WHEN v_should_graduate AND graduated_at IS NULL THEN NOW() ELSE graduated_at END,\n      updated_at = NOW()\n    WHERE lead_id = p_lead_id AND tenant_org_id = p_tenant_id::text;\n  END IF;\n\n  -- Create follow-up if callback requested\n  IF p_designation IN ('CALLBACK', 'CALLBACK_REQ', 'BUSY_RETRY') OR v_status = 'Needs Follow Up' THEN\n    INSERT INTO followups (lead_id, rep_email, customer_name, followup_date, notes, status, tenant_org_id)\n    SELECT p_lead_id, p.email, v_lead_name, v_followup_date, COALESCE(p_notes, 'Follow up needed'), 'Pending', p_tenant_id::text\n    FROM profiles p WHERE p.id = v_user_id \n    ON CONFLICT DO NOTHING;\n  END IF;\n\n  -- Add to DNC list if requested\n  IF p_designation IN ('DNC', 'DO_NOT_CALL') AND p_phone_called IS NOT NULL THEN\n    INSERT INTO dnc_list (phone, name, reason, added_by, tenant_org_id)\n    SELECT p_phone_called, v_lead_name, COALESCE(p_notes, 'DNC requested during call'), p.email, p_tenant_id::text\n    FROM profiles p WHERE p.id = v_user_id \n    ON CONFLICT (phone) DO NOTHING;\n  END IF;\n\n  RETURN jsonb_build_object(\n    'ok', true, \n    'designation', p_designation, \n    'status', v_status, \n    'lead_stage', v_lead_stage,\n    'graduated', v_should_graduate,\n    'call_log_id', v_call_log_id, \n    'contact_id', v_contact_id,\n    'lead_id', p_lead_id, \n    'assigned_to', COALESCE(p_assignee, v_caller_email), \n    'deleted', v_should_delete, \n    'timestamp', NOW()\n  );\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_lead_id text, p_user_id uuid, p_designation text, p_notes text, p_appt_date text, p_appt_time text, p_assignee text, p_phone_called text, p_duration_seconds integer, p_metadata jsonb"},{"name":"handle_new_user","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.handle_new_user()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  insert into public.profiles (id, email, phone, name)\n  values (\n    new.id,\n    nullif(btrim(new.email), ''),\n    nullif(btrim(new.phone), ''),\n    coalesce(\n      nullif(new.raw_user_meta_data->>'full_name', ''),\n      nullif(new.raw_user_meta_data->>'name', ''),\n      nullif(btrim(new.email), ''),\n      nullif(btrim(new.phone), ''),\n      'KnockLaunch User'\n    )\n  )\n  on conflict (id) do update\n  set email = excluded.email,\n      phone = coalesce(excluded.phone, public.profiles.phone),\n      name = coalesce(nullif(public.profiles.name, ''), excluded.name),\n      updated_at = now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"has_acting_pm_grant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.has_acting_pm_grant(_user_id uuid, _tenant_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(),'') <> 'service_role'\n     AND auth.uid() IS DISTINCT FROM _user_id\n     AND NOT coalesce(public.is_system_admin(auth.uid()),false)\n     AND NOT coalesce(public.is_manager_or_higher(auth.uid(),_tenant_id),false) THEN\n    RAISE EXCEPTION 'acting PM grant introspection denied' USING ERRCODE='42501';\n  END IF;\n  RETURN EXISTS (\n    SELECT 1 FROM public.acting_pm_grants\n    WHERE user_id=_user_id AND tenant_id=_tenant_id\n      AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at > now())\n  );\nEND;\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"has_any_active_tenant_membership","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.has_any_active_tenant_membership(_user_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(),'') <> 'service_role'\n     AND auth.uid() IS DISTINCT FROM _user_id\n     AND NOT coalesce(public.is_system_admin(auth.uid()),false) THEN\n    RAISE EXCEPTION 'membership introspection denied' USING ERRCODE='42501';\n  END IF;\n  RETURN EXISTS (\n    SELECT 1 FROM public.user_tenant_memberships\n    WHERE user_id=_user_id AND status='active'\n  );\nEND;\n$function$\n","identity_arguments":"_user_id uuid"},{"name":"has_entitlement","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.has_entitlement(_tenant_id uuid, _feature_key text)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT coalesce(public.is_tenant_member(auth.uid(), _tenant_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'tenant entitlement access denied' USING ERRCODE = '42501';\n  END IF;\n  RETURN public.is_tenant_comped(_tenant_id) OR EXISTS (\n    SELECT 1 FROM public.tenant_subscriptions ts\n    JOIN public.plan_features pf ON pf.plan_id = ts.plan_id\n    WHERE ts.tenant_id = _tenant_id AND pf.feature_key = _feature_key\n      AND ts.status IN ('trial','active','past_due')\n      AND ((pf.is_boolean = true AND coalesce(pf.limit_value,0) > 0)\n        OR (pf.is_boolean = false AND (pf.limit_value IS NULL OR pf.limit_value <> 0)))\n  );\nEND;\n$function$\n","identity_arguments":"_tenant_id uuid, _feature_key text"},{"name":"has_role","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.has_role(_user_id uuid, _tenant_id uuid, _role app_role)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(),'') <> 'service_role'\n     AND auth.uid() IS DISTINCT FROM _user_id\n     AND NOT coalesce(public.is_system_admin(auth.uid()),false)\n     AND NOT coalesce(public.is_manager_or_higher(auth.uid(),_tenant_id),false) THEN\n    RAISE EXCEPTION 'role introspection denied' USING ERRCODE='42501';\n  END IF;\n  RETURN EXISTS (\n    SELECT 1\n    FROM public.user_tenant_memberships m\n    JOIN public.user_roles ur ON ur.user_id=m.user_id AND ur.tenant_id=m.tenant_id\n    WHERE m.user_id=_user_id AND m.tenant_id=_tenant_id AND m.status='active' AND ur.role=_role\n  );\nEND;\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid, _role app_role"},{"name":"has_user_accepted_required_agreements","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.has_user_accepted_required_agreements(p_user_id uuid, p_tenant_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE v_pending_count integer;\nBEGIN\n  IF p_user_id IS NULL OR p_tenant_id IS NULL THEN RETURN false; END IF;\n  SELECT count(*) INTO v_pending_count FROM public.get_user_pending_agreements(p_user_id, p_tenant_id);\n  RETURN v_pending_count = 0;\nEND;\n$function$\n","identity_arguments":"p_user_id uuid, p_tenant_id uuid"},{"name":"increment_active_enrollments","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.increment_active_enrollments(p_sequence_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  UPDATE communication_sequences\n  SET active_enrollments = COALESCE(active_enrollments, 0) + 1,\n      total_enrollments = COALESCE(total_enrollments, 0) + 1\n  WHERE id = p_sequence_id;\nEND;\n$function$\n","identity_arguments":"p_sequence_id uuid"},{"name":"increment_community_shoutout_heart_count","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.increment_community_shoutout_heart_count()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  update public.community_shoutouts\n  set heart_count = heart_count + 1,\n      updated_at = now()\n  where id = new.shoutout_id\n    and tenant_org_id = new.tenant_org_id;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"is_active_message_tenant_member","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_active_message_tenant_member(p_tenant_id uuid, p_user_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select exists (\n    select 1 from public.tenants t\n    where t.id = p_tenant_id\n      and t.status = 'active'\n      and (t.owner_id = p_user_id or exists (\n        select 1 from public.user_tenant_memberships m\n        where m.tenant_id = t.id and m.user_id = p_user_id and m.status = 'active'\n      ))\n  );\n$function$\n","identity_arguments":"p_tenant_id uuid, p_user_id uuid"},{"name":"is_admin_or_higher","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_admin_or_higher(_user_id uuid, _tenant_id uuid DEFAULT NULL::uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_caller uuid := auth.uid();\n  v_service boolean := coalesce(auth.jwt()->>'role','') = 'service_role';\nbegin\n  if _user_id is null then return false; end if;\n  if not exists (\n    select 1 from public.profiles p\n    where p.id=_user_id and coalesce(p.active,true)=true\n  ) then return false; end if;\n  if _tenant_id is null then return coalesce(public.is_system_admin(_user_id), false); end if;\n\n  if not (\n    v_service\n    or (\n      v_caller is not null\n      and exists (\n        select 1 from public.profiles cp\n        where cp.id=v_caller and coalesce(cp.active,true)=true\n      )\n      and (\n        v_caller = _user_id\n        or coalesce(public.is_system_admin(v_caller), false)\n        or exists (\n          select 1\n          from public.user_tenant_memberships m\n          left join public.user_roles ur on ur.user_id=m.user_id and ur.tenant_id=m.tenant_id\n          where m.user_id=v_caller and m.tenant_id=_tenant_id and m.status='active'\n            and (m.is_owner=true or ur.role::text in ('Admin','TenantOwner','Tenant Owner','Owner'))\n        )\n      )\n    )\n  ) then return false; end if;\n\n  return coalesce(public.is_system_admin(_user_id), false)\n    or exists (\n      select 1\n      from public.user_tenant_memberships m\n      left join public.user_roles ur on ur.user_id=m.user_id and ur.tenant_id=m.tenant_id\n      where m.user_id=_user_id and m.tenant_id=_tenant_id and m.status='active'\n        and (m.is_owner=true or ur.role::text in ('Admin','TenantOwner','Tenant Owner','Owner'))\n    );\nend;\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"is_assigned_to","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_assigned_to(_user_id uuid, _assigned_to text)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nDECLARE v_email text;\nBEGIN\n  IF coalesce(auth.role(),'') <> 'service_role'\n     AND auth.uid() IS DISTINCT FROM _user_id\n     AND NOT coalesce(public.is_system_admin(auth.uid()),false) THEN\n    RAISE EXCEPTION 'assignment introspection denied' USING ERRCODE='42501';\n  END IF;\n  SELECT email INTO v_email FROM public.profiles WHERE id=_user_id;\n  RETURN _assigned_to=_user_id::text OR lower(_assigned_to)=lower(v_email);\nEND;\n$function$\n","identity_arguments":"_user_id uuid, _assigned_to text"},{"name":"is_claim_participant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_claim_participant(_claim_id uuid, _user_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _claim_id is not null\n    and _user_id is not null\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or auth.uid()=_user_id\n      or public.is_system_admin(auth.uid())\n    )\n    and (\n      exists (\n        select 1\n        from public.shared_claim_participants scp\n        join public.user_tenant_memberships utm on utm.tenant_id=scp.tenant_id\n        where scp.shared_claim_id=_claim_id\n          and utm.user_id=_user_id\n          and utm.status='active'\n          and scp.status='accepted'\n      )\n      or exists (\n        select 1\n        from public.shared_claims sc\n        join public.user_tenant_memberships utm on utm.tenant_id=sc.created_by_tenant_id\n        where sc.id=_claim_id\n          and utm.user_id=_user_id\n          and utm.status='active'\n      )\n      or public.is_system_admin(_user_id)\n    );\n$function$\n","identity_arguments":"_claim_id uuid, _user_id uuid"},{"name":"is_claim_participant_any_status","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_claim_participant_any_status(_claim_id uuid, _user_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _claim_id is not null\n    and _user_id is not null\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or auth.uid()=_user_id\n      or public.is_system_admin(auth.uid())\n    )\n    and (\n      exists (\n        select 1\n        from public.shared_claim_participants scp\n        join public.user_tenant_memberships utm on utm.tenant_id=scp.tenant_id\n        where scp.shared_claim_id=_claim_id\n          and utm.user_id=_user_id\n          and utm.status='active'\n      )\n      or public.is_system_admin(_user_id)\n    );\n$function$\n","identity_arguments":"_claim_id uuid, _user_id uuid"},{"name":"is_command_agent","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_command_agent(_user_id uuid, _tenant_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _user_id is not null\n    and _tenant_id is not null\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or auth.uid()=_user_id\n      or public.is_system_admin(auth.uid())\n    )\n    and (\n      public.is_system_admin(_user_id)\n      or exists (\n        select 1\n        from public.user_tenant_memberships m\n        join public.user_roles ur on ur.user_id=m.user_id and ur.tenant_id=m.tenant_id\n        where m.user_id=_user_id\n          and m.tenant_id=_tenant_id\n          and m.status='active'\n          and ur.role::text in ('GodMode','Admin','Owner','Tenant Owner','Manager','command_agent')\n      )\n    );\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"is_door_accessible","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_door_accessible(p_door_tenant_id text, p_created_by uuid, p_last_visited_by uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  SELECT public.is_system_admin(auth.uid()) OR auth.uid()=p_created_by OR auth.uid()=p_last_visited_by OR EXISTS (\n    SELECT 1 FROM public.user_tenant_memberships m\n    LEFT JOIN public.user_roles ur ON ur.user_id=m.user_id AND ur.tenant_id=m.tenant_id\n    WHERE m.user_id=auth.uid() AND m.tenant_id::text=p_door_tenant_id AND m.status='active'\n      AND (m.is_owner=true OR ur.role::text IN ('Owner','Tenant Owner','Admin','GodMode')));\n$function$\n","identity_arguments":"p_door_tenant_id text, p_created_by uuid, p_last_visited_by uuid"},{"name":"is_existing_client_record","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_existing_client_record(p_status text, p_lead_stage text, p_jobs_stage text, p_claim_stage text, p_graduated_at timestamp with time zone)\n RETURNS boolean\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  SELECT\n    p_graduated_at IS NOT NULL\n    OR LOWER(COALESCE(p_status,'')) ~ '(client|customer|active|job|approved|signed|contract|in progress|in-progress|inprogress)'\n    OR LOWER(COALESCE(p_jobs_stage,'')) ~ '(active|approved|signed|contract|in progress|complete|paid)'\n    OR LOWER(COALESCE(p_claim_stage,'')) ~ '(active|approved|signed|contract|in progress|complete|paid|settled)';\n$function$\n","identity_arguments":"p_status text, p_lead_stage text, p_jobs_stage text, p_claim_stage text, p_graduated_at timestamp with time zone"},{"name":"is_global_admin","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_global_admin(_user_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _user_id is not null\n    and (\n      _user_id = auth.uid()\n      or coalesce(auth.jwt() ->> 'role', '') = 'service_role'\n    )\n    and public.is_system_admin(_user_id);\n$function$\n","identity_arguments":"_user_id uuid"},{"name":"is_manager_or_higher","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_manager_or_higher(_user_id uuid, _tenant_id uuid DEFAULT NULL::uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _user_id is not null\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or auth.uid()=_user_id\n      or public.is_system_admin(auth.uid())\n    )\n    and (\n      public.is_system_admin(_user_id)\n      or (\n        _tenant_id is not null\n        and exists (\n          select 1\n          from public.user_tenant_memberships m\n          left join public.user_roles ur\n            on ur.user_id=m.user_id and ur.tenant_id=m.tenant_id\n          where m.user_id=_user_id\n            and m.tenant_id=_tenant_id\n            and m.status='active'\n            and (\n              m.is_owner=true\n              or ur.role::text in ('Manager','PM','OfficeAdmin','Office Staff','Admin','TenantOwner','Tenant Owner','Owner','GodMode')\n            )\n        )\n      )\n    );\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"is_manager_or_higher_strict","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_manager_or_higher_strict(_user_id uuid, _tenant_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(),'') <> 'service_role'\n     AND auth.uid() IS DISTINCT FROM _user_id\n     AND NOT coalesce(public.is_system_admin(auth.uid()),false)\n     AND NOT coalesce(public.is_manager_or_higher(auth.uid(),_tenant_id),false) THEN\n    RAISE EXCEPTION 'manager-role introspection denied' USING ERRCODE='42501';\n  END IF;\n  RETURN EXISTS (\n    SELECT 1\n    FROM public.user_tenant_memberships m\n    LEFT JOIN public.user_roles ur ON ur.user_id=m.user_id AND ur.tenant_id=m.tenant_id\n    WHERE m.user_id=_user_id AND m.tenant_id=_tenant_id AND m.status='active'\n      AND (m.is_owner=true OR ur.role::text IN ('Manager','PM','Admin','Owner','Tenant Owner','GodMode'))\n  );\nEND;\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"is_manager_pm_or_higher","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_manager_pm_or_higher(_user uuid, _tenant uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _user is not null\n    and _tenant is not null\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or auth.uid()=_user\n      or public.is_system_admin(auth.uid())\n    )\n    and public.is_manager_or_higher(_user,_tenant);\n$function$\n","identity_arguments":"_user uuid, _tenant uuid"},{"name":"is_platform_admin","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_platform_admin(_user_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _user_id is not null\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or auth.uid()=_user_id\n      or public.is_system_admin(auth.uid())\n    )\n    and public.is_system_admin(_user_id);\n$function$\n","identity_arguments":"_user_id uuid"},{"name":"is_platform_owner_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_platform_owner_tenant(p_tenant_type text, p_settings jsonb, p_company_slug text)\n RETURNS boolean\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  select\n    upper(trim(coalesce(p_tenant_type, ''))) in ('PLATFORM','PLATFORM_ADMIN','GODMODE','ADMIN','SYSTEM_ADMIN')\n    or upper(trim(coalesce(p_settings->>'declared_tenant_type', ''))) in ('PLATFORM','PLATFORM_ADMIN','GODMODE','ADMIN','SYSTEM_ADMIN')\n    or upper(trim(coalesce(p_settings->>'declared_business_type', ''))) in ('PLATFORM','PLATFORM_ADMIN','GODMODE','ADMIN','SYSTEM_ADMIN')\n    or lower(trim(coalesce(p_settings->>'workspace_variant', ''))) = 'platform_admin'\n    or lower(trim(coalesce(p_settings->>'workspace_type', ''))) = 'platform_owner'\n    or lower(trim(coalesce(p_settings->>'canonical_owner_route', ''))) = '/knock-launch-os'\n    or lower(trim(coalesce(p_company_slug, ''))) = 'knocklaunch-crm';\n$function$\n","identity_arguments":"p_tenant_type text, p_settings jsonb, p_company_slug text"},{"name":"is_realtor_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_realtor_tenant(_tenant_org_id text)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT coalesce(public.is_tenant_member(_tenant_org_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'tenant type access denied' USING ERRCODE = '42501';\n  END IF;\n  RETURN EXISTS (\n    SELECT 1 FROM public.tenants t\n    WHERE t.id::text = _tenant_org_id AND upper(t.tenant_type) = 'REALTOR'\n  );\nEND;\n$function$\n","identity_arguments":"_tenant_org_id text"},{"name":"is_repo_agent_admin","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_repo_agent_admin()\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  SELECT EXISTS (\n    SELECT 1 FROM auth.users\n    WHERE id = auth.uid()\n      AND lower(coalesce(email, '')) = 'info@knocklaunch.app'\n  );\n$function$\n","identity_arguments":""},{"name":"is_system_admin","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_system_admin()\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$ SELECT public.is_system_admin(auth.uid()); $function$\n","identity_arguments":""},{"name":"is_system_admin","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_system_admin(_user_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  with caller as (\n    select auth.uid() as uid,\n           coalesce(auth.jwt() ->> 'role', '') as jwt_role\n  ),\n  caller_authorized as (\n    select\n      c.jwt_role = 'service_role'\n      or (\n        c.uid is not null\n        and exists (\n          select 1 from public.profiles cp\n          where cp.id=c.uid and coalesce(cp.active,true)=true\n        )\n        and (\n          c.uid = _user_id\n          or exists (\n            select 1\n            from public.user_roles ur\n            where ur.user_id = c.uid\n              and ur.role::text = 'GodMode'\n              and ur.tenant_id is null\n          )\n        )\n      ) as allowed\n    from caller c\n  )\n  select\n    _user_id is not null\n    and coalesce((select allowed from caller_authorized), false)\n    and exists (\n      select 1 from public.profiles p\n      where p.id=_user_id and coalesce(p.active,true)=true\n    )\n    and exists (\n      select 1\n      from public.user_roles ur\n      where ur.user_id = _user_id\n        and ur.role::text = 'GodMode'\n        and ur.tenant_id is null\n    );\n$function$\n","identity_arguments":"_user_id uuid"},{"name":"is_tenant_comped","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_tenant_comped(_tenant_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT coalesce(public.is_tenant_member(auth.uid(), _tenant_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'tenant billing access denied' USING ERRCODE = '42501';\n  END IF;\n  RETURN EXISTS (\n    SELECT 1 FROM public.billing_comps c\n    WHERE c.is_active = true AND c.scope = 'tenant' AND c.tenant_id = _tenant_id\n      AND (c.expires_at IS NULL OR c.expires_at > now())\n  );\nEND;\n$function$\n","identity_arguments":"_tenant_id uuid"},{"name":"is_tenant_crew_only","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_tenant_crew_only(_user_id uuid, _tenant_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(),'') <> 'service_role'\n     AND auth.uid() IS DISTINCT FROM _user_id\n     AND NOT coalesce(public.is_system_admin(auth.uid()),false)\n     AND NOT coalesce(public.is_manager_or_higher(auth.uid(),_tenant_id),false) THEN\n    RAISE EXCEPTION 'crew-role introspection denied' USING ERRCODE='42501';\n  END IF;\n  RETURN EXISTS (\n    SELECT 1 FROM public.user_tenant_memberships m\n    JOIN public.user_roles ur ON ur.user_id=m.user_id AND ur.tenant_id=m.tenant_id\n    WHERE m.user_id=_user_id AND m.tenant_id=_tenant_id AND m.status='active' AND ur.role::text='Crew'\n  ) AND NOT EXISTS (\n    SELECT 1 FROM public.user_tenant_memberships m2\n    JOIN public.user_roles ur2 ON ur2.user_id=m2.user_id AND ur2.tenant_id=m2.tenant_id\n    WHERE m2.user_id=_user_id AND m2.tenant_id=_tenant_id AND m2.status='active' AND ur2.role::text<>'Crew'\n  );\nEND;\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"is_tenant_member","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_tenant_member(_user_id uuid, _tenant_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_caller uuid := auth.uid();\n  v_service boolean := coalesce(auth.jwt()->>'role','') = 'service_role';\n  v_caller_can_inspect boolean := false;\nbegin\n  if _user_id is null or _tenant_id is null then return false; end if;\n  if not exists (\n    select 1 from public.profiles p\n    where p.id=_user_id and coalesce(p.active,true)=true\n  ) then return false; end if;\n\n  v_caller_can_inspect :=\n    v_service\n    or (\n      v_caller is not null\n      and exists (\n        select 1 from public.profiles cp\n        where cp.id=v_caller and coalesce(cp.active,true)=true\n      )\n      and (\n        v_caller = _user_id\n        or coalesce(public.is_system_admin(v_caller), false)\n        or exists (\n          select 1\n          from public.user_tenant_memberships m\n          left join public.user_roles ur on ur.user_id=m.user_id and ur.tenant_id=m.tenant_id\n          where m.user_id=v_caller\n            and m.tenant_id=_tenant_id\n            and m.status='active'\n            and (\n              m.is_owner=true\n              or ur.role::text in ('Manager','PM','OfficeAdmin','Office Staff','Admin','TenantOwner','Tenant Owner','Owner')\n            )\n        )\n      )\n    );\n\n  if not v_caller_can_inspect then return false; end if;\n\n  return coalesce(public.is_system_admin(_user_id), false)\n    or exists (\n      select 1\n      from public.user_tenant_memberships m\n      where m.user_id=_user_id and m.tenant_id=_tenant_id and m.status='active'\n    );\nend;\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"is_tenant_member","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_tenant_member(check_tenant_id text)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    check_tenant_id is not null\n    and auth.uid() is not null\n    and exists (\n      select 1 from public.profiles p\n      where p.id=auth.uid() and coalesce(p.active,true)=true\n    )\n    and (\n      public.is_system_admin(auth.uid())\n      or exists (\n        select 1 from public.user_tenant_memberships m\n        where m.user_id=auth.uid()\n          and m.tenant_id::text=check_tenant_id\n          and m.status='active'\n      )\n    );\n$function$\n","identity_arguments":"check_tenant_id text"},{"name":"is_tenant_owner","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_tenant_owner(_user_id uuid, _tenant_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_caller uuid := auth.uid();\n  v_service boolean := coalesce(auth.jwt()->>'role','') = 'service_role';\nbegin\n  if _user_id is null or _tenant_id is null then return false; end if;\n  if not exists (\n    select 1 from public.profiles p\n    where p.id=_user_id and coalesce(p.active,true)=true\n  ) then return false; end if;\n\n  if not (\n    v_service\n    or (\n      v_caller is not null\n      and exists (\n        select 1 from public.profiles cp\n        where cp.id=v_caller and coalesce(cp.active,true)=true\n      )\n      and (\n        v_caller = _user_id\n        or coalesce(public.is_system_admin(v_caller), false)\n        or exists (\n          select 1\n          from public.user_tenant_memberships m\n          left join public.user_roles ur on ur.user_id=m.user_id and ur.tenant_id=m.tenant_id\n          where m.user_id=v_caller and m.tenant_id=_tenant_id and m.status='active'\n            and (m.is_owner=true or ur.role::text in ('Admin','TenantOwner','Tenant Owner','Owner'))\n        )\n      )\n    )\n  ) then return false; end if;\n\n  return exists (\n    select 1\n    from public.user_tenant_memberships m\n    left join public.user_roles ur on ur.user_id=m.user_id and ur.tenant_id=m.tenant_id\n    where m.user_id=_user_id and m.tenant_id=_tenant_id and m.status='active'\n      and (m.is_owner=true or ur.role::text in ('TenantOwner','Tenant Owner','Owner'))\n  );\nend;\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"is_tenant_owner_for","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_tenant_owner_for(_user_id uuid, _tenant_id text)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _user_id is not null\n    and nullif(btrim(_tenant_id),'') is not null\n    and exists (\n      select 1 from public.profiles p\n      where p.id=_user_id and coalesce(p.active,true)=true\n    )\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or (\n        auth.uid() is not null\n        and exists (\n          select 1 from public.profiles cp\n          where cp.id=auth.uid() and coalesce(cp.active,true)=true\n        )\n        and (\n          auth.uid()=_user_id\n          or public.is_system_admin(auth.uid())\n        )\n      )\n    )\n    and exists (\n      select 1\n      from public.user_tenant_memberships m\n      left join public.user_roles ur\n        on ur.user_id=m.user_id and ur.tenant_id=m.tenant_id\n      where m.user_id=_user_id\n        and m.tenant_id::text=_tenant_id\n        and m.status='active'\n        and (m.is_owner=true or ur.role::text in ('Owner','Tenant Owner'))\n    );\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id text"},{"name":"is_tenant_owner_membership","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_tenant_owner_membership(_viewer uuid, _tenant uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _viewer is not null\n    and _tenant is not null\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or auth.uid()=_viewer\n      or public.is_system_admin(auth.uid())\n    )\n    and exists (\n      select 1 from public.user_tenant_memberships utm\n      where utm.user_id=_viewer\n        and utm.tenant_id=_tenant\n        and utm.is_owner=true\n        and utm.status='active'\n    );\n$function$\n","identity_arguments":"_viewer uuid, _tenant uuid"},{"name":"is_tenant_owner_or_admin","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_tenant_owner_or_admin(_user_id uuid, _tenant_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _user_id is not null\n    and _tenant_id is not null\n    and exists (\n      select 1 from public.profiles p\n      where p.id=_user_id and coalesce(p.active,true)=true\n    )\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or (\n        auth.uid() is not null\n        and exists (\n          select 1 from public.profiles cp\n          where cp.id=auth.uid() and coalesce(cp.active,true)=true\n        )\n        and (\n          auth.uid()=_user_id\n          or public.is_system_admin(auth.uid())\n        )\n      )\n    )\n    and (\n      public.is_system_admin(_user_id)\n      or exists (\n        select 1\n        from public.user_tenant_memberships m\n        left join public.user_roles ur\n          on ur.user_id=m.user_id and ur.tenant_id=m.tenant_id\n        where m.user_id=_user_id\n          and m.tenant_id=_tenant_id\n          and m.status='active'\n          and (m.is_owner=true or ur.role::text in ('Owner','Tenant Owner','Admin'))\n      )\n    );\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"is_trial_tenant_active","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_trial_tenant_active(_tenant_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT coalesce(public.is_tenant_member(auth.uid(), _tenant_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'tenant trial access denied' USING ERRCODE = '42501';\n  END IF;\n  RETURN EXISTS (\n    SELECT 1 FROM public.trial_accounts\n    WHERE tenant_id = _tenant_id AND trial_status = 'active'\n      AND (trial_end_date IS NULL OR trial_end_date > now())\n  );\nEND;\n$function$\n","identity_arguments":"_tenant_id uuid"},{"name":"is_user_active","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_user_active(_user_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         auth.uid() IS DISTINCT FROM _user_id\n         AND NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT coalesce(public.shares_tenant_as_manager_pm(auth.uid(), _user_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'user status access denied' USING ERRCODE = '42501';\n  END IF;\n  RETURN EXISTS (SELECT 1 FROM public.profiles WHERE id = _user_id AND coalesce(active,true) = true);\nEND;\n$function$\n","identity_arguments":"_user_id uuid"},{"name":"is_user_active_in_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_user_active_in_tenant(_user_id uuid, _tenant_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT (auth.uid() = _user_id AND coalesce(public.is_tenant_member(auth.uid(), _tenant_id), false))\n         AND NOT coalesce(public.is_manager_or_higher(auth.uid(), _tenant_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'tenant user status access denied' USING ERRCODE = '42501';\n  END IF;\n  RETURN EXISTS (\n    SELECT 1 FROM public.profiles p\n    JOIN public.user_tenant_memberships m ON m.user_id = p.id\n    WHERE p.id = _user_id AND m.tenant_id = _tenant_id\n      AND coalesce(p.active,true) = true AND coalesce(m.status,'active') = 'active'\n  );\nEND;\n$function$\n","identity_arguments":"_user_id uuid, _tenant_id uuid"},{"name":"is_user_comped","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_user_comped(_user_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         auth.uid() IS DISTINCT FROM _user_id\n         AND NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT EXISTS (\n           SELECT 1 FROM public.user_tenant_memberships m\n           WHERE m.user_id = _user_id AND m.status = 'active'\n             AND coalesce(public.is_admin_or_higher(auth.uid(), m.tenant_id), false)\n         )\n       )\n     ) THEN\n    RAISE EXCEPTION 'user billing access denied' USING ERRCODE = '42501';\n  END IF;\n  RETURN EXISTS (\n    SELECT 1 FROM public.billing_comps c\n    WHERE c.is_active = true AND (c.expires_at IS NULL OR c.expires_at > now())\n      AND ((c.scope='user' AND c.user_id=_user_id)\n        OR (c.scope='tenant' AND c.tenant_id IN (\n          SELECT tenant_id FROM public.user_tenant_memberships WHERE user_id=_user_id\n        )))\n  );\nEND;\n$function$\n","identity_arguments":"_user_id uuid"},{"name":"is_within_business_hours","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_within_business_hours(_profile_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_tenant_id uuid;\n  v_tz text;\n  v_hours jsonb;\n  v_local timestamptz;\n  v_dow text;\n  v_today date;\n  v_override record;\n  v_day jsonb;\n  v_open time;\n  v_close time;\n  v_now_time time;\nBEGIN\n  SELECT tenant_org_id, timezone, business_hours\n    INTO v_tenant_id, v_tz, v_hours\n  FROM public.inbound_routing_profiles\n  WHERE id = _profile_id;\n\n  IF v_tenant_id IS NULL THEN RETURN false; END IF;\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT coalesce(public.is_tenant_member(auth.uid(), v_tenant_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'routing profile access denied' USING ERRCODE = '42501';\n  END IF;\n  IF v_tz IS NULL THEN RETURN false; END IF;\n\n  v_local := now() AT TIME ZONE v_tz;\n  v_today := v_local::date;\n  v_now_time := v_local::time;\n\n  SELECT * INTO v_override FROM public.business_hours_overrides\n   WHERE routing_profile_id = _profile_id AND override_date = v_today LIMIT 1;\n  IF FOUND THEN\n    IF v_override.closed THEN RETURN false; END IF;\n    RETURN v_now_time BETWEEN v_override.open_time AND v_override.close_time;\n  END IF;\n\n  v_dow := lower(to_char(v_local, 'dy'));\n  v_day := v_hours -> v_dow;\n  IF v_day IS NULL OR (v_day ->> 'closed')::boolean = true THEN RETURN false; END IF;\n  v_open := (v_day ->> 'open')::time;\n  v_close := (v_day ->> 'close')::time;\n  RETURN v_now_time BETWEEN v_open AND v_close;\nEND;\n$function$\n","identity_arguments":"_profile_id uuid"},{"name":"is_workflow_template_admin","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.is_workflow_template_admin(_user_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _user_id is not null\n    and (\n      _user_id = auth.uid()\n      or coalesce(auth.jwt() ->> 'role', '') = 'service_role'\n    )\n    and public.is_system_admin(_user_id);\n$function$\n","identity_arguments":"_user_id uuid"},{"name":"issue_auto_unlock_upload_ticket","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.issue_auto_unlock_upload_ticket(p_ip_hash text, p_proof_kind text, p_file_name text, p_mime text, p_size bigint)\n RETURNS TABLE(ticket_id uuid, object_path text, expires_at timestamp with time zone)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_catalog', 'pg_temp'\nAS $function$\nDECLARE\n  v_id uuid := gen_random_uuid();\n  v_ext text;\n  v_path text;\n  v_expires timestamptz := now() + interval '15 minutes';\n  v_recent integer;\n  v_daily integer;\nBEGIN\n  IF coalesce(auth.role(),'') <> 'service_role' THEN\n    RAISE EXCEPTION 'service role required' USING ERRCODE='42501';\n  END IF;\n  IF p_ip_hash !~ '^[0-9a-f]{64}$' OR p_proof_kind NOT IN ('identity','authority') THEN\n    RAISE EXCEPTION 'invalid upload ticket request' USING ERRCODE='22023';\n  END IF;\n  IF p_size IS NULL OR p_size <= 0 OR p_size > 10485760 THEN\n    RAISE EXCEPTION 'upload_size_invalid' USING ERRCODE='22023';\n  END IF;\n  v_ext := CASE p_mime\n    WHEN 'image/jpeg' THEN 'jpg'\n    WHEN 'image/png' THEN 'png'\n    WHEN 'image/webp' THEN 'webp'\n    WHEN 'image/heic' THEN 'heic'\n    WHEN 'image/heif' THEN 'heif'\n    WHEN 'application/pdf' THEN 'pdf'\n    ELSE NULL\n  END;\n  IF v_ext IS NULL OR length(coalesce(p_file_name,'')) < 1 OR length(p_file_name) > 180 THEN\n    RAISE EXCEPTION 'upload_type_invalid' USING ERRCODE='22023';\n  END IF;\n\n  PERFORM pg_advisory_xact_lock(hashtextextended(p_ip_hash, 0));\n  SELECT count(*) INTO v_recent FROM public.auto_unlock_upload_tickets\n   WHERE ip_hash=p_ip_hash AND created_at >= now()-interval '10 minutes';\n  SELECT count(*) INTO v_daily FROM public.auto_unlock_upload_tickets\n   WHERE ip_hash=p_ip_hash AND created_at >= now()-interval '24 hours';\n  IF v_recent >= 6 OR v_daily >= 20 THEN\n    RAISE EXCEPTION 'upload_rate_limited' USING ERRCODE='P0001';\n  END IF;\n\n  v_path := format('public-intake/%s/%s.%s',p_proof_kind,v_id,v_ext);\n  INSERT INTO public.auto_unlock_upload_tickets(id,object_path,proof_kind,declared_filename,declared_mime,declared_size,ip_hash,expires_at)\n  VALUES(v_id,v_path,p_proof_kind,left(p_file_name,180),p_mime,p_size,p_ip_hash,v_expires);\n  RETURN QUERY SELECT v_id,v_path,v_expires;\nEND;\n$function$\n","identity_arguments":"p_ip_hash text, p_proof_kind text, p_file_name text, p_mime text, p_size bigint"},{"name":"job_activity_set_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.job_activity_set_tenant()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.tenant_id IS NULL THEN\n    SELECT tenant_id INTO NEW.tenant_id FROM public.jobs WHERE id = NEW.job_id;\n  END IF;\n  RETURN NEW;\nEND $function$\n","identity_arguments":""},{"name":"job_photos_set_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.job_photos_set_tenant()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.tenant_id IS NULL THEN\n    SELECT tenant_id INTO NEW.tenant_id FROM public.jobs WHERE id = NEW.job_id;\n  END IF;\n  RETURN NEW;\nEND $function$\n","identity_arguments":""},{"name":"jobs_contact_claim_link_check","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.jobs_contact_claim_link_check()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_claim_contact_text text; v_claim_tenant_text text;\n  v_claim_contact_uuid uuid; v_claim_tenant_uuid uuid;\nBEGIN\n  IF NEW.contact_claim_id IS NULL THEN RETURN NEW; END IF;\n  SELECT contact_id, tenant_org_id INTO v_claim_contact_text, v_claim_tenant_text\n    FROM public.contact_claims WHERE id = NEW.contact_claim_id;\n  IF NOT FOUND THEN\n    RAISE EXCEPTION 'jobs.contact_claim_id %: claim not found', NEW.contact_claim_id USING ERRCODE='23503';\n  END IF;\n  BEGIN\n    v_claim_contact_uuid := v_claim_contact_text::uuid;\n    v_claim_tenant_uuid  := v_claim_tenant_text::uuid;\n  EXCEPTION WHEN others THEN\n    RAISE EXCEPTION 'jobs.contact_claim_id %: claim has non-uuid contact/tenant identifiers', NEW.contact_claim_id USING ERRCODE='23514';\n  END;\n  IF NEW.contact_id IS NULL OR v_claim_contact_uuid <> NEW.contact_id THEN\n    RAISE EXCEPTION 'jobs.contact_claim_id %: claim contact (%) does not match job contact (%)',\n      NEW.contact_claim_id, v_claim_contact_uuid, NEW.contact_id USING ERRCODE='23514';\n  END IF;\n  IF v_claim_tenant_uuid <> NEW.tenant_id THEN\n    RAISE EXCEPTION 'jobs.contact_claim_id %: claim tenant (%) does not match job tenant (%)',\n      NEW.contact_claim_id, v_claim_tenant_uuid, NEW.tenant_id USING ERRCODE='23514';\n  END IF;\n  RETURN NEW;\nEND; $function$\n","identity_arguments":""},{"name":"jobs_set_job_number","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.jobs_set_job_number()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.job_number IS NULL OR NEW.job_number = '' THEN\n    NEW.job_number := 'J-' || to_char(now(),'YYYYMMDD') || '-' || lpad(((random()*9999)::int)::text, 4, '0');\n  END IF;\n  RETURN NEW;\nEND $function$\n","identity_arguments":""},{"name":"jobs_set_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.jobs_set_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN NEW.updated_at = now(); RETURN NEW; END $function$\n","identity_arguments":""},{"name":"journal_background_job_transition","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.journal_background_job_transition()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if tg_op = 'UPDATE' then\n    if old.status is not distinct from new.status then\n      return new;\n    end if;\n  end if;\n  insert into public.platform_business_events (\n    tenant_id, event_type, event_source, actor_type, entity_type, entity_id,\n    outcome, summary, visibility, correlation_id, idempotency_key, metadata, occurred_at\n  ) values (\n    new.tenant_id, 'background_job.status_changed', new.source_app, 'system',\n    coalesce(nullif(new.entity_type,''), 'background_job'),\n    coalesce(nullif(new.entity_id,''), new.id::text),\n    case new.status when 'failed' then 'failed' when 'canceled' then 'canceled'\n      when 'completed' then 'succeeded' else 'changed' end,\n    'Background work ' || replace(new.status, '_', ' '), 'staff',\n    nullif(new.metadata->>'correlation_id', ''),\n    'background-job:' || new.id::text || ':' || new.status || ':' || new.updated_at::text,\n    jsonb_build_object('job_id', new.id, 'job_type', new.job_type, 'status', new.status),\n    new.updated_at\n  ) on conflict (tenant_id, idempotency_key) do nothing;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"journal_contact_assignment","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.journal_contact_assignment()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_row public.contact_assignments%rowtype;\n  v_action text := lower(tg_op);\nbegin\n  if tg_op = 'DELETE' then\n    v_row := old;\n  else\n    v_row := new;\n    if tg_op = 'UPDATE' and\n      new.user_id is not distinct from old.user_id and\n      new.assignment_role is not distinct from old.assignment_role and\n      new.can_edit is not distinct from old.can_edit and\n      new.can_view_notes is not distinct from old.can_view_notes\n    then\n      return new;\n    end if;\n  end if;\n\n  insert into public.platform_business_events (\n    tenant_id, event_type, event_source, actor_type, actor_user_id,\n    entity_type, entity_id, outcome, summary, visibility, idempotency_key,\n    metadata, occurred_at\n  ) values (\n    v_row.tenant_id, 'contact.assignment_' || v_action,\n    'crm', case when auth.uid() is null then 'system' else 'user' end,\n    auth.uid(), 'unified_contact', v_row.contact_id::text, 'changed',\n    'Contact responsibility ' ||\n      case when tg_op = 'INSERT' then 'assigned'\n           when tg_op = 'DELETE' then 'removed' else 'updated' end,\n    'staff',\n    'contact-assignment:' || v_row.id::text || ':' ||\n      v_action || ':' || txid_current()::text,\n    jsonb_strip_nulls(jsonb_build_object(\n      'assignment_id', v_row.id,\n      'assignee_user_id', v_row.user_id,\n      'assignment_role', v_row.assignment_role,\n      'change', v_action\n    )),\n    clock_timestamp()\n  ) on conflict (tenant_id, idempotency_key) do nothing;\n  if tg_op = 'DELETE' then return old; end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"journal_marketing_campaign_state","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.journal_marketing_campaign_state()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  if tg_op='UPDATE' then\n    if old.status is not distinct from new.status then return new; end if;\n  end if;\n  insert into public.platform_business_events (\n    tenant_id,event_type,event_source,actor_type,actor_user_id,\n    entity_type,entity_id,outcome,summary,visibility,correlation_id,\n    idempotency_key,metadata,occurred_at\n  ) values (\n    new.tenant_id,\n    'marketing_campaign.' || coalesce(nullif(new.status,''),'changed'),\n    'marketing',\n    case when new.created_by is null then 'system' else 'user' end,\n    new.created_by,\n    'marketing_campaign',new.id::text,\n    case when new.status='completed' then 'succeeded'\n      when new.status='cancelled' then 'canceled'\n      when new.status='processing' then 'started' else 'changed' end,\n    'Marketing campaign ' || replace(coalesce(new.status,'changed'),'_',' '),\n    'staff',new.id::text,\n    'marketing-run:' || new.id::text || ':' ||\n      coalesce(new.status,'') || ':' ||\n      coalesce(new.updated_at,new.created_at,now())::text,\n    jsonb_build_object('run_id',new.id,'status',new.status,\n      'total_count',new.total_count,\n      'sent_count',new.sent_count,\n      'skipped_count',new.skipped_count,\n      'failed_count',new.failed_count),\n    coalesce(new.updated_at,new.created_at,now())\n  ) on conflict (tenant_id,idempotency_key) do nothing;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"journal_pcg_lifecycle","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.journal_pcg_lifecycle()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_type text;\n  v_id uuid;\n  v_source text;\nbegin\n  if tg_table_name = 'pcg_card_lifecycle_events' then\n    v_type := 'pcg_card';\n    v_id := new.card_id;\n    v_source := 'pcg-card-lifecycle:';\n  elsif tg_table_name = 'pcg_submission_lifecycle_events' then\n    v_type := 'pcg_submission';\n    v_id := new.submission_id;\n    v_source := 'pcg-submission-lifecycle:';\n  else\n    raise exception 'Unexpected PCG lifecycle table';\n  end if;\n  if v_id is null then return new; end if;\n  insert into public.platform_business_events (\n    tenant_id,event_type,event_source,actor_type,actor_user_id,\n    entity_type,entity_id,outcome,summary,visibility,\n    idempotency_key,metadata,occurred_at\n  ) values (\n    new.tenant_id,'pcg.lifecycle.' || coalesce(nullif(new.action,''),'changed'),\n    'pcg',case when new.actor_user_id is null then 'system' else 'user' end,\n    new.actor_user_id,v_type,v_id::text,'changed',\n    'PCG lifecycle updated','staff',v_source || new.id::text,\n    jsonb_build_object('lifecycle_event_id',new.id,'action',new.action),\n    new.created_at\n  ) on conflict (tenant_id,idempotency_key) do nothing;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"journal_pcg_workflow_transition","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.journal_pcg_workflow_transition()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  insert into public.platform_business_events (\n    tenant_id, event_type, event_source, actor_type, actor_user_id,\n    entity_type, entity_id, outcome, summary, visibility, correlation_id,\n    idempotency_key, metadata, occurred_at\n  ) values (\n    new.tenant_id,\n    'pcg.workflow.' || coalesce(nullif(new.event_type,''), 'changed'),\n    'pcg',\n    case when new.actor_user_id is null then 'system' else 'user' end,\n    new.actor_user_id,\n    case when new.card_id is not null then 'pcg_card' else 'pcg_submission' end,\n    coalesce(new.card_id, new.submission_id)::text,\n    'changed',\n    'Card workflow updated',\n    'staff',\n    new.submission_id::text,\n    'pcg-workflow:' || new.id::text,\n    jsonb_strip_nulls(jsonb_build_object(\n      'workflow_event_id',new.id,\n      'submission_id',new.submission_id,\n      'card_id',new.card_id,\n      'from_status',new.from_status,\n      'to_status',new.to_status,\n      'workflow_event_type',new.event_type\n    )),\n    new.occurred_at\n  ) on conflict (tenant_id,idempotency_key) do nothing;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"kl_apply_mode_default_media","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_apply_mode_default_media(p_settings jsonb)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_settings jsonb := coalesce(p_settings, '{}'::jsonb);\n  v_modes jsonb; v_cards jsonb; v_next_cards jsonb := '[]'::jsonb; v_card jsonb;\n  v_default_key text; v_default_url text; v_image_url text; v_fallback_url text;\n  v_has_default boolean; v_custom boolean; v_any_default boolean := false;\nBEGIN\n  IF upper(coalesce(v_settings->>'shell_template','')) <> 'MODES' THEN RETURN v_settings; END IF;\n  v_modes := coalesce(v_settings->'modes', '{}'::jsonb);\n  v_cards := coalesce(v_modes->'cards', '[]'::jsonb);\n  IF jsonb_typeof(v_cards) <> 'array' THEN RETURN v_settings; END IF;\n  FOR v_card IN SELECT value FROM jsonb_array_elements(v_cards) LOOP\n    v_default_key := public.kl_mode_default_key(v_card->>'key', v_card->>'title');\n    v_default_url := public.kl_mode_default_url(v_default_key);\n    SELECT EXISTS (SELECT 1 FROM public.platform_mode_default_media d WHERE d.mode_key=v_default_key AND d.active=true) INTO v_has_default;\n    v_image_url := btrim(coalesce(v_card->>'image_url',''));\n    v_fallback_url := btrim(coalesce(v_card->>'fallback_image_url',''));\n    v_custom := btrim(coalesce(v_card->>'image_asset_id','')) <> '' OR lower(coalesce(v_card->>'image_source',''))='custom' OR (v_image_url <> '' AND position('mode=default-mode' in v_image_url)=0) OR v_fallback_url <> '';\n    IF v_has_default THEN\n      v_any_default := true;\n      IF v_custom THEN\n        v_card := v_card || jsonb_build_object('default_image_key',v_default_key,'default_image_url',v_default_url,'image_source','custom');\n      ELSE\n        v_card := v_card || jsonb_build_object('default_image_key',v_default_key,'default_image_url',v_default_url,'image_url',v_default_url,'image_source','default');\n      END IF;\n    END IF;\n    v_next_cards := v_next_cards || jsonb_build_array(v_card);\n  END LOOP;\n  IF NOT v_any_default THEN RETURN v_settings; END IF;\n  v_modes := v_modes || jsonb_build_object('cards',v_next_cards,'default_media_contract','MODE_DEFAULT_MEDIA_V1','default_media_pack_version',1,'default_media_customization',jsonb_build_object('upload_action','create_mode_card_upload','finalize_action','finalize_upload','promote_action','promote_mode_card_asset','position_action','update_mode_card_position','tenant_overrides_are_private',true));\n  RETURN jsonb_set(v_settings,'{modes}',v_modes,true);\nEND;\n$function$\n","identity_arguments":"p_settings jsonb"},{"name":"kl_assign_readable_tenant_storage_bucket","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_assign_readable_tenant_storage_bucket()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'storage', 'pg_temp'\nAS $function$\ndeclare\n  v_settings jsonb:=coalesce(new.settings,'{}'::jsonb);\n  v_configured text:=nullif(trim(coalesce(v_settings->>'storage_bucket','')),'');\n  v_scope text;\n  v_bucket text;\nbegin\n  -- Persisted bucket identity is intentionally stable across later slug edits.\n  if v_configured is not null then return new; end if;\n\n  v_scope:=public.kl_tenant_storage_scope(v_settings);\n  v_bucket:=public.kl_readable_tenant_storage_bucket(\n    new.id,\n    new.company_slug,\n    coalesce(new.company_dba_name,new.company_legal_name,new.name),\n    v_settings\n  );\n\n  new.settings:=jsonb_set(\n    jsonb_set(v_settings,'{storage_bucket}',to_jsonb(v_bucket),true),\n    '{storage_scope}',to_jsonb(v_scope),true\n  );\n  return new;\nend\n$function$\n","identity_arguments":""},{"name":"kl_is_real_tenant_media_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_is_real_tenant_media_tenant(p_tenant_id uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT coalesce(public.is_tenant_member(auth.uid(), p_tenant_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'tenant media scope access denied' USING ERRCODE = '42501';\n  END IF;\n  RETURN EXISTS(\n    SELECT 1 FROM public.tenants t\n    WHERE t.id = p_tenant_id AND t.status = 'active'\n      AND coalesce(t.settings->>'storage_scope','') <> 'demo'\n      AND coalesce(t.settings->>'workspace_mode','') <> 'prospect_demo'\n      AND coalesce((t.settings->>'internal_prospect_demo')::boolean,false) = false\n  );\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"kl_mode_default_key","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_mode_default_key(p_key text, p_title text DEFAULT NULL::text)\n RETURNS text\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_key text := trim(both '-' from regexp_replace(lower(coalesce(p_key,'')), '[^a-z0-9]+', '-', 'g'));\n  v_title text := trim(both '-' from regexp_replace(lower(coalesce(p_title,'')), '[^a-z0-9]+', '-', 'g'));\n  v text;\nBEGIN\n  FOREACH v IN ARRAY ARRAY[v_key, v_title] LOOP\n    IF v IN ('rentals','rental') THEN RETURN 'rentals'; END IF;\n    IF v IN ('events','event','booked-event') THEN RETURN 'events'; END IF;\n    IF v IN ('activations','activation') THEN RETURN 'activations'; END IF;\n    IF v IN ('vendors','vendor') THEN RETURN 'vendors'; END IF;\n    IF v IN ('financials','financial','finance','money','performance','reports','analytics') THEN RETURN 'financials'; END IF;\n    IF v IN ('planning','plan','schedule','calendar','prep','prepare') THEN RETURN 'planning'; END IF;\n    IF v IN ('growth','opportunity','opportunities','pipeline','sales','customers','customer','follow-up','followup') THEN RETURN 'growth'; END IF;\n    IF v IN ('back-office','backoffice','office','admin','administration','documents','document') THEN RETURN 'back-office'; END IF;\n    IF v IN ('field','popup','pop-up','on-site','onsite') THEN RETURN 'field'; END IF;\n    IF v IN ('operations','operation','command','today','work','work-queue','jobs','job','team','overview','focus') THEN RETURN 'operations'; END IF;\n  END LOOP;\n  RETURN 'operations';\nEND;\n$function$\n","identity_arguments":"p_key text, p_title text"},{"name":"kl_mode_default_url","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_mode_default_url(p_default_key text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\nSELECT 'https://ymntrajfubicyxwwdxxa.supabase.co/functions/v1/tenant-media-library?mode=default-mode&key=' || public.kl_mode_default_key(p_default_key, NULL) || '&v=1';\n$function$\n","identity_arguments":"p_default_key text"},{"name":"kl_proposal_version_content_immutable","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_proposal_version_content_immutable()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  if new.proposal_id is distinct from old.proposal_id or new.tenant_id is distinct from old.tenant_id or new.version is distinct from old.version or new.reason is distinct from old.reason or new.snapshot is distinct from old.snapshot or new.snapshot_hash is distinct from old.snapshot_hash or new.created_by is distinct from old.created_by or new.created_at is distinct from old.created_at then\n    raise exception 'proposal_version_content_is_immutable' using errcode='55000';\n  end if;\n  if old.render_hash is not null and (new.render_hash is distinct from old.render_hash or new.render_path is distinct from old.render_path or new.render_bucket is distinct from old.render_bucket) then\n    raise exception 'proposal_version_render_receipt_is_immutable' using errcode='55000';\n  end if;\n  return new;\nend; $function$\n","identity_arguments":""},{"name":"kl_readable_tenant_storage_bucket","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_readable_tenant_storage_bucket(p_tenant_id uuid, p_company_slug text, p_name text, p_settings jsonb)\n RETURNS text\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'storage', 'pg_temp'\nAS $function$\ndeclare\n  v_scope text := public.kl_tenant_storage_scope(coalesce(p_settings,'{}'::jsonb));\n  v_identity text;\n  v_base text;\n  v_candidate text;\nbegin\n  v_identity := lower(trim(coalesce(nullif(p_company_slug,''),nullif(p_name,''),'tenant')));\n  if v_scope='demo' then\n    v_identity:=regexp_replace(v_identity,'^demo-+','');\n  end if;\n  v_identity:=trim(both '-' from regexp_replace(v_identity,'[^a-z0-9]+','-','g'));\n  if v_identity='' then v_identity:='tenant'; end if;\n  v_base:=v_scope||'-'||left(v_identity,80);\n  v_candidate:=v_base;\n\n  if exists(\n    select 1 from public.tenants t\n    where t.id<>p_tenant_id\n      and nullif(trim(coalesce(t.settings->>'storage_bucket','')),'')=v_candidate\n  ) or exists(\n    select 1 from storage.buckets b\n    where b.id=v_candidate\n      and not exists(\n        select 1 from public.tenants t\n        where t.id=p_tenant_id\n          and nullif(trim(coalesce(t.settings->>'storage_bucket','')),'')=v_candidate\n      )\n  ) then\n    v_candidate:=v_base||'-'||left(p_tenant_id::text,8);\n  end if;\n\n  return v_candidate;\nend\n$function$\n","identity_arguments":"p_tenant_id uuid, p_company_slug text, p_name text, p_settings jsonb"},{"name":"kl_refresh_storage_registry_v3","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_refresh_storage_registry_v3()\n RETURNS TABLE(bucket_count bigint, registry_count bigint, attention_count bigint)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'storage', 'pg_temp'\nAS $function$\nbegin\n  insert into public.platform_storage_registry(bucket_id,namespace,domain,purpose,owner_tenant_id,owner_tenant_slug,canonical_path_contract,visibility,lifecycle,retention_class,managed_by,status)\n  select coalesce(t.settings->>'storage_bucket',''),case when coalesce(t.settings->>'storage_scope','tenant')='demo' or coalesce(t.settings->>'workspace_mode','')='prospect_demo' or coalesce((t.settings->>'internal_prospect_demo')::boolean,false) then 'demo' else 'tenant' end,'tenant-workspace','Canonical private storage for one tenant workspace',t.id,t.company_slug,'brand/; media/; documents/; records/; apps/; property-photos/; public-intake/; marketing/; library/','private',case when t.status='active' then 'active' else 'inactive-tenant' end,'business','tenant-storage-provisioning','active'\n  from public.tenants t where coalesce(t.settings->>'storage_bucket','')<>''\n  on conflict(bucket_id) do update set namespace=excluded.namespace,domain=excluded.domain,purpose=excluded.purpose,owner_tenant_id=excluded.owner_tenant_id,owner_tenant_slug=excluded.owner_tenant_slug,canonical_path_contract=excluded.canonical_path_contract,lifecycle=excluded.lifecycle,retention_class=excluded.retention_class,managed_by=excluded.managed_by,architecture_version='v3',updated_at=now();\n  insert into public.platform_storage_registry(bucket_id,namespace,domain,purpose,canonical_path_contract,visibility,lifecycle,retention_class,managed_by,status)\n  select b.id,case when b.id like 'platform-%' then 'platform' when b.id like 'command-center-%' then 'system' else 'legacy_pending' end,case when b.id like 'platform-%' then 'platform' when b.id like 'command-center-%' then 'observability' else 'unclassified' end,case when b.id like 'platform-%' then 'Registered platform storage' when b.id like 'command-center-%' then 'Registered system storage' else 'Unclassified bucket detected by V3 registry' end,case when b.id like 'platform-%' then 'registered platform contract' when b.id like 'command-center-%' then 'system-owned contract' else 'unclassified' end,case when b.public then 'public' else 'private' end,'active',case when b.id like 'command-center-%' then 'operational' else 'unknown' end,'storage-architecture-v3',case when b.id like 'platform-%' or b.id like 'command-center-%' then 'active' else 'unregistered' end\n  from storage.buckets b where not exists(select 1 from public.platform_storage_registry r where r.bucket_id=b.id) on conflict(bucket_id) do nothing;\n  with stats as (select b.id as bucket_id,b.public,count(o.id)::bigint as object_count,coalesce(sum(case when coalesce(o.metadata->>'size','') ~ '^[0-9]+$' then (o.metadata->>'size')::bigint else 0 end),0)::bigint as bytes from storage.buckets b left join storage.objects o on o.bucket_id=b.id group by b.id,b.public)\n  update public.platform_storage_registry r set visibility=case when s.public then 'public' else 'private' end,object_count=s.object_count,bytes=s.bytes,status=case when r.namespace='platform' and r.status='planned' then 'active' else r.status end,last_audited_at=now(),updated_at=now() from stats s where s.bucket_id=r.bucket_id;\n  return query select (select count(*)::bigint from storage.buckets),(select count(*)::bigint from public.platform_storage_registry r where exists(select 1 from storage.buckets b where b.id=r.bucket_id)),(select count(*)::bigint from public.platform_storage_registry r where exists(select 1 from storage.buckets b where b.id=r.bucket_id) and (r.namespace='legacy_pending' or r.status not in ('active','planned')));\nend;$function$\n","identity_arguments":""},{"name":"kl_refresh_tenant_media_primaries","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_refresh_tenant_media_primaries(p_tenant_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'storage', 'pg_temp'\nAS $function$\ndeclare\n  v_logo public.tenant_media_assets%rowtype;\n  v_background public.tenant_media_assets%rowtype;\n  v_media_branding jsonb;\nbegin\n  if not public.kl_is_real_tenant_media_tenant(p_tenant_id) then return; end if;\n  perform pg_advisory_xact_lock(hashtextextended('prehistoric-001:'||p_tenant_id::text,0));\n\n  update public.tenant_media_assets\n  set is_primary=false\n  where tenant_id=p_tenant_id\n    and collection_key in('branding','backgrounds')\n    and deleted_at is null\n    and is_primary=true;\n\n  select * into v_logo\n  from public.tenant_media_assets\n  where tenant_id=p_tenant_id\n    and collection_key='branding'\n    and deleted_at is null\n    and status='ready'\n    and public.kl_tenant_media_mime(coalesce(storage_key,original_key),coalesce(mime_type,original_content_type,'')) like 'image/%'\n    and not public.kl_tenant_media_generated_brand_derivative(coalesce(storage_key,original_key))\n  order by coalesce(nullif(metadata->>'storage_updated_at','')::timestamptz,updated_at,created_at) desc,\n           coalesce(storage_key,original_key) desc,\n           id desc\n  limit 1;\n  if v_logo.id is not null then\n    update public.tenant_media_assets set is_primary=true where id=v_logo.id;\n  end if;\n\n  select * into v_background\n  from public.tenant_media_assets\n  where tenant_id=p_tenant_id\n    and collection_key='backgrounds'\n    and deleted_at is null\n    and status='ready'\n    and public.kl_tenant_media_mime(coalesce(storage_key,original_key),coalesce(mime_type,original_content_type,'')) like 'image/%'\n  order by coalesce(nullif(metadata->>'storage_updated_at','')::timestamptz,updated_at,created_at) desc,\n           coalesce(storage_key,original_key) desc,\n           id desc\n  limit 1;\n  if v_background.id is not null then\n    update public.tenant_media_assets set is_primary=true where id=v_background.id;\n  end if;\n\n  select coalesce(settings->'media_branding','{}'::jsonb)\n  into v_media_branding\n  from public.tenants\n  where id=p_tenant_id\n  for update;\n  if not found then return; end if;\n\n  v_media_branding:=v_media_branding||jsonb_build_object(\n    'resolved_logo_asset_id',case when v_logo.id is null then null else v_logo.id::text end,\n    'resolved_logo_version',case when v_logo.id is null then null else coalesce(v_logo.metadata->>'storage_updated_at',v_logo.updated_at::text) end,\n    'resolved_background_asset_id',case when v_background.id is null then null else v_background.id::text end,\n    'resolved_background_version',case when v_background.id is null then null else coalesce(v_background.metadata->>'storage_updated_at',v_background.updated_at::text) end,\n    'contract','PREHISTORIC-001-TENANT-MEDIA');\n\n  update public.tenants\n  set settings=jsonb_set(coalesce(settings,'{}'::jsonb),'{media_branding}',v_media_branding,true),\n      updated_at=now()\n  where id=p_tenant_id;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"kl_sync_tenant_media_storage_object","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_sync_tenant_media_storage_object()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'storage', 'pg_temp'\nAS $function$\ndeclare\n  v_object storage.objects%rowtype;\n  v_tenant_id uuid;\n  v_old_tenant_id uuid;\n  v_collection text;\n  v_mime text;\n  v_size bigint;\n  v_preserved_id uuid;\nbegin\n  if tg_op='DELETE' then\n    v_old_tenant_id:=public.kl_tenant_media_bucket_tenant_id(old.bucket_id);\n    if v_old_tenant_id is not null then\n      update public.tenant_media_assets\n      set deleted_at=now(),published=false,is_primary=false,updated_at=now()\n      where tenant_id=v_old_tenant_id and bucket_name=old.bucket_id and original_key=old.name and deleted_at is null;\n      perform public.kl_refresh_tenant_media_primaries(v_old_tenant_id);\n    end if;\n    return old;\n  end if;\n\n  v_object:=new;\n  v_tenant_id:=public.kl_tenant_media_bucket_tenant_id(v_object.bucket_id);\n  v_mime:=public.kl_tenant_media_mime(v_object.name,coalesce(v_object.metadata->>'mimetype',v_object.metadata->>'contentType',''));\n  v_collection:=public.kl_tenant_media_collection(v_object.name);\n  begin\n    v_size:=nullif(coalesce(v_object.metadata->>'size',v_object.metadata->>'contentLength',''),'')::bigint;\n  exception when invalid_text_representation then\n    v_size:=null;\n  end;\n\n  if tg_op='UPDATE' and (old.bucket_id is distinct from new.bucket_id or old.name is distinct from new.name) then\n    v_old_tenant_id:=public.kl_tenant_media_bucket_tenant_id(old.bucket_id);\n    if v_old_tenant_id is not null\n       and v_tenant_id is not null\n       and v_old_tenant_id=v_tenant_id\n       and public.kl_tenant_media_supported(v_object.name,v_mime)\n       and coalesce(v_collection,'')<>''\n       and not (v_collection='branding' and public.kl_tenant_media_generated_brand_derivative(v_object.name)) then\n      update public.tenant_media_assets\n      set collection_key=case\n            when coalesce(metadata->>'usage','')='mode_card' then collection_key\n            else v_collection\n          end,\n          bucket_name=v_object.bucket_id,\n          original_key=v_object.name,\n          original_content_type=nullif(v_mime,''),\n          mime_type=nullif(v_mime,''),\n          size_bytes=v_size,\n          storage_provider='supabase',\n          storage_key=v_object.name,\n          is_primary=false,\n          deleted_at=null,\n          metadata=case\n            when coalesce(metadata->>'usage','')='mode_card' then\n              jsonb_build_object(\n                'existing_storage',true,\n                'existing_origin','supabase_storage',\n                'source_bucket',v_object.bucket_id,\n                'storage_object_id',v_object.id::text,\n                'storage_created_at',v_object.created_at::text,\n                'storage_updated_at',v_object.updated_at::text,\n                'contract','READABLE-TENANT-STORAGE-V2') || coalesce(metadata,'{}'::jsonb)\n            else\n              coalesce(metadata,'{}'::jsonb) || jsonb_build_object(\n                'existing_storage',true,\n                'existing_origin','supabase_storage',\n                'source_bucket',v_object.bucket_id,\n                'storage_object_id',v_object.id::text,\n                'storage_created_at',v_object.created_at::text,\n                'storage_updated_at',v_object.updated_at::text,\n                'contract','READABLE-TENANT-STORAGE-V2')\n          end,\n          updated_at=coalesce(v_object.updated_at,now())\n      where tenant_id=v_old_tenant_id\n        and bucket_name=old.bucket_id\n        and original_key=old.name\n        and deleted_at is null\n      returning id into v_preserved_id;\n      if v_preserved_id is not null then\n        perform public.kl_refresh_tenant_media_primaries(v_old_tenant_id);\n        return new;\n      end if;\n    end if;\n\n    if v_old_tenant_id is not null then\n      update public.tenant_media_assets\n      set deleted_at=now(),published=false,is_primary=false,updated_at=now()\n      where tenant_id=v_old_tenant_id and bucket_name=old.bucket_id and original_key=old.name and deleted_at is null;\n      perform public.kl_refresh_tenant_media_primaries(v_old_tenant_id);\n    end if;\n  end if;\n\n  if v_tenant_id is null then return new; end if;\n  if not public.kl_tenant_media_supported(v_object.name,v_mime) then return new; end if;\n  if coalesce(v_collection,'')='' then return new; end if;\n  if v_collection='branding' and public.kl_tenant_media_generated_brand_derivative(v_object.name) then return new; end if;\n\n  insert into public.tenant_media_assets(\n    tenant_id,collection_key,bucket_name,original_key,original_content_type,source_kind,status,review_status,published,is_primary,title,mime_type,size_bytes,storage_provider,storage_key,deleted_at,metadata,created_at,updated_at)\n  values(\n    v_tenant_id,v_collection,v_object.bucket_id,v_object.name,nullif(v_mime,''),'existing','ready','approved',true,false,\n    split_part(v_object.name,'/',array_length(string_to_array(v_object.name,'/'),1)),nullif(v_mime,''),v_size,'supabase',v_object.name,null,\n    jsonb_build_object('existing_storage',true,'existing_origin','supabase_storage','source_bucket',v_object.bucket_id,'storage_object_id',v_object.id::text,'storage_created_at',v_object.created_at::text,'storage_updated_at',v_object.updated_at::text,'contract','READABLE-TENANT-STORAGE-V2'),\n    coalesce(v_object.created_at,now()),coalesce(v_object.updated_at,now()))\n  on conflict(tenant_id,bucket_name,original_key) do update\n  set collection_key=case\n        when coalesce(tenant_media_assets.metadata->>'usage','')='mode_card' then tenant_media_assets.collection_key\n        else excluded.collection_key\n      end,\n      original_content_type=excluded.original_content_type,\n      status='ready',\n      review_status='approved',\n      published=tenant_media_assets.published,\n      mime_type=excluded.mime_type,\n      size_bytes=excluded.size_bytes,\n      storage_provider='supabase',\n      storage_key=excluded.storage_key,\n      deleted_at=null,\n      metadata=case\n        when coalesce(tenant_media_assets.metadata->>'usage','')='mode_card'\n          then excluded.metadata || coalesce(tenant_media_assets.metadata,'{}'::jsonb)\n        else coalesce(tenant_media_assets.metadata,'{}'::jsonb) || excluded.metadata\n      end,\n      updated_at=excluded.updated_at;\n  perform public.kl_refresh_tenant_media_primaries(v_tenant_id);\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"kl_tenant_media_bucket_tenant_id","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_tenant_media_bucket_tenant_id(p_bucket text)\n RETURNS uuid\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare v_id uuid;\nbegin\n  select t.id into v_id from public.tenants t where t.status='active' and public.kl_is_real_tenant_media_tenant(t.id) and nullif(trim(coalesce(t.settings->>'storage_bucket','')),'')=p_bucket limit 1;\n  if v_id is null and p_bucket ~ '^(tenant|demo)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' then\n    select t.id into v_id from public.tenants t where t.status='active' and public.kl_is_real_tenant_media_tenant(t.id) and p_bucket in ('tenant-'||t.id::text,'demo-'||t.id::text) limit 1;\n  end if;\n  return v_id;\nend $function$\n","identity_arguments":"p_bucket text"},{"name":"kl_tenant_media_collection","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_tenant_media_collection(p_name text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  select case lower(split_part(coalesce(p_name,''), '/', 1))\n    when 'brand' then case lower(split_part(coalesce(p_name,''), '/', 2))\n      when 'logos' then 'branding'\n      when 'backgrounds' then 'backgrounds'\n      else trim(both '-' from regexp_replace(lower(split_part(coalesce(p_name,''), '/', 2)), '[^a-z0-9]+', '-', 'g'))\n    end\n    when 'media' then case lower(split_part(coalesce(p_name,''), '/', 2))\n      when 'videos' then 'videos'\n      when 'modes' then case\n        when trim(both '-' from regexp_replace(lower(split_part(coalesce(p_name,''), '/', 3)), '[^a-z0-9]+', '-', 'g')) <> ''\n          then 'mode-' || trim(both '-' from regexp_replace(lower(split_part(coalesce(p_name,''), '/', 3)), '[^a-z0-9]+', '-', 'g'))\n        else 'modes'\n      end\n      else trim(both '-' from regexp_replace(lower(split_part(coalesce(p_name,''), '/', 2)), '[^a-z0-9]+', '-', 'g'))\n    end\n    when 'apps' then trim(both '-' from regexp_replace(lower(split_part(coalesce(p_name,''), '/', 2)), '[^a-z0-9]+', '-', 'g'))\n    when 'library' then trim(both '-' from regexp_replace(lower(split_part(coalesce(p_name,''), '/', 2)), '[^a-z0-9]+', '-', 'g'))\n    when 'logo' then 'branding'\n    when 'branding' then 'branding'\n    when 'background' then 'backgrounds'\n    when 'backgrounds' then 'backgrounds'\n    when 'video' then 'videos'\n    when 'videos' then 'videos'\n    when 'advertisement' then 'marketing'\n    when 'advertisements' then 'marketing'\n    when 'marketing' then 'marketing'\n    when 'documents' then 'documents'\n    when 'property-photos' then 'property-photos'\n    when 'public-intake' then 'public-intake'\n    else trim(both '-' from regexp_replace(lower(split_part(coalesce(p_name,''), '/', 1)), '[^a-z0-9]+', '-', 'g'))\n  end;\n$function$\n","identity_arguments":"p_name text"},{"name":"kl_tenant_media_generated_brand_derivative","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_tenant_media_generated_brand_derivative(p_name text)\n RETURNS boolean\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  select coalesce(p_name,'') ~* '\\.thumb-[0-9a-f]{12}\\.(webp|avif|jpe?g|png)$';\n$function$\n","identity_arguments":"p_name text"},{"name":"kl_tenant_media_mime","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_tenant_media_mime(p_name text, p_mime text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  select case\n    when nullif(trim(coalesce(p_mime,'')),'') is not null then trim(p_mime)\n    when coalesce(p_name,'') ~* '\\.png$' then 'image/png'\n    when coalesce(p_name,'') ~* '\\.jpe?g$' then 'image/jpeg'\n    when coalesce(p_name,'') ~* '\\.webp$' then 'image/webp'\n    when coalesce(p_name,'') ~* '\\.gif$' then 'image/gif'\n    when coalesce(p_name,'') ~* '\\.svg$' then 'image/svg+xml'\n    when coalesce(p_name,'') ~* '\\.avif$' then 'image/avif'\n    when coalesce(p_name,'') ~* '\\.(mp4|m4v)$' then 'video/mp4'\n    when coalesce(p_name,'') ~* '\\.mov$' then 'video/quicktime'\n    when coalesce(p_name,'') ~* '\\.webm$' then 'video/webm'\n    else '' end;\n$function$\n","identity_arguments":"p_name text, p_mime text"},{"name":"kl_tenant_media_supported","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_tenant_media_supported(p_name text, p_mime text)\n RETURNS boolean\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  select coalesce(p_name,'') !~* '(^|/)\\.keep$'\n    and public.kl_tenant_media_mime(p_name,p_mime) ~* '^(image|video)/';\n$function$\n","identity_arguments":"p_name text, p_mime text"},{"name":"kl_tenant_storage_bucket","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_tenant_storage_bucket(p_tenant_id uuid)\n RETURNS text\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select case\n    when p_tenant_id is null then null\n    when coalesce(auth.jwt()->>'role','')='service_role'\n      or public.is_system_admin(auth.uid())\n      or public.is_tenant_member(auth.uid(),p_tenant_id)\n    then (\n      select coalesce(\n        nullif(trim(coalesce(t.settings->>'storage_bucket','')),''),\n        public.kl_readable_tenant_storage_bucket(\n          t.id,t.company_slug,\n          coalesce(t.company_dba_name,t.company_legal_name,t.name),\n          coalesce(t.settings,'{}'::jsonb)\n        )\n      )\n      from public.tenants t\n      where t.id=p_tenant_id\n      limit 1\n    )\n    else null\n  end;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"kl_tenant_storage_scope","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.kl_tenant_storage_scope(p_settings jsonb)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  select case\n    when coalesce(p_settings->>'internal_prospect_demo','false')='true'\n      or coalesce(p_settings->>'workspace_mode','')='prospect_demo'\n      or coalesce(p_settings->>'storage_scope','')='demo'\n    then 'demo'\n    else 'tenant'\n  end\n$function$\n","identity_arguments":"p_settings jsonb"},{"name":"knocklaunch_invoice_allocation_append_only","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.knocklaunch_invoice_allocation_append_only()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  RAISE EXCEPTION 'invoice_allocation_history_append_only'\n    USING ERRCODE='23514';\nEND;\n$function$\n","identity_arguments":""},{"name":"knocklaunch_invoice_paid_integrity_guard","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.knocklaunch_invoice_paid_integrity_guard()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_old_status text;\nBEGIN\n  v_old_status := lower(coalesce(OLD.status, ''));\n\n  IF TG_OP = 'DELETE' THEN\n    IF v_old_status IN ('paid','partially_paid') OR OLD.paid_at IS NOT NULL OR\n       OLD.payment_provider_payment_id IS NOT NULL OR\n       coalesce(nullif(OLD.document_metadata->>'applied_payment_amount','')::numeric,0) > 0 THEN\n      RAISE EXCEPTION 'invoice_paid_history_immutable' USING ERRCODE='23514';\n    END IF;\n    RETURN OLD;\n  END IF;\n\n  IF OLD.tenant_org_id IS DISTINCT FROM NEW.tenant_org_id OR OLD.id IS DISTINCT FROM NEW.id THEN\n    RAISE EXCEPTION 'invoice_tenant_identity_immutable' USING ERRCODE='23514';\n  END IF;\n\n  IF v_old_status IN ('paid','partially_paid') OR OLD.paid_at IS NOT NULL OR\n     OLD.payment_provider_payment_id IS NOT NULL OR\n     coalesce(nullif(OLD.document_metadata->>'applied_payment_amount','')::numeric,0) > 0 THEN\n    IF OLD.invoice_id IS DISTINCT FROM NEW.invoice_id OR\n       OLD.amount IS DISTINCT FROM NEW.amount OR\n       OLD.subtotal IS DISTINCT FROM NEW.subtotal OR\n       OLD.tax_amount IS DISTINCT FROM NEW.tax_amount OR\n       OLD.tax_rate IS DISTINCT FROM NEW.tax_rate OR\n       OLD.line_items IS DISTINCT FROM NEW.line_items OR\n       OLD.invoice_date IS DISTINCT FROM NEW.invoice_date OR\n       OLD.document_kind IS DISTINCT FROM NEW.document_kind OR\n       OLD.document_subtype IS DISTINCT FROM NEW.document_subtype OR\n       OLD.payment_provider_payment_id IS DISTINCT FROM NEW.payment_provider_payment_id THEN\n      RAISE EXCEPTION 'invoice_paid_financial_fields_immutable' USING ERRCODE='23514';\n    END IF;\n  END IF;\n\n  IF (v_old_status = 'paid' OR OLD.paid_at IS NOT NULL) AND (\n      lower(coalesce(NEW.status,'')) <> 'paid' OR NEW.paid_at IS DISTINCT FROM OLD.paid_at\n  ) THEN\n    RAISE EXCEPTION 'invoice_paid_status_immutable' USING ERRCODE='23514';\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"knocklaunch_remove_orphan_profile_email_conflict","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.knocklaunch_remove_orphan_profile_email_conflict()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\nDECLARE\n  orphan_id uuid;\nBEGIN\n  IF NEW.email IS NULL OR btrim(NEW.email) = '' THEN\n    RETURN NEW;\n  END IF;\n\n  SELECT p.id\n    INTO orphan_id\n  FROM public.profiles p\n  WHERE lower(btrim(p.email)) = lower(btrim(NEW.email))\n    AND p.id <> NEW.id\n    AND NOT EXISTS (\n      SELECT 1\n      FROM auth.users au\n      WHERE au.id = p.id\n    )\n  LIMIT 1;\n\n  IF orphan_id IS NOT NULL THEN\n    UPDATE public.tenants SET owner_id = NULL WHERE owner_id = orphan_id;\n    DELETE FROM public.user_roles WHERE user_id = orphan_id;\n    DELETE FROM public.user_tenant_memberships WHERE user_id = orphan_id;\n    DELETE FROM public.profiles WHERE id = orphan_id;\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"knocklaunch_sync_auth_delete_to_profile","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.knocklaunch_sync_auth_delete_to_profile()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\nBEGIN\n  DELETE FROM public.profiles WHERE id = OLD.id;\n  RETURN OLD;\nEND;\n$function$\n","identity_arguments":""},{"name":"knocklaunch_sync_profile_delete_to_auth","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.knocklaunch_sync_profile_delete_to_auth()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\nBEGIN\n  DELETE FROM auth.users WHERE id = OLD.id;\n  RETURN OLD;\nEND;\n$function$\n","identity_arguments":""},{"name":"leave_platform_message_group","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.leave_platform_message_group(p_conversation_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare my_role text;\nbegin\n  select role into my_role from public.message_conversation_members where conversation_id=p_conversation_id and user_id=auth.uid();\n  if my_role is null or not exists(select 1 from public.message_conversations where id=p_conversation_id and kind='group') then raise exception 'group_leave_denied'; end if;\n  if my_role='owner' and (select count(*) from public.message_conversation_members where conversation_id=p_conversation_id and role='owner')<=1 then raise exception 'transfer_group_ownership_first'; end if;\n  delete from public.message_conversation_members where conversation_id=p_conversation_id and user_id=auth.uid();\n  update public.message_conversations set key_rotation_required=true,updated_at=now() where id=p_conversation_id;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid"},{"name":"limit_for_entitlement","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.limit_for_entitlement(_tenant_id uuid, _feature_key text)\n RETURNS bigint\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT coalesce(public.is_tenant_member(auth.uid(), _tenant_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'tenant entitlement limit access denied' USING ERRCODE = '42501';\n  END IF;\n  IF public.is_tenant_comped(_tenant_id) THEN RETURN NULL; END IF;\n  RETURN (\n    SELECT pf.limit_value\n    FROM public.tenant_subscriptions ts\n    JOIN public.plan_features pf ON pf.plan_id = ts.plan_id\n    WHERE ts.tenant_id = _tenant_id AND pf.feature_key = _feature_key\n    LIMIT 1\n  );\nEND;\n$function$\n","identity_arguments":"_tenant_id uuid, _feature_key text"},{"name":"link_job_to_claim","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.link_job_to_claim(_job_id uuid, _claim_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_tenant      uuid;\n  v_prev_claim  uuid;\n  v_actor_email text;\nBEGIN\n  IF auth.uid() IS NULL THEN RAISE EXCEPTION 'unauthenticated' USING ERRCODE='42501'; END IF;\n\n  SELECT tenant_id, contact_claim_id INTO v_tenant, v_prev_claim\n  FROM public.jobs WHERE id = _job_id;\n\n  IF v_tenant IS NULL THEN RAISE EXCEPTION 'job not found' USING ERRCODE='02000'; END IF;\n\n  IF NOT public._is_manager_or_higher_in_tenant(v_tenant) THEN\n    RAISE EXCEPTION 'forbidden' USING ERRCODE='42501';\n  END IF;\n\n  UPDATE public.jobs SET contact_claim_id = _claim_id WHERE id = _job_id;\n\n  SELECT email INTO v_actor_email FROM auth.users WHERE id = auth.uid();\n\n  INSERT INTO public.job_activity_log\n    (job_id, tenant_id, activity_type, actor_id, actor_email, description, metadata)\n  VALUES (\n    _job_id,\n    v_tenant,\n    'job_claim_link',\n    auth.uid(),\n    v_actor_email,\n    CASE\n      WHEN v_prev_claim IS NULL THEN 'Linked job to claim'\n      WHEN v_prev_claim = _claim_id THEN 'Re-linked job to same claim'\n      ELSE 'Re-linked job to different claim'\n    END,\n    jsonb_build_object(\n      'action', 'link',\n      'previous_claim_id', v_prev_claim,\n      'new_claim_id', _claim_id\n    )\n  );\nEND; $function$\n","identity_arguments":"_job_id uuid, _claim_id uuid"},{"name":"list_console_sessions","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_console_sessions(_query text DEFAULT NULL::text, _limit integer DEFAULT 100)\n RETURNS TABLE(session_id uuid, event_title text, session_status text, ledger_tenant_id uuid, ledger_tenant_name text, ledger_tenant_slug text, turn_count bigint, first_message text, last_message text, created_at timestamp with time zone, updated_at timestamp with time zone, last_message_at timestamp with time zone)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_query text := trim(coalesce(_query, ''));\n  v_pattern text := '%' || trim(coalesce(_query, '')) || '%';\n  v_limit integer := greatest(1, least(coalesce(_limit, 100), 250));\nbegin\n  if auth.uid() is null or not public.is_system_admin(auth.uid()) then\n    raise exception 'Platform owner required' using errcode = '42501';\n  end if;\n\n  return query\n  select\n    e.id,\n    e.title,\n    e.status,\n    e.tenant_id,\n    t.name,\n    t.company_slug,\n    (select count(*) from public.command_center_messages cm where cm.command_center_event_id = e.id),\n    fm.message,\n    lm.message,\n    e.created_at,\n    greatest(e.updated_at, coalesce(lm.created_at, e.updated_at)),\n    lm.created_at\n  from public.command_center_events e\n  left join public.tenants t on t.id = e.tenant_id\n  left join lateral (\n    select cm.message, cm.created_at\n    from public.command_center_messages cm\n    where cm.command_center_event_id = e.id\n      and (v_query = '' or cm.message ilike v_pattern)\n    order by\n      case when v_query <> '' and cm.message ilike v_pattern then 0 else 1 end,\n      cm.created_at desc\n    limit 1\n  ) fm on true\n  left join lateral (\n    select cm.message, cm.created_at\n    from public.command_center_messages cm\n    where cm.command_center_event_id = e.id\n    order by cm.created_at desc\n    limit 1\n  ) lm on true\n  where e.event_type = 'sidekick_conversation_log'\n    and (\n      v_query = ''\n      or e.title ilike v_pattern\n      or coalesce(t.name, '') ilike v_pattern\n      or coalesce(t.company_slug, '') ilike v_pattern\n      or exists (\n        select 1\n        from public.command_center_messages sm\n        where sm.command_center_event_id = e.id\n          and sm.message ilike v_pattern\n      )\n      or exists (\n        select 1\n        from public.command_center_receipts sr\n        where sr.command_center_event_id = e.id\n          and (\n            coalesce(sr.external_id, '') ilike v_pattern\n            or coalesce(sr.proof_gate, '') ilike v_pattern\n            or coalesce(sr.source_sha, '') ilike v_pattern\n            or sr.payload::text ilike v_pattern\n          )\n      )\n    )\n  order by greatest(e.updated_at, coalesce(lm.created_at, e.updated_at)) desc\n  limit v_limit;\nend;\n$function$\n","identity_arguments":"_query text, _limit integer"},{"name":"list_jobs_with_claim_payment_status","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_jobs_with_claim_payment_status(_tenant_id uuid)\n RETURNS TABLE(claim_payment_status claim_payment_lifecycle_v4, job_count bigint)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF auth.uid() IS NULL THEN RAISE EXCEPTION 'unauthenticated' USING ERRCODE='42501'; END IF;\n  IF NOT public._is_manager_or_higher_in_tenant(_tenant_id) THEN\n    RAISE EXCEPTION 'forbidden' USING ERRCODE='42501';\n  END IF;\n  RETURN QUERY\n    SELECT cc.claim_payment_status, COUNT(*)::bigint\n    FROM public.jobs j JOIN public.contact_claims cc ON cc.id = j.contact_claim_id\n    WHERE j.tenant_id = _tenant_id AND j.contact_claim_id IS NOT NULL\n    GROUP BY cc.claim_payment_status;\nEND; $function$\n","identity_arguments":"_tenant_id uuid"},{"name":"list_live_edit_sidekick_sessions","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_live_edit_sidekick_sessions(_context_tenant_id uuid, _route text, _limit integer DEFAULT 8)\n RETURNS TABLE(session_id uuid, event_title text, session_status text, created_at timestamp with time zone, updated_at timestamp with time zone, last_message_at timestamp with time zone)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_route text := left(trim(coalesce(_route, '')), 240);\n  v_limit integer := greatest(1, least(coalesce(_limit, 8), 20));\nbegin\n  if auth.uid() is null or not public.can_use_live_edit_sidekick_memory(auth.uid(), _context_tenant_id) then\n    raise exception 'Live Edit Sidekick memory access denied' using errcode = '42501';\n  end if;\n\n  return query\n  select\n    e.id,\n    e.title,\n    e.status,\n    e.created_at,\n    e.updated_at,\n    lm.created_at\n  from public.command_center_events e\n  left join lateral (\n    select cm.created_at\n    from public.command_center_messages cm\n    where cm.command_center_event_id = e.id\n    order by cm.created_at desc\n    limit 1\n  ) lm on true\n  where e.event_type = 'sidekick_conversation_log'\n    and e.created_by_user_id = auth.uid()\n    and coalesce(e.mission_context->>'sidekick_surface', '') = 'live-edit'\n    and coalesce(e.mission_context->>'context_tenant_id', '') = _context_tenant_id::text\n    and coalesce(e.mission_context->>'last_route', '') = v_route\n  order by greatest(e.updated_at, coalesce(lm.created_at, e.updated_at)) desc\n  limit v_limit;\nend;\n$function$\n","identity_arguments":"_context_tenant_id uuid, _route text, _limit integer"},{"name":"list_platform_message_conversations","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_platform_message_conversations()\n RETURNS jsonb\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select coalesce(jsonb_agg(item order by (item->>'updated_at')::timestamptz desc),'[]'::jsonb)\n  from (\n    select jsonb_build_object(\n      'id', c.id,\n      'kind', c.kind,\n      'tenant_id', c.tenant_id,\n      'title', case\n        when c.kind='tenant' then coalesce(t.company_dba_name,t.company_legal_name,t.name,'Workspace')\n        when c.kind='direct' then coalesce(nullif(other_names.names,''),'Conversation')\n        else coalesce(nullif(c.title,''),nullif(other_names.names,''),'Group')\n      end,\n      'updated_at', greatest(c.updated_at, coalesce(last_message.created_at,c.created_at)),\n      'last_message', coalesce(last_message.body,''),\n      'last_message_at', last_message.created_at,\n      'unread_count', coalesce(unread.count,0)\n    ) item\n    from public.message_conversations c\n    join public.message_conversation_members mine on mine.conversation_id=c.id and mine.user_id=auth.uid()\n    left join public.tenants t on t.id=c.tenant_id\n    left join lateral (\n      select string_agg(coalesce(nullif(trim(p.name),''),'KNOCKLAUNCH User'), ', ' order by p.name) names\n      from public.message_conversation_members cm\n      left join public.profiles p on p.id=cm.user_id\n      where cm.conversation_id=c.id and cm.user_id<>auth.uid()\n    ) other_names on true\n    left join lateral (\n      select m.body,m.created_at\n      from public.messages m\n      where m.conversation_id=c.id and m.deleted_at is null\n      order by m.created_at desc limit 1\n    ) last_message on true\n    left join lateral (\n      select count(*)::int count\n      from public.messages m\n      where m.conversation_id=c.id\n        and m.sender_id<>auth.uid()\n        and m.created_at>coalesce(mine.last_read_at,mine.joined_at)\n        and m.deleted_at is null\n    ) unread on true\n  ) rows;\n$function$\n","identity_arguments":""},{"name":"list_platform_message_conversations_v2","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_platform_message_conversations_v2()\n RETURNS jsonb\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nselect coalesce(jsonb_agg(item order by (item->>'pinned_at')::timestamptz desc nulls last,(item->>'updated_at')::timestamptz desc),'[]'::jsonb)\nfrom (\n  select jsonb_build_object(\n    'id',c.id,'kind',c.kind,'tenant_id',c.tenant_id,\n    'title',case when c.kind='tenant' then coalesce(t.company_dba_name,t.company_legal_name,t.name,'Workspace')\n      when c.kind='direct' then coalesce(nullif(other_names.names,''),'Conversation')\n      else coalesce(nullif(c.title,''),nullif(other_names.names,''),'Group') end,\n    'updated_at',greatest(c.updated_at,coalesce(last_message.created_at,c.created_at)),\n    'last_message',case when last_message.encrypted_payload is not null then 'Encrypted message' else coalesce(last_message.body,'') end,\n    'last_message_at',last_message.created_at,'unread_count',coalesce(unread.count,0),\n    'folder_id',pref.folder_id,'folder_name',folder.name,'labels',coalesce(pref.labels,array[]::text[]),\n    'archived_at',pref.archived_at,'pinned_at',pref.pinned_at,'muted_at',coalesce(pref.muted_at,mine.muted_at),\n    'encryption_enabled',c.encryption_enabled,'current_key_version',c.current_key_version,'key_rotation_required',c.key_rotation_required\n  ) item\n  from public.message_conversations c\n  join public.message_conversation_members mine on mine.conversation_id=c.id and mine.user_id=auth.uid()\n  left join public.message_conversation_preferences pref on pref.conversation_id=c.id and pref.user_id=auth.uid()\n  left join public.message_folders folder on folder.id=pref.folder_id and folder.user_id=auth.uid()\n  left join public.tenants t on t.id=c.tenant_id\n  left join lateral (\n    select string_agg(coalesce(nullif(trim(p.name),''),'KNOCKLAUNCH User'),', ' order by p.name) names\n    from public.message_conversation_members cm left join public.profiles p on p.id=cm.user_id\n    where cm.conversation_id=c.id and cm.user_id<>auth.uid()\n  ) other_names on true\n  left join lateral (\n    select m.body,m.encrypted_payload,m.created_at from public.messages m\n    where m.conversation_id=c.id and m.deleted_at is null order by m.created_at desc limit 1\n  ) last_message on true\n  left join lateral (\n    select count(*)::int count from public.messages m where m.conversation_id=c.id and m.sender_id<>auth.uid()\n      and m.created_at>coalesce(mine.last_read_at,mine.joined_at) and m.deleted_at is null\n  ) unread on true\n) rows;\n$function$\n","identity_arguments":""},{"name":"list_platform_message_folders","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_platform_message_folders()\n RETURNS jsonb\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select coalesce(jsonb_agg(jsonb_build_object('id',id,'name',name,'position',position) order by position,name),'[]'::jsonb)\n  from public.message_folders where user_id=auth.uid();\n$function$\n","identity_arguments":""},{"name":"list_platform_message_key_envelopes","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_platform_message_key_envelopes(p_conversation_id uuid, p_device_id text)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare result jsonb;\nbegin\n  if not public.can_access_message_conversation(p_conversation_id,auth.uid()) then raise exception 'message_conversation_access_denied'; end if;\n  select coalesce(jsonb_agg(jsonb_build_object(\n    'conversation_id',conversation_id,'key_version',key_version,'device_id',device_id,\n    'sender_device_id',sender_device_id,'sender_public_key',sender_public_key,\n    'wrapped_key',wrapped_key,'wrap_nonce',wrap_nonce\n  ) order by key_version),'[]'::jsonb) into result\n  from public.message_conversation_key_envelopes\n  where conversation_id=p_conversation_id and user_id=auth.uid() and device_id=p_device_id;\n  return result;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_device_id text"},{"name":"list_platform_message_members","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_platform_message_members(p_conversation_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare result jsonb;\nbegin\n  if not public.can_access_message_conversation(p_conversation_id,auth.uid()) then raise exception 'message_conversation_access_denied'; end if;\n  select coalesce(jsonb_agg(jsonb_build_object('user_id',m.user_id,'role',m.role,'display_name',coalesce(nullif(trim(p.name),''),'KNOCKLAUNCH User'),'joined_at',m.joined_at) order by m.joined_at),'[]'::jsonb)\n    into result from public.message_conversation_members m left join public.profiles p on p.id=m.user_id\n    where m.conversation_id=p_conversation_id;\n  return result;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid"},{"name":"list_platform_message_recipient_devices","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_platform_message_recipient_devices(p_conversation_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare result jsonb;\nbegin\n  if not public.can_access_message_conversation(p_conversation_id,auth.uid()) then raise exception 'message_conversation_access_denied'; end if;\n  select coalesce(jsonb_agg(jsonb_build_object(\n    'user_id',m.user_id,'role',m.role,'display_name',coalesce(nullif(trim(p.name),''),'KNOCKLAUNCH User'),\n    'device_id',d.device_id,'public_key',d.public_key\n  ) order by m.joined_at,d.created_at),'[]'::jsonb)\n  into result\n  from public.message_conversation_members m\n  left join public.profiles p on p.id=m.user_id\n  left join public.message_device_keys d on d.user_id=m.user_id and d.revoked_at is null\n  where m.conversation_id=p_conversation_id;\n  return result;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid"},{"name":"list_platform_messages","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_platform_messages(p_conversation_id uuid, p_limit integer DEFAULT 80, p_before timestamp with time zone DEFAULT NULL::timestamp with time zone)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare result jsonb;\nbegin\n  if not public.can_access_message_conversation(p_conversation_id, auth.uid()) then\n    raise exception 'message_conversation_access_denied';\n  end if;\n  select coalesce(jsonb_agg(row_data order by (row_data->>'created_at')::timestamptz),'[]'::jsonb)\n  into result\n  from (\n    select jsonb_build_object(\n      'id',m.id,'conversation_id',m.conversation_id,'sender_id',m.sender_id,\n      'sender_name',coalesce(nullif(trim(p.name),''),'KNOCKLAUNCH User'),\n      'body',case when m.deleted_at is null then m.body else '' end,\n      'reply_to_id',m.reply_to_id,'context',case when m.deleted_at is null then m.context else null end,\n      'created_at',m.created_at,'edited_at',m.edited_at,'deleted_at',m.deleted_at,\n      'reactions',coalesce((select jsonb_agg(jsonb_build_object('emoji',r.emoji,'user_id',r.user_id))\n                            from public.message_reactions r where r.message_id=m.id),'[]'::jsonb),\n      'attachments',coalesce((select jsonb_agg(jsonb_build_object(\n          'id',a.id,'bucket_name',a.bucket_name,'storage_path',a.storage_path,\n          'file_name',a.file_name,'mime_type',a.mime_type,'size_bytes',a.size_bytes))\n        from public.message_attachments a where a.message_id=m.id),'[]'::jsonb)\n    ) row_data\n    from public.messages m\n    left join public.profiles p on p.id=m.sender_id\n    where m.conversation_id=p_conversation_id\n      and (p_before is null or m.created_at<p_before)\n    order by m.created_at desc\n    limit least(greatest(coalesce(p_limit,80),1),150)\n  ) q;\n  return result;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_limit integer, p_before timestamp with time zone"},{"name":"list_platform_messages_v2","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_platform_messages_v2(p_conversation_id uuid, p_limit integer DEFAULT 100, p_before timestamp with time zone DEFAULT NULL::timestamp with time zone)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare result jsonb;\nbegin\n  if not public.can_access_message_conversation(p_conversation_id,auth.uid()) then raise exception 'message_conversation_access_denied'; end if;\n  select coalesce(jsonb_agg(row_data order by (row_data->>'created_at')::timestamptz),'[]'::jsonb) into result from (\n    select jsonb_build_object(\n      'id',m.id,'conversation_id',m.conversation_id,'sender_id',m.sender_id,\n      'sender_name',coalesce(nullif(trim(p.name),''),'KNOCKLAUNCH User'),\n      'body',case when m.deleted_at is null and m.encrypted_payload is null then m.body else '' end,\n      'encrypted_payload',case when m.deleted_at is null then m.encrypted_payload else null end,\n      'encryption_nonce',case when m.deleted_at is null then m.encryption_nonce else null end,\n      'encryption_alg',m.encryption_alg,'key_version',m.key_version,\n      'reply_to_id',m.reply_to_id,'context',case when m.deleted_at is null then m.context else null end,\n      'created_at',m.created_at,'edited_at',m.edited_at,'deleted_at',m.deleted_at,\n      'reactions',coalesce((select jsonb_agg(jsonb_build_object('emoji',r.emoji,'user_id',r.user_id)) from public.message_reactions r where r.message_id=m.id),'[]'::jsonb),\n      'attachments',coalesce((select jsonb_agg(jsonb_build_object(\n        'id',a.id,'conversation_id',a.conversation_id,'bucket_name',a.bucket_name,'storage_path',a.storage_path,\n        'file_name',a.file_name,'mime_type',a.mime_type,'size_bytes',a.size_bytes,\n        'encrypted_metadata',a.encrypted_metadata,'encryption_nonce',a.encryption_nonce,'key_version',a.key_version\n      )) from public.message_attachments a where a.message_id=m.id),'[]'::jsonb)\n    ) row_data\n    from public.messages m left join public.profiles p on p.id=m.sender_id\n    where m.conversation_id=p_conversation_id and (p_before is null or m.created_at<p_before)\n    order by m.created_at desc limit least(greatest(coalesce(p_limit,100),1),150)\n  ) q;\n  return result;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_limit integer, p_before timestamp with time zone"},{"name":"list_platform_messages_v3","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_platform_messages_v3(p_conversation_id uuid, p_limit integer DEFAULT 100, p_before timestamp with time zone DEFAULT NULL::timestamp with time zone)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare result jsonb; admin_review boolean; retention_key text;\nbegin\n  if not public.can_access_message_conversation(p_conversation_id,auth.uid())\n     and not public.can_review_deleted_message_conversation(p_conversation_id,auth.uid()) then\n    raise exception 'message_conversation_access_denied';\n  end if;\n  admin_review:=public.can_review_deleted_message_conversation(p_conversation_id,auth.uid());\n  if admin_review then select archive_key into retention_key from public.message_retention_config where singleton=true; end if;\n\n  select coalesce(jsonb_agg(row_data order by (row_data->>'created_at')::timestamptz),'[]'::jsonb) into result\n  from (\n    select jsonb_build_object(\n      'id',m.id,'conversation_id',m.conversation_id,'sender_id',m.sender_id,\n      'sender_name',coalesce(nullif(trim(p.name),''),'KNOCKLAUNCH User'),\n      'body',case\n        when m.deleted_at is not null and admin_review and r.message_id is not null\n          then extensions.pgp_sym_decrypt(r.retained_body_cipher,retention_key)\n        when m.deleted_at is null and m.encrypted_payload is null then m.body\n        else ''\n      end,\n      'encrypted_payload',case when m.deleted_at is null then m.encrypted_payload else null end,\n      'encryption_nonce',case when m.deleted_at is null then m.encryption_nonce else null end,\n      'encryption_alg',case when m.deleted_at is null then m.encryption_alg else null end,\n      'key_version',case when m.deleted_at is null then m.key_version else null end,\n      'reply_to_id',m.reply_to_id,\n      'context',case when m.deleted_at is null then m.context when admin_review then r.retained_context else null end,\n      'created_at',m.created_at,'edited_at',m.edited_at,'deleted_at',m.deleted_at,\n      'retained_deleted',(m.deleted_at is not null and admin_review),\n      'deleted_by',case when admin_review then r.deleted_by else null end,\n      'deleted_retained_at',case when admin_review then r.deleted_at else null end,\n      'reactions',case when m.deleted_at is null then coalesce((select jsonb_agg(jsonb_build_object('emoji',x.emoji,'user_id',x.user_id)) from public.message_reactions x where x.message_id=m.id),'[]'::jsonb) else '[]'::jsonb end,\n      'attachments',case\n        when m.deleted_at is null then coalesce((select jsonb_agg(jsonb_build_object(\n          'id',a.id,'conversation_id',a.conversation_id,'bucket_name',a.bucket_name,'storage_path',a.storage_path,\n          'file_name',a.file_name,'mime_type',a.mime_type,'size_bytes',a.size_bytes,\n          'encrypted_metadata',a.encrypted_metadata,'encryption_nonce',a.encryption_nonce,'key_version',a.key_version\n        )) from public.message_attachments a where a.message_id=m.id),'[]'::jsonb)\n        when admin_review then coalesce(r.attachment_manifest,'[]'::jsonb)\n        else '[]'::jsonb\n      end\n    ) row_data\n    from public.messages m\n    left join public.profiles p on p.id=m.sender_id\n    left join public.message_deleted_retention r on r.message_id=m.id\n    where m.conversation_id=p_conversation_id\n      and (p_before is null or m.created_at<p_before)\n      and (m.deleted_at is null or admin_review)\n    order by m.created_at desc\n    limit least(greatest(coalesce(p_limit,100),1),150)\n  ) q;\n  return result;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_limit integer, p_before timestamp with time zone"},{"name":"list_projection_users_for_tenants","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.list_projection_users_for_tenants(_tenant_ids uuid[])\n RETURNS TABLE(user_id uuid, tenant_id uuid, effective_role text, role text, is_owner boolean, membership_status text, has_membership boolean, name text, email text)\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  with access_rows as (\n    select\n      coalesce(r.user_id, m.user_id) as user_id,\n      coalesce(r.tenant_id, m.tenant_id) as tenant_id,\n      r.role::text as role,\n      coalesce(m.is_owner, false) as is_owner,\n      coalesce(m.status, 'active'::text) as membership_status,\n      m.user_id is not null as has_membership,\n      coalesce(\n        r.role::text,\n        case when m.is_owner then 'Tenant Owner'::text else 'Rep'::text end\n      ) as effective_role\n    from public.user_roles r\n    full join public.user_tenant_memberships m\n      on r.user_id = m.user_id and r.tenant_id = m.tenant_id\n  )\n  select\n    a.user_id,\n    a.tenant_id,\n    a.effective_role,\n    a.role,\n    a.is_owner,\n    a.membership_status,\n    a.has_membership,\n    coalesce(p.name, p.email, 'Tenant user')::text as name,\n    coalesce(p.email, '')::text as email\n  from access_rows a\n  left join public.profiles p on p.id = a.user_id\n  where (\n      public.is_system_admin(auth.uid())\n      or (\n        auth.uid() is not null\n        and lower(coalesce(auth.jwt() ->> 'email', '')) in (\n          'info@knocklaunch.app',\n          'noelmal2289@gmail.com'\n        )\n      )\n    )\n    and a.user_id is not null\n    and a.tenant_id is not null\n    and a.tenant_id = any(coalesce(_tenant_ids, array[]::uuid[]))\n    and a.has_membership = true\n    and a.membership_status = 'active';\n$function$\n","identity_arguments":"_tenant_ids uuid[]"},{"name":"live_edit_operations_safe","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.live_edit_operations_safe(_operations jsonb)\n RETURNS boolean\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$ declare _operation jsonb;_action text;_component_key text;_property_key text;_property_name text;_value text;_device text; begin if _operations is null or jsonb_typeof(_operations)<>'array' or jsonb_array_length(_operations)>200 then return false;end if;for _operation in select value from jsonb_array_elements(_operations) loop if jsonb_typeof(_operation)<>'object' then return false;end if;_action:=coalesce(_operation->>'action','');_component_key:=coalesce(_operation#>>'{audit,componentKey}','');_property_key:=coalesce(_operation#>>'{audit,propertyKey}','');_value:=coalesce(_operation->>'value','');_device:=coalesce(_operation->>'device','all');if _action not in('text','visibility','order','style','attribute') or coalesce(_operation#>>'{audit,source}','')<>'live-edit' or _component_key!~'^[A-Za-z0-9_.:-]{1,120}$' or _property_key!~'^[A-Za-z0-9_.:-]{1,120}$' or length(_value)>16000 or _device not in('all','desktop','mobile') then return false;end if;if _action='text' and not(_property_key='self' or _property_key~'^text\\.[0-9]+$') then return false;end if;if _action='visibility' and _property_key<>'visibility' then return false;end if;if _action='order' and _property_key<>'order' then return false;end if;if _action='style' then if _property_key!~'^style\\.[0-9]+\\.[A-Za-z0-9-]+$' then return false;end if;_property_name:=regexp_replace(_property_key,'^style\\.[0-9]+\\.','');if _property_name not in('color','backgroundColor','opacity','borderColor','borderWidth','borderStyle','borderRadius','boxShadow','width','height','minWidth','maxWidth','minHeight','maxHeight','padding','margin','gap','fontSize','fontWeight','lineHeight','letterSpacing','textAlign','display','flexDirection','justifyContent','alignItems','objectFit','overflow') then return false;end if;end if;if _action='attribute' then if _property_key!~'^attr\\.[0-9]+\\.[A-Za-z0-9-]+$' then return false;end if;_property_name:=regexp_replace(_property_key,'^attr\\.[0-9]+\\.','');if _property_name not in('href','target','src','alt','title','aria-label') then return false;end if;if _property_name in('href','src') and _value<>'' and _value!~*'^(https?:|mailto:|tel:|/|#|data:image/)' then return false;end if;if _property_name='target' and _value not in('','_self','_blank') then return false;end if;end if;end loop;return true;end;$function$\n","identity_arguments":"_operations jsonb"},{"name":"log_activity_timeline","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.log_activity_timeline(p_tenant_org_id uuid, p_contact_id uuid, p_user_id uuid, p_activity_type text, p_title text, p_description text DEFAULT NULL::text, p_metadata jsonb DEFAULT '{}'::jsonb, p_related_entity_type text DEFAULT NULL::text, p_related_entity_id uuid DEFAULT NULL::uuid, p_importance text DEFAULT 'normal'::text, p_is_system boolean DEFAULT false)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare v_actor uuid; v_system boolean;\nbegin\n  perform public.business_activity_assert_tenant_access(p_tenant_org_id);\n  v_actor := case when coalesce(auth.role(),'')='service_role' then p_user_id else auth.uid() end;\n  v_system := case when coalesce(auth.role(),'')='service_role' then p_is_system else false end;\n  return public.business_activity_project(p_tenant_org_id,p_activity_type,p_title,\n    jsonb_build_object('contact_id',p_contact_id,'actor_user_id',v_actor,'description',p_description,'metadata',coalesce(p_metadata,'{}'::jsonb),\n      'related_entity_type',p_related_entity_type,'related_entity_id',p_related_entity_id,'importance',p_importance,'is_system_generated',v_system,\n      'event_domain',coalesce(nullif(p_metadata->>'event_domain',''),'activity'),'source_channel',coalesce(p_metadata->>'source_channel',p_metadata->>'source'),\n      'touch_channel',p_metadata->>'touch_channel','source_detail',p_metadata->>'source_detail','source_campaign',coalesce(p_metadata->>'source_campaign',p_metadata->>'campaign'),\n      'source_referrer',coalesce(p_metadata->>'source_referrer',p_metadata->>'referrer'),'correlation_key',coalesce(p_metadata->>'correlation_key',case when p_contact_id is not null then 'contact:'||p_contact_id::text else null end),\n      'source_system',coalesce(p_metadata->>'source_system','knocklaunch'),'source_record_type',coalesce(p_metadata->>'source_record_type','legacy_activity')));\nend;\n$function$\n","identity_arguments":"p_tenant_org_id uuid, p_contact_id uuid, p_user_id uuid, p_activity_type text, p_title text, p_description text, p_metadata jsonb, p_related_entity_type text, p_related_entity_id uuid, p_importance text, p_is_system boolean"},{"name":"log_audit_event","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.log_audit_event(p_user_id uuid DEFAULT NULL::uuid, p_user_email text DEFAULT NULL::text, p_user_name text DEFAULT NULL::text, p_tenant_id uuid DEFAULT NULL::uuid, p_event_type text DEFAULT 'system'::text, p_event_category text DEFAULT 'system'::text, p_event_action text DEFAULT 'unknown'::text, p_resource_type text DEFAULT NULL::text, p_resource_id text DEFAULT NULL::text, p_resource_name text DEFAULT NULL::text, p_old_value jsonb DEFAULT NULL::jsonb, p_new_value jsonb DEFAULT NULL::jsonb, p_metadata jsonb DEFAULT '{}'::jsonb, p_ip_address text DEFAULT NULL::text, p_user_agent text DEFAULT NULL::text, p_session_id text DEFAULT NULL::text, p_success boolean DEFAULT true, p_error_message text DEFAULT NULL::text, p_severity text DEFAULT 'info'::text)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_log_id uuid;\n  v_request_user uuid := public.request_user_id();\n  v_claims text := nullif(current_setting('request.jwt.claims', true), '');\n  v_role text := nullif(current_setting('request.jwt.claim.role', true), '');\n  v_request_email text;\n  v_platform_admin boolean := false;\nbegin\n  if v_claims is not null then\n    v_role := coalesce(v_role, nullif((v_claims::jsonb) ->> 'role', ''));\n    v_request_email := nullif((v_claims::jsonb) ->> 'email', '');\n  end if;\n\n  if coalesce(v_role, '') <> 'service_role' then\n    if v_request_user is null then\n      raise exception 'authenticated audit caller required'\n        using errcode = '42501';\n    end if;\n\n    v_platform_admin := coalesce(public.is_platform_admin(v_request_user), false);\n\n    if p_user_id is not null\n       and p_user_id <> v_request_user\n       and not v_platform_admin then\n      raise exception 'audit user mismatch'\n        using errcode = '42501';\n    end if;\n\n    if p_tenant_id is not null\n       and not v_platform_admin\n       and not coalesce(public.is_tenant_member(v_request_user, p_tenant_id), false) then\n      raise exception 'audit tenant access denied'\n        using errcode = '42501';\n    end if;\n\n    if not v_platform_admin or p_user_id is null then\n      p_user_id := v_request_user;\n    end if;\n    p_user_email := coalesce(v_request_email, p_user_email);\n  end if;\n\n  insert into public.comprehensive_audit_logs (\n    user_id, user_email, user_name, tenant_id,\n    event_type, event_category, event_action,\n    resource_type, resource_id, resource_name,\n    old_value, new_value, metadata,\n    ip_address, user_agent, session_id,\n    success, error_message, severity,\n    request_id\n  ) values (\n    p_user_id, p_user_email, p_user_name, p_tenant_id,\n    p_event_type, p_event_category, p_event_action,\n    p_resource_type, p_resource_id, p_resource_name,\n    p_old_value, p_new_value, p_metadata,\n    p_ip_address, p_user_agent, p_session_id,\n    p_success, p_error_message, p_severity,\n    gen_random_uuid()::text\n  )\n  returning id into v_log_id;\n\n  return v_log_id;\nend;\n$function$\n","identity_arguments":"p_user_id uuid, p_user_email text, p_user_name text, p_tenant_id uuid, p_event_type text, p_event_category text, p_event_action text, p_resource_type text, p_resource_id text, p_resource_name text, p_old_value jsonb, p_new_value jsonb, p_metadata jsonb, p_ip_address text, p_user_agent text, p_session_id text, p_success boolean, p_error_message text, p_severity text"},{"name":"log_call_attempt","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.log_call_attempt(p_tenant_id text, p_lead_id text, p_phone text, p_phone_normalized text, p_rep_id uuid, p_attempt_type text, p_outcome text DEFAULT NULL::text, p_was_inbound boolean DEFAULT false, p_call_log_id uuid DEFAULT NULL::uuid)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE v_id UUID;\nBEGIN\n  INSERT INTO public.call_attempts_log (tenant_org_id, lead_id, phone_number, phone_normalized, rep_id, attempt_type, outcome, was_inbound, call_log_id)\n  VALUES (p_tenant_id, p_lead_id, p_phone, p_phone_normalized, p_rep_id, p_attempt_type, p_outcome, p_was_inbound, p_call_log_id)\n  RETURNING id INTO v_id;\n  RETURN v_id;\nEND; $function$\n","identity_arguments":"p_tenant_id text, p_lead_id text, p_phone text, p_phone_normalized text, p_rep_id uuid, p_attempt_type text, p_outcome text, p_was_inbound boolean, p_call_log_id uuid"},{"name":"log_comm_mode_change","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.log_comm_mode_change()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF OLD.mode IS DISTINCT FROM NEW.mode THEN\n    INSERT INTO public.mode_change_log (from_mode, to_mode, reason, changed_by, changed_by_email)\n    VALUES (OLD.mode, NEW.mode, NEW.reason, NEW.updated_by, NEW.updated_by_email);\n  END IF;\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"log_realtor_assignment_change","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.log_realtor_assignment_change()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_tenant_uuid uuid;\n  v_is_realtor boolean := false;\nBEGIN\n  IF NEW.tenant_org_id IS NULL THEN\n    RETURN NEW;\n  END IF;\n\n  SELECT EXISTS (\n    SELECT 1\n    FROM public.tenants t\n    WHERE t.id::text = NEW.tenant_org_id\n      AND upper(coalesce(t.tenant_type,'')) = 'REALTOR'\n  )\n  INTO v_is_realtor;\n\n  IF NOT v_is_realtor THEN\n    RETURN NEW;\n  END IF;\n\n  IF COALESCE(NEW.assigned_user,'') = COALESCE(OLD.assigned_user,'') THEN\n    RETURN NEW;\n  END IF;\n\n  v_tenant_uuid := public.try_cast_uuid(NEW.tenant_org_id);\n  IF v_tenant_uuid IS NULL THEN\n    RETURN NEW;\n  END IF;\n\n  INSERT INTO public.realtor_lead_assignments (\n    tenant_id, lead_id, previous_assigned_user_id, new_assigned_user_id, changed_by, reason\n  ) VALUES (\n    v_tenant_uuid,\n    NEW.id,\n    public.try_cast_uuid(OLD.assigned_user),\n    public.try_cast_uuid(NEW.assigned_user),\n    auth.uid(),\n    NULL\n  );\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"log_shared_claim_claim_stage_change","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.log_shared_claim_claim_stage_change()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_participant RECORD;\n  v_member RECORD;\n  v_actor_name TEXT;\nBEGIN\n  IF OLD.claim_stage IS DISTINCT FROM NEW.claim_stage THEN\n    SELECT name INTO v_actor_name FROM profiles WHERE id = auth.uid() LIMIT 1;\n    \n    INSERT INTO shared_claim_activity (shared_claim_id, actor_tenant_id, actor_user_id, activity_type, field_changed, old_value, new_value, metadata)\n    VALUES (NEW.id, NEW.created_by_tenant_id, auth.uid(), 'stage_change', 'claim_stage', OLD.claim_stage, NEW.claim_stage,\n      jsonb_build_object('actor_name', v_actor_name));\n\n    FOR v_participant IN \n      SELECT scp.tenant_id FROM shared_claim_participants scp \n      WHERE scp.shared_claim_id = NEW.id AND scp.status = 'accepted'\n    LOOP\n      FOR v_member IN\n        SELECT utm.user_id FROM user_tenant_memberships utm\n        WHERE utm.tenant_id = v_participant.tenant_id AND utm.status = 'active'\n      LOOP\n        INSERT INTO notification_queue (user_id, title, message, notification_type, severity, metadata, created_at)\n        VALUES (\n          v_member.user_id,\n          'Shared Claim Stage Updated',\n          'Claim stage changed to: ' || COALESCE(NEW.claim_stage, 'Unknown'),\n          'shared_claim_update',\n          'info',\n          jsonb_build_object('shared_claim_id', NEW.id, 'field', 'claim_stage', 'new_value', NEW.claim_stage, 'actor_name', v_actor_name),\n          now()\n        );\n      END LOOP;\n    END LOOP;\n  END IF;\n  \n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"log_shared_claim_stage_change","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.log_shared_claim_stage_change()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_participant RECORD;\n  v_member RECORD;\n  v_actor_name TEXT;\nBEGIN\n  IF OLD.jobs_stage IS DISTINCT FROM NEW.jobs_stage THEN\n    SELECT name INTO v_actor_name FROM profiles WHERE id = auth.uid() LIMIT 1;\n    \n    -- Log activity\n    INSERT INTO shared_claim_activity (shared_claim_id, actor_tenant_id, actor_user_id, activity_type, field_changed, old_value, new_value, metadata)\n    VALUES (NEW.shared_claim_id, NEW.tenant_id, auth.uid(), 'stage_change', 'jobs_stage', OLD.jobs_stage, NEW.jobs_stage, \n      jsonb_build_object('tenant_id', NEW.tenant_id, 'actor_name', v_actor_name));\n\n    -- Notify all users in OTHER participant tenants via notification_queue\n    FOR v_participant IN \n      SELECT scp.tenant_id FROM shared_claim_participants scp \n      WHERE scp.shared_claim_id = NEW.shared_claim_id AND scp.tenant_id != NEW.tenant_id AND scp.status = 'accepted'\n    LOOP\n      FOR v_member IN\n        SELECT utm.user_id FROM user_tenant_memberships utm\n        WHERE utm.tenant_id = v_participant.tenant_id AND utm.status = 'active'\n      LOOP\n        INSERT INTO notification_queue (user_id, title, message, notification_type, severity, metadata, created_at)\n        VALUES (\n          v_member.user_id,\n          'Shared Claim Update',\n          'Partner updated job stage to: ' || COALESCE(NEW.jobs_stage, 'Unknown'),\n          'shared_claim_update',\n          'info',\n          jsonb_build_object('shared_claim_id', NEW.shared_claim_id, 'field', 'jobs_stage', 'new_value', NEW.jobs_stage, 'actor_name', v_actor_name),\n          now()\n        );\n      END LOOP;\n    END LOOP;\n  END IF;\n  \n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"log_supabase_auth_event","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.log_supabase_auth_event()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_ip TEXT;\nBEGIN\n  -- Try multiple metadata paths for IP\n  v_ip := COALESCE(\n    NEW.raw_app_meta_data->>'ip',\n    NEW.raw_app_meta_data->>'request_ip',\n    current_setting('request.headers', true)::json->>'x-forwarded-for',\n    current_setting('request.headers', true)::json->>'cf-connecting-ip',\n    NULL\n  );\n\n  -- Treat 'unknown' as NULL\n  IF v_ip = 'unknown' OR v_ip = '' THEN\n    v_ip := NULL;\n  END IF;\n\n  INSERT INTO public.security_events (\n    event_type, user_id, email, ip_address, user_agent, metadata, severity, success, timestamp\n  ) VALUES (\n    'auth.login', NEW.id, NEW.email, v_ip,\n    COALESCE(NEW.raw_app_meta_data->>'user_agent', NULL),\n    jsonb_build_object('provider', COALESCE(NEW.raw_app_meta_data->>'provider', 'email'), 'login_at', NEW.last_sign_in_at),\n    'low', true, NOW()\n  );\n  \n  UPDATE public.profiles SET last_login_at = NEW.last_sign_in_at WHERE id = NEW.id;\n  \n  RETURN NEW;\nEXCEPTION WHEN OTHERS THEN\n  RAISE WARNING 'log_supabase_auth_event error: %', SQLERRM;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"log_user_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.log_user_activity(p_activity_type text, p_title text, p_description text DEFAULT NULL::text, p_contact_id uuid DEFAULT NULL::uuid, p_metadata jsonb DEFAULT NULL::jsonb)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_user_id UUID;\n  v_tenant_id TEXT;\n  v_activity_id UUID;\nBEGIN\n  -- Get current user\n  v_user_id := auth.uid();\n  \n  IF v_user_id IS NULL THEN\n    RAISE EXCEPTION 'Authentication required';\n  END IF;\n  \n  -- Get user's tenant from profiles or memberships\n  SELECT COALESCE(p.tenant_org_id, utm.tenant_id::text)\n  INTO v_tenant_id\n  FROM profiles p\n  LEFT JOIN user_tenant_memberships utm ON utm.user_id = p.id AND utm.status = 'active'\n  WHERE p.id = v_user_id\n  LIMIT 1;\n  \n  IF v_tenant_id IS NULL THEN\n    v_tenant_id := 'system';\n  END IF;\n  \n  -- Insert activity log\n  INSERT INTO public.activity_log (\n    user_id,\n    tenant_id,\n    activity_type,\n    title,\n    description,\n    contact_id,\n    metadata,\n    created_at\n  ) VALUES (\n    v_user_id,\n    v_tenant_id,\n    p_activity_type,\n    p_title,\n    p_description,\n    p_contact_id,\n    COALESCE(p_metadata, '{}'::jsonb),\n    NOW()\n  )\n  RETURNING id INTO v_activity_id;\n  \n  RETURN v_activity_id;\nEND;\n$function$\n","identity_arguments":"p_activity_type text, p_title text, p_description text, p_contact_id uuid, p_metadata jsonb"},{"name":"manage_pcg_submission_lifecycle","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.manage_pcg_submission_lifecycle(p_tenant_id uuid, p_submission_id uuid, p_action text, p_reason text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_actor uuid := auth.uid();\n  v_action text := lower(btrim(coalesce(p_action,'')));\n  v_reason text := btrim(coalesce(p_reason,''));\n  v_submission public.card_grading_submissions%rowtype;\n  v_is_pcg boolean := false;\n  v_hold_id uuid;\nbegin\n  if current_user <> 'service_role' then\n    if v_actor is null or not public.is_tenant_member(p_tenant_id::text) then\n      raise exception 'PCG workspace access required' using errcode='42501';\n    end if;\n  end if;\n\n  if v_action not in ('hold','resume','cancel','reopen','archive','restore') then\n    raise exception 'Unsupported PCG order action';\n  end if;\n  if v_reason = '' then\n    raise exception 'A reason is required for this order action';\n  end if;\n\n  select coalesce(t.company_slug,'')='pcg' into v_is_pcg\n  from public.tenants t where t.id=p_tenant_id;\n  if not coalesce(v_is_pcg,false) then\n    raise exception 'PCG workspace required' using errcode='42501';\n  end if;\n\n  select * into v_submission\n  from public.card_grading_submissions\n  where id=p_submission_id and tenant_id=p_tenant_id\n  for update;\n  if not found then raise exception 'Submission unavailable'; end if;\n  if v_submission.submission_number='PCG-INVENTORY' then\n    raise exception 'PCG inventory cannot be changed with customer order actions';\n  end if;\n\n  if v_action='hold' then\n    if v_submission.deleted_at is not null or v_submission.lifecycle_state <> 'active' then\n      raise exception 'Only an active order can be put on hold';\n    end if;\n    if v_submission.status in ('shipped','picked_up','delivered','closed') then\n      raise exception 'Completed fulfillment cannot be put on hold';\n    end if;\n    select id into v_hold_id from public.card_grading_exceptions\n      where tenant_id=p_tenant_id and submission_id=p_submission_id and kind='hold' and status='open'\n      limit 1;\n    if v_hold_id is not null then raise exception 'This order is already on hold'; end if;\n    insert into public.card_grading_exceptions(tenant_id,submission_id,kind,reason,status,opened_by,opened_at)\n    values(p_tenant_id,p_submission_id,'hold',v_reason,'open',v_actor,now());\n\n  elsif v_action='resume' then\n    if v_submission.deleted_at is not null or v_submission.lifecycle_state <> 'active' then\n      raise exception 'Only an active held order can be resumed';\n    end if;\n    update public.card_grading_exceptions\n      set status='resolved',resolved_by=v_actor,resolved_at=now(),resolution=v_reason\n      where tenant_id=p_tenant_id and submission_id=p_submission_id and kind='hold' and status='open';\n    if not found then raise exception 'This order is not on hold'; end if;\n\n  elsif v_action='cancel' then\n    if v_submission.deleted_at is not null then raise exception 'Restore this archived order before cancelling it'; end if;\n    if v_submission.lifecycle_state='cancelled' then raise exception 'This order is already cancelled'; end if;\n    if v_submission.status in ('shipped','picked_up','delivered','closed') then\n      raise exception 'Shipped or completed orders cannot be cancelled';\n    end if;\n    update public.card_grading_exceptions\n      set status='resolved',resolved_by=v_actor,resolved_at=now(),resolution='Order cancelled: '||v_reason\n      where tenant_id=p_tenant_id and submission_id=p_submission_id and kind='hold' and status='open';\n    update public.card_grading_submissions\n      set lifecycle_state='cancelled',cancelled_at=now(),cancelled_by=v_actor,\n          cancellation_reason=v_reason,updated_at=now()\n      where id=p_submission_id and tenant_id=p_tenant_id;\n\n  elsif v_action='reopen' then\n    if v_submission.deleted_at is not null then raise exception 'Restore this archived order before reopening it'; end if;\n    if v_submission.lifecycle_state<>'cancelled' then raise exception 'Only a cancelled order can be reopened'; end if;\n    update public.card_grading_submissions\n      set lifecycle_state='active',cancelled_at=null,cancelled_by=null,\n          cancellation_reason=null,updated_at=now()\n      where id=p_submission_id and tenant_id=p_tenant_id;\n\n  elsif v_action='archive' then\n    if v_submission.deleted_at is not null then raise exception 'This order is already archived'; end if;\n    update public.card_grading_exceptions\n      set status='resolved',resolved_by=v_actor,resolved_at=now(),resolution='Order archived: '||v_reason\n      where tenant_id=p_tenant_id and submission_id=p_submission_id and kind='hold' and status='open';\n    update public.card_grading_submissions\n      set deleted_at=now(),deleted_by=v_actor,deletion_reason=v_reason,updated_at=now()\n      where id=p_submission_id and tenant_id=p_tenant_id;\n\n  elsif v_action='restore' then\n    if v_submission.deleted_at is null then raise exception 'Only an archived order can be restored'; end if;\n    update public.card_grading_submissions\n      set deleted_at=null,deleted_by=null,deletion_reason=null,updated_at=now()\n      where id=p_submission_id and tenant_id=p_tenant_id;\n  end if;\n\n  insert into public.pcg_submission_lifecycle_events(\n    tenant_id,submission_id,action,message,actor_user_id,prior_lifecycle_state,prior_status\n  ) values(\n    p_tenant_id,p_submission_id,v_action,v_reason,coalesce(v_actor,v_submission.cancelled_by,v_submission.deleted_by),\n    v_submission.lifecycle_state,v_submission.status\n  );\n\n  return jsonb_build_object('ok',true,'action',v_action,'submission_id',p_submission_id);\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_submission_id uuid, p_action text, p_reason text"},{"name":"mark_courses_stale_for_action","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mark_courses_stale_for_action(_action_key text)\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_count int;\n  v_current int;\nBEGIN\n  IF NOT is_system_admin(auth.uid()) THEN\n    RAISE EXCEPTION 'GodMode only';\n  END IF;\n  SELECT current_version INTO v_current FROM public.academy_app_actions WHERE key = _action_key;\n  UPDATE public.academy_lessons\n     SET review_status = 'stale', updated_at = now()\n   WHERE linked_action_key = _action_key\n     AND action_version < COALESCE(v_current, 1);\n  GET DIAGNOSTICS v_count = ROW_COUNT;\n  RETURN v_count;\nEND;\n$function$\n","identity_arguments":"_action_key text"},{"name":"mark_courses_stale_for_workflow","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mark_courses_stale_for_workflow(_workflow_key text)\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE v_count int;\nBEGIN\n  IF NOT is_system_admin(auth.uid()) THEN RAISE EXCEPTION 'GodMode only'; END IF;\n  UPDATE public.academy_lessons SET review_status = 'stale', updated_at = now()\n   WHERE workflow_key = _workflow_key AND review_status = 'active';\n  GET DIAGNOSTICS v_count = ROW_COUNT;\n  RETURN v_count;\nEND;\n$function$\n","identity_arguments":"_workflow_key text"},{"name":"mark_late_deadlines","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mark_late_deadlines()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  -- If due_date is past and still Open, mark Late on read/write\n  IF NEW.status = 'Open' AND NEW.due_date < CURRENT_DATE THEN\n    NEW.status := 'Late';\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"mark_platform_message_conversation_read","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mark_platform_message_conversation_read(p_conversation_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if not public.can_access_message_conversation(p_conversation_id,auth.uid()) then\n    raise exception 'message_conversation_access_denied';\n  end if;\n  update public.message_conversation_members set last_read_at=now()\n    where conversation_id=p_conversation_id and user_id=auth.uid();\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid"},{"name":"mark_score_stale_on_contact_change","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mark_score_stale_on_contact_change()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF (\n       NEW.property_year_built  IS DISTINCT FROM OLD.property_year_built\n    OR NEW.property_square_feet IS DISTINCT FROM OLD.property_square_feet\n    OR NEW.carrier              IS DISTINCT FROM OLD.carrier\n    OR NEW.carrier_name         IS DISTINCT FROM OLD.carrier_name\n    OR NEW.is_dnc               IS DISTINCT FROM OLD.is_dnc\n    OR NEW.last_touched_at      IS DISTINCT FROM OLD.last_touched_at\n    OR NEW.zip                  IS DISTINCT FROM OLD.zip\n    OR NEW.lat                  IS DISTINCT FROM OLD.lat\n    OR NEW.lng                  IS DISTINCT FROM OLD.lng\n    OR NEW.contact_status       IS DISTINCT FROM OLD.contact_status\n  ) THEN\n    UPDATE public.lead_intelligence_scores\n    SET stale = true, stale_reason = 'contact_changed', updated_at = now()\n    WHERE subject_id = NEW.id\n      AND subject_type = 'contact'\n      AND score_type = 'stormscore'\n      AND stale = false;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"mark_scores_stale_for_contact","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mark_scores_stale_for_contact()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF (TG_OP = 'UPDATE') THEN\n    -- Only react when fields that influence the score change.\n    IF (\n      COALESCE(NEW.status,'') IS DISTINCT FROM COALESCE(OLD.status,'')\n      OR COALESCE(NEW.contact_status,'') IS DISTINCT FROM COALESCE(OLD.contact_status,'')\n      OR COALESCE(NEW.assigned_to::text,'') IS DISTINCT FROM COALESCE(OLD.assigned_to::text,'')\n      OR COALESCE(NEW.last_touched_at::text,'') IS DISTINCT FROM COALESCE(OLD.last_touched_at::text,'')\n      OR COALESCE(NEW.roof_age,'') IS DISTINCT FROM COALESCE(OLD.roof_age,'')\n      OR COALESCE(NEW.roof_permit_finaled_date::text,'') IS DISTINCT FROM COALESCE(OLD.roof_permit_finaled_date::text,'')\n      OR COALESCE(NEW.has_recent_roof_permit,false) IS DISTINCT FROM COALESCE(OLD.has_recent_roof_permit,false)\n      OR COALESCE(NEW.permit_data::text,'') IS DISTINCT FROM COALESCE(OLD.permit_data::text,'')\n      OR COALESCE(NEW.zip,'') IS DISTINCT FROM COALESCE(OLD.zip,'')\n    ) THEN\n      UPDATE public.lead_intelligence_scores\n         SET stale = true,\n             stale_reason = 'contact_updated'\n       WHERE subject_type IN ('contact','lead','client')\n         AND subject_id = NEW.id;\n    END IF;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"mark_scores_stale_on_storm","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mark_scores_stale_on_storm()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.zip_prefix IS NOT NULL AND NEW.state IS NOT NULL THEN\n    UPDATE public.lead_intelligence_scores s\n    SET stale = true, stale_reason = 'new_storm_event', updated_at = now()\n    FROM public.unified_contacts c\n    WHERE s.subject_id = c.id\n      AND s.subject_type = 'contact'\n      AND s.score_type = 'stormscore'\n      AND c.deleted_at IS NULL\n      AND c.state = NEW.state\n      AND substring(c.zip from 1 for 3) = NEW.zip_prefix\n      AND s.stale = false;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"mark_scores_stale_on_storm_event","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mark_scores_stale_on_storm_event()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  -- New storm landed → flag every contact in the affected county as stale.\n  UPDATE public.lead_intelligence_scores lis\n     SET stale = true,\n         stale_reason = 'new_storm_event'\n    FROM public.unified_contacts uc\n   WHERE lis.subject_id = uc.id\n     AND lis.subject_type IN ('contact','lead','client')\n     AND uc.tenant_org_id = lis.tenant_org_id\n     AND (\n       (NEW.zip_prefix IS NOT NULL AND uc.zip IS NOT NULL\n          AND left(uc.zip, length(NEW.zip_prefix)) = NEW.zip_prefix)\n       OR (NEW.county IS NOT NULL AND uc.city IS NOT NULL\n            AND lower(uc.city) = lower(NEW.county))\n     );\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"mark_tenant_application_manifest_stale","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mark_tenant_application_manifest_stale()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant_id uuid;\nbegin\n  v_tenant_id := coalesce(new.tenant_id, old.tenant_id);\n  update public.tenants\n  set settings = jsonb_set(\n      jsonb_set(coalesce(settings, '{}'::jsonb), '{tenant_application_manifest_state}', '\"stale\"'::jsonb, true),\n      '{tenant_application_manifest_changed_at}', to_jsonb(now()), true\n    ),\n    updated_at = now()\n  where id = v_tenant_id;\n  return coalesce(new, old);\nend;\n$function$\n","identity_arguments":""},{"name":"mark_voicemail_read","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mark_voicemail_read(_voicemail_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE v_tenant text;\nBEGIN\n  SELECT tenant_org_id INTO v_tenant FROM voicemail_messages WHERE id = _voicemail_id;\n  IF v_tenant IS NULL THEN RAISE EXCEPTION 'Voicemail not found'; END IF;\n  IF NOT is_tenant_member(v_tenant) THEN RAISE EXCEPTION 'Not authorized'; END IF;\n  UPDATE voicemail_messages\n    SET is_read = true, read_by_user_id = auth.uid(), read_at = now()\n    WHERE id = _voicemail_id;\nEND $function$\n","identity_arguments":"_voicemail_id uuid"},{"name":"materialize_lawn_workday","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.materialize_lawn_workday(p_tenant_id uuid, p_service_date date DEFAULT CURRENT_DATE)\n RETURNS jsonb\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  generated integer := 0;\n  route_row public.lawn_service_routes%ROWTYPE;\n  visit_count integer := 0;\n  default_crew text;\nBEGIN\n  generated := public.generate_lawn_service_visits(p_tenant_id, p_service_date, 0);\n\n  SELECT item_id INTO default_crew\n  FROM public.lawn_care_readiness_items\n  WHERE tenant_id = p_tenant_id\n    AND item_type = 'crew'\n    AND status = 'Assigned'\n  ORDER BY updated_at DESC, item_id\n  LIMIT 1;\n\n  SELECT count(*) INTO visit_count\n  FROM public.lawn_service_visits\n  WHERE tenant_id = p_tenant_id\n    AND service_date = p_service_date\n    AND status <> 'cancelled';\n\n  IF visit_count > 0 THEN\n    INSERT INTO public.lawn_service_routes (tenant_id, service_date, status, assigned_crew_id, metadata)\n    VALUES (\n      p_tenant_id,\n      p_service_date,\n      'planned',\n      default_crew,\n      jsonb_build_object('materialized_by','seaside_today_v2','materialized_at',now())\n    )\n    ON CONFLICT (tenant_id, service_date) DO UPDATE\n    SET assigned_crew_id = coalesce(public.lawn_service_routes.assigned_crew_id, excluded.assigned_crew_id),\n        metadata = public.lawn_service_routes.metadata || excluded.metadata\n    RETURNING * INTO route_row;\n\n    UPDATE public.lawn_service_visits\n    SET route_id = route_row.id,\n        assigned_crew_id = coalesce(assigned_crew_id, route_row.assigned_crew_id)\n    WHERE tenant_id = p_tenant_id\n      AND service_date = p_service_date\n      AND status <> 'cancelled'\n      AND (route_id IS DISTINCT FROM route_row.id OR (assigned_crew_id IS NULL AND route_row.assigned_crew_id IS NOT NULL));\n  END IF;\n\n  RETURN jsonb_build_object(\n    'tenant_id', p_tenant_id,\n    'service_date', p_service_date,\n    'generated_visits', generated,\n    'visit_count', visit_count,\n    'route_id', route_row.id,\n    'assigned_crew_id', route_row.assigned_crew_id\n  );\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_service_date date"},{"name":"materialize_owner_notes_tasks_from_email_signal","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.materialize_owner_notes_tasks_from_email_signal()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_owner_user_id uuid;\n  v_provider text;\n  v_thread_id text;\n  v_source_id text;\n  v_summary text;\n  v_due_at timestamptz;\n  v_actionable boolean;\n  v_subject text;\nbegin\n  v_provider := coalesce(nullif(new.provider, ''), 'provider');\n  v_thread_id := nullif(new.raw_metadata->>'thread_id', '');\n  v_source_id := 'mail:' || v_provider || ':' ||\n    case\n      when v_thread_id is not null then 'thread:' || v_thread_id\n      else 'message:' || coalesce(nullif(new.provider_message_id, ''), new.id::text)\n    end;\n  v_subject := regexp_replace(\n    coalesce(nullif(new.subject, ''), nullif(new.sender_name, ''), nullif(new.sender_email, ''), 'email'),\n    '^\\s*((re|fw|fwd)\\s*:\\s*)+',\n    '',\n    'i'\n  );\n  v_actionable := lower(coalesce(new.status, 'review')) not in ('ignored', 'dismissed')\n    and (\n      new.classification = 'event_opportunity'\n      or jsonb_array_length(coalesce(new.proposed_actions, '[]'::jsonb)) > 0\n    );\n\n  if not v_actionable then\n    update public.tasks\n      set status = 'dismissed', updated_at = now()\n      where tenant_id = new.tenant_org_id\n        and source_kind = 'inbound_email_signal'\n        and source_id = v_source_id;\n    update public.owner_workspace_notes\n      set dismissed_at = coalesce(dismissed_at, now()), updated_at = now()\n      where tenant_id = new.tenant_org_id\n        and source_type = 'inbound_email_signal'\n        and source_id = v_source_id;\n    return new;\n  end if;\n\n  select membership.user_id\n    into v_owner_user_id\n    from public.user_tenant_memberships membership\n    where membership.tenant_id = new.tenant_org_id::uuid\n      and membership.status = 'active'\n      and membership.is_owner is true\n    order by membership.joined_at nulls last, membership.id\n    limit 1;\n\n  if v_owner_user_id is null then\n    return new;\n  end if;\n\n  v_summary := concat_ws(' • ',\n    nullif(new.sender_name, ''),\n    nullif(new.sender_email, ''),\n    nullif(new.extracted->>'event_type', ''),\n    nullif(new.extracted->>'date_text', ''),\n    nullif(new.extracted->>'time_text', ''),\n    nullif(new.extracted->>'location', ''),\n    case when nullif(new.extracted->>'guest_count', '') is not null then (new.extracted->>'guest_count') || ' guests' end\n  );\n\n  begin\n    v_due_at := nullif(new.extracted->>'event_date', '')::timestamptz;\n  exception when others then\n    v_due_at := null;\n  end;\n\n  insert into public.tasks (\n    tenant_id, user_id, title, description, priority, status, due_date, metadata\n  ) values (\n    new.tenant_org_id,\n    v_owner_user_id,\n    'Follow up: ' || v_subject,\n    nullif(v_summary, ''),\n    'medium',\n    'pending',\n    v_due_at,\n    jsonb_build_object(\n      'auto_generated', true,\n      'source_kind', 'inbound_email_signal',\n      'source_id', v_source_id,\n      'email_signal_id', new.id,\n      'provider_message_id', new.provider_message_id,\n      'thread_id', v_thread_id,\n      'source_route', '/big-papis-coquito-iceys/owner/email'\n    )\n  )\n  on conflict (tenant_id, source_kind, source_id)\n    where source_kind is not null and source_id is not null\n  do update set\n    title = excluded.title,\n    description = excluded.description,\n    due_date = coalesce(excluded.due_date, public.tasks.due_date),\n    status = case when public.tasks.status = 'dismissed' then 'dismissed' else 'pending' end,\n    completed_at = case when public.tasks.status = 'dismissed' then public.tasks.completed_at else null end,\n    metadata = public.tasks.metadata || excluded.metadata,\n    updated_at = now();\n\n  insert into public.owner_workspace_notes (\n    tenant_id, user_id, title, body, pinned, source_type, source_id, source_metadata\n  ) values (\n    new.tenant_org_id,\n    v_owner_user_id,\n    v_subject,\n    coalesce(nullif(v_summary, ''), 'Actionable email captured by KnockLaunch Mail.'),\n    false,\n    'inbound_email_signal',\n    v_source_id,\n    jsonb_build_object(\n      'email_signal_id', new.id,\n      'provider_message_id', new.provider_message_id,\n      'thread_id', v_thread_id,\n      'source_route', '/big-papis-coquito-iceys/owner/email'\n    )\n  )\n  on conflict (tenant_id, source_type, source_id)\n    where source_type is not null and source_id is not null\n  do update set\n    title = excluded.title,\n    body = excluded.body,\n    source_metadata = public.owner_workspace_notes.source_metadata || excluded.source_metadata,\n    dismissed_at = null,\n    updated_at = now();\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"merge_tenant_application_ids","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.merge_tenant_application_ids(VARIADIC p_sources jsonb[])\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_source jsonb;\n  v_combined jsonb := '[]'::jsonb;\nbegin\n  foreach v_source in array p_sources loop\n    if jsonb_typeof(v_source) = 'array' then\n      v_combined := v_combined || v_source;\n    end if;\n  end loop;\n  return public.canonical_tenant_application_ids(v_combined);\nend;\n$function$\n","identity_arguments":"VARIADIC p_sources jsonb[]"},{"name":"message_deleted_retention_immutable","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.message_deleted_retention_immutable()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  raise exception 'message_deleted_retention_is_immutable';\nend;\n$function$\n","identity_arguments":""},{"name":"message_push_receipt_summary","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.message_push_receipt_summary(p_message_id uuid)\n RETURNS TABLE(state text, total bigint)\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO ''\nAS $function$\n  select o.state,count(*)::bigint from public.message_push_outbox o\n  join public.messages m on m.id=o.message_id\n  join public.message_conversation_members cm on cm.conversation_id=m.conversation_id and cm.user_id=auth.uid()\n  where m.id=p_message_id and m.sender_id=auth.uid()\n  group by o.state;\n$function$\n","identity_arguments":"p_message_id uuid"},{"name":"message_storage_conversation_id","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.message_storage_conversation_id(p_name text)\n RETURNS uuid\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public', 'storage', 'pg_temp'\nAS $function$\ndeclare\n  parts text[];\nbegin\n  parts := storage.foldername(p_name);\n  if coalesce(parts[1],'') <> 'messages' or coalesce(parts[2],'') = '' then\n    return null;\n  end if;\n  return parts[2]::uuid;\nexception when others then\n  return null;\nend;\n$function$\n","identity_arguments":"p_name text"},{"name":"migrate_card_grading_legacy_cert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.migrate_card_grading_legacy_cert(p_tenant_id uuid, p_card_id uuid, p_grader_user_id uuid, p_reason text DEFAULT 'PCG KnockLaunch cert migration'::text)\n RETURNS text\n LANGUAGE plpgsql\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_card public.card_grading_cards%rowtype;\n  v_prefix smallint;\n  v_old_cert text;\n  v_new_cert text;\nbegin\n  if auth.uid() is null or not (\n    public.is_system_admin(auth.uid())\n    or exists (\n      select 1 from public.security_active_user_tenant_memberships m\n      where m.user_id=auth.uid()\n        and m.tenant_id=p_tenant_id\n        and m.status='active'\n        and m.is_owner=true\n    )\n  ) then\n    raise exception 'Owner or platform-admin authority required' using errcode='42501';\n  end if;\n  -- Red-label numbers are permanent and must never be renumbered into black labels.\n  if p_tenant_id = '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid then\n    raise exception 'pcg_legacy_red_label_cert_must_remain_unchanged';\n  end if;\n\n  select * into v_card\n  from public.card_grading_cards\n  where id=p_card_id and tenant_id=p_tenant_id\n  for update;\n\n  if v_card.id is null then raise exception 'Card unavailable'; end if;\n\n  v_old_cert := btrim(coalesce(v_card.cert_number,''));\n  if v_old_cert !~ '^0[0-9]{4}$' then\n    raise exception 'Card does not have a migratable legacy 0xxxx Cert Number';\n  end if;\n\n  select cert_prefix into v_prefix\n  from public.card_grading_cert_prefix_assignments\n  where tenant_id=p_tenant_id\n    and grader_user_id=p_grader_user_id\n    and active=true;\n\n  if v_prefix is null then\n    raise exception 'No PCG cert prefix is assigned to this grader';\n  end if;\n\n  v_new_cert := v_prefix::text || right(v_old_cert,4);\n\n  if exists (\n    select 1 from public.card_grading_cards\n    where tenant_id=p_tenant_id and cert_number=v_new_cert and id<>p_card_id\n  ) or exists (\n    select 1 from public.card_grading_certificates\n    where tenant_id=p_tenant_id and cert_number=v_new_cert and card_id<>p_card_id\n  ) then\n    raise exception 'Target Cert Number % already exists',v_new_cert;\n  end if;\n\n  perform set_config('app.card_grading_cert_correction','allowed',true);\n\n  update public.card_grading_cards\n     set cert_number=v_new_cert, updated_at=now()\n   where id=p_card_id and tenant_id=p_tenant_id;\n\n  update public.card_grading_certificates\n     set cert_number=v_new_cert, updated_at=now()\n   where card_id=p_card_id and tenant_id=p_tenant_id;\n\n  insert into public.card_grading_workflow_events(\n    tenant_id, submission_id, card_id, event_type, actor_user_id, reason, metadata\n  ) values (\n    p_tenant_id,v_card.submission_id,p_card_id,'legacy_certificate_migrated',auth.uid(),\n    nullif(btrim(coalesce(p_reason,'')),''),\n    jsonb_build_object(\n      'legacy_cert_number',v_old_cert,\n      'cert_number',v_new_cert,\n      'grader_user_id',p_grader_user_id,\n      'cert_prefix',v_prefix\n    )\n  );\n\n  return v_new_cert;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_card_id uuid, p_grader_user_id uuid, p_reason text"},{"name":"mirror_lead_deck_to_unified","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.mirror_lead_deck_to_unified()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF TG_OP = 'INSERT' THEN\n    IF NEW.tenant_org_id IS NULL THEN\n      RETURN NEW;\n    END IF;\n\n    IF EXISTS (SELECT 1 FROM public.unified_contacts WHERE id = NEW.id) THEN\n      UPDATE public.unified_contacts SET\n        tenant_org_id = NEW.tenant_org_id,\n        name = NEW.name, phone = NEW.phone, email = NEW.email,\n        address = NEW.address, city = NEW.city, state = NEW.state, zip = NEW.zip,\n        status = NEW.status, priority = NEW.priority, source = NEW.source,\n        assigned_to = NEW.assigned_to, notes = NEW.notes,\n        lead_stage = NEW.lead_stage, graduated_at = NEW.graduated_at,\n        property_data = NEW.property_data, property_parcel_id = NEW.property_parcel_id,\n        property_owner_name = NEW.property_owner_name,\n        property_assessed_value = NEW.property_assessed_value,\n        property_square_feet = NEW.property_square_feet,\n        property_year_built = NEW.property_year_built,\n        lat = NEW.lat, lng = NEW.lng,\n        updated_at = COALESCE(NEW.updated_at, now()),\n        last_touched_at = COALESCE(NEW.updated_at, last_touched_at)\n      WHERE id = NEW.id;\n    ELSE\n      IF EXISTS (\n        SELECT 1 FROM public.unified_contacts uc\n        WHERE uc.tenant_org_id = NEW.tenant_org_id\n          AND (\n            (NULLIF(regexp_replace(coalesce(uc.phone,''),'[^0-9]','','g'),'') IS NOT NULL\n              AND regexp_replace(coalesce(uc.phone,''),'[^0-9]','','g')\n                = regexp_replace(coalesce(NEW.phone,''),'[^0-9]','','g'))\n            OR\n            (NULLIF(lower(trim(coalesce(uc.address,''))),'') IS NOT NULL\n              AND lower(trim(coalesce(uc.address,'')))\n                = lower(trim(coalesce(NEW.address,''))))\n          )\n      ) THEN\n        RETURN NEW;\n      END IF;\n\n      INSERT INTO public.unified_contacts (\n        id, tenant_org_id, legacy_lead_deck_id, lead_id, name, phone, email,\n        address, city, state, zip, status, priority, source, assigned_to,\n        notes, created_at, updated_at, last_touched_at, lead_origin, lead_stage,\n        graduated_at, property_data, property_parcel_id, property_owner_name,\n        property_assessed_value, property_square_feet, property_year_built, lat, lng\n      ) VALUES (\n        NEW.id, NEW.tenant_org_id, NEW.id, NEW.lead_id, NEW.name, NEW.phone, NEW.email,\n        NEW.address, NEW.city, NEW.state, NEW.zip, NEW.status, NEW.priority, NEW.source,\n        NEW.assigned_to, NEW.notes, COALESCE(NEW.created_at, now()),\n        COALESCE(NEW.updated_at, now()), COALESCE(NEW.updated_at, now()), 'system',\n        NEW.lead_stage, NEW.graduated_at, NEW.property_data, NEW.property_parcel_id,\n        NEW.property_owner_name, NEW.property_assessed_value, NEW.property_square_feet,\n        NEW.property_year_built, NEW.lat, NEW.lng\n      );\n    END IF;\n    RETURN NEW;\n  ELSIF TG_OP = 'UPDATE' THEN\n    UPDATE public.unified_contacts SET\n      tenant_org_id = NEW.tenant_org_id,\n      name = NEW.name, phone = NEW.phone, email = NEW.email,\n      address = NEW.address, city = NEW.city, state = NEW.state, zip = NEW.zip,\n      status = NEW.status, priority = NEW.priority, source = NEW.source,\n      assigned_to = NEW.assigned_to, notes = NEW.notes,\n      lead_stage = NEW.lead_stage, graduated_at = NEW.graduated_at,\n      property_data = NEW.property_data, property_parcel_id = NEW.property_parcel_id,\n      property_owner_name = NEW.property_owner_name,\n      property_assessed_value = NEW.property_assessed_value,\n      property_square_feet = NEW.property_square_feet,\n      property_year_built = NEW.property_year_built,\n      lat = NEW.lat, lng = NEW.lng,\n      updated_at = COALESCE(NEW.updated_at, now()),\n      last_touched_at = COALESCE(NEW.updated_at, last_touched_at)\n    WHERE id = NEW.id OR legacy_lead_deck_id = NEW.id;\n    RETURN NEW;\n  ELSIF TG_OP = 'DELETE' THEN\n    UPDATE public.unified_contacts\n    SET archived_at = now(), updated_at = now()\n    WHERE (id = OLD.id OR legacy_lead_deck_id = OLD.id)\n      AND archived_at IS NULL;\n    RETURN OLD;\n  END IF;\n  RETURN NULL;\nEND;\n$function$\n","identity_arguments":""},{"name":"modes_storage_reconcile_authorize","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.modes_storage_reconcile_authorize(p_token text)\n RETURNS boolean\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public', 'vault', 'extensions'\nAS $function$\n  select coalesce((\n    select extensions.digest(ds.decrypted_secret, 'sha256') = extensions.digest(coalesce(p_token,''), 'sha256')\n      from vault.decrypted_secrets ds\n     where ds.name = 'knocklaunch_modes_storage_reconcile_trigger'\n     limit 1\n  ), false);\n$function$\n","identity_arguments":"p_token text"},{"name":"move_to_dlq","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.move_to_dlq(source_queue text, dlq_name text, message_id bigint, payload jsonb)\n RETURNS bigint\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_catalog'\nAS $function$\nDECLARE new_id BIGINT;\nBEGIN\n  SELECT pgmq.send(dlq_name, payload) INTO new_id;\n  PERFORM pgmq.delete(source_queue, message_id);\n  RETURN new_id;\nEXCEPTION WHEN undefined_table THEN\n  BEGIN\n    PERFORM pgmq.create(dlq_name);\n  EXCEPTION WHEN OTHERS THEN\n    NULL;\n  END;\n  SELECT pgmq.send(dlq_name, payload) INTO new_id;\n  BEGIN\n    PERFORM pgmq.delete(source_queue, message_id);\n  EXCEPTION WHEN undefined_table THEN\n    NULL;\n  END;\n  RETURN new_id;\nEND;\n$function$\n","identity_arguments":"source_queue text, dlq_name text, message_id bigint, payload jsonb"},{"name":"next_global_lead","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.next_global_lead()\n RETURNS TABLE(id uuid, lead_id text, name text, phone text, email text, address text, city text, state text, zip text, status text, priority text, source text, assigned_to text, notes text, tenant_org_id text, created_at timestamp with time zone, updated_at timestamp with time zone)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  RETURN QUERY\n  SELECT \n    ld.id,\n    ld.lead_id,\n    ld.name,\n    ld.phone,\n    ld.email,\n    ld.address,\n    ld.city,\n    ld.state,\n    ld.zip,\n    ld.status,\n    ld.priority,\n    ld.source,\n    ld.assigned_to,\n    ld.notes,\n    ld.tenant_org_id,\n    ld.created_at,\n    ld.updated_at\n  FROM lead_deck ld\n  WHERE ld.deleted_at IS NULL\n    AND ld.tenant_org_id IS NULL\n    AND (ld.assigned_to IS NULL OR ld.assigned_to = '')\n    AND (ld.status IS NULL OR ld.status NOT IN (\n      'Completed', 'Closed', 'Lost', 'DNC', 'Suppressed', \n      'Not Qualified', 'Not Qualified - Metal'\n    ))\n  ORDER BY RANDOM()\n  LIMIT 1;\nEND;\n$function$\n","identity_arguments":""},{"name":"next_pcg_submission_number","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.next_pcg_submission_number()\n RETURNS text\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select lpad(nextval('public.pcg_submission_number_seq')::text, 5, '0')\n$function$\n","identity_arguments":""},{"name":"next_supplement_number","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.next_supplement_number(_claim_id uuid)\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_next integer;\n  v_tenant_text text;\n  v_tenant_id uuid;\n  v_request_user uuid := public.request_user_id();\n  v_claims text := nullif(current_setting('request.jwt.claims', true), '');\n  v_role text := nullif(current_setting('request.jwt.claim.role', true), '');\nbegin\n  if v_claims is not null then\n    v_role := coalesce(v_role, nullif((v_claims::jsonb) ->> 'role', ''));\n  end if;\n\n  select cc.tenant_org_id\n    into v_tenant_text\n    from public.contact_claims cc\n   where cc.id = _claim_id;\n\n  if not found then\n    raise exception 'claim not found'\n      using errcode = '22023';\n  end if;\n\n  v_tenant_id := public.try_cast_uuid(v_tenant_text);\n  if v_tenant_id is null then\n    raise exception 'claim tenant is invalid'\n      using errcode = '22023';\n  end if;\n\n  if coalesce(v_role, '') <> 'service_role' then\n    if v_request_user is null\n       or (\n         not coalesce(public.is_platform_admin(v_request_user), false)\n         and not coalesce(public.is_tenant_member(v_request_user, v_tenant_id), false)\n       ) then\n      raise exception 'claim tenant access denied'\n        using errcode = '42501';\n    end if;\n  end if;\n\n  select coalesce(max(cs.supplement_number), 0) + 1\n    into v_next\n    from public.claim_supplements cs\n   where cs.claim_id = _claim_id;\n\n  return v_next;\nend;\n$function$\n","identity_arguments":"_claim_id uuid"},{"name":"next_voicemail_preset_slot","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.next_voicemail_preset_slot(_rep_id uuid, _phone text)\n RETURNS smallint\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  attempts_30d int;\nBEGIN\n  IF coalesce(auth.role(), '') <> 'service_role'\n     AND (\n       auth.uid() IS NULL\n       OR (\n         auth.uid() IS DISTINCT FROM _rep_id\n         AND NOT coalesce(public.is_system_admin(auth.uid()), false)\n         AND NOT coalesce(public.shares_tenant_as_manager_pm(auth.uid(), _rep_id), false)\n       )\n     ) THEN\n    RAISE EXCEPTION 'voicemail preset access denied' USING ERRCODE = '42501';\n  END IF;\n\n  SELECT count(*) INTO attempts_30d\n  FROM public.call_logs\n  WHERE phone_called = _phone\n    AND created_at >= now() - interval '30 days';\n\n  IF attempts_30d >= 3 THEN RETURN NULL; END IF;\n  RETURN least(attempts_30d + 1, 3)::smallint;\nEND;\n$function$\n","identity_arguments":"_rep_id uuid, _phone text"},{"name":"normalize_address","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.normalize_address(_addr text, _zip text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  SELECT\n    CASE\n      WHEN _addr IS NULL OR length(trim(_addr)) = 0 THEN NULL\n      ELSE\n        regexp_replace(\n          regexp_replace(\n            regexp_replace(\n              lower(trim(_addr)),\n              '\\s+(street|str|st\\.?)\\b', ' st', 'g'\n            ),\n            '\\s+(avenue|ave\\.?)\\b', ' ave', 'g'\n          ),\n          '[^a-z0-9 ]', '', 'g'\n        )\n        || coalesce(' ' || substring(regexp_replace(coalesce(_zip,''), '\\D', '', 'g') from 1 for 5), '')\n    END;\n$function$\n","identity_arguments":"_addr text, _zip text"},{"name":"normalize_business_source","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.normalize_business_source(_source text, _metadata jsonb DEFAULT '{}'::jsonb)\n RETURNS text\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare raw text := nullif(btrim(coalesce(_source, '')), ''); evidence text;\nbegin\n  evidence := lower(concat_ws(' ', raw, _metadata->>'source', _metadata->>'utm_source', _metadata->>'utm_medium', _metadata->>'medium', _metadata->>'provider', _metadata->>'referrer'));\n  if evidence ~ '(google[ _-]?ads|ppc|paid[ _-]?search|cpc|sem)' then return 'PPC'; end if;\n  if evidence ~ '(organic|seo|organic[ _-]?search)' then return 'SEO'; end if;\n  if evidence ~ 'roof[ _-]?help[ _-]?finder' then return 'RoofHelpFinder'; end if;\n  if evidence ~ '(canvass|door[ _-]?knock|field[ _-]?sales)' then return 'Canvassing'; end if;\n  if evidence ~ '(referr|partner)' then return 'Referral'; end if;\n  if evidence ~ '(facebook|instagram|tiktok|linkedin|nextdoor|yelp|twitter|social)' then return 'Social'; end if;\n  if evidence ~ '(phone|call|twilio)' then return 'Phone'; end if;\n  if evidence ~ '(email|mail)' then return 'Email'; end if;\n  if evidence ~ '(manual|entered[ _-]?by|admin)' then return 'Manual'; end if;\n  if raw is null then return 'Unknown'; end if;\n  return initcap(regexp_replace(raw, '[_-]+', ' ', 'g'));\nend;\n$function$\n","identity_arguments":"_source text, _metadata jsonb"},{"name":"normalize_declared_business_type","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.normalize_declared_business_type(p_value text)\n RETURNS text\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_token text := trim(both '_' from regexp_replace(upper(trim(coalesce(p_value, ''))), '[^A-Z0-9]+', '_', 'g'));\nbegin\n  if v_token = '' or v_token in ('PLATFORM','PLATFORM_ADMIN','GODMODE','ADMIN','SYSTEM_ADMIN') then return null; end if;\n  return case\n    when v_token in ('MITIGATION','EMERGENCY_MITIGATION','RESTORATION','WATER_MITIGATION','TARPING','SCETARPING','SCE_TARPING') then 'MITIGATION'\n    when v_token in ('ROOFING','ROOFER','ROOFING_COMPANY','ROOFINGCOMPANY') then 'ROOFING_COMPANY'\n    when v_token in ('PUBLIC_ADJUSTER','PUBLIC_ADJUSTER_FIRM','PUBLICADJUSTERFIRM','PA') then 'PUBLIC_ADJUSTER_FIRM'\n    when v_token in ('REALTOR','REAL_ESTATE','REAL_ESTATE_AGENT','BROKERAGE') then 'REALTOR'\n    when v_token in ('LAWN_CARE','LAWNCARE','LAWN','LANDSCAPING','ROUTE_BASED','ROUTE_BASED_SERVICE','FIELD_SERVICE') then 'LAWN_CARE'\n    when v_token in ('TIRE_SHOP','TIRESHOP','TIRE_STORE','TIRE_AND_AUTO','TIRE_AUTO') then 'TIRE_SHOP'\n    when v_token in ('AUTO_DETAILING','AUTODETAILING','AUTO_DETAILER','MOBILE_DETAILING','CAR_DETAILING','DETAILING') then 'AUTO_DETAILING'\n    when v_token in ('CAFE_QSR','CAFE','QSR','QUICK_SERVICE','QUICK_SERVICE_RESTAURANT','FOOD_BEVERAGE','FOOD_AND_BEVERAGE','RESTAURANT') then 'CAFE_QSR'\n    when v_token in ('MOBILE_VENDOR','MOBILEVENDOR','FOOD_TRUCK','FOODTRUCK','MOBILE_KITCHEN','MOBILEKITCHEN','POP_UP_VENDOR') then 'MOBILE_VENDOR'\n    when v_token in ('SHORT_TERM_RENTAL','SHORT_TERM_RENTALS','VACATION_RENTAL','VACATION_RENTALS','STR') then 'SHORT_TERM_RENTAL'\n    when v_token in ('PORTFOLIO_CONTROL_CENTER','PORTFOLIO_CONTROL','EXECUTIVE_CONTROL_CENTER','EXECUTIVE_OVERSIGHT') then 'PORTFOLIO_CONTROL_CENTER'\n    when v_token in ('MISC','MISCELLANEOUS') then 'MISC'\n    when v_token ~ '^[A-Z][A-Z0-9_]{1,95}$' then v_token\n    else null\n  end;\nend;\n$function$\n","identity_arguments":"p_value text"},{"name":"normalize_event_booking_completion","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.normalize_event_booking_completion()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nbegin\n  if new.stage = 'Completed' then\n    new.status := 'completed';\n    new.completed_at := coalesce(new.completed_at, now());\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"normalize_phone_for_dnc","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.normalize_phone_for_dnc(p text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\n  SELECT CASE\n    WHEN p IS NULL OR length(regexp_replace(p, '[^0-9]', '', 'g')) < 10 THEN NULL\n    ELSE right(regexp_replace(p, '[^0-9]', '', 'g'), 10)\n  END;\n$function$\n","identity_arguments":"p text"},{"name":"normalize_tenant_business_blueprint_requirements","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.normalize_tenant_business_blueprint_requirements(p_blueprint jsonb, p_settings jsonb DEFAULT '{}'::jsonb)\n RETURNS jsonb\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_blueprint jsonb := case when jsonb_typeof(coalesce(p_blueprint,'{}'::jsonb))='object' then coalesce(p_blueprint,'{}'::jsonb) else '{}'::jsonb end;\n  v_settings jsonb := case when jsonb_typeof(coalesce(p_settings,'{}'::jsonb))='object' then coalesce(p_settings,'{}'::jsonb) else '{}'::jsonb end;\n  v_existing jsonb;\n  v_apps jsonb;\n  v_stages jsonb;\n  v_model text;\n  v_relationship jsonb;\n  v_lifecycle_existing jsonb;\n  v_resources_existing jsonb;\n  v_documents_existing jsonb;\n  v_connections_existing jsonb;\n  v_presence_existing jsonb;\n  v_lifecycle_apps jsonb;\n  v_resource_apps jsonb;\n  v_document_apps jsonb;\n  v_document_outputs jsonb;\n  v_resource_kinds jsonb;\n  v_presence_surfaces jsonb;\n  v_presence_required boolean;\n  v_requirements jsonb;\nbegin\n  v_existing := case\n    when jsonb_typeof(v_blueprint->'bootstrapRequirements')='object' then v_blueprint->'bootstrapRequirements'\n    when jsonb_typeof(v_blueprint->'bootstrap_requirements')='object' then v_blueprint->'bootstrap_requirements'\n    else '{}'::jsonb\n  end;\n  v_lifecycle_existing := case when jsonb_typeof(coalesce(v_existing->'customerLifecycle',v_existing->'customer_lifecycle'))='object' then coalesce(v_existing->'customerLifecycle',v_existing->'customer_lifecycle') else '{}'::jsonb end;\n  v_resources_existing := case when jsonb_typeof(coalesce(v_existing->'resourceManagement',v_existing->'resource_management'))='object' then coalesce(v_existing->'resourceManagement',v_existing->'resource_management') else '{}'::jsonb end;\n  v_documents_existing := case when jsonb_typeof(v_existing->'documents')='object' then v_existing->'documents' else '{}'::jsonb end;\n  v_connections_existing := case when jsonb_typeof(v_existing->'connections')='object' then v_existing->'connections' else '{}'::jsonb end;\n  v_presence_existing := case when jsonb_typeof(coalesce(v_existing->'customerFacingPresence',v_existing->'customer_facing_presence'))='object' then coalesce(v_existing->'customerFacingPresence',v_existing->'customer_facing_presence') else '{}'::jsonb end;\n  v_apps := public.canonical_tenant_application_ids(v_blueprint->'applications');\n  v_stages := case when jsonb_typeof(coalesce(v_blueprint->'workflowStages',v_blueprint->'workflow_stages'))='array' then coalesce(v_blueprint->'workflowStages',v_blueprint->'workflow_stages') else '[]'::jsonb end;\n  v_model := lower(coalesce(nullif(v_blueprint->>'operatingModel',''),nullif(v_blueprint->>'operating_model',''),'general'));\n  v_relationship := case when jsonb_typeof(coalesce(v_blueprint->'primaryRelationship',v_blueprint->'primary_relationship'))='object' then coalesce(v_blueprint->'primaryRelationship',v_blueprint->'primary_relationship') else '{}'::jsonb end;\n  select coalesce(jsonb_agg(value order by ord),'[]'::jsonb) into v_lifecycle_apps from jsonb_array_elements_text(v_apps) with ordinality as app(value,ord) where value in ('contacts','opportunity-radar');\n  select coalesce(jsonb_agg(value order by ord),'[]'::jsonb) into v_resource_apps from jsonb_array_elements_text(v_apps) with ordinality as app(value,ord) where value in ('jobs','booking','route-service-operations');\n  select coalesce(jsonb_agg(value order by ord),'[]'::jsonb) into v_document_apps from jsonb_array_elements_text(v_apps) with ordinality as app(value,ord) where value in ('documents','invoices','proposals','forms');\n  select coalesce(jsonb_agg(output order by ord),'[]'::jsonb) into v_document_outputs from (select distinct on (output) output,ord from (select case value when 'documents' then 'document' when 'invoices' then 'invoice' when 'proposals' then 'proposal' when 'forms' then 'form' end output,ord from jsonb_array_elements_text(v_document_apps) with ordinality as app(value,ord)) q where output is not null order by output,ord) dedup;\n  v_resource_kinds := case v_model when 'appointments' then '[\"appointment\"]'::jsonb when 'recurring_routes' then '[\"service-route\",\"service\"]'::jsonb when 'events' then '[\"event\",\"service\"]'::jsonb when 'orders' then '[\"order\",\"inventory\"]'::jsonb when 'professional_cases' then '[\"matter\",\"service\"]'::jsonb when 'service_jobs' then '[\"service-job\",\"service\"]'::jsonb else '[]'::jsonb end;\n  v_presence_required := coalesce(case when jsonb_typeof(v_presence_existing->'required')='boolean' then (v_presence_existing->>'required')::boolean end,v_settings->>'public_site_required'='true',v_settings->>'customer_site_required'='true',false) or coalesce(nullif(v_settings->>'website',''),nullif(v_settings->>'public_url',''),nullif(v_settings->>'public_site_url',''),nullif(v_settings->>'customer_site_url',''),nullif(v_settings->>'custom_domain',''),nullif(v_settings->>'public_domain',''),nullif(v_settings->>'customer_site_domain','')) is not null;\n  v_presence_surfaces := case when v_presence_required then '[\"website\"]'::jsonb else '[]'::jsonb end;\n  if v_apps ? 'customer-portal' then v_presence_surfaces := v_presence_surfaces || '[\"portal\"]'::jsonb; end if;\n  v_requirements := v_existing;\n  v_requirements := jsonb_set(v_requirements,'{schemaVersion}',coalesce(v_existing->'schemaVersion',v_existing->'schema_version','1'::jsonb),true);\n  v_requirements := jsonb_set(v_requirements,'{customerLifecycle}',jsonb_build_object('required',jsonb_array_length(v_stages)>0,'stages',v_stages,'relationship',v_relationship,'applicationIds',v_lifecycle_apps)||v_lifecycle_existing,true);\n  v_requirements := jsonb_set(v_requirements,'{resourceManagement}',jsonb_build_object('required',jsonb_array_length(v_resource_apps)>0 or jsonb_array_length(v_resource_kinds)>0,'kinds',v_resource_kinds,'applicationIds',v_resource_apps)||v_resources_existing,true);\n  v_requirements := jsonb_set(v_requirements,'{documents}',jsonb_build_object('required',jsonb_array_length(v_document_apps)>0,'outputs',v_document_outputs,'applicationIds',v_document_apps)||v_documents_existing,true);\n  v_requirements := jsonb_set(v_requirements,'{connections}',jsonb_build_object('registry','shared-connections','requiredProviders','[]'::jsonb,'optionalProviders','[]'::jsonb)||v_connections_existing,true);\n  v_requirements := jsonb_set(v_requirements,'{customerFacingPresence}',jsonb_build_object('required',v_presence_required,'surfaces',v_presence_surfaces)||v_presence_existing,true);\n  return v_blueprint || jsonb_build_object('bootstrapRequirements',v_requirements);\nend;\n$function$\n","identity_arguments":"p_blueprint jsonb, p_settings jsonb"},{"name":"normalize_tenant_logo_ingest_base64","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.normalize_tenant_logo_ingest_base64()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\ndeclare\n  raw_logo text;\n  normalized_logo text;\n  padding_count integer;\n  logo_mime text;\n  normalized_data_url text;\nbegin\n  if new.settings is null then\n    return new;\n  end if;\n\n  raw_logo := nullif(btrim(new.settings ->> 'logo_ingest_b64'), '');\n  logo_mime := lower(coalesce(nullif(btrim(new.settings ->> 'logo_ingest_mime'), ''), 'image/webp'));\n\n  if raw_logo is null or logo_mime not like 'image/%' then\n    return new;\n  end if;\n\n  normalized_logo := regexp_replace(raw_logo, '\\s+', '', 'g');\n  padding_count := (4 - (length(normalized_logo) % 4)) % 4;\n  if padding_count > 0 then\n    normalized_logo := normalized_logo || repeat('=', padding_count);\n  end if;\n\n  begin\n    perform decode(normalized_logo, 'base64');\n  exception when others then\n    return new;\n  end;\n\n  if normalized_logo is distinct from raw_logo then\n    new.settings := jsonb_set(new.settings, '{logo_ingest_b64}', to_jsonb(normalized_logo), true);\n  end if;\n\n  normalized_data_url := 'data:' || logo_mime || ';base64,' || normalized_logo;\n  if nullif(btrim(new.company_logo_url), '') is null or lower(new.company_logo_url) like 'data:%' then\n    new.company_logo_url := normalized_data_url;\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"notify_task_assignment","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.notify_task_assignment()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  if new.assigned_to is null or new.assigned_to = new.user_id then\n    return new;\n  end if;\n  if tg_op = 'UPDATE' then\n    if new.assigned_to is not distinct from old.assigned_to then\n      return new;\n    end if;\n  end if;\n  perform public.create_notification_for_user(\n    new.assigned_to,\n    new.tenant_id::uuid,\n    'task.assigned',\n    'Work assigned to you',\n    'Open Work Center to review and complete this task.',\n    null,\n    jsonb_build_object('source_app','crm','severity','info',\n      'entity_type','task','entity_id',new.id,\n      'task_id',new.id,'dedupe_key','task-assigned:' || new.id::text || ':' || new.assigned_to::text)\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"notify_tenant_owner_on_appointment","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.notify_tenant_owner_on_appointment()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_owner_id UUID;\n  v_tenant_name TEXT;\nBEGIN\n  -- Only fire when lead_stage changes TO 'Appointment Set'\n  IF NEW.lead_stage = 'Appointment Set' AND (OLD.lead_stage IS DISTINCT FROM 'Appointment Set') THEN\n    \n    -- Get tenant owner\n    SELECT t.owner_id, t.name INTO v_owner_id, v_tenant_name\n    FROM tenants t\n    WHERE t.id::text = NEW.tenant_org_id\n    LIMIT 1;\n    \n    IF v_owner_id IS NOT NULL THEN\n      INSERT INTO notifications (user_id, tenant_id, type, title, message, link, metadata)\n      VALUES (\n        v_owner_id,\n        NEW.tenant_org_id::uuid,\n        'appointment_booked',\n        '🎯 New Appointment Booked!',\n        COALESCE(NEW.name, 'A lead') || ' — ' || COALESCE(NEW.appt_date, 'TBD') || ' at ' || COALESCE(NEW.appt_time, 'TBD') || ' (set by ' || COALESCE(NEW.assigned_rep, 'unknown') || ')',\n        '/clients/' || NEW.id::text,\n        jsonb_build_object(\n          'lead_id', NEW.lead_id,\n          'customer_name', NEW.name,\n          'appt_date', NEW.appt_date,\n          'appt_time', NEW.appt_time,\n          'rep', NEW.assigned_rep\n        )\n      );\n    END IF;\n  END IF;\n  \n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"notify_tenant_owners_dnc_overdue","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.notify_tenant_owners_dnc_overdue(_days_since integer)\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\nDECLARE\n  v_count integer := 0;\n  v_tenant_count integer := 0;\n  v_platform_count integer := 0;\n  v_title text;\n  v_message text;\n  v_today date := current_date;\nBEGIN\n  v_title := CASE\n    WHEN _days_since >= 31 THEN '⚠️ Federal DNC Scrub OVERDUE'\n    ELSE 'Federal DNC Scrub Due Soon'\n  END;\n  v_message := CASE\n    WHEN _days_since >= 31 THEN 'Your last FTC DNC scrub was ' || _days_since || ' days ago. Calling workflows are blocked until an admin runs the scrub. (FTC TSR §310.4(b)(3)(iv) requires scrubs every 31 days.)'\n    ELSE 'Your last FTC DNC scrub was ' || _days_since || ' days ago. Please coordinate with an admin to re-scrub before day 31 to avoid blocked workflows.'\n  END;\n\n  -- Tenant notifications: role and active membership must be the same tenant.\n  INSERT INTO public.notifications (user_id, tenant_id, type, title, message, link, metadata)\n  SELECT DISTINCT\n    ur.user_id,\n    ur.tenant_id::text,\n    'dnc_scrub_overdue',\n    v_title,\n    v_message,\n    '/admin/dnc',\n    jsonb_build_object('days_since', _days_since, 'reminder_date', v_today)\n  FROM public.user_roles ur\n  JOIN public.user_tenant_memberships m\n    ON m.user_id = ur.user_id\n   AND m.tenant_id = ur.tenant_id\n  WHERE ur.tenant_id IS NOT NULL\n    AND m.status = 'active'\n    AND ur.role IN ('Owner','Tenant Owner','Admin')\n    AND NOT EXISTS (\n      SELECT 1 FROM public.notifications n\n      WHERE n.user_id = ur.user_id\n        AND n.tenant_id IS NOT DISTINCT FROM ur.tenant_id::text\n        AND n.type = 'dnc_scrub_overdue'\n        AND (n.metadata->>'reminder_date')::date = v_today\n    );\n  GET DIAGNOSTICS v_tenant_count = ROW_COUNT;\n\n  -- Platform notifications: strict system-admin primitive only.\n  INSERT INTO public.notifications (user_id, tenant_id, type, title, message, link, metadata)\n  SELECT DISTINCT\n    p.id,\n    NULL,\n    'dnc_scrub_overdue',\n    v_title,\n    v_message,\n    '/admin/dnc',\n    jsonb_build_object('days_since', _days_since, 'reminder_date', v_today, 'platform_admin', true)\n  FROM public.profiles p\n  WHERE public.is_system_admin(p.id)\n    AND NOT EXISTS (\n      SELECT 1 FROM public.notifications n\n      WHERE n.user_id = p.id\n        AND n.tenant_id IS NULL\n        AND n.type = 'dnc_scrub_overdue'\n        AND (n.metadata->>'reminder_date')::date = v_today\n    );\n  GET DIAGNOSTICS v_platform_count = ROW_COUNT;\n\n  v_count := v_tenant_count + v_platform_count;\n  RETURN v_count;\nEND;\n$function$\n","identity_arguments":"_days_since integer"},{"name":"owner_capture_unknown_inbound_call_contact","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.owner_capture_unknown_inbound_call_contact()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant uuid;\n  v_digits text;\n  v_contact_id uuid;\nbegin\n  if coalesce(new.direction, 'inbound') <> 'inbound' then\n    return new;\n  end if;\n\n  v_tenant := new.tenant_org_id;\n\n  if v_tenant is null then\n    select tenant_org_id into v_tenant\n    from public.tenant_phone_numbers\n    where phone_number = new.to_number\n      and is_active = true\n    order by is_default desc, created_at desc\n    limit 1;\n  end if;\n\n  if v_tenant is null then\n    return new;\n  end if;\n\n  new.tenant_org_id := v_tenant;\n\n  v_digits := regexp_replace(coalesce(new.from_number, ''), '\\D', '', 'g');\n\n  if length(v_digits) = 11 and left(v_digits, 1) = '1' then\n    v_digits := right(v_digits, 10);\n  end if;\n\n  if v_digits is null or length(v_digits) < 10 then\n    return new;\n  end if;\n\n  select id into v_contact_id\n  from public.unified_contacts\n  where tenant_org_id = v_tenant::text\n    and deleted_at is null\n    and (\n      phone ilike '%' || v_digits || '%'\n      or normalized_phone = v_digits\n    )\n  order by created_at desc\n  limit 1;\n\n  if v_contact_id is null then\n    insert into public.unified_contacts (\n      tenant_org_id,\n      name,\n      phone,\n      normalized_phone,\n      source,\n      import_source,\n      lead_origin,\n      lead_stage,\n      status,\n      contact_status,\n      priority,\n      raw_data,\n      is_dnc,\n      is_test_account,\n      test_account_static,\n      voicemail_attempt_count\n    )\n    values (\n      v_tenant::text,\n      'Inbound Call Lead ' || coalesce(new.from_number, v_digits),\n      v_digits,\n      v_digits,\n      'Inbound Call',\n      'inbound_call_capture_net',\n      'system',\n      'New / Unassigned',\n      'New',\n      'New',\n      'high',\n      jsonb_build_object(\n        'capture_net', 'owner-inbound-call-unknown-contact-net-v1',\n        'first_channel', 'call',\n        'from_number', new.from_number,\n        'to_number', new.to_number,\n        'twilio_call_sid', new.twilio_call_sid,\n        'call_status', new.call_status,\n        'recording_url', new.recording_url,\n        'captured_at', now()\n      ),\n      false,\n      false,\n      false,\n      0\n    )\n    returning id into v_contact_id;\n  end if;\n\n  new.raw_payload := coalesce(new.raw_payload, '{}'::jsonb)\n    || jsonb_build_object(\n      'capture_net_contact_id', v_contact_id,\n      'capture_net', 'owner-inbound-call-unknown-contact-net-v1'\n    );\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"owner_capture_unknown_inbound_sms_contact","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.owner_capture_unknown_inbound_sms_contact()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant uuid;\n  v_digits text;\n  v_contact_id uuid;\nbegin\n  if new.direction <> 'inbound' then\n    return new;\n  end if;\n\n  if new.contact_id is not null then\n    return new;\n  end if;\n\n  v_tenant := nullif(new.tenant_id, '00000000-0000-0000-0000-000000000000'::uuid);\n\n  if v_tenant is null then\n    select tenant_org_id into v_tenant\n    from public.tenant_phone_numbers\n    where phone_number = new.to_number\n      and is_active = true\n    order by is_default desc, created_at desc\n    limit 1;\n  end if;\n\n  if v_tenant is null then\n    new.error_message := coalesce(new.error_message, 'Unknown inbound SMS: tenant could not be resolved');\n    return new;\n  end if;\n\n  new.tenant_id := v_tenant;\n\n  v_digits := regexp_replace(coalesce(new.from_number, ''), '\\D', '', 'g');\n\n  if length(v_digits) = 11 and left(v_digits, 1) = '1' then\n    v_digits := right(v_digits, 10);\n  end if;\n\n  select id into v_contact_id\n  from public.unified_contacts\n  where tenant_org_id = v_tenant::text\n    and deleted_at is null\n    and (\n      phone ilike '%' || v_digits || '%'\n      or normalized_phone = v_digits\n    )\n  order by created_at desc\n  limit 1;\n\n  if v_contact_id is null then\n    insert into public.unified_contacts (\n      tenant_org_id,\n      name,\n      phone,\n      normalized_phone,\n      source,\n      import_source,\n      lead_origin,\n      lead_stage,\n      status,\n      contact_status,\n      priority,\n      raw_data,\n      is_dnc,\n      is_test_account,\n      test_account_static,\n      voicemail_attempt_count\n    )\n    values (\n      v_tenant::text,\n      'Inbound Lead ' || coalesce(new.from_number, v_digits),\n      v_digits,\n      v_digits,\n      'Inbound SMS',\n      'inbound_sms_capture_net',\n      'system',\n      'New / Unassigned',\n      'New',\n      'New',\n      'high',\n      jsonb_build_object(\n        'capture_net', 'owner-sms-unknown-contact-net-v2',\n        'first_channel', 'sms',\n        'from_number', new.from_number,\n        'to_number', new.to_number,\n        'body_preview', left(coalesce(new.body, ''), 240),\n        'twilio_sid', new.twilio_sid,\n        'captured_at', now()\n      ),\n      false,\n      false,\n      false,\n      0\n    )\n    returning id into v_contact_id;\n  end if;\n\n  new.contact_id := v_contact_id;\n  new.error_message := null;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"owner_receivable_payment_event_rollup","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.owner_receivable_payment_event_rollup()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if tg_op='DELETE' then\n    if old.event_type='payment_received' then\n      perform public.refresh_owner_receivable_payment_rollup(old.receivable_id);\n    end if;\n    return old;\n  end if;\n\n  if tg_op='UPDATE' then\n    if old.event_type='payment_received'\n       and (new.event_type is distinct from old.event_type or new.receivable_id is distinct from old.receivable_id) then\n      perform public.refresh_owner_receivable_payment_rollup(old.receivable_id);\n    end if;\n    if new.event_type='payment_received' then\n      perform public.refresh_owner_receivable_payment_rollup(new.receivable_id);\n    end if;\n    return new;\n  end if;\n\n  if new.event_type='payment_received' then\n    perform public.refresh_owner_receivable_payment_rollup(new.receivable_id);\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"owner_sms_history_dedupe_sid_guard","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.owner_sms_history_dedupe_sid_guard()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if new.twilio_sid is null or btrim(new.twilio_sid) = '' then\n    return new;\n  end if;\n\n  if exists (\n    select 1\n    from public.sms_history existing\n    where existing.twilio_sid = new.twilio_sid\n    limit 1\n  ) then\n    return null;\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"pa_lor_templates_enforce_single_default","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pa_lor_templates_enforce_single_default()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.is_default THEN\n    UPDATE public.pa_lor_templates\n       SET is_default = false\n     WHERE tenant_org_id = NEW.tenant_org_id\n       AND id <> NEW.id\n       AND is_default = true;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"pa_lor_templates_touch","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pa_lor_templates_touch()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN NEW.updated_at = now(); RETURN NEW; END;\n$function$\n","identity_arguments":""},{"name":"paul_schedule_claim_due","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.paul_schedule_claim_due(p_limit integer DEFAULT 5)\n RETURNS SETOF paul_schedules\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  return query\n  with due as (\n    select id from public.paul_schedules\n    where enabled=true and next_run_at<=now()\n    order by next_run_at,id\n    for update skip locked\n    limit greatest(1,least(coalesce(p_limit,5),10))\n  )\n  update public.paul_schedules s\n  set last_run_at=now(),last_status='dispatching',last_error=null,\n      next_run_at=case when s.cadence='interval' then now()+make_interval(mins=>s.interval_minutes) else s.next_run_at end,\n      enabled=case when s.cadence='once' then false else s.enabled end,\n      updated_at=now()\n  from due where s.id=due.id\n  returning s.*;\nend;\n$function$\n","identity_arguments":"p_limit integer"},{"name":"paul_scheduler_authorize","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.paul_scheduler_authorize(p_token text)\n RETURNS boolean\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public', 'vault', 'extensions'\nAS $function$\n  select coalesce((\n    select extensions.digest(ds.decrypted_secret,'sha256')=extensions.digest(coalesce(p_token,''),'sha256')\n    from vault.decrypted_secrets ds\n    where ds.name='knocklaunch_paul_scheduler_trigger'\n    limit 1\n  ),false);\n$function$\n","identity_arguments":"p_token text"},{"name":"pcg_cert_claim_conflicts","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_cert_claim_conflicts(_tenant_id uuid, _candidate text, _exclude_card_id uuid DEFAULT NULL::uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO ''\nAS $function$\n  select case\n    when _candidate ~ '^[0-9]{5}$' then\n      exists(\n        select 1 from public.card_grading_cards c\n        where c.tenant_id = _tenant_id\n          and (_exclude_card_id is null or c.id <> _exclude_card_id)\n          and (\n            c.cert_number = _candidate\n            or (c.cert_number ~ '^[0-9]{4}$' and '0'||c.cert_number = _candidate)\n            or (c.cert_number ~ '^[0-9]{11}$' and strpos(c.cert_number,_candidate)>0)\n          )\n      ) or exists(\n        select 1 from public.pcg_import_rows r\n        where r.tenant_id = _tenant_id\n          and (\n            (coalesce(r.normalized_payload->>'cert_number','') ~ '^[0-9]{11}$'\n              and strpos(r.normalized_payload->>'cert_number',_candidate)>0)\n          )\n      )\n    when _candidate ~ '^[0-9]{11}$' then\n      exists(\n        select 1 from public.card_grading_cards c\n        where c.tenant_id = _tenant_id\n          and (_exclude_card_id is null or c.id <> _exclude_card_id)\n          and (\n            c.cert_number = _candidate\n            or (c.cert_number ~ '^[0-9]{5}$' and strpos(_candidate,c.cert_number)>0)\n            or (c.cert_number ~ '^[0-9]{4}$' and strpos(_candidate,'0'||c.cert_number)>0)\n          )\n      ) or exists(\n        select 1 from public.pcg_import_rows r\n        where r.tenant_id = _tenant_id\n          and (\n            (coalesce(r.normalized_payload->>'cert_number','') ~ '^[0-9]{5}$'\n              and strpos(_candidate,r.normalized_payload->>'cert_number')>0)\n            or (coalesce(r.normalized_payload->>'cert_number','') ~ '^[0-9]{4}$'\n              and strpos(_candidate,'0'||(r.normalized_payload->>'cert_number'))>0)\n          )\n      )\n    else true\n  end\n$function$\n","identity_arguments":"_tenant_id uuid, _candidate text, _exclude_card_id uuid"},{"name":"pcg_confirm_legacy_photo_recovery","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_confirm_legacy_photo_recovery(p_tenant_id uuid, p_batch_id uuid, p_object_key text, p_card_id uuid, p_side text, p_media_url text, p_actor_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_asset public.tenant_media_assets%ROWTYPE;\n  v_card public.card_grading_cards%ROWTYPE;\n  v_existing text;\n  v_column text;\n  v_attachment jsonb;\n  v_now timestamptz := clock_timestamp();\nBEGIN\n  v_column := CASE p_side WHEN 'front' THEN 'front_image_url' WHEN 'back' THEN 'back_image_url'\n    WHEN 'slab_front' THEN 'slab_image_url' WHEN 'slab_back' THEN 'slab_back_image_url' ELSE NULL END;\n  IF v_column IS NULL OR p_actor_id IS NULL OR p_media_url NOT LIKE 'https://%'\n    OR left(p_object_key,length('tenant/'||p_tenant_id::text||'/Cards/Recovery/'||p_batch_id::text||'/'))\n      <> 'tenant/'||p_tenant_id::text||'/Cards/Recovery/'||p_batch_id::text||'/' THEN\n    RAISE EXCEPTION 'invalid_legacy_photo_confirmation';\n  END IF;\n  SELECT * INTO v_asset FROM public.tenant_media_assets\n    WHERE tenant_id=p_tenant_id AND original_key=p_object_key\n      AND collection_key='pcg-legacy-recovery' AND deleted_at IS NULL FOR UPDATE;\n  IF NOT FOUND OR v_asset.metadata->>'batch_id' <> p_batch_id::text\n    OR v_asset.metadata->>'usage' <> 'pcg_legacy_photo_recovery' THEN\n    RAISE EXCEPTION 'recovery_asset_not_in_tenant_batch';\n  END IF;\n  SELECT * INTO v_card FROM public.card_grading_cards\n    WHERE tenant_id=p_tenant_id AND id=p_card_id AND is_demo=false AND deleted_at IS NULL FOR UPDATE;\n  IF NOT FOUND THEN RAISE EXCEPTION 'existing_pcg_card_not_found'; END IF;\n  v_existing := CASE p_side\n    WHEN 'front' THEN nullif(btrim(v_card.front_image_url),'')\n    WHEN 'back' THEN nullif(btrim(v_card.back_image_url),'')\n    WHEN 'slab_front' THEN nullif(btrim(v_card.slab_image_url),'')\n    WHEN 'slab_back' THEN nullif(btrim(v_card.slab_back_image_url),'') END;\n  v_attachment := v_asset.metadata->'attachment';\n  IF v_attachment IS NOT NULL THEN\n    IF v_attachment->>'card_id' <> p_card_id::text OR v_attachment->>'side' <> p_side\n       OR v_existing IS DISTINCT FROM p_media_url THEN\n      RAISE EXCEPTION 'photo_already_assigned_to_another_record';\n    END IF;\n    RETURN jsonb_build_object('card_id',p_card_id,'side',p_side,'idempotent',true);\n  END IF;\n  IF v_existing IS NOT NULL AND v_existing <> p_media_url THEN\n    RAISE EXCEPTION 'photo_slot_already_filled';\n  END IF;\n  IF v_existing IS NULL THEN\n    EXECUTE format('UPDATE public.card_grading_cards SET %I = $1, updated_at = $2 WHERE tenant_id = $3 AND id = $4',v_column)\n      USING p_media_url,v_now,p_tenant_id,p_card_id;\n  END IF;\n  UPDATE public.tenant_media_assets SET\n    metadata=jsonb_set(coalesce(metadata,'{}'::jsonb),'{attachment}',jsonb_build_object(\n      'card_id',p_card_id::text,'side',p_side,'approved_by',p_actor_id::text,'approved_at',v_now,\n      'media_url',p_media_url,'source','pcg_legacy_photo_recovery'\n    ),true),\n    review_status='approved',updated_at=v_now\n    WHERE id=v_asset.id AND tenant_id=p_tenant_id;\n  RETURN jsonb_build_object('card_id',p_card_id,'side',p_side,'idempotent',false);\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_batch_id uuid, p_object_key text, p_card_id uuid, p_side text, p_media_url text, p_actor_id uuid"},{"name":"pcg_default_publish_destination","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_default_publish_destination()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if new.publish_to_website is null then\n    new.publish_to_website := true;\n  end if;\n  if new.publish_to_ebay is null then\n    new.publish_to_ebay := false;\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"pcg_dispatch_legacy_media_migration","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_dispatch_legacy_media_migration(_job_id uuid, _batch_size integer DEFAULT 40)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'extensions'\nAS $function$\ndeclare\n  _token text;\n  _response extensions.http_response;\n  _payload jsonb;\nbegin\n  select dispatch_token\n    into _token\n  from public.pcg_legacy_media_migration_jobs\n  where id = _job_id\n    and status in ('pending','running')\n    and expires_at > now();\n\n  if coalesce(_token,'') = '' then\n    raise exception 'pcg_migration_dispatch_token_required';\n  end if;\n\n  perform extensions.http_set_curlopt('CURLOPT_TIMEOUT_MS','120000');\n\n  _payload := jsonb_build_object(\n    'job_id', _job_id::text,\n    'token', _token,\n    'batch_size', least(75, greatest(1, coalesce(_batch_size,40)))\n  );\n\n  select *\n    into _response\n  from extensions.http_post(\n    'https://ymntrajfubicyxwwdxxa.supabase.co/functions/v1/pcg-r2-media/run-legacy-migration',\n    _payload::text,\n    'application/json'\n  );\n\n  if _response.status <> 200 then\n    raise exception 'pcg_migration_dispatch_failed:%:%', _response.status, left(coalesce(_response.content,''),500);\n  end if;\n\n  return coalesce(_response.content,'{}')::jsonb;\nend;\n$function$\n","identity_arguments":"_job_id uuid, _batch_size integer"},{"name":"pcg_grade_credit_transition","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_grade_credit_transition(p_tenant uuid, p_period uuid, p_submission uuid, p_action text, p_quantity integer, p_key text)\n RETURNS uuid\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nDECLARE\n v_period public.pcg_grade_credit_periods%rowtype;\n v_member public.pcg_seller_memberships%rowtype;\n v_existing public.pcg_grade_credit_events%rowtype;\n v_allocated integer; v_reserved integer; v_used integer; v_released integer;\n v_id uuid;\nBEGIN\n IF p_action NOT IN ('reserve','consume','release')\n    OR p_quantity IS NULL OR p_quantity<1\n    OR NULLIF(btrim(p_key),'') IS NULL OR p_submission IS NULL\n THEN RAISE EXCEPTION 'invalid_credit_transition'; END IF;\n SELECT * INTO STRICT v_period FROM public.pcg_grade_credit_periods\n  WHERE id=p_period AND tenant_id=p_tenant FOR UPDATE;\n SELECT * INTO v_existing FROM public.pcg_grade_credit_events\n  WHERE tenant_id=p_tenant AND event_key=p_key;\n IF FOUND THEN\n   IF v_existing.period_id=p_period AND v_existing.submission_id=p_submission\n     AND v_existing.event_type=p_action AND v_existing.quantity=p_quantity\n   THEN RETURN v_existing.id;\n   ELSE RAISE EXCEPTION 'credit_event_idempotency_conflict'; END IF;\n END IF;\n SELECT * INTO STRICT v_member FROM public.pcg_seller_memberships\n  WHERE id=v_period.membership_id AND tenant_id=p_tenant;\n IF NOT EXISTS (\n  SELECT 1 FROM public.card_grading_submissions sub\n  JOIN public.pcg_marketplace_sellers sel\n    ON sel.tenant_id=p_tenant AND sel.id=v_member.seller_id\n  WHERE sub.id=p_submission AND sub.tenant_id=p_tenant\n    AND sub.customer_contact_id=sel.contact_id\n ) THEN RAISE EXCEPTION 'submission_does_not_belong_to_member'; END IF;\n IF p_action='reserve' THEN\n  IF v_member.status<>'active' OR now()<v_period.starts_at OR now()>=v_period.ends_at\n  THEN RAISE EXCEPTION 'credit_period_not_active'; END IF;\n  SELECT COALESCE(SUM(CASE WHEN event_type='reserve' THEN quantity WHEN event_type='release' THEN -quantity ELSE 0 END),0)\n    INTO v_allocated FROM public.pcg_grade_credit_events WHERE tenant_id=p_tenant AND period_id=p_period;\n  IF v_allocated+p_quantity>v_period.granted THEN RAISE EXCEPTION 'insufficient_grade_credits'; END IF;\n ELSE\n  SELECT COALESCE(SUM(CASE WHEN event_type='reserve' THEN quantity ELSE 0 END),0),\n         COALESCE(SUM(CASE WHEN event_type='consume' THEN quantity ELSE 0 END),0),\n         COALESCE(SUM(CASE WHEN event_type='release' THEN quantity ELSE 0 END),0)\n    INTO v_reserved,v_used,v_released\n    FROM public.pcg_grade_credit_events\n    WHERE tenant_id=p_tenant AND period_id=p_period AND submission_id=p_submission;\n  IF v_reserved-v_used-v_released<p_quantity THEN RAISE EXCEPTION 'insufficient_reserved_credits'; END IF;\n END IF;\n INSERT INTO public.pcg_grade_credit_events(tenant_id,period_id,submission_id,event_key,event_type,quantity)\n VALUES(p_tenant,p_period,p_submission,p_key,p_action,p_quantity) RETURNING id INTO v_id;\n RETURN v_id;\nEND\n$function$\n","identity_arguments":"p_tenant uuid, p_period uuid, p_submission uuid, p_action text, p_quantity integer, p_key text"},{"name":"pcg_guard_cert_registration","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_guard_cert_registration()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\nDECLARE _excluded_card_id uuid := null;\nBEGIN\n  IF new.tenant_id <> '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid\n     OR coalesce(new.cert_number,'') = '' THEN\n    RETURN new;\n  END IF;\n  IF tg_op='UPDATE' THEN\n    IF new.cert_number IS NOT DISTINCT FROM old.cert_number THEN RETURN new; END IF;\n    _excluded_card_id := old.id;\n  END IF;\n  IF new.cert_number ~ '^[0-9]{4}$' THEN\n    RAISE EXCEPTION 'pcg_cert_requires_five_digit_zero_padding' USING errcode='23514';\n  END IF;\n  IF new.cert_number !~ '^([0-9]{5}|[0-9]{11})$' THEN\n    RAISE EXCEPTION 'pcg_cert_unsupported_format_new_registration' USING errcode='23514';\n  END IF;\n  IF new.cert_number ~ '^[0-9]{5}$' AND (\n      new.metadata #>> '{slab_cert_provenance,authority}' IS DISTINCT FROM 'physical_slab_label'\n      OR new.metadata #>> '{slab_cert_provenance,cert_number}' IS DISTINCT FROM new.cert_number\n      OR nullif(btrim(coalesce(new.front_image_url,'')), '') IS NULL\n  ) THEN\n    RAISE EXCEPTION 'pcg_five_digit_cert_requires_verified_slab_photo' USING errcode='23514';\n  END IF;\n  PERFORM pg_catalog.pg_advisory_xact_lock(\n    pg_catalog.hashtextextended('pcg-cert-registration-'||new.tenant_id::text,0)\n  );\n  IF public.pcg_cert_claim_conflicts(new.tenant_id,new.cert_number,_excluded_card_id) THEN\n    RAISE EXCEPTION 'pcg_cert_cross_format_collision' USING errcode='23505';\n  END IF;\n  RETURN new;\nEND;\n$function$\n","identity_arguments":""},{"name":"pcg_guard_certificate_registry_format","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_guard_certificate_registry_format()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\nBEGIN\n  IF new.tenant_id <> '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid THEN RETURN new; END IF;\n  IF tg_op='UPDATE' AND new.cert_number IS NOT DISTINCT FROM old.cert_number THEN RETURN new; END IF;\n  IF coalesce(new.cert_number,'') !~ '^([0-9]{5}|[0-9]{11})$' THEN\n    RAISE EXCEPTION 'pcg_registry_unsupported_cert_format' USING errcode='23514';\n  END IF;\n  -- A registered certificate linked to a card must match the card's exact number.\n  IF new.card_id IS NOT NULL AND NOT EXISTS(\n    SELECT 1 FROM public.card_grading_cards card\n    WHERE card.id=new.card_id AND card.tenant_id=new.tenant_id\n      AND card.cert_number=new.cert_number AND card.deleted_at IS NULL\n  ) THEN\n    RAISE EXCEPTION 'pcg_registry_card_certificate_mismatch' USING errcode='23514';\n  END IF;\n  RETURN new;\nEND;\n$function$\n","identity_arguments":""},{"name":"pcg_link_existing_card","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_link_existing_card(p_tenant_id uuid, p_card_id uuid, p_submission_id uuid, p_kind text DEFAULT 'return_service'::text, p_reason text DEFAULT 'Returning certified card'::text)\n RETURNS uuid\n LANGUAGE plpgsql\n SET search_path TO ''\nAS $function$\nDECLARE v_id uuid;\nBEGIN\n  IF auth.uid() IS NULL THEN RAISE EXCEPTION 'Sign in required'; END IF;\n  IF p_kind NOT IN ('return_service','legacy_reconciliation','photo_attachment') OR length(btrim(p_reason))=0 THEN\n    RAISE EXCEPTION 'Choose a valid reconciliation reason';\n  END IF;\n  IF NOT EXISTS(SELECT 1 FROM public.card_grading_cards WHERE id=p_card_id AND tenant_id=p_tenant_id)\n     OR NOT EXISTS(SELECT 1 FROM public.card_grading_submissions WHERE id=p_submission_id AND tenant_id=p_tenant_id) THEN\n    RAISE EXCEPTION 'Card and order must both belong to the active tenant';\n  END IF;\n  INSERT INTO public.pcg_card_order_links(tenant_id,card_id,submission_id,link_kind,reason,created_by)\n  VALUES (p_tenant_id,p_card_id,p_submission_id,p_kind,p_reason,auth.uid())\n  ON CONFLICT (tenant_id,card_id,submission_id) DO NOTHING\n  RETURNING id INTO v_id;\n  IF v_id IS NULL THEN\n    SELECT id INTO v_id FROM public.pcg_card_order_links\n      WHERE tenant_id=p_tenant_id AND card_id=p_card_id AND submission_id=p_submission_id;\n  ELSE\n    INSERT INTO public.pcg_reconciliation_decisions\n      (tenant_id,card_id,submission_id,action,reason,evidence,actor_user_id)\n    VALUES (p_tenant_id,p_card_id,p_submission_id,'link_existing',p_reason,\n      jsonb_build_object('link_kind',p_kind),auth.uid());\n  END IF;\n  RETURN v_id;\nEND $function$\n","identity_arguments":"p_tenant_id uuid, p_card_id uuid, p_submission_id uuid, p_kind text, p_reason text"},{"name":"pcg_mark_external_withdrawal_pending","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_mark_external_withdrawal_pending()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF OLD.deleted_at IS NULL AND NEW.deleted_at IS NOT NULL THEN\n    UPDATE public.pcg_commerce_publications\n    SET withdrawal_requested_at = NEW.deleted_at,\n        website_status = CASE WHEN website_status = 'live' THEN 'withdraw_pending' ELSE website_status END,\n        ebay_status = CASE WHEN ebay_status = 'live' THEN 'withdraw_pending' ELSE ebay_status END,\n        error_code = 'withdrawal_pending',\n        updated_at = now()\n    WHERE tenant_id = NEW.tenant_id\n      AND card_id = NEW.id;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"pcg_marketplace_place_bid","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_marketplace_place_bid(p_tenant uuid, p_listing uuid, p_user uuid, p_amount numeric, p_key text)\n RETURNS pcg_marketplace_bids\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$declare l public.pcg_marketplace_listings%rowtype;b public.pcg_marketplace_bids%rowtype;m numeric;begin select * into l from public.pcg_marketplace_listings where id=p_listing and tenant_id=p_tenant for update;if not found or l.status<>'active' or l.listing_type<>'auction' then raise exception 'listing_unavailable';end if;if l.auction_ends_at is null or l.auction_ends_at<=now() then raise exception 'auction_ended';end if;if exists(select 1 from public.pcg_marketplace_sellers s where s.id=l.seller_id and s.auth_user_id=p_user) then raise exception 'seller_cannot_bid';end if;select * into b from public.pcg_marketplace_bids where tenant_id=p_tenant and bidder_user_id=p_user and idempotency_key=p_key;if found then return b;end if;m:=coalesce(l.current_bid,l.starting_bid,0)+case when l.current_bid is null then 0 else l.min_increment end;if p_amount<m then raise exception 'bid_too_low';end if;insert into public.pcg_marketplace_bids(tenant_id,listing_id,bidder_user_id,amount,idempotency_key) values(p_tenant,p_listing,p_user,p_amount,p_key) returning * into b;update public.pcg_marketplace_listings set current_bid=p_amount where id=p_listing;return b;end$function$\n","identity_arguments":"p_tenant uuid, p_listing uuid, p_user uuid, p_amount numeric, p_key text"},{"name":"pcg_reconcile_verified_slab_publications","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_reconcile_verified_slab_publications()\n RETURNS jsonb\n LANGUAGE plpgsql\n SET search_path TO ''\nAS $function$\nDECLARE\n  v_tenant constant uuid := '9602e177-0cbb-496c-bdf5-2fbc93f1b859';\n  v_new integer := 0;\n  v_restored integer := 0;\n  v_pending integer := 0;\nBEGIN\n  -- Existing, unpublished registry entries can be finalized without replacing identity.\n  WITH eligible AS (\n    SELECT k.*\n      FROM public.card_grading_cards k\n     WHERE k.tenant_id = v_tenant\n       AND k.deleted_at IS NULL\n       AND k.is_demo = false\n       AND k.cert_number ~ '^[0-9]{5}$'\n       AND k.cert_number = k.metadata->'certification'->>'printed_cert_number'\n       AND k.metadata->'certification'->>'source' = 'physical_slab_printed_number'\n       AND k.metadata->>'intake_destination' IN ('shop','cert')\n       AND k.publish_to_website = true\n       AND NULLIF(BTRIM(COALESCE(k.front_image_url,'')),'') IS NOT NULL\n       AND NULLIF(BTRIM(COALESCE(k.back_image_url,'')),'') IS NOT NULL\n       AND NULLIF(BTRIM(COALESCE(k.grade_label,'')),'') IS NOT NULL\n       AND k.grade IS NOT NULL\n       AND NOT EXISTS (\n         SELECT 1 FROM public.pcg_card_publication_revocations r\n          WHERE r.tenant_id=k.tenant_id\n            AND (r.card_id=k.id OR r.cert_number=k.cert_number)\n       )\n  )\n  UPDATE public.card_grading_certificates c\n     SET published_at=now(),\n         category=e.category,\n         year=e.year,\n         manufacturer=e.manufacturer,\n         set_name=e.set_name,\n         brand_set=e.brand_set,\n         subset=e.subset,\n         player_character=e.player_character,\n         card_number=e.card_number,\n         variation=e.variation,\n         serial_number=e.serial_number,\n         autograph_present=e.autograph_present,\n         relic_present=e.relic_present,\n         final_grade=e.grade,\n         grade_label=e.grade_label,\n         final_image_url=COALESCE(NULLIF(e.slab_image_url,''),e.front_image_url),\n         finalized_at=COALESCE(c.finalized_at,e.finalized_at,now()),\n         updated_at=now()\n    FROM eligible e\n   WHERE c.tenant_id=e.tenant_id AND c.card_id=e.id\n     AND c.cert_number=e.cert_number AND c.published_at IS NULL;\n  GET DIAGNOSTICS v_restored = ROW_COUNT;\n\n  -- The source is an already certified physical slab; NEVER generate a number.\n  WITH eligible AS (\n    SELECT k.*\n      FROM public.card_grading_cards k\n     WHERE k.tenant_id=v_tenant\n       AND k.deleted_at IS NULL\n       AND k.is_demo=false\n       AND k.cert_number ~ '^[0-9]{5}$'\n       AND k.cert_number=k.metadata->'certification'->>'printed_cert_number'\n       AND k.metadata->'certification'->>'source'='physical_slab_printed_number'\n       AND k.metadata->>'intake_destination' IN ('shop','cert')\n       AND k.publish_to_website=true\n       AND NULLIF(BTRIM(COALESCE(k.front_image_url,'')),'') IS NOT NULL\n       AND NULLIF(BTRIM(COALESCE(k.back_image_url,'')),'') IS NOT NULL\n       AND NULLIF(BTRIM(COALESCE(k.grade_label,'')),'') IS NOT NULL\n       AND k.grade IS NOT NULL\n       AND NOT EXISTS (\n         SELECT 1 FROM public.pcg_card_publication_revocations r\n         WHERE r.tenant_id=k.tenant_id AND (r.card_id=k.id OR r.cert_number=k.cert_number)\n       )\n       AND NOT EXISTS (SELECT 1 FROM public.card_grading_certificates existing WHERE existing.card_id=k.id)\n       AND NOT EXISTS (SELECT 1 FROM public.card_grading_certificates conflicting WHERE conflicting.tenant_id=k.tenant_id AND conflicting.cert_number=k.cert_number)\n  )\n  INSERT INTO public.card_grading_certificates(\n    tenant_id,card_id,cert_number,category,year,manufacturer,set_name,brand_set,subset,\n    player_character,card_number,variation,serial_number,autograph_present,relic_present,\n    final_grade,grade_label,final_image_url,finalized_at,published_at\n  )\n  SELECT e.tenant_id,e.id,e.cert_number,e.category,e.year,e.manufacturer,e.set_name,e.brand_set,e.subset,\n         e.player_character,e.card_number,e.variation,e.serial_number,e.autograph_present,e.relic_present,\n         e.grade,e.grade_label,COALESCE(NULLIF(e.slab_image_url,''),e.front_image_url),\n         COALESCE(e.finalized_at,now()),now()\n    FROM eligible e\n  ON CONFLICT DO NOTHING;\n  GET DIAGNOSTICS v_new = ROW_COUNT;\n\n  -- A pending status remains visibly pending until the public API, not merely the DB,\n  -- is independently verified. The receipt is deliberately not marked verified here.\n  SELECT COUNT(*) INTO v_pending\n    FROM public.card_grading_cards k\n   WHERE k.tenant_id=v_tenant\n     AND k.deleted_at IS NULL AND k.is_demo=false\n     AND k.metadata->>'intake_destination' IN ('shop','cert')\n     AND k.metadata->'public_verification'->>'status'='pending'\n     AND NOT EXISTS (\n       SELECT 1 FROM public.card_grading_public_certificates v\n        WHERE v.tenant_id=k.tenant_id AND v.cert_number=k.cert_number\n     );\n  RETURN jsonb_build_object('new_public_certificates',v_new,'previously_unpublished_fixed',v_restored,'pending_registry_gaps',v_pending,'checked_at',now());\nEND;\n$function$\n","identity_arguments":""},{"name":"pcg_restore_card","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_restore_card(p_tenant_id uuid, p_card_id uuid, p_message text)\n RETURNS card_grading_cards\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_message text := trim(coalesce(p_message,''));\n  v_card public.card_grading_cards;\nbegin\n  if v_message = '' then\n    raise exception 'A restore message is required.';\n  end if;\n\n  update public.card_grading_cards\n  set deleted_at = null,\n      deleted_by = null,\n      deletion_reason = null,\n      restored_at = now(),\n      restored_by = auth.uid(),\n      restore_reason = v_message,\n      updated_at = now()\n  where tenant_id = p_tenant_id\n    and id = p_card_id\n    and deleted_at is not null\n  returning * into v_card;\n\n  if v_card.id is null then\n    raise exception 'Card not found or is not deleted.';\n  end if;\n\n  insert into public.pcg_card_lifecycle_events(tenant_id,card_id,action,message,actor_user_id)\n  values (p_tenant_id,p_card_id,'restore',v_message,auth.uid());\n\n  return v_card;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_card_id uuid, p_message text"},{"name":"pcg_revoke_deleted_card_publications","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_revoke_deleted_card_publications()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF OLD.deleted_at IS NULL AND NEW.deleted_at IS NOT NULL THEN\n    INSERT INTO public.pcg_card_publication_revocations\n      (tenant_id, card_id, cert_number, revoked_at)\n    VALUES (NEW.tenant_id, NEW.id, NEW.cert_number, NEW.deleted_at)\n    ON CONFLICT (tenant_id, card_id) DO NOTHING;\n\n    UPDATE public.pcg_marketplace_listings\n    SET publication_revoked_at = NEW.deleted_at,\n        status = CASE WHEN status = 'active' THEN 'ended' ELSE status END,\n        updated_at = now()\n    WHERE tenant_id = NEW.tenant_id\n      AND card_id = NEW.id\n      AND publication_revoked_at IS NULL;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"pcg_soft_delete_card","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_soft_delete_card(p_tenant_id uuid, p_card_id uuid, p_message text)\n RETURNS card_grading_cards\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_message text := trim(coalesce(p_message,''));\n  v_card public.card_grading_cards;\nbegin\n  if v_message = '' then\n    raise exception 'A deletion message is required.';\n  end if;\n\n  update public.card_grading_cards\n  set deleted_at = now(),\n      deleted_by = auth.uid(),\n      deletion_reason = v_message,\n      restored_at = null,\n      restored_by = null,\n      restore_reason = null,\n      updated_at = now()\n  where tenant_id = p_tenant_id\n    and id = p_card_id\n    and deleted_at is null\n  returning * into v_card;\n\n  if v_card.id is null then\n    raise exception 'Card not found or already deleted.';\n  end if;\n\n  insert into public.pcg_card_lifecycle_events(tenant_id,card_id,action,message,actor_user_id)\n  values (p_tenant_id,p_card_id,'delete',v_message,auth.uid());\n\n  return v_card;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_card_id uuid, p_message text"},{"name":"pcg_stage_rank","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_stage_rank(stage text)\n RETURNS integer\n LANGUAGE sql\n IMMUTABLE\nAS $function$\n  select case lower(coalesce(stage,''))\n    when 'received' then 10\n    when 'intake_imaging' then 20\n    when 'authentication' then 30\n    when 'grading' then 40\n    when 'encapsulation' then 50\n    when 'qa' then 60\n    when 'ready' then 70\n    when 'shipped' then 80\n    when 'picked_up' then 90\n    when 'delivered' then 90\n    when 'closed' then 100\n    else 10\n  end;\n$function$\n","identity_arguments":"stage text"},{"name":"pcg_wholesale_audit_partner","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_wholesale_audit_partner()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO ''\nAS $function$\nbegin\n  if tg_op = 'UPDATE' and new.tenant_id is distinct from old.tenant_id then\n    raise exception 'wholesale_tenant_is_immutable';\n  end if;\n  if tg_op = 'INSERT' then\n    insert into public.pcg_wholesale_activity(tenant_id,partner_id,event_type,summary,created_by)\n    values (new.tenant_id,new.id,'created','Relationship added: ' || new.name || ' (' || new.stage || ')',new.created_by);\n  elsif new.stage is distinct from old.stage then\n    insert into public.pcg_wholesale_activity(tenant_id,partner_id,event_type,summary,created_by)\n    values (new.tenant_id,new.id,'status_change','Application stage: ' || old.stage || ' to ' || new.stage,new.updated_by);\n  end if;\n  if tg_op = 'UPDATE' and new.follow_up_on is distinct from old.follow_up_on then\n    insert into public.pcg_wholesale_activity(tenant_id,partner_id,event_type,summary,created_by)\n    values (new.tenant_id,new.id,'follow_up',\n      case when new.follow_up_on is null then 'Follow-up date cleared'\n      else 'Follow-up scheduled: ' || new.follow_up_on::text end,new.updated_by);\n  end if;\n  return null;\nend;\n$function$\n","identity_arguments":""},{"name":"pcg_wholesale_guard_evidence","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_wholesale_guard_evidence()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO ''\nAS $function$\nbegin\n  if not exists (\n    select 1 from public.tenant_media_assets a\n    where a.id = new.asset_id and a.tenant_id = new.tenant_id\n      and a.collection_key = 'pcg-wholesale-evidence'\n      and a.deleted_at is null and a.published is false and a.status = 'ready'\n  ) then\n    raise exception 'wholesale_private_same_tenant_evidence_required';\n  end if;\n  if tg_op = 'UPDATE' and new.tenant_id is distinct from old.tenant_id then\n    raise exception 'wholesale_tenant_is_immutable';\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"pcg_wholesale_touch_partner","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pcg_wholesale_touch_partner()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO ''\nAS $function$\nbegin\n  if new.tenant_id is distinct from old.tenant_id or new.created_by is distinct from old.created_by then\n    raise exception 'wholesale_identity_is_immutable';\n  end if;\n  new.updated_at = now();\n  new.updated_by = auth.uid();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"pick_next_ring_group_member","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.pick_next_ring_group_member(_group_id uuid)\n RETURNS TABLE(user_id uuid, phone text)\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  SELECT rgm.user_id::uuid,\n         coalesce(nullif(ap.current_phone,''), nullif(p.phone,''))::text\n  FROM public.ring_group_members rgm\n  JOIN public.ring_groups rg ON rg.id = rgm.ring_group_id AND rg.is_active = true\n  JOIN public.profiles p ON p.id = rgm.user_id\n  LEFT JOIN public.agent_presence ap ON ap.user_id = rgm.user_id AND ap.tenant_id = rgm.tenant_org_id\n  WHERE rgm.ring_group_id = _group_id\n    AND public.is_tenant_member(auth.uid(), rg.tenant_org_id)\n    AND rgm.is_active = true\n    AND coalesce(nullif(ap.current_phone,''), nullif(p.phone,'')) IS NOT NULL\n    AND coalesce(nullif(ap.current_phone,''), nullif(p.phone,'')) <> ''\n    AND (ap.status IS NULL OR ap.status IN ('available','online','idle'))\n  ORDER BY rgm.priority ASC NULLS LAST, rgm.user_id ASC\n  LIMIT 1;\n$function$\n","identity_arguments":"_group_id uuid"},{"name":"platform_message_after_insert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.platform_message_after_insert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare sender_name text; conv_tenant uuid;\nbegin\n  select coalesce(nullif(trim(name),''),'KNOCKLAUNCH User') into sender_name from public.profiles where id=new.sender_id;\n  select tenant_id into conv_tenant from public.message_conversations where id=new.conversation_id;\n  insert into public.message_user_events(user_id,conversation_id,event_type)\n    select user_id,new.conversation_id,'message_created' from public.message_conversation_members where conversation_id=new.conversation_id;\n  insert into public.notifications(user_id,tenant_id,type,title,message,link,metadata)\n    select cm.user_id,coalesce(conv_tenant::text,new.context->>'tenant_id'),'message_received',\n      'Message from '||coalesce(sender_name,'KNOCKLAUNCH User'),\n      case when new.encrypted_payload is not null then 'New encrypted message' else left(new.body,180) end,\n      '/messages?conversation='||new.conversation_id::text,\n      jsonb_build_object('source_app','messages','actor_user_id',new.sender_id,'entity_type','message_conversation',\n        'entity_id',new.conversation_id,'conversation_id',new.conversation_id,'dedupe_key','message:'||new.id::text)\n    from public.message_conversation_members cm\n    where cm.conversation_id=new.conversation_id and cm.user_id<>new.sender_id;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"platform_notification_category","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.platform_notification_category(p_event_type text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'pg_catalog'\nAS $function$\n  select case\n    when coalesce(p_event_type,'') ~* '^(message_received|message[._]|mail[.]inbound|email[.]inbound)' then 'messages'\n    when coalesce(p_event_type,'') ~* '(overdue|escalat|deadline|past_due|dnc_scrub)' then 'deadlines'\n    when coalesce(p_event_type,'') ~* '(assigned|assignment|job_request_pending)' then 'assigned'\n    when coalesce(p_event_type,'') ~* '(billing|invoice|payment|receipt|subscription)' then 'billing'\n    else 'updates' end;\n$function$\n","identity_arguments":"p_event_type text"},{"name":"platform_notification_default_channel","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.platform_notification_default_channel(p_category text)\n RETURNS text\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'pg_catalog'\nAS $function$\n  select case\n    when p_category in ('messages','assigned','deadlines') then 'push'\n    when p_category in ('billing','updates') then 'email'\n    else 'in_app' end;\n$function$\n","identity_arguments":"p_category text"},{"name":"portal_ack_check_received","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.portal_ack_check_received(_portal_token text, _claim_id uuid, _received boolean, _notes text DEFAULT NULL::text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _link RECORD;\n  _claim RECORD;\nBEGIN\n  -- Validate portal link\n  SELECT * INTO _link FROM public.portal_links\n   WHERE token = _portal_token AND is_active = true\n     AND (expires_at IS NULL OR expires_at > now())\n   LIMIT 1;\n\n  IF _link IS NULL THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'Invalid or expired portal link');\n  END IF;\n\n  -- Validate claim belongs to this contact + tenant\n  SELECT * INTO _claim FROM public.contact_claims\n   WHERE id = _claim_id\n     AND contact_id = _link.contact_id\n     AND tenant_org_id = _link.tenant_org_id\n   LIMIT 1;\n\n  IF _claim IS NULL THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'Claim not found for this portal');\n  END IF;\n\n  UPDATE public.contact_claims\n     SET check_received_by_homeowner_at = CASE WHEN _received THEN now() ELSE NULL END,\n         check_received_notes = _notes,\n         updated_at = now()\n   WHERE id = _claim_id;\n\n  RETURN jsonb_build_object('ok', true);\nEND;\n$function$\n","identity_arguments":"_portal_token text, _claim_id uuid, _received boolean, _notes text"},{"name":"portal_get_roofing_project","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.portal_get_roofing_project(_portal_token text)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'extensions'\nAS $function$\ndeclare\n  v_contact_id uuid;\n  v_tenant_id uuid;\n  v_expires_at timestamptz;\n  v_job record;\n  v_ops record;\n  v_material record;\n  v_permit record;\n  v_closeout record;\n  v_token_hash text;\nbegin\n  select contact_id, tenant_org_id, expires_at\n    into v_contact_id, v_tenant_id, v_expires_at\n  from public.portal_links\n  where token = _portal_token\n    and is_active = true\n  limit 1;\n\n  if v_contact_id is null then\n    v_token_hash := encode(digest(_portal_token, 'sha256'), 'hex');\n    select contact_id, tenant_id, expires_at\n      into v_contact_id, v_tenant_id, v_expires_at\n    from public.customer_portal_access\n    where is_active = true\n      and (token_hash = v_token_hash or access_token = _portal_token)\n    limit 1;\n  end if;\n\n  if v_contact_id is null or v_tenant_id is null or (v_expires_at is not null and v_expires_at < now()) then\n    return null;\n  end if;\n\n  select id, status\n    into v_job\n  from public.jobs\n  where tenant_id = v_tenant_id\n    and contact_id = v_contact_id\n  order by updated_at desc nulls last, created_at desc\n  limit 1;\n\n  if not found then return null; end if;\n\n  select project_phase, install_date, materials_status, permit_status, closeout_status, warranty_status\n    into v_ops\n  from public.roofing_project_ops\n  where tenant_id = v_tenant_id\n    and job_id = v_job.id\n  limit 1;\n\n  if not found then return null; end if;\n\n  select status, delivery_date\n    into v_material\n  from public.roofing_material_orders\n  where tenant_id = v_tenant_id\n    and job_id = v_job.id\n  order by created_at desc\n  limit 1;\n\n  select status\n    into v_permit\n  from public.permits\n  where tenant_org_id = v_tenant_id\n    and contact_id = v_contact_id\n    and coalesce(is_roof_related, false) = true\n  order by updated_at desc nulls last, created_at desc\n  limit 1;\n\n  select final_photos_complete,\n         completion_certificate_complete,\n         warranty_registered,\n         homeowner_handoff_complete,\n         closed_at\n    into v_closeout\n  from public.roofing_closeout\n  where tenant_id = v_tenant_id\n    and job_id = v_job.id\n  limit 1;\n\n  return jsonb_build_object(\n    'phase', v_ops.project_phase,\n    'installDate', v_ops.install_date,\n    'materialStatus', coalesce(v_material.status, v_ops.materials_status),\n    'materialDeliveryDate', v_material.delivery_date,\n    'permitStatus', coalesce(v_permit.status, v_ops.permit_status),\n    'closeoutStatus', v_ops.closeout_status,\n    'warrantyStatus', v_ops.warranty_status,\n    'warrantyRegistered', coalesce(v_closeout.warranty_registered, false),\n    'finalPhotosComplete', coalesce(v_closeout.final_photos_complete, false),\n    'completionCertificateComplete', coalesce(v_closeout.completion_certificate_complete, false),\n    'homeownerHandoffComplete', coalesce(v_closeout.homeowner_handoff_complete, false),\n    'closedAt', v_closeout.closed_at\n  );\nend;\n$function$\n","identity_arguments":"_portal_token text"},{"name":"prepare_declared_tenant_blueprint","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.prepare_declared_tenant_blueprint()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE v_declared text; v_model text; v_blueprint jsonb; v_apps jsonb; v_manifest jsonb; v_custom boolean; v_slug text;\nBEGIN\n  v_declared:=public.normalize_declared_business_type(coalesce(nullif(new.settings->>'declared_business_type',''),nullif(new.settings->>'business_type',''),nullif(new.settings->>'business_category',''),nullif(new.settings#>>'{business_operating_blueprint,businessTypeKey}',''),nullif(new.tenant_type,'')));\n  IF v_declared IS NULL THEN RAISE EXCEPTION 'A valid declared business type is required before tenant creation' USING ERRCODE='22023'; END IF;\n  new.tenant_type:=v_declared;\n  v_slug:=nullif(trim(coalesce(new.company_slug,'')),'');\n  IF v_slug IS NULL THEN\n    v_slug:=trim(both '-' from regexp_replace(lower(new.name),'[^a-z0-9]+','-','g'));\n    IF v_slug='' THEN v_slug:='tenant'; END IF;\n    IF EXISTS(SELECT 1 FROM public.tenants existing WHERE existing.company_slug=v_slug) THEN v_slug:=v_slug||'-'||substr(replace(new.id::text,'-',''),1,6); END IF;\n  END IF;\n  new.company_slug:=v_slug;\n  v_model:=public.tenant_operating_model_for(v_declared,coalesce(new.settings,'{}'::jsonb));\n  IF v_model IS NULL THEN RAISE EXCEPTION 'Operating model is required for declared business type %; tenant creation will not generalize it to MISC',v_declared USING ERRCODE='22023'; END IF;\n  v_blueprint:=public.build_tenant_business_blueprint(v_declared,coalesce(new.settings,'{}'::jsonb),new.name);\n  IF v_declared='EVENT_RENTALS' THEN\n    v_blueprint:=v_blueprint||public.event_rentals_operating_contract()||jsonb_build_object(\n      'contractVersion',2,\n      'businessTypeKey','EVENT_RENTALS','operatingModel','events',\n      'primaryRelationship',jsonb_build_object('singular','Client','plural','Clients','kind','client'),\n      'workObjects',jsonb_build_array(\n        jsonb_build_object('singular','Event','plural','Events','kind','events'),\n        jsonb_build_object('singular','Rental Booking','plural','Rental Bookings','kind','rentals'),\n        jsonb_build_object('singular','Activation','plural','Activations','kind','activations')\n      ),\n      'workflowStages',jsonb_build_array('Inquiry','Quote','Reserved','Prep','Setup','Live','Teardown','Return & Inspection','Complete','Paid'),\n      'vocabulary',jsonb_build_object('workspace','Event Operations','work','Event','workPlural','Events'),\n      'dashboardPriorities',jsonb_build_array('Upcoming bookings and events','Readiness risks and blockers','Inventory conflicts and utilization','Deliveries and pickups','Outstanding deposits and balances','Vendor compliance expirations','Next operational tasks'),\n      'modules',jsonb_build_array(\n        jsonb_build_object('id','today','path','dashboard','label','Operations','emphasis','primary'),\n        jsonb_build_object('id','booking','path','calendar','label','Bookings'),\n        jsonb_build_object('id','calendar','path','calendar','label','Event Calendar'),\n        jsonb_build_object('id','contacts','path','contacts','label','Customers'),\n        jsonb_build_object('id','proposals','path','proposals','label','Quotes & Proposals'),\n        jsonb_build_object('id','payments','path','payments','label','Payments'),\n        jsonb_build_object('id','jobs','path','jobs','label','Crews & Work'),\n        jsonb_build_object('id','communications','path','communications','label','Messages'),\n        jsonb_build_object('id','documents','path','documents','label','Documents'),\n        jsonb_build_object('id','analytics','path','analytics','label','Performance'),\n        jsonb_build_object('id','opportunity-radar','path','opportunity-radar','label','Opportunities'),\n        jsonb_build_object('id','settings','path','settings','label','Settings')\n      )\n    );\n  END IF;\n  v_apps:=coalesce(v_blueprint->'applications',public.tenant_blueprint_applications(v_model));\n  IF v_declared='EVENT_RENTALS' THEN\n    v_apps:=jsonb_build_array('booking','contacts','calendar','proposals','payments','invoices','documents','tasks','jobs','communications','analytics','opportunity-radar','settings');\n  END IF;\n  v_custom:=v_declared NOT IN ('MITIGATION','ROOFING_COMPANY','PUBLIC_ADJUSTER_FIRM','REALTOR','LAWN_CARE','TIRE_SHOP','AUTO_DETAILING','CAFE_QSR','MOBILE_VENDOR','SHORT_TERM_RENTAL','EVENT_RENTALS','MISC');\n  v_manifest:=coalesce(new.settings->'tenant_manifest','{}'::jsonb)||jsonb_build_object('schemaVersion',2,'businessTypeKey',v_declared,'moduleTenantType',CASE WHEN v_custom THEN 'CUSTOM_BLUEPRINT' ELSE v_declared END,'applications',v_apps,'businessOperatingBlueprint',v_blueprint);\n  new.settings:=coalesce(new.settings,'{}'::jsonb)||jsonb_build_object('declared_business_type',v_declared,'operating_model',v_model,'business_operating_blueprint',v_blueprint,'enabled_applications',v_apps,'tenant_manifest',v_manifest,'route_namespace',new.company_slug,'canonical_workspace_route','/'||new.company_slug||'/dashboard','canonical_owner_route','/'||new.company_slug||'/dashboard','canonical_public_route','https://whatsmyprogress.com/'||new.company_slug||'/','bootstrap_state','provisioning')||CASE WHEN v_custom THEN jsonb_build_object('archetype','ADAPTIVE_BUSINESS','experience_family','adaptive-business-operations','workspace_variant',v_model||'_business') ELSE '{}'::jsonb END;\n  IF v_declared='EVENT_RENTALS' THEN\n    new.settings:=new.settings||jsonb_build_object('shell_template','MODES','experience_family','modes','routing_family','EVENT_RENTALS_OPS','workspace_type','event_rentals','workspace_variant','event_operations','tenant_platform_contract','KNOCKLAUNCH-TENANT-v1');\n  END IF;\n  IF v_declared='EVENT_RENTALS' AND new.settings->'modes' IS NULL THEN\n    new.settings:=new.settings||jsonb_build_object('modes',jsonb_build_object('version',3,'cards',jsonb_build_array(\n      jsonb_build_object('key','rentals','title','Rentals','headline','Know what is available and get it booked','subtitle','Inventory, availability, quotes, delivery & returns','color','#4F46E5','route','/'||new.company_slug||'/dashboard?mode=rentals','storage_slug','rentals','roles',jsonb_build_array('Owner','Admin','GodMode'),'primary_applications',jsonb_build_array('booking','proposals','payments','documents','tasks'),'quick_actions',jsonb_build_array(jsonb_build_object('label','New Rental','application','booking','action','create'),jsonb_build_object('label','Build Proposal','application','proposals','action','create'),jsonb_build_object('label','Collect Payment','application','payments','action','collect'))),\n      jsonb_build_object('key','events','title','Events','headline','Get every event ready before showtime','subtitle','Calendar, crews, readiness, setup & teardown','color','#0F766E','route','/'||new.company_slug||'/dashboard?mode=events','storage_slug','events','roles',jsonb_build_array('Owner','Admin','GodMode'),'primary_applications',jsonb_build_array('calendar','booking','jobs','tasks','documents'),'quick_actions',jsonb_build_array(jsonb_build_object('label','New Event','application','calendar','action','create-event'),jsonb_build_object('label','Create Work','application','jobs','action','create'),jsonb_build_object('label','Create Task','application','tasks','action','create'))),\n      jsonb_build_object('key','activations','title','Activations','headline','Turn events into measurable business','subtitle','Promote, capture leads, measure ROI & follow up','color','#B45309','route','/'||new.company_slug||'/dashboard?mode=activations','storage_slug','activations','roles',jsonb_build_array('Owner','Admin','GodMode'),'primary_applications',jsonb_build_array('contacts','calendar','opportunity-radar','communications','analytics'),'quick_actions',jsonb_build_array(jsonb_build_object('label','Add Contact','application','contacts','action','create'),jsonb_build_object('label','Create Event','application','calendar','action','create-event'),jsonb_build_object('label','Scan Opportunities','application','opportunity-radar','action','scan'))),\n      jsonb_build_object('key','vendors','title','Vendors','headline','Keep every vendor confirmed and compliant','subtitle','Assignments, documents, COIs, expirations & history','color','#7C3AED','route','/'||new.company_slug||'/dashboard?mode=vendors','storage_slug','vendors','roles',jsonb_build_array('Owner','Admin','GodMode'),'primary_applications',jsonb_build_array('contacts','documents','tasks','communications'),'quick_actions',jsonb_build_array(jsonb_build_object('label','Add Contact','application','contacts','action','create'),jsonb_build_object('label','Create Task','application','tasks','action','create')))\n    )));\n  END IF;\n  IF v_model='appointments' THEN new.settings:=new.settings||jsonb_build_object('enabled_automations',coalesce(new.settings->'enabled_automations','[\"booking-confirmation\",\"appointment-reminder\",\"queue-up-next\",\"queue-your-turn\",\"rebook-followup\"]'::jsonb)); END IF;\n  new.status:='inactive'; new.is_active:=false; RETURN new;\nEND;\n$function$\n","identity_arguments":""},{"name":"prepare_handyman_modes_bootstrap","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.prepare_handyman_modes_bootstrap()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_type text;\n  v_slug text;\n  v_settings jsonb := coalesce(new.settings, '{}'::jsonb);\n  v_modes jsonb := coalesce(new.settings->'modes', '{}'::jsonb);\nbegin\n  v_type := public.normalize_declared_business_type(coalesce(\n    nullif(v_settings->>'declared_business_type',''),\n    nullif(v_settings#>>'{business_operating_blueprint,businessTypeKey}',''),\n    nullif(new.tenant_type,'')\n  ));\n\n  if v_type not in ('HANDYMAN','HANDYMAN_SERVICE','HANDYMAN_SERVICES') then\n    return new;\n  end if;\n\n  new.tenant_type := 'HANDYMAN';\n  v_slug := coalesce(\n    nullif(trim(new.company_slug),''),\n    nullif(trim(both '-' from regexp_replace(lower(coalesce(new.name,'')), '[^a-z0-9]+', '-', 'g')),''),\n    'handyman'\n  );\n\n  v_settings := v_settings || jsonb_build_object(\n    'declared_business_type','HANDYMAN',\n    'operating_model','service_jobs',\n    'shell_template','MODES',\n    'experience_family','modes',\n    'workspace_type','handyman_field_service',\n    'workspace_variant','handyman_operations',\n    'routing_family','HANDYMAN_FIELD_SERVICE',\n    'tenant_classification',jsonb_build_object(\n      'schemaVersion',1,\n      'primary_archetype','field-service',\n      'traits',jsonb_build_array('modes','booking-scheduling','customer-portal','business-documents','payments'),\n      'activation_state','active'\n    ),\n    'business_operating_blueprint',\n      coalesce(v_settings->'business_operating_blueprint','{}'::jsonb)\n      || jsonb_build_object(\n        'businessTypeKey','HANDYMAN',\n        'operatingModel','service_jobs',\n        'applications',jsonb_build_array(\n          'booking','contacts','jobs','calendar','tasks','communications',\n          'proposals','invoices','payments','documents','forms','analytics'\n        )\n      )\n  );\n\n  if jsonb_typeof(v_modes) <> 'object' then\n    v_modes := '{}'::jsonb;\n  end if;\n\n  if jsonb_typeof(v_modes->'cards') <> 'array' or jsonb_array_length(v_modes->'cards') = 0 then\n    v_modes := v_modes || jsonb_build_object('version',4,'cards',jsonb_build_array(\n      jsonb_build_object(\n        'key','dispatch','title','Dispatch','storage_slug','dispatch',\n        'route','/'||v_slug||'/dashboard?mode=dispatch',\n        'primary_applications',jsonb_build_array('booking','calendar','tasks','communications','contacts')\n      ),\n      jsonb_build_object(\n        'key','active-jobs','title','Active Jobs','storage_slug','active-jobs',\n        'route','/'||v_slug||'/dashboard?mode=active-jobs',\n        'primary_applications',jsonb_build_array('jobs','documents','tasks','calendar','communications')\n      ),\n      jsonb_build_object(\n        'key','customers','title','Customers','storage_slug','customers',\n        'route','/'||v_slug||'/dashboard?mode=customers',\n        'primary_applications',jsonb_build_array('contacts','proposals','booking','communications','documents')\n      ),\n      jsonb_build_object(\n        'key','back-office','title','Back Office','storage_slug','back-office',\n        'route','/'||v_slug||'/dashboard?mode=back-office',\n        'primary_applications',jsonb_build_array('invoices','payments','proposals','analytics','documents')\n      )\n    ));\n  end if;\n\n  new.settings := v_settings || jsonb_build_object('modes',v_modes);\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"prepare_mobile_catering_first_class","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.prepare_mobile_catering_first_class()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_family text;\nbegin\n  if public.normalize_declared_business_type(new.tenant_type) <> 'MOBILE_CATERING' then\n    return new;\n  end if;\n\n  v_family := public.canonical_tenant_experience_family(coalesce(new.settings, '{}'::jsonb), 'MOBILE_CATERING');\n  new.tenant_type := 'MOBILE_CATERING';\n  new.settings := coalesce(new.settings, '{}'::jsonb) || jsonb_build_object(\n    'business_type', 'MOBILE_CATERING',\n    'declared_business_type', 'MOBILE_CATERING',\n    'declared_tenant_type', 'MOBILE_CATERING',\n    'archetype', 'MOBILE_CATERING',\n    'module_tenant_type', 'MOBILE_CATERING',\n    'operating_model', 'events',\n    'experience_family', v_family,\n    'factory_experience_family', 'mobile-catering-operations',\n    'blueprint_key', 'mobile-catering-standard',\n    'workspace_type', 'mobile_catering',\n    'routing_family', 'MOBILE_CATERING_OPS'\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"prepare_modes_tenant_workspace","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.prepare_modes_tenant_workspace(p_tenant_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_settings jsonb;\n  v_modes jsonb;\n  v_cards jsonb;\n  v_namespaces jsonb;\n  v_default_count integer := 0;\n  v_now timestamptz := now();\n  v_tenant_type text;\n  v_normalized_type text;\n  v_is_generic_seed boolean := false;\nbegin\n  select coalesce(settings, '{}'::jsonb), tenant_type\n    into v_settings, v_tenant_type\n    from public.tenants\n   where id = p_tenant_id\n   for update;\n\n  if not found then raise exception 'tenant_not_found'; end if;\n  if to_regclass('public.platform_mode_default_media') is null then raise exception 'mode_capability_prerequisite_required'; end if;\n\n  select count(distinct mode_key) into v_default_count\n    from public.platform_mode_default_media\n   where active = true\n     and mode_key = any(array['operations','planning','growth','financials','back-office','field','rentals','events','activations','vendors']);\n  if v_default_count <> 10 then raise exception 'mode_capability_prerequisite_required'; end if;\n\n  v_modes := coalesce(v_settings -> 'modes', '{}'::jsonb);\n  v_normalized_type := public.normalize_declared_business_type(coalesce(\n    v_settings #>> '{business_operating_blueprint,businessTypeKey}',\n    v_settings ->> 'declared_business_type',\n    v_settings ->> 'business_type',\n    v_tenant_type\n  ));\n\n  if jsonb_typeof(v_modes -> 'cards') = 'array' and jsonb_array_length(v_modes -> 'cards') = 4 then\n    select count(*) = 4 into v_is_generic_seed\n      from jsonb_array_elements(v_modes -> 'cards') with ordinality as c(card, ord)\n     where (ord = 1 and coalesce(card->>'key','') = 'today' and coalesce(card->>'title','') = 'Today')\n        or (ord = 2 and coalesce(card->>'key','') = 'operations' and coalesce(card->>'title','') = 'Operations')\n        or (ord = 3 and coalesce(card->>'key','') = 'opportunities' and coalesce(card->>'title','') = 'Opportunities')\n        or (ord = 4 and coalesce(card->>'key','') = 'performance' and coalesce(card->>'title','') = 'Performance');\n  end if;\n\n  if v_normalized_type = 'MOBILE_CATERING' and (\n       jsonb_typeof(v_modes -> 'cards') <> 'array'\n       or jsonb_array_length(coalesce(v_modes -> 'cards', '[]'::jsonb)) = 0\n       or v_is_generic_seed\n     ) then\n    v_cards := jsonb_build_array(\n      jsonb_build_object('key','plan','title','Plan & Book','subtitle','Find catering leads, food-truck events, festivals, and turn them into booked work.','storage_slug','plan','default_image_key','planning','color','#18b8ff','primary_applications',jsonb_build_array('opportunity-radar','booking','calendar','proposals','contacts','communications')),\n      jsonb_build_object('key','prep','title','Kitchen Prep','subtitle','Turn booked work into prep lists, production tasks, documents, and a ready kitchen.','storage_slug','kitchen-prep','default_image_key','planning','color','#13ed86','primary_applications',jsonb_build_array('jobs','tasks','documents','calendar','contacts','communications')),\n      jsonb_build_object('key','events','title','Catering & Events','subtitle','Run private catering, food-truck festivals, pop-ups, and booked mobile events.','storage_slug','catering-events','default_image_key','events','color','#ff7b22','primary_applications',jsonb_build_array('booking','calendar','jobs','tasks','documents','communications')),\n      jsonb_build_object('key','office','title','Back Office','subtitle','Build proposals, create flyers, send invoices, collect payments, follow up, and watch the numbers.','storage_slug','back-office','default_image_key','back-office','color','#ff3f97','primary_applications',jsonb_build_array('creative-studio','invoices','payments','proposals','analytics','documents','communications'))\n    );\n  elsif jsonb_typeof(v_modes -> 'cards') = 'array' and jsonb_array_length(v_modes -> 'cards') > 0 then\n    v_cards := v_modes -> 'cards';\n  else\n    v_cards := jsonb_build_array(\n      jsonb_build_object('key','today','title','Today','subtitle','Plan the day and keep priorities visible.','storage_slug','today','default_image_key','planning','color','#38bdf8'),\n      jsonb_build_object('key','operations','title','Operations','subtitle','Run the work that keeps the business moving.','storage_slug','operations','default_image_key','operations','color','#34d399'),\n      jsonb_build_object('key','opportunities','title','Opportunities','subtitle','Work leads, follow-up, and growth.','storage_slug','opportunities','default_image_key','growth','color','#f59e0b'),\n      jsonb_build_object('key','performance','title','Performance','subtitle','See money, results, and business health.','storage_slug','performance','default_image_key','financials','color','#a78bfa')\n    );\n  end if;\n\n  select coalesce(jsonb_agg(namespace order by namespace), '[]'::jsonb) into v_namespaces\n    from (\n      select distinct 'media/modes/' || trim(both '-' from regexp_replace(lower(coalesce(nullif(card ->> 'storage_slug',''), nullif(card ->> 'key',''), nullif(card ->> 'title',''))), '[^a-z0-9]+','-','g')) as namespace\n      from jsonb_array_elements(v_cards) as card\n    ) prepared\n   where namespace <> 'media/modes/';\n\n  v_modes := v_modes || jsonb_build_object('version',4,'capability_contract','MODES_TENANT_V1','default_media_contract','MODE_DEFAULT_MEDIA_V2','activation_state','prepare','storage_namespaces',v_namespaces,'cards',v_cards,'reconciled_at',v_now);\n\n  update public.tenants set settings = jsonb_set(v_settings, '{modes}', v_modes, true), updated_at = v_now where id = p_tenant_id;\n\n  return jsonb_build_object('ok',true,'tenantId',p_tenant_id,'activation_state','prepare','card_count',jsonb_array_length(v_cards),'storage_namespaces',v_namespaces,'prepared_at',v_now,'mobile_catering_preserved',v_normalized_type='MOBILE_CATERING');\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"prevent_accepted_invitation_mutation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.prevent_accepted_invitation_mutation()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'pg_catalog', 'public'\nAS $function$\nbegin\n  if old.status = 'accepted' and (\n    new.status is distinct from old.status\n    or new.invitation_token is distinct from old.invitation_token\n    or new.email is distinct from old.email\n    or new.phone is distinct from old.phone\n    or new.tenant_id is distinct from old.tenant_id\n    or new.role is distinct from old.role\n  ) then\n    raise exception 'Accepted invitations are immutable';\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"prevent_business_activity_mutation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.prevent_business_activity_mutation()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin raise exception 'business_activity_ledger_is_append_only'; end;\n$function$\n","identity_arguments":""},{"name":"prevent_demo_activity_log_mutation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.prevent_demo_activity_log_mutation()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nbegin\n  raise exception 'demo_activity_log is append-only';\nend;\n$function$\n","identity_arguments":""},{"name":"prevent_dnc_audit_modification","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.prevent_dnc_audit_modification()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF auth.role() = 'service_role' THEN\n    RETURN NEW;\n  END IF;\n  RAISE EXCEPTION 'DNC audit entries are immutable for compliance. Modifications are not permitted.';\nEND;\n$function$\n","identity_arguments":""},{"name":"prevent_quarantine_modification","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.prevent_quarantine_modification()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF auth.role() = 'service_role' THEN RETURN NEW; END IF;\n  RAISE EXCEPTION 'DNC quarantine entries are immutable.';\nEND;\n$function$\n","identity_arguments":""},{"name":"process_task_deadline_alerts","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.process_task_deadline_alerts()\n RETURNS integer\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_count integer := 0;\nbegin\n  -- A concurrent cron retry must not fan out duplicate alerts.\n  if not pg_try_advisory_xact_lock(62061, 101) then\n    return 0;\n  end if;\n  with due_tasks as (\n    select t.id, t.tenant_id, t.due_date,\n      coalesce(t.assigned_to,t.user_id) as responsible_user,\n      (t.due_date < now() - interval '24 hours') as escalated\n    from public.tasks t\n    where t.due_date is not null\n      and t.due_date < now()\n      and t.due_date > now() - interval '30 days'\n      and lower(coalesce(t.status,'pending')) not in ('completed','dismissed','canceled','cancelled')\n    order by t.due_date desc\n    limit 200\n  ),\n  recipients as (\n    select d.id,d.tenant_id,d.due_date,d.responsible_user as user_id,\n      'due'::text as notice_kind\n    from due_tasks d\n    join public.user_tenant_memberships m\n      on m.tenant_id::text=d.tenant_id\n       and m.user_id=d.responsible_user and m.status='active'\n    join public.profiles p\n      on p.id=m.user_id and coalesce(p.active,true)=true\n    union all\n    select d.id,d.tenant_id,d.due_date,m.user_id,\n      'escalated'::text\n    from due_tasks d\n    join public.user_tenant_memberships m\n      on m.tenant_id::text=d.tenant_id\n        and m.status='active' and m.is_owner=true\n        and m.user_id is distinct from d.responsible_user\n    join public.profiles p\n      on p.id=m.user_id and coalesce(p.active,true)=true\n    where d.escalated\n  ),\n  candidates as (\n    select r.*,\n      'task-deadline:' || r.id::text || ':' ||\n      to_char(r.due_date at time zone 'UTC','YYYYMMDDHH24MISS') ||\n      ':' || r.notice_kind as dedupe_key\n    from recipients r\n  ),\n  saved as (\n    insert into public.notifications (\n      user_id,tenant_id,type,title,message,link,metadata\n    )\n    select\n      c.user_id,c.tenant_id,\n      case when c.notice_kind='escalated' then 'task.escalated' else 'task.overdue' end,\n      case when c.notice_kind='escalated' then 'Team task needs follow-up'\n        else 'A task is overdue' end,\n      'Open Work Center to review the overdue task and its owner.',\n      null,\n      jsonb_build_object('source_app','crm','severity','warning',\n        'entity_type','task','entity_id',c.id,'task_id',c.id,\n        'dedupe_key',c.dedupe_key,'notice_kind',c.notice_kind)\n    from candidates c\n    where not exists (\n      select 1 from public.notifications n\n      where n.user_id=c.user_id and n.tenant_id=c.tenant_id\n        and n.metadata->>'dedupe_key'=c.dedupe_key\n    )\n    returning id\n  )\n  select count(*) into v_count from saved;\n  return v_count;\nend;\n$function$\n","identity_arguments":""},{"name":"progress_create_record","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.progress_create_record(_tenant_id uuid, _payload jsonb DEFAULT '{}'::jsonb)\n RETURNS business_opportunities\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\ndeclare\n  v_settings jsonb;\n  v_templates jsonb;\n  v_template jsonb;\n  v_stages jsonb;\n  v_template_id text;\n  v_requested_stage text;\n  v_stage text;\n  v_waiting_on text;\n  v_title text;\n  v_contact_id uuid;\n  v_id uuid := gen_random_uuid();\n  v_row public.business_opportunities%rowtype;\nbegin\n  if _tenant_id is null then raise exception 'progress_tenant_required'; end if;\n  if _payload is null or jsonb_typeof(_payload) <> 'object' then raise exception 'progress_payload_object_required'; end if;\n\n  perform public.business_engine_assert_access(_tenant_id);\n  select coalesce(settings, '{}'::jsonb) into v_settings from public.tenants where id = _tenant_id;\n  if not found then raise exception 'progress_tenant_not_found'; end if;\n  if coalesce(v_settings->>'workspace_type', '') <> 'progress_platform' then\n    raise exception 'progress_platform_not_enabled';\n  end if;\n\n  v_title := nullif(btrim(coalesce(_payload->>'title', '')), '');\n  if v_title is null then raise exception 'progress_title_required'; end if;\n\n  v_templates := case\n    when jsonb_typeof(v_settings->'progress_vertical_templates') = 'array' then v_settings->'progress_vertical_templates'\n    else '[]'::jsonb\n  end;\n  v_template_id := nullif(btrim(coalesce(_payload->>'template_id', '')), '');\n\n  if jsonb_array_length(v_templates) > 0 then\n    v_template_id := coalesce(v_template_id, nullif(v_settings->>'progress_default_template', ''), v_templates->0->>'id');\n    select item.value into v_template\n      from jsonb_array_elements(v_templates) as item(value)\n     where item.value->>'id' = v_template_id\n     limit 1;\n    if v_template is null then raise exception 'progress_template_invalid:%', coalesce(v_template_id, '<missing>'); end if;\n  else\n    v_stages := case\n      when jsonb_typeof(v_settings#>'{business_operating_blueprint,workflowStages}') = 'array'\n        then v_settings#>'{business_operating_blueprint,workflowStages}'\n      else jsonb_build_array('Received','In Review','In Progress','Waiting','Complete')\n    end;\n    v_template_id := coalesce(v_template_id, 'custom');\n    v_template := jsonb_build_object('id', v_template_id, 'label', 'Custom Progress', 'stages', v_stages);\n  end if;\n\n  v_stages := case when jsonb_typeof(v_template->'stages') = 'array' then v_template->'stages' else '[]'::jsonb end;\n  v_requested_stage := coalesce(nullif(btrim(coalesce(_payload->>'progress_stage', '')), ''), v_stages->>0);\n  select stage into v_stage\n    from jsonb_array_elements_text(v_stages) as stage\n   where lower(stage) = lower(v_requested_stage)\n   limit 1;\n  if v_stage is null then raise exception 'progress_stage_invalid:%', coalesce(v_requested_stage, '<missing>'); end if;\n\n  v_waiting_on := lower(coalesce(nullif(btrim(coalesce(_payload->>'waiting_on', '')), ''), 'none'));\n  if v_waiting_on not in ('none','customer','business') then raise exception 'progress_waiting_on_invalid:%', v_waiting_on; end if;\n\n  if _payload ? 'contact_id' and nullif(_payload->>'contact_id', '') is not null then\n    v_contact_id := (_payload->>'contact_id')::uuid;\n    if not exists (\n      select 1 from public.unified_contacts c\n       where c.id = v_contact_id and c.tenant_org_id = _tenant_id::text and c.deleted_at is null\n    ) then raise exception 'progress_contact_tenant_mismatch'; end if;\n  end if;\n\n  insert into public.business_opportunities (\n    id, tenant_id, contact_id, source_module, source_entity_type, dedupe_key,\n    title, summary, category, lifecycle_state, proposal_state, payment_state,\n    fulfillment_state, created_by, metadata\n  ) values (\n    v_id,\n    _tenant_id,\n    v_contact_id,\n    'progress-platform',\n    'progress_record',\n    'progress:' || v_id::text,\n    v_title,\n    nullif(btrim(coalesce(_payload->>'internal_summary', '')), ''),\n    coalesce(v_template->>'label', 'Progress'),\n    'captured',\n    'not_started',\n    'not_required',\n    'not_scheduled',\n    auth.uid(),\n    jsonb_strip_nulls(jsonb_build_object(\n      'template_id', v_template_id,\n      'template_label', v_template->>'label',\n      'progress_stage', v_stage,\n      'customer_name', nullif(btrim(coalesce(_payload->>'customer_name', '')), ''),\n      'next_step', nullif(btrim(coalesce(_payload->>'next_step', '')), ''),\n      'waiting_on', v_waiting_on,\n      'next_update_due_at', nullif(_payload->>'next_update_due_at', ''),\n      'target_date', nullif(_payload->>'target_date', ''),\n      'customer_visible_summary', nullif(btrim(coalesce(_payload->>'customer_visible_summary', '')), ''),\n      'last_progress_update_at', now()\n    ))\n  ) returning * into v_row;\n\n  insert into public.business_opportunity_events (\n    tenant_id, opportunity_id, dimension, from_state, to_state, reason_code, actor_user_id, metadata\n  ) values (\n    _tenant_id, v_row.id, 'progress', null, v_stage, 'progress_record_created', auth.uid(),\n    jsonb_build_object('template_id', v_template_id, 'source', 'progress-platform')\n  );\n\n  return v_row;\nend;\n$function$\n","identity_arguments":"_tenant_id uuid, _payload jsonb"},{"name":"progress_update_record","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.progress_update_record(_opportunity_id uuid, _patch jsonb)\n RETURNS business_opportunities\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth'\nAS $function$\ndeclare\n  v_row public.business_opportunities%rowtype;\n  v_final public.business_opportunities%rowtype;\n  v_settings jsonb;\n  v_templates jsonb;\n  v_template jsonb;\n  v_stages jsonb;\n  v_template_id text;\n  v_requested_stage text;\n  v_stage text;\n  v_old_stage text;\n  v_waiting_on text;\n  v_contact_id uuid;\n  v_metadata_patch jsonb := '{}'::jsonb;\n  v_allowed_keys constant text[] := array[\n    'contact_id','title','internal_summary','template_id','progress_stage','customer_name',\n    'next_step','waiting_on','next_update_due_at','target_date','customer_visible_summary'\n  ];\n  v_unknown_keys text[];\nbegin\n  if _patch is null or jsonb_typeof(_patch) <> 'object' then raise exception 'progress_patch_object_required'; end if;\n\n  select * into v_row from public.business_opportunities where id = _opportunity_id for update;\n  if not found then raise exception 'progress_record_not_found'; end if;\n  perform public.business_engine_assert_access(v_row.tenant_id);\n  if coalesce(v_row.source_entity_type, '') <> 'progress_record' then raise exception 'progress_record_type_mismatch'; end if;\n\n  select coalesce(settings, '{}'::jsonb) into v_settings from public.tenants where id = v_row.tenant_id;\n  if coalesce(v_settings->>'workspace_type', '') <> 'progress_platform' then raise exception 'progress_platform_not_enabled'; end if;\n\n  select array_agg(key) into v_unknown_keys\n    from jsonb_object_keys(_patch) as key\n   where not (key = any(v_allowed_keys));\n  if coalesce(cardinality(v_unknown_keys), 0) > 0 then\n    raise exception 'progress_patch_unknown_keys:%', array_to_string(v_unknown_keys, ',');\n  end if;\n  if _patch ? 'title' and nullif(btrim(coalesce(_patch->>'title', '')), '') is null then raise exception 'progress_title_required'; end if;\n\n  v_templates := case\n    when jsonb_typeof(v_settings->'progress_vertical_templates') = 'array' then v_settings->'progress_vertical_templates'\n    else '[]'::jsonb\n  end;\n  v_template_id := coalesce(nullif(btrim(coalesce(_patch->>'template_id', '')), ''), v_row.metadata->>'template_id', nullif(v_settings->>'progress_default_template', ''));\n\n  if jsonb_array_length(v_templates) > 0 then\n    v_template_id := coalesce(v_template_id, v_templates->0->>'id');\n    select item.value into v_template\n      from jsonb_array_elements(v_templates) as item(value)\n     where item.value->>'id' = v_template_id\n     limit 1;\n    if v_template is null then raise exception 'progress_template_invalid:%', coalesce(v_template_id, '<missing>'); end if;\n  else\n    v_stages := case\n      when jsonb_typeof(v_settings#>'{business_operating_blueprint,workflowStages}') = 'array'\n        then v_settings#>'{business_operating_blueprint,workflowStages}'\n      else jsonb_build_array('Received','In Review','In Progress','Waiting','Complete')\n    end;\n    v_template_id := coalesce(v_template_id, 'custom');\n    v_template := jsonb_build_object('id', v_template_id, 'label', 'Custom Progress', 'stages', v_stages);\n  end if;\n\n  v_stages := case when jsonb_typeof(v_template->'stages') = 'array' then v_template->'stages' else '[]'::jsonb end;\n  v_old_stage := nullif(v_row.metadata->>'progress_stage', '');\n  v_requested_stage := coalesce(nullif(btrim(coalesce(_patch->>'progress_stage', '')), ''), v_old_stage, v_stages->>0);\n  select stage into v_stage\n    from jsonb_array_elements_text(v_stages) as stage\n   where lower(stage) = lower(v_requested_stage)\n   limit 1;\n  if v_stage is null then raise exception 'progress_stage_invalid:%', coalesce(v_requested_stage, '<missing>'); end if;\n\n  v_waiting_on := lower(coalesce(\n    case when _patch ? 'waiting_on' then nullif(btrim(coalesce(_patch->>'waiting_on', '')), '') else null end,\n    v_row.metadata->>'waiting_on',\n    'none'\n  ));\n  if v_waiting_on not in ('none','customer','business') then raise exception 'progress_waiting_on_invalid:%', v_waiting_on; end if;\n\n  if _patch ? 'contact_id' then\n    if nullif(_patch->>'contact_id', '') is null then\n      v_contact_id := null;\n    else\n      v_contact_id := (_patch->>'contact_id')::uuid;\n      if not exists (\n        select 1 from public.unified_contacts c\n         where c.id = v_contact_id and c.tenant_org_id = v_row.tenant_id::text and c.deleted_at is null\n      ) then raise exception 'progress_contact_tenant_mismatch'; end if;\n    end if;\n  else\n    v_contact_id := v_row.contact_id;\n  end if;\n\n  if _patch ? 'template_id' then v_metadata_patch := v_metadata_patch || jsonb_build_object('template_id', v_template_id, 'template_label', v_template->>'label'); end if;\n  if _patch ? 'progress_stage' or v_old_stage is null then v_metadata_patch := v_metadata_patch || jsonb_build_object('progress_stage', v_stage); end if;\n  if _patch ? 'customer_name' then v_metadata_patch := v_metadata_patch || jsonb_build_object('customer_name', nullif(btrim(coalesce(_patch->>'customer_name', '')), '')); end if;\n  if _patch ? 'next_step' then v_metadata_patch := v_metadata_patch || jsonb_build_object('next_step', nullif(btrim(coalesce(_patch->>'next_step', '')), '')); end if;\n  if _patch ? 'waiting_on' then v_metadata_patch := v_metadata_patch || jsonb_build_object('waiting_on', v_waiting_on); end if;\n  if _patch ? 'next_update_due_at' then v_metadata_patch := v_metadata_patch || jsonb_build_object('next_update_due_at', nullif(_patch->>'next_update_due_at', '')); end if;\n  if _patch ? 'target_date' then v_metadata_patch := v_metadata_patch || jsonb_build_object('target_date', nullif(_patch->>'target_date', '')); end if;\n  if _patch ? 'customer_visible_summary' then v_metadata_patch := v_metadata_patch || jsonb_build_object('customer_visible_summary', nullif(btrim(coalesce(_patch->>'customer_visible_summary', '')), '')); end if;\n  v_metadata_patch := v_metadata_patch || jsonb_build_object('last_progress_update_at', now());\n\n  update public.business_opportunities\n     set contact_id = v_contact_id,\n         title = case when _patch ? 'title' then btrim(_patch->>'title') else title end,\n         summary = case when _patch ? 'internal_summary' then nullif(btrim(coalesce(_patch->>'internal_summary', '')), '') else summary end,\n         category = case when _patch ? 'template_id' then coalesce(v_template->>'label', category) else category end,\n         metadata = metadata || v_metadata_patch,\n         updated_at = now()\n   where id = v_row.id\n   returning * into v_final;\n\n  insert into public.business_opportunity_events (\n    tenant_id, opportunity_id, dimension, from_state, to_state, reason_code, actor_user_id, metadata\n  ) values (\n    v_row.tenant_id,\n    v_row.id,\n    'progress',\n    v_old_stage,\n    v_stage,\n    case when v_old_stage is distinct from v_stage then 'progress_stage_changed' else 'progress_record_updated' end,\n    auth.uid(),\n    _patch\n  );\n\n  return v_final;\nend;\n$function$\n","identity_arguments":"_opportunity_id uuid, _patch jsonb"},{"name":"project_claim_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_claim_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_tid uuid := public.business_activity_safe_uuid(new.tenant_org_id);\n  v_contact uuid := coalesce(new.canonical_contact_id, public.business_activity_safe_uuid(new.contact_id));\n  v_event text;\n  v_prev text;\n  v_state text := coalesce(new.claim_stage, new.claim_status, new.claim_payment_status::text, new.payment_pipeline_status::text);\n  v_dedupe text;\nbegin\n  if v_tid is null then return new; end if;\n  if tg_op = 'INSERT' then\n    v_event := 'claim_created'; v_prev := null; v_dedupe := 'claim-created:' || new.id::text;\n  else\n    if new.claim_status is not distinct from old.claim_status\n       and new.claim_stage is not distinct from old.claim_stage\n       and new.claim_payment_status is not distinct from old.claim_payment_status\n       and new.payment_pipeline_status is not distinct from old.payment_pipeline_status\n       and new.settlement_amount is not distinct from old.settlement_amount\n       and new.fee_status is not distinct from old.fee_status\n       and new.check_issued_at is not distinct from old.check_issued_at\n       and new.check_received_by_homeowner_at is not distinct from old.check_received_by_homeowner_at then\n      return new;\n    end if;\n    v_prev := coalesce(old.claim_stage, old.claim_status, old.claim_payment_status::text, old.payment_pipeline_status::text);\n    if new.settlement_amount is not null and old.settlement_amount is null then\n      v_event := 'claim_settled'; v_dedupe := 'claim-settled:' || new.id::text;\n    elsif new.claim_payment_status is distinct from old.claim_payment_status or new.payment_pipeline_status is distinct from old.payment_pipeline_status then\n      v_event := 'claim_payment_updated'; v_dedupe := null;\n    else\n      v_event := 'claim_updated'; v_dedupe := null;\n    end if;\n  end if;\n\n  perform public.business_activity_project(\n    v_tid,\n    v_event,\n    initcap(replace(v_event, '_', ' ')),\n    jsonb_build_object(\n      'contact_id', v_contact,\n      'actor_user_id', coalesce(auth.uid(), new.claim_payment_status_updated_by, new.check_issued_by),\n      'description', coalesce(new.claim_number, new.carrier, 'Claim'),\n      'metadata', jsonb_build_object('carrier', new.carrier, 'claim_type', new.claim_type, 'fee_status', new.fee_status, 'claim_payment_status', new.claim_payment_status, 'payment_pipeline_status', new.payment_pipeline_status),\n      'related_entity_type', 'claim',\n      'related_entity_id', new.id,\n      'event_domain', 'claims',\n      'correlation_key', case when v_contact is not null then 'contact:' || v_contact::text else 'claim:' || new.id::text end,\n      'previous_state', v_prev,\n      'new_state', v_state,\n      'monetary_value', new.settlement_amount,\n      'outcome', case when v_event='claim_settled' then 'settled' else null end,\n      'dedupe_key', v_dedupe,\n      'source_record_type', 'contact_claims',\n      'source_record_id', new.id,\n      'occurred_at', coalesce(new.claim_payment_status_updated_at, new.check_received_by_homeowner_at, new.check_issued_at, new.updated_at, new.created_at, now())\n    )\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_communication_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_communication_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare tid uuid:=public.business_activity_safe_uuid(new.tenant_org_id); channel text;\nbegin\n  if tid is null then return new; end if;\n  channel:=case when lower(coalesce(new.event_type,'')) like '%email%' then 'Email' when lower(coalesce(new.event_type,'')) like '%sms%' or lower(coalesce(new.event_type,'')) like '%text%' then 'SMS' else 'Phone' end;\n  perform public.business_activity_project(tid,'communication_'||coalesce(new.event_type,'activity'),initcap(coalesce(new.direction,'Business'))||' '||replace(coalesce(new.event_type,'communication'),'_',' '),\n    jsonb_build_object('contact_id',coalesce(new.contact_id,new.lead_id),'actor_user_id',new.rep_id,'description',coalesce(new.outcome,new.result,new.status,new.disposition),'metadata',jsonb_build_object('provider',new.provider,'status',new.status,'duration_seconds',new.duration_seconds),\n      'related_entity_type','communication','related_entity_id',new.id,'event_domain','communication','touch_channel',channel,'source_detail',new.provider,'correlation_key',case when coalesce(new.contact_id,new.lead_id) is not null then 'contact:'||coalesce(new.contact_id,new.lead_id)::text else 'communication:'||new.id::text end,\n      'outcome',coalesce(new.outcome,new.result,new.disposition),'dedupe_key','communication-event:'||new.id::text,'source_record_type','communication_events','source_record_id',new.id,'occurred_at',new.created_at));\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_contact_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_contact_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare source_raw text; changed text[]:=array[]::text[]; event_name text;\nbegin\n  if public.business_activity_safe_uuid(new.tenant_org_id) is null then return new; end if;\n  source_raw:=coalesce(nullif(new.raw_data #>> '{acquisition,source}',''),nullif(new.source,''),nullif(new.lead_origin,''),nullif(new.referral_source,''),nullif(new.import_source,''));\n  if tg_op='INSERT' then event_name:='contact_created'; else\n    if new.source is distinct from old.source or new.lead_origin is distinct from old.lead_origin or new.referral_source is distinct from old.referral_source then changed:=array_append(changed,'source'); end if;\n    if new.lead_stage is distinct from old.lead_stage or new.status is distinct from old.status or new.contact_status is distinct from old.contact_status or new.service_status is distinct from old.service_status then changed:=array_append(changed,'stage'); end if;\n    if new.assigned_to is distinct from old.assigned_to or new.assigned_user is distinct from old.assigned_user or new.assigned_rep is distinct from old.assigned_rep then changed:=array_append(changed,'assignment'); end if;\n    if new.graduated_at is distinct from old.graduated_at or new.lost_at is distinct from old.lost_at then changed:=array_append(changed,'outcome'); end if;\n    if cardinality(changed)=0 then return new; end if; event_name:='contact_updated';\n  end if;\n  perform public.business_activity_project(new.tenant_org_id::uuid,event_name,case when tg_op='INSERT' then 'Contact entered business' else 'Contact activity updated' end,\n    jsonb_build_object('contact_id',new.id,'actor_user_id',coalesce(auth.uid(),new.created_by_user_id),'description',case when tg_op='INSERT' then coalesce(new.name,trim(concat_ws(' ',new.first_name,new.last_name)),'Contact') else array_to_string(changed,', ') end,\n      'metadata',jsonb_build_object('changed_fields',changed,'raw_source',source_raw),'related_entity_type','contact','related_entity_id',new.id,'event_domain',case when tg_op='INSERT' then 'acquisition' else 'relationship' end,\n      'source_channel',source_raw,'source_detail',coalesce(new.raw_data #>> '{acquisition,medium}',new.raw_data->>'utm_medium'),'source_campaign',coalesce(new.raw_data #>> '{acquisition,campaign}',new.raw_data->>'utm_campaign'),\n      'source_referrer',coalesce(new.raw_data #>> '{acquisition,referrer}',new.raw_data->>'referrer'),'correlation_key','contact:'||new.id::text,'previous_state',case when tg_op='UPDATE' then coalesce(old.lead_stage,old.status,old.contact_status) else null end,\n      'new_state',coalesce(new.lead_stage,new.status,new.contact_status),'outcome',case when new.lost_at is not null then 'lost' when new.graduated_at is not null then 'converted' else null end,\n      'dedupe_key',case when tg_op='INSERT' then 'contact-created:'||new.id::text else null end,'source_record_type','unified_contacts','source_record_id',new.id,'occurred_at',coalesce(new.created_at,now())));\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_document_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_document_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare tid uuid:=public.business_activity_safe_uuid(new.tenant_org_id);\nbegin\n  if tid is null then return new; end if;\n  perform public.business_activity_project(tid,'document_'||coalesce(new.activity_type,'activity'),initcap(replace(coalesce(new.activity_type,'Document activity'),'_',' ')),\n    jsonb_build_object('contact_id',public.business_activity_safe_uuid(new.activity_data->>'contact_id'),'actor_user_id',new.user_id,'description',new.document_type,'metadata',coalesce(new.activity_data,'{}'::jsonb),\n      'related_entity_type','document','event_domain','document','correlation_key',coalesce('document:'||nullif(new.document_id,''),'document-activity:'||new.id::text),'dedupe_key','document-activity:'||new.id::text,\n      'source_record_type','document_activity','source_record_id',new.id,'occurred_at',new.created_at));\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_event_booking_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_event_booking_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_tid uuid := public.business_activity_safe_uuid(new.tenant_org_id);\n  v_event text;\n  v_prev text;\n  v_dedupe text;\nbegin\n  if v_tid is null then return new; end if;\n  if tg_op = 'INSERT' then\n    v_event := 'booking_created'; v_prev := null; v_dedupe := 'booking-created:' || new.id::text;\n  else\n    if new.status is not distinct from old.status\n       and new.stage is not distinct from old.stage\n       and new.event_date is not distinct from old.event_date\n       and new.start_time is not distinct from old.start_time\n       and new.quote_amount is not distinct from old.quote_amount\n       and new.deposit_amount is not distinct from old.deposit_amount\n       and new.balance_due is not distinct from old.balance_due\n       and new.confirmed_at is not distinct from old.confirmed_at\n       and new.completed_at is not distinct from old.completed_at then\n      return new;\n    end if;\n    v_prev := coalesce(old.status, old.stage);\n    if new.completed_at is not null and old.completed_at is null then\n      v_event := 'booking_completed'; v_dedupe := 'booking-completed:' || new.id::text;\n    elsif lower(coalesce(new.status,'')) = 'cancelled' and lower(coalesce(old.status,'')) <> 'cancelled' then\n      v_event := 'booking_cancelled'; v_dedupe := 'booking-cancelled:' || new.id::text;\n    elsif new.confirmed_at is not null and old.confirmed_at is null then\n      v_event := 'booking_confirmed'; v_dedupe := 'booking-confirmed:' || new.id::text;\n    else\n      v_event := 'booking_updated'; v_dedupe := null;\n    end if;\n  end if;\n\n  perform public.business_activity_project(\n    v_tid,\n    v_event,\n    initcap(replace(v_event, '_', ' ')),\n    jsonb_build_object(\n      'contact_id', new.contact_id,\n      'actor_user_id', coalesce(auth.uid(), new.created_by),\n      'description', coalesce(new.event_name, new.venue_name, 'Event booking'),\n      'metadata', jsonb_build_object('event_type', new.event_type, 'venue_name', new.venue_name, 'event_date', new.event_date, 'start_time', new.start_time, 'guest_count', new.guest_count, 'service_package', new.service_package),\n      'related_entity_type', 'event_booking',\n      'related_entity_id', new.id,\n      'event_domain', 'booking',\n      'source_channel', new.source,\n      'source_detail', new.source_ref,\n      'correlation_key', case when new.contact_id is not null then 'contact:' || new.contact_id::text else 'booking:' || new.id::text end,\n      'previous_state', v_prev,\n      'new_state', coalesce(new.status, new.stage),\n      'monetary_value', new.quote_amount,\n      'outcome', case when v_event='booking_completed' then 'completed' when v_event='booking_cancelled' then 'cancelled' when v_event='booking_confirmed' then 'confirmed' else null end,\n      'dedupe_key', v_dedupe,\n      'source_record_type', 'event_bookings',\n      'source_record_id', new.id,\n      'occurred_at', coalesce(new.completed_at, new.confirmed_at, new.updated_at, new.created_at, now())\n    )\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_invoice_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_invoice_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare tid uuid:=public.business_activity_safe_uuid(new.tenant_org_id); cid uuid:=coalesce(new.canonical_contact_id,public.business_activity_safe_uuid(new.contact_id)); event_name text;\nbegin\n  if tid is null then return new; end if;\n  if tg_op='UPDATE' and new.status is not distinct from old.status and new.amount is not distinct from old.amount and new.paid_at is not distinct from old.paid_at then return new; end if;\n  event_name:=case when tg_op='INSERT' then 'invoice_created' when new.paid_at is not null and old.paid_at is null then 'invoice_paid' else 'invoice_updated' end;\n  perform public.business_activity_project(tid,event_name,case when event_name='invoice_paid' then 'Invoice paid' when event_name='invoice_created' then 'Invoice created' else 'Invoice updated' end,\n    jsonb_build_object('contact_id',cid,'actor_user_id',public.business_activity_safe_uuid(new.created_by),'description',coalesce(new.customer_name,new.invoice_id,'Invoice'),'metadata',jsonb_build_object('invoice_number',new.invoice_id),\n      'related_entity_type','invoice','related_entity_id',new.id,'event_domain','revenue','correlation_key',coalesce('contact:'||cid::text,'invoice:'||new.id::text),'previous_state',case when tg_op='UPDATE' then old.status else null end,'new_state',new.status,\n      'monetary_value',case when event_name='invoice_paid' then new.amount else null end,'outcome',case when event_name='invoice_paid' then 'paid' else null end,'dedupe_key',case when tg_op='INSERT' then 'invoice-created:'||new.id::text else null end,\n      'source_record_type','invoices','source_record_id',new.id,'occurred_at',coalesce(new.created_at,now())));\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_job_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_job_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare changed text[]:=array[]::text[]; event_name text;\nbegin\n  if tg_op='INSERT' then event_name:='job_created'; else\n    if new.status is distinct from old.status then changed:=array_append(changed,'status'); end if;\n    if new.assigned_crew_id is distinct from old.assigned_crew_id or new.assigned_pm_id is distinct from old.assigned_pm_id then changed:=array_append(changed,'assignment'); end if;\n    if new.scheduled_date is distinct from old.scheduled_date then changed:=array_append(changed,'schedule'); end if;\n    if new.completed_at is distinct from old.completed_at or new.paid_at is distinct from old.paid_at then changed:=array_append(changed,'outcome'); end if;\n    if new.financing_mode is distinct from old.financing_mode or new.financed_amount is distinct from old.financed_amount then changed:=array_append(changed,'finance'); end if;\n    if cardinality(changed)=0 then return new; end if; event_name:='job_updated';\n  end if;\n  perform public.business_activity_project(new.tenant_id,event_name,case when tg_op='INSERT' then 'Job created' else 'Job activity updated' end,\n    jsonb_build_object('contact_id',new.contact_id,'actor_user_id',coalesce(auth.uid(),new.claim_payment_updated_by,new.verified_by,new.manager_approved_by,new.created_by),'description',coalesce(new.customer_name,new.job_number,'Job')||case when cardinality(changed)>0 then ' · '||array_to_string(changed,', ') else '' end,\n      'metadata',jsonb_build_object('job_number',new.job_number,'job_type',new.job_type),'related_entity_type','job','related_entity_id',new.id,'event_domain','fulfillment','correlation_key',coalesce('contact:'||new.contact_id::text,'job:'||new.id::text),\n      'previous_state',case when tg_op='UPDATE' then old.status else null end,'new_state',new.status,'outcome',case when new.paid_at is not null then 'paid' when new.completed_at is not null then 'completed' else null end,\n      'dedupe_key',case when tg_op='INSERT' then 'job-created:'||new.id::text else null end,'source_record_type','jobs','source_record_id',new.id,'occurred_at',coalesce(new.created_at,now())));\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_opportunity_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_opportunity_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare o public.business_opportunities%rowtype;\nbegin\n  select * into o from public.business_opportunities where id=new.opportunity_id; if not found then return new; end if;\n  perform public.business_activity_project(new.tenant_id,'opportunity_'||new.dimension,'Opportunity '||replace(new.dimension,'_',' ')||': '||coalesce(new.from_state,'new')||' → '||coalesce(new.to_state,'updated'),\n    jsonb_build_object('contact_id',o.contact_id,'actor_user_id',new.actor_user_id,'description',o.title,'metadata',coalesce(new.metadata,'{}'::jsonb),'related_entity_type','opportunity','related_entity_id',new.opportunity_id,\n      'event_domain','sales','source_channel',o.source_module,'source_detail',o.source_entity_type,'correlation_key','opportunity:'||new.opportunity_id::text,'previous_state',new.from_state,'new_state',new.to_state,'reason_code',new.reason_code,\n      'outcome',case when new.dimension='lifecycle' and new.to_state in ('won','lost','cancelled') then new.to_state when new.dimension='payment' and new.to_state='paid' then 'paid' else null end,\n      'dedupe_key','opportunity-event:'||new.id::text,'source_record_type','business_opportunity_events','source_record_id',new.id,'occurred_at',new.created_at));\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_pending_agreement_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_pending_agreement_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_event text;\n  v_prev text;\n  v_dedupe text;\nbegin\n  if new.tenant_id is null then return new; end if;\n  if tg_op = 'INSERT' then\n    v_event := 'agreement_created'; v_prev := null; v_dedupe := 'agreement-created:' || new.id::text;\n  else\n    if new.status is not distinct from old.status\n       and new.sent_at is not distinct from old.sent_at\n       and new.viewed_at is not distinct from old.viewed_at\n       and new.signed_at is not distinct from old.signed_at then\n      return new;\n    end if;\n    v_prev := old.status;\n    if new.signed_at is not null and old.signed_at is null then\n      v_event := 'agreement_signed'; v_dedupe := 'agreement-signed:' || new.id::text;\n    elsif lower(coalesce(new.status,'')) = 'declined' and lower(coalesce(old.status,'')) <> 'declined' then\n      v_event := 'agreement_declined'; v_dedupe := 'agreement-declined:' || new.id::text;\n    elsif new.viewed_at is not null and old.viewed_at is null then\n      v_event := 'agreement_viewed'; v_dedupe := null;\n    elsif new.sent_at is not null and old.sent_at is null then\n      v_event := 'agreement_sent'; v_dedupe := null;\n    else\n      v_event := 'agreement_updated'; v_dedupe := null;\n    end if;\n  end if;\n\n  perform public.business_activity_project(\n    new.tenant_id,\n    v_event,\n    initcap(replace(v_event, '_', ' ')),\n    jsonb_build_object(\n      'contact_id', new.contact_id,\n      'actor_user_id', coalesce(auth.uid(), new.sent_by_user_id),\n      'description', coalesce(new.template_type, 'Agreement') || case when new.recipient_name is not null then ' · ' || new.recipient_name else '' end,\n      'metadata', jsonb_build_object('recipient_email', new.recipient_email, 'template_type', new.template_type, 'event_booking_id', new.event_booking_id),\n      'related_entity_type', 'agreement',\n      'related_entity_id', new.id,\n      'event_domain', 'document',\n      'correlation_key', case when new.contact_id is not null then 'contact:' || new.contact_id::text else 'agreement:' || new.id::text end,\n      'previous_state', v_prev,\n      'new_state', new.status,\n      'outcome', case when v_event='agreement_signed' then 'signed' when v_event='agreement_declined' then 'declined' else null end,\n      'dedupe_key', v_dedupe,\n      'source_record_type', 'pending_agreements',\n      'source_record_id', new.id,\n      'occurred_at', coalesce(new.signed_at, new.viewed_at, new.sent_at, new.updated_at, new.created_at, now())\n    )\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_proposal_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_proposal_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_event text;\n  v_prev text;\n  v_dedupe text;\nbegin\n  if new.tenant_id is null then return new; end if;\n  if tg_op = 'INSERT' then\n    v_event := 'proposal_created';\n    v_prev := null;\n    v_dedupe := 'proposal-created:' || new.id::text;\n  else\n    if new.status is not distinct from old.status\n       and new.current_version is not distinct from old.current_version\n       and new.selected_option_key is not distinct from old.selected_option_key\n       and new.total_amount is not distinct from old.total_amount\n       and new.approved_at is not distinct from old.approved_at\n       and new.sent_at is not distinct from old.sent_at\n       and new.accepted_at is not distinct from old.accepted_at\n       and new.declined_at is not distinct from old.declined_at\n       and new.paid_at is not distinct from old.paid_at\n       and new.voided_at is not distinct from old.voided_at then\n      return new;\n    end if;\n    v_prev := old.status;\n    if new.paid_at is not null and old.paid_at is null then\n      v_event := 'proposal_paid'; v_dedupe := 'proposal-paid:' || new.id::text;\n    elsif new.accepted_at is not null and old.accepted_at is null then\n      v_event := 'proposal_accepted'; v_dedupe := 'proposal-accepted:' || new.id::text;\n    elsif new.declined_at is not null and old.declined_at is null then\n      v_event := 'proposal_declined'; v_dedupe := 'proposal-declined:' || new.id::text;\n    elsif new.voided_at is not null and old.voided_at is null then\n      v_event := 'proposal_voided'; v_dedupe := 'proposal-voided:' || new.id::text;\n    elsif new.sent_at is not null and old.sent_at is null then\n      v_event := 'proposal_sent'; v_dedupe := null;\n    elsif new.approved_at is not null and old.approved_at is null then\n      v_event := 'proposal_approved'; v_dedupe := null;\n    else\n      v_event := 'proposal_updated'; v_dedupe := null;\n    end if;\n  end if;\n\n  perform public.business_activity_project(\n    new.tenant_id,\n    v_event,\n    initcap(replace(v_event, '_', ' ')),\n    jsonb_build_object(\n      'contact_id', new.source_contact_id,\n      'actor_user_id', coalesce(auth.uid(), new.created_by),\n      'description', coalesce(new.proposal_number, 'Proposal'),\n      'metadata', jsonb_build_object('current_version', new.current_version, 'offer_key', new.offer_key, 'selected_option_key', new.selected_option_key),\n      'related_entity_type', 'proposal',\n      'related_entity_id', new.id,\n      'event_domain', 'sales',\n      'correlation_key', case when new.source_contact_id is not null then 'contact:' || new.source_contact_id::text else 'proposal:' || new.id::text end,\n      'previous_state', v_prev,\n      'new_state', new.status,\n      'monetary_value', new.total_amount,\n      'currency', coalesce(new.currency, 'USD'),\n      'outcome', case when v_event='proposal_paid' then 'paid' when v_event='proposal_accepted' then 'accepted' when v_event='proposal_declined' then 'declined' when v_event='proposal_voided' then 'voided' else null end,\n      'dedupe_key', v_dedupe,\n      'source_record_type', 'proposals',\n      'source_record_id', new.id,\n      'occurred_at', coalesce(new.paid_at, new.accepted_at, new.declined_at, new.voided_at, new.sent_at, new.approved_at, new.updated_at, new.created_at, now())\n    )\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_roof_estimate_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_roof_estimate_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_tid uuid := public.business_activity_safe_uuid(new.tenant_org_id);\n  v_contact uuid := public.business_activity_safe_uuid(new.contact_id);\n  v_event text;\n  v_prev text;\n  v_state text := coalesce(new.approval_status, new.status);\n  v_dedupe text;\nbegin\n  if v_tid is null then return new; end if;\n  if tg_op = 'INSERT' then\n    v_event := 'estimate_created'; v_prev := null; v_dedupe := 'roof-estimate-created:' || new.id::text;\n  else\n    if new.status is not distinct from old.status\n       and new.approval_status is not distinct from old.approval_status\n       and new.approved_at is not distinct from old.approved_at\n       and new.total_job_price is not distinct from old.total_job_price\n       and new.total_squares is not distinct from old.total_squares\n       and new.report_pdf_path is not distinct from old.report_pdf_path then\n      return new;\n    end if;\n    v_prev := coalesce(old.approval_status, old.status);\n    if (new.approved_at is not null and old.approved_at is null) or (lower(coalesce(new.approval_status,''))='approved' and lower(coalesce(old.approval_status,''))<>'approved') then\n      v_event := 'estimate_approved'; v_dedupe := 'roof-estimate-approved:' || new.id::text;\n    elsif lower(coalesce(new.approval_status,''))='rejected' and lower(coalesce(old.approval_status,''))<>'rejected' then\n      v_event := 'estimate_rejected'; v_dedupe := 'roof-estimate-rejected:' || new.id::text;\n    else\n      v_event := 'estimate_updated'; v_dedupe := null;\n    end if;\n  end if;\n\n  perform public.business_activity_project(\n    v_tid,\n    v_event,\n    initcap(replace(v_event, '_', ' ')),\n    jsonb_build_object(\n      'contact_id', v_contact,\n      'actor_user_id', coalesce(auth.uid(), new.approved_by, new.created_by_user_id),\n      'description', coalesce(new.property_address, 'Roof estimate'),\n      'metadata', jsonb_build_object('roof_type', new.roof_type, 'total_squares', new.total_squares, 'pricing_mode', new.pricing_mode, 'report_pdf_path', new.report_pdf_path),\n      'related_entity_type', 'roof_estimate',\n      'related_entity_id', new.id,\n      'event_domain', 'sales',\n      'correlation_key', case when v_contact is not null then 'contact:' || v_contact::text else 'roof-estimate:' || new.id::text end,\n      'previous_state', v_prev,\n      'new_state', v_state,\n      'monetary_value', new.total_job_price,\n      'outcome', case when v_event='estimate_approved' then 'approved' when v_event='estimate_rejected' then 'rejected' else null end,\n      'dedupe_key', v_dedupe,\n      'source_record_type', 'roof_estimates',\n      'source_record_id', new.id,\n      'occurred_at', coalesce(new.approved_at, new.updated_at, new.created_at, now())\n    )\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_settlement_invoice_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_settlement_invoice_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare tid uuid:=public.business_activity_safe_uuid(new.tenant_org_id); cid uuid:=public.business_activity_safe_uuid(new.contact_id); event_name text;\nbegin\n  if tid is null then return new; end if;\n  if tg_op='UPDATE' and new.status is not distinct from old.status and new.settlement_amount is not distinct from old.settlement_amount and new.remaining_balance is not distinct from old.remaining_balance and new.paid_at is not distinct from old.paid_at then return new; end if;\n  event_name:=case when tg_op='INSERT' then 'settlement_invoice_created' when new.paid_at is not null and old.paid_at is null then 'settlement_invoice_paid' else 'settlement_invoice_updated' end;\n  perform public.business_activity_project(tid,event_name,case when event_name='settlement_invoice_paid' then 'Invoice paid' when event_name='settlement_invoice_created' then 'Invoice created' else 'Invoice updated' end,\n    jsonb_build_object('contact_id',cid,'actor_user_id',new.created_by_user_id,'description',coalesce(new.homeowner_name,new.invoice_number,'Invoice'),'metadata',jsonb_build_object('invoice_number',new.invoice_number,'remaining_balance',new.remaining_balance),\n      'related_entity_type','settlement_invoice','related_entity_id',new.id,'event_domain','revenue','correlation_key',coalesce('contact:'||cid::text,'invoice:'||new.id::text),'previous_state',case when tg_op='UPDATE' then old.status else null end,'new_state',new.status,\n      'monetary_value',case when event_name='settlement_invoice_paid' then new.settlement_amount else null end,'outcome',case when event_name='settlement_invoice_paid' then 'paid' else null end,'dedupe_key',case when tg_op='INSERT' then 'settlement-invoice-created:'||new.id::text else null end,\n      'source_record_type','settlement_invoices','source_record_id',new.id,'occurred_at',coalesce(new.created_at,now())));\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_signed_agreement_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_signed_agreement_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_event text;\n  v_prev text;\n  v_dedupe text;\nbegin\n  if new.tenant_id is null then return new; end if;\n  if tg_op = 'INSERT' then\n    v_event := 'signed_agreement_recorded'; v_prev := null; v_dedupe := 'signed-agreement:' || new.id::text;\n  else\n    if new.status is not distinct from old.status\n       and new.declined_at is not distinct from old.declined_at\n       and new.signed_at is not distinct from old.signed_at then\n      return new;\n    end if;\n    v_prev := old.status;\n    if new.declined_at is not null and old.declined_at is null then\n      v_event := 'signed_agreement_declined'; v_dedupe := 'signed-agreement-declined:' || new.id::text;\n    else\n      v_event := 'signed_agreement_updated'; v_dedupe := null;\n    end if;\n  end if;\n\n  perform public.business_activity_project(\n    new.tenant_id,\n    v_event,\n    initcap(replace(v_event, '_', ' ')),\n    jsonb_build_object(\n      'contact_id', new.contact_id,\n      'actor_user_id', coalesce(auth.uid(), new.user_id),\n      'description', coalesce(new.agreement_type, 'Signed agreement'),\n      'metadata', jsonb_build_object('agreement_version', new.agreement_version, 'signer_role', new.signer_role, 'event_booking_id', new.event_booking_id),\n      'related_entity_type', 'signed_agreement',\n      'related_entity_id', new.id,\n      'event_domain', 'document',\n      'correlation_key', case when new.contact_id is not null then 'contact:' || new.contact_id::text else 'signed-agreement:' || new.id::text end,\n      'previous_state', v_prev,\n      'new_state', new.status,\n      'outcome', case when v_event='signed_agreement_recorded' then 'signed' when v_event='signed_agreement_declined' then 'declined' else null end,\n      'dedupe_key', v_dedupe,\n      'source_record_type', 'signed_agreements',\n      'source_record_id', new.id,\n      'occurred_at', coalesce(new.declined_at, new.signed_at, now())\n    )\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_task_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_task_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_tid uuid := public.business_activity_safe_uuid(new.tenant_id);\n  v_contact uuid := coalesce(new.canonical_contact_id, public.business_activity_safe_uuid(new.contact_id));\n  v_event text;\n  v_prev text;\n  v_dedupe text;\nbegin\n  if v_tid is null then return new; end if;\n  if tg_op = 'INSERT' then\n    v_event := 'task_created'; v_prev := null; v_dedupe := 'task-created:' || new.id::text;\n  else\n    if new.status is not distinct from old.status\n       and new.assigned_to is not distinct from old.assigned_to\n       and new.due_date is not distinct from old.due_date\n       and new.completed_at is not distinct from old.completed_at\n       and new.priority is not distinct from old.priority then\n      return new;\n    end if;\n    v_prev := old.status;\n    if (new.completed_at is not null and old.completed_at is null) or (lower(coalesce(new.status,''))='completed' and lower(coalesce(old.status,''))<>'completed') then\n      v_event := 'task_completed'; v_dedupe := 'task-completed:' || new.id::text;\n    else\n      v_event := 'task_updated'; v_dedupe := null;\n    end if;\n  end if;\n\n  perform public.business_activity_project(\n    v_tid,\n    v_event,\n    initcap(replace(v_event, '_', ' ')),\n    jsonb_build_object(\n      'contact_id', v_contact,\n      'actor_user_id', coalesce(auth.uid(), new.user_id),\n      'description', new.title,\n      'metadata', jsonb_build_object('priority', new.priority, 'assigned_to', new.assigned_to, 'due_date', new.due_date, 'source_kind', new.source_kind, 'source_id', new.source_id),\n      'related_entity_type', 'task',\n      'related_entity_id', new.id,\n      'event_domain', 'workflow',\n      'correlation_key', case when v_contact is not null then 'contact:' || v_contact::text else 'task:' || new.id::text end,\n      'previous_state', v_prev,\n      'new_state', new.status,\n      'outcome', case when v_event='task_completed' then 'completed' else null end,\n      'dedupe_key', v_dedupe,\n      'source_record_type', 'tasks',\n      'source_record_id', new.id,\n      'occurred_at', coalesce(new.completed_at, new.updated_at, new.created_at, now())\n    )\n  );\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_tenant_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_tenant_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare event_name text;\nbegin\n  if tg_op='UPDATE' and new.status is not distinct from old.status and new.is_active is not distinct from old.is_active and new.is_trial is not distinct from old.is_trial then return new; end if;\n  event_name:=case when tg_op='INSERT' then 'business_joined_platform' else 'business_lifecycle_updated' end;\n  perform public.business_activity_project(new.id,event_name,case when tg_op='INSERT' then 'Business joined KnockLaunch' else 'Business lifecycle updated' end,\n    jsonb_build_object('actor_user_id',new.owner_id,'description',coalesce(new.company_dba_name,new.company_legal_name,new.name),'metadata',jsonb_build_object('tenant_type',new.tenant_type,'is_trial',new.is_trial),\n      'related_entity_type','tenant','related_entity_id',new.id,'importance','high','event_domain','platform','source_channel',coalesce(new.settings #>> '{acquisition,source}',new.settings->>'lead_source'),\n      'source_detail',coalesce(new.settings #>> '{acquisition,medium}',new.settings->>'utm_medium'),'source_campaign',coalesce(new.settings #>> '{acquisition,campaign}',new.settings->>'utm_campaign'),\n      'source_referrer',coalesce(new.settings #>> '{acquisition,referrer}',new.settings->>'referrer'),'correlation_key','tenant:'||new.id::text,'previous_state',case when tg_op='UPDATE' then old.status else null end,'new_state',new.status,\n      'outcome',case when new.is_active=false then 'inactive' when new.is_trial=false and tg_op='UPDATE' and old.is_trial=true then 'converted' else null end,'dedupe_key',case when tg_op='INSERT' then 'tenant-created:'||new.id::text else null end,\n      'source_record_type','tenants','source_record_id',new.id,'occurred_at',coalesce(new.created_at,now())));\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"project_user_presence_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.project_user_presence_business_activity()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare tid uuid:=public.business_activity_safe_uuid(new.tenant_id);\nbegin\n  if tid is null or new.event_type not in ('login','session_start') then return new; end if;\n  perform public.business_activity_project(tid,'user_'||new.event_type,case when new.event_type='login' then 'User signed in' else 'User session started' end,\n    jsonb_build_object('actor_user_id',new.user_id,'description',new.human_summary,'metadata',jsonb_build_object('device_family',new.device_family,'route_path',new.route_path),'related_entity_type','user','related_entity_id',new.user_id,\n      'event_domain','usage','touch_channel','App','correlation_key','user:'||new.user_id::text,'dedupe_key','user-activity:'||new.id::text,'source_record_type','user_activity_events','source_record_id',new.id,'occurred_at',new.occurred_at));\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"promote_committed_message_push_intent","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.promote_committed_message_push_intent()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare message_text text;\nbegin\n  if new.type<>'message_received' or new.tenant_id is null or new.user_id is null\n     then return new; end if;\n  message_text:=substring(coalesce(new.metadata->>'dedupe_key','')\n    from '^message:([0-9a-fA-F-]{36})$');\n  if message_text is null\n     or message_text !~* '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'\n     then return new; end if;\n  if exists(\n    select 1 from public.message_push_outbox o\n    where o.message_id=message_text::uuid\n      and o.recipient_user_id=new.user_id\n      and o.tenant_id::text=new.tenant_id\n  ) then\n    update public.platform_notification_deliveries d\n      set delivery_state='queued',last_error_code=null,\n          next_attempt_at=now(),updated_at=now()\n      where d.notification_id=new.id and d.channel='push'\n        and d.tenant_id::text=new.tenant_id\n        and d.user_id=new.user_id and d.delivery_state='blocked_unconfigured';\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"propagate_dnc_to_leads","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.propagate_dnc_to_leads()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_normalized text;\nBEGIN\n  v_normalized := NEW.phone_normalized;\n  IF v_normalized IS NULL THEN\n    RETURN NEW;\n  END IF;\n\n  UPDATE public.lead_deck\n  SET is_dnc = true,\n      dnc_reason = COALESCE(NEW.reason, 'Matched DNC list'),\n      dnc_checked_at = now(),\n      status = 'DNC',\n      updated_at = now()\n  WHERE public.normalize_phone_for_dnc(phone) = v_normalized\n    AND is_dnc = false;\n\n  UPDATE public.unified_contacts\n  SET is_dnc = true,\n      dnc_reason = COALESCE(NEW.reason, 'Matched DNC list'),\n      dnc_checked_at = now(),\n      status = 'DNC',\n      updated_at = now()\n  WHERE public.normalize_phone_for_dnc(phone) = v_normalized\n    AND is_dnc = false;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"propagate_federal_dnc_to_contacts","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.propagate_federal_dnc_to_contacts()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_last10 text;\nBEGIN\n  v_last10 := right(regexp_replace(NEW.phone, '\\D', '', 'g'), 10);\n  IF v_last10 IS NULL OR length(v_last10) <> 10 THEN\n    RETURN NEW;\n  END IF;\n  UPDATE public.unified_contacts\n  SET is_dnc = true,\n      updated_at = now()\n  WHERE is_dnc IS DISTINCT FROM true\n    AND right(regexp_replace(coalesce(phone, ''), '\\D', '', 'g'), 10) = v_last10;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"propagate_florida_dnc_to_contacts","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.propagate_florida_dnc_to_contacts()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_last10 text;\nBEGIN\n  v_last10 := right(regexp_replace(NEW.phone_normalized, '\\D', '', 'g'), 10);\n  IF v_last10 IS NULL OR length(v_last10) <> 10 THEN\n    RETURN NEW;\n  END IF;\n  UPDATE public.unified_contacts\n  SET is_dnc = true,\n      updated_at = now()\n  WHERE is_dnc IS DISTINCT FROM true\n    AND right(regexp_replace(coalesce(phone, ''), '\\D', '', 'g'), 10) = v_last10;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"protect_forward_phone","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.protect_forward_phone()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _normalized text;\n  _conflict   record;\nBEGIN\n  IF NEW.forward_to_phone IS NULL OR NEW.forward_to_phone = '' THEN\n    RETURN NEW;\n  END IF;\n\n  _normalized := regexp_replace(NEW.forward_to_phone, '\\D', '', 'g');\n  IF length(_normalized) < 10 THEN\n    RETURN NEW;\n  END IF;\n\n  SELECT id, phone_number, friendly_name INTO _conflict\n  FROM public.tenant_phone_numbers\n  WHERE regexp_replace(phone_number, '\\D', '', 'g') = _normalized\n  LIMIT 1;\n\n  IF FOUND THEN\n    RAISE EXCEPTION 'forward_phone_collision: % is a tenant-owned Twilio number (%) and cannot be the bridge target',\n      NEW.forward_to_phone, _conflict.friendly_name\n      USING ERRCODE = 'check_violation',\n            HINT = 'Forward target must be the rep''s real cell phone, not a Twilio DID.';\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"protect_profile_phone","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.protect_profile_phone()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _normalized text;\n  _conflict   record;\nBEGIN\n  IF NEW.phone IS NULL OR NEW.phone = '' THEN\n    RETURN NEW;\n  END IF;\n\n  _normalized := regexp_replace(NEW.phone, '\\D', '', 'g');\n  IF length(_normalized) < 10 THEN\n    RETURN NEW; -- let app-level validation handle bad formats\n  END IF;\n\n  SELECT id, phone_number, friendly_name, tenant_org_id INTO _conflict\n  FROM public.tenant_phone_numbers\n  WHERE regexp_replace(phone_number, '\\D', '', 'g') = _normalized\n  LIMIT 1;\n\n  IF FOUND THEN\n    RAISE EXCEPTION 'phone_collision: % is a tenant-owned Twilio number (%) and cannot be saved as a personal cell',\n      NEW.phone, _conflict.friendly_name\n      USING ERRCODE = 'check_violation',\n            HINT = 'Use the user''s real personal cell. Tenant Twilio numbers are managed under Communications Hub.';\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"provision_my_onboarding_session","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.provision_my_onboarding_session(p_session_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE v_uid uuid:=auth.uid(); s public.onboarding_sessions%rowtype; v_readiness jsonb; v_blueprint jsonb; v_business jsonb; v_tenant_id uuid; v_slug text; v_templates jsonb; v_foundation jsonb; v_bootstrap jsonb;\nBEGIN\n  IF v_uid IS NULL THEN RAISE EXCEPTION 'Authentication required' USING ERRCODE='42501'; END IF; SELECT * INTO s FROM public.onboarding_sessions WHERE id=p_session_id AND (owner_user_id=v_uid OR public.is_system_admin(v_uid)); IF NOT FOUND THEN RAISE EXCEPTION 'Onboarding session not found' USING ERRCODE='42501'; END IF;\n  v_blueprint:=public.derive_onboarding_blueprint(p_session_id); v_readiness:=public.refresh_onboarding_readiness(p_session_id); IF jsonb_array_length(coalesce(v_readiness->'missing','[]'::jsonb))>0 THEN RETURN public.get_my_onboarding_context(p_session_id)||jsonb_build_object('provisioned',false,'reason','needs_input'); END IF;\n  SELECT * INTO s FROM public.onboarding_sessions WHERE id=p_session_id; v_business:=v_blueprint->'business_operating_blueprint'; v_tenant_id:=s.tenant_id;\n  IF v_tenant_id IS NULL THEN v_tenant_id:=gen_random_uuid(); v_slug:=coalesce(nullif(s.company_slug,''),trim(both '-' from regexp_replace(lower(s.company_name),'[^a-z0-9]+','-','g'))||'-'||substr(replace(s.id::text,'-',''),1,6)); INSERT INTO public.tenants(id,name,tenant_type,owner_id,status,settings,company_slug,company_state,company_email,company_website,is_active) VALUES(v_tenant_id,s.company_name,s.canonical_tenant_type,v_uid,'inactive',jsonb_build_object('onboarding_session_id',s.id,'onboarding_blueprint',v_blueprint,'business_type',s.requested_business_type,'declared_business_type',s.canonical_tenant_type,'operating_model',v_blueprint->>'operating_model','business_operating_blueprint',v_business,'service_lines',s.service_lines,'goals',s.goals,'requested_capabilities',s.requested_capabilities,'service_area',s.service_area),v_slug,case when cardinality(s.operating_states)>0 then s.operating_states[1] else null end,s.email,nullif(s.intake_answers->>'website',''),false); UPDATE public.onboarding_sessions SET tenant_id=v_tenant_id,company_slug=v_slug,status='provisioning',updated_at=now() WHERE id=p_session_id; ELSE UPDATE public.onboarding_sessions SET status='provisioning',updated_at=now() WHERE id=p_session_id; END IF;\n  v_templates:=public.clone_onboarding_templates_internal(v_tenant_id,s.canonical_tenant_type,public.academy_track_for_type(s.canonical_tenant_type)); v_foundation:=public.ensure_tenant_provisioning_foundation(v_tenant_id,v_uid,'Tenant Owner'); v_bootstrap:=public.provision_tenant_blueprint(v_tenant_id);\n  UPDATE public.onboarding_sessions SET status=CASE WHEN coalesce((v_bootstrap->>'ok')::boolean,false) THEN 'ready' ELSE 'validating' END,last_error=CASE WHEN coalesce((v_bootstrap->>'ok')::boolean,false) THEN null ELSE 'Tenant product bootstrap is not ready' END,updated_at=now() WHERE id=p_session_id;\n  RETURN public.get_my_onboarding_context(p_session_id)||jsonb_build_object('provisioned',coalesce((v_bootstrap->>'ok')::boolean,false),'tenant_id',v_tenant_id,'foundation',v_foundation,'templates',v_templates,'bootstrap',v_bootstrap);\nEND;\n$function$\n","identity_arguments":"p_session_id uuid"},{"name":"provision_tenant_blueprint","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.provision_tenant_blueprint(p_tenant_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'storage'\nAS $function$\nDECLARE t public.tenants%rowtype; v_model text; v_blueprint jsonb; v_apps jsonb; v_bucket text; v_owner_required boolean; v_pending int; v_public text; v_caller uuid:=auth.uid(); v_authorized boolean:=false;\nBEGIN\n  SELECT * INTO t FROM public.tenants WHERE id=p_tenant_id FOR UPDATE; IF NOT FOUND THEN RAISE EXCEPTION 'Tenant not found'; END IF;\n  v_authorized:=session_user IN ('postgres','supabase_admin') OR coalesce(auth.role(),'')='service_role' OR public.is_system_admin(v_caller) OR public.is_admin_or_higher(v_caller,p_tenant_id) OR t.owner_id=v_caller;\n  IF NOT v_authorized THEN RAISE EXCEPTION 'Not authorized to provision this tenant blueprint' USING ERRCODE='42501'; END IF;\n  v_model:=public.tenant_operating_model_for(t.tenant_type,coalesce(t.settings,'{}'::jsonb)); v_blueprint:=public.build_tenant_business_blueprint(t.tenant_type,coalesce(t.settings,'{}'::jsonb),t.name); v_apps:=coalesce(t.settings->'enabled_applications',v_blueprint->'applications',public.tenant_blueprint_applications(v_model));\n  v_bucket:=public.kl_tenant_storage_bucket(t.id); IF nullif(v_bucket,'') IS NULL THEN RAISE EXCEPTION 'Tenant storage identity was not assigned'; END IF;\n  INSERT INTO storage.buckets(id,name,public,file_size_limit) VALUES(v_bucket,v_bucket,false,262144000) ON CONFLICT(id) DO UPDATE SET name=excluded.name,public=false,file_size_limit=greatest(coalesce(storage.buckets.file_size_limit,0),excluded.file_size_limit);\n  v_owner_required:=NOT(coalesce(t.settings->>'workspace_mode','')='prospect_demo' OR coalesce((t.settings->>'internal_prospect_demo')::boolean,false));\n  IF t.owner_id IS NOT NULL THEN PERFORM public.ensure_tenant_provisioning_foundation(t.id,t.owner_id,'Tenant Owner');\n  ELSIF v_owner_required THEN\n    INSERT INTO public.tenant_readiness_checks(tenant_id,check_key,status,detail) VALUES(t.id,'owner_foundation','blocked',jsonb_build_object('reason','owner_required')) ON CONFLICT(tenant_id,check_key) DO UPDATE SET status='blocked',detail=excluded.detail,updated_at=now();\n  ELSE\n    INSERT INTO public.tenant_readiness_checks(tenant_id,check_key,status,detail) VALUES(t.id,'owner_foundation','ready',jsonb_build_object('demo_owner_not_required',true)) ON CONFLICT(tenant_id,check_key) DO UPDATE SET status='ready',detail=excluded.detail,updated_at=now();\n  END IF;\n  INSERT INTO public.tenant_readiness_checks(tenant_id,check_key,status,detail) VALUES\n    (t.id,'business_identity','ready',jsonb_build_object('declared_business_type',t.tenant_type,'operating_model',v_model)),\n    (t.id,'blueprint','ready',jsonb_build_object('blueprint',v_blueprint)),\n    (t.id,'applications','ready',jsonb_build_object('applications',v_apps,'source','business_operating_blueprint')),\n    (t.id,'experience','ready',jsonb_build_object('shell','blueprint_driven','module_count',jsonb_array_length(coalesce(v_blueprint->'modules','[]'::jsonb)),'operating_model',v_model)),\n    (t.id,'routing','ready',jsonb_build_object('namespace',t.settings->>'route_namespace','workspace_route',t.settings->>'canonical_workspace_route')),\n    (t.id,'storage_media','ready',jsonb_build_object('bucket',v_bucket,'collections',jsonb_build_array('branding','backgrounds','videos','marketing'))),\n    (t.id,'settings_billing','ready',jsonb_build_object('settings_route','/'||t.company_slug||'/settings','billing_route','/'||t.company_slug||'/settings/billing')),\n    (t.id,'opportunity_radar','ready',jsonb_build_object('baseline','tenant_lifecycle_seed'))\n  ON CONFLICT(tenant_id,check_key) DO UPDATE SET status='ready',detail=excluded.detail,updated_at=now();\n  v_public:=CASE WHEN v_model IN ('appointments','recurring_routes','events','orders') OR t.tenant_type='SHORT_TERM_RENTAL' THEN coalesce(nullif(t.settings->>'canonical_public_route',''),'https://whatsmyprogress.com/'||t.company_slug||'/') ELSE NULL END;\n  INSERT INTO public.tenant_readiness_checks(tenant_id,check_key,status,detail) VALUES(t.id,'customer_entry','ready',jsonb_build_object('required',v_public IS NOT NULL,'public_route',v_public)) ON CONFLICT(tenant_id,check_key) DO UPDATE SET status='ready',detail=excluded.detail,updated_at=now();\n  SELECT count(*) INTO v_pending FROM public.tenant_readiness_checks WHERE tenant_id=t.id AND check_key IN ('business_identity','blueprint','applications','experience','routing','storage_media','owner_foundation','settings_billing','customer_entry','opportunity_radar') AND status<>'ready';\n  UPDATE public.tenants SET settings=coalesce(settings,'{}'::jsonb)||jsonb_build_object('business_operating_blueprint',v_blueprint,'enabled_applications',v_apps,'bootstrap_state',CASE WHEN v_pending=0 THEN 'ready' ELSE 'blocked' END),status=CASE WHEN v_pending=0 THEN 'active' ELSE 'inactive' END,is_active=(v_pending=0),updated_at=now() WHERE id=t.id;\n  RETURN jsonb_build_object('ok',v_pending=0,'tenant_id',t.id,'tenant_type',t.tenant_type,'operating_model',v_model,'applications',v_apps,'storage_bucket',v_bucket,'pending_required_checks',v_pending);\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"publish_live_edit_override","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.publish_live_edit_override(_tenant_id uuid, _route_path text, _operations jsonb)\n RETURNS TABLE(override_id uuid, revision_id uuid)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  _user_id uuid := public.request_user_id();\n  _override_id uuid;\n  _revision_id uuid;\n  _parent_revision_id uuid;\n  _existing_operations jsonb := '[]'::jsonb;\n  _non_live_operations jsonb := '[]'::jsonb;\nbegin\n  if _user_id is null then raise exception 'Authentication required'; end if;\n  if not public.can_manage_page_override(_user_id, _tenant_id::text) then raise exception 'Tenant edit access denied'; end if;\n  if _route_path is null or length(_route_path) < 1 or length(_route_path) > 512 then raise exception 'Invalid route'; end if;\n  if not public.live_edit_operations_safe(_operations) then raise exception 'Unsafe Live Edit operations'; end if;\n\n  select id, operations into _override_id, _existing_operations\n  from public.godmode_page_overrides\n  where tenant_scope = _tenant_id::text\n    and route_path = _route_path\n    and status = 'published'\n    and (title = 'Live page edits' or metadata->>'source' in ('live-edit-v1','live-edit-v2'))\n  order by published_at desc nulls last, updated_at desc\n  limit 1\n  for update;\n\n  if _override_id is not null then\n    select coalesce(jsonb_agg(value), '[]'::jsonb) into _non_live_operations\n    from jsonb_array_elements(coalesce(_existing_operations, '[]'::jsonb))\n    where coalesce(value#>>'{audit,source}', '') <> 'live-edit';\n\n    update public.godmode_page_overrides\n    set operations = _non_live_operations || _operations,\n        status = 'published',\n        title = 'Live page edits',\n        metadata = coalesce(metadata, '{}'::jsonb) || jsonb_build_object('source','live-edit-v2'),\n        version = coalesce(version, 0) + 1,\n        updated_by = _user_id,\n        published_by = _user_id,\n        updated_at = now(),\n        published_at = now()\n    where id = _override_id;\n  else\n    insert into public.godmode_page_overrides (\n      route_path, tenant_scope, device_scope, status, title, operations, metadata,\n      created_by, updated_by, published_by, created_at, updated_at, published_at\n    ) values (\n      _route_path, _tenant_id::text, 'all', 'published', 'Live page edits', _operations,\n      jsonb_build_object('source','live-edit-v2'), _user_id, _user_id, _user_id, now(), now(), now()\n    ) returning id into _override_id;\n  end if;\n\n  select id into _parent_revision_id\n  from public.live_edit_revisions\n  where tenant_id = _tenant_id and route_path = _route_path\n  order by created_at desc\n  limit 1;\n\n  insert into public.live_edit_revisions (\n    tenant_id, route_path, override_id, parent_revision_id, operations, created_by\n  ) values (\n    _tenant_id, _route_path, _override_id, _parent_revision_id, _operations, _user_id\n  ) returning id into _revision_id;\n\n  delete from public.godmode_page_overrides\n  where tenant_scope = _tenant_id::text\n    and route_path = _route_path\n    and status = 'draft'\n    and title = 'Live page draft'\n    and metadata->>'source' = 'live-edit-v2';\n\n  return query select _override_id, _revision_id;\nend;\n$function$\n","identity_arguments":"_tenant_id uuid, _route_path text, _operations jsonb"},{"name":"publish_platform_message_key_version","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.publish_platform_message_key_version(p_conversation_id uuid, p_key_version integer, p_envelopes jsonb)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare item jsonb; target_user uuid; target_device text;\nbegin\n  if not public.can_access_message_conversation(p_conversation_id,auth.uid()) then raise exception 'message_conversation_access_denied'; end if;\n  if p_key_version is null or p_key_version<1 or p_key_version>100000 then raise exception 'invalid_key_version'; end if;\n  if jsonb_typeof(p_envelopes)<>'array' or jsonb_array_length(p_envelopes)=0 then raise exception 'key_envelopes_required'; end if;\n  if p_key_version <= coalesce((select current_key_version from public.message_conversations where id=p_conversation_id),0) then raise exception 'stale_key_version'; end if;\n  for item in select value from jsonb_array_elements(p_envelopes) loop\n    target_user := (item->>'user_id')::uuid; target_device := item->>'device_id';\n    if not exists(\n      select 1 from public.message_conversation_members m\n      join public.message_device_keys d on d.user_id=m.user_id and d.device_id=target_device and d.revoked_at is null\n      where m.conversation_id=p_conversation_id and m.user_id=target_user\n    ) then raise exception 'invalid_key_envelope_target'; end if;\n    insert into public.message_conversation_key_envelopes(\n      conversation_id,key_version,user_id,device_id,sender_device_id,sender_public_key,wrapped_key,wrap_nonce\n    ) values(\n      p_conversation_id,p_key_version,target_user,target_device,\n      left(item->>'sender_device_id',160),item->'sender_public_key',item->>'wrapped_key',item->>'wrap_nonce'\n    ) on conflict(conversation_id,key_version,user_id,device_id) do update set\n      sender_device_id=excluded.sender_device_id,sender_public_key=excluded.sender_public_key,\n      wrapped_key=excluded.wrapped_key,wrap_nonce=excluded.wrap_nonce,created_at=now();\n  end loop;\n  update public.message_conversations set encryption_enabled=true,current_key_version=p_key_version,key_rotation_required=false,updated_at=now()\n  where id=p_conversation_id;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_key_version integer, p_envelopes jsonb"},{"name":"purge_call_lifecycle_events","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.purge_call_lifecycle_events()\n RETURNS void\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  DELETE FROM public.call_lifecycle_events WHERE created_at < now() - interval '7 days';\n$function$\n","identity_arguments":""},{"name":"queue_onboarding_license_research","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.queue_onboarding_license_research(p_session_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  s public.onboarding_sessions%rowtype; v_state text; v_business_type text; v_source record; v_owner_name text; v_license_number text; v_mode text; v_query jsonb; v_result jsonb; v_status text; v_error text; v_token uuid; v_queued int := 0; v_owner_input int := 0; v_operator_review int := 0;\nBEGIN\n  SELECT * INTO s FROM public.onboarding_sessions WHERE id=p_session_id;\n  IF NOT FOUND THEN RAISE EXCEPTION 'Onboarding session not found'; END IF;\n  IF coalesce(auth.role(),'') <> 'service_role' THEN IF auth.uid() IS NULL OR (s.owner_user_id IS DISTINCT FROM auth.uid() AND NOT public.is_system_admin(auth.uid())) THEN RAISE EXCEPTION 'Not authorized for this onboarding session' USING ERRCODE='42501'; END IF; END IF;\n  IF cardinality(s.operating_states)=0 THEN RETURN public.refresh_onboarding_readiness(p_session_id); END IF;\n  v_business_type := public.canonical_tenant_type(s.requested_business_type);\n  IF v_business_type IS NULL THEN RETURN public.refresh_onboarding_readiness(p_session_id); END IF;\n  SELECT p.name,p.license_number INTO v_owner_name,v_license_number FROM public.profiles p WHERE p.id=s.owner_user_id;\n  v_owner_name := coalesce(nullif(s.intake_answers->>'owner_name',''),nullif(v_owner_name,''));\n  v_license_number := coalesce(nullif(s.intake_answers->>'license_number',''),nullif(v_license_number,''));\n  FOREACH v_state IN ARRAY s.operating_states LOOP\n    SELECT * INTO v_source FROM public.onboarding_license_sources ls WHERE upper(ls.jurisdiction)=upper(v_state) AND ls.business_type=v_business_type AND ls.is_active=true AND ls.is_official=true ORDER BY CASE WHEN ls.metadata->>'automation_mode'='automated' THEN 0 ELSE 1 END, ls.created_at ASC LIMIT 1;\n    v_query := jsonb_build_object('company_name',s.company_name,'business_type',v_business_type,'jurisdiction',upper(v_state),'owner_name',v_owner_name,'license_number',v_license_number);\n    IF FOUND THEN\n      v_mode := coalesce(v_source.metadata->>'automation_mode','interactive_required');\n      IF v_mode='automated' AND (coalesce(v_owner_name,'')<>'' OR coalesce(v_license_number,'')<>'') THEN v_status:='pending'; v_error:=null; v_token:=gen_random_uuid(); v_result:='{}'::jsonb; v_queued:=v_queued+1;\n      ELSIF v_mode='automated' THEN v_status:='needs_review'; v_error:='Owner name or license number is needed to complete the official license lookup'; v_token:=null; v_result:=jsonb_build_object('owner_input_required',true,'missing',jsonb_build_array('owner_name')); v_owner_input:=v_owner_input+1;\n      ELSE v_status:='needs_review'; v_error:=coalesce(v_source.metadata->>'reason','This official registry requires interactive verification'); v_token:=null; v_result:=jsonb_build_object('owner_input_required',false,'review_type','knocklaunch_operator','reason',v_error); v_operator_review:=v_operator_review+1; END IF;\n      INSERT INTO public.onboarding_research_tasks(session_id,research_type,jurisdiction,provider_key,query,result,status,source_url,last_error,dispatch_token,dispatched_at)\n      VALUES(p_session_id,'license_verification',upper(v_state),v_source.provider_key,v_query,v_result,v_status,v_source.source_url,v_error,v_token,CASE WHEN v_token IS NOT NULL THEN now() ELSE null END)\n      ON CONFLICT (session_id,research_type,jurisdiction) DO UPDATE SET provider_key=excluded.provider_key,query=excluded.query,source_url=excluded.source_url,result=CASE WHEN public.onboarding_research_tasks.status='verified' THEN public.onboarding_research_tasks.result ELSE excluded.result END,status=CASE WHEN public.onboarding_research_tasks.status='verified' THEN 'verified' ELSE excluded.status END,last_error=CASE WHEN public.onboarding_research_tasks.status='verified' THEN null ELSE excluded.last_error END,dispatch_token=CASE WHEN public.onboarding_research_tasks.status='verified' THEN null ELSE excluded.dispatch_token END,dispatched_at=CASE WHEN public.onboarding_research_tasks.status='verified' THEN public.onboarding_research_tasks.dispatched_at ELSE excluded.dispatched_at END,updated_at=now();\n    ELSE\n      v_result:=jsonb_build_object('owner_input_required',false,'review_type','knocklaunch_operator','reason','No configured authoritative licensing source for this jurisdiction/business type');\n      INSERT INTO public.onboarding_research_tasks(session_id,research_type,jurisdiction,provider_key,query,result,status,last_error,dispatch_token)\n      VALUES(p_session_id,'license_verification',upper(v_state),null,v_query,v_result,'needs_review','No configured authoritative licensing source for this jurisdiction/business type',null)\n      ON CONFLICT (session_id,research_type,jurisdiction) DO UPDATE SET provider_key=null,query=excluded.query,source_url=null,result=CASE WHEN public.onboarding_research_tasks.status='verified' THEN public.onboarding_research_tasks.result ELSE excluded.result END,status=CASE WHEN public.onboarding_research_tasks.status='verified' THEN 'verified' ELSE 'needs_review' END,last_error=CASE WHEN public.onboarding_research_tasks.status='verified' THEN null ELSE excluded.last_error END,dispatch_token=null,updated_at=now();\n      v_operator_review:=v_operator_review+1;\n    END IF;\n  END LOOP;\n  PERFORM public.refresh_onboarding_readiness(p_session_id);\n  RETURN jsonb_build_object('ok',true,'session_id',p_session_id,'queued',v_queued,'owner_input_required',v_owner_input,'operator_review',v_operator_review,'business_type',v_business_type);\nEND;\n$function$\n","identity_arguments":"p_session_id uuid"},{"name":"queue_opportunity_radar_lifecycle_seed","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.queue_opportunity_radar_lifecycle_seed()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'private', 'net'\nAS $function$\ndeclare\n  lifecycle_token text;\n  old_radar_settings jsonb;\n  new_radar_settings jsonb;\nbegin\n  if coalesce(new.status, 'active') <> 'active' or coalesce(new.is_active, true) = false then\n    return new;\n  end if;\n\n  if tg_op = 'UPDATE' then\n    old_radar_settings := jsonb_build_object(\n      'profile', old.settings->'opportunity_radar_profile',\n      'workspace_type', old.settings->'workspace_type',\n      'keywords', old.settings->'opportunity_radar_keywords',\n      'intents', old.settings->'opportunity_intent_terms',\n      'event_terms', old.settings->'opportunity_event_terms',\n      'territory_terms', old.settings#>'{opportunity_territory,terms}',\n      'inferred_type', old.settings#>'{business_discovery,inferredTenantType}'\n    );\n    new_radar_settings := jsonb_build_object(\n      'profile', new.settings->'opportunity_radar_profile',\n      'workspace_type', new.settings->'workspace_type',\n      'keywords', new.settings->'opportunity_radar_keywords',\n      'intents', new.settings->'opportunity_intent_terms',\n      'event_terms', new.settings->'opportunity_event_terms',\n      'territory_terms', new.settings#>'{opportunity_territory,terms}',\n      'inferred_type', new.settings#>'{business_discovery,inferredTenantType}'\n    );\n\n    if new.tenant_type is not distinct from old.tenant_type\n       and new.company_city is not distinct from old.company_city\n       and new.company_state is not distinct from old.company_state\n       and new.company_zip is not distinct from old.company_zip\n       and new_radar_settings is not distinct from old_radar_settings then\n      return new;\n    end if;\n  end if;\n\n  select token into lifecycle_token\n  from private.opportunity_radar_lifecycle_secret\n  where singleton = true;\n\n  if nullif(lifecycle_token, '') is null then\n    return new;\n  end if;\n\n  perform net.http_post(\n    url := 'https://ymntrajfubicyxwwdxxa.supabase.co/functions/v1/opportunity-radar/seed',\n    body := jsonb_build_object('tenant_id', new.id),\n    headers := jsonb_build_object(\n      'Content-Type', 'application/json',\n      'x-knocklaunch-radar-seed', lifecycle_token\n    ),\n    timeout_milliseconds := 30000\n  );\n\n  return new;\nexception when others then\n  raise warning 'Opportunity Radar lifecycle seed queue failed for tenant %: %', new.id, sqlerrm;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"read_email_batch","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.read_email_batch(queue_name text, batch_size integer, vt integer)\n RETURNS TABLE(msg_id bigint, read_ct integer, message jsonb)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_catalog'\nAS $function$\nBEGIN\n  RETURN QUERY SELECT r.msg_id, r.read_ct, r.message FROM pgmq.read(queue_name, vt, batch_size) r;\nEXCEPTION WHEN undefined_table THEN\n  PERFORM pgmq.create(queue_name);\n  RETURN;\nEND;\n$function$\n","identity_arguments":"queue_name text, batch_size integer, vt integer"},{"name":"realtor_campaign_property_tenant_guard","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.realtor_campaign_property_tenant_guard()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  c_tenant uuid;\n  p_tenant uuid;\nBEGIN\n  SELECT tenant_id INTO c_tenant FROM public.realtor_campaigns WHERE id = NEW.campaign_id;\n  SELECT tenant_id INTO p_tenant FROM public.realtor_properties WHERE id = NEW.property_id;\n  IF c_tenant IS NULL OR p_tenant IS NULL THEN\n    RAISE EXCEPTION 'Campaign or property not found';\n  END IF;\n  IF c_tenant <> NEW.tenant_id OR p_tenant <> NEW.tenant_id THEN\n    RAISE EXCEPTION 'Cross-tenant campaign/property link rejected';\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"recalc_academy_enrollment_progress","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.recalc_academy_enrollment_progress(_user_id uuid, _course_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_total_lessons int;\n  v_completed_lessons int;\n  v_pct int;\n  v_status text;\nBEGIN\n  -- Total lessons in the course (via units)\n  SELECT COUNT(*)::int INTO v_total_lessons\n  FROM public.academy_lessons l\n  JOIN public.academy_units u ON u.id = l.unit_id\n  WHERE u.course_id = _course_id;\n\n  -- Completed lessons by this user for this course\n  SELECT COUNT(*)::int INTO v_completed_lessons\n  FROM public.academy_trainee_progress tp\n  WHERE tp.user_id = _user_id\n    AND tp.course_id = _course_id\n    AND (tp.status = 'completed' OR tp.completed_at IS NOT NULL);\n\n  IF v_total_lessons > 0 THEN\n    v_pct := LEAST(100, ROUND((v_completed_lessons::numeric / v_total_lessons::numeric) * 100)::int);\n  ELSE\n    v_pct := 0;\n  END IF;\n\n  IF v_pct >= 100 THEN\n    v_status := 'completed';\n  ELSIF v_pct > 0 THEN\n    v_status := 'active';\n  ELSE\n    v_status := 'active';\n  END IF;\n\n  -- Upsert the enrollment row (auto-enroll if missing so progress is never lost)\n  INSERT INTO public.academy_enrollments (user_id, course_id, status, progress_percent, completed_at, created_at, updated_at)\n  VALUES (\n    _user_id,\n    _course_id,\n    v_status,\n    v_pct,\n    CASE WHEN v_pct >= 100 THEN now() ELSE NULL END,\n    now(),\n    now()\n  )\n  ON CONFLICT (user_id, course_id) DO UPDATE\n  SET progress_percent = EXCLUDED.progress_percent,\n      status = EXCLUDED.status,\n      completed_at = CASE WHEN EXCLUDED.progress_percent >= 100\n                          THEN COALESCE(public.academy_enrollments.completed_at, now())\n                          ELSE NULL END,\n      updated_at = now();\nEND;\n$function$\n","identity_arguments":"_user_id uuid, _course_id uuid"},{"name":"recall_live_edit_sidekick_memory","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.recall_live_edit_sidekick_memory(_context_tenant_id uuid, _route text, _limit integer DEFAULT 32)\n RETURNS TABLE(session_id uuid, turn_id uuid, created_at timestamp with time zone, raw_message text)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_route text := left(trim(coalesce(_route, '')), 240);\n  v_limit integer := greatest(1, least(coalesce(_limit, 32), 80));\nbegin\n  if auth.uid() is null or not public.can_use_live_edit_sidekick_memory(auth.uid(), _context_tenant_id) then\n    raise exception 'Live Edit Sidekick memory access denied' using errcode = '42501';\n  end if;\n\n  return query\n  select\n    e.id,\n    cm.id,\n    cm.created_at,\n    cm.message\n  from public.command_center_events e\n  join public.command_center_messages cm on cm.command_center_event_id = e.id\n  where e.event_type = 'sidekick_conversation_log'\n    and e.created_by_user_id = auth.uid()\n    and cm.sender_user_id = auth.uid()\n    and coalesce(e.mission_context->>'sidekick_surface', '') = 'live-edit'\n    and coalesce(e.mission_context->>'context_tenant_id', '') = _context_tenant_id::text\n    and coalesce(e.mission_context->>'last_route', '') = v_route\n  order by cm.created_at desc\n  limit v_limit;\nend;\n$function$\n","identity_arguments":"_context_tenant_id uuid, _route text, _limit integer"},{"name":"reconcile_configured_lead_source_routing_on_membership","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.reconcile_configured_lead_source_routing_on_membership()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare v_email text;\nbegin\n  if new.status <> 'active' then return new; end if;\n  select p.email into v_email from public.profiles p where p.id=new.user_id;\n  if nullif(btrim(coalesce(v_email,'')),'') is null then return new; end if;\n  update public.unified_contacts c set source=c.source,updated_at=now() from public.tenants t where t.id=new.tenant_id and c.tenant_org_id=new.tenant_id::text and lower(coalesce(t.settings->'lead_source_routing'->c.source->>'assignee_email',''))=lower(v_email);\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"reconcile_default_role_insert","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.reconcile_default_role_insert()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare v_existing public.user_roles%rowtype;\nbegin\n  if new.tenant_id is null then return new; end if;\n  select * into v_existing from public.user_roles where user_id=new.user_id and tenant_id=new.tenant_id limit 1;\n  if not found then return new; end if;\n  if v_existing.role = new.role then\n    if new.assigned_by is not null and v_existing.assigned_by is null then\n      update public.user_roles set assigned_by=new.assigned_by, assigned_at=coalesce(new.assigned_at,now()) where id=v_existing.id;\n    end if;\n    return null;\n  end if;\n  if v_existing.role in ('Rep'::app_role,'Tenant Owner'::app_role) and new.assigned_by is not null then\n    update public.user_roles set role=new.role, assigned_by=new.assigned_by, assigned_at=coalesce(new.assigned_at,now()) where id=v_existing.id;\n    return null;\n  end if;\n  raise exception 'Conflicting explicit tenant role for user % tenant %: existing %, requested %',new.user_id,new.tenant_id,v_existing.role,new.role;\nend;\n$function$\n","identity_arguments":""},{"name":"reconcile_modes_tenant_capability","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.reconcile_modes_tenant_capability(p_tenant_id uuid DEFAULT NULL::uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_count integer := 0;\n  v_changed integer := 0;\n  v_ready integer := 0;\n  v_prerequisite integer := 0;\nbegin\n  select count(*)\n    into v_count\n    from public.tenants as tenant\n    where (p_tenant_id is null or tenant.id = p_tenant_id)\n      and public.canonical_tenant_experience_family(tenant.settings, tenant.tenant_type) = 'modes';\n\n  update public.tenants as tenant\n  set settings = computed.next_settings,\n      updated_at = now()\n  from lateral (\n    select public.apply_modes_tenant_capability_contract(tenant.settings, tenant.tenant_type) as next_settings\n  ) as computed\n  where (p_tenant_id is null or tenant.id = p_tenant_id)\n    and public.canonical_tenant_experience_family(tenant.settings, tenant.tenant_type) = 'modes'\n    and tenant.settings is distinct from computed.next_settings;\n\n  get diagnostics v_changed = row_count;\n\n  select count(*) filter (where tenant.settings #>> '{modes,activation_state}' = 'ready'),\n         count(*) filter (where tenant.settings #>> '{modes,activation_state}' = 'prerequisite_required')\n    into v_ready, v_prerequisite\n    from public.tenants as tenant\n    where (p_tenant_id is null or tenant.id = p_tenant_id)\n      and lower(coalesce(tenant.settings ->> 'experience_family', '')) = 'modes';\n\n  return jsonb_build_object(\n    'reconciled', v_count,\n    'changed', v_changed,\n    'ready', v_ready,\n    'prerequisite_required', v_prerequisite,\n    'contract', 'MODES_TENANT_V1',\n    'default_media_contract', 'MODE_DEFAULT_MEDIA_V2'\n  );\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"reconcile_tenant_business_blueprint","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.reconcile_tenant_business_blueprint(p_tenant_id uuid, p_merge_legacy boolean DEFAULT false)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant public.tenants%rowtype;\n  v_legacy_apps jsonb := '[]'::jsonb;\n  v_settings jsonb;\n  v_apps jsonb;\n  v_enabled_count integer := 0;\nbegin\n  select * into v_tenant from public.tenants where id = p_tenant_id for update;\n  if not found then raise exception 'tenant_not_found'; end if;\n\n  if public.normalize_declared_business_type(coalesce(\n      v_tenant.settings#>>'{business_operating_blueprint,businessTypeKey}',\n      v_tenant.settings->>'declared_business_type',\n      v_tenant.settings->>'business_type',\n      v_tenant.tenant_type\n    )) is null then\n    return jsonb_build_object(\n      'ok', true,\n      'tenant_id', p_tenant_id,\n      'skipped', true,\n      'reason', 'non_business_platform_identity'\n    );\n  end if;\n\n  if p_merge_legacy\n     and jsonb_array_length(public.canonical_tenant_application_ids(v_tenant.settings->'enabled_applications')) = 0\n     and jsonb_array_length(public.canonical_tenant_application_ids(v_tenant.settings#>'{tenant_manifest,applications}')) = 0 then\n    select coalesce(jsonb_agg(ta.application_id order by ta.installed_at, ta.application_id), '[]'::jsonb)\n      into v_legacy_apps\n    from public.tenant_applications ta\n    where ta.tenant_id = p_tenant_id and ta.enabled = true;\n  end if;\n\n  v_settings := public.compile_tenant_business_blueprint_settings(\n    v_tenant.tenant_type,\n    v_tenant.name,\n    coalesce(v_tenant.settings, '{}'::jsonb),\n    p_merge_legacy,\n    v_legacy_apps\n  );\n  v_apps := public.canonical_tenant_application_ids(v_settings#>'{business_operating_blueprint,applications}');\n\n  update public.tenants\n  set settings = v_settings,\n      updated_at = now()\n  where id = p_tenant_id;\n\n  insert into public.tenant_applications (\n    tenant_id, application_id, enabled, settings, bootstrap_version, updated_at\n  )\n  select\n    p_tenant_id,\n    c.id,\n    true,\n    jsonb_build_object(\n      'application_slug', c.slug,\n      'standalone_path', c.standalone_path,\n      'login_path', c.login_path,\n      'bootstrap_contract', 'application-bootstrap.v' || c.bootstrap_version::text,\n      'route_adapter', c.route_adapter,\n      'bootstrap_source', 'business-operating-blueprint'\n    ),\n    c.bootstrap_version,\n    now()\n  from jsonb_array_elements_text(v_apps) app(application_id)\n  join public.application_catalog c on c.id = app.application_id\n  on conflict (tenant_id, application_id) do update set\n    enabled = true,\n    settings = coalesce(public.tenant_applications.settings, '{}'::jsonb) || excluded.settings,\n    bootstrap_version = greatest(public.tenant_applications.bootstrap_version, excluded.bootstrap_version),\n    updated_at = now();\n\n  update public.tenant_applications ta\n  set enabled = false,\n      updated_at = now(),\n      settings = coalesce(ta.settings, '{}'::jsonb) || jsonb_build_object('disabled_by', 'business-operating-blueprint')\n  where ta.tenant_id = p_tenant_id\n    and ta.enabled = true\n    and not (v_apps ? ta.application_id)\n    and exists (\n      select 1 from public.application_catalog c\n      where c.id = ta.application_id and c.audience = 'tenant-user'\n    );\n\n  select count(*) into v_enabled_count\n  from public.tenant_applications\n  where tenant_id = p_tenant_id and enabled = true;\n\n  return jsonb_build_object(\n    'ok', true,\n    'tenant_id', p_tenant_id,\n    'business_type_key', v_settings#>>'{business_operating_blueprint,businessTypeKey}',\n    'operating_model', v_settings#>>'{business_operating_blueprint,operatingModel}',\n    'module_tenant_type', v_settings->>'module_tenant_type',\n    'applications', v_apps,\n    'enabled_application_count', v_enabled_count,\n    'authority', 'business-operating-blueprint'\n  );\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_merge_legacy boolean"},{"name":"record_business_activity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.record_business_activity(p_tenant_org_id uuid, p_activity_type text, p_title text, p_event jsonb DEFAULT '{}'::jsonb)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\ndeclare v_event jsonb;\nbegin\n  perform public.business_activity_assert_tenant_access(p_tenant_org_id);\n  v_event := coalesce(p_event,'{}'::jsonb) || jsonb_build_object('actor_user_id',auth.uid(),'is_system_generated',false,'source_system',coalesce(p_event->>'source_system','knocklaunch'));\n  return public.business_activity_project(p_tenant_org_id,p_activity_type,p_title,v_event);\nend;\n$function$\n","identity_arguments":"p_tenant_org_id uuid, p_activity_type text, p_title text, p_event jsonb"},{"name":"record_card_grading_qc","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.record_card_grading_qc(p_tenant_id uuid, p_card_id uuid, p_outcome text, p_notes text DEFAULT NULL::text)\n RETURNS uuid\n LANGUAGE plpgsql\n SET search_path TO 'public', 'private', 'auth', 'pg_temp'\nAS $function$\ndeclare\n  v_card public.card_grading_cards%rowtype;\n  v_review_id uuid;\n  v_session_id uuid;\n  v_grader_user_id uuid;\n  v_cert_number text;\nbegin\n  if auth.uid() is null or not (\n    public.is_system_admin(auth.uid())\n    or exists (\n      select 1 from public.security_active_user_tenant_memberships m\n      where m.user_id = auth.uid() and m.status = 'active' and m.tenant_id = p_tenant_id\n    )\n  ) then\n    raise exception 'Card grading workspace access required' using errcode = '42501';\n  end if;\n\n  if p_outcome not in ('approved','regrade','rework','discrepancy') then\n    raise exception 'Invalid QC outcome';\n  end if;\n\n  select * into v_card\n  from public.card_grading_cards\n  where id = p_card_id and tenant_id = p_tenant_id\n  for update;\n\n  if v_card.id is null then raise exception 'Card unavailable'; end if;\n\n  select gs.id, gs.grader_user_id\n    into v_session_id, v_grader_user_id\n  from public.card_grading_grading_sessions gs\n  where gs.tenant_id = p_tenant_id\n    and gs.card_id = p_card_id\n    and gs.status = 'submitted'\n  order by gs.submitted_at desc nulls last, gs.created_at desc\n  limit 1;\n\n  v_grader_user_id := coalesce(v_grader_user_id, auth.uid());\n\n  if p_outcome='approved' and (\n    v_card.grade is null\n    or nullif(btrim(coalesce(v_card.slab_image_url,'')),'') is null\n  ) then\n    raise exception 'QC approval requires a saved grade and final image';\n  end if;\n\n  if p_outcome='approved' then\n    v_cert_number := nullif(btrim(coalesce(v_card.cert_number,'')),'');\n    if v_cert_number is null then\n      if p_tenant_id = '9602e177-0cbb-496c-bdf5-2fbc93f1b859'::uuid then\n        raise exception 'pcg_qc_requires_existing_physical_slab_cert';\n      end if;\n      v_cert_number := private.next_card_grading_cert_number(p_tenant_id,v_grader_user_id);\n    end if;\n\n    perform public.assign_card_grading_certificate(p_tenant_id,p_card_id,v_cert_number);\n\n    update public.card_grading_cards\n       set finalized_at=coalesce(finalized_at,now()),\n           updated_at=now()\n     where id=p_card_id and tenant_id=p_tenant_id;\n\n    update public.card_grading_certificates\n       set finalized_at=coalesce(finalized_at,now()),\n           updated_at=now()\n     where card_id=p_card_id and tenant_id=p_tenant_id;\n  end if;\n\n  insert into public.card_grading_qc_reviews(\n    tenant_id, card_id, grading_session_id, reviewer_user_id, outcome, notes\n  ) values (\n    p_tenant_id, p_card_id, v_session_id, auth.uid(), p_outcome, nullif(btrim(coalesce(p_notes,'')),'')\n  ) returning id into v_review_id;\n\n  if p_outcome in ('regrade','rework','discrepancy') then\n    insert into public.card_grading_exceptions(\n      tenant_id, submission_id, card_id, kind, reason, opened_by\n    ) values (\n      p_tenant_id, v_card.submission_id, p_card_id,\n      case when p_outcome='discrepancy' then 'escalation' else 'rework' end,\n      coalesce(nullif(btrim(coalesce(p_notes,'')),''),'QC requested additional review'),\n      auth.uid()\n    );\n  end if;\n\n  insert into public.card_grading_workflow_events(\n    tenant_id, submission_id, card_id, event_type, actor_user_id, reason, metadata\n  ) values (\n    p_tenant_id, v_card.submission_id, p_card_id, 'qc_reviewed', auth.uid(),\n    nullif(btrim(coalesce(p_notes,'')),''),\n    jsonb_strip_nulls(jsonb_build_object(\n      'outcome',p_outcome,\n      'review_id',v_review_id,\n      'cert_number',v_cert_number,\n      'grader_user_id',v_grader_user_id\n    ))\n  );\n\n  return v_review_id;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_card_id uuid, p_outcome text, p_notes text"},{"name":"record_content_version","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.record_content_version(_course_id uuid, _lesson_id uuid, _content_hash text, _reason text)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_id uuid;\n  v_ver int;\nBEGIN\n  IF NOT (is_system_admin(auth.uid())) THEN\n    RAISE EXCEPTION 'Only GodMode may record content versions';\n  END IF;\n  IF _course_id IS NOT NULL THEN\n    UPDATE public.academy_courses SET version = version + 1, content_hash = COALESCE(_content_hash, content_hash), updated_at = now()\n    WHERE id = _course_id RETURNING version INTO v_ver;\n  END IF;\n  IF _lesson_id IS NOT NULL THEN\n    UPDATE public.academy_lessons SET content_hash = COALESCE(_content_hash, content_hash), updated_at = now()\n    WHERE id = _lesson_id;\n  END IF;\n  INSERT INTO public.academy_content_versions(course_id, lesson_id, version, content_hash, reason, changed_by)\n  VALUES (_course_id, _lesson_id, COALESCE(v_ver, 1), _content_hash, _reason, auth.uid())\n  RETURNING id INTO v_id;\n  RETURN v_id;\nEND;\n$function$\n","identity_arguments":"_course_id uuid, _lesson_id uuid, _content_hash text, _reason text"},{"name":"record_invoice_payment_allocation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.record_invoice_payment_allocation(p_tenant_id uuid, p_finance_transaction_id uuid, p_invoice_id uuid, p_amount numeric, p_idempotency_key text, p_actor_id uuid, p_evidence_level text DEFAULT 'owner_attested'::text)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_tx public.finance_transactions%ROWTYPE;\n  v_invoice public.invoices%ROWTYPE;\n  v_existing public.invoice_payment_allocations%ROWTYPE;\n  v_transaction_allocated numeric;\n  v_invoice_allocated numeric;\n  v_new_id uuid;\nBEGIN\n  IF coalesce(auth.role(),'') <> 'service_role' THEN\n    RAISE EXCEPTION 'invoice_allocation_service_role_required' USING ERRCODE='42501';\n  END IF;\n  IF p_tenant_id IS NULL OR p_actor_id IS NULL OR p_invoice_id IS NULL OR p_finance_transaction_id IS NULL\n    OR p_amount IS NULL OR p_amount::text = 'NaN' OR p_amount <= 0 OR p_amount <> round(p_amount,2)\n    OR p_idempotency_key IS NULL OR length(btrim(p_idempotency_key)) NOT BETWEEN 8 AND 180\n    OR p_evidence_level NOT IN ('owner_attested','bank_verified') THEN\n    RAISE EXCEPTION 'invalid_invoice_allocation_request' USING ERRCODE='22023';\n  END IF;\n  -- Consistent lock order: transaction then invoice. Concurrency cannot over-apply either.\n  SELECT * INTO v_tx FROM public.finance_transactions\n   WHERE id=p_finance_transaction_id AND tenant_id=p_tenant_id AND direction='income' FOR UPDATE;\n  IF NOT FOUND OR v_tx.amount <= 0 OR v_tx.amount::text='NaN' THEN\n    RAISE EXCEPTION 'finance_transaction_not_found_for_tenant' USING ERRCODE='42501';\n  END IF;\n  IF p_evidence_level='bank_verified'\n    AND (v_tx.source NOT IN ('sccu_csv','bank_statement','verified_bank_feed') OR v_tx.receipt_document_ref IS NULL) THEN\n    RAISE EXCEPTION 'bank_verification_evidence_required' USING ERRCODE='22023';\n  END IF;\n  SELECT * INTO v_invoice FROM public.invoices\n   WHERE id=p_invoice_id AND tenant_org_id=p_tenant_id::text\n     AND document_kind='invoice' FOR UPDATE;\n  IF NOT FOUND THEN RAISE EXCEPTION 'invoice_not_found_for_tenant' USING ERRCODE='42501'; END IF;\n  IF lower(coalesce(v_invoice.status,'')) IN ('void','cancelled') OR\n    coalesce(v_invoice.document_metadata->>'owner_invoice_archived','false')='true' OR v_invoice.amount <= 0 THEN\n    RAISE EXCEPTION 'invoice_not_eligible_for_allocation' USING ERRCODE='22023';\n  END IF;\n  SELECT * INTO v_existing FROM public.invoice_payment_allocations\n   WHERE tenant_id=p_tenant_id AND idempotency_key=p_idempotency_key LIMIT 1;\n  IF FOUND THEN\n    IF v_existing.entry_kind='allocation' AND\n       v_existing.invoice_id=p_invoice_id AND\n       v_existing.finance_transaction_id=p_finance_transaction_id AND\n       v_existing.amount=p_amount THEN\n      RETURN v_existing.id;\n    END IF;\n    RAISE EXCEPTION 'invoice_allocation_idempotency_conflict' USING ERRCODE='23505';\n  END IF;\n  SELECT coalesce(sum(CASE WHEN entry_kind='allocation' THEN amount ELSE -amount END),0)\n    INTO v_transaction_allocated FROM public.invoice_payment_allocations\n    WHERE tenant_id=p_tenant_id AND finance_transaction_id=p_finance_transaction_id;\n  SELECT coalesce(sum(CASE WHEN entry_kind='allocation' THEN amount ELSE -amount END),0)\n    INTO v_invoice_allocated FROM public.invoice_payment_allocations\n    WHERE tenant_id=p_tenant_id AND invoice_id=p_invoice_id;\n  IF (v_transaction_allocated+p_amount) > v_tx.amount OR (v_invoice_allocated+p_amount) > v_invoice.amount THEN\n    RAISE EXCEPTION 'invoice_allocation_exceeds_available_amount' USING ERRCODE='23514';\n  END IF;\n  INSERT INTO public.invoice_payment_allocations (\n    tenant_id,invoice_id,finance_transaction_id,entry_kind,amount,evidence_level,\n    idempotency_key,created_by\n  ) VALUES (p_tenant_id,p_invoice_id,p_finance_transaction_id,'allocation',\n    p_amount,p_evidence_level,p_idempotency_key,p_actor_id)\n  RETURNING id INTO v_new_id;\n  RETURN v_new_id;\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_finance_transaction_id uuid, p_invoice_id uuid, p_amount numeric, p_idempotency_key text, p_actor_id uuid, p_evidence_level text"},{"name":"record_mobile_vendor_loyalty_purchase","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.record_mobile_vendor_loyalty_purchase(_tenant_org_id uuid, _member_id uuid, _purchase_ref text, _payment_method text DEFAULT 'cash'::text, _amount_cents integer DEFAULT NULL::integer, _source text DEFAULT 'owner_action'::text, _source_transaction_id text DEFAULT NULL::text, _confirmed_by_user_id uuid DEFAULT NULL::uuid, _referral_points integer DEFAULT 100)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_purchase public.mobile_vendor_loyalty_purchases%rowtype;\n  v_visit jsonb;\n  v_ref text := nullif(btrim(coalesce(_purchase_ref, '')), '');\n  v_method text := lower(btrim(coalesce(_payment_method, 'cash')));\n  v_source text := nullif(btrim(coalesce(_source, 'owner_action')), '');\n  v_source_transaction_id text := nullif(btrim(coalesce(_source_transaction_id, '')), '');\nbegin\n  if v_ref is null then raise exception 'Purchase reference is required'; end if;\n  if v_method not in ('cash', 'square', 'other') then raise exception 'Unsupported payment method'; end if;\n  if _amount_cents is not null and _amount_cents < 0 then raise exception 'Purchase amount cannot be negative'; end if;\n  if v_source is null then v_source := 'owner_action'; end if;\n\n  select * into v_purchase\n  from public.mobile_vendor_loyalty_purchases\n  where tenant_org_id = _tenant_org_id and purchase_ref = v_ref\n  for update;\n\n  if found then\n    return jsonb_build_object(\n      'ok', true,\n      'already_recorded', true,\n      'purchase_id', v_purchase.id,\n      'purchase_ref', v_purchase.purchase_ref,\n      'payment_method', v_purchase.payment_method,\n      'occurred_at', v_purchase.occurred_at,\n      'reason', 'idempotent_replay'\n    );\n  end if;\n\n  insert into public.mobile_vendor_loyalty_purchases (\n    tenant_org_id, member_id, purchase_ref, payment_method, amount_cents, currency,\n    source, source_transaction_id, confirmed_by_user_id, status, metadata\n  ) values (\n    _tenant_org_id, _member_id, v_ref, v_method, _amount_cents, 'USD',\n    v_source, v_source_transaction_id, _confirmed_by_user_id, 'confirmed',\n    jsonb_build_object('loyalty_qualifying', true)\n  )\n  returning * into v_purchase;\n\n  v_visit := public.record_mobile_vendor_loyalty_visit(\n    _tenant_org_id,\n    _member_id,\n    v_ref,\n    _referral_points\n  );\n\n  update public.mobile_vendor_loyalty_purchases\n  set metadata = coalesce(metadata, '{}'::jsonb) || jsonb_build_object('loyalty_result', v_visit),\n      updated_at = now()\n  where id = v_purchase.id;\n\n  return jsonb_build_object(\n    'ok', true,\n    'already_recorded', false,\n    'purchase_id', v_purchase.id,\n    'purchase_ref', v_purchase.purchase_ref,\n    'payment_method', v_purchase.payment_method,\n    'occurred_at', v_purchase.occurred_at,\n    'visit', v_visit,\n    'referral_event', v_visit->>'referral_event'\n  );\nexception\n  when unique_violation then\n    select * into v_purchase\n    from public.mobile_vendor_loyalty_purchases\n    where tenant_org_id = _tenant_org_id\n      and (purchase_ref = v_ref or (v_source_transaction_id is not null and payment_method = v_method and source_transaction_id = v_source_transaction_id))\n    order by created_at asc\n    limit 1;\n    if found then\n      return jsonb_build_object(\n        'ok', true,\n        'already_recorded', true,\n        'purchase_id', v_purchase.id,\n        'purchase_ref', v_purchase.purchase_ref,\n        'payment_method', v_purchase.payment_method,\n        'occurred_at', v_purchase.occurred_at,\n        'reason', 'idempotent_replay'\n      );\n    end if;\n    raise;\nend;\n$function$\n","identity_arguments":"_tenant_org_id uuid, _member_id uuid, _purchase_ref text, _payment_method text, _amount_cents integer, _source text, _source_transaction_id text, _confirmed_by_user_id uuid, _referral_points integer"},{"name":"record_mobile_vendor_loyalty_visit","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.record_mobile_vendor_loyalty_visit(_tenant_org_id uuid, _member_id uuid, _visit_ref text DEFAULT NULL::text, _referral_points integer DEFAULT 100)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_member public.mobile_vendor_loyalty_members%rowtype;\n  v_referrer public.mobile_vendor_loyalty_members%rowtype;\n  v_referral public.mobile_vendor_loyalty_referrals%rowtype;\n  v_now timestamptz := now();\n  v_next_stamps integer;\n  v_points integer;\n  v_event text := null;\n  v_first_purchase_recorded boolean := false;\n  v_visit_ref text := nullif(btrim(coalesce(_visit_ref, '')), '');\nbegin\n  select * into v_member\n  from public.mobile_vendor_loyalty_members\n  where tenant_org_id = _tenant_org_id and id = _member_id\n  for update;\n  if not found or v_member.status <> 'active' then raise exception 'Active loyalty member not found'; end if;\n\n  if v_visit_ref is not null and exists (\n    select 1 from public.mobile_vendor_loyalty_activity\n    where tenant_org_id = _tenant_org_id and member_id = v_member.id\n      and activity_type = 'visit' and source = 'owner_action' and source_ref = v_visit_ref\n  ) then\n    return jsonb_build_object('ok', true, 'already_recorded', true, 'member_id', v_member.id, 'stamp_balance', v_member.stamp_balance, 'points_balance', v_member.points_balance, 'reason', 'idempotent_replay');\n  end if;\n\n  if v_member.last_visit_at is not null and v_member.last_visit_at > v_now - interval '30 minutes' then\n    return jsonb_build_object('ok', true, 'already_recorded', true, 'member_id', v_member.id, 'stamp_balance', v_member.stamp_balance, 'points_balance', v_member.points_balance, 'reason', 'visit_debounce');\n  end if;\n\n  v_next_stamps := coalesce(v_member.stamp_balance, 0) + 1;\n  update public.mobile_vendor_loyalty_members\n  set stamp_balance = v_next_stamps,\n      lifetime_stamps = coalesce(lifetime_stamps, 0) + 1,\n      visits = coalesce(visits, 0) + 1,\n      last_visit_at = v_now,\n      updated_at = v_now\n  where tenant_org_id = _tenant_org_id and id = v_member.id;\n\n  insert into public.mobile_vendor_loyalty_activity (\n    tenant_org_id, member_id, contact_id, activity_type, stamps_delta, balance_after,\n    points_delta, points_balance_after, source, source_ref, metadata\n  ) values (\n    _tenant_org_id, v_member.id, v_member.contact_id, 'visit', 1, v_next_stamps,\n    0, coalesce(v_member.points_balance, 0), 'owner_action', v_visit_ref, '{}'::jsonb\n  );\n\n  select * into v_referral\n  from public.mobile_vendor_loyalty_referrals\n  where tenant_org_id = _tenant_org_id and friend_member_id = v_member.id\n  order by joined_at desc limit 1 for update;\n\n  if found then\n    if v_referral.first_purchase_at is null then\n      update public.mobile_vendor_loyalty_referrals\n      set status = 'purchase_confirmed',\n          first_purchase_at = v_now,\n          first_purchase_ref = v_visit_ref,\n          first_purchase_source = 'owner_action',\n          metadata = coalesce(metadata, '{}'::jsonb) || jsonb_build_object('first_purchase_confirmed_by', 'owner_action'),\n          updated_at = v_now\n      where id = v_referral.id;\n      v_referral.first_purchase_at := v_now;\n      v_first_purchase_recorded := true;\n      v_event := 'purchase_confirmed';\n    end if;\n\n    if v_referral.referrer_points_awarded_at is null then\n      select * into v_referrer\n      from public.mobile_vendor_loyalty_members\n      where tenant_org_id = _tenant_org_id and id = v_referral.referrer_member_id\n      for update;\n      if found and v_referrer.status = 'active' and v_referrer.id <> v_member.id then\n        v_points := greatest(1, least(1000, coalesce(_referral_points, 100)));\n        update public.mobile_vendor_loyalty_members\n        set points_balance = coalesce(points_balance, 0) + v_points,\n            lifetime_points = coalesce(lifetime_points, 0) + v_points,\n            updated_at = v_now\n        where tenant_org_id = _tenant_org_id and id = v_referrer.id;\n\n        insert into public.mobile_vendor_loyalty_activity (\n          tenant_org_id, member_id, contact_id, activity_type, stamps_delta, balance_after,\n          points_delta, points_balance_after, source, source_ref, metadata\n        ) values (\n          _tenant_org_id, v_referrer.id, v_referrer.contact_id, 'referral_purchase', 0, coalesce(v_referrer.stamp_balance, 0),\n          v_points, coalesce(v_referrer.points_balance, 0) + v_points, 'bring_a_friend', v_referral.id::text,\n          jsonb_build_object('friend_member_id', v_member.id, 'first_purchase_ref', v_visit_ref)\n        );\n\n        update public.mobile_vendor_loyalty_referrals\n        set status = 'purchase_confirmed', referrer_points_awarded = v_points,\n            referrer_points_awarded_at = v_now, updated_at = v_now\n        where id = v_referral.id;\n        v_event := 'referrer_points_awarded';\n      end if;\n    end if;\n\n    if not v_first_purchase_recorded and v_referral.welcome_reward_status = 'pending_return' and v_referral.first_purchase_at is not null and v_referral.first_purchase_at < v_now then\n      update public.mobile_vendor_loyalty_referrals\n      set status = 'welcome_ready', welcome_reward_status = 'ready',\n          welcome_unlocked_at = coalesce(welcome_unlocked_at, v_now), updated_at = v_now\n      where id = v_referral.id and welcome_reward_status = 'pending_return';\n\n      if found then\n        insert into public.mobile_vendor_loyalty_activity (\n          tenant_org_id, member_id, contact_id, activity_type, stamps_delta, balance_after,\n          points_delta, points_balance_after, source, source_ref, metadata\n        ) values (\n          _tenant_org_id, v_member.id, v_member.contact_id, 'welcome_reward_unlocked', 0, v_next_stamps,\n          0, coalesce(v_member.points_balance, 0), 'bring_a_friend', v_referral.id::text,\n          jsonb_build_object('reward', 'free_size_upgrade')\n        );\n        v_event := 'welcome_reward_unlocked';\n      end if;\n    end if;\n  end if;\n\n  return jsonb_build_object('ok', true, 'already_recorded', false, 'member_id', v_member.id,\n    'stamp_balance', v_next_stamps, 'points_balance', coalesce(v_member.points_balance, 0), 'referral_event', v_event);\nend;\n$function$\n","identity_arguments":"_tenant_org_id uuid, _member_id uuid, _visit_ref text, _referral_points integer"},{"name":"record_score_change","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.record_score_change()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF OLD.lead_score IS DISTINCT FROM NEW.lead_score THEN\n    INSERT INTO public.lead_score_history (\n      contact_id, tenant_org_id, previous_score, new_score,\n      score_type, change_reason, factors\n    ) VALUES (\n      NEW.id, NEW.tenant_org_id::uuid, OLD.lead_score, NEW.lead_score,\n      'total', 'Score recalculation',\n      jsonb_build_object(\n        'quality_score', NEW.quality_score,\n        'engagement_score', NEW.engagement_score,\n        'recency_score', NEW.recency_score\n      )\n    );\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"redeem_mobile_vendor_loyalty_reward","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.redeem_mobile_vendor_loyalty_reward(_tenant_org_id uuid, _member_id uuid, _milestone integer, _reward_label text, _redemption_ref text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_member public.mobile_vendor_loyalty_members%rowtype;\n  v_ref text := nullif(btrim(coalesce(_redemption_ref, '')), '');\n  v_milestone integer := greatest(2, least(20, coalesce(_milestone, 10)));\n  v_next integer;\n  v_now timestamptz := now();\nbegin\n  if v_ref is null then raise exception 'Redemption reference required'; end if;\n  select * into v_member from public.mobile_vendor_loyalty_members\n  where tenant_org_id = _tenant_org_id and id = _member_id for update;\n  if not found then raise exception 'Loyalty member not found'; end if;\n  if v_member.status <> 'active' then raise exception 'Loyalty membership is not active'; end if;\n\n  if exists (select 1 from public.mobile_vendor_loyalty_activity where tenant_org_id = _tenant_org_id and member_id = v_member.id and activity_type = 'reward_redeemed' and source = 'owner_action' and source_ref = v_ref) then\n    return jsonb_build_object('ok', true, 'already_redeemed', true, 'member_id', v_member.id, 'stamp_balance', v_member.stamp_balance);\n  end if;\n\n  v_next := coalesce(v_member.stamp_balance, 0) - v_milestone;\n  if v_next < 0 then raise exception 'Loyalty reward is not ready'; end if;\n\n  update public.mobile_vendor_loyalty_members\n  set stamp_balance = v_next, rewards_redeemed = coalesce(rewards_redeemed, 0) + 1, updated_at = v_now\n  where tenant_org_id = _tenant_org_id and id = v_member.id;\n\n  insert into public.mobile_vendor_loyalty_activity (\n    tenant_org_id, member_id, contact_id, activity_type, stamps_delta, balance_after,\n    points_delta, points_balance_after, source, source_ref, metadata\n  ) values (\n    _tenant_org_id, v_member.id, v_member.contact_id, 'reward_redeemed', -v_milestone, v_next,\n    0, coalesce(v_member.points_balance, 0), 'owner_action', v_ref,\n    jsonb_build_object('reward_label', coalesce(nullif(btrim(_reward_label), ''), 'Loyalty reward'))\n  );\n  return jsonb_build_object('ok', true, 'already_redeemed', false, 'member_id', v_member.id, 'stamp_balance', v_next);\nend;\n$function$\n","identity_arguments":"_tenant_org_id uuid, _member_id uuid, _milestone integer, _reward_label text, _redemption_ref text"},{"name":"redeem_mobile_vendor_referral_welcome_reward","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.redeem_mobile_vendor_referral_welcome_reward(_tenant_org_id uuid, _referral_id uuid, _redemption_ref text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_referral public.mobile_vendor_loyalty_referrals%rowtype;\n  v_member public.mobile_vendor_loyalty_members%rowtype;\n  v_now timestamptz := now();\n  v_ref text := nullif(btrim(coalesce(_redemption_ref, '')), '');\nbegin\n  if v_ref is null then raise exception 'Redemption reference required'; end if;\n  select * into v_referral from public.mobile_vendor_loyalty_referrals\n  where tenant_org_id = _tenant_org_id and id = _referral_id for update;\n  if not found then raise exception 'Referral reward not found'; end if;\n  if v_referral.welcome_reward_status = 'redeemed' then\n    return jsonb_build_object('ok', true, 'already_redeemed', true, 'referral_id', v_referral.id, 'member_id', v_referral.friend_member_id);\n  end if;\n  if v_referral.welcome_reward_status <> 'ready' then raise exception 'Referral welcome reward is not ready'; end if;\n\n  select * into v_member from public.mobile_vendor_loyalty_members\n  where tenant_org_id = _tenant_org_id and id = v_referral.friend_member_id for update;\n  if not found then raise exception 'Loyalty member not found'; end if;\n\n  update public.mobile_vendor_loyalty_referrals\n  set status = 'completed', welcome_reward_status = 'redeemed', welcome_redeemed_at = v_now,\n      metadata = coalesce(metadata, '{}'::jsonb) || jsonb_build_object('welcome_redemption_ref', v_ref), updated_at = v_now\n  where id = v_referral.id;\n\n  insert into public.mobile_vendor_loyalty_activity (\n    tenant_org_id, member_id, contact_id, activity_type, stamps_delta, balance_after,\n    points_delta, points_balance_after, source, source_ref, metadata\n  ) values (\n    _tenant_org_id, v_member.id, v_member.contact_id, 'welcome_reward_redeemed', 0, coalesce(v_member.stamp_balance, 0),\n    0, coalesce(v_member.points_balance, 0), 'bring_a_friend', v_ref,\n    jsonb_build_object('referral_id', v_referral.id, 'reward', 'free_size_upgrade')\n  );\n  return jsonb_build_object('ok', true, 'already_redeemed', false, 'referral_id', v_referral.id, 'member_id', v_member.id);\nend;\n$function$\n","identity_arguments":"_tenant_org_id uuid, _referral_id uuid, _redemption_ref text"},{"name":"refresh_onboarding_readiness","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.refresh_onboarding_readiness(p_session_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE s public.onboarding_sessions%rowtype; v_missing jsonb:='[]'::jsonb; v_pending int:=0; v_owner_review int:=0; v_operator_review int:=0; v_failed int:=0; v_result jsonb; v_status text; v_type text; v_model text;\nBEGIN\n  SELECT * INTO s FROM public.onboarding_sessions WHERE id=p_session_id; IF NOT FOUND THEN RAISE EXCEPTION 'Onboarding session not found'; END IF;\n  IF coalesce(auth.role(),'')<>'service_role' AND (auth.uid() IS NULL OR (s.owner_user_id IS DISTINCT FROM auth.uid() AND NOT public.is_system_admin(auth.uid()))) THEN RAISE EXCEPTION 'Not authorized for this onboarding session' USING ERRCODE='42501'; END IF;\n  v_type:=public.normalize_declared_business_type(s.requested_business_type); IF v_type IS NULL THEN v_missing:=v_missing||jsonb_build_array('business_type'); END IF;\n  v_model:=public.tenant_operating_model_for(v_type,jsonb_build_object('operating_model',coalesce(s.intake_answers->>'operating_model',''))); IF v_type IS NOT NULL AND v_model IS NULL THEN v_missing:=v_missing||jsonb_build_array('operating_model'); END IF;\n  IF coalesce(s.company_name,'')='' THEN v_missing:=v_missing||jsonb_build_array('company_name'); END IF; IF cardinality(s.operating_states)=0 THEN v_missing:=v_missing||jsonb_build_array('operating_states'); END IF; IF coalesce(s.service_area->>'mode','')='' THEN v_missing:=v_missing||jsonb_build_array('service_area'); END IF;\n  SELECT count(*) INTO v_pending FROM public.onboarding_research_tasks WHERE session_id=p_session_id AND status IN ('pending','running'); SELECT count(*) INTO v_owner_review FROM public.onboarding_research_tasks WHERE session_id=p_session_id AND status IN ('needs_review','not_found') AND coalesce((result->>'owner_input_required')::boolean,false)=true; SELECT count(*) INTO v_operator_review FROM public.onboarding_research_tasks WHERE session_id=p_session_id AND status IN ('needs_review','not_found') AND coalesce((result->>'owner_input_required')::boolean,false)=false; SELECT count(*) INTO v_failed FROM public.onboarding_research_tasks WHERE session_id=p_session_id AND status='failed';\n  IF v_owner_review>0 THEN v_missing:=v_missing||jsonb_build_array('owner_verification_input'); END IF;\n  v_status:=CASE WHEN jsonb_array_length(v_missing)>0 THEN 'needs_input' WHEN v_pending>0 THEN 'researching' WHEN v_operator_review>0 OR v_failed>0 THEN 'validating' WHEN s.status IN ('provisioning','ready','live') THEN s.status ELSE 'ready_to_provision' END;\n  v_result:=jsonb_build_object('missing',v_missing,'research_pending',v_pending,'owner_input_required',v_owner_review,'operator_review',v_operator_review,'research_failed',v_failed,'ready',jsonb_array_length(v_missing)=0 AND v_pending=0,'declared_business_type',v_type,'operating_model',v_model); UPDATE public.onboarding_sessions SET canonical_tenant_type=v_type,readiness=v_result,status=v_status,updated_at=now() WHERE id=p_session_id; RETURN v_result;\nEND;\n$function$\n","identity_arguments":"p_session_id uuid"},{"name":"refresh_owner_receivable_payment_rollup","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.refresh_owner_receivable_payment_rollup(p_receivable_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_paid numeric(14,2); v_last timestamptz; v_target numeric(14,2);\n  v_invoice uuid; v_start date; v_end date;\nbegin\n  select coalesce(sum(amount),0),max(occurred_at) into v_paid,v_last\n  from public.owner_receivable_events\n  where receivable_id=p_receivable_id and event_type='payment_received';\n\n  select case when earned_amount>0 then earned_amount else expected_amount end,\n         invoice_record_id,service_period_start,service_period_end\n  into v_target,v_invoice,v_start,v_end\n  from public.owner_receivables where id=p_receivable_id;\n\n  update public.owner_receivables set\n    paid_amount=v_paid,\n    paid_at=case when v_paid>0 then v_last else null end,\n    stage=case\n      when coalesce(v_target,0)>0 and v_paid>=v_target then 'paid'\n      when v_paid>0 then 'partially_paid'\n      when stage in ('paid','partially_paid') then 'expected'\n      else stage end,\n    next_action=case when coalesce(v_target,0)>0 and v_paid>=v_target then null else next_action end,\n    next_action_due_at=case when coalesce(v_target,0)>0 and v_paid>=v_target then null else next_action_due_at end,\n    updated_at=now()\n  where id=p_receivable_id;\n\n  if v_invoice is not null then\n    update public.invoices set\n      status=case when coalesce(v_target,0)>0 and v_paid>=v_target then 'paid' when v_paid>0 then 'sent' else status end,\n      paid_at=case when coalesce(v_target,0)>0 and v_paid>=v_target then v_last else paid_at end,\n      document_metadata=coalesce(document_metadata,'{}'::jsonb)||jsonb_build_object(\n        'owner_receivable_id',p_receivable_id,\n        'applied_payment_amount',v_paid,\n        'service_period_start',v_start,\n        'service_period_end',v_end\n      ),\n      updated_at=now()\n    where id=v_invoice;\n  end if;\nend $function$\n","identity_arguments":"p_receivable_id uuid"},{"name":"refresh_owner_relationship_next_action","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.refresh_owner_relationship_next_action()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$ declare v_relationship_id uuid; v_next record; begin if tg_op = 'DELETE' then v_relationship_id := old.relationship_id; else v_relationship_id := new.relationship_id; end if; select f.title, f.due_at into v_next from public.owner_relationship_followups f where f.relationship_id = v_relationship_id and f.status in ('open','snoozed') order by f.due_at asc, f.created_at asc limit 1; update public.owner_tenant_relationships r set next_action = v_next.title, next_action_due_at = v_next.due_at, updated_at = now() where r.id = v_relationship_id; if tg_op = 'DELETE' then return old; end if; return new; end; $function$\n","identity_arguments":""},{"name":"register_platform_message_attachment","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.register_platform_message_attachment(p_message_id uuid, p_storage_path text, p_file_name text, p_mime_type text, p_size_bytes bigint)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  conv uuid;\n  result uuid;\n  expected_prefix text;\nbegin\n  select conversation_id into conv from public.messages where id=p_message_id and sender_id=auth.uid();\n  if conv is null or not public.can_access_message_conversation(conv,auth.uid()) then raise exception 'message_attachment_access_denied'; end if;\n  expected_prefix := 'messages/' || conv::text || '/' || auth.uid()::text || '/';\n  if left(p_storage_path,length(expected_prefix))<>expected_prefix then raise exception 'message_attachment_path_invalid'; end if;\n  if coalesce(p_size_bytes,0)<0 or p_size_bytes>15728640 then raise exception 'message_attachment_too_large'; end if;\n  insert into public.message_attachments(message_id,conversation_id,uploader_id,storage_path,file_name,mime_type,size_bytes)\n  values(p_message_id,conv,auth.uid(),p_storage_path,left(coalesce(p_file_name,'attachment'),240),left(coalesce(p_mime_type,'application/octet-stream'),160),p_size_bytes)\n  returning id into result;\n  insert into public.message_user_events(user_id,conversation_id,event_type)\n    select user_id,conv,'attachment_added' from public.message_conversation_members where conversation_id=conv;\n  return result;\nend;\n$function$\n","identity_arguments":"p_message_id uuid, p_storage_path text, p_file_name text, p_mime_type text, p_size_bytes bigint"},{"name":"register_platform_message_attachment_v2","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.register_platform_message_attachment_v2(p_message_id uuid, p_storage_path text, p_encrypted_metadata text, p_encryption_nonce text, p_key_version integer, p_size_bytes bigint)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare conv uuid; result uuid; expected_prefix text;\nbegin\n  select conversation_id into conv from public.messages where id=p_message_id and sender_id=auth.uid();\n  if conv is null or not public.can_access_message_conversation(conv,auth.uid()) then raise exception 'message_attachment_access_denied'; end if;\n  expected_prefix := 'messages/'||conv::text||'/'||auth.uid()::text||'/';\n  if left(p_storage_path,length(expected_prefix))<>expected_prefix then raise exception 'message_attachment_path_invalid'; end if;\n  if coalesce(p_size_bytes,0)<0 or p_size_bytes>15728640 then raise exception 'message_attachment_too_large'; end if;\n  insert into public.message_attachments(message_id,conversation_id,uploader_id,storage_path,file_name,mime_type,size_bytes,encrypted_metadata,encryption_nonce,key_version)\n  values(p_message_id,conv,auth.uid(),p_storage_path,'Encrypted attachment','application/octet-stream',p_size_bytes,p_encrypted_metadata,p_encryption_nonce,p_key_version)\n  returning id into result;\n  return result;\nend;\n$function$\n","identity_arguments":"p_message_id uuid, p_storage_path text, p_encrypted_metadata text, p_encryption_nonce text, p_key_version integer, p_size_bytes bigint"},{"name":"register_platform_message_device","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.register_platform_message_device(p_device_id text, p_public_key jsonb, p_label text DEFAULT NULL::text)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if auth.uid() is null then raise exception 'authentication_required'; end if;\n  if length(trim(coalesce(p_device_id,'')))<8 or jsonb_typeof(p_public_key)<>'object' then raise exception 'invalid_message_device'; end if;\n  insert into public.message_device_keys(user_id,device_id,public_key,label,last_seen_at,revoked_at)\n  values(auth.uid(),left(trim(p_device_id),160),p_public_key,left(trim(coalesce(p_label,'')),120),now(),null)\n  on conflict(user_id,device_id) do update set public_key=excluded.public_key,label=excluded.label,last_seen_at=now(),revoked_at=null;\n  update public.message_conversations c set key_rotation_required=true\n  where exists(select 1 from public.message_conversation_members m where m.conversation_id=c.id and m.user_id=auth.uid());\nend;\n$function$\n","identity_arguments":"p_device_id text, p_public_key jsonb, p_label text"},{"name":"reject_platform_business_event_mutation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.reject_platform_business_event_mutation()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nbegin\n  raise exception 'Business history is append-only; write a correction event instead';\nend;\n$function$\n","identity_arguments":""},{"name":"remove_pcg_demo_data","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.remove_pcg_demo_data(p_tenant_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$declare v_tasks int:=0;v_cards int:=0;v_submissions int:=0;v_opportunities int:=0;begin if not(is_tenant_member(auth.uid(),p_tenant_id) or is_system_admin(auth.uid())) then raise exception 'tenant access required';end if;delete from public.pcg_growth_tasks where tenant_id=p_tenant_id and is_demo=true;get diagnostics v_tasks=row_count;delete from public.card_grading_cards where tenant_id=p_tenant_id and is_demo=true;get diagnostics v_cards=row_count;delete from public.card_grading_submissions where tenant_id=p_tenant_id and is_demo=true;get diagnostics v_submissions=row_count;delete from public.opportunity_radar_opportunities where tenant_id=p_tenant_id and coalesce((metadata->>'demo')::boolean,false)=true;get diagnostics v_opportunities=row_count;return jsonb_build_object('tasks',v_tasks,'cards',v_cards,'submissions',v_submissions,'opportunities',v_opportunities);end$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"remove_platform_message_group_member","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.remove_platform_message_group_member(p_conversation_id uuid, p_user_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare target_role text;\nbegin\n  if not public.can_manage_message_group(p_conversation_id,auth.uid()) then raise exception 'group_manage_denied'; end if;\n  select role into target_role from public.message_conversation_members where conversation_id=p_conversation_id and user_id=p_user_id;\n  if target_role='owner' and (select count(*) from public.message_conversation_members where conversation_id=p_conversation_id and role='owner')<=1 then raise exception 'group_requires_owner'; end if;\n  delete from public.message_conversation_members where conversation_id=p_conversation_id and user_id=p_user_id;\n  update public.message_conversations set key_rotation_required=true,updated_at=now() where id=p_conversation_id;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_user_id uuid"},{"name":"rename_platform_message_folder","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.rename_platform_message_folder(p_folder_id uuid, p_name text)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  update public.message_folders set name=left(trim(p_name),80),updated_at=now() where id=p_folder_id and user_id=auth.uid();\n  if not found then raise exception 'folder_not_found'; end if;\nend;\n$function$\n","identity_arguments":"p_folder_id uuid, p_name text"},{"name":"rename_platform_message_group","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.rename_platform_message_group(p_conversation_id uuid, p_title text)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if not public.can_manage_message_group(p_conversation_id,auth.uid()) then raise exception 'group_manage_denied'; end if;\n  update public.message_conversations set title=nullif(left(trim(coalesce(p_title,'')),120),''),updated_at=now() where id=p_conversation_id;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_title text"},{"name":"request_user_id","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.request_user_id()\n RETURNS uuid\n LANGUAGE plpgsql\n STABLE\n SET search_path TO ''\nAS $function$\ndeclare\n  v_sub text := nullif(current_setting('request.jwt.claim.sub', true), '');\n  v_claims text;\nbegin\n  if v_sub is null then\n    v_claims := nullif(current_setting('request.jwt.claims', true), '');\n    if v_claims is not null then\n      v_sub := nullif((v_claims::jsonb) ->> 'sub', '');\n    end if;\n  end if;\n\n  if v_sub is null then\n    return null;\n  end if;\n\n  begin\n    return v_sub::uuid;\n  exception\n    when invalid_text_representation then\n      return null;\n  end;\nend;\n$function$\n","identity_arguments":""},{"name":"require_platform_operator","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.require_platform_operator()\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_role text := nullif(current_setting('request.jwt.claim.role', true), '');\n  v_claims text;\nbegin\n  if v_role is null then\n    v_claims := nullif(current_setting('request.jwt.claims', true), '');\n    if v_claims is not null then\n      v_role := nullif((v_claims::jsonb) ->> 'role', '');\n    end if;\n  end if;\n\n  if coalesce(v_role, '') = 'service_role' then\n    return;\n  end if;\n\n  if public.request_user_id() is null\n     or not coalesce(public.is_platform_admin(public.request_user_id()), false) then\n    raise exception 'platform administrator authorization required'\n      using errcode = '42501';\n  end if;\nend;\n$function$\n","identity_arguments":""},{"name":"reserve_big_papis_proposal_number","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.reserve_big_papis_proposal_number(p_tenant_id uuid, p_year integer)\n RETURNS text\n LANGUAGE sql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  SELECT public.reserve_proposal_number(p_tenant_id, 'BP', p_year);\n$function$\n","identity_arguments":"p_tenant_id uuid, p_year integer"},{"name":"reserve_proposal_number","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.reserve_proposal_number(p_tenant_id uuid, p_prefix text, p_year integer)\n RETURNS text\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare v_prefix text; v_next integer;\nbegin\n  v_prefix:=upper(regexp_replace(trim(coalesce(p_prefix,'')),'[^A-Z0-9]','','g'));\n  if v_prefix='' or length(v_prefix)>12 then raise exception 'invalid_proposal_prefix' using errcode='22023'; end if;\n  if p_year<2000 or p_year>2200 then raise exception 'invalid_proposal_year' using errcode='22023'; end if;\n  if coalesce(auth.role(),'')<>'service_role' and (auth.uid() is null or not public.is_tenant_member(auth.uid(),p_tenant_id)) then raise exception 'tenant_access_denied' using errcode='42501'; end if;\n  insert into public.proposal_sequences(tenant_id,proposal_year,number_prefix,last_sequence,updated_at)\n  values(p_tenant_id,p_year,v_prefix,1,now())\n  on conflict(tenant_id,proposal_year,number_prefix) do update set last_sequence=public.proposal_sequences.last_sequence+1,updated_at=now()\n  returning last_sequence into v_next;\n  return format('%s-%s-%s',v_prefix,p_year,lpad(v_next::text,3,'0'));\nend; $function$\n","identity_arguments":"p_tenant_id uuid, p_prefix text, p_year integer"},{"name":"reset_test_contact_to_workflow","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.reset_test_contact_to_workflow(p_contact_id uuid)\n RETURNS TABLE(id uuid, status text, contact_status text, graduated_at timestamp with time zone, archived_at timestamp with time zone, is_test_account boolean)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_tenant uuid;\n  v_is_test boolean;\n  v_caller uuid := auth.uid();\nBEGIN\n  IF v_caller IS NULL THEN\n    RAISE EXCEPTION 'not_authenticated' USING ERRCODE = '42501';\n  END IF;\n\n  SELECT uc.tenant_org_id, uc.is_test_account\n    INTO v_tenant, v_is_test\n  FROM public.unified_contacts uc\n  WHERE uc.id = p_contact_id;\n\n  IF v_tenant IS NULL THEN\n    RAISE EXCEPTION 'contact_not_found' USING ERRCODE = 'P0002';\n  END IF;\n\n  IF COALESCE(v_is_test, false) = false THEN\n    RAISE EXCEPTION 'not_a_test_contact' USING ERRCODE = '42501';\n  END IF;\n\n  -- Authorization: must be system admin OR manager+ in this tenant.\n  IF NOT (\n    public.is_system_admin()\n    OR public.is_manager_or_higher(v_caller, v_tenant)\n  ) THEN\n    RAISE EXCEPTION 'insufficient_privileges' USING ERRCODE = '42501';\n  END IF;\n\n  RETURN QUERY\n  UPDATE public.unified_contacts uc\n     SET graduated_at = NULL,\n         archived_at  = NULL,\n         status         = 'New',\n         contact_status = 'New',\n         lead_stage     = 'New / Unassigned',\n         updated_at     = now()\n   WHERE uc.id = p_contact_id\n     AND uc.is_test_account = true\n  RETURNING uc.id, uc.status, uc.contact_status, uc.graduated_at, uc.archived_at, uc.is_test_account;\nEND;\n$function$\n","identity_arguments":"p_contact_id uuid"},{"name":"resolve_approved_oauth_authorization_redirect","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.resolve_approved_oauth_authorization_redirect(p_authorization_id text)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_row record;\nbegin\n  if auth.uid() is null then\n    return null;\n  end if;\n\n  select a.redirect_uri, a.authorization_code, a.state, a.expires_at\n    into v_row\n  from auth.oauth_authorizations a\n  where a.authorization_id = p_authorization_id\n    and a.user_id = auth.uid()\n    and a.status::text = 'approved'\n    and a.authorization_code is not null\n    and a.expires_at > now()\n  limit 1;\n\n  if not found then\n    return null;\n  end if;\n\n  return jsonb_build_object(\n    'redirect_uri', v_row.redirect_uri,\n    'authorization_code', v_row.authorization_code,\n    'state', v_row.state,\n    'expires_at', v_row.expires_at\n  );\nend;\n$function$\n","identity_arguments":"p_authorization_id text"},{"name":"resolve_command_center_tenant_reference","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.resolve_command_center_tenant_reference(_tenant_ref text)\n RETURNS TABLE(tenant_id uuid, tenant_name text, company_slug text, confidence double precision, match_kind text)\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'extensions', 'pg_catalog'\nAS $function$\nwith input as (\n  select\n    trim(coalesce(_tenant_ref,'')) raw_ref,\n    public.command_center_normalize_tenant_ref(_tenant_ref) norm_ref,\n    replace(public.command_center_normalize_tenant_ref(_tenant_ref),' ','') compact_ref,\n    public.command_center_tenant_acronym(_tenant_ref) acronym_ref\n),\nalias_candidates as (\n  select\n    t.id tenant_id,\n    t.name tenant_name,\n    t.company_slug,\n    case\n      when a.normalized_alias = i.norm_ref then 0.998\n      when length(a.normalized_alias) >= 3\n        and strpos(' ' || i.norm_ref || ' ', ' ' || a.normalized_alias || ' ') > 0 then 0.992\n      else least(0.93, 0.52 + 0.40 * extensions.similarity(a.normalized_alias, i.norm_ref))\n    end confidence,\n    case\n      when a.normalized_alias = i.norm_ref then 'learned_alias_exact'\n      when length(a.normalized_alias) >= 3\n        and strpos(' ' || i.norm_ref || ' ', ' ' || a.normalized_alias || ' ') > 0 then 'learned_alias_phrase'\n      else 'learned_alias_fuzzy'\n    end match_kind\n  from input i\n  join public.command_center_tenant_aliases a\n    on i.norm_ref <> ''\n   and (\n     a.normalized_alias = i.norm_ref\n     or (\n       length(a.normalized_alias) >= 3\n       and strpos(' ' || i.norm_ref || ' ', ' ' || a.normalized_alias || ' ') > 0\n     )\n     or extensions.similarity(a.normalized_alias, i.norm_ref) >= 0.55\n   )\n  join public.tenants t on t.id = a.tenant_id\n  where coalesce(t.status,'active') = 'active'\n),\ntenant_base as (\n  select\n    t.id,\n    t.name,\n    t.company_slug,\n    public.command_center_normalize_tenant_ref(t.name) norm_name,\n    public.command_center_normalize_tenant_ref(t.company_slug) norm_slug,\n    replace(public.command_center_normalize_tenant_ref(t.name),' ','') compact_name,\n    replace(public.command_center_normalize_tenant_ref(t.company_slug),' ','') compact_slug,\n    public.command_center_tenant_acronym(t.name) acronym_name,\n    public.command_center_tenant_acronym(t.company_slug) acronym_slug\n  from public.tenants t\n  where coalesce(t.status,'active') = 'active'\n),\nscored as (\n  select\n    t.id tenant_id,\n    t.name tenant_name,\n    t.company_slug,\n    best.confidence,\n    best.match_kind\n  from input i\n  join tenant_base t on i.norm_ref <> ''\n  cross join lateral (\n    select v.confidence, v.match_kind\n    from (values\n      (case when t.id::text = i.raw_ref then 1.0 else 0.0 end, 'exact_id'::text),\n      (case when i.norm_ref = t.norm_name then 0.997 else 0.0 end, 'exact_name'::text),\n      (case when i.norm_ref = t.norm_slug then 0.996 else 0.0 end, 'exact_slug'::text),\n      (case when i.compact_ref <> '' and (i.compact_ref = t.compact_name or i.compact_ref = t.compact_slug) then 0.992 else 0.0 end, 'normalized_exact'::text),\n      (case when length(i.norm_ref) >= 3 and (t.norm_name like i.norm_ref || ' %' or t.norm_slug like i.norm_ref || ' %') then 0.968 else 0.0 end, 'name_prefix'::text),\n      (case when length(i.compact_ref) >= 4 and (t.compact_name like i.compact_ref || '%' or t.compact_slug like i.compact_ref || '%') then 0.958 else 0.0 end, 'compact_prefix'::text),\n      (case when length(i.acronym_ref) >= 2 and (i.acronym_ref = t.acronym_name or i.acronym_ref = t.acronym_slug) then 0.965 else 0.0 end, 'acronym_exact'::text),\n      (case when length(i.acronym_ref) >= 3 and greatest(length(t.acronym_name), length(t.acronym_slug)) >= 3 and least(\n        case when t.acronym_name = '' then 99 else extensions.levenshtein(i.acronym_ref,t.acronym_name) end,\n        case when t.acronym_slug = '' then 99 else extensions.levenshtein(i.acronym_ref,t.acronym_slug) end\n      ) <= 1 then 0.925 else 0.0 end, 'acronym_one_edit'::text),\n      (least(0.94, 0.50 + 0.44 * greatest(\n        extensions.word_similarity(i.norm_ref,t.norm_name),\n        extensions.word_similarity(i.norm_ref,t.norm_slug),\n        extensions.word_similarity(t.norm_name,i.norm_ref),\n        extensions.word_similarity(t.norm_slug,i.norm_ref)\n      )), 'word_similarity'::text),\n      (least(0.90, 0.46 + 0.42 * greatest(\n        extensions.similarity(i.norm_ref,t.norm_name),\n        extensions.similarity(i.norm_ref,t.norm_slug),\n        extensions.similarity(i.compact_ref,t.compact_name),\n        extensions.similarity(i.compact_ref,t.compact_slug)\n      )), 'trigram_similarity'::text)\n    ) v(confidence,match_kind)\n    order by v.confidence desc\n    limit 1\n  ) best\n  where best.confidence >= 0.55\n),\ncombined as (\n  select * from alias_candidates\n  union all\n  select * from scored\n),\ndeduped as (\n  select distinct on (tenant_id)\n    tenant_id,\n    tenant_name,\n    company_slug,\n    confidence,\n    match_kind\n  from combined\n  order by tenant_id, confidence desc\n)\nselect tenant_id, tenant_name, company_slug, confidence, match_kind\nfrom deduped\norder by confidence desc, tenant_name asc\nlimit 5;\n$function$\n","identity_arguments":"_tenant_ref text"},{"name":"resolve_console_tenant_context","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.resolve_console_tenant_context(_tenant_ref text)\n RETURNS TABLE(tenant_id uuid, tenant_name text, company_slug text, confidence double precision, match_kind text)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO ''\nAS $function$\nbegin\n  if auth.uid() is null or not public.is_system_admin(auth.uid()) then\n    raise exception 'Platform owner required' using errcode = '42501';\n  end if;\n\n  return query\n  select\n    resolved.tenant_id,\n    resolved.tenant_name,\n    resolved.company_slug,\n    resolved.confidence,\n    resolved.match_kind\n  from public.resolve_command_center_tenant_reference(_tenant_ref) as resolved;\nend;\n$function$\n","identity_arguments":"_tenant_ref text"},{"name":"resolve_platform_message_tenant_context","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.resolve_platform_message_tenant_context(p_route_path text DEFAULT NULL::text, p_cached_tenant_id uuid DEFAULT NULL::uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  caller uuid := auth.uid();\n  route_slug text;\n  selected public.tenants%rowtype;\nbegin\n  if caller is null then return null; end if;\n  route_slug := lower(split_part(trim(both '/' from coalesce(p_route_path,'')), '/', 1));\n  if route_slug <> '' then\n    select t.* into selected\n    from public.tenants t\n    where lower(coalesce(t.company_slug,'')) = route_slug\n      and public.is_active_message_tenant_member(t.id, caller)\n    limit 1;\n  end if;\n  if selected.id is null and p_cached_tenant_id is not null\n     and public.is_active_message_tenant_member(p_cached_tenant_id, caller) then\n    select t.* into selected from public.tenants t where t.id = p_cached_tenant_id limit 1;\n  end if;\n  if selected.id is null then return null; end if;\n  return jsonb_build_object(\n    'id', selected.id,\n    'name', coalesce(selected.company_dba_name, selected.company_legal_name, selected.name, 'Workspace'),\n    'slug', selected.company_slug\n  );\nend;\n$function$\n","identity_arguments":"p_route_path text, p_cached_tenant_id uuid"},{"name":"retry_member_academy_onboarding","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.retry_member_academy_onboarding(p_user_id uuid, p_tenant_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_uid uuid := auth.uid();\nbegin\n  if v_uid is null then raise exception 'Authentication required' using errcode='42501'; end if;\n  if not (\n    public.is_system_admin(v_uid)\n    or public.is_tenant_owner_or_admin(v_uid,p_tenant_id)\n    or public.is_manager_or_higher(v_uid,p_tenant_id)\n    or (v_uid=p_user_id and public.is_tenant_member(v_uid,p_tenant_id))\n  ) then\n    raise exception 'Not authorized to retry Academy onboarding' using errcode='42501';\n  end if;\n  return public.ensure_academy_onboarding_for_member(p_user_id,p_tenant_id,v_uid);\nend;\n$function$\n","identity_arguments":"p_user_id uuid, p_tenant_id uuid"},{"name":"reverse_invoice_payment_allocation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.reverse_invoice_payment_allocation(p_tenant_id uuid, p_original_allocation_id uuid, p_idempotency_key text, p_reason text, p_actor_id uuid)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_original public.invoice_payment_allocations%ROWTYPE;\n  v_existing public.invoice_payment_allocations%ROWTYPE;\n  v_id uuid;\nBEGIN\n  IF coalesce(auth.role(),'') <> 'service_role' THEN\n    RAISE EXCEPTION 'invoice_allocation_service_role_required' USING ERRCODE='42501';\n  END IF;\n  IF p_tenant_id IS NULL OR p_actor_id IS NULL OR p_original_allocation_id IS NULL OR\n     p_idempotency_key IS NULL OR length(btrim(p_idempotency_key)) NOT BETWEEN 8 AND 180 OR\n     p_reason IS NULL OR length(btrim(p_reason)) < 8 THEN\n    RAISE EXCEPTION 'invoice_allocation_reversal_reason_required' USING ERRCODE='22023';\n  END IF;\n  SELECT * INTO v_original FROM public.invoice_payment_allocations\n    WHERE id=p_original_allocation_id AND tenant_id=p_tenant_id AND entry_kind='allocation';\n  IF NOT FOUND THEN\n    RAISE EXCEPTION 'invoice_allocation_not_found_for_tenant' USING ERRCODE='42501';\n  END IF;\n  -- Lock the same rows in the same order as allocation; reversal restores both capacities.\n  PERFORM 1 FROM public.finance_transactions WHERE id=v_original.finance_transaction_id\n    AND tenant_id=p_tenant_id FOR UPDATE;\n  IF NOT FOUND THEN RAISE EXCEPTION 'finance_transaction_not_found_for_tenant' USING ERRCODE='42501'; END IF;\n  PERFORM 1 FROM public.invoices WHERE id=v_original.invoice_id\n    AND tenant_org_id=p_tenant_id::text FOR UPDATE;\n  IF NOT FOUND THEN RAISE EXCEPTION 'invoice_not_found_for_tenant' USING ERRCODE='42501'; END IF;\n  SELECT * INTO v_existing FROM public.invoice_payment_allocations\n    WHERE tenant_id=p_tenant_id AND idempotency_key=p_idempotency_key;\n  IF FOUND THEN\n    IF v_existing.entry_kind='reversal' AND v_existing.reverses_allocation_id=p_original_allocation_id\n      THEN RETURN v_existing.id;\n    END IF;\n    RAISE EXCEPTION 'invoice_allocation_idempotency_conflict' USING ERRCODE='23505';\n  END IF;\n  IF EXISTS(SELECT 1 FROM public.invoice_payment_allocations\n    WHERE reverses_allocation_id=p_original_allocation_id AND entry_kind='reversal') THEN\n    RAISE EXCEPTION 'invoice_allocation_already_reversed' USING ERRCODE='23505';\n  END IF;\n  INSERT INTO public.invoice_payment_allocations (\n    tenant_id,invoice_id,finance_transaction_id,entry_kind,amount,evidence_level,\n    idempotency_key,reverses_allocation_id,reason,created_by\n  ) VALUES (p_tenant_id,v_original.invoice_id,v_original.finance_transaction_id,'reversal',\n    v_original.amount,v_original.evidence_level,p_idempotency_key,p_original_allocation_id,\n    btrim(p_reason),p_actor_id)\n  RETURNING id INTO v_id;\n  RETURN v_id;\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_original_allocation_id uuid, p_idempotency_key text, p_reason text, p_actor_id uuid"},{"name":"revert_call_designation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.revert_call_designation(p_call_log_id uuid)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_user_id UUID := auth.uid();\n  v_log RECORD;\n  v_prev JSONB;\n  v_age_seconds NUMERIC;\nBEGIN\n  IF v_user_id IS NULL THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'Authentication required');\n  END IF;\n\n  SELECT * INTO v_log FROM call_logs WHERE id = p_call_log_id LIMIT 1;\n  IF NOT FOUND THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'Call log not found');\n  END IF;\n\n  IF v_log.user_id <> v_user_id THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'Only the rep who logged this call can undo it');\n  END IF;\n\n  v_age_seconds := EXTRACT(EPOCH FROM (NOW() - v_log.created_at));\n  IF v_age_seconds > 30 THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'Undo window expired');\n  END IF;\n\n  v_prev := COALESCE(v_log.metadata->'previous_state', '{}'::jsonb);\n  IF v_prev = '{}'::jsonb THEN\n    RETURN jsonb_build_object('ok', false, 'error', 'No previous state recorded');\n  END IF;\n\n  -- Restore unified_contacts\n  UPDATE unified_contacts SET\n    status         = COALESCE(v_prev->>'status', status),\n    contact_status = COALESCE(v_prev->>'contact_status', contact_status),\n    lead_stage     = COALESCE(v_prev->>'lead_stage', lead_stage),\n    assigned_to    = COALESCE(v_prev->>'assigned_to', assigned_to),\n    assigned_rep   = COALESCE(v_prev->>'assigned_rep', assigned_rep),\n    appt_date      = NULLIF(v_prev->>'appt_date', ''),\n    appt_time      = NULLIF(v_prev->>'appt_time', ''),\n    graduated_at   = NULLIF(v_prev->>'graduated_at', '')::timestamptz,\n    jobs_stage     = NULLIF(v_prev->>'jobs_stage', ''),\n    claim_stage    = NULLIF(v_prev->>'claim_stage', ''),\n    deleted_at     = NULLIF(v_prev->>'deleted_at', '')::timestamptz,\n    notes          = COALESCE(v_prev->>'notes', notes),\n    updated_at     = NOW()\n  WHERE lead_id = v_log.lead_id AND tenant_org_id = v_log.tenant_id::text;\n\n  -- Mirror onto lead_deck\n  UPDATE lead_deck SET\n    status     = COALESCE(v_prev->>'status', status),\n    lead_stage = COALESCE(v_prev->>'lead_stage', lead_stage),\n    deleted_at = NULLIF(v_prev->>'deleted_at', '')::timestamptz,\n    updated_at = NOW()\n  WHERE lead_id = v_log.lead_id AND tenant_org_id = v_log.tenant_id::text;\n\n  -- Remove the follow-up created by this designation (if any was created same-second)\n  DELETE FROM followups\n  WHERE lead_id = v_log.lead_id\n    AND tenant_org_id = v_log.tenant_id::text\n    AND created_at >= v_log.created_at - INTERVAL '2 seconds'\n    AND status = 'Pending';\n\n  -- Roll back DNC entry if this call set it\n  IF v_log.outcome = 'dnc_requested' AND v_log.phone_called IS NOT NULL AND v_log.phone_called <> '' THEN\n    DELETE FROM dnc_list\n    WHERE phone = v_log.phone_called\n      AND tenant_org_id = v_log.tenant_id::text\n      AND created_at >= v_log.created_at - INTERVAL '2 seconds';\n  END IF;\n\n  -- Mark the call log as reverted (do NOT delete, keep audit trail)\n  UPDATE call_logs SET\n    metadata = COALESCE(metadata, '{}'::jsonb)\n               || jsonb_build_object(\n                    'reverted', true,\n                    'reverted_at', NOW(),\n                    'reverted_by', v_user_id\n                  ),\n    updated_at = NOW()\n  WHERE id = p_call_log_id;\n\n  RETURN jsonb_build_object(\n    'ok', true,\n    'lead_id', v_log.lead_id,\n    'restored_status', v_prev->>'status',\n    'restored_lead_stage', v_prev->>'lead_stage'\n  );\nEND;\n$function$\n","identity_arguments":"p_call_log_id uuid"},{"name":"review_mobile_vendor_loyalty_claim","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.review_mobile_vendor_loyalty_claim(_tenant_org_id uuid, _claim_id uuid, _reviewer_id uuid, _decision text, _bonus_stamps integer DEFAULT 1, _review_note text DEFAULT NULL::text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_claim public.mobile_vendor_loyalty_claims%rowtype;\n  v_member public.mobile_vendor_loyalty_members%rowtype;\n  v_bonus integer;\n  v_balance integer;\nbegin\n  if _decision not in ('approve', 'reject') then\n    raise exception 'Invalid loyalty claim decision';\n  end if;\n\n  select * into v_claim\n  from public.mobile_vendor_loyalty_claims\n  where tenant_org_id = _tenant_org_id and id = _claim_id\n  for update;\n\n  if not found then\n    raise exception 'Loyalty claim not found';\n  end if;\n\n  if v_claim.status in ('approved', 'rejected') then\n    return jsonb_build_object(\n      'ok', true,\n      'already_reviewed', true,\n      'status', v_claim.status,\n      'awarded_delta', v_claim.awarded_delta\n    );\n  end if;\n\n  if v_claim.status <> 'pending' then\n    raise exception 'Loyalty claim is not ready for review';\n  end if;\n\n  if _decision = 'reject' then\n    update public.mobile_vendor_loyalty_claims\n    set status = 'rejected', awarded_delta = 0, reviewed_by = _reviewer_id,\n        reviewed_at = now(), review_note = nullif(trim(coalesce(_review_note, '')), ''), updated_at = now()\n    where id = v_claim.id;\n\n    return jsonb_build_object('ok', true, 'status', 'rejected', 'awarded_delta', 0);\n  end if;\n\n  v_bonus := greatest(1, least(5, coalesce(_bonus_stamps, 1)));\n\n  select * into v_member\n  from public.mobile_vendor_loyalty_members\n  where tenant_org_id = _tenant_org_id and id = v_claim.member_id\n  for update;\n\n  if not found or v_member.status <> 'active' then\n    raise exception 'Active loyalty member not found';\n  end if;\n\n  v_balance := coalesce(v_member.stamp_balance, 0) + v_bonus;\n\n  update public.mobile_vendor_loyalty_members\n  set stamp_balance = v_balance,\n      lifetime_stamps = coalesce(lifetime_stamps, 0) + v_bonus,\n      updated_at = now()\n  where tenant_org_id = _tenant_org_id and id = v_member.id;\n\n  insert into public.mobile_vendor_loyalty_activity (\n    tenant_org_id, member_id, contact_id, activity_type, stamps_delta, balance_after, source, source_ref, metadata\n  ) values (\n    _tenant_org_id,\n    v_member.id,\n    v_member.contact_id,\n    'photo_bonus',\n    v_bonus,\n    v_balance,\n    'loyalty_photo_claim',\n    v_claim.id::text,\n    jsonb_build_object('claim_id', v_claim.id, 'reviewed_by', _reviewer_id)\n  );\n\n  update public.mobile_vendor_loyalty_claims\n  set status = 'approved', awarded_delta = v_bonus, reviewed_by = _reviewer_id,\n      reviewed_at = now(), review_note = nullif(trim(coalesce(_review_note, '')), ''), updated_at = now()\n  where id = v_claim.id;\n\n  return jsonb_build_object(\n    'ok', true,\n    'status', 'approved',\n    'awarded_delta', v_bonus,\n    'balance_after', v_balance\n  );\nend;\n$function$\n","identity_arguments":"_tenant_org_id uuid, _claim_id uuid, _reviewer_id uuid, _decision text, _bonus_stamps integer, _review_note text"},{"name":"revoke_customer_portal_when_claims_close","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.revoke_customer_portal_when_claims_close()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_contact_id text;\n  v_tenant_id text;\nbegin\n  if tg_op = 'DELETE' then\n    v_contact_id := old.contact_id;\n    v_tenant_id := old.tenant_org_id;\n  else\n    v_contact_id := new.contact_id;\n    v_tenant_id := new.tenant_org_id;\n  end if;\n\n  if not exists (\n    select 1\n    from public.contact_claims cc\n    where cc.contact_id = v_contact_id\n      and cc.tenant_org_id = v_tenant_id\n      and upper(trim(coalesce(cc.claim_stage, ''))) <> 'P7_CLOSE'\n  ) then\n    update public.customer_portal_access cpa\n    set\n      is_active = false,\n      expires_at = least(coalesce(cpa.expires_at, now()), now())\n    where cpa.contact_id = v_contact_id\n      and cpa.tenant_id = v_tenant_id\n      and cpa.is_active is true;\n  end if;\n\n  return coalesce(new, old);\nend;\n$function$\n","identity_arguments":""},{"name":"revoke_portal_links_on_archive","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.revoke_portal_links_on_archive()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.archived_at IS NOT NULL AND (OLD.archived_at IS NULL OR OLD.archived_at IS DISTINCT FROM NEW.archived_at) THEN\n    UPDATE public.portal_links\n       SET is_active = false\n     WHERE contact_id = NEW.id\n       AND is_active = true;\n  ELSIF NEW.archived_at IS NULL AND OLD.archived_at IS NOT NULL THEN\n    -- Restore portal links if contact is un-archived\n    UPDATE public.portal_links\n       SET is_active = true\n     WHERE contact_id = NEW.id\n       AND is_active = false;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"roofing_ops_can_manage","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.roofing_ops_can_manage(p_tenant_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select public.is_platform_admin(auth.uid())\n    or exists (\n      select 1\n      from public.user_tenant_access uta\n      where uta.user_id = auth.uid()\n        and uta.tenant_id = p_tenant_id\n        and coalesce(uta.membership_status, 'active') = 'active'\n        and coalesce(uta.effective_role, '') in (\n          'GodMode',\n          'Admin',\n          'Owner',\n          'Tenant Owner',\n          'Manager',\n          'OfficeAdmin',\n          'OFFICE_ADMIN',\n          'PM'\n        )\n    );\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"roofing_ops_can_read","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.roofing_ops_can_read(p_tenant_id uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select public.is_platform_admin(auth.uid())\n    or exists (\n      select 1\n      from public.user_tenant_access uta\n      where uta.user_id = auth.uid()\n        and uta.tenant_id = p_tenant_id\n        and coalesce(uta.membership_status, 'active') = 'active'\n    );\n$function$\n","identity_arguments":"p_tenant_id uuid"},{"name":"roofing_ops_touch_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.roofing_ops_touch_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin new.updated_at = now(); return new; end;\n$function$\n","identity_arguments":""},{"name":"route_platform_notification_delivery","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.route_platform_notification_delivery()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_tenant uuid;\n  v_category text;\n  v_requested text;\n  v_personal text;\n  v_tenant_channel text;\n  v_policy_mode text;\n  v_route_source text;\n  v_push_ready boolean;\n  v_state text;\n  v_error text;\nbegin\n  if new.tenant_id is null or new.user_id is null\n     or new.tenant_id !~* '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' then\n    return new; -- global/invalid tenant notifications get no outbound delivery\n  end if;\n  v_tenant := new.tenant_id::uuid;\n  if not exists (\n    select 1 from public.user_tenant_memberships m\n    join public.profiles p on p.id=m.user_id\n    where m.tenant_id=v_tenant and m.user_id=new.user_id\n      and m.status='active' and coalesce(p.active,true)=true\n  ) then return new; end if;\n\n  v_category := public.platform_notification_category(new.type);\n  select p.category_channels->>v_category\n    into v_personal from public.app_notification_preferences p\n    where p.tenant_id=v_tenant and p.user_id=new.user_id;\n  select p.channel,p.mode into v_tenant_channel,v_policy_mode\n    from public.tenant_notification_policies p\n    where p.tenant_id=v_tenant and p.category=v_category;\n  if v_policy_mode='enforce' then\n    v_requested:=v_tenant_channel;v_route_source:='tenant_enforced';\n  elsif v_personal is not null then\n    v_requested:=v_personal;v_route_source:='personal_override';\n  elsif v_tenant_channel is not null then\n    v_requested:=v_tenant_channel;v_route_source:='tenant_recommendation';\n  else\n    v_requested:=public.platform_notification_default_channel(v_category);\n    v_route_source:='platform_default';\n  end if;\n\n  insert into public.platform_notification_deliveries\n    (notification_id,tenant_id,user_id,category,channel,route_source,delivery_state)\n  values (new.id,v_tenant,new.user_id,v_category,'in_app',v_route_source,'recorded')\n  on conflict (notification_id,channel) do nothing;\n\n  if v_requested='push' then\n    select exists(select 1 from public.message_push_subscriptions ps\n      where ps.user_id=new.user_id and ps.disabled_at is null)\n      into v_push_ready;\n    -- A messaging-device subscription alone is NOT an activated universal\n    -- notification dispatcher. No queue record should imply a worker exists.\n    v_state:='blocked_unconfigured';\n    v_error:=case when v_push_ready then 'universal_push_dispatch_not_activated'\n      else 'push_subscription_missing' end;\n  elsif v_requested='email' then\n    -- The universal verified-email adapter and signed delivery webhooks\n    -- are NOT connected; do not claim queued/sent just because a profile has an email.\n    v_state:='blocked_unconfigured';\n    v_error:='verified_email_adapter_not_activated';\n  else\n    return new; -- in_app or off: recorded ledger remains; no outbound intent\n  end if;\n  insert into public.platform_notification_deliveries\n    (notification_id,tenant_id,user_id,category,channel,route_source,\n     delivery_state,last_error_code)\n  values (new.id,v_tenant,new.user_id,v_category,v_requested,v_route_source,\n    v_state,v_error)\n  on conflict (notification_id,channel) do nothing;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"run_pa_claim_automation_rules","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.run_pa_claim_automation_rules()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  rule_row record;\n  action_row jsonb;\n  cfg jsonb;\n  due_days integer;\n  assigned_user uuid;\nbegin\n  if new.claim_stage is not distinct from old.claim_stage then\n    return new;\n  end if;\n\n  select assigned_to into assigned_user\n  from public.unified_contacts\n  where id::text = new.contact_id::text\n  limit 1;\n\n  for rule_row in\n    select id, name, actions\n    from public.pipeline_automation_rules\n    where tenant_org_id::text = new.tenant_org_id::text\n      and is_active = true\n      and trigger_type = 'stage_change'\n      and coalesce(trigger_config ->> 'entity_kind', 'contact') = 'claim'\n      and (trigger_config ->> 'to_stage' is null or trigger_config ->> 'to_stage' = new.claim_stage)\n      and (trigger_config ->> 'from_stage' is null or trigger_config ->> 'from_stage' = old.claim_stage)\n    order by priority desc, created_at asc\n  loop\n    for action_row in select value from jsonb_array_elements(coalesce(rule_row.actions, '[]'::jsonb))\n    loop\n      cfg := coalesce(action_row -> 'config', action_row -> 'params', '{}'::jsonb);\n\n      if action_row ->> 'type' = 'create_claim_task' then\n        due_days := greatest(0, coalesce((cfg ->> 'due_in_days')::integer, 1));\n\n        if not exists (\n          select 1\n          from public.tasks t\n          where t.claim_id = new.id\n            and t.metadata ->> 'automation_rule_id' = rule_row.id::text\n            and t.metadata ->> 'claim_stage' = new.claim_stage\n            and t.status in ('pending', 'in_progress')\n        ) then\n          insert into public.tasks (\n            tenant_id,\n            user_id,\n            assigned_to,\n            contact_id,\n            claim_id,\n            title,\n            description,\n            priority,\n            status,\n            due_date,\n            metadata\n          ) values (\n            new.tenant_org_id,\n            assigned_user,\n            assigned_user,\n            new.contact_id,\n            new.id,\n            coalesce(cfg ->> 'title', rule_row.name),\n            cfg ->> 'description',\n            coalesce(cfg ->> 'priority', 'medium'),\n            'pending',\n            now() + make_interval(days => due_days),\n            jsonb_build_object(\n              'source', 'pa_claim_automation',\n              'automation_rule_id', rule_row.id,\n              'automation_rule_name', rule_row.name,\n              'claim_stage', new.claim_stage\n            )\n          );\n        end if;\n      end if;\n    end loop;\n\n    update public.pipeline_automation_rules\n    set execution_count = coalesce(execution_count, 0) + 1,\n        last_executed_at = now()\n    where id = rule_row.id;\n\n    insert into public.automation_run_log (\n      tenant_org_id,\n      rule_id,\n      rule_name,\n      engine,\n      trigger_type,\n      entity_kind,\n      entity_id,\n      status,\n      dry_run,\n      payload,\n      actions_executed\n    ) values (\n      new.tenant_org_id::uuid,\n      rule_row.id,\n      rule_row.name,\n      'pa-claim-stage-trigger',\n      'stage_change',\n      'claim',\n      new.id,\n      'success',\n      false,\n      jsonb_build_object('from_stage', old.claim_stage, 'to_stage', new.claim_stage, 'contact_id', new.contact_id),\n      rule_row.actions\n    );\n  end loop;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"save_canonical_invoice","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.save_canonical_invoice(p_tenant_org_id text, p_invoice jsonb, p_created_by text DEFAULT NULL::text)\n RETURNS invoices\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_id uuid;\n  v_invoice_id text;\n  v_row public.invoices;\n  v_year integer := EXTRACT(YEAR FROM now())::integer;\n  v_prefix text;\n  v_next integer;\n  v_render_dirty boolean;\nBEGIN\n  IF NULLIF(btrim(p_tenant_org_id), '') IS NULL THEN\n    RAISE EXCEPTION 'tenant_required';\n  END IF;\n\n  BEGIN\n    v_id := NULLIF(p_invoice->>'id', '')::uuid;\n  EXCEPTION WHEN invalid_text_representation THEN\n    RAISE EXCEPTION 'invalid_invoice_id';\n  END;\n\n  v_invoice_id := NULLIF(btrim(p_invoice->>'invoice_id'), '');\n  v_prefix := 'INV-' || v_year::text || '-';\n\n  IF v_id IS NULL AND v_invoice_id IS NULL THEN\n    PERFORM pg_advisory_xact_lock(hashtextextended('canonical-invoice:' || p_tenant_org_id, 0));\n    SELECT COALESCE(MAX((regexp_match(invoice_id, '^INV-' || v_year::text || '-([0-9]+)$'))[1]::integer), 0) + 1\n      INTO v_next\n    FROM public.invoices\n    WHERE tenant_org_id = p_tenant_org_id\n      AND invoice_id ~ ('^INV-' || v_year::text || '-[0-9]+$');\n    v_invoice_id := v_prefix || lpad(v_next::text, 4, '0');\n  END IF;\n\n  v_render_dirty := p_invoice ?| ARRAY[\n    'invoice_id','customer_name','customer_email','amount','due_date','line_items','contact_id',\n    'subtotal','tax_rate','tax_amount','invoice_date','notes','payment_terms','insurance_carrier',\n    'claim_number','policy_number','document_subtype','document_metadata','source_proposal_id','event_booking_id'\n  ];\n\n  IF v_id IS NULL THEN\n    INSERT INTO public.invoices (\n      invoice_id, customer_name, customer_email, amount, status, due_date, line_items,\n      tenant_org_id, created_by, contact_id, subtotal, tax_rate, tax_amount, invoice_date,\n      notes, payment_terms, insurance_carrier, claim_number, policy_number, payment_url,\n      paid_at, event_booking_id, payment_provider, payment_provider_link_id,\n      payment_provider_order_id, payment_provider_payment_id, payment_provider_status,\n      canonical_contact_id, document_kind, document_subtype, document_metadata, source_proposal_id\n    ) VALUES (\n      v_invoice_id,\n      COALESCE(NULLIF(p_invoice->>'customer_name', ''), 'Customer'),\n      NULLIF(p_invoice->>'customer_email', ''),\n      COALESCE(NULLIF(p_invoice->>'amount', '')::numeric, 0),\n      lower(COALESCE(NULLIF(p_invoice->>'status', ''), 'draft')),\n      NULLIF(p_invoice->>'due_date', '')::date,\n      COALESCE(p_invoice->'line_items', '[]'::jsonb),\n      p_tenant_org_id,\n      COALESCE(p_created_by, NULLIF(p_invoice->>'created_by', '')),\n      NULLIF(p_invoice->>'contact_id', ''),\n      COALESCE(NULLIF(p_invoice->>'subtotal', '')::numeric, NULLIF(p_invoice->>'amount', '')::numeric, 0),\n      COALESCE(NULLIF(p_invoice->>'tax_rate', '')::numeric, 0),\n      COALESCE(NULLIF(p_invoice->>'tax_amount', '')::numeric, 0),\n      COALESCE(NULLIF(p_invoice->>'invoice_date', '')::date, CURRENT_DATE),\n      NULLIF(p_invoice->>'notes', ''),\n      NULLIF(p_invoice->>'payment_terms', ''),\n      NULLIF(p_invoice->>'insurance_carrier', ''),\n      NULLIF(p_invoice->>'claim_number', ''),\n      NULLIF(p_invoice->>'policy_number', ''),\n      NULLIF(p_invoice->>'payment_url', ''),\n      NULLIF(p_invoice->>'paid_at', '')::timestamptz,\n      NULLIF(p_invoice->>'event_booking_id', '')::uuid,\n      NULLIF(p_invoice->>'payment_provider', ''),\n      NULLIF(p_invoice->>'payment_provider_link_id', ''),\n      NULLIF(p_invoice->>'payment_provider_order_id', ''),\n      NULLIF(p_invoice->>'payment_provider_payment_id', ''),\n      NULLIF(p_invoice->>'payment_provider_status', ''),\n      NULLIF(p_invoice->>'canonical_contact_id', '')::uuid,\n      'invoice',\n      COALESCE(NULLIF(p_invoice->>'document_subtype', ''), 'standard'),\n      COALESCE(p_invoice->'document_metadata', '{}'::jsonb),\n      NULLIF(p_invoice->>'source_proposal_id', '')::uuid\n    )\n    RETURNING * INTO v_row;\n  ELSE\n    UPDATE public.invoices\n    SET\n      invoice_id = CASE WHEN p_invoice ? 'invoice_id' THEN COALESCE(v_invoice_id, invoice_id) ELSE invoice_id END,\n      customer_name = CASE WHEN p_invoice ? 'customer_name' THEN COALESCE(NULLIF(p_invoice->>'customer_name', ''), customer_name) ELSE customer_name END,\n      customer_email = CASE WHEN p_invoice ? 'customer_email' THEN NULLIF(p_invoice->>'customer_email', '') ELSE customer_email END,\n      amount = CASE WHEN p_invoice ? 'amount' THEN COALESCE(NULLIF(p_invoice->>'amount', '')::numeric, 0) ELSE amount END,\n      status = CASE WHEN p_invoice ? 'status' THEN lower(COALESCE(NULLIF(p_invoice->>'status', ''), status)) ELSE status END,\n      due_date = CASE WHEN p_invoice ? 'due_date' THEN NULLIF(p_invoice->>'due_date', '')::date ELSE due_date END,\n      line_items = CASE WHEN p_invoice ? 'line_items' THEN COALESCE(p_invoice->'line_items', '[]'::jsonb) ELSE line_items END,\n      contact_id = CASE WHEN p_invoice ? 'contact_id' THEN NULLIF(p_invoice->>'contact_id', '') ELSE contact_id END,\n      subtotal = CASE WHEN p_invoice ? 'subtotal' THEN COALESCE(NULLIF(p_invoice->>'subtotal', '')::numeric, 0) ELSE subtotal END,\n      tax_rate = CASE WHEN p_invoice ? 'tax_rate' THEN COALESCE(NULLIF(p_invoice->>'tax_rate', '')::numeric, 0) ELSE tax_rate END,\n      tax_amount = CASE WHEN p_invoice ? 'tax_amount' THEN COALESCE(NULLIF(p_invoice->>'tax_amount', '')::numeric, 0) ELSE tax_amount END,\n      invoice_date = CASE WHEN p_invoice ? 'invoice_date' THEN NULLIF(p_invoice->>'invoice_date', '')::date ELSE invoice_date END,\n      notes = CASE WHEN p_invoice ? 'notes' THEN NULLIF(p_invoice->>'notes', '') ELSE notes END,\n      payment_terms = CASE WHEN p_invoice ? 'payment_terms' THEN NULLIF(p_invoice->>'payment_terms', '') ELSE payment_terms END,\n      insurance_carrier = CASE WHEN p_invoice ? 'insurance_carrier' THEN NULLIF(p_invoice->>'insurance_carrier', '') ELSE insurance_carrier END,\n      claim_number = CASE WHEN p_invoice ? 'claim_number' THEN NULLIF(p_invoice->>'claim_number', '') ELSE claim_number END,\n      policy_number = CASE WHEN p_invoice ? 'policy_number' THEN NULLIF(p_invoice->>'policy_number', '') ELSE policy_number END,\n      payment_url = CASE WHEN p_invoice ? 'payment_url' THEN NULLIF(p_invoice->>'payment_url', '') ELSE payment_url END,\n      paid_at = CASE WHEN p_invoice ? 'paid_at' THEN NULLIF(p_invoice->>'paid_at', '')::timestamptz ELSE paid_at END,\n      event_booking_id = CASE WHEN p_invoice ? 'event_booking_id' THEN NULLIF(p_invoice->>'event_booking_id', '')::uuid ELSE event_booking_id END,\n      payment_provider = CASE WHEN p_invoice ? 'payment_provider' THEN NULLIF(p_invoice->>'payment_provider', '') ELSE payment_provider END,\n      payment_provider_link_id = CASE WHEN p_invoice ? 'payment_provider_link_id' THEN NULLIF(p_invoice->>'payment_provider_link_id', '') ELSE payment_provider_link_id END,\n      payment_provider_order_id = CASE WHEN p_invoice ? 'payment_provider_order_id' THEN NULLIF(p_invoice->>'payment_provider_order_id', '') ELSE payment_provider_order_id END,\n      payment_provider_payment_id = CASE WHEN p_invoice ? 'payment_provider_payment_id' THEN NULLIF(p_invoice->>'payment_provider_payment_id', '') ELSE payment_provider_payment_id END,\n      payment_provider_status = CASE WHEN p_invoice ? 'payment_provider_status' THEN NULLIF(p_invoice->>'payment_provider_status', '') ELSE payment_provider_status END,\n      canonical_contact_id = CASE WHEN p_invoice ? 'canonical_contact_id' THEN NULLIF(p_invoice->>'canonical_contact_id', '')::uuid ELSE canonical_contact_id END,\n      document_kind = 'invoice',\n      document_subtype = CASE WHEN p_invoice ? 'document_subtype' THEN COALESCE(NULLIF(p_invoice->>'document_subtype', ''), 'standard') ELSE document_subtype END,\n      document_metadata = CASE WHEN p_invoice ? 'document_metadata' THEN COALESCE(p_invoice->'document_metadata', '{}'::jsonb) ELSE document_metadata END,\n      source_proposal_id = CASE WHEN p_invoice ? 'source_proposal_id' THEN NULLIF(p_invoice->>'source_proposal_id', '')::uuid ELSE source_proposal_id END,\n      render_bucket = CASE WHEN v_render_dirty THEN NULL ELSE render_bucket END,\n      pdf_file_path = CASE WHEN v_render_dirty THEN NULL ELSE pdf_file_path END,\n      pdf_url = CASE WHEN v_render_dirty THEN NULL ELSE pdf_url END,\n      render_hash = CASE WHEN v_render_dirty THEN NULL ELSE render_hash END,\n      rendered_at = CASE WHEN v_render_dirty THEN NULL ELSE rendered_at END,\n      updated_at = now()\n    WHERE id = v_id AND tenant_org_id = p_tenant_org_id\n    RETURNING * INTO v_row;\n\n    IF v_row.id IS NULL THEN\n      RAISE EXCEPTION 'invoice_not_found';\n    END IF;\n  END IF;\n\n  RETURN v_row;\nEND;\n$function$\n","identity_arguments":"p_tenant_org_id text, p_invoice jsonb, p_created_by text"},{"name":"save_my_onboarding_intake","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.save_my_onboarding_intake(p_session_id uuid DEFAULT NULL::uuid, p_company_name text DEFAULT NULL::text, p_business_type text DEFAULT NULL::text, p_service_lines jsonb DEFAULT NULL::jsonb, p_operating_states text[] DEFAULT NULL::text[], p_service_area jsonb DEFAULT NULL::jsonb, p_team_size integer DEFAULT NULL::integer, p_goals jsonb DEFAULT NULL::jsonb, p_requested_capabilities jsonb DEFAULT NULL::jsonb, p_intake_answers jsonb DEFAULT NULL::jsonb, p_email text DEFAULT NULL::text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_uid uuid := auth.uid();\n  v_session_id uuid;\n  v_email text;\n  s public.onboarding_sessions%rowtype;\nbegin\n  if v_uid is null then raise exception 'Authentication required' using errcode='42501'; end if;\n  select email into v_email from auth.users where id=v_uid;\n  v_email := coalesce(nullif(p_email,''),v_email);\n\n  if p_session_id is not null then\n    select id into v_session_id from public.onboarding_sessions\n    where id=p_session_id and (owner_user_id=v_uid or public.is_system_admin(v_uid));\n    if v_session_id is null then raise exception 'Onboarding session not found' using errcode='42501'; end if;\n  else\n    select id into v_session_id\n    from public.onboarding_sessions\n    where owner_user_id=v_uid and status not in ('live','cancelled')\n    order by updated_at desc\n    limit 1;\n  end if;\n\n  if v_session_id is null then\n    insert into public.onboarding_sessions(owner_user_id,email,company_name,status)\n    values(v_uid,v_email,coalesce(p_company_name,''),'draft')\n    returning id into v_session_id;\n  end if;\n\n  update public.onboarding_sessions\n  set email=coalesce(v_email,email),\n      company_name=coalesce(p_company_name,company_name),\n      requested_business_type=coalesce(p_business_type,requested_business_type),\n      service_lines=case when p_service_lines is null then service_lines else p_service_lines end,\n      operating_states=case when p_operating_states is null then operating_states else p_operating_states end,\n      service_area=case when p_service_area is null then service_area else p_service_area end,\n      team_size=coalesce(p_team_size,team_size),\n      goals=case when p_goals is null then goals else p_goals end,\n      requested_capabilities=case when p_requested_capabilities is null then requested_capabilities else p_requested_capabilities end,\n      intake_answers=coalesce(intake_answers,'{}'::jsonb) || coalesce(p_intake_answers,'{}'::jsonb),\n      last_error=null,\n      updated_at=now()\n  where id=v_session_id;\n\n  perform public.derive_onboarding_blueprint(v_session_id);\n  select * into s from public.onboarding_sessions where id=v_session_id;\n  if coalesce(s.requested_business_type,'')<>'' and cardinality(s.operating_states)>0 then\n    perform public.queue_onboarding_license_research(v_session_id);\n  else\n    perform public.refresh_onboarding_readiness(v_session_id);\n  end if;\n\n  return public.get_my_onboarding_context(v_session_id);\nend;\n$function$\n","identity_arguments":"p_session_id uuid, p_company_name text, p_business_type text, p_service_lines jsonb, p_operating_states text[], p_service_area jsonb, p_team_size integer, p_goals jsonb, p_requested_capabilities jsonb, p_intake_answers jsonb, p_email text"},{"name":"save_tenant_full_workflow_script","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.save_tenant_full_workflow_script(p_tenant_id uuid, p_tenant_type text, p_cards jsonb, p_rebuttals jsonb, p_change_notes text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_uid uuid := auth.uid();\n  v_email text;\n  v_type text;\n  v_full_key text;\n  v_override_key text;\n  v_card_count int;\n  v_rebuttal_count int;\n  v_saved_at timestamptz := now();\n  v_payload jsonb;\nBEGIN\n  IF v_uid IS NULL THEN\n    RAISE EXCEPTION 'Authentication required' USING ERRCODE = '42501';\n  END IF;\n\n  IF p_tenant_id IS NULL THEN\n    RAISE EXCEPTION 'tenant_id is required' USING ERRCODE = '22023';\n  END IF;\n\n  -- Permission gate: platform admin OR tenant owner/admin OR manager-in-tenant.\n  IF NOT (\n    public.is_system_admin(v_uid)\n    OR public.is_tenant_owner_or_admin(v_uid, p_tenant_id)\n    OR public.is_manager_or_higher(v_uid, p_tenant_id)\n  ) THEN\n    RAISE EXCEPTION 'You do not have permission to activate scripts for this tenant'\n      USING ERRCODE = '42501';\n  END IF;\n\n  -- Payload validation.\n  IF p_cards IS NULL OR jsonb_typeof(p_cards) <> 'array' OR jsonb_array_length(p_cards) = 0 THEN\n    RAISE EXCEPTION 'cards must be a non-empty JSON array' USING ERRCODE = '22023';\n  END IF;\n\n  v_card_count := jsonb_array_length(p_cards);\n  v_rebuttal_count := CASE\n    WHEN p_rebuttals IS NOT NULL AND jsonb_typeof(p_rebuttals) = 'array'\n      THEN jsonb_array_length(p_rebuttals)\n    ELSE 0\n  END;\n\n  v_type := upper(regexp_replace(coalesce(p_tenant_type, 'MITIGATION'), '\\s+', '_', 'g'));\n  v_full_key := 'workflow_full_' || v_type;\n  v_override_key := 'workflow_overrides_' || v_type;\n\n  SELECT email INTO v_email FROM auth.users WHERE id = v_uid;\n\n  v_payload := jsonb_build_object(\n    '_format', 'knocklaunch.script-bundle.v1',\n    'cards', p_cards,\n    'rebuttals', COALESCE(p_rebuttals, '[]'::jsonb),\n    'changeNotes', COALESCE(p_change_notes, ''),\n    'savedAt', to_jsonb(v_saved_at),\n    'savedBy', COALESCE(v_email, v_uid::text)\n  );\n\n  INSERT INTO public.site_config (\n    config_key, config_value, category, tenant_org_id, updated_by, updated_at\n  ) VALUES (\n    v_full_key, v_payload, 'workflow_full', p_tenant_id::text,\n    COALESCE(v_email, v_uid::text), v_saved_at\n  )\n  ON CONFLICT (config_key, tenant_org_id) DO UPDATE\n  SET config_value = EXCLUDED.config_value,\n      category     = EXCLUDED.category,\n      updated_by   = EXCLUDED.updated_by,\n      updated_at   = EXCLUDED.updated_at;\n\n  -- Stale sparse-override row is no longer authoritative — remove it.\n  DELETE FROM public.site_config\n  WHERE config_key = v_override_key\n    AND tenant_org_id = p_tenant_id::text;\n\n  RETURN jsonb_build_object(\n    'ok', true,\n    'savedAt', to_jsonb(v_saved_at),\n    'cardCount', v_card_count,\n    'rebuttalCount', v_rebuttal_count,\n    'tenantOrgId', p_tenant_id,\n    'tenantType', v_type\n  );\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_tenant_type text, p_cards jsonb, p_rebuttals jsonb, p_change_notes text"},{"name":"scrub_lead_against_dnc","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.scrub_lead_against_dnc()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_normalized text;\n  v_match RECORD;\n  v_quarantined BOOLEAN;\nBEGIN\n  IF TG_OP = 'UPDATE' AND NEW.phone IS NOT DISTINCT FROM OLD.phone AND OLD.is_dnc = NEW.is_dnc THEN\n    RETURN NEW;\n  END IF;\n\n  v_normalized := public.normalize_phone_for_dnc(NEW.phone);\n  IF v_normalized IS NULL THEN\n    NEW.dnc_checked_at := now();\n    NEW.is_dnc := false;\n    RETURN NEW;\n  END IF;\n\n  -- Block if previously quarantined\n  SELECT EXISTS(SELECT 1 FROM public.dnc_quarantine WHERE phone_normalized = v_normalized)\n    INTO v_quarantined;\n  IF v_quarantined THEN\n    RAISE EXCEPTION 'Phone % is in DNC quarantine vault and cannot be re-imported.', NEW.phone;\n  END IF;\n\n  SELECT phone, reason INTO v_match\n  FROM public.dnc_list WHERE phone_normalized = v_normalized LIMIT 1;\n\n  NEW.dnc_checked_at := now();\n  IF v_match.phone IS NOT NULL THEN\n    NEW.is_dnc := true;\n    NEW.dnc_reason := COALESCE(v_match.reason, 'Matched DNC list');\n    NEW.status := 'DNC';\n  ELSE\n    NEW.is_dnc := false;\n    NEW.dnc_reason := NULL;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"search_console_runs","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.search_console_runs(_query text DEFAULT NULL::text, _limit integer DEFAULT 100)\n RETURNS TABLE(run_id uuid, tenant_id uuid, tenant_name text, tenant_slug text, title text, mission_type text, mission_phase text, mission_status text, event_status text, created_at timestamp with time zone, updated_at timestamp with time zone, last_progress_at timestamp with time zone, terminal_reason text, receipt_count bigint, latest_receipt jsonb, mission_context jsonb)\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_query text := trim(coalesce(_query, ''));\n  v_pattern text := '%' || trim(coalesce(_query, '')) || '%';\n  v_limit integer := greatest(1, least(coalesce(_limit, 100), 250));\nbegin\n  if auth.uid() is null or not public.is_system_admin(auth.uid()) then\n    raise exception 'Platform owner required' using errcode = '42501';\n  end if;\n\n  return query\n  select\n    e.id,\n    e.tenant_id,\n    t.name,\n    t.company_slug,\n    e.title,\n    e.mission_type,\n    e.mission_phase,\n    e.mission_status,\n    e.status,\n    e.created_at,\n    e.updated_at,\n    e.last_progress_at,\n    e.terminal_reason,\n    (select count(*) from public.command_center_receipts cr where cr.command_center_event_id = e.id),\n    (\n      select jsonb_build_object(\n        'id', cr.id,\n        'created_at', cr.created_at,\n        'receipt_type', cr.receipt_type,\n        'source', cr.source,\n        'status', cr.status,\n        'proof_gate', cr.proof_gate,\n        'external_id', cr.external_id,\n        'source_sha', cr.source_sha,\n        'payload', cr.payload\n      )\n      from public.command_center_receipts cr\n      where cr.command_center_event_id = e.id\n      order by cr.created_at desc\n      limit 1\n    ),\n    coalesce(e.mission_context, '{}'::jsonb)\n  from public.command_center_events e\n  left join public.tenants t on t.id = e.tenant_id\n  where e.mission_type is not null\n    and (\n      v_query = ''\n      or e.title ilike v_pattern\n      or coalesce(e.message, '') ilike v_pattern\n      or coalesce(e.mission_type, '') ilike v_pattern\n      or coalesce(e.mission_phase, '') ilike v_pattern\n      or coalesce(e.mission_status, '') ilike v_pattern\n      or coalesce(t.name, '') ilike v_pattern\n      or coalesce(t.company_slug, '') ilike v_pattern\n      or e.mission_context::text ilike v_pattern\n      or exists (\n        select 1\n        from public.command_center_messages sm\n        where sm.command_center_event_id = e.id\n          and sm.message ilike v_pattern\n      )\n      or exists (\n        select 1\n        from public.command_center_receipts sr\n        where sr.command_center_event_id = e.id\n          and (\n            coalesce(sr.external_id, '') ilike v_pattern\n            or coalesce(sr.proof_gate, '') ilike v_pattern\n            or coalesce(sr.source_sha, '') ilike v_pattern\n            or sr.payload::text ilike v_pattern\n          )\n      )\n    )\n  order by coalesce(e.last_progress_at, e.updated_at, e.created_at) desc\n  limit v_limit;\nend;\n$function$\n","identity_arguments":"_query text, _limit integer"},{"name":"search_contacts","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.search_contacts(search_query text, tenant_id text DEFAULT NULL::text)\n RETURNS TABLE(id text, name text, phone text, email text, address text, city text, state text, status text, rank real)\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  RETURN QUERY\n  SELECT uc.id, uc.name, uc.phone, uc.email, uc.address, uc.city, uc.state, uc.status,\n    ts_rank(to_tsvector('english', coalesce(uc.name, '') || ' ' || coalesce(uc.email, '') || ' ' || coalesce(uc.phone, '') || ' ' || coalesce(uc.address, '') || ' ' || coalesce(uc.city, '') || ' ' || coalesce(uc.notes, '')), plainto_tsquery('english', search_query)) as rank\n  FROM unified_contacts uc\n  WHERE (tenant_id IS NULL OR uc.tenant_org_id = tenant_id) AND uc.deleted_at IS NULL\n    AND to_tsvector('english', coalesce(uc.name, '') || ' ' || coalesce(uc.email, '') || ' ' || coalesce(uc.phone, '') || ' ' || coalesce(uc.address, '') || ' ' || coalesce(uc.city, '') || ' ' || coalesce(uc.notes, '')) @@ plainto_tsquery('english', search_query)\n  ORDER BY rank DESC LIMIT 100;\nEND;\n$function$\n","identity_arguments":"search_query text, tenant_id text"},{"name":"search_pcg_workspace","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.search_pcg_workspace(p_tenant_id uuid, p_query text, p_limit integer DEFAULT 40, p_offset integer DEFAULT 0)\n RETURNS TABLE(entity_type text, entity_id text, title text, subtitle text, occurred_at timestamp with time zone, score double precision, metadata jsonb)\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_uid uuid := auth.uid();\n  v_query text := lower(trim(regexp_replace(coalesce(p_query,''),'\\\\s+',' ','g')));\n  v_limit integer := least(100,greatest(1,coalesce(p_limit,40)));\n  v_offset integer := greatest(0,coalesce(p_offset,0));\nbegin\n  if v_uid is null then raise exception 'authentication_required' using errcode='42501'; end if;\n  if p_tenant_id is null then raise exception 'tenant_required' using errcode='22023'; end if;\n  if not public.is_tenant_member(v_uid,p_tenant_id) and not coalesce(public.is_system_admin(v_uid),false) then raise exception 'tenant_membership_required' using errcode='42501'; end if;\n  if length(v_query)<2 then return; end if;\n  return query\n  -- pcg-search-bounded-text-v1\n  with raw as materialized (\n    select 'card'::text entity_type,c.id::text entity_id,coalesce(nullif(concat_ws(' · ',c.cert_number,c.year,c.brand_set,c.player_character,c.card_number),''),'PCG card') title,nullif(concat_ws(' • ',c.status,c.grade_label,c.card_description,c.variation,c.internal_notes,c.grader_notes),'') subtitle,coalesce(c.updated_at,c.created_at) occurred_at,lower(concat_ws(' ',c.id,c.submission_id,c.pcg_submission_number,c.cert_number,c.year,c.brand_set,c.player_character,c.card_number,c.status,c.grade_label,c.card_description,c.variation,c.internal_notes,c.grader_notes,c.import_key)) search_text,jsonb_build_object('cardId',c.id,'submissionId',c.submission_id,'deleted',c.deleted_at is not null,'workspacePath','/pcg/dashboard?mode=grading&tool=queue&submissionId='||c.submission_id::text||'&cardId='||c.id::text) metadata from public.card_grading_cards c where c.tenant_id=p_tenant_id and c.is_demo=false\n    union all select 'submission',s.id::text,coalesce(nullif(s.submission_number,''),'PCG submission'),nullif(concat_ws(' • ',s.customer_name,s.customer_email,s.customer_phone,s.status,s.tracking_in,s.tracking_out,s.payment_reference,s.notes),''),coalesce(s.updated_at,s.created_at),lower(concat_ws(' ',s.id,s.submission_number,s.customer_name,s.customer_email,s.customer_phone,s.status,s.tracking_in,s.tracking_out,s.payment_reference,s.notes)),jsonb_build_object('submissionId',s.id,'workspacePath','/pcg/dashboard?mode=received&tool=submissions&submissionId='||s.id::text) from public.card_grading_submissions s where s.tenant_id=p_tenant_id and s.is_demo=false\n    union all select 'certificate',c.id::text,coalesce(nullif(c.cert_number,''),'PCG certificate'),nullif(concat_ws(' • ',c.year,c.brand_set,c.player_character,c.card_number,c.grade_label),''),coalesce(c.updated_at,c.created_at),lower(concat_ws(' ',c.id,c.card_id,c.cert_number,c.year,c.brand_set,c.player_character,c.card_number,c.grade_label)),jsonb_build_object('cardId',c.card_id,'certNumber',c.cert_number,'workspacePath','/pcg/dashboard?mode=grading&tool=certs&cardId='||c.card_id::text) from public.card_grading_certificates c where c.tenant_id=p_tenant_id\n    union all select 'grading_session',g.id::text,'Grading session',nullif(concat_ws(' • ',g.status,g.grade_label,g.notes),''),coalesce(g.updated_at,g.created_at),lower(concat_ws(' ',g.id,g.card_id,g.status,g.grade_label,g.notes)),jsonb_build_object('cardId',g.card_id,'workspacePath','/pcg/dashboard?mode=grading&tool=queue&cardId='||g.card_id::text) from public.card_grading_grading_sessions g where g.tenant_id=p_tenant_id\n    union all select 'grading_criterion',r.id::text,'Grading criterion '||coalesce(r.criterion_key,''),nullif(concat_ws(' • ',r.score::text,r.notes),''),coalesce(r.updated_at,r.created_at),lower(concat_ws(' ',r.id,r.session_id,r.criterion_key,r.score,r.notes)),jsonb_build_object('sessionId',r.session_id) from public.card_grading_criterion_results r where r.tenant_id=p_tenant_id\n    union all select 'qc_review',q.id::text,'QC review',nullif(concat_ws(' • ',q.outcome,q.notes),''),q.reviewed_at,lower(concat_ws(' ',q.id,q.card_id,q.outcome,q.notes)),jsonb_build_object('cardId',q.card_id,'workspacePath','/pcg/dashboard?mode=grading&tool=queue&cardId='||q.card_id::text) from public.card_grading_qc_reviews q where q.tenant_id=p_tenant_id\n    union all select 'exception',e.id::text,'PCG exception',nullif(concat_ws(' • ',e.kind,e.reason,e.status,e.resolution),''),coalesce(e.resolved_at,e.opened_at),lower(concat_ws(' ',e.id,e.card_id,e.submission_id,e.kind,e.reason,e.status,e.resolution)),jsonb_build_object('cardId',e.card_id,'submissionId',e.submission_id) from public.card_grading_exceptions e where e.tenant_id=p_tenant_id\n    union all select 'workflow_event',w.id::text,'Workflow event '||coalesce(w.event_type,''),nullif(concat_ws(' • ',w.from_status,w.to_status,w.reason),''),w.occurred_at,lower(concat_ws(' ',w.id,w.card_id,w.submission_id,w.event_type,w.from_status,w.to_status,w.reason)),jsonb_build_object('cardId',w.card_id,'submissionId',w.submission_id) from public.card_grading_workflow_events w where w.tenant_id=p_tenant_id\n    union all select 'lifecycle_event',l.id::text,'Card lifecycle '||coalesce(l.action,''),nullif(l.message,''),l.created_at,lower(concat_ws(' ',l.id,l.card_id,l.action,l.message)),jsonb_build_object('cardId',l.card_id,'workspacePath','/pcg/card-vault?cardId='||l.card_id::text) from public.pcg_card_lifecycle_events l where l.tenant_id=p_tenant_id\n    union all select 'legacy_import',r.id::text,coalesce(nullif(r.normalized_payload->>'cert_number',''),nullif(r.normalized_payload->>'player_character',''),'Legacy PCG card'),nullif(concat_ws(' • ',r.normalized_payload->>'year',r.normalized_payload->>'brand_set',r.normalized_payload->>'card_number',r.normalized_payload->>'grade_label',r.source_url),''),coalesce(r.updated_at,r.created_at),lower(concat_ws(' ',r.id,r.external_key,r.import_key,r.source_url,r.normalized_payload->>'cert_number',r.normalized_payload->>'year',r.normalized_payload->>'brand_set',r.normalized_payload->>'player_character',r.normalized_payload->>'card_number',r.normalized_payload->>'card_description',r.normalized_payload->>'description',r.normalized_payload->>'variation',r.normalized_payload->>'category',r.normalized_payload->>'autograph',r.normalized_payload->>'grade',r.normalized_payload->>'grade_label',r.normalized_payload->>'grader_notes',r.normalized_payload->>'notes',r.normalized_payload->>'customer_name',r.validation_status,r.planned_action,r.error_text)),jsonb_build_object('legacyRowId',r.id,'canonicalCardId',r.canonical_card_id,'canonicalSubmissionId',r.canonical_submission_id,'sourceUrl',r.source_url,'workspacePath',case when r.canonical_card_id is not null then '/pcg/card-vault?cardId='||r.canonical_card_id::text else '/pcg/dashboard?tool=migration' end) from public.pcg_import_rows r where r.tenant_id=p_tenant_id\n    union all select 'legacy_batch',b.id::text,coalesce(nullif(b.source_label,''),'Legacy import batch'),nullif(concat_ws(' • ',b.source_type,b.status,b.source_url),''),coalesce(b.updated_at,b.created_at),lower(concat_ws(' ',b.id,b.source_label,b.source_type,b.status,b.source_url)),jsonb_build_object('batchId',b.id,'workspacePath','/pcg/dashboard?tool=migration') from public.pcg_import_batches b where b.tenant_id=p_tenant_id\n    union all select 'customer',u.id::text,coalesce(nullif(u.name,''),nullif(u.email,''),'PCG customer'),nullif(concat_ws(' • ',u.email,u.phone,u.address,u.city,u.state,u.zip),''),coalesce(u.updated_at,u.created_at),lower(concat_ws(' ',u.id,u.name,u.email,u.phone,u.address,u.city,u.state,u.zip)),jsonb_build_object('contactId',u.id,'workspacePath','/pcg/dashboard?mode=intake&tool=collectors') from public.unified_contacts u where u.tenant_org_id=p_tenant_id::text and exists(select 1 from public.card_grading_submissions s where s.tenant_id=p_tenant_id and s.customer_contact_id=u.id)\n  ), scored as (\n    select r.*,case\n      when lower(r.title)=v_query then 200\n      when left(lower(r.title),length(v_query))=v_query then 170\n      when strpos(r.search_text,v_query)>0 then 130\n      else 80+extensions.similarity(lower(r.title),v_query)*40\n    end::double precision score\n    from raw r\n    where strpos(r.search_text,v_query)>0 or strpos(lower(r.title),v_query)>0\n      or case when v_query ~ '^[0-9]+$' then false else extensions.similarity(lower(r.title),v_query)>=0.25 end\n  )\n  select s.entity_type,s.entity_id,s.title,s.subtitle,s.occurred_at,s.score,s.metadata from scored s order by s.score desc,s.occurred_at desc nulls last,s.title,s.entity_id,s.entity_type limit v_limit offset v_offset;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_query text, p_limit integer, p_offset integer"},{"name":"search_platform_message_people","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.search_platform_message_people(p_query text DEFAULT ''::text, p_limit integer DEFAULT 20)\n RETURNS TABLE(user_id uuid, display_name text, company text)\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select p.id, coalesce(nullif(trim(p.name),''),'KNOCKLAUNCH User'), coalesce(p.company,'')\n  from public.profiles p\n  where auth.uid() is not null\n    and p.active is distinct from false\n    and p.id <> auth.uid()\n    and (\n      trim(coalesce(p_query,'')) = ''\n      or coalesce(p.name,'') ilike '%' || replace(replace(trim(p_query),'%','\\%'),'_','\\_') || '%' escape '\\'\n      or coalesce(p.company,'') ilike '%' || replace(replace(trim(p_query),'%','\\%'),'_','\\_') || '%' escape '\\'\n    )\n  order by coalesce(p.name,p.company,'')\n  limit least(greatest(coalesce(p_limit,20),1),50);\n$function$\n","identity_arguments":"p_query text, p_limit integer"},{"name":"search_platform_messages","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.search_platform_messages(p_query text, p_limit integer DEFAULT 40)\n RETURNS jsonb\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  select coalesce(jsonb_agg(jsonb_build_object(\n    'id',m.id,'conversation_id',m.conversation_id,'body',m.body,'created_at',m.created_at,\n    'sender_name',coalesce(nullif(trim(p.name),''),'KNOCKLAUNCH User')\n  ) order by m.created_at desc),'[]'::jsonb)\n  from public.messages m\n  left join public.profiles p on p.id=m.sender_id\n  where m.deleted_at is null\n    and public.can_access_message_conversation(m.conversation_id,auth.uid())\n    and trim(coalesce(p_query,''))<>''\n    and to_tsvector('simple',coalesce(m.body,'')) @@ plainto_tsquery('simple',p_query)\n  limit least(greatest(coalesce(p_limit,40),1),100);\n$function$\n","identity_arguments":"p_query text, p_limit integer"},{"name":"search_tenant_workspace","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.search_tenant_workspace(p_tenant_id uuid, p_query text, p_application_ids text[] DEFAULT ARRAY[]::text[], p_limit integer DEFAULT 28)\n RETURNS TABLE(domain text, entity_type text, entity_id text, title text, subtitle text, occurred_at timestamp with time zone, score double precision, app_id text, metadata jsonb)\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_user_id uuid := auth.uid();\n  v_query text := lower(trim(regexp_replace(coalesce(p_query, ''), '\\s+', ' ', 'g')));\n  v_apps text[] := coalesce(p_application_ids, array[]::text[]);\n  v_limit integer := least(40, greatest(1, coalesce(p_limit, 28)));\n  v_next_work boolean := v_query = any(array['next stop','next event','next appointment','next job','what''s next','whats next','what is next']);\nbegin\n  if v_user_id is null then\n    raise exception 'Sign in to search this business.' using errcode = '42501';\n  end if;\n  if p_tenant_id is null then\n    raise exception 'Business scope is required.' using errcode = '22023';\n  end if;\n  if not coalesce(public.is_system_admin(v_user_id), false)\n     and not exists (\n       select 1\n       from public.user_tenant_access uta\n       where uta.user_id = v_user_id\n         and uta.tenant_id = p_tenant_id\n         and (coalesce(uta.has_membership, false) or lower(coalesce(uta.membership_status, '')) = 'active')\n     ) then\n    raise exception 'This business is not available to the signed-in user.' using errcode = '42501';\n  end if;\n  if length(v_query) < 2 and not v_next_work then\n    return;\n  end if;\n\n  return query\n  with raw as (\n    select\n      'people'::text as domain,\n      'contact'::text as entity_type,\n      c.id::text as entity_id,\n      coalesce(nullif(c.name, ''), nullif(trim(concat_ws(' ', c.first_name, c.last_name)), ''), 'Customer')::text as title,\n      nullif(concat_ws(' • ', nullif(c.email, ''), nullif(c.phone, ''), nullif(c.city, '')), '')::text as subtitle,\n      coalesce(c.updated_at, c.created_at) as occurred_at,\n      'contacts'::text as app_id,\n      lower(concat_ws(' ', c.name, c.first_name, c.last_name, c.email, c.phone, c.address, c.city, c.state, c.zip)) as search_text,\n      0::double precision as base_score,\n      false as next_only,\n      jsonb_build_object('contactId', c.id, 'email', c.email, 'phone', c.phone) as metadata\n    from public.unified_contacts c\n    where 'contacts' = any(v_apps)\n      and c.tenant_org_id = p_tenant_id::text\n      and c.deleted_at is null\n\n    union all\n\n    select\n      'sales', 'invoice', i.id::text,\n      coalesce(nullif(i.invoice_id, ''), 'Invoice ' || left(i.id::text, 8)),\n      nullif(concat_ws(' • ', nullif(i.customer_name, ''), nullif(i.status, ''), case when i.amount is not null then '$' || trim(to_char(i.amount, 'FM999999990.00')) end), ''),\n      coalesce(i.updated_at, i.created_at), 'invoices',\n      lower(concat_ws(' ', i.invoice_id, i.customer_name, i.customer_email, i.status, i.amount::text)),\n      0::double precision, false,\n      jsonb_build_object('invoiceId', i.id, 'contactId', i.contact_id, 'eventId', i.event_booking_id, 'status', i.status)\n    from public.invoices i\n    where 'invoices' = any(v_apps)\n      and i.tenant_org_id = p_tenant_id::text\n\n    union all\n\n    select\n      'schedule', 'event', e.id::text,\n      coalesce(nullif(e.event_name, ''), nullif(e.venue_name, ''), 'Scheduled event'),\n      nullif(concat_ws(' • ', nullif(e.venue_name, ''), nullif(e.location, ''), e.event_date::text), ''),\n      coalesce(e.start_time, e.event_date::timestamptz, e.updated_at, e.created_at),\n      case when 'calendar' = any(v_apps) then 'calendar' else 'booking' end,\n      lower(concat_ws(' ', e.event_name, e.venue_name, e.location, e.event_type, e.status, e.event_date::text)),\n      0::double precision, false,\n      jsonb_build_object('eventId', e.id, 'contactId', e.contact_id, 'eventDate', e.event_date, 'startTime', e.start_time)\n    from public.event_bookings e\n    where ('calendar' = any(v_apps) or 'booking' = any(v_apps))\n      and e.tenant_org_id = p_tenant_id::text\n\n    union all\n\n    select\n      'work', 'job', j.id::text,\n      coalesce(nullif(j.job_number, ''), nullif(j.customer_name, ''), 'Job'),\n      nullif(concat_ws(' • ', nullif(j.customer_name, ''), nullif(j.property_address, ''), j.scheduled_date::text, nullif(j.status, '')), ''),\n      coalesce(j.updated_at, j.created_at), 'jobs',\n      lower(concat_ws(' ', j.job_number, j.customer_name, j.customer_email, j.customer_phone, j.property_address, j.status, j.scheduled_date::text)),\n      0::double precision, false,\n      jsonb_build_object('jobId', j.id, 'contactId', j.contact_id, 'scheduledDate', j.scheduled_date, 'scheduledTime', j.scheduled_time)\n    from public.jobs j\n    where 'jobs' = any(v_apps)\n      and j.tenant_id = p_tenant_id\n\n    union all\n\n    select\n      'documents', 'document', d.id::text,\n      coalesce(nullif(d.name, ''), 'Document'),\n      nullif(concat_ws(' • ', nullif(d.category, ''), nullif(d.mime_type, '')), ''),\n      d.uploaded_at, 'documents',\n      lower(concat_ws(' ', d.name, d.category, d.mime_type, d.scope)),\n      0::double precision, false,\n      jsonb_build_object('documentId', d.id, 'eventId', d.event_booking_id, 'category', d.category)\n    from public.documents d\n    where 'documents' = any(v_apps)\n      and d.tenant_id = p_tenant_id\n\n    union all\n\n    select\n      'work', 'route_stop', s.id::text,\n      coalesce(nullif(d.address, ''), 'Route stop ' || s.stop_order::text),\n      nullif(concat_ws(' • ', nullif(d.city, ''), nullif(d.state, ''), 'Stop ' || s.stop_order::text), ''),\n      coalesce(rs.started_at, s.created_at), 'route-service-operations',\n      lower(concat_ws(' ', d.address, d.city, d.state, d.zip, s.status)),\n      (130 - least(coalesce(s.stop_order, 0), 99)::double precision / 100), true,\n      jsonb_build_object('routeSessionId', s.route_session_id, 'stopId', s.id, 'doorId', s.door_id, 'contactId', d.contact_id, 'stopOrder', s.stop_order)\n    from public.route_session_stops s\n    join public.route_sessions rs on rs.id = s.route_session_id and rs.tenant_org_id = p_tenant_id\n    left join public.door_objects d on d.id = s.door_id and d.tenant_org_id = p_tenant_id::text and d.deleted_at is null\n    where v_next_work\n      and 'route-service-operations' = any(v_apps)\n      and s.tenant_org_id = p_tenant_id\n      and rs.ended_at is null\n      and lower(coalesce(s.status, 'pending')) not in ('completed','skipped','cancelled','canceled')\n\n    union all\n\n    select\n      'work', 'service_visit', v.id::text,\n      coalesce(nullif(c.name, ''), 'Service stop ' || coalesce(v.stop_order, 0)::text),\n      nullif(concat_ws(' • ', v.service_date::text, 'Stop ' || coalesce(v.stop_order, 0)::text, nullif(v.status, '')), ''),\n      v.service_date::timestamptz, 'route-service-operations',\n      lower(concat_ws(' ', c.name, c.email, c.phone, v.service_date::text, v.status)),\n      (125 - least(coalesce(v.stop_order, 0), 99)::double precision / 100), true,\n      jsonb_build_object('visitId', v.id, 'routeId', v.route_id, 'contactId', v.contact_id, 'stopOrder', v.stop_order)\n    from public.lawn_service_visits v\n    left join public.unified_contacts c on c.id = v.contact_id and c.tenant_org_id = p_tenant_id::text and c.deleted_at is null\n    where v_next_work\n      and 'route-service-operations' = any(v_apps)\n      and v.tenant_id = p_tenant_id\n      and v.service_date >= current_date\n      and lower(coalesce(v.status, 'scheduled')) not in ('completed','cancelled','canceled','skipped')\n\n    union all\n\n    select\n      'work', 'job', j.id::text,\n      coalesce(nullif(j.job_number, ''), nullif(j.customer_name, ''), 'Upcoming job'),\n      nullif(concat_ws(' • ', nullif(j.customer_name, ''), nullif(j.property_address, ''), j.scheduled_date::text, nullif(j.scheduled_time, '')), ''),\n      j.scheduled_date::timestamptz, 'jobs',\n      lower(concat_ws(' ', j.job_number, j.customer_name, j.property_address, j.scheduled_date::text)),\n      120::double precision, true,\n      jsonb_build_object('jobId', j.id, 'contactId', j.contact_id, 'scheduledDate', j.scheduled_date, 'scheduledTime', j.scheduled_time)\n    from public.jobs j\n    where v_next_work\n      and 'jobs' = any(v_apps)\n      and j.tenant_id = p_tenant_id\n      and j.scheduled_date >= current_date\n      and lower(coalesce(j.status, 'scheduled')) not in ('completed','cancelled','canceled')\n\n    union all\n\n    select\n      'schedule', 'event', e.id::text,\n      coalesce(nullif(e.event_name, ''), nullif(e.venue_name, ''), 'Upcoming event'),\n      nullif(concat_ws(' • ', nullif(e.venue_name, ''), nullif(e.location, ''), e.event_date::text), ''),\n      coalesce(e.start_time, e.event_date::timestamptz),\n      case when 'calendar' = any(v_apps) then 'calendar' else 'booking' end,\n      lower(concat_ws(' ', e.event_name, e.venue_name, e.location, e.event_date::text)),\n      115::double precision, true,\n      jsonb_build_object('eventId', e.id, 'contactId', e.contact_id, 'eventDate', e.event_date, 'startTime', e.start_time)\n    from public.event_bookings e\n    where v_next_work\n      and ('calendar' = any(v_apps) or 'booking' = any(v_apps))\n      and e.tenant_org_id = p_tenant_id::text\n      and e.event_date >= current_date\n      and lower(coalesce(e.status, 'scheduled')) not in ('cancelled','canceled')\n  ),\n  scored as (\n    select\n      r.domain, r.entity_type, r.entity_id, r.title, r.subtitle, r.occurred_at, r.app_id, r.metadata,\n      case\n        when r.next_only then r.base_score\n        when lower(r.title) = v_query then 100::double precision\n        when lower(r.title) like v_query || '%' then 90::double precision\n        when lower(r.title) like '%' || v_query || '%' then 75::double precision\n        else 50::double precision + greatest(similarity(lower(r.title), v_query), similarity(r.search_text, v_query)) * 20\n      end as score\n    from raw r\n    where (v_next_work and r.next_only)\n       or (not v_next_work and not r.next_only and (\n         r.search_text like '%' || v_query || '%'\n         or similarity(r.search_text, v_query) >= 0.22\n         or similarity(lower(r.title), v_query) >= 0.28\n       ))\n  ),\n  deduped as (\n    select distinct on (s.domain, s.entity_type, s.entity_id)\n      s.domain, s.entity_type, s.entity_id, s.title, s.subtitle, s.occurred_at, s.score, s.app_id, s.metadata\n    from scored s\n    order by s.domain, s.entity_type, s.entity_id, s.score desc, s.occurred_at desc nulls last\n  ),\n  ranked as (\n    select d.*, row_number() over (partition by d.domain order by d.score desc, d.occurred_at desc nulls last, d.title, d.entity_id) as domain_rank\n    from deduped d\n  )\n  select r.domain, r.entity_type, r.entity_id, r.title, r.subtitle, r.occurred_at, r.score, r.app_id, r.metadata\n  from ranked r\n  where r.domain_rank <= 8\n  order by r.score desc, r.occurred_at desc nulls last, r.title, r.entity_id\n  limit v_limit;\nend;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_query text, p_application_ids text[], p_limit integer"},{"name":"security_remove_roles_for_inactive_membership","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.security_remove_roles_for_inactive_membership()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_user_id uuid;\n  v_tenant_id uuid;\n  v_remove boolean := false;\nBEGIN\n  IF TG_OP = 'DELETE' THEN\n    v_user_id := OLD.user_id;\n    v_tenant_id := OLD.tenant_id;\n    v_remove := true;\n  ELSE\n    v_user_id := NEW.user_id;\n    v_tenant_id := NEW.tenant_id;\n    v_remove := coalesce(NEW.status, '') <> 'active';\n  END IF;\n\n  IF v_remove THEN\n    DELETE FROM public.user_roles ur\n    WHERE ur.user_id = v_user_id\n      AND ur.tenant_id = v_tenant_id;\n  END IF;\n\n  RETURN CASE WHEN TG_OP = 'DELETE' THEN OLD ELSE NEW END;\nEND;\n$function$\n","identity_arguments":""},{"name":"security_validate_role_scope_update","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.security_validate_role_scope_update()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF NEW.tenant_id IS NOT NULL\n     AND NOT EXISTS (\n       SELECT 1\n       FROM public.user_tenant_memberships m\n       WHERE m.user_id = NEW.user_id\n         AND m.tenant_id = NEW.tenant_id\n         AND m.status = 'active'\n     ) THEN\n    RAISE EXCEPTION 'scoped role requires active tenant membership' USING ERRCODE = '42501';\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"seed_default_automation_on_tenant_create","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.seed_default_automation_on_tenant_create()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  PERFORM public.ensure_default_homeowner_stage_rule(NEW.id);\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"seed_roofing_invoice_templates","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.seed_roofing_invoice_templates()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_body text := '<section class=\"roofing-invoice\"><header><h1>{{company_name}}</h1><p>Roofing Invoice</p></header><p><strong>Invoice:</strong> {{invoice_number}}</p><p><strong>Homeowner:</strong> {{customer_name}}</p><p><strong>Property:</strong> {{property_address}}</p><div>{{line_items}}</div><p><strong>Subtotal:</strong> {{subtotal}}</p><p><strong>Tax:</strong> {{tax}}</p><p><strong>Total due:</strong> {{total}}</p><p><strong>Due date:</strong> {{due_date}}</p><footer>{{payment_instructions}}</footer></section>';\n  v_variables jsonb := '[\"company_name\",\"invoice_number\",\"customer_name\",\"property_address\",\"line_items\",\"subtotal\",\"tax\",\"total\",\"due_date\",\"payment_instructions\"]'::jsonb;\nbegin\n  if upper(replace(coalesce(new.tenant_type, ''), ' ', '_')) <> 'ROOFING_COMPANY' then\n    return new;\n  end if;\n\n  insert into public.invoice_templates (tenant_id, key, label, tone, body, variables, is_default)\n  values\n    (new.id, 'roofing_invoice', 'Roofing Invoice', 'vertical', v_body, v_variables, true),\n    (new.id, 'roofing', 'Roofing Invoice', 'vertical', v_body, v_variables, false),\n    (new.id, 'standard', 'Standard Invoice', 'standard', v_body, v_variables, false)\n  on conflict (tenant_id, key) do update\n    set body = case\n          when length(btrim(public.invoice_templates.body)) = 0 then excluded.body\n          else public.invoice_templates.body\n        end,\n        variables = case\n          when public.invoice_templates.variables = '[]'::jsonb then excluded.variables\n          else public.invoice_templates.variables\n        end,\n        updated_at = now();\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"seed_statutory_deadlines","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.seed_statutory_deadlines()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _dol DATE;\nBEGIN\n  -- Skip if no DOL or DOL not parseable\n  IF NEW.date_of_loss IS NULL OR NEW.date_of_loss = '' THEN\n    RETURN NEW;\n  END IF;\n\n  BEGIN\n    _dol := NEW.date_of_loss::DATE;\n  EXCEPTION WHEN OTHERS THEN\n    RETURN NEW;\n  END;\n\n  -- Only seed if no deadlines exist yet for this claim\n  IF EXISTS (SELECT 1 FROM public.claim_deadlines WHERE claim_id = NEW.id) THEN\n    RETURN NEW;\n  END IF;\n\n  -- 14-day acknowledgement (FL §627.70131(1)(a)) - measured from claim filing, default to today\n  INSERT INTO public.claim_deadlines (claim_id, contact_id, tenant_org_id, code, label, due_date, is_statutory)\n  VALUES (NEW.id, NEW.contact_id, NEW.tenant_org_id, 'ACK_14D', 'Carrier acknowledgement (14 days)', CURRENT_DATE + INTERVAL '14 days', true);\n\n  -- 60-day coverage decision (post-2022 FL reform §627.70131(7))\n  INSERT INTO public.claim_deadlines (claim_id, contact_id, tenant_org_id, code, label, due_date, is_statutory)\n  VALUES (NEW.id, NEW.contact_id, NEW.tenant_org_id, 'DECISION_60D', 'Coverage decision (60 days)', CURRENT_DATE + INTERVAL '60 days', true);\n\n  -- 1-year notice of claim (FL §627.70132 — post-2022 reform)\n  INSERT INTO public.claim_deadlines (claim_id, contact_id, tenant_org_id, code, label, due_date, is_statutory)\n  VALUES (NEW.id, NEW.contact_id, NEW.tenant_org_id, 'NOTICE_1Y', 'Notice of new/reopened claim (1 year from DOL)', _dol + INTERVAL '1 year', true);\n\n  -- 5-year statute of limitations on suit (FL §95.11(2)(e))\n  INSERT INTO public.claim_deadlines (claim_id, contact_id, tenant_org_id, code, label, due_date, is_statutory)\n  VALUES (NEW.id, NEW.contact_id, NEW.tenant_org_id, 'SOL_5Y', 'Statute of limitations on suit (5 years from DOL)', _dol + INTERVAL '5 years', true);\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"send_platform_message","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.send_platform_message(p_conversation_id uuid, p_body text, p_reply_to_id uuid DEFAULT NULL::uuid, p_context jsonb DEFAULT NULL::jsonb)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  caller uuid := auth.uid();\n  clean_body text := trim(coalesce(p_body,''));\n  context_tenant uuid;\n  destination text;\n  message_id uuid;\nbegin\n  if caller is null or not public.can_access_message_conversation(p_conversation_id,caller) then\n    raise exception 'message_conversation_access_denied';\n  end if;\n  if clean_body='' then raise exception 'message_body_required'; end if;\n  if char_length(clean_body)>4000 then raise exception 'message_body_too_long'; end if;\n  if p_reply_to_id is not null and not exists (\n    select 1 from public.messages where id=p_reply_to_id and conversation_id=p_conversation_id\n  ) then raise exception 'invalid_reply_target'; end if;\n\n  if p_context is not null then\n    begin context_tenant := nullif(p_context->>'tenant_id','')::uuid; exception when others then context_tenant := null; end;\n    destination := p_context->>'destination_path';\n    if context_tenant is null or destination is null or left(destination,1)<>'/' then\n      raise exception 'invalid_message_context';\n    end if;\n    if exists (\n      select 1 from public.message_conversation_members cm\n      where cm.conversation_id=p_conversation_id\n        and not public.is_active_message_tenant_member(context_tenant,cm.user_id)\n    ) then raise exception 'message_context_not_shared_by_members'; end if;\n    p_context := jsonb_build_object(\n      'tenant_id',context_tenant,\n      'entity_type',left(coalesce(p_context->>'entity_type','item'),80),\n      'entity_id',left(coalesce(p_context->>'entity_id',''),160),\n      'destination_path',left(destination,500)\n    );\n  end if;\n\n  insert into public.messages(conversation_id,sender_id,body,reply_to_id,context)\n  values(p_conversation_id,caller,clean_body,p_reply_to_id,p_context)\n  returning id into message_id;\n\n  update public.message_conversations set updated_at=now() where id=p_conversation_id;\n  update public.message_conversation_members set last_read_at=now()\n    where conversation_id=p_conversation_id and user_id=caller;\n  return message_id;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_body text, p_reply_to_id uuid, p_context jsonb"},{"name":"send_platform_message_v2","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.send_platform_message_v2(p_conversation_id uuid, p_encrypted_payload text, p_encryption_nonce text, p_key_version integer, p_reply_to_id uuid DEFAULT NULL::uuid, p_context jsonb DEFAULT NULL::jsonb)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare caller uuid:=auth.uid(); message_id uuid; current_version integer;\nbegin\n  if caller is null or not public.can_access_message_conversation(p_conversation_id,caller) then raise exception 'message_conversation_access_denied'; end if;\n  select current_key_version into current_version from public.message_conversations where id=p_conversation_id;\n  if p_key_version is null or p_key_version<>current_version then raise exception 'message_key_rotation_required'; end if;\n  if length(coalesce(p_encrypted_payload,''))<8 or length(p_encrypted_payload)>24000 then raise exception 'encrypted_message_invalid'; end if;\n  if length(coalesce(p_encryption_nonce,''))<8 then raise exception 'encrypted_message_nonce_required'; end if;\n  if p_reply_to_id is not null and not exists(select 1 from public.messages where id=p_reply_to_id and conversation_id=p_conversation_id) then raise exception 'invalid_reply_target'; end if;\n  insert into public.messages(conversation_id,sender_id,body,reply_to_id,context,encrypted_payload,encryption_nonce,encryption_alg,key_version)\n  values(p_conversation_id,caller,'[encrypted]',p_reply_to_id,p_context,p_encrypted_payload,p_encryption_nonce,'AES-GCM-256',p_key_version)\n  returning id into message_id;\n  update public.message_conversations set updated_at=now() where id=p_conversation_id;\n  update public.message_conversation_members set last_read_at=now() where conversation_id=p_conversation_id and user_id=caller;\n  return message_id;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_encrypted_payload text, p_encryption_nonce text, p_key_version integer, p_reply_to_id uuid, p_context jsonb"},{"name":"set_communication_events_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.set_communication_events_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"set_contact_compliance_bypass","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.set_contact_compliance_bypass(_tenant_org_id text, _contact_id uuid, _enabled boolean, _reason text)\n RETURNS TABLE(active boolean, audit_event_id uuid, checked_at timestamp with time zone)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_user uuid := auth.uid();\n  v_tenant_uuid uuid;\n  v_can_bypass boolean := false;\n  v_contact record;\n  v_previous_active boolean := false;\n  v_event_id uuid;\n  v_checked_at timestamptz;\n  v_reason text := btrim(COALESCE(_reason, ''));\nBEGIN\n  IF v_user IS NULL THEN\n    RAISE EXCEPTION 'Authentication required';\n  END IF;\n\n  IF _tenant_org_id IS NULL OR _contact_id IS NULL THEN\n    RAISE EXCEPTION 'Tenant and contact are required';\n  END IF;\n\n  BEGIN\n    v_tenant_uuid := _tenant_org_id::uuid;\n  EXCEPTION WHEN others THEN\n    v_tenant_uuid := NULL;\n  END;\n\n  v_can_bypass := public.is_system_admin(v_user)\n    OR (v_tenant_uuid IS NOT NULL AND public.is_admin_or_higher(v_user, v_tenant_uuid));\n\n  IF NOT v_can_bypass THEN\n    RAISE EXCEPTION 'Only tenant owners/admins can bypass compliance gates';\n  END IF;\n\n  SELECT uc.id, uc.tenant_org_id, uc.phone, uc.normalized_phone, uc.is_test_account\n  INTO v_contact\n  FROM public.unified_contacts uc\n  WHERE uc.id = _contact_id\n    AND uc.tenant_org_id = _tenant_org_id;\n\n  IF NOT FOUND THEN\n    RAISE EXCEPTION 'Contact not found in active tenant';\n  END IF;\n\n  IF v_contact.is_test_account IS DISTINCT FROM true THEN\n    RAISE EXCEPTION 'Compliance bypass is limited to test contacts';\n  END IF;\n\n  IF char_length(v_reason) < 5 THEN\n    RAISE EXCEPTION 'Reason must be at least 5 characters';\n  END IF;\n\n  SELECT COALESCE(ce.result = 'bypass_enabled', false)\n  INTO v_previous_active\n  FROM public.communication_compliance_events ce\n  WHERE ce.tenant_org_id = _tenant_org_id\n    AND ce.lead_id = _contact_id::text\n    AND ce.check_type = 'owner_bypass'\n  ORDER BY ce.checked_at DESC\n  LIMIT 1;\n\n  v_previous_active := COALESCE(v_previous_active, false);\n\n  INSERT INTO public.communication_compliance_events AS cce (\n    tenant_org_id,\n    lead_id,\n    phone_number,\n    phone_normalized,\n    check_type,\n    provider,\n    result,\n    decision,\n    reason,\n    raw_response,\n    checked_by\n  ) VALUES (\n    _tenant_org_id,\n    _contact_id::text,\n    COALESCE(v_contact.phone, v_contact.normalized_phone, 'N/A'),\n    v_contact.normalized_phone,\n    'owner_bypass',\n    'owner_manual_override',\n    CASE WHEN _enabled THEN 'bypass_enabled' ELSE 'bypass_disabled' END,\n    'override',\n    v_reason,\n    jsonb_build_object(\n      'action', CASE WHEN _enabled THEN 'bypass_enabled' ELSE 'bypass_disabled' END,\n      'previous_state', CASE WHEN v_previous_active THEN 'gates_bypassed' ELSE 'gates_active' END,\n      'new_state', CASE WHEN _enabled THEN 'gates_bypassed' ELSE 'gates_active' END,\n      'previous_active', v_previous_active,\n      'new_active', _enabled,\n      'contact_id', _contact_id,\n      'tenant_org_id', _tenant_org_id,\n      'user_id', v_user\n    ),\n    v_user\n  )\n  RETURNING cce.id, cce.checked_at INTO v_event_id, v_checked_at;\n\n  RETURN QUERY SELECT _enabled, v_event_id, v_checked_at;\nEND;\n$function$\n","identity_arguments":"_tenant_org_id text, _contact_id uuid, _enabled boolean, _reason text"},{"name":"set_door_created_by","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.set_door_created_by()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  IF NEW.created_by IS NULL THEN\n    NEW.created_by = auth.uid();\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"set_mobile_vendor_inventory_snapshot","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.set_mobile_vendor_inventory_snapshot(p_tenant_org_id uuid, p_item_id uuid, p_quantity_on_hand numeric, p_metadata jsonb DEFAULT NULL::jsonb, p_event_booking_id uuid DEFAULT NULL::uuid, p_movement_type text DEFAULT 'adjustment'::text, p_note text DEFAULT NULL::text)\n RETURNS mobile_vendor_inventory_items\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\ndeclare\n  current_item public.mobile_vendor_inventory_items%rowtype;\n  updated_item public.mobile_vendor_inventory_items%rowtype;\n  quantity_delta numeric(12,2);\nbegin\n  if p_quantity_on_hand is null or p_quantity_on_hand < 0 then\n    raise exception 'Inventory quantity must be zero or greater.';\n  end if;\n  if p_movement_type not in ('purchase','adjustment','event_usage','waste') then\n    raise exception 'Unsupported inventory movement type.';\n  end if;\n\n  select * into current_item\n  from public.mobile_vendor_inventory_items\n  where id = p_item_id\n    and tenant_org_id = p_tenant_org_id\n    and item_kind = 'flavor'\n  for update;\n\n  if not found then\n    raise exception 'Flavor inventory item not found.';\n  end if;\n\n  if p_event_booking_id is not null and not exists (\n    select 1 from public.event_bookings\n    where id = p_event_booking_id\n      and tenant_org_id = p_tenant_org_id::text\n  ) then\n    raise exception 'Event booking does not belong to this workspace.';\n  end if;\n\n  quantity_delta := p_quantity_on_hand - current_item.quantity_on_hand;\n\n  update public.mobile_vendor_inventory_items\n  set quantity_on_hand = p_quantity_on_hand,\n      metadata = coalesce(p_metadata, current_item.metadata),\n      updated_at = now()\n  where id = current_item.id\n  returning * into updated_item;\n\n  if quantity_delta <> 0 then\n    insert into public.mobile_vendor_inventory_movements (\n      tenant_org_id, inventory_item_id, event_booking_id, movement_type,\n      quantity_delta, balance_after, unit_cost_snapshot, note, created_by, metadata\n    ) values (\n      p_tenant_org_id, current_item.id, p_event_booking_id, p_movement_type,\n      quantity_delta, p_quantity_on_hand, current_item.unit_cost,\n      nullif(trim(coalesce(p_note, '')), ''), auth.uid(),\n      jsonb_build_object('inventory_version','v2','snapshot_write',true)\n    );\n  end if;\n\n  return updated_item;\nend;\n$function$\n","identity_arguments":"p_tenant_org_id uuid, p_item_id uuid, p_quantity_on_hand numeric, p_metadata jsonb, p_event_booking_id uuid, p_movement_type text, p_note text"},{"name":"set_platform_message_member_role","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.set_platform_message_member_role(p_conversation_id uuid, p_user_id uuid, p_role text)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare current_role text;\nbegin\n  if not public.can_manage_message_group(p_conversation_id,auth.uid()) then raise exception 'group_manage_denied'; end if;\n  if p_role not in ('owner','admin','member') then raise exception 'invalid_group_role'; end if;\n  select role into current_role from public.message_conversation_members where conversation_id=p_conversation_id and user_id=p_user_id;\n  if current_role='owner' and p_role<>'owner' and (select count(*) from public.message_conversation_members where conversation_id=p_conversation_id and role='owner')<=1 then raise exception 'group_requires_owner'; end if;\n  update public.message_conversation_members set role=p_role where conversation_id=p_conversation_id and user_id=p_user_id;\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_user_id uuid, p_role text"},{"name":"set_updated_at_simple","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.set_updated_at_simple()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$ BEGIN NEW.updated_at = now(); RETURN NEW; END $function$\n","identity_arguments":""},{"name":"set_vm_drop_month_bucket","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.set_vm_drop_month_bucket()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.month_bucket := to_char(NEW.dropped_at AT TIME ZONE 'UTC','YYYY-MM');\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"shares_tenant_as_manager_pm","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.shares_tenant_as_manager_pm(_viewer uuid, _target uuid)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  select\n    _viewer is not null\n    and _target is not null\n    and (\n      coalesce(auth.jwt()->>'role','')='service_role'\n      or auth.uid()=_viewer\n      or public.is_system_admin(auth.uid())\n    )\n    and exists (\n      select 1\n      from public.user_tenant_memberships utm_target\n      where utm_target.user_id=_target\n        and utm_target.status='active'\n        and public.is_manager_pm_or_higher(_viewer, utm_target.tenant_id)\n    );\n$function$\n","identity_arguments":"_viewer uuid, _target uuid"},{"name":"submit_public_event_rental_booking_request","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.submit_public_event_rental_booking_request(p_tenant_slug text, p_full_name text, p_phone text, p_email text, p_event_type text, p_event_date date, p_start_time time without time zone, p_end_time time without time zone, p_guest_count integer, p_location text, p_additional_details text DEFAULT NULL::text)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant record;\n  v_booking_id uuid;\n  v_start timestamptz;\n  v_end timestamptz;\nbegin\n  if nullif(trim(p_tenant_slug),'') is null then raise exception 'tenant_required'; end if;\n  if nullif(trim(p_full_name),'') is null then raise exception 'full_name_required'; end if;\n  if nullif(trim(p_event_type),'') is null then raise exception 'event_type_required'; end if;\n  if p_event_date is null then raise exception 'event_date_required'; end if;\n  if p_event_date < (now() at time zone 'America/New_York')::date then raise exception 'event_date_past'; end if;\n  if p_start_time is null then raise exception 'start_time_required'; end if;\n  if p_end_time is null then raise exception 'end_time_required'; end if;\n  if nullif(trim(p_location),'') is null then raise exception 'location_required'; end if;\n  if nullif(trim(p_phone),'') is null and nullif(trim(p_email),'') is null then raise exception 'contact_required'; end if;\n  if p_guest_count is not null and (p_guest_count < 1 or p_guest_count > 10000) then raise exception 'guest_count_invalid'; end if;\n  if nullif(trim(p_email),'') is not null and trim(p_email) !~* '^[^@[:space:]]+@[^@[:space:]]+\\.[^@[:space:]]+$' then raise exception 'email_invalid'; end if;\n\n  v_start := (p_event_date + p_start_time) at time zone 'America/New_York';\n  v_end := (p_event_date + p_end_time) at time zone 'America/New_York';\n  if v_end <= v_start then raise exception 'end_time_invalid'; end if;\n\n  select id,tenant_type,settings,is_active,status into v_tenant\n  from public.tenants\n  where lower(company_slug)=lower(trim(p_tenant_slug))\n  limit 1;\n\n  if v_tenant.id is null then raise exception 'tenant_not_found'; end if;\n  if coalesce(v_tenant.is_active,false) is not true or coalesce(v_tenant.status,'') <> 'active' then raise exception 'tenant_unavailable'; end if;\n  if upper(replace(replace(coalesce(v_tenant.tenant_type,''),'-','_'),' ','_')) not in ('EVENT_RENTAL','EVENT_RENTALS','PARTY_RENTAL','PARTY_RENTALS') then raise exception 'tenant_type_not_supported'; end if;\n  if coalesce(v_tenant.settings->'public_presence'->>'required','false')::boolean is not true then raise exception 'public_presence_unavailable'; end if;\n\n  insert into public.event_bookings(\n    tenant_org_id,event_name,event_type,stage,status,event_date,start_time,end_time,location,guest_count,source,raw_intake,metadata\n  ) values (\n    v_tenant.id::text,\n    trim(p_full_name) || ' - ' || trim(p_event_type),\n    trim(p_event_type),\n    'Inquiry',\n    'active',\n    p_event_date,\n    v_start,\n    v_end,\n    trim(p_location),\n    p_guest_count,\n    'public_booking',\n    jsonb_build_object(\n      'full_name',trim(p_full_name),\n      'phone',nullif(trim(p_phone),''),\n      'email',nullif(trim(p_email),''),\n      'event_type',trim(p_event_type),\n      'event_date',p_event_date,\n      'start_time',p_start_time,\n      'end_time',p_end_time,\n      'guest_count',p_guest_count,\n      'location',trim(p_location),\n      'additional_details',nullif(trim(p_additional_details),'')\n    ),\n    jsonb_build_object('public_source','speedy_panda_customer_site_legacy','tenant_slug',trim(p_tenant_slug))\n  )\n  returning id into v_booking_id;\n\n  return v_booking_id;\nend;\n$function$\n","identity_arguments":"p_tenant_slug text, p_full_name text, p_phone text, p_email text, p_event_type text, p_event_date date, p_start_time time without time zone, p_end_time time without time zone, p_guest_count integer, p_location text, p_additional_details text"},{"name":"submit_public_event_rental_booking_request_v2","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.submit_public_event_rental_booking_request_v2(p_tenant_slug text, p_full_name text, p_phone text, p_email text, p_event_type text, p_event_date date, p_start_time time without time zone, p_end_time time without time zone, p_guest_count integer, p_location text, p_additional_details text DEFAULT NULL::text, p_requested_assets jsonb DEFAULT '[]'::jsonb, p_honeypot text DEFAULT NULL::text, p_request_token text DEFAULT NULL::text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant record;\n  v_booking_id uuid;\n  v_contact_id uuid;\n  v_start timestamptz;\n  v_end timestamptz;\n  v_availability jsonb;\n  v_recent_count integer := 0;\n  v_phone_digits text;\n  v_email text;\nbegin\n  if nullif(trim(p_honeypot),'') is not null then raise exception 'request_rejected'; end if;\n  if nullif(trim(p_tenant_slug),'') is null then raise exception 'tenant_required'; end if;\n  if nullif(trim(p_full_name),'') is null then raise exception 'full_name_required'; end if;\n  if nullif(trim(p_event_type),'') is null then raise exception 'event_type_required'; end if;\n  if p_event_date is null then raise exception 'event_date_required'; end if;\n  if p_event_date < (now() at time zone 'America/New_York')::date then raise exception 'event_date_past'; end if;\n  if p_start_time is null then raise exception 'start_time_required'; end if;\n  if p_end_time is null then raise exception 'end_time_required'; end if;\n  if nullif(trim(p_location),'') is null then raise exception 'location_required'; end if;\n  if nullif(trim(p_phone),'') is null and nullif(trim(p_email),'') is null then raise exception 'contact_required'; end if;\n  if p_guest_count is not null and (p_guest_count < 1 or p_guest_count > 10000) then raise exception 'guest_count_invalid'; end if;\n\n  v_email := nullif(lower(trim(p_email)),'');\n  v_phone_digits := nullif(regexp_replace(coalesce(p_phone,''),'[^0-9]','','g'),'');\n  if v_email is not null and v_email !~* '^[^@[:space:]]+@[^@[:space:]]+\\.[^@[:space:]]+$' then raise exception 'email_invalid'; end if;\n  if v_phone_digits is not null and length(v_phone_digits) < 7 then raise exception 'phone_invalid'; end if;\n\n  v_start := (p_event_date + p_start_time) at time zone 'America/New_York';\n  v_end := (p_event_date + p_end_time) at time zone 'America/New_York';\n  if v_end <= v_start then raise exception 'end_time_invalid'; end if;\n\n  select id,tenant_type,settings,is_active,status,owner_id into v_tenant\n  from public.tenants\n  where lower(company_slug)=lower(trim(p_tenant_slug))\n  limit 1;\n\n  if v_tenant.id is null then raise exception 'tenant_not_found'; end if;\n  if coalesce(v_tenant.is_active,false) is not true or coalesce(v_tenant.status,'') <> 'active' then raise exception 'tenant_unavailable'; end if;\n  if upper(replace(replace(coalesce(v_tenant.tenant_type,''),'-','_'),' ','_')) not in ('EVENT_RENTAL','EVENT_RENTALS','PARTY_RENTAL','PARTY_RENTALS') then raise exception 'tenant_type_not_supported'; end if;\n  if coalesce(v_tenant.settings->'public_presence'->>'required','false')::boolean is not true then raise exception 'public_presence_unavailable'; end if;\n\n  if nullif(trim(p_request_token),'') is not null then\n    select id into v_booking_id\n    from public.event_bookings\n    where tenant_org_id=v_tenant.id::text\n      and source='public_booking'\n      and metadata->>'request_token'=trim(p_request_token)\n    order by created_at desc\n    limit 1;\n    if v_booking_id is not null then\n      return jsonb_build_object('status','received','duplicate',true,'availability',null);\n    end if;\n  end if;\n\n  select count(*)::integer into v_recent_count\n  from public.event_bookings b\n  where b.tenant_org_id=v_tenant.id::text\n    and b.source='public_booking'\n    and b.created_at >= now()-interval '15 minutes'\n    and (\n      (v_email is not null and lower(coalesce(b.raw_intake->>'email',''))=v_email)\n      or\n      (v_phone_digits is not null and regexp_replace(coalesce(b.raw_intake->>'phone',''),'[^0-9]','','g')=v_phone_digits)\n    );\n  if v_recent_count >= 5 then raise exception 'rate_limited'; end if;\n\n  v_availability := public.check_public_event_rental_availability(\n    p_tenant_slug,p_event_date,p_start_time,p_end_time,p_requested_assets\n  );\n  if coalesce((v_availability->>'available')::boolean,false) is not true then\n    raise exception 'requested_assets_unavailable';\n  end if;\n\n  select c.id into v_contact_id\n  from public.unified_contacts c\n  where c.tenant_org_id=v_tenant.id::text\n    and c.deleted_at is null\n    and (\n      (v_email is not null and lower(coalesce(c.email,''))=v_email)\n      or\n      (v_phone_digits is not null and regexp_replace(coalesce(c.phone,''),'[^0-9]','','g')=v_phone_digits)\n    )\n  order by c.updated_at desc nulls last,c.created_at desc nulls last\n  limit 1;\n\n  if v_contact_id is null then\n    insert into public.unified_contacts(\n      tenant_org_id,name,email,phone,address,source,contact_role,raw_data\n    ) values (\n      v_tenant.id::text,\n      trim(p_full_name),\n      nullif(trim(p_email),''),\n      nullif(trim(p_phone),''),\n      trim(p_location),\n      'bookmedirectly',\n      'customer',\n      jsonb_build_object('event_type',trim(p_event_type),'event_date',p_event_date,'source','public_event_rental_booking')\n    )\n    returning id into v_contact_id;\n  end if;\n\n  insert into public.event_bookings(\n    tenant_org_id,contact_id,event_name,event_type,stage,status,event_date,start_time,end_time,location,guest_count,source,source_ref,raw_intake,metadata\n  ) values (\n    v_tenant.id::text,\n    v_contact_id,\n    trim(p_full_name) || ' - ' || trim(p_event_type),\n    trim(p_event_type),\n    'Inquiry',\n    'active',\n    p_event_date,\n    v_start,\n    v_end,\n    trim(p_location),\n    p_guest_count,\n    'public_booking',\n    nullif(trim(p_request_token),''),\n    jsonb_build_object(\n      'full_name',trim(p_full_name),\n      'phone',nullif(trim(p_phone),''),\n      'email',nullif(trim(p_email),''),\n      'event_type',trim(p_event_type),\n      'event_date',p_event_date,\n      'start_time',p_start_time,\n      'end_time',p_end_time,\n      'guest_count',p_guest_count,\n      'location',trim(p_location),\n      'requested_assets',p_requested_assets,\n      'additional_details',nullif(trim(p_additional_details),'')\n    ),\n    jsonb_build_object(\n      'public_source','bookmedirectly_event_rental',\n      'tenant_slug',trim(p_tenant_slug),\n      'request_token',nullif(trim(p_request_token),''),\n      'availability_checked_at',now(),\n      'availability_snapshot',v_availability,\n      'reservation_state','inquiry_not_reserved'\n    )\n  )\n  returning id into v_booking_id;\n\n  if v_tenant.owner_id is not null then\n    insert into public.app_notifications(\n      tenant_id,user_id,source_app,event_type,title,body,severity,destination_path,entity_type,entity_id,metadata,dedupe_key\n    ) values (\n      v_tenant.id,\n      v_tenant.owner_id,\n      'bookmedirectly',\n      'event_rental_booking_request',\n      'New event rental request',\n      trim(p_full_name) || ' requested rentals for ' || p_event_date::text,\n      'info',\n      '/' || trim(p_tenant_slug) || '/apps/booking',\n      'event_booking',\n      v_booking_id::text,\n      jsonb_build_object('contact_id',v_contact_id,'event_date',p_event_date,'source','bookmedirectly'),\n      'event-booking:' || v_booking_id::text\n    )\n    on conflict (tenant_id,user_id,source_app,dedupe_key) do nothing;\n  end if;\n\n  return jsonb_build_object(\n    'status','received',\n    'duplicate',false,\n    'booking_id',v_booking_id,\n    'availability',v_availability,\n    'message','Request received. The rental items are not reserved until the business confirms the booking.'\n  );\nend;\n$function$\n","identity_arguments":"p_tenant_slug text, p_full_name text, p_phone text, p_email text, p_event_type text, p_event_date date, p_start_time time without time zone, p_end_time time without time zone, p_guest_count integer, p_location text, p_additional_details text, p_requested_assets jsonb, p_honeypot text, p_request_token text"},{"name":"submit_public_event_rental_booking_request_v3","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.submit_public_event_rental_booking_request_v3(p_tenant_slug text, p_full_name text, p_phone text, p_email text, p_event_type text, p_event_date date, p_start_time time without time zone, p_end_time time without time zone, p_guest_count integer, p_location text, p_additional_details text DEFAULT NULL::text, p_requested_assets jsonb DEFAULT '[]'::jsonb, p_honeypot text DEFAULT NULL::text, p_request_token text DEFAULT NULL::text, p_terms_accepted boolean DEFAULT false, p_terms_version text DEFAULT 'event-rental-v1'::text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_result jsonb;\n  v_booking_id uuid;\n  v_availability jsonb;\nbegin\n  if coalesce(p_terms_accepted,false) is not true then raise exception 'terms_required'; end if;\n\n  v_availability := public.check_public_event_rental_availability_v2(\n    p_tenant_slug,p_event_date,p_start_time,p_end_time,p_requested_assets\n  );\n  if coalesce((v_availability->>'available')::boolean,false) is not true then\n    raise exception 'requested_assets_unavailable';\n  end if;\n\n  v_result := public.submit_public_event_rental_booking_request_v2(\n    p_tenant_slug,p_full_name,p_phone,p_email,p_event_type,p_event_date,p_start_time,p_end_time,\n    p_guest_count,p_location,p_additional_details,p_requested_assets,p_honeypot,p_request_token\n  );\n\n  if coalesce((v_result->>'duplicate')::boolean,false) is false\n     and coalesce(v_result->>'booking_id','') ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'\n  then\n    v_booking_id := (v_result->>'booking_id')::uuid;\n    update public.event_bookings\n       set raw_intake = coalesce(raw_intake,'{}'::jsonb) || jsonb_build_object(\n             'terms_accepted',true,\n             'terms_version',coalesce(nullif(trim(p_terms_version),''),'event-rental-v1')\n           ),\n           metadata = coalesce(metadata,'{}'::jsonb) || jsonb_build_object(\n             'terms_accepted',true,\n             'terms_version',coalesce(nullif(trim(p_terms_version),''),'event-rental-v1'),\n             'service_area_review_required',true,\n             'availability_snapshot',v_availability\n           ),\n           updated_at = now()\n     where id=v_booking_id;\n  end if;\n\n  return v_result || jsonb_build_object(\n    'availability',v_availability,\n    'terms_accepted',true,\n    'terms_version',coalesce(nullif(trim(p_terms_version),''),'event-rental-v1')\n  );\nend;\n$function$\n","identity_arguments":"p_tenant_slug text, p_full_name text, p_phone text, p_email text, p_event_type text, p_event_date date, p_start_time time without time zone, p_end_time time without time zone, p_guest_count integer, p_location text, p_additional_details text, p_requested_assets jsonb, p_honeypot text, p_request_token text, p_terms_accepted boolean, p_terms_version text"},{"name":"sync_321_lockout_signed_agreement","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_321_lockout_signed_agreement()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  request_id uuid;\nbegin\n  if new.template_type <> '321_auto_unlock_service_authorization'\n     or new.status <> 'signed'\n     or old.status is not distinct from 'signed' then\n    return new;\n  end if;\n\n  if coalesce(new.variables ->> 'LOCKOUT_REQUEST_ID', '') !~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$' then\n    return new;\n  end if;\n\n  request_id := (new.variables ->> 'LOCKOUT_REQUEST_ID')::uuid;\n\n  update public.vehicle_lockout_requests\n     set ownership_confirmed = coalesce(new.variables ->> 'AUTHORITY_BASIS_CODE', '') = 'registered_owner',\n         authorization_consented = true,\n         authorization_name = coalesce(new.signer_name, authorization_name),\n         authorization_at = coalesce(new.signed_at, now()),\n         authorization_signed_at = coalesce(new.signed_at, now()),\n         authorization_agreement_id = new.id,\n         status = case when status = 'awaiting_signature' then 'requested' else status end,\n         updated_at = now()\n   where id = request_id\n     and tenant_id = new.tenant_id;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"sync_lead_score_to_contact","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_lead_score_to_contact()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.subject_type = 'contact' AND NEW.score_type = 'stormscore' THEN\n    UPDATE public.unified_contacts\n    SET lead_score = NEW.score\n    WHERE id = NEW.subject_id\n      AND (lead_score IS DISTINCT FROM NEW.score);\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"sync_linked_contacts","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_linked_contacts()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_link_group UUID;\n  v_shared_fields_changed BOOLEAN;\n  v_claim_stage_changed BOOLEAN;\n  v_linked_tenant RECORD;\n  v_member RECORD;\n  v_actor_name TEXT;\nBEGIN\n  -- Check if any shared core field actually changed\n  -- NOTE: claim_stage is PUBLIC (shared), jobs_stage is PRIVATE (not shared)\n  v_shared_fields_changed := (\n    OLD.name IS DISTINCT FROM NEW.name OR\n    OLD.first_name IS DISTINCT FROM NEW.first_name OR\n    OLD.last_name IS DISTINCT FROM NEW.last_name OR\n    OLD.phone IS DISTINCT FROM NEW.phone OR\n    OLD.email IS DISTINCT FROM NEW.email OR\n    OLD.address IS DISTINCT FROM NEW.address OR\n    OLD.city IS DISTINCT FROM NEW.city OR\n    OLD.state IS DISTINCT FROM NEW.state OR\n    OLD.zip IS DISTINCT FROM NEW.zip OR\n    OLD.claim_stage IS DISTINCT FROM NEW.claim_stage\n  );\n\n  v_claim_stage_changed := (OLD.claim_stage IS DISTINCT FROM NEW.claim_stage);\n\n  IF NOT v_shared_fields_changed THEN\n    RETURN NEW;\n  END IF;\n\n  -- Find the link group for this contact\n  SELECT link_group_id INTO v_link_group\n  FROM contact_links\n  WHERE contact_id = NEW.id\n  LIMIT 1;\n\n  IF v_link_group IS NULL THEN\n    RETURN NEW;\n  END IF;\n\n  -- Get actor name for notifications\n  IF v_claim_stage_changed THEN\n    SELECT name INTO v_actor_name FROM profiles WHERE id = auth.uid() LIMIT 1;\n  END IF;\n\n  -- Propagate shared fields to all other contacts in the same link group\n  -- IMPORTANT: jobs_stage is NOT included — it stays private per tenant\n  UPDATE unified_contacts uc\n  SET\n    name = NEW.name,\n    first_name = NEW.first_name,\n    last_name = NEW.last_name,\n    phone = NEW.phone,\n    email = NEW.email,\n    address = NEW.address,\n    city = NEW.city,\n    state = NEW.state,\n    zip = NEW.zip,\n    claim_stage = NEW.claim_stage,\n    updated_at = now()\n  FROM contact_links cl\n  WHERE cl.link_group_id = v_link_group\n    AND cl.contact_id = uc.id\n    AND cl.contact_id != NEW.id;\n\n  -- If claim_stage changed, notify all users in linked tenants\n  IF v_claim_stage_changed THEN\n    FOR v_linked_tenant IN\n      SELECT cl.tenant_id, cl.contact_id\n      FROM contact_links cl\n      WHERE cl.link_group_id = v_link_group\n        AND cl.contact_id != NEW.id\n    LOOP\n      FOR v_member IN\n        SELECT utm.user_id\n        FROM user_tenant_memberships utm\n        WHERE utm.tenant_id = v_linked_tenant.tenant_id\n          AND utm.status = 'active'\n      LOOP\n        INSERT INTO notification_queue (\n          user_id, title, message, notification_type, severity, metadata, created_at\n        ) VALUES (\n          v_member.user_id,\n          'Claim Stage Updated',\n          COALESCE(NEW.name, 'Contact') || ' claim stage changed to: ' || COALESCE(NEW.claim_stage, 'Unknown'),\n          'shared_contact_update',\n          'info',\n          jsonb_build_object(\n            'link_group_id', v_link_group,\n            'contact_id', v_linked_tenant.contact_id,\n            'source_contact_id', NEW.id,\n            'field', 'claim_stage',\n            'old_value', OLD.claim_stage,\n            'new_value', NEW.claim_stage,\n            'actor_name', v_actor_name,\n            'contact_name', NEW.name\n          ),\n          now()\n        );\n      END LOOP;\n    END LOOP;\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"sync_membership_to_role","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_membership_to_role()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_role public.app_role;\nbegin\n  if coalesce(new.status, '') <> 'active' then\n    delete from public.user_roles ur\n    where ur.user_id = new.user_id\n      and ur.tenant_id = new.tenant_id;\n    return new;\n  end if;\n\n  if exists (\n    select 1\n    from public.user_roles ur\n    where ur.user_id = new.user_id\n      and ur.tenant_id = new.tenant_id\n  ) then\n    return new;\n  end if;\n\n  if exists (\n    select 1\n    from public.user_roles ur\n    where ur.user_id = new.user_id\n      and ur.tenant_id is null\n      and ur.role in ('GodMode'::public.app_role, 'PlatformAdmin'::public.app_role)\n  ) then\n    return new;\n  end if;\n\n  v_role := (\n    case\n      when coalesce(new.is_owner, false) then 'Tenant Owner'\n      else 'Rep'\n    end\n  )::public.app_role;\n\n  insert into public.user_roles(user_id, tenant_id, role)\n  values (new.user_id, new.tenant_id, v_role)\n  on conflict (user_id, tenant_id) do nothing;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"sync_message_push_delivery_receipt","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_message_push_delivery_receipt()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  accepted_count bigint;\n  waiting_count bigint;\n  failure_count bigint;\n  all_count bigint;\n  latest_acceptance timestamptz;\n  provider_ok boolean;\nbegin\n  if new.tenant_id is null\n     or (new.state=old.state and new.provider_accepted_at is not distinct from old.provider_accepted_at)\n     then return new; end if;\n\n  select count(*) filter(where state='accepted'),\n         count(*) filter(where state in ('pending','processing','retry')),\n         count(*) filter(where state in ('failed','expired')),\n         count(*),\n         max(provider_accepted_at) filter(where state='accepted')\n    into accepted_count,waiting_count,failure_count,all_count,latest_acceptance\n    from public.message_push_outbox\n    where message_id=new.message_id\n      and recipient_user_id=new.recipient_user_id\n      and tenant_id=new.tenant_id;\n  if all_count=0 then return new; end if;\n  provider_ok:=accepted_count>0 and latest_acceptance is not null;\n\n  update public.platform_notification_deliveries d\n    set delivery_state=case\n          when provider_ok then 'provider_accepted'\n          when waiting_count>0 or accepted_count>0 then 'queued'\n          when failure_count>0 then 'failed'\n          else 'canceled' end,\n        provider_name=case when provider_ok then 'web-push' else null end,\n        accepted_at=case when provider_ok then latest_acceptance else null end,\n        last_error_code=case\n          when not provider_ok and waiting_count=0 and failure_count>0\n            then 'message_phone_alert_not_accepted'\n          else null end,\n        updated_at=now()\n    from public.notifications n\n    where d.notification_id=n.id and d.channel='push'\n      and n.type='message_received'\n      and n.user_id=new.recipient_user_id\n      and n.tenant_id=new.tenant_id::text\n      and n.metadata->>'dedupe_key'='message:'||new.message_id::text;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"sync_mobile_vendor_event_expenses_to_finance","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_mobile_vendor_event_expenses_to_finance()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_tenant_id uuid := public.business_activity_safe_uuid(new.tenant_org_id);\n  is_mobile_vendor boolean := false;\n  expense_key text;\n  expense_label text;\n  raw_amount text;\n  expense_amount numeric(12,2);\n  external_id text;\nbegin\n  if v_tenant_id is null then\n    return new;\n  end if;\n\n  select coalesce(settings->>'workspace_type','') = 'mobile_vendor' or company_slug = 'big-papis'\n    into is_mobile_vendor\n  from public.tenants\n  where id = v_tenant_id;\n\n  if not coalesce(is_mobile_vendor, false) then\n    return new;\n  end if;\n\n  for expense_key, expense_label in\n    select * from (values\n      ('rental','Rental'),\n      ('product','Product'),\n      ('fuel','Fuel'),\n      ('food','Food'),\n      ('other','Other')\n    ) as expense_categories(key, label)\n  loop\n    raw_amount := trim(coalesce(new.expenses->>expense_key, ''));\n    expense_amount := case\n      when raw_amount ~ '^([0-9]+([.][0-9]{1,2})?|[.][0-9]{1,2})$' then raw_amount::numeric\n      else 0\n    end;\n    external_id := 'event:' || new.id::text || ':expense:' || expense_key;\n\n    if expense_amount > 0 then\n      insert into public.finance_transactions (\n        tenant_id, source, provider, provider_external_id, transaction_date, posted_at,\n        merchant, description, amount, direction, transaction_type, category,\n        classification, notes, receipt_document_ref, metadata, created_by, updated_at\n      ) values (\n        v_tenant_id,\n        'mobile_vendor_event_expense',\n        'manual',\n        external_id,\n        coalesce(new.event_date, current_date),\n        now(),\n        coalesce((select company_dba_name from public.tenants where id = v_tenant_id), (select name from public.tenants where id = v_tenant_id), 'Mobile vendor'),\n        coalesce(new.event_name, 'Event') || ' · ' || expense_label || ' expense',\n        expense_amount,\n        'expense',\n        'event_expense',\n        expense_label,\n        'business',\n        null,\n        null,\n        jsonb_build_object('record_class','business','event_booking_id',new.id,'expense_key',expense_key),\n        null,\n        now()\n      )\n      on conflict (tenant_id, source, provider_external_id)\n      do update set transaction_date=excluded.transaction_date, posted_at=excluded.posted_at,\n        merchant=excluded.merchant, description=excluded.description, amount=excluded.amount,\n        category=excluded.category, metadata=excluded.metadata, updated_at=now();\n    else\n      delete from public.finance_transactions\n      where tenant_id=v_tenant_id and source='mobile_vendor_event_expense' and provider_external_id=external_id;\n    end if;\n  end loop;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"sync_pcg_submission_stage_from_cards","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_pcg_submission_stage_from_cards()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  target_submission uuid;\n  next_status text;\n  current_status text;\n  submission_number_value text;\n  current_lifecycle text;\n  current_deleted_at timestamptz;\nbegin\n  target_submission := coalesce(new.submission_id, old.submission_id);\n  if target_submission is null then return coalesce(new, old); end if;\n\n  select status, submission_number, lifecycle_state, deleted_at\n    into current_status, submission_number_value, current_lifecycle, current_deleted_at\n  from public.card_grading_submissions\n  where id = target_submission;\n\n  if submission_number_value='PCG-INVENTORY' then\n    if current_status is distinct from 'encapsulation' then\n      update public.card_grading_submissions set status='encapsulation',updated_at=now()\n      where id=target_submission;\n    end if;\n    return coalesce(new,old);\n  end if;\n\n  if current_deleted_at is not null or coalesce(current_lifecycle,'active') <> 'active' then\n    return coalesce(new,old);\n  end if;\n\n  if exists (\n    select 1 from public.card_grading_exceptions e\n    where e.submission_id=target_submission and e.kind='hold' and e.status='open'\n  ) then\n    return coalesce(new,old);\n  end if;\n\n  if lower(coalesce(current_status,'')) in ('shipped','picked_up','delivered','closed') then\n    return coalesce(new,old);\n  end if;\n\n  select c.status into next_status\n  from public.card_grading_cards c\n  where c.submission_id=target_submission and coalesce(c.is_demo,false)=false\n  order by public.pcg_stage_rank(c.status) asc, c.sequence_number asc nulls last\n  limit 1;\n\n  if next_status is not null and next_status is distinct from current_status then\n    update public.card_grading_submissions\n      set status=next_status,updated_at=now()\n    where id=target_submission\n      and deleted_at is null\n      and lifecycle_state='active'\n      and lower(coalesce(status,'')) not in ('shipped','picked_up','delivered','closed');\n  end if;\n  return coalesce(new,old);\nend;\n$function$\n","identity_arguments":""},{"name":"sync_primary_tenant_logo_pointer","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_primary_tenant_logo_pointer()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if new.collection_key = 'branding'\n     and new.is_primary = true\n     and new.deleted_at is null then\n    update public.tenants\n    set company_logo_url = case\n          when company_logo_url like '%/functions/v1/tenant-media-library?mode=asset&id=%'\n            then regexp_replace(company_logo_url, 'id=[^&]+', 'id=' || new.id::text)\n          else 'https://ymntrajfubicyxwwdxxa.supabase.co/functions/v1/tenant-media-library?mode=asset&id=' || new.id::text\n        end,\n        settings = jsonb_set(\n          jsonb_set(coalesce(settings, '{}'::jsonb), '{media_branding,resolved_logo_asset_id}', to_jsonb(new.id::text), true),\n          '{media_branding,resolved_logo_version}',\n          to_jsonb(new.updated_at::text),\n          true\n        ),\n        updated_at = now()\n    where id = new.tenant_id;\n  end if;\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"sync_profile_role_from_user_roles","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_profile_role_from_user_roles()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE v_user_id uuid; v_new_primary text; v_old_primary text;\nBEGIN\n  v_user_id := COALESCE(NEW.user_id, OLD.user_id);\n  IF v_user_id IS NULL THEN RETURN COALESCE(NEW, OLD); END IF;\n  v_new_primary := public.compute_primary_role_for_user(v_user_id);\n  SELECT role INTO v_old_primary FROM public.profiles WHERE id = v_user_id;\n  UPDATE public.profiles\n  SET role = COALESCE(v_new_primary, 'Rep'), updated_at = now()\n  WHERE id = v_user_id\n    AND COALESCE(role, '') IS DISTINCT FROM COALESCE(v_new_primary, 'Rep');\n  IF COALESCE(v_old_primary, '') IS DISTINCT FROM COALESCE(v_new_primary, 'Rep') THEN\n    INSERT INTO public.comprehensive_audit_logs (\n      user_id, tenant_id, event_type, event_category, event_action,\n      resource_type, resource_id, old_value, new_value, severity, human_summary\n    ) VALUES (\n      auth.uid(), COALESCE(NEW.tenant_id, OLD.tenant_id),\n      'role_change', 'security', lower(TG_OP) || '_user_role',\n      'user_roles', v_user_id::text,\n      jsonb_build_object('role', v_old_primary),\n      jsonb_build_object('role', v_new_primary),\n      'warn',\n      'Primary role for user ' || v_user_id::text || ' changed: ' ||\n        COALESCE(v_old_primary, '(none)') || ' -> ' || COALESCE(v_new_primary, '(none)')\n    );\n  END IF;\n  RETURN COALESCE(NEW, OLD);\nEND;\n$function$\n","identity_arguments":""},{"name":"sync_proposal_render_to_document_family","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_proposal_render_to_document_family()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare v_document_id uuid;\nbegin\n if new.render_path is null or new.render_bucket is null then return new; end if;\n begin v_document_id:=nullif(new.metadata->>'canonicalDocumentId','')::uuid; exception when others then v_document_id:=null; end;\n if v_document_id is null then\n  insert into public.documents(scope,category,name,mime_type,uploaded_by,metadata,tenant_id) values('tenant','proposal',new.proposal_number||'.pdf','application/pdf',new.created_by,jsonb_build_object('documentFamily','proposal','proposalId',new.id,'proposalVersion',new.current_version,'storageBucket',new.render_bucket,'storagePath',new.render_path,'renderHash',new.render_hash),new.tenant_id) returning id into v_document_id;\n  new.metadata:=coalesce(new.metadata,'{}'::jsonb)||jsonb_build_object('canonicalDocumentId',v_document_id,'documentFamily','proposal');\n else\n  update public.documents set name=new.proposal_number||'.pdf',mime_type='application/pdf',metadata=coalesce(metadata,'{}'::jsonb)||jsonb_build_object('proposalVersion',new.current_version,'storageBucket',new.render_bucket,'storagePath',new.render_path,'renderHash',new.render_hash) where id=v_document_id;\n end if;\n insert into public.document_activity(tenant_org_id,document_id,document_type,activity_type,activity_data,user_id) values(new.tenant_id::text,v_document_id::text,'proposal','proposal_rendered',jsonb_build_object('proposal_id',new.id,'proposal_version',new.current_version,'render_hash',new.render_hash),new.created_by); return new;\nend;$function$\n","identity_arguments":""},{"name":"sync_role_to_membership","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_role_to_membership()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  if new.tenant_id is null then\n    return new;\n  end if;\n\n  insert into public.user_tenant_memberships (\n    user_id,\n    tenant_id,\n    is_owner,\n    status\n  )\n  values (\n    new.user_id,\n    new.tenant_id,\n    new.role::text in ('Owner', 'Tenant Owner'),\n    'active'\n  )\n  on conflict (user_id, tenant_id) do update\n    set status = 'active',\n        is_owner = excluded.is_owner;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"sync_task_calendar_projection","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_task_calendar_projection()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_assigned_email text;\n  v_start timestamptz;\nBEGIN\n  IF TG_OP = 'DELETE' THEN\n    DELETE FROM public.user_calendar_events\n    WHERE tenant_org_id = OLD.tenant_id\n      AND metadata->>'source_kind' = 'task'\n      AND metadata->>'task_id' = OLD.id::text;\n    RETURN OLD;\n  END IF;\n\n  IF NEW.due_date IS NULL AND NEW.reminder_at IS NULL THEN\n    DELETE FROM public.user_calendar_events\n    WHERE tenant_org_id = NEW.tenant_id\n      AND metadata->>'source_kind' = 'task'\n      AND metadata->>'task_id' = NEW.id::text;\n    RETURN NEW;\n  END IF;\n\n  IF NEW.assigned_to IS NOT NULL THEN\n    SELECT email INTO v_assigned_email FROM public.profiles WHERE id = NEW.assigned_to;\n  END IF;\n\n  v_start := COALESCE(NEW.due_date, NEW.reminder_at);\n\n  INSERT INTO public.user_calendar_events (\n    tenant_org_id,\n    user_id,\n    assigned_to,\n    contact_id,\n    claim_id,\n    title,\n    description,\n    event_type,\n    status,\n    start_time,\n    reminder_at,\n    is_auto_generated,\n    metadata,\n    all_day\n  ) VALUES (\n    NEW.tenant_id,\n    NEW.user_id,\n    v_assigned_email,\n    NEW.canonical_contact_id,\n    NEW.claim_id::text,\n    NEW.title,\n    NEW.description,\n    'task',\n    CASE WHEN lower(COALESCE(NEW.status, 'pending')) = 'completed' THEN 'completed' ELSE 'scheduled' END,\n    v_start,\n    NEW.reminder_at,\n    true,\n    COALESCE(NEW.metadata, '{}'::jsonb) || jsonb_build_object(\n      'source_kind', 'task',\n      'task_id', NEW.id::text,\n      'task_status', COALESCE(NEW.status, 'pending'),\n      'projection_version', 1\n    ),\n    false\n  )\n  ON CONFLICT (tenant_org_id, ((metadata->>'task_id')))\n  WHERE (metadata->>'source_kind' = 'task' AND metadata ? 'task_id')\n  DO UPDATE SET\n    user_id = EXCLUDED.user_id,\n    assigned_to = EXCLUDED.assigned_to,\n    contact_id = EXCLUDED.contact_id,\n    claim_id = EXCLUDED.claim_id,\n    title = EXCLUDED.title,\n    description = EXCLUDED.description,\n    status = EXCLUDED.status,\n    start_time = EXCLUDED.start_time,\n    reminder_at = EXCLUDED.reminder_at,\n    is_auto_generated = true,\n    metadata = EXCLUDED.metadata,\n    updated_at = now();\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"sync_tenant_is_trial","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_tenant_is_trial()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF TG_OP = 'INSERT' THEN\n    UPDATE public.tenants SET is_trial = true, trial_account_id = NEW.id WHERE id = NEW.tenant_id;\n  ELSIF TG_OP = 'DELETE' THEN\n    UPDATE public.tenants SET is_trial = false, trial_account_id = NULL WHERE id = OLD.tenant_id;\n  END IF;\n  RETURN COALESCE(NEW, OLD);\nEND;\n$function$\n","identity_arguments":""},{"name":"sync_tenant_public_presence_readiness","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_tenant_public_presence_readiness()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_slug text := lower(trim(coalesce(new.company_slug,'')));\n  v_progress_url text;\n  v_booking_url text;\nbegin\n  if v_slug='' then\n    insert into public.tenant_readiness_checks(tenant_id,check_key,status,detail)\n    values(new.id,'customer_entry','blocked',jsonb_build_object(\n      'required',true,'contract','TENANT_PUBLIC_PRESENCE_V1','reason','canonical_tenant_slug_required'\n    ))\n    on conflict(tenant_id,check_key) do update\n      set status=excluded.status,detail=excluded.detail,updated_at=now();\n    return new;\n  end if;\n  v_progress_url := 'https://whatsmyprogress.com/'||v_slug||'/';\n  v_booking_url := 'https://bookmedirectly.com/'||v_slug||'/';\n  insert into public.tenant_readiness_checks(tenant_id,check_key,status,detail)\n  values(new.id,'customer_entry','ready',jsonb_build_object(\n    'required',true,\n    'contract','TENANT_PUBLIC_PRESENCE_V1',\n    'public_route',v_progress_url,\n    'booking_route',v_booking_url,\n    'surfaces',jsonb_build_array('bookmedirectly','whatsmyprogress')\n  ))\n  on conflict(tenant_id,check_key) do update\n    set status=excluded.status,detail=excluded.detail,updated_at=now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"sync_to_unified_inbox","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.sync_to_unified_inbox(p_tenant_id uuid, p_contact_id uuid, p_channel text, p_direction text, p_subject text, p_body text, p_from_address text, p_to_address text, p_external_id text DEFAULT NULL::text, p_metadata jsonb DEFAULT '{}'::jsonb)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_inbox_id UUID;\n  v_preview TEXT;\nBEGIN\n  v_preview := LEFT(REGEXP_REPLACE(p_body, '<[^>]+>', '', 'g'), 100);\n  \n  INSERT INTO public.unified_inbox (\n    tenant_id, contact_id, channel, direction, subject, body, preview,\n    from_address, to_address, external_id, metadata,\n    sent_at, is_read\n  ) VALUES (\n    p_tenant_id, p_contact_id, p_channel, p_direction, p_subject, p_body, v_preview,\n    p_from_address, p_to_address, p_external_id, p_metadata,\n    CASE WHEN p_direction = 'outbound' THEN now() ELSE NULL END,\n    p_direction = 'outbound'\n  ) RETURNING id INTO v_inbox_id;\n  \n  RETURN v_inbox_id;\nEND;\n$function$\n","identity_arguments":"p_tenant_id uuid, p_contact_id uuid, p_channel text, p_direction text, p_subject text, p_body text, p_from_address text, p_to_address text, p_external_id text, p_metadata jsonb"},{"name":"system_backup_authorize","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.system_backup_authorize(p_token text)\n RETURNS boolean\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public', 'vault', 'extensions'\nAS $function$\n  select coalesce((\n    select extensions.digest(ds.decrypted_secret, 'sha256') = extensions.digest(coalesce(p_token,''), 'sha256')\n    from vault.decrypted_secrets ds\n    where ds.name = 'knocklaunch_system_backup_trigger'\n    limit 1\n  ), false);\n$function$\n","identity_arguments":"p_token text"},{"name":"system_backup_catalog_snapshot","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.system_backup_catalog_snapshot()\n RETURNS jsonb\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public', 'private', 'auth', 'storage', 'supabase_migrations', 'extensions'\n SET statement_timeout TO '60s'\nAS $function$\n  select jsonb_build_object(\n    'format','knocklaunch-database-catalog-v1','captured_at',now(),'database',current_database(),'server_version',current_setting('server_version'),\n    'extensions',(select coalesce(jsonb_agg(jsonb_build_object('name',e.extname,'version',e.extversion) order by e.extname),'[]'::jsonb) from pg_extension e),\n    'tables',(\n      select coalesce(jsonb_agg(jsonb_build_object(\n        'schema',n.nspname,'table',c.relname,\n        'columns',(select coalesce(jsonb_agg(jsonb_build_object('name',a.attname,'type',pg_catalog.format_type(a.atttypid,a.atttypmod),'not_null',a.attnotnull,'default',pg_get_expr(ad.adbin,ad.adrelid),'identity',a.attidentity,'generated',a.attgenerated) order by a.attnum),'[]'::jsonb) from pg_attribute a left join pg_attrdef ad on ad.adrelid=a.attrelid and ad.adnum=a.attnum where a.attrelid=c.oid and a.attnum>0 and not a.attisdropped),\n        'constraints',(select coalesce(jsonb_agg(jsonb_build_object('name',con.conname,'definition',pg_get_constraintdef(con.oid,true)) order by con.conname),'[]'::jsonb) from pg_constraint con where con.conrelid=c.oid),\n        'indexes',(select coalesce(jsonb_agg(jsonb_build_object('name',ci.relname,'definition',pg_get_indexdef(ci.oid)) order by ci.relname),'[]'::jsonb) from pg_index ix join pg_class ci on ci.oid=ix.indexrelid where ix.indrelid=c.oid),\n        'triggers',(select coalesce(jsonb_agg(jsonb_build_object('name',tg.tgname,'definition',pg_get_triggerdef(tg.oid,true)) order by tg.tgname),'[]'::jsonb) from pg_trigger tg where tg.tgrelid=c.oid and not tg.tgisinternal),\n        'policies',(select coalesce(jsonb_agg(to_jsonb(p) order by p.policyname),'[]'::jsonb) from pg_policies p where p.schemaname=n.nspname and p.tablename=c.relname)\n      ) order by n.nspname,c.relname),'[]'::jsonb)\n      from pg_class c join pg_namespace n on n.oid=c.relnamespace\n      where c.relkind='r' and n.nspname in ('public','private','auth','storage','supabase_migrations')\n        and not (n.nspname='public' and c.relname in ('system_backup_runs','system_backup_items'))\n    ),\n    'views',(select coalesce(jsonb_agg(jsonb_build_object('schema',n.nspname,'name',c.relname,'definition',pg_get_viewdef(c.oid,true)) order by n.nspname,c.relname),'[]'::jsonb) from pg_class c join pg_namespace n on n.oid=c.relnamespace where c.relkind in ('v','m') and n.nspname in ('public','private','auth','storage')),\n    'routines',(select coalesce(jsonb_agg(jsonb_build_object('schema',n.nspname,'name',p.proname,'identity_arguments',pg_get_function_identity_arguments(p.oid),'definition',pg_get_functiondef(p.oid)) order by n.nspname,p.proname,pg_get_function_identity_arguments(p.oid)),'[]'::jsonb) from pg_proc p join pg_namespace n on n.oid=p.pronamespace where n.nspname in ('public','private') and p.prokind in ('f','p')),\n    'cron_jobs',(select coalesce(jsonb_agg(jsonb_build_object('jobname',j.jobname,'schedule',j.schedule,'command',j.command,'active',j.active) order by j.jobid),'[]'::jsonb) from cron.job j),\n    'vault_secret_names',(select coalesce(jsonb_agg(jsonb_build_object('name',s.name,'description',s.description) order by s.name),'[]'::jsonb) from vault.secrets s),\n    'migration_history',(select coalesce(jsonb_agg(jsonb_build_object('version',m.version,'name',m.name) order by m.version),'[]'::jsonb) from supabase_migrations.schema_migrations m)\n  );\n$function$\n","identity_arguments":""},{"name":"system_backup_export_chunk","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.system_backup_export_chunk(p_item_id bigint)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'private', 'auth', 'storage', 'supabase_migrations', 'pg_temp'\n SET statement_timeout TO '20s'\nAS $function$\ndeclare\n  i public.system_backup_items%rowtype;\n  v_data jsonb;\n  v_rows integer;\n  v_pk_col text;\nbegin\n  select * into i\n  from public.system_backup_items\n  where id = p_item_id;\n\n  if i.id is null or i.kind <> 'database_chunk' then\n    raise exception 'backup_item_not_database_chunk';\n  end if;\n\n  if i.source_schema not in ('public','private','auth','storage','supabase_migrations') then\n    raise exception 'backup_schema_not_allowed';\n  end if;\n\n  if i.source_schema = 'public'\n     and i.source_table in ('system_backup_runs','system_backup_items') then\n    raise exception 'backup_internal_table_excluded';\n  end if;\n\n  if coalesce(i.row_limit, 0) = 0 then\n    v_data := '[]'::jsonb;\n  else\n    select a.attname\n      into v_pk_col\n    from pg_index ix\n    join pg_class c on c.oid = ix.indrelid\n    join pg_namespace n on n.oid = c.relnamespace\n    join pg_attribute a\n      on a.attrelid = ix.indrelid\n     and a.attnum = ix.indkey[0]\n    where ix.indisprimary\n      and array_length(ix.indkey, 1) = 1\n      and n.nspname = i.source_schema\n      and c.relname = i.source_table\n    limit 1;\n\n    if v_pk_col is not null then\n      execute format(\n        'select coalesce(jsonb_agg(to_jsonb(t)), ''[]''::jsonb)\n           from (\n             select * from %I.%I\n             order by %I\n             offset %s limit %s\n           ) t',\n        i.source_schema,\n        i.source_table,\n        v_pk_col,\n        greatest(coalesce(i.row_offset, 0), 0),\n        greatest(coalesce(i.row_limit, 0), 0)\n      )\n      into v_data;\n    else\n      execute format(\n        'select coalesce(jsonb_agg(to_jsonb(t)), ''[]''::jsonb)\n           from (\n             select * from %I.%I\n             order by ctid\n             offset %s limit %s\n           ) t',\n        i.source_schema,\n        i.source_table,\n        greatest(coalesce(i.row_offset, 0), 0),\n        greatest(coalesce(i.row_limit, 0), 0)\n      )\n      into v_data;\n    end if;\n  end if;\n\n  v_rows := jsonb_array_length(v_data);\n\n  return jsonb_build_object(\n    'format', 'knocklaunch-table-chunk-v1',\n    'schema', i.source_schema,\n    'table', i.source_table,\n    'offset', coalesce(i.row_offset, 0),\n    'limit', coalesce(i.row_limit, 0),\n    'order_key', coalesce(v_pk_col, 'ctid'),\n    'rows', v_rows,\n    'data', v_data\n  );\nend;\n$function$\n","identity_arguments":"p_item_id bigint"},{"name":"system_backup_lease_items","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.system_backup_lease_items(p_run_id uuid, p_limit integer DEFAULT 1)\n RETURNS SETOF system_backup_items\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  with picked as (\n    select i.id from public.system_backup_items i\n    where i.run_id=p_run_id and ((i.status='pending' and i.next_attempt_at<=now()) or (i.status='processing' and i.lease_until<now()))\n    order by case i.kind when 'database_catalog' then 0 when 'database_chunk' then 1 else 2 end,i.id\n    for update skip locked limit greatest(1,least(coalesce(p_limit,1),10))\n  )\n  update public.system_backup_items i\n  set status='processing',attempts=i.attempts+1,lease_until=now()+interval '6 minutes',started_at=coalesce(i.started_at,now()),updated_at=now(),error=null\n  from picked where i.id=picked.id returning i.*;\n$function$\n","identity_arguments":"p_run_id uuid, p_limit integer"},{"name":"system_backup_prepare","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.system_backup_prepare(p_trigger_source text DEFAULT 'manual'::text, p_source_main_sha text DEFAULT NULL::text, p_force boolean DEFAULT false, p_chunk_rows integer DEFAULT 500)\n RETURNS uuid\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'private', 'auth', 'storage', 'supabase_migrations', 'extensions'\n SET statement_timeout TO '120s'\nAS $function$\ndeclare\n  v_run_id uuid;\n  v_existing uuid;\n  v_migration_head text;\n  v_database_bytes bigint;\n  v_storage_count bigint;\n  v_storage_bytes bigint;\n  v_count bigint;\n  v_offset bigint;\n  v_chunk integer := greatest(100, least(coalesce(p_chunk_rows, 500), 2000));\n  r record;\nbegin\n  if not p_force then\n    select id into v_existing\n    from public.system_backup_runs\n    where status in ('preparing','running','verifying')\n      and requested_at > now() - interval '24 hours'\n    order by requested_at desc\n    limit 1;\n    if v_existing is not null then\n      return v_existing;\n    end if;\n  end if;\n\n  select version || ' ' || name\n  into v_migration_head\n  from supabase_migrations.schema_migrations\n  order by version desc\n  limit 1;\n\n  select pg_database_size(current_database())::bigint into v_database_bytes;\n\n  select\n    count(*)::bigint,\n    coalesce(sum(case when (metadata->>'size') ~ '^[0-9]+$' then (metadata->>'size')::bigint else 0 end),0)::bigint\n  into v_storage_count, v_storage_bytes\n  from storage.objects;\n\n  insert into public.system_backup_runs(\n    trigger_source, started_at, status, source_main_sha, migration_head,\n    database_bytes, storage_object_count, storage_bytes, metadata\n  )\n  values (\n    left(coalesce(nullif(trim(p_trigger_source),''),'manual'),80),\n    now(),\n    'preparing',\n    nullif(trim(coalesce(p_source_main_sha,'')),''),\n    v_migration_head,\n    v_database_bytes,\n    v_storage_count,\n    v_storage_bytes,\n    jsonb_build_object(\n      'format','knocklaunch-full-data-backup-v1',\n      'database_consistency','best_effort_logical_plus_supabase_native_physical',\n      'schemas',jsonb_build_array('public','private','auth','storage','supabase_migrations'),\n      'storage_objects_included',true,\n      'secret_values_included',false,\n      'secret_names_cataloged',true,\n      'chunk_rows',v_chunk\n    )\n  )\n  returning id into v_run_id;\n\n  insert into public.system_backup_items(run_id, kind, row_offset, row_limit, metadata)\n  values (v_run_id, 'database_catalog', 0, 1, jsonb_build_object('format','catalog-v1'));\n\n  for r in\n    select n.nspname as schema_name, c.relname as table_name\n    from pg_class c\n    join pg_namespace n on n.oid=c.relnamespace\n    where c.relkind='r'\n      and n.nspname in ('public','private','auth','storage','supabase_migrations')\n      and not (n.nspname='public' and c.relname in ('system_backup_runs','system_backup_items'))\n    order by n.nspname,c.relname\n  loop\n    execute format('select count(*)::bigint from %I.%I',r.schema_name,r.table_name) into v_count;\n\n    if v_count=0 then\n      insert into public.system_backup_items(\n        run_id,kind,source_schema,source_table,row_offset,row_limit,metadata\n      )\n      values (\n        v_run_id,'database_chunk',r.schema_name,r.table_name,0,0,\n        jsonb_build_object('table_rows_at_prepare',0)\n      );\n    else\n      v_offset:=0;\n      while v_offset<v_count loop\n        insert into public.system_backup_items(\n          run_id,kind,source_schema,source_table,row_offset,row_limit,metadata\n        )\n        values (\n          v_run_id,'database_chunk',r.schema_name,r.table_name,v_offset,v_chunk,\n          jsonb_build_object('table_rows_at_prepare',v_count)\n        );\n        v_offset:=v_offset+v_chunk;\n      end loop;\n    end if;\n  end loop;\n\n  insert into public.system_backup_items(\n    run_id,kind,source_bucket,source_object,source_object_id,source_updated_at,\n    source_size,source_fingerprint,artifact_key,metadata\n  )\n  select\n    v_run_id,\n    'storage_object',\n    o.bucket_id,\n    o.name,\n    o.id::text,\n    coalesce(o.updated_at,o.created_at,now()),\n    case when (o.metadata->>'size') ~ '^[0-9]+$' then (o.metadata->>'size')::bigint else 0 end,\n    encode(\n      extensions.digest(\n        concat_ws('|',o.bucket_id,o.id::text,coalesce(o.updated_at,o.created_at)::text,\n          coalesce(o.metadata->>'size','0'),coalesce(o.metadata->>'mimetype','')),\n        'sha256'\n      ),\n      'hex'\n    ),\n    'blobs/storage/'||\n      regexp_replace(o.bucket_id,'[^a-zA-Z0-9._-]+','-','g')||'/'||\n      o.id::text||'/'||\n      encode(\n        extensions.digest(\n          concat_ws('|',o.bucket_id,o.id::text,coalesce(o.updated_at,o.created_at)::text,\n            coalesce(o.metadata->>'size','0'),coalesce(o.metadata->>'mimetype','')),\n          'sha256'\n        ),\n        'hex'\n      ),\n    jsonb_build_object('mime_type',o.metadata->>'mimetype')\n  from storage.objects o;\n\n  update public.system_backup_runs\n  set\n    item_count=(select count(*) from public.system_backup_items where run_id=v_run_id),\n    status='running'\n  where id=v_run_id;\n\n  return v_run_id;\nexception when others then\n  if v_run_id is not null then\n    update public.system_backup_runs\n    set status='failed',completed_at=now(),error=left(sqlerrm,2000)\n    where id=v_run_id;\n  end if;\n  raise;\nend;\n$function$\n","identity_arguments":"p_trigger_source text, p_source_main_sha text, p_force boolean, p_chunk_rows integer"},{"name":"system_backup_r2_identity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.system_backup_r2_identity()\n RETURNS jsonb\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public', 'vault'\nAS $function$\n  select coalesce((select decrypted_secret::jsonb from vault.decrypted_secrets where name='knocklaunch_system_backup_r2_identity' limit 1),'{}'::jsonb);\n$function$\n","identity_arguments":""},{"name":"system_backup_store_r2_identity","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.system_backup_store_r2_identity(p_account_id text, p_api_token text)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'vault'\nAS $function$\ndeclare\n  v_id uuid;\n  v_payload text;\nbegin\n  if coalesce(length(trim(p_account_id)),0) <> 32 then raise exception 'backup_r2_account_id_invalid'; end if;\n  if coalesce(length(trim(p_api_token)),0) < 40 then raise exception 'backup_r2_token_invalid'; end if;\n  v_payload := jsonb_build_object('accountId',trim(p_account_id),'apiToken',trim(p_api_token))::text;\n  select id into v_id from vault.secrets where name='knocklaunch_system_backup_r2_identity' limit 1;\n  if v_id is null then\n    perform vault.create_secret(v_payload,'knocklaunch_system_backup_r2_identity','Dedicated Cloudflare R2 object token for KNOCKLAUNCH full backups.');\n  else\n    perform vault.update_secret(v_id,v_payload,'knocklaunch_system_backup_r2_identity','Dedicated Cloudflare R2 object token for KNOCKLAUNCH full backups.');\n  end if;\nend;\n$function$\n","identity_arguments":"p_account_id text, p_api_token text"},{"name":"tenant_allowed_zips","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tenant_allowed_zips(_tenant_id uuid)\n RETURNS text[]\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\n  SELECT ta.allowed_zip_codes\n  FROM public.trial_accounts ta\n  WHERE ta.tenant_id = _tenant_id\n    AND (\n      coalesce(auth.role(), '') = 'service_role'\n      OR public.is_system_admin(auth.uid())\n      OR public.is_tenant_member(auth.uid(), _tenant_id)\n    )\n  LIMIT 1;\n$function$\n","identity_arguments":"_tenant_id uuid"},{"name":"tenant_blueprint_applications","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tenant_blueprint_applications(p_model text)\n RETURNS jsonb\n LANGUAGE sql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\nselect case p_model\n  when 'appointments' then '[\"booking\",\"contacts\",\"calendar\",\"communications\",\"invoices\",\"documents\",\"tasks\",\"analytics\",\"opportunity-radar\"]'::jsonb\n  when 'recurring_routes' then '[\"route-service-operations\",\"jobs\",\"contacts\",\"calendar\",\"communications\",\"invoices\",\"documents\",\"tasks\",\"analytics\",\"opportunity-radar\"]'::jsonb\n  when 'events' then '[\"booking\",\"jobs\",\"contacts\",\"calendar\",\"communications\",\"invoices\",\"documents\",\"tasks\",\"analytics\",\"opportunity-radar\",\"proposals\",\"payments\"]'::jsonb\n  when 'orders' then '[\"jobs\",\"contacts\",\"communications\",\"invoices\",\"documents\",\"analytics\",\"opportunity-radar\",\"payments\"]'::jsonb\n  when 'professional_cases' then '[\"contacts\",\"calendar\",\"communications\",\"documents\",\"tasks\",\"analytics\",\"opportunity-radar\"]'::jsonb\n  when 'service_jobs' then '[\"jobs\",\"contacts\",\"calendar\",\"communications\",\"invoices\",\"documents\",\"tasks\",\"analytics\",\"opportunity-radar\",\"forms\",\"proposals\",\"payments\"]'::jsonb\n  when 'general' then '[\"jobs\",\"contacts\",\"calendar\",\"communications\",\"invoices\",\"documents\",\"tasks\",\"analytics\",\"opportunity-radar\"]'::jsonb\n  else '[\"jobs\",\"contacts\",\"calendar\",\"communications\",\"invoices\",\"documents\",\"tasks\",\"analytics\",\"opportunity-radar\"]'::jsonb\nend;\n$function$\n","identity_arguments":"p_model text"},{"name":"tenant_operating_model_for","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tenant_operating_model_for(p_business_type text, p_settings jsonb DEFAULT '{}'::jsonb)\n RETURNS text\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'public'\nAS $function$\ndeclare\n  v_type text := public.normalize_declared_business_type(p_business_type);\n  v_model text := lower(trim(coalesce(\n    p_settings #>> '{business_operating_blueprint,operatingModel}',\n    p_settings #>> '{tenant_manifest,businessOperatingBlueprint,operatingModel}',\n    p_settings #>> '{tenant_manifest,adaptiveBusinessProfile,operatingModel}',\n    p_settings #>> '{adaptive_business_profile,operatingModel}',\n    p_settings ->> 'operating_model',\n    ''\n  )));\nbegin\n  if v_model in ('service_jobs','recurring_routes','appointments','professional_cases','orders','events','general') then return v_model; end if;\n  if v_type is null then return null; end if;\n  if v_type = 'MISC' then return 'general'; end if;\n  if v_type in ('CUSTOMER_PROGRESS_PLATFORM','ROOFING_LEAD_FUNNEL') or v_type ~ '(LEAD_FUNNEL|PROGRESS_PLATFORM|SAAS_PLATFORM)' then return 'general'; end if;\n  if v_type ~ '(BARBER|SALON|SPA|NAIL|MASSAGE|TATTOO|MEDSPA|DENTAL|DENTIST|CHIROPRACT|THERAP|APPOINTMENT)' then return 'appointments'; end if;\n  if v_type in ('LAWN_CARE') or v_type ~ '(POOL|PEST|ROUTE|RECURRING_SERVICE)' then return 'recurring_routes'; end if;\n  if v_type in ('MOBILE_VENDOR') or v_type ~ '(CATER|EVENT|WEDDING|VENUE)' then return 'events'; end if;\n  if v_type in ('CAFE_QSR') or v_type ~ '(RETAIL|BAKERY|ORDER|RESTAURANT)' then return 'orders'; end if;\n  if v_type in ('PUBLIC_ADJUSTER_FIRM','REALTOR') or v_type ~ '(LAW|LEGAL|ACCOUNT|CONSULT|CASE_MANAGEMENT)' then return 'professional_cases'; end if;\n  if v_type in ('MITIGATION','ROOFING_COMPANY','TIRE_SHOP','AUTO_DETAILING','MOBILE_LOCKSMITH','HANDYMAN')\n     or v_type ~ '(LOCKSMITH|LOCKOUT|AUTO_LOCK|ROADSIDE|HVAC|PLUMB|ELECTRIC|CONTRACTOR|REPAIR|SERVICE_JOB|HANDYMAN)'\n  then return 'service_jobs'; end if;\n  if v_type = 'SHORT_TERM_RENTAL' then return 'appointments'; end if;\n  return null;\nend;\n$function$\n","identity_arguments":"p_business_type text, p_settings jsonb"},{"name":"tenant_provider_secrets_touch_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tenant_provider_secrets_touch_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"test_activity_logging","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.test_activity_logging()\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_activity_id UUID;\n  v_security_count INT;\n  v_activity_count INT;\nBEGIN\n  -- Try to log a test activity\n  v_activity_id := public.log_user_activity(\n    'system_test',\n    'Activity Logging Test',\n    'Testing that activity logging is functioning correctly',\n    NULL,\n    jsonb_build_object('test', true, 'timestamp', NOW())\n  );\n  \n  -- Count recent logs\n  SELECT COUNT(*) INTO v_security_count \n  FROM security_events \n  WHERE timestamp > NOW() - INTERVAL '24 hours';\n  \n  SELECT COUNT(*) INTO v_activity_count \n  FROM activity_log \n  WHERE created_at > NOW() - INTERVAL '24 hours';\n  \n  RETURN jsonb_build_object(\n    'ok', true,\n    'test_activity_id', v_activity_id,\n    'security_events_24h', v_security_count,\n    'activity_logs_24h', v_activity_count,\n    'timestamp', NOW()\n  );\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_create_job_request_from_signed_work_auth","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_create_job_request_from_signed_work_auth()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_creator uuid;\nBEGIN\n  IF NEW.agreement_type IS DISTINCT FROM 'work_authorization' THEN\n    RETURN NEW;\n  END IF;\n  IF NEW.status IS DISTINCT FROM 'signed' THEN\n    RETURN NEW;\n  END IF;\n  IF NEW.tenant_id IS NULL THEN\n    RETURN NEW;\n  END IF;\n\n  -- Idempotency via existing UNIQUE(source_signed_agreement_id)\n  IF EXISTS (SELECT 1 FROM public.job_requests WHERE source_signed_agreement_id = NEW.id) THEN\n    RETURN NEW;\n  END IF;\n\n  v_creator := COALESCE(NEW.user_id, auth.uid());\n  IF v_creator IS NULL THEN\n    -- Job_requests requires created_by NOT NULL; fall back to a tenant owner\n    SELECT ur.user_id INTO v_creator\n      FROM public.user_roles ur\n     WHERE ur.tenant_id = NEW.tenant_id\n       AND ur.role IN ('Tenant Owner','Owner','Admin')\n     LIMIT 1;\n  END IF;\n\n  IF v_creator IS NULL THEN\n    RAISE WARNING '[work_auth->job_request] no creator resolvable for tenant %', NEW.tenant_id;\n    RETURN NEW;\n  END IF;\n\n  INSERT INTO public.job_requests (\n    tenant_id, contact_id, source_signed_agreement_id, source_kind,\n    created_by, job_type, scope, priority,\n    property_address, city, state, zip, status, notes\n  ) VALUES (\n    NEW.tenant_id,\n    NEW.contact_id,\n    NEW.id,\n    'signed_work_auth',\n    v_creator,\n    COALESCE(NEW.metadata->>'job_type', 'tarp'),\n    NEW.metadata->>'scope',\n    COALESCE(NEW.metadata->>'priority', 'normal'),\n    NEW.metadata->>'property_address',\n    NEW.metadata->>'city',\n    NEW.metadata->>'state',\n    NEW.metadata->>'zip',\n    'pending_review',\n    'Auto-created from signed Work Authorization ('||NEW.id||')'\n  )\n  ON CONFLICT (source_signed_agreement_id) DO NOTHING;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_door_notes_stamp_edited","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_door_notes_stamp_edited()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.author_id <> OLD.author_id\n     OR NEW.door_id <> OLD.door_id\n     OR NEW.tenant_org_id <> OLD.tenant_org_id\n     OR NEW.created_at <> OLD.created_at THEN\n    RAISE EXCEPTION 'Immutable fields on door_notes cannot be changed';\n  END IF;\n  NEW.edited_at := now();\n  NEW.updated_at := now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_door_status_to_timeline","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_door_status_to_timeline()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  INSERT INTO public.activity_timeline (\n    tenant_org_id, user_id, activity_type, title, description,\n    related_entity_id, related_entity_type, importance, is_system_generated, metadata\n  ) VALUES (\n    NEW.tenant_org_id,\n    NEW.actor_id,\n    'door_status_change',\n    'Door status: ' || COALESCE(NEW.previous_status, 'new') || ' → ' || NEW.new_status,\n    COALESCE(NEW.actor_name, 'A team member') || ' updated a door',\n    NEW.door_id,\n    'door',\n    'normal',\n    true,\n    jsonb_build_object('source', NEW.source, 'visit_id', NEW.visit_id)\n  );\n  RETURN NEW;\nEXCEPTION WHEN OTHERS THEN\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_legal_pages_set_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_legal_pages_set_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_notify_managers_on_new_job_request","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_notify_managers_on_new_job_request()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_tenant   tenant_organizations%ROWTYPE;\n  v_contact  unified_contacts%ROWTYPE;\n  v_link     text;\n  v_addr     text;\n  v_name     text;\n  v_title    text := 'New Job Request Pending Review';\n  v_msg_base text;\nBEGIN\n  IF NEW.status IS DISTINCT FROM 'pending_review' THEN\n    RETURN NEW;\n  END IF;\n\n  SELECT * INTO v_tenant FROM public.tenant_organizations WHERE id = NEW.tenant_id;\n  IF NOT FOUND THEN RETURN NEW; END IF;\n\n  IF NEW.contact_id IS NOT NULL THEN\n    SELECT * INTO v_contact FROM public.unified_contacts WHERE id = NEW.contact_id;\n  END IF;\n\n  v_name := COALESCE(v_contact.name, 'Customer');\n  v_addr := COALESCE(NEW.property_address, '(no address)');\n\n  v_link := '/crm/' || COALESCE(v_tenant.tenant_type, 'MITIGATION')\n            || '/' || COALESCE(v_tenant.company_slug, v_tenant.id::text)\n            || '/job-requests';\n\n  v_msg_base := 'A signed Work Authorization is ready for manager review — '\n                || v_name || ' · ' || v_addr\n                || ' · ' || COALESCE(NEW.job_type, 'job');\n\n  -- Write to notification_queue (read by NotificationCenter bell)\n  INSERT INTO public.notification_queue\n    (user_id, notification_type, title, message, severity, action_url, metadata)\n  SELECT\n    ur.user_id,\n    'job_request_pending',\n    v_title,\n    v_msg_base,\n    'info',\n    v_link,\n    jsonb_build_object(\n      'job_request_id', NEW.id,\n      'tenant_id', NEW.tenant_id,\n      'signed_agreement_id', NEW.source_signed_agreement_id,\n      'contact_id', NEW.contact_id,\n      'contact_name', v_name,\n      'property_address', NEW.property_address,\n      'job_type', NEW.job_type,\n      'created_at', NEW.created_at\n    )\n  FROM public.user_roles ur\n  WHERE ur.tenant_id = NEW.tenant_id\n    AND ur.role IN ('Manager','Admin','Tenant Owner','Owner')\n  ON CONFLICT (user_id, notification_type, ((metadata->>'job_request_id')))\n    WHERE notification_type = 'job_request_pending'\n    DO NOTHING;\n\n  -- Also keep legacy notifications table populated for any other consumers\n  INSERT INTO public.notifications (user_id, tenant_id, type, title, message, link, metadata)\n  SELECT\n    ur.user_id,\n    NEW.tenant_id::text,\n    'job_request_pending',\n    v_title,\n    v_msg_base,\n    v_link,\n    jsonb_build_object(\n      'job_request_id', NEW.id,\n      'tenant_id', NEW.tenant_id,\n      'contact_name', v_name,\n      'property_address', NEW.property_address,\n      'job_type', NEW.job_type\n    )\n  FROM public.user_roles ur\n  WHERE ur.tenant_id = NEW.tenant_id\n    AND ur.role IN ('Manager','Admin','Tenant Owner','Owner')\n  ON CONFLICT (user_id, type, ((metadata->>'job_request_id')))\n    WHERE type = 'job_request_pending'\n    DO NOTHING;\n\n  RETURN NEW;\nEXCEPTION WHEN OTHERS THEN\n  RAISE WARNING '[notify_managers_on_new_job_request] failed: %', SQLERRM;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_pending_voicemail_drops_touch","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_pending_voicemail_drops_touch()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_set_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_set_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at := now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_sync_enrollment_progress","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_sync_enrollment_progress()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF TG_OP = 'DELETE' THEN\n    PERFORM public.recalc_academy_enrollment_progress(OLD.user_id, OLD.course_id);\n    RETURN OLD;\n  ELSE\n    PERFORM public.recalc_academy_enrollment_progress(NEW.user_id, NEW.course_id);\n    RETURN NEW;\n  END IF;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_sync_pa_engagement_from_pending_agreement","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_sync_pa_engagement_from_pending_agreement()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_pa  public.pa_engagements%ROWTYPE;\n  v_new_status text;\n  v_now timestamptz := now();\n  v_doc_type text := 'Letter of Representation';\n  v_signed_path text;\n  v_status_changed boolean;\n  v_path_just_set boolean;\nBEGIN\n  v_status_changed := (TG_OP = 'INSERT')\n    OR (TG_OP = 'UPDATE' AND NEW.status IS DISTINCT FROM OLD.status);\n  v_path_just_set := (TG_OP = 'UPDATE'\n    AND NEW.status = 'signed'\n    AND NEW.signed_pdf_path IS NOT NULL\n    AND OLD.signed_pdf_path IS DISTINCT FROM NEW.signed_pdf_path);\n\n  -- Only act when something material changed for sync purposes\n  IF NOT (v_status_changed OR v_path_just_set) THEN\n    RETURN NEW;\n  END IF;\n\n  SELECT * INTO v_pa\n    FROM public.pa_engagements\n   WHERE pending_agreement_id = NEW.id\n   LIMIT 1;\n\n  IF NOT FOUND THEN\n    RETURN NEW; -- not PA-linked (e.g. SCETARPING work_auth) -> no-op\n  END IF;\n\n  v_new_status := CASE NEW.status\n    WHEN 'sent'    THEN 'Sent'\n    WHEN 'viewed'  THEN 'Viewed'\n    WHEN 'signed'  THEN 'Signed'\n    WHEN 'voided'  THEN 'Cancelled'\n    WHEN 'expired' THEN 'Cancelled'\n    ELSE NULL\n  END;\n\n  -- Status update path (or already-signed + path arrived)\n  IF v_new_status IS NOT NULL OR v_path_just_set THEN\n    UPDATE public.pa_engagements\n       SET status        = COALESCE(v_new_status, status),\n           sent_at       = COALESCE(sent_at,     NEW.sent_at),\n           viewed_at     = COALESCE(viewed_at,   NEW.viewed_at),\n           signed_at     = CASE WHEN NEW.status = 'signed'  THEN COALESCE(signed_at,    NEW.signed_at, v_now) ELSE signed_at END,\n           cancelled_at  = CASE WHEN NEW.status IN ('voided','expired') THEN COALESCE(cancelled_at, v_now) ELSE cancelled_at END,\n           signed_document_url = CASE WHEN NEW.status = 'signed' AND NEW.signed_pdf_path IS NOT NULL\n                                      THEN COALESCE(signed_document_url, NEW.signed_pdf_path)\n                                      ELSE signed_document_url END,\n           updated_at    = v_now\n     WHERE id = v_pa.id;\n  END IF;\n\n  -- Mirror to PA document checklist on signed (status change OR path arrival)\n  IF NEW.status = 'signed' AND v_pa.claim_id IS NOT NULL THEN\n    v_signed_path := NEW.signed_pdf_path;\n\n    IF EXISTS (\n      SELECT 1 FROM public.case_documents_required\n       WHERE tenant_org_id = v_pa.tenant_org_id::text\n         AND claim_id      = v_pa.claim_id\n         AND document_type = v_doc_type\n    ) THEN\n      UPDATE public.case_documents_required\n         SET status         = 'Verified',\n             linked_file_id = COALESCE(linked_file_id, v_signed_path),\n             linked_file_url= COALESCE(linked_file_url, v_signed_path),\n             verified_at    = COALESCE(verified_at, v_now),\n             notes          = COALESCE(notes, '') || CASE WHEN COALESCE(notes,'') = '' THEN '' ELSE E'\\n' END\n                              || 'Auto-verified via KnockLaunch Sign ('||NEW.id||')',\n             updated_at     = v_now\n       WHERE tenant_org_id = v_pa.tenant_org_id::text\n         AND claim_id      = v_pa.claim_id\n         AND document_type = v_doc_type;\n    ELSE\n      INSERT INTO public.case_documents_required (\n        tenant_org_id, claim_id, document_type, status,\n        linked_file_id, linked_file_url, verified_at, notes\n      ) VALUES (\n        v_pa.tenant_org_id::text, v_pa.claim_id, v_doc_type, 'Verified',\n        v_signed_path, v_signed_path, v_now,\n        'Auto-created via KnockLaunch Sign ('||NEW.id||')'\n      );\n    END IF;\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_sync_profile_last_login","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_sync_profile_last_login()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.last_sign_in_at IS DISTINCT FROM OLD.last_sign_in_at\n     AND NEW.last_sign_in_at IS NOT NULL THEN\n    UPDATE public.profiles\n    SET last_login = NEW.last_sign_in_at,\n        last_login_at = NEW.last_sign_in_at\n    WHERE id = NEW.id;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_uce_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_uce_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN NEW.updated_at = now(); RETURN NEW; END;\n$function$\n","identity_arguments":""},{"name":"tg_unified_contacts_mirror_assigned","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_unified_contacts_mirror_assigned()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF TG_OP = 'INSERT' THEN\n    IF NEW.assigned_to IS NOT NULL AND NEW.assigned_user IS NULL THEN\n      NEW.assigned_user := NEW.assigned_to;\n    ELSIF NEW.assigned_user IS NOT NULL AND NEW.assigned_to IS NULL THEN\n      NEW.assigned_to := NEW.assigned_user;\n    END IF;\n  ELSIF TG_OP = 'UPDATE' THEN\n    IF NEW.assigned_to IS DISTINCT FROM OLD.assigned_to THEN\n      NEW.assigned_user := NEW.assigned_to;\n    ELSIF NEW.assigned_user IS DISTINCT FROM OLD.assigned_user THEN\n      NEW.assigned_to := NEW.assigned_user;\n    END IF;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_unified_contacts_validate_tenant","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_unified_contacts_validate_tenant()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_exists boolean;\nBEGIN\n  -- NULL tenant_org_id: reject\n  IF NEW.tenant_org_id IS NULL OR btrim(NEW.tenant_org_id) = '' THEN\n    INSERT INTO public.unified_contacts_insert_violations\n      (violation_type, attempted_tenant_org_id, attempted_lead_id, auth_uid, application_name, client_addr, raw_row)\n    VALUES\n      ('null_tenant', NEW.tenant_org_id, NEW.lead_id, auth.uid(),\n       current_setting('application_name', true),\n       inet_client_addr(),\n       to_jsonb(NEW));\n    RAISE EXCEPTION\n      'unified_contacts.tenant_org_id cannot be NULL (P0.1a-defense). lead_id=%, auth_uid=%',\n      NEW.lead_id, auth.uid()\n      USING ERRCODE = '23514';\n  END IF;\n\n  -- Orphan tenant_org_id: reject\n  SELECT EXISTS (SELECT 1 FROM public.tenants t WHERE t.id::text = NEW.tenant_org_id)\n    INTO v_exists;\n\n  IF NOT v_exists THEN\n    INSERT INTO public.unified_contacts_insert_violations\n      (violation_type, attempted_tenant_org_id, attempted_lead_id, auth_uid, application_name, client_addr, raw_row)\n    VALUES\n      ('orphan_tenant', NEW.tenant_org_id, NEW.lead_id, auth.uid(),\n       current_setting('application_name', true),\n       inet_client_addr(),\n       to_jsonb(NEW));\n    RAISE EXCEPTION\n      'unified_contacts.tenant_org_id=% does not reference an existing tenant (P0.1a-defense). lead_id=%, auth_uid=%',\n      NEW.tenant_org_id, NEW.lead_id, auth.uid()\n      USING ERRCODE = '23514';\n  END IF;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_workflow_template_set_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_workflow_template_set_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"tg_wtv_immutable_when_published","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.tg_wtv_immutable_when_published()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF OLD.status = 'published' AND NEW.status = 'published' THEN\n    IF NEW.cards IS DISTINCT FROM OLD.cards\n       OR NEW.metadata IS DISTINCT FROM OLD.metadata\n       OR NEW.version_number IS DISTINCT FROM OLD.version_number\n       OR NEW.template_id IS DISTINCT FROM OLD.template_id\n       OR NEW.lint_report IS DISTINCT FROM OLD.lint_report\n       OR NEW.rollback_parent_version_id IS DISTINCT FROM OLD.rollback_parent_version_id\n       OR NEW.published_at IS DISTINCT FROM OLD.published_at\n       OR NEW.published_by IS DISTINCT FROM OLD.published_by THEN\n      RAISE EXCEPTION 'Published workflow template versions are immutable. Create a new version instead.';\n    END IF;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"to_business_time","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.to_business_time(value timestamp with time zone)\n RETURNS timestamp without time zone\n LANGUAGE sql\n STABLE\n SET search_path TO 'pg_catalog', 'public'\nRETURN (value AT TIME ZONE business_timezone())\n","identity_arguments":"value timestamp with time zone"},{"name":"to_business_time_label","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.to_business_time_label(value timestamp with time zone)\n RETURNS text\n LANGUAGE sql\n STABLE\n SET search_path TO 'pg_catalog', 'public'\nRETURN (to_char((value AT TIME ZONE business_timezone()), 'YYYY-MM-DD HH12:MI:SS AM'::text) || ' ET'::text)\n","identity_arguments":"value timestamp with time zone"},{"name":"toggle_platform_message_reaction","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.toggle_platform_message_reaction(p_message_id uuid, p_emoji text)\n RETURNS boolean\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\ndeclare\n  conv uuid;\n  removed boolean := false;\n  removed_count integer := 0;\n  clean_emoji text := left(trim(coalesce(p_emoji,'')),16);\nbegin\n  select conversation_id into conv\n  from public.messages\n  where id=p_message_id;\n\n  if conv is null or not public.can_access_message_conversation(conv,auth.uid()) then\n    raise exception 'message_access_denied';\n  end if;\n\n  if clean_emoji='' then\n    raise exception 'reaction_required';\n  end if;\n\n  delete from public.message_reactions\n  where message_id=p_message_id\n    and user_id=auth.uid()\n    and emoji=clean_emoji;\n\n  get diagnostics removed_count = row_count;\n  removed := removed_count > 0;\n\n  if not removed then\n    insert into public.message_reactions(message_id,user_id,emoji)\n    values(p_message_id,auth.uid(),clean_emoji);\n  end if;\n\n  insert into public.message_user_events(user_id,conversation_id,event_type)\n  select user_id,conv,'reaction_changed'\n  from public.message_conversation_members\n  where conversation_id=conv;\n\n  return not removed;\nend;\n$function$\n","identity_arguments":"p_message_id uuid, p_emoji text"},{"name":"touch_appointment_settings_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_appointment_settings_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN NEW.updated_at = now(); RETURN NEW; END $function$\n","identity_arguments":""},{"name":"touch_cafe_menu_item_media_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_cafe_menu_item_media_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'pg_catalog', 'public'\nAS $function$\nbegin\n  new.updated_at = now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"touch_call_summaries_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_call_summaries_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"touch_compliance_settings_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_compliance_settings_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $function$\n","identity_arguments":""},{"name":"touch_elevated_patch_requests","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_elevated_patch_requests()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"touch_lawn_care_readiness_items_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_lawn_care_readiness_items_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'pg_catalog', 'public'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"touch_lawn_service_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_lawn_service_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'pg_catalog', 'public'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"touch_lead_campaigns_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_lead_campaigns_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN NEW.updated_at = now(); RETURN NEW; END $function$\n","identity_arguments":""},{"name":"touch_opportunity_radar_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_opportunity_radar_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'pg_catalog', 'public'\nAS $function$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $function$\n","identity_arguments":""},{"name":"touch_owner_relationship_from_event","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_owner_relationship_from_event()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$ begin update public.owner_tenant_relationships set last_meaningful_contact_at = greatest(coalesce(last_meaningful_contact_at, new.occurred_at), new.occurred_at), updated_at = now() where id = new.relationship_id; return new; end; $function$\n","identity_arguments":""},{"name":"touch_realtor_transactions_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_realtor_transactions_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.updated_at := now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"touch_trial_accounts_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_trial_accounts_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN NEW.updated_at = now(); RETURN NEW; END;\n$function$\n","identity_arguments":""},{"name":"touch_vmpsc_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.touch_vmpsc_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.updated_at := now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"trg_rcoq_tenant_guard","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.trg_rcoq_tenant_guard()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  cp_tenant uuid;\n  c_tenant uuid;\n  p_tenant uuid;\nBEGIN\n  SELECT tenant_id INTO cp_tenant FROM public.realtor_campaign_properties WHERE id = NEW.campaign_property_id;\n  SELECT tenant_id INTO c_tenant FROM public.realtor_campaigns WHERE id = NEW.campaign_id;\n  SELECT tenant_id INTO p_tenant FROM public.realtor_properties WHERE id = NEW.property_id;\n  IF cp_tenant IS NULL OR c_tenant IS NULL OR p_tenant IS NULL THEN\n    RAISE EXCEPTION 'Outreach queue: missing parent record';\n  END IF;\n  IF cp_tenant <> NEW.tenant_id OR c_tenant <> NEW.tenant_id OR p_tenant <> NEW.tenant_id THEN\n    RAISE EXCEPTION 'Outreach queue: cross-tenant link blocked';\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"try_cast_uuid","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.try_cast_uuid(_v text)\n RETURNS uuid\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'pg_catalog', 'public'\nAS $function$\nBEGIN\n  IF _v IS NULL OR _v = '' THEN RETURN NULL; END IF;\n  RETURN _v::uuid;\nEXCEPTION WHEN others THEN\n  RETURN NULL;\nEND;\n$function$\n","identity_arguments":"_v text"},{"name":"uce_is_member","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.uce_is_member(_tenant_id text)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\n  SELECT EXISTS (\n    SELECT 1 FROM public.user_tenant_memberships\n    WHERE user_id = auth.uid()\n      AND tenant_id::text = _tenant_id\n      AND status = 'active'\n  );\n$function$\n","identity_arguments":"_tenant_id text"},{"name":"uce_is_owner_or_admin","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.uce_is_owner_or_admin(_tenant_id text)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'auth', 'pg_temp'\nAS $function$\n  SELECT public.is_system_admin(auth.uid()) OR EXISTS (SELECT 1 FROM public.user_tenant_memberships m\n    LEFT JOIN public.user_roles ur ON ur.user_id=m.user_id AND ur.tenant_id=m.tenant_id\n    WHERE m.user_id=auth.uid() AND m.tenant_id::text=_tenant_id AND m.status='active'\n      AND (m.is_owner=true OR ur.role::text IN ('Owner','Tenant Owner','Admin','GodMode')));\n$function$\n","identity_arguments":"_tenant_id text"},{"name":"unified_contacts_autofill_name","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.unified_contacts_autofill_name()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF (NEW.name IS NULL OR TRIM(NEW.name) = '') THEN\n    NEW.name := NULLIF(TRIM(CONCAT_WS(' ', NEW.first_name, NEW.last_name)), '');\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"unlink_job_from_claim","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.unlink_job_from_claim(_job_id uuid)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_tenant      uuid;\n  v_prev_claim  uuid;\n  v_actor_email text;\nBEGIN\n  IF auth.uid() IS NULL THEN RAISE EXCEPTION 'unauthenticated' USING ERRCODE='42501'; END IF;\n\n  SELECT tenant_id, contact_claim_id INTO v_tenant, v_prev_claim\n  FROM public.jobs WHERE id = _job_id;\n\n  IF v_tenant IS NULL THEN RAISE EXCEPTION 'job not found' USING ERRCODE='02000'; END IF;\n\n  IF NOT public._is_manager_or_higher_in_tenant(v_tenant) THEN\n    RAISE EXCEPTION 'forbidden' USING ERRCODE='42501';\n  END IF;\n\n  UPDATE public.jobs SET contact_claim_id = NULL WHERE id = _job_id;\n\n  SELECT email INTO v_actor_email FROM auth.users WHERE id = auth.uid();\n\n  INSERT INTO public.job_activity_log\n    (job_id, tenant_id, activity_type, actor_id, actor_email, description, metadata)\n  VALUES (\n    _job_id,\n    v_tenant,\n    'job_claim_unlink',\n    auth.uid(),\n    v_actor_email,\n    CASE\n      WHEN v_prev_claim IS NULL THEN 'Unlink called on already-unlinked job'\n      ELSE 'Unlinked job from claim'\n    END,\n    jsonb_build_object(\n      'action', 'unlink',\n      'previous_claim_id', v_prev_claim,\n      'new_claim_id', NULL\n    )\n  );\nEND; $function$\n","identity_arguments":"_job_id uuid"},{"name":"update_canvassing_stats","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_canvassing_stats()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  UPDATE canvassing_goals\n  SET \n    completed_doors = completed_doors + 1,\n    completed_appointments = CASE WHEN NEW.result_status = 'appointment_set' \n                             THEN completed_appointments + 1 ELSE completed_appointments END,\n    completed_interested = CASE WHEN NEW.result_status = 'interested' \n                           THEN completed_interested + 1 ELSE completed_interested END,\n    updated_at = NOW()\n  WHERE user_id = NEW.user_id::text AND date = CURRENT_DATE;\n\n  INSERT INTO canvassing_goals (tenant_org_id, user_id, date, completed_doors, completed_appointments, completed_interested)\n  VALUES (\n    NEW.tenant_org_id, \n    NEW.user_id::text,\n    CURRENT_DATE, \n    1,\n    CASE WHEN NEW.result_status = 'appointment_set' THEN 1 ELSE 0 END,\n    CASE WHEN NEW.result_status = 'interested' THEN 1 ELSE 0 END\n  ) ON CONFLICT (user_id, date) DO NOTHING;\n\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_contact_claim_payment_status","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_contact_claim_payment_status(_claim_id uuid, _new_status claim_payment_lifecycle_v4, _note text DEFAULT NULL::text)\n RETURNS contact_claims\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  _uid uuid := auth.uid();\n  _tenant text;\n  _from public.claim_payment_lifecycle_v4;\n  _row public.contact_claims;\nBEGIN\n  IF _uid IS NULL THEN\n    RAISE EXCEPTION 'unauthenticated' USING ERRCODE = '42501';\n  END IF;\n\n  SELECT cc.tenant_org_id, cc.claim_payment_status\n    INTO _tenant, _from\n  FROM public.contact_claims cc\n  WHERE cc.id = _claim_id;\n\n  IF _tenant IS NULL THEN\n    RAISE EXCEPTION 'claim not found' USING ERRCODE = 'P0002';\n  END IF;\n\n  IF NOT (\n    public.is_system_admin(_uid)\n    OR public.is_manager_or_higher(_uid, _tenant::uuid)\n  ) THEN\n    RAISE EXCEPTION 'forbidden: requires Manager, Admin, Owner, Tenant Owner, or GodMode'\n      USING ERRCODE = '42501';\n  END IF;\n\n  UPDATE public.contact_claims\n     SET claim_payment_status = _new_status,\n         claim_payment_status_updated_at = now(),\n         claim_payment_status_updated_by = _uid,\n         updated_at = now()\n   WHERE id = _claim_id\n   RETURNING * INTO _row;\n\n  INSERT INTO public.claim_payment_status_history\n    (claim_id, tenant_org_id, from_status, to_status, changed_by, note, source)\n  VALUES\n    (_claim_id, _tenant, _from, _new_status, _uid, _note, 'manual');\n\n  RETURN _row;\nEND;\n$function$\n","identity_arguments":"_claim_id uuid, _new_status claim_payment_lifecycle_v4, _note text"},{"name":"update_document_drafts_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_document_drafts_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at = NOW();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_door_object_status","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_door_object_status()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  UPDATE door_objects\n  SET \n    current_status = NEW.result_status,\n    last_result_at = NEW.visited_at,\n    last_visited_by = NEW.user_id,\n    updated_at = now()\n  WHERE id = NEW.door_id;\n  \n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_new_roofs_queue_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_new_roofs_queue_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_own_profile","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_own_profile(p_name text DEFAULT NULL::text, p_phone text DEFAULT NULL::text, p_company text DEFAULT NULL::text)\n RETURNS profiles\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n  v_uid uuid := auth.uid();\n  v_row public.profiles;\nBEGIN\n  IF v_uid IS NULL THEN\n    RAISE EXCEPTION 'Not authenticated';\n  END IF;\n\n  UPDATE public.profiles\n  SET\n    name       = COALESCE(p_name, name),\n    phone      = COALESCE(p_phone, phone),\n    company    = COALESCE(p_company, company),\n    updated_at = now()\n  WHERE id = v_uid\n  RETURNING * INTO v_row;\n\n  RETURN v_row;\nEND;\n$function$\n","identity_arguments":"p_name text, p_phone text, p_company text"},{"name":"update_permit_history_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_permit_history_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN \n  NEW.updated_at = now(); \n  RETURN NEW; \nEND;\n$function$\n","identity_arguments":""},{"name":"update_platform_message_conversation_preferences","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_platform_message_conversation_preferences(p_conversation_id uuid, p_folder_id uuid, p_labels text[], p_archived boolean, p_pinned boolean, p_muted boolean)\n RETURNS void\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nbegin\n  if not public.can_access_message_conversation(p_conversation_id,auth.uid()) then raise exception 'message_conversation_access_denied'; end if;\n  if p_folder_id is not null and not exists(select 1 from public.message_folders where id=p_folder_id and user_id=auth.uid()) then raise exception 'folder_not_found'; end if;\n  insert into public.message_conversation_preferences(conversation_id,user_id,folder_id,labels,archived_at,pinned_at,muted_at,updated_at)\n  values(p_conversation_id,auth.uid(),p_folder_id,coalesce(p_labels,array[]::text[]),\n    case when p_archived then now() else null end,case when p_pinned then now() else null end,case when p_muted then now() else null end,now())\n  on conflict(conversation_id,user_id) do update set folder_id=excluded.folder_id,labels=excluded.labels,\n    archived_at=excluded.archived_at,pinned_at=excluded.pinned_at,muted_at=excluded.muted_at,updated_at=now();\n  update public.message_conversation_members set muted_at=case when p_muted then now() else null end\n    where conversation_id=p_conversation_id and user_id=auth.uid();\nend;\n$function$\n","identity_arguments":"p_conversation_id uuid, p_folder_id uuid, p_labels text[], p_archived boolean, p_pinned boolean, p_muted boolean"},{"name":"update_quality_score","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_quality_score()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  NEW.quality_score := calculate_quality_score(NEW.name, NEW.phone, NEW.email, NEW.address, NEW.city, NEW.state, NEW.zip);\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_roof_price_book_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_roof_price_book_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $function$\n","identity_arguments":""},{"name":"update_seminole_parcels_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_seminole_parcels_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $function$\n","identity_arguments":""},{"name":"update_settlement_invoices_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_settlement_invoices_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at = NOW();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_system_variable_templates_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_system_variable_templates_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_table_row","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_table_row(p_table_name text, p_row_id uuid, p_row_data jsonb)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\ndeclare\n  v_set_clause text;\n  v_rows integer;\nbegin\n  perform public.require_platform_operator();\n  if not exists (\n    select 1\n    from pg_catalog.pg_class c\n    join pg_catalog.pg_namespace n on n.oid = c.relnamespace\n    where n.nspname = 'public'\n      and c.relname = p_table_name\n      and c.relkind in ('r', 'p')\n  ) then\n    raise exception 'unknown writable public table' using errcode = '22023';\n  end if;\n\n  select string_agg(format('%I = %L', e.key, e.value), ', ')\n  into v_set_clause\n  from jsonb_each_text(coalesce(p_row_data, '{}'::jsonb) - 'id' - 'created_at') e\n  where exists (\n    select 1\n    from information_schema.columns c\n    where c.table_schema = 'public'\n      and c.table_name = p_table_name\n      and c.column_name = e.key\n      and c.is_generated = 'NEVER'\n  );\n\n  if coalesce(v_set_clause, '') = '' then\n    raise exception 'no writable columns supplied' using errcode = '22023';\n  end if;\n\n  execute format(\n    'update public.%I set %s where id = %L::uuid',\n    p_table_name, v_set_clause, p_row_id\n  );\n  get diagnostics v_rows = row_count;\n\n  return jsonb_build_object(\n    'ok', true,\n    'message', 'Row updated successfully',\n    'rows_updated', v_rows\n  );\nend;\n$function$\n","identity_arguments":"p_table_name text, p_row_id uuid, p_row_data jsonb"},{"name":"update_tarping_invoices_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_tarping_invoices_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at = NOW();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_tenant_rebuttals_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_tenant_rebuttals_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_unified_contacts_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_unified_contacts_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_updated_at_column","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_updated_at_column()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at = NOW();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_workflow_dialogue_templates_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_workflow_dialogue_templates_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"update_workflow_sessions_updated_at","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.update_workflow_sessions_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nBEGIN\n  NEW.updated_at = now();\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"user_can_subscribe_topic","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.user_can_subscribe_topic(_topic text)\n RETURNS boolean\n LANGUAGE plpgsql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_uid uuid := auth.uid();\n  v_tenant uuid;\n  v_user uuid;\nBEGIN\n  IF v_uid IS NULL THEN\n    RETURN false;\n  END IF;\n\n  -- System admins (GodMode) can subscribe to any channel\n  IF public.is_system_admin(v_uid) THEN\n    RETURN true;\n  END IF;\n\n  -- user:<uuid> — only the user themselves\n  IF _topic LIKE 'user:%' THEN\n    BEGIN\n      v_user := substring(_topic from 6)::uuid;\n      RETURN v_user = v_uid;\n    EXCEPTION WHEN others THEN\n      RETURN false;\n    END;\n  END IF;\n\n  -- tenant:<uuid>(:anything) — must be active member\n  IF _topic LIKE 'tenant:%' THEN\n    BEGIN\n      v_tenant := split_part(substring(_topic from 8), ':', 1)::uuid;\n    EXCEPTION WHEN others THEN\n      RETURN false;\n    END;\n    RETURN EXISTS (\n      SELECT 1 FROM public.user_tenant_memberships\n      WHERE user_id = v_uid\n        AND tenant_id = v_tenant\n        AND status = 'active'\n    );\n  END IF;\n\n  -- Postgres changes channels (postgres_changes via supabase) — keep auth-only\n  -- but warn: business code should migrate to tenant: topics.\n  -- Default DENY for unknown topic shapes.\n  RETURN false;\nEND;\n$function$\n","identity_arguments":"_topic text"},{"name":"user_has_permission","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.user_has_permission(p_user_id uuid, p_permission_key text, p_tenant_id uuid DEFAULT NULL::uuid)\n RETURNS boolean\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nDECLARE\n  v_caller uuid := auth.uid();\n  v_override_granted boolean;\n  v_user_roles text[];\n  v_allowed boolean := false;\nBEGIN\n  IF v_caller IS NULL THEN\n    RAISE EXCEPTION 'authentication required' USING ERRCODE='42501';\n  END IF;\n  IF p_user_id IS NULL OR p_permission_key IS NULL OR btrim(p_permission_key) = '' THEN\n    RAISE EXCEPTION 'user and permission are required' USING ERRCODE='22023';\n  END IF;\n\n  v_allowed := (v_caller = p_user_id) OR public.is_system_admin(v_caller);\n\n  IF NOT v_allowed AND p_tenant_id IS NOT NULL THEN\n    v_allowed := public.is_admin_or_higher(v_caller, p_tenant_id)\n      AND public.is_tenant_member(p_user_id, p_tenant_id);\n  END IF;\n\n  IF NOT v_allowed THEN\n    RAISE EXCEPTION 'permission introspection denied' USING ERRCODE='42501';\n  END IF;\n\n  SELECT granted INTO v_override_granted\n  FROM public.user_permission_overrides\n  WHERE user_id = p_user_id\n    AND permission_key = p_permission_key\n    AND (tenant_id IS NULL OR tenant_id = p_tenant_id)\n    AND (expires_at IS NULL OR expires_at > now())\n  LIMIT 1;\n  IF FOUND THEN RETURN v_override_granted; END IF;\n\n  SELECT array_agg(DISTINCT role::text) INTO v_user_roles\n  FROM public.user_roles\n  WHERE user_id = p_user_id\n    AND (tenant_id IS NULL OR tenant_id = p_tenant_id);\n\n  IF 'GodMode' = ANY(coalesce(v_user_roles, ARRAY[]::text[])) THEN RETURN true; END IF;\n\n  RETURN EXISTS (\n    SELECT 1\n    FROM public.role_permissions rp\n    WHERE rp.permission_key = p_permission_key\n      AND rp.role = ANY(coalesce(v_user_roles, ARRAY[]::text[]))\n      AND (rp.tenant_id IS NULL OR rp.tenant_id = p_tenant_id)\n  );\nEND;\n$function$\n","identity_arguments":"p_user_id uuid, p_permission_key text, p_tenant_id uuid"},{"name":"valid_notification_category_channels","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.valid_notification_category_channels(p_channels jsonb)\n RETURNS boolean\n LANGUAGE plpgsql\n IMMUTABLE\n SET search_path TO 'pg_catalog'\nAS $function$\ndeclare entry record;\nbegin\n  if p_channels is null or jsonb_typeof(p_channels) <> 'object' then return false; end if;\n  for entry in select key, value from jsonb_each_text(p_channels) loop\n    if entry.key not in ('messages','assigned','deadlines','billing','updates')\n       or entry.value not in ('push','email','in_app','off') then return false; end if;\n  end loop;\n  return true;\nend;\n$function$\n","identity_arguments":"p_channels jsonb"},{"name":"validate_assigned_to_uuid","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.validate_assigned_to_uuid()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.assigned_to IS NOT NULL\n     AND NEW.assigned_to <> ''\n     AND NEW.assigned_to !~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' THEN\n    RAISE EXCEPTION 'assigned_to must be NULL or a UUID. Got: %', NEW.assigned_to\n      USING HINT = 'Resolve email/username to user id (auth.users.id) before writing.';\n  END IF;\n  IF NEW.assigned_to = '' THEN\n    NEW.assigned_to := NULL;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"validate_mail_continuity_machine_token","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.validate_mail_continuity_machine_token(p_token text)\n RETURNS boolean\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'public', 'private', 'extensions'\nAS $function$\n  select exists (\n    select 1\n    from private.mail_continuity_machine_auth\n    where key='primary'\n      and secret_hash=encode(extensions.digest(coalesce(p_token,''),'sha256'),'hex')\n  );\n$function$\n","identity_arguments":"p_token text"},{"name":"validate_opportunity_radar_seed_token","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.validate_opportunity_radar_seed_token(_token text)\n RETURNS boolean\n LANGUAGE sql\n STABLE SECURITY DEFINER\n SET search_path TO 'public', 'private'\nAS $function$\n  select coalesce(\n    exists(\n      select 1\n      from private.opportunity_radar_lifecycle_secret\n      where token = _token\n        and nullif(btrim(_token), '') is not null\n    ),\n    false\n  );\n$function$\n","identity_arguments":"_token text"},{"name":"validate_voicemail_preset_slot","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.validate_voicemail_preset_slot()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.preset_slot IS NOT NULL THEN\n    IF NEW.preset_slot < 1 OR NEW.preset_slot > 4 THEN\n      RAISE EXCEPTION 'preset_slot must be between 1 and 4';\n    END IF;\n    IF NEW.scope <> 'personal' OR NEW.direction <> 'outbound' THEN\n      RAISE EXCEPTION 'preset_slot only allowed on personal outbound templates';\n    END IF;\n    IF NEW.owner_user_id IS NULL THEN\n      RAISE EXCEPTION 'preset_slot requires owner_user_id';\n    END IF;\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""},{"name":"vehicle_lockout_request_record_guard","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.vehicle_lockout_request_record_guard()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nbegin\n  if tg_op = 'INSERT' then\n    if coalesce(new.status, '') not in ('awaiting_signature', 'agreement_prepared') then\n      new.status := 'requested';\n    end if;\n    new.payment_status := 'unpaid';\n    new.source := 'public_site';\n    new.authorization_at := case when new.status in ('awaiting_signature', 'agreement_prepared') then null else coalesce(new.authorization_at, now()) end;\n    new.technician_notes := null;\n    new.amount_due := null;\n    new.amount_paid := null;\n    new.en_route_at := null;\n    new.on_scene_at := null;\n    new.completed_at := null;\n    new.canceled_at := null;\n    new.service_evidence_storage_path := null;\n    new.service_evidence_filename := null;\n    new.authority_verified := false;\n    new.authority_verification_method := null;\n    new.authority_verified_at := null;\n    new.completion_acknowledged := false;\n    new.completion_acknowledgement_name := null;\n    new.completion_acknowledged_at := null;\n  elsif tg_op = 'UPDATE' then\n    if new.authority_verified = true and old.authority_verified = false then\n      new.authority_verified_at := coalesce(new.authority_verified_at, now());\n    elsif new.authority_verified = false then\n      new.authority_verified_at := null;\n      new.authority_verification_method := null;\n    end if;\n    if new.completion_acknowledged = true and old.completion_acknowledged = false then\n      new.completion_acknowledged_at := coalesce(new.completion_acknowledged_at, now());\n    elsif new.completion_acknowledged = false then\n      new.completion_acknowledged_at := null;\n    end if;\n    if new.status is distinct from old.status then\n      if new.status = 'en_route' then\n        new.en_route_at := coalesce(new.en_route_at, now());\n      elsif new.status = 'on_scene' then\n        new.on_scene_at := coalesce(new.on_scene_at, now());\n      elsif new.status = 'completed' then\n        new.completed_at := coalesce(new.completed_at, now());\n      elsif new.status = 'canceled' then\n        new.canceled_at := coalesce(new.canceled_at, now());\n      end if;\n    end if;\n  end if;\n  new.updated_at := now();\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"vehicle_lockout_sync_customer","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.vehicle_lockout_sync_customer()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_contact_id uuid;\n  v_phone text;\n  v_email text;\n  v_address text;\nbegin\n  v_phone := nullif(regexp_replace(coalesce(new.phone, ''), '\\D', '', 'g'), '');\n  v_email := nullif(lower(btrim(coalesce(new.email, ''))), '');\n  v_address := nullif(regexp_replace(lower(btrim(coalesce(new.service_location, ''))), '\\s+', ' ', 'g'), '');\n\n  perform pg_advisory_xact_lock(\n    hashtextextended(\n      new.tenant_id::text || ':' || coalesce(v_phone, v_email, lower(btrim(new.phone))),\n      0\n    )\n  );\n\n  select contact.id\n    into v_contact_id\n  from public.unified_contacts contact\n  where contact.tenant_org_id = new.tenant_id::text\n    and (\n      (v_phone is not null and contact.normalized_phone = v_phone)\n      or (v_email is not null and contact.normalized_email = v_email)\n    )\n  order by contact.updated_at desc nulls last, contact.created_at desc\n  limit 1;\n\n  if v_contact_id is null then\n    insert into public.unified_contacts (\n      name, phone, normalized_phone, email, normalized_email,\n      address, normalized_address, city, state,\n      status, contact_status, service_status, jobs_stage,\n      source, tenant_org_id, graduated_at, last_touched_at,\n      contact_role, raw_data\n    ) values (\n      new.customer_name, new.phone, v_phone, new.email, v_email,\n      new.service_location, v_address, new.city, 'FL',\n      'Active', 'Active', new.status, new.status,\n      '321_auto_unlock', new.tenant_id::text, now(), now(),\n      'Customer', jsonb_build_object('vehicle_lockout_request_id', new.id::text)\n    )\n    returning id into v_contact_id;\n  else\n    update public.unified_contacts\n    set name = new.customer_name,\n        phone = new.phone,\n        normalized_phone = v_phone,\n        email = coalesce(new.email, email),\n        normalized_email = coalesce(v_email, normalized_email),\n        address = new.service_location,\n        normalized_address = v_address,\n        city = new.city,\n        state = coalesce(state, 'FL'),\n        status = 'Active',\n        contact_status = 'Active',\n        service_status = new.status,\n        jobs_stage = new.status,\n        source = '321_auto_unlock',\n        graduated_at = coalesce(graduated_at, now()),\n        last_touched_at = now(),\n        contact_role = coalesce(contact_role, 'Customer'),\n        raw_data = coalesce(raw_data, '{}'::jsonb)\n          || jsonb_build_object('vehicle_lockout_request_id', new.id::text),\n        updated_at = now()\n    where id = v_contact_id;\n  end if;\n\n  insert into public.contact_tenant_memberships (\n    contact_id, tenant_id, status, contact_status, service_status,\n    jobs_stage, source, contact_role, last_touched_at, updated_at\n  ) values (\n    v_contact_id, new.tenant_id, 'active', 'Active', new.status,\n    new.status, '321_auto_unlock', 'Customer', now(), now()\n  )\n  on conflict (contact_id, tenant_id) do update\n    set status = 'active',\n        contact_status = 'Active',\n        service_status = excluded.service_status,\n        jobs_stage = excluded.jobs_stage,\n        source = '321_auto_unlock',\n        contact_role = coalesce(public.contact_tenant_memberships.contact_role, 'Customer'),\n        last_touched_at = now(),\n        updated_at = now();\n\n  if tg_op = 'INSERT' then\n    insert into public.consent_ledger (\n      tenant_org_id, contact_id, phone_number, phone_normalized,\n      consent_type, consent_status, source, source_url, capture_text,\n      granted_at, metadata\n    ) values\n    (\n      new.tenant_id::text,\n      v_contact_id,\n      new.phone,\n      v_phone,\n      'lawful_authority_attestation',\n      'granted',\n      '321_auto_unlock_public_intake',\n      '/321-auto-unlock',\n      'I confirm I am the owner, authorized driver, or otherwise have lawful authority to request entry into this vehicle.',\n      new.authorization_at,\n      jsonb_build_object(\n        'vehicle_lockout_request_id', new.id::text,\n        'authorization_name', new.authorization_name,\n        'vehicle_year', new.vehicle_year,\n        'vehicle_make', new.vehicle_make,\n        'vehicle_model', new.vehicle_model,\n        'license_plate', new.license_plate,\n        'proof_filename', new.proof_filename,\n        'proof_storage_path', new.proof_storage_path\n      )\n    ),\n    (\n      new.tenant_id::text,\n      v_contact_id,\n      new.phone,\n      v_phone,\n      'vehicle_entry_authorization',\n      'granted',\n      '321_auto_unlock_public_intake',\n      '/321-auto-unlock',\n      'I authorize 321 Auto Unlock to perform vehicle entry service on the vehicle described above.',\n      new.authorization_at,\n      jsonb_build_object(\n        'vehicle_lockout_request_id', new.id::text,\n        'authorization_name', new.authorization_name,\n        'vehicle_year', new.vehicle_year,\n        'vehicle_make', new.vehicle_make,\n        'vehicle_model', new.vehicle_model,\n        'license_plate', new.license_plate,\n        'proof_filename', new.proof_filename,\n        'proof_storage_path', new.proof_storage_path\n      )\n    );\n  end if;\n\n  return new;\nend;\n$function$\n","identity_arguments":""},{"name":"vista_check_availability","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.vista_check_availability(p_unit_name text, p_check_in date, p_check_out date)\n RETURNS boolean\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\nbegin\n  if p_unit_name not in ('The View', 'The Nest') or p_check_in is null or p_check_out is null or p_check_out <= p_check_in or p_check_in < current_date or (p_check_out - p_check_in) > 90 then return false; end if;\n  return not exists (\n    select 1 from public.short_stay_reservations r\n    where r.tenant_id = '71b397ba-b9ad-496b-914c-985d97dbb12e'::uuid\n      and r.unit_name = p_unit_name\n      and r.status = any (array['confirmed'::text, 'checked_in'::text])\n      and r.check_in < p_check_out and r.check_out > p_check_in\n  );\nend;\n$function$\n","identity_arguments":"p_unit_name text, p_check_in date, p_check_out date"},{"name":"vista_create_reservation","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.vista_create_reservation(p_unit_name text, p_check_in date, p_check_out date, p_guest_count integer, p_guest_name text, p_guest_email text, p_guest_phone text, p_notes text DEFAULT NULL::text, p_website text DEFAULT NULL::text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public', 'pg_temp'\nAS $function$\ndeclare\n  v_id uuid := gen_random_uuid();\n  v_reference text;\n  v_recent_count integer;\nbegin\n  if coalesce(trim(p_website), '') <> '' then return jsonb_build_object('ok', true, 'status', 'pending', 'reference', 'VDM'); end if;\n  if p_unit_name not in ('The View', 'The Nest') or p_check_in is null or p_check_out is null or p_check_out <= p_check_in or p_check_in < current_date or (p_check_out - p_check_in) > 90 then return jsonb_build_object('ok', false, 'code', 'INVALID_DATES', 'message', 'Choose valid future check-in and check-out dates.'); end if;\n  if p_guest_count is null or p_guest_count < 1 or p_guest_count > 2 then return jsonb_build_object('ok', false, 'code', 'INVALID_GUEST_COUNT', 'message', 'These vacation homes accommodate up to two guests.'); end if;\n  if length(trim(coalesce(p_guest_name, ''))) < 2 or position('@' in trim(coalesce(p_guest_email, ''))) < 2 or length(trim(coalesce(p_guest_phone, ''))) < 7 then return jsonb_build_object('ok', false, 'code', 'CONTACT_REQUIRED', 'message', 'Name, email, and phone are required.'); end if;\n  if not public.vista_check_availability(p_unit_name, p_check_in, p_check_out) then return jsonb_build_object('ok', false, 'code', 'DATES_UNAVAILABLE', 'message', 'Those dates are already reserved.'); end if;\n\n  select count(*) into v_recent_count from public.short_stay_reservations r\n  where r.tenant_id = '71b397ba-b9ad-496b-914c-985d97dbb12e'::uuid\n    and r.source = 'direct_web'\n    and r.created_at >= now() - interval '1 hour'\n    and (lower(coalesce(r.guest_email, '')) = lower(trim(coalesce(p_guest_email, ''))) or coalesce(r.guest_phone, '') = trim(coalesce(p_guest_phone, '')));\n  if v_recent_count >= 5 then return jsonb_build_object('ok', false, 'code', 'TOO_MANY_REQUESTS', 'message', 'We already have several recent reservation requests from this contact. Please contact La Vista del Mar directly if you need help.'); end if;\n\n  v_reference := 'VDM-' || upper(substr(replace(v_id::text, '-', ''), 1, 8));\n  insert into public.short_stay_reservations (id, tenant_id, unit_name, guest_name, guest_email, guest_phone, source, check_in, check_out, status, guest_count, amount_paid, payment_status, notes, metadata)\n  values (v_id, '71b397ba-b9ad-496b-914c-985d97dbb12e'::uuid, p_unit_name, left(trim(p_guest_name),120), left(lower(trim(p_guest_email)),180), left(trim(p_guest_phone),40), 'direct_web', p_check_in, p_check_out, 'inquiry', p_guest_count, 0, 'unpaid', nullif(left(trim(coalesce(p_notes,'')),1200),''), jsonb_build_object('channel','knocklaunch_direct','customer_facing',true,'reference',v_reference));\n  return jsonb_build_object('ok', true, 'status', 'pending', 'reference', v_reference);\nend;\n$function$\n","identity_arguments":"p_unit_name text, p_check_in date, p_check_out date, p_guest_count integer, p_guest_name text, p_guest_email text, p_guest_phone text, p_notes text, p_website text"},{"name":"visual_witness_expired_storage_paths","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.visual_witness_expired_storage_paths(p_before timestamp with time zone, p_limit integer DEFAULT 500)\n RETURNS TABLE(name text)\n LANGUAGE sql\n SECURITY DEFINER\n SET search_path TO 'pg_catalog', 'public'\nAS $function$\n  SELECT object.name\n  FROM storage.objects AS object\n  WHERE object.bucket_id = 'command-center-visual-witness'\n    AND object.created_at < COALESCE(p_before, now() - interval '14 days')\n    AND (\n      object.name LIKE 'universal-witness/%'\n      OR object.name LIKE 'hosted-runner/%'\n      OR object.name LIKE 'tenant/%'\n      OR object.name LIKE 'visual-witness-jobs/%'\n    )\n  ORDER BY object.created_at ASC, object.name ASC\n  LIMIT LEAST(GREATEST(COALESCE(p_limit, 500), 1), 1000);\n$function$\n","identity_arguments":"p_before timestamp with time zone, p_limit integer"},{"name":"voicemail_dtmf_tokens_validate","schema":"public","definition":"CREATE OR REPLACE FUNCTION public.voicemail_dtmf_tokens_validate()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'public'\nAS $function$\nBEGIN\n  IF NEW.expires_at > now() + interval '15 minutes' THEN\n    RAISE EXCEPTION 'voicemail_dtmf_tokens.expires_at exceeds 15-minute ceiling';\n  END IF;\n  IF NEW.expires_at <= now() THEN\n    RAISE EXCEPTION 'voicemail_dtmf_tokens.expires_at must be in the future';\n  END IF;\n  RETURN NEW;\nEND;\n$function$\n","identity_arguments":""}],"cron_jobs":[{"active":true,"command":"select private.expire_stale_user_sessions(interval '60 minutes');","jobname":"knocklaunch-expire-stale-user-sessions","schedule":"*/15 * * * *"},{"active":true,"command":"select private.prune_call_lifecycle_debug_events(interval '7 days');","jobname":"knocklaunch-prune-call-lifecycle-debug-events","schedule":"17 3 * * *"},{"active":true,"command":"select private.system_backup_edge_request_at_local_hour(3,'start','daily-3am-eastern',null,false);","jobname":"knocklaunch-daily-full-backup-3am-eastern","schedule":"0 * * * *"},{"active":true,"command":"select private.system_backup_edge_request('resume','recovery-pulse',null,false);","jobname":"knocklaunch-backup-recovery-pulse","schedule":"*/15 * * * *"},{"active":true,"command":"select private.paul_scheduler_edge_request();","jobname":"knocklaunch-paul-scheduler-dispatch","schedule":"* * * * *"},{"active":true,"command":"select public.process_task_deadline_alerts();","jobname":"knocklaunch-existing-task-deadlines","schedule":"15 * * * *"},{"active":true,"command":"\n      with cfg as (\n        select function_url from public.message_push_worker_config\n        where singleton=true and enabled=true\n          and function_url ~ '^https://[a-z0-9-]+\\.supabase\\.co/functions/v1/platform-message-push$'\n      )\n      select net.http_post(\n        url:=cfg.function_url,\n        headers:=jsonb_build_object('Content-Type','application/json',\n          'x-knocklaunch-message-worker',(select decrypted_secret from vault.decrypted_secrets where name='kl_message_push_worker_v1' limit 1)),\n        body:='{\"action\":\"drain\"}'::jsonb,timeout_milliseconds:=10000)\n      from cfg;\n      ","jobname":"knocklaunch_message_push_outbox_v1","schedule":"* * * * *"},{"active":true,"command":"SELECT public.pcg_reconcile_verified_slab_publications();","jobname":"pcg-verified-slab-publication-reconcile","schedule":"*/5 * * * *"}],"extensions":[{"name":"btree_gist","version":"1.7"},{"name":"cube","version":"1.5"},{"name":"earthdistance","version":"1.2"},{"name":"fuzzystrmatch","version":"1.2"},{"name":"http","version":"1.6"},{"name":"pg_cron","version":"1.6.4"},{"name":"pg_net","version":"0.20.3"},{"name":"pg_stat_statements","version":"1.11"},{"name":"pg_trgm","version":"1.6"},{"name":"pgcrypto","version":"1.3"},{"name":"pgmq","version":"1.5.1"},{"name":"plpgsql","version":"1.0"},{"name":"supabase_vault","version":"0.3.1"},{"name":"uuid-ossp","version":"1.1"}],"captured_at":"2026-10-10T13:29:43.18107+00:00","server_version":"17.6","migration_history":[{"name":"af1291c7-72ba-4090-aabe-cfb61a190943","version":"20251206122717"},{"name":"3c431b73-2989-4914-ac21-7285fb479ca1","version":"20251206122746"},{"name":"742dd6c3-db15-46cc-a746-8c42a354f3d0","version":"20251206123638"},{"name":"5bae2680-ec2d-4313-a670-7f61dfd2a403","version":"20251206123658"},{"name":"7acd1d16-f02a-41d1-8ace-7fdca63409a1","version":"20251206123740"},{"name":"26ccb3a7-481f-4146-a7f5-80b9fa5a3f6c","version":"20251206131116"},{"name":"4fd25a26-3c50-4c43-acfb-7c4051534992","version":"20251206131205"},{"name":"b796abec-5644-4f97-b8a5-d6a93c56ecac","version":"20251206134521"},{"name":"9a1422ec-747a-44a4-a730-61bc58966b31","version":"20251206214338"},{"name":"encore_canonical_claim_stage","version":"20260812144215"},{"name":"harden_customer_portal_token_contract","version":"20260812195936"},{"name":"revoke_portal_when_claims_close","version":"20260812200236"},{"name":"harden_privileged_backend_boundaries","version":"20260812203000"},{"name":"harden_internal_rpc_execution","version":"20260812205500"},{"name":"reconcile_canonical_migration_ledger","version":"20260812212048"},{"name":"harden_trigger_function_execute_privileges","version":"20260813050000"},{"name":"harden_all_trigger_function_execute_privileges","version":"20260813054500"},{"name":"create_pa_staff_compliance","version":"20260813071000"},{"name":"create_pa_staff_compliance","version":"20260813071103"},{"name":"add_pa_claim_automation_pack","version":"20260813072226"},{"name":"add_pa_claim_automation_pack","version":"20260813073000"},{"name":"harden_remaining_function_search_paths","version":"20260813074000"},{"name":"create_pa_carrier_estimate_items","version":"20260813084500"},{"name":"create_pa_carrier_estimate_items","version":"20260813100747"},{"name":"claim_scope_customer_portal_access","version":"20260813113000"},{"name":"shared_claim_valuation_scope","version":"20260813113500"},{"name":"harden_internal_auth_helper_rpc_grants","version":"20260813115000"},{"name":"harden_ai_auth_helper_anon_grants","version":"20260813115500"},{"name":"fix_claim_stage_dispatch_contact_scope","version":"20260813125535"},{"name":"repair_academy_membership_onboarding_contract","version":"20260814173727"},{"name":"unify_onboarding_provisioning_contract","version":"20260814200148"},{"name":"reconcile_default_roles_with_explicit_assignments","version":"20260814200223"},{"name":"fix_academy_global_course_nested_access","version":"20260814200333"},{"name":"harden_onboarding_academy_and_license_research","version":"20260814205121"},{"name":"make_onboarding_research_idempotent","version":"20260814205259"},{"name":"secure_onboarding_and_make_academy_role_aware","version":"20260814210255"},{"name":"add_owner_safe_self_service_onboarding_orchestrator","version":"20260814210403"},{"name":"lock_raw_academy_enrollment_and_add_safe_retry","version":"20260814210431"},{"name":"align_canonical_tenant_types_with_tenant_contract","version":"20260814210511"},{"name":"repair_tenant_provisioning_logo_contract","version":"20260814210556"},{"name":"stop_writing_through_tenant_organizations_view","version":"20260814210634"},{"name":"add_automatic_onboarding_license_research_dispatch","version":"20260814212546"},{"name":"align_onboarding_session_state_machine","version":"20260814212651"},{"name":"separate_owner_research_and_scope_vertical_academy","version":"20260814213114"},{"name":"make_async_research_preserve_provisioned_onboarding_state","version":"20260814213154"},{"name":"adaptive_command_center_tenant_resolution","version":"20260815134500"},{"name":"mobile_vendor_event_constraint_prerequisites","version":"20260815204459"},{"name":"mobile_vendor_event_operating_system","version":"20260815204500"},{"name":"reconcile_mobile_vendor_event_operating_system","version":"20260815215000"},{"name":"create_communication_setup_requests","version":"20260816035000"},{"name":"live_edit_tenant_override_rls","version":"20260816105000"},{"name":"live_edit_v2_history_templates","version":"20260816151000"},{"name":"phone_first_auth_identity","version":"20260816170000"},{"name":"finance_recordkeeping","version":"20260816172100"},{"name":"finance_report_automation","version":"20260816224500"},{"name":"create_thirsty_panda_tenant","version":"20260817044500"},{"name":"thirsty_panda_cafe_qsr","version":"20260817143000"},{"name":"thirsty_panda_owner_office_operations","version":"20260817190000"},{"name":"thirsty_panda_full_menu_media_library","version":"20260817224500"},{"name":"cafe_qsr_tenant_type_contract","version":"20260818124500"},{"name":"knocklaunch_mail360_platform","version":"20260818133600"},{"name":"add_auto_detailing_vertical_and_tranzformer_tenant","version":"20260818144500"},{"name":"reconcile_knocklaunch_mail360_platform","version":"20260818184300"},{"name":"remove_customer_tenant_as_command_center_platform_anchor","version":"20260818233526"},{"name":"fix_command_center_platform_mission_anchor","version":"20260818233700"},{"name":"add_square_tenant_payments","version":"20260819000500"},{"name":"fix_explicit_tenant_member_godmode","version":"20260819042147"},{"name":"align_platform_admin_tenant_manager_authority","version":"20260819043300"},{"name":"restore_cached_parcel_intel_view_fields","version":"20260819073900"},{"name":"zoho_mail_direct_provider","version":"20260819143500"},{"name":"add_zoho_mail_platform_vault_reader","version":"20260819165700"},{"name":"deterministic_business_operations_core","version":"20260819203500"},{"name":"platform_zoho_mail_credentials","version":"20260820015500"},{"name":"supabase_auth_security_repair","version":"20260820214500"},{"name":"optimize_supabase_hot_paths","version":"20260820220000"},{"name":"harden_public_security_definer_rpc_surface","version":"20260820222500"},{"name":"optimize_supabase_policy_topology","version":"20260820223000"},{"name":"optimize_command_center_mission_resolution","version":"20260820223500"},{"name":"close_remaining_authz_bypasses","version":"20260820224500"},{"name":"optimize_session_telemetry_integrity","version":"20260820231000"},{"name":"optimize_unified_contacts_read_paths","version":"20260820232000"},{"name":"retire_call_lifecycle_debug_noise","version":"20260820233000"},{"name":"mobile_vendor_growth_club","version":"20260821175400"},{"name":"big_papis_loyalty_member_portal","version":"20260822021500"},{"name":"big_papis_referral_points","version":"20260822175500"},{"name":"make_finance_transaction_sources_provider_agnostic","version":"20260824153500"},{"name":"mobile_vendor_schedule_import_recovery","version":"20260824172500"},{"name":"harden_big_papis_loyalty_integrity","version":"20260825014800"},{"name":"mobile_vendor_loyalty_cash_purchases","version":"20260825031000"},{"name":"tenant_ad_analytics_events","version":"20260825032500"},{"name":"mobile_vendor_inventory_ledger","version":"20260825061000"},{"name":"mobile_vendor_event_finance_and_domain_truth","version":"20260825062000"},{"name":"owner_workspace_notes_and_deterministic_tasks","version":"20260826214500"},{"name":"tenant_photo_studio","version":"20260827223000"},{"name":"vista_short_term_rental","version":"20260827232500"},{"name":"vista_first_party_reservations","version":"20260828184000"},{"name":"fix_mobile_vendor_inventory_adjustment","version":"20260829022000"},{"name":"add_unified_inbox_contact_fk","version":"20260829023500"},{"name":"add_jobs_funding_type","version":"20260829121500"},{"name":"add_job_financing_overlay","version":"20260829123500"},{"name":"redfish_contact_first_spine","version":"20260829124200"},{"name":"knocklaunch_demo_requests","version":"20260829134500"},{"name":"roof_help_funnel_events","version":"20260829144500"},{"name":"align_backend_tenant_type_canonicalization","version":"20260830140500"},{"name":"tenant_media_library","version":"20260830142554"},{"name":"tenant_media_library_existing_media_backfill","version":"20260830151500"},{"name":"enforce_strict_tenant_type_contract","version":"20260830152000"},{"name":"media_taxonomy_v1","version":"20260830164000"},{"name":"demo_request_completion_workflow","version":"20260830214000"},{"name":"roofing_operating_system","version":"20260831041000"},{"name":"roofing_portal_projection","version":"20260831045500"},{"name":"roofing_portal_canonical_tokens","version":"20260831050000"},{"name":"tenant_owned_storage_buckets","version":"20260831131500"},{"name":"redfish_roofing_contract_repairs","version":"20260831222417"},{"name":"redfish_owner_demo_completion","version":"20260831222418"},{"name":"redfish_roofhelpfinder_jimmy_routing","version":"20260831235000"},{"name":"create_vehicle_lockout_requests","version":"20260901014812"},{"name":"progress_platform_records","version":"20260901023000"},{"name":"321_auto_unlock_service_record","version":"20260901031500"},{"name":"redfish_demo_financial_readiness","version":"20260901105500"},{"name":"enable_redfish_storm_report","version":"20260901110500"},{"name":"public_321_auto_unlock_brand","version":"20260901110800"},{"name":"normalize_tenant_logo_ingest_base64","version":"20260901130500"},{"name":"expand_live_edit_operations","version":"20260901140000"},{"name":"fix_roofing_ops_platform_admin_access","version":"20260901183000"},{"name":"open_exact_media_reorg_upload_targets","version":"20260901184201"},{"name":"open_exact_media_reorg_copy_sources","version":"20260901184303"},{"name":"enable_http_for_bounded_media_reorg","version":"20260901184421"},{"name":"normalize_redfish_demo_contact_ids","version":"20260901184500"},{"name":"allow_clean_big_papis_video_reorg_target","version":"20260901184829"},{"name":"close_tenant_media_reorg_window","version":"20260901190322"},{"name":"temp_generated_media_legacy_delete_scope","version":"20260901193627"},{"name":"remove_temp_generated_media_legacy_delete_scope","version":"20260901193740"},{"name":"canonicalize_tenant_media_storage","version":"20260901195800"},{"name":"temporary_exact_legacy_media_delete_scope_20260901","version":"20260901200714"},{"name":"remove_temporary_exact_legacy_media_delete_scope_20260901","version":"20260901200814"},{"name":"retire_legacy_tenant_storage_contract","version":"20260901202000"},{"name":"standardize_tenant_media_branding","version":"20260901203500"},{"name":"seed_unambiguous_tenant_branding_logos","version":"20260901205500"},{"name":"321_auto_unlock_esign_intake","version":"20260901213000"},{"name":"public_321_auto_unlock_video_branding","version":"20260901220500"},{"name":"allow_multiple_roof_estimates_per_contact","version":"20260901225000"},{"name":"expand_tenant_provider_connections","version":"20260902033500"},{"name":"preserve_321_pre_submit_status","version":"20260902040000"},{"name":"redfish_tenant_specific_rebuttals","version":"20260902053000"},{"name":"tenant_content_isolation_contract","version":"20260902054500"},{"name":"restore_default_stormscore_model","version":"20260902132500"},{"name":"create_user_tenant_tutorial_state","version":"20260902161000"},{"name":"create_user_tenant_tutorial_progress","version":"20260902164500"},{"name":"atomic_big_papis_proposal_numbers","version":"20260902182000"},{"name":"redfish_scope_agreement_resolver","version":"20260902183500"},{"name":"roof_measurement_jobs","version":"20260902192500"},{"name":"fix_vehicle_lockout_pre_submit_status_check","version":"20260903011500"},{"name":"prehistoric_001_deterministic_tenant_media","version":"20260903020000"},{"name":"harden_prehistoric_001_tenant_media","version":"20260903021500"},{"name":"platform_security_hardening_10_10","version":"20260903023500"},{"name":"prehistoric_002_universal_proposals","version":"20260903024500"},{"name":"security_rpc_least_privilege","version":"20260903024600"},{"name":"job_readiness_tenant_guard","version":"20260903024900"},{"name":"guard_user_permission_introspection","version":"20260903025300"},{"name":"harden_prehistoric_002_verified_renders","version":"20260903030000"},{"name":"security_final_10_of_10","version":"20260903033000"},{"name":"security_metadata_boundaries_10_of_10","version":"20260903035000"},{"name":"security_tenant_policy_boundaries_10_of_10","version":"20260903041000"},{"name":"security_authorization_primitives_10_of_10","version":"20260903042000"},{"name":"security_role_scope_invariant_10_of_10","version":"20260903043000"},{"name":"security_dnc_notification_scope_10_of_10","version":"20260903044000"},{"name":"security_active_membership_authorization_10_of_10","version":"20260903045000"},{"name":"security_membership_role_promotion_10_of_10","version":"20260903046000"},{"name":"security_public_upload_contract_10_of_10","version":"20260903047000"},{"name":"pcg_card_vault","version":"20260903133000"},{"name":"pcg_card_grading_core_v2","version":"20260903140839"},{"name":"pcg_operator_v2","version":"20260903142500"},{"name":"weekly_full_backup_system","version":"20260903165000"},{"name":"allow_one_time_pcg_workspace_background_seed","version":"20260903173741"},{"name":"remove_one_time_pcg_workspace_background_seed","version":"20260903173759"},{"name":"system_backup_r2_identity","version":"20260903181000"},{"name":"pcg_demo_growth_support_and_inventory_tier","version":"20260903191708"},{"name":"pcg_demo_growth_support_and_inventory_tier","version":"20260903192500"},{"name":"system_backup_catalog_timeout","version":"20260903194704"},{"name":"knock_launch_os_relationships_money_pipeline","version":"20260903201500"},{"name":"opportunity_radar_preconnection_seed","version":"20260905004500"},{"name":"readable_tenant_storage_final","version":"20260905102000"},{"name":"readable_tenant_storage_assignment_invariant","version":"20260905103000"},{"name":"readable_tenant_storage_buckets","version":"20260905135518"},{"name":"readable_tenant_storage_assignment_invariant","version":"20260905141327"},{"name":"barbershop_application_family","version":"20260905145500"},{"name":"barbershop_application_family","version":"20260905145614"},{"name":"deterministic_declared_tenant_blueprints","version":"20260905163500"},{"name":"universal_proposal_editor_assets","version":"20260905225500"},{"name":"tenant_isolated_proposal_editor_assets","version":"20260905231000"},{"name":"canonical_tenant_storage","version":"20260905233000"},{"name":"tenant_media_cleanup_control","version":"20260905235500"},{"name":"tenant_storage_layout_v2","version":"20260905235930"},{"name":"standardize_canonical_tenant_bucket_capabilities","version":"20260906000000"},{"name":"preserve_tenant_media_identity_on_storage_move","version":"20260906000500"},{"name":"storage_architecture_v3","version":"20260906002000"},{"name":"fix_tenant_provisioning_membership_role_drift","version":"20260906004252"},{"name":"fix_tenant_provisioning_owner_role_conflict","version":"20260906004315"},{"name":"universal_app_notifications","version":"20260906005000"},{"name":"book_me_directly_public_profile_and_provisioning_reconciliation","version":"20260906013000"},{"name":"storage_v3_retire_legacy_bucket_policies","version":"20260906021400"},{"name":"fix_proposal_editor_storage_rls_path","version":"20260906033000"},{"name":"sync_primary_tenant_logo_pointer","version":"20260906222732"},{"name":"sync_primary_tenant_logo_pointer","version":"20260906223000"},{"name":"capability_layer_foundation","version":"20260907015000"},{"name":"capability_existing_service_bindings","version":"20260907020000"},{"name":"capability_mail_contacts_bindings","version":"20260907021500"},{"name":"capability_delegation_foundation","version":"20260907023000"},{"name":"realtor_transaction_demo_identity","version":"20260907023500"},{"name":"repair_realtor_demo_backfill","version":"20260907024500"},{"name":"capability_native_calendar_bindings","version":"20260907031100"},{"name":"application_capability_layer","version":"20260907031200"},{"name":"application_demo_orchestration","version":"20260907040100"},{"name":"progress_application_api_bridge","version":"20260907040400"},{"name":"application_api_bindings","version":"20260907040500"},{"name":"progress_application_api_finalize","version":"20260907040600"},{"name":"application_capability_gap_closure","version":"20260907051600"},{"name":"create_call_center_application","version":"20260907121500"},{"name":"call_center_future_tenant_bootstrap","version":"20260907133000"},{"name":"knocklaunch_call_center_tenant_specific","version":"20260907143000"},{"name":"finish_call_center_operating_floor","version":"20260907155300"},{"name":"calendar_oversight_sources_policy_repair","version":"20260907164730"},{"name":"expand_call_center_campaigns_reporting","version":"20260907170000"},{"name":"first_class_application_routes_bootstrap","version":"20260907170500"},{"name":"calendar_first_class_application_bootstrap","version":"20260907171500"},{"name":"tenant_applications_platform_admin_read","version":"20260907182500"},{"name":"advance_call_center_operations","version":"20260907183000"},{"name":"curri_multi_tenant_control_center","version":"20260907190000"},{"name":"calendar_caldav_provider","version":"20260907190500"},{"name":"curri_three_tenant_demo_readiness","version":"20260907193000"},{"name":"curri_opportunity_radar_profiles","version":"20260907203000"},{"name":"calendar_bootstrap_v3_contract_reconcile","version":"20260907215200"},{"name":"resolve_approved_oauth_authorization_redirect","version":"20260908130234"},{"name":"fix_invitation_delivery_history","version":"20260909164000"},{"name":"system_backup_3am_eastern","version":"20260909172457"},{"name":"harden_system_backup_recovery","version":"20260909173000"},{"name":"schedule_system_backup_3am_eastern","version":"20260909174500"},{"name":"create_platform_godmode_media_bucket","version":"20260910044620"},{"name":"remove_temporary_godmode_media_upload_policy","version":"20260910044644"},{"name":"temporary_godmode_media_upload_policy","version":"20260910045653"},{"name":"remove_temporary_godmode_media_upload_policy","version":"20260910051325"},{"name":"user_activity_observability","version":"20260911012500"},{"name":"repair_owner_membership_role_sync","version":"20260911020123"},{"name":"repair_owner_membership_role_sync","version":"20260911021500"},{"name":"bootstrap_redfish_proposal_profile","version":"20260911153500"},{"name":"proposal_operating_contracts","version":"20260911163000"},{"name":"fix_proposal_operating_contract_task_source","version":"20260911170000"},{"name":"platform_business_activity_ledger","version":"20260911183000"},{"name":"preserve_modes_media_upload_contract","version":"20260911213000"},{"name":"business_activity_ledger_primitive_projection_coverage","version":"20260912011031"},{"name":"portfolio_control_center_classification","version":"20260912142000"},{"name":"private_owner_search_console_provider","version":"20260912151000"},{"name":"owner_proposals_personal_tenant","version":"20260912152000"},{"name":"event_rentals_tenant_type","version":"20260912163500"},{"name":"harden_proposal_esign_invariants","version":"20260912180000"},{"name":"event_rentals_modes_shell_contract","version":"20260912184000"},{"name":"add_esign_health_canary","version":"20260912184500"},{"name":"allow_agreement_activity_events","version":"20260912190000"},{"name":"allow_signed_agreement_activity_events","version":"20260912193000"},{"name":"platform_mode_default_media","version":"20260912194500"},{"name":"modes_tenant_capability_contract","version":"20260912220000"},{"name":"modes_card_driven_namespaces","version":"20260912224718"},{"name":"automatic_modes_storage_reconciliation","version":"20260913022000"},{"name":"modes_hq_image_library","version":"20260913032000"},{"name":"allow_default_pack_media_source_kind","version":"20260913033000"},{"name":"normalize_bookmedirectly_slug","version":"20260914012400"},{"name":"canonical_tenant_workspace_family","version":"20260914015000"},{"name":"fix_tenant_type_blueprint_contract","version":"20260914031800"},{"name":"roof_help_finder_tenant_native_apps","version":"20260914032000"},{"name":"prepare_modes_workspace_activation","version":"20260914032800"},{"name":"business_blueprint_authority","version":"20260914033800"},{"name":"canonicalize_big_papis_mode_card_routes","version":"20260914035800"},{"name":"create_app_background_jobs","version":"20260914065000"},{"name":"mobile_catering_contract","version":"20260914103200"},{"name":"creative_studio","version":"20260914202000"},{"name":"mobile_catering_modes_preservation","version":"20260914205500"},{"name":"mobile_catering_modes_enforcement","version":"20260914210000"},{"name":"reconcile_tenant_blueprint_machine_type","version":"20260914213500"},{"name":"current_user_workspace_bootstrap","version":"20260914234500"},{"name":"mail_continuity_primitive","version":"20260915130000"},{"name":"rehome_mail_continuity_pulse","version":"20260915133000"},{"name":"contact_price_overrides_and_order_requests","version":"20260915135000"},{"name":"tenant_workspace_search","version":"20260915182000"},{"name":"repair_deterministic_tenant_search_scope","version":"20260915191500"},{"name":"platform_application_registry_release_recovery","version":"20260916000000"},{"name":"creative_studio_productize","version":"20260917025500"},{"name":"business_blueprint_bootstrap_contract","version":"20260917040000"},{"name":"allow_tenant_proposal_pdf_reads","version":"20260917122000"},{"name":"allow_supabase_documents_without_drive_file","version":"20260917160500"},{"name":"tenant_type_registry","version":"20260917190000"},{"name":"document_lifecycle_invoice_owner","version":"20260917195800"},{"name":"tenant_type_authoritative_aliases","version":"20260917200000"},{"name":"stop_recursive_brand_derivatives","version":"20260917212000"},{"name":"stop_recursive_brand_derivatives_recovery","version":"20260917212744"},{"name":"consolidate_party_lifecycle_ownership","version":"20260917214500"},{"name":"consolidate_party_opportunity_lifecycle","version":"20260917224500"},{"name":"allow_task_activity_lifecycle_events","version":"20260918031500"},{"name":"stop_modes_reconcile_timestamp_feedback","version":"20260918031611"},{"name":"stop_modes_reconcile_timestamp_feedback","version":"20260918032000"},{"name":"owner_business_prospects","version":"20260918110000"},{"name":"revoke_direct_trigger_function_rpc_execute","version":"20260918144000"},{"name":"pin_search_tenant_workspace_search_path","version":"20260918144500"},{"name":"revoke_internal_security_definer_rpc_execute","version":"20260918145000"},{"name":"revoke_internal_storage_bucket_helper_execute","version":"20260918145500"},{"name":"revoke_barbershop_public_rpc_execute","version":"20260918150500"},{"name":"revoke_authenticated_only_helper_anon_execute","version":"20260918151000"},{"name":"remove_redundant_duplicate_indexes","version":"20260918151500"},{"name":"remove_redundant_unique_constraints","version":"20260918152000"},{"name":"harden_academy_member_visibility_auth","version":"20260918152500"},{"name":"harden_session_bound_policy_helpers","version":"20260918153000"},{"name":"enforce_invitation_state_consistency","version":"20260918163000"},{"name":"event_rental_application_catalog","version":"20260918171400"},{"name":"allow_booking_activity_timeline_namespace","version":"20260918173500"},{"name":"fix_event_booking_finance_tenant_id","version":"20260918174000"},{"name":"tenant_public_presence_contract","version":"20260918175000"},{"name":"task_calendar_projection","version":"20260918194500"},{"name":"speedy_panda_public_booking_request","version":"20260919103717"},{"name":"speedy_panda_bookmedirectly_hardening","version":"20260919112000"},{"name":"event_rental_bookmedirectly_policy_contract","version":"20260919113000"},{"name":"lock_legacy_event_rental_bmd_entrypoints","version":"20260919113100"},{"name":"event_rental_bookmedirectly_policy_contract","version":"20260919113333"},{"name":"handyman_modes_bootstrap","version":"20260919140743"},{"name":"handyman_runtime_identity","version":"20260919140824"},{"name":"email_thread_task_dedupe","version":"20260919143000"},{"name":"big_papis_inventory_event_integrity","version":"20260919150500"},{"name":"pcg_card_data_contract","version":"20260919205400"},{"name":"pcg_canonical_modes_bootstrap","version":"20260919213500"},{"name":"knocklaunch_owner_os_platform_identity","version":"20260921182500"},{"name":"platform_owner_tenant_classification_guard","version":"20260921185500"},{"name":"seed_pcg_owner_managed_proposal","version":"20260921194000"},{"name":"platform_messages_v2","version":"20260922122500"},{"name":"platform_messages_deleted_retention","version":"20260922123200"},{"name":"platform_messages","version":"20260922134500"},{"name":"platform_messages_reaction_hardening","version":"20260922141000"},{"name":"pcg_commerce_publishing","version":"20260922191500"},{"name":"wmp_mission_control","version":"20260923012815"},{"name":"quickbooks_schema_adapter","version":"20260923104500"},{"name":"modes_storage_reconcile_egress_guard","version":"20260924233000"},{"name":"knocklaunch_owner_operating_truth","version":"20260925130000"},{"name":"console_owner_tenant_context","version":"20260927153500"},{"name":"command_center_tenant_alias_phrase_resolution","version":"20260927155800"},{"name":"console_session_archive","version":"20260927163500"},{"name":"console_session_search_match","version":"20260927164500"},{"name":"seed_godmode_platform_branding","version":"20260928162949"},{"name":"preserve_lab_unpublished_media","version":"20260928164623"},{"name":"backup_preparation_timeout_hardening","version":"20260928175300"},{"name":"paul_scheduler","version":"20260928180500"},{"name":"pcg_grading_transition_readiness","version":"20260929013200"},{"name":"pcg_expected_card_count","version":"20260929014400"},{"name":"pcg_legacy_import_center","version":"20260929015000"},{"name":"pcg_import_staging_grants","version":"20260929023600"},{"name":"live_edit_sidekick_durable_memory","version":"20260929131000"},{"name":"pcg_submission_return_fulfillment","version":"20260929212000"},{"name":"card_grading_application_v1","version":"20260930015105"},{"name":"calendar_event_owner_admin_insert_authority","version":"20260930192250"},{"name":"fix_user_calendar_events_system_admin_projection_insert","version":"20260930193650"},{"name":"marketing_application_catalog","version":"20261001002000"},{"name":"assign_marketing_to_tennex","version":"20261001003000"},{"name":"tennex_bootstrap_repair","version":"20261001011800"},{"name":"tennex_modes_route_authority","version":"20261001013500"},{"name":"tennex_full_bootstrap","version":"20261001020500"},{"name":"marketing_campaign_runs","version":"20261001123500"},{"name":"paul_multimodal_attachments","version":"20261001143000"},{"name":"multi_google_workspace_accounts","version":"20261001173500"},{"name":"add_tennex_assistant_tax_specialist_roles","version":"20261001201933"},{"name":"allow_irslogiqs_provider","version":"20261001202203"},{"name":"tennex_user_contact_exclusivity","version":"20261002004716"},{"name":"guard_realtor_assignment_trigger_by_tenant_type","version":"20261002150038"},{"name":"ensure_unique_route_contact_number","version":"20261002154026"},{"name":"platform_projection_users_rpc","version":"20261002161000"},{"name":"godmode_projected_connection_actor","version":"20261002162500"},{"name":"onepath_google_workspace_account_binding","version":"20261002162925"},{"name":"restore_projection_user_admin_authority","version":"20261002172138"},{"name":"academy_paul_training_lab","version":"20261003040000"},{"name":"owner_billing_invoice_payment_bridge","version":"20261003160322"},{"name":"add_cloudflare_r2_tenant_provider","version":"20261003160745"},{"name":"fix_owner_receivable_payment_rollup_recursion","version":"20261003164023"},{"name":"optimize_pcg_card_vault_rls_and_pagination","version":"20261003204114"},{"name":"pcg_squarespace_provider","version":"20261004005800"},{"name":"trim_workspace_bootstrap_ingest_blob","version":"20261004112212"},{"name":"bound_workspace_bootstrap_settings_payload","version":"20261004112319"},{"name":"big_papis_workspace_template_retirement","version":"20261004114000"},{"name":"allow_users_read_own_activity_presence","version":"20261004193023"},{"name":"fix_pcg_membership_rls_recursion","version":"20261004194906"},{"name":"fix_pcg_status_audit_trigger_record_shape","version":"20261004204555"},{"name":"pcg_cert_number_grader_prefixes","version":"20261004213049"},{"name":"harden_platform_message_security_definer_boundaries","version":"20261004235937"},{"name":"bind_message_security_helpers_to_authenticated_caller","version":"20261005000009"},{"name":"close_unauthenticated_message_rpc_surface_and_pin_search_path","version":"20261005000035"},{"name":"close_remaining_unauthenticated_message_mutators","version":"20261005001220"},{"name":"close_anonymous_platform_message_read_and_edit_surface","version":"20261005001240"},{"name":"remove_trigger_only_rpc_execution","version":"20261005001318"},{"name":"revoke_direct_client_access_to_internal_control_tables","version":"20261005001334"},{"name":"lock_internal_sequence_and_commerce_event_tables","version":"20261005001353"},{"name":"least_privilege_all_rls_deny_all_tables","version":"20261005001410"},{"name":"revoke_anonymous_tenant_owner_introspection","version":"20261005002422"},{"name":"revoke_anon_internal_authorization_helpers","version":"20261005003038"},{"name":"remove_public_execute_from_internal_auth_helpers","version":"20261005003103"},{"name":"internalize_message_tenant_membership_helper","version":"20261005003133"},{"name":"bind_system_admin_introspection_to_caller","version":"20261005004131"},{"name":"scope_tenant_role_introspection","version":"20261005004218"},{"name":"bind_secondary_authorization_helpers_to_caller","version":"20261005004301"},{"name":"make_public_views_read_only_for_api_roles","version":"20261005004610"},{"name":"remove_anon_read_from_internal_security_views","version":"20261005004853"},{"name":"close_legacy_godmode_bucket_and_message_read_scope","version":"20261005005044"},{"name":"bind_auto_unlock_public_uploads_to_active_tickets","version":"20261005005126"},{"name":"internalize_account_lockout_rpc","version":"20261005005259"},{"name":"remove_anon_academy_visibility_rpc","version":"20261005005319"},{"name":"remove_explicit_anon_auth_helper_grants","version":"20261005005340"},{"name":"platform_security_hardening_reconciliation","version":"20261005005500"},{"name":"harden_security_helpers_and_321_upload_policy","version":"20261005010554"},{"name":"security_hardening_followup","version":"20261005011314"},{"name":"index_system_backup_export_chunks","version":"20261005013500"},{"name":"pcg_post_slab_certification","version":"20261005121000"},{"name":"pcg_submission_number_contract","version":"20261005122500"},{"name":"pcg_legacy_media_migration_jobs","version":"20261005130000"},{"name":"pcg_legacy_media_migration_dispatcher","version":"20261005131500"},{"name":"supabase_churn_guards","version":"20261005141500"},{"name":"command_center_mission_graph_rpc","version":"20261005142500"},{"name":"modes_reconcile_noop_guard","version":"20261005144500"},{"name":"pcg_public_submission_number","version":"20261005151100"},{"name":"pcg_public_submission_number","version":"20261005153250"},{"name":"pcg_marketplace_v1","version":"20261005165500"},{"name":"pcg_cert_on_acceptance","version":"20261006152002"},{"name":"pcg_wmp_end_to_end_tracking","version":"20261006203812"},{"name":"pcg_wmp_shipping_status_sync","version":"20261006204147"},{"name":"pcg_card_publish_destinations","version":"20261006210946"},{"name":"pcg_site_primary_sales_channel","version":"20261006211049"},{"name":"pcg_cert_lookup_publish_on_acceptance","version":"20261006211055"},{"name":"pcg_public_cert_allow_authentic_designation","version":"20261006211131"},{"name":"pcg_backfill_public_cert_database_v3","version":"20261006211152"},{"name":"pcg_internal_inventory_fast_lane_v4","version":"20261006212646"},{"name":"pcg_inventory_stage_bypass","version":"20261006212819"},{"name":"fix_modes_trigger_platform_media_privilege","version":"20261007110954"},{"name":"scope_tenant_admin_policies_to_authenticated","version":"20261007111150"},{"name":"pcg_card_lifecycle_management","version":"20261007150955"},{"name":"pcg_cert_prefix_authority","version":"20261007152449"},{"name":"pcg_cert_prefix_authority","version":"20261007152600"},{"name":"pcg_universal_search","version":"20261007153100"},{"name":"pcg_submission_business_lifecycle","version":"20261007215500"},{"name":"harden_pcg_stage_sync_trigger","version":"20261007220100"},{"name":"verify_pcg_stripe_payment_authority","version":"20261007222800"},{"name":"pcg_stripe_payment_authority_reconcile","version":"20261007222813"},{"name":"pcg_drive_fallback_customer_cleanup","version":"20261007223500"},{"name":"pcg_marketplace_purchase_request_idempotency","version":"20261008033342"},{"name":"pcg_website_media_migration_jobs","version":"20261008153600"},{"name":"fix_pcg_workspace_search_resolution","version":"20261008155800"},{"name":"bound_pcg_workspace_search_text","version":"20261008160300"},{"name":"restore_pcg_acceptance_three_arg_rpc_compatibility","version":"20261008184536"},{"name":"pcg_seller_memberships_credit_ledger_foundation","version":"20261008221128"},{"name":"pcg_membership_seller_integrity_keys","version":"20261008221152"},{"name":"pcg_grade_credit_atomic_reservation_transitions","version":"20261008221403"},{"name":"pcg_seller_memberships_grading_credit_foundation","version":"20261008221800"},{"name":"pcg_seller_payment_provider_fields","version":"20261008222100"},{"name":"pcg_confirm_legacy_photo_recovery","version":"20261009004600"},{"name":"pcg_intake_reconciliation_guard","version":"20261009021400"},{"name":"pcg_cert_cross_format_guard","version":"20261009023500"},{"name":"pcg_cert_registration_forward_fix","version":"20261009025000"},{"name":"pcg_hide_retired_11_digit_certificates_from_public_view","version":"20261009025507"},{"name":"pcg_retired_cert_public_views_guard_after_tombstones","version":"20261009030150"},{"name":"scope_retired_cert_public_view_restriction_to_pcg_tenant","version":"20261009030426"},{"name":"pcg_deleted_cards_revoke_public_visibility","version":"20261009030500"},{"name":"pcg_linked_external_withdrawal","version":"20261009031400"},{"name":"pcg_retired_red_privacy","version":"20261009031500"},{"name":"pcg_retired_red_certificate_direct_read_rls_guard","version":"20261009031743"},{"name":"pcg_red_label_direct_certificate_rls","version":"20261009031900"},{"name":"platform_business_events","version":"20261009045500"},{"name":"background_job_notification_bridge","version":"20261009050600"},{"name":"pcg_90003_ai_identity_audited_correction","version":"20261009104800"},{"name":"pcg_workflow_platform_journal","version":"20261009111700"},{"name":"pcg_lifecycle_journal_history","version":"20261009112600"},{"name":"existing_task_coordination","version":"20261009120500"},{"name":"existing_task_deadline_alerts","version":"20261009121800"},{"name":"notification_direct_insert_guard","version":"20261009123800"},{"name":"notification_readonly_evidence","version":"20261009124200"},{"name":"notification_attention_state","version":"20261009124700"},{"name":"pcg_cert_registration_strict_five_or_retired_eleven","version":"20261009125500"},{"name":"contact_assignment_tenant_integrity","version":"20261009125800"},{"name":"tennex_marketing_unsubscribe_scope","version":"20261009133000"},{"name":"notification_safe_destination","version":"20261009133600"},{"name":"notification_routing_delivery_receipts","version":"20261009150000"},{"name":"invoice_paid_integrity_guard","version":"20261009160000"},{"name":"invoice_payment_allocations","version":"20261009170000"},{"name":"restrictive_finance_authorization","version":"20261009180000"},{"name":"pcg_quarantine_unresolved_public_certificate_collisions","version":"20261009184500"},{"name":"pcg_public_legacy_unpublished_rows_visibility_guard","version":"20261009184600"},{"name":"pcg_public_usps_return_shipping_contract","version":"20261009184700"},{"name":"tenant_activity_telemetry_scope","version":"20261009190800"},{"name":"messages_push_outbox","version":"20261009191000"},{"name":"owner_invitation_notification_bridge","version":"20261009191831"},{"name":"tenant_owner_team_presence_read","version":"20261009192637"},{"name":"message_push_notification_parity","version":"20261009200800"},{"name":"marketing_campaign_state_journal","version":"20261009230743"},{"name":"pcg_wholesale_relations","version":"20261010001000"},{"name":"allow_stripe_connect_oauth_states","version":"20261010001300"},{"name":"tenant_handoff_evidence_ledger","version":"20261010003248"},{"name":"pcg_stop_legacy_post_slab_cert_allocation","version":"20261010031000"},{"name":"pcg_verified_slab_publication_reconciler","version":"20261010032300"},{"name":"pcg_physical_slab_cert_only","version":"20261010114100"},{"name":"pcg_photo_verified_cert_acceptance","version":"20261010115000"}],"vault_secret_names":[{"name":"Client Secret","description":""},{"name":"kl_message_push_worker_v1","description":""},{"name":"knocklaunch_mail_continuity_trigger","description":"Machine-only token for KNOCKLAUNCH Mail Continuity health reconciliation."},{"name":"knocklaunch_modes_storage_reconcile_trigger","description":"Machine-only token for automatic MODES tenant storage reconciliation."},{"name":"knocklaunch_paul_scheduler_trigger","description":"Machine-only token used by pg_cron/pg_net to invoke the PAUL scheduler dispatcher."},{"name":"knocklaunch_platform_zoho_mail_client_id","description":""},{"name":"knocklaunch_platform_zoho_mail_client_secret","description":""},{"name":"knocklaunch_system_backup_trigger","description":"Machine-only token used by pg_cron/pg_net to invoke the KNOCKLAUNCH system-backup Edge Function."},{"name":"knocklaunch_zoho_mail_client_id","description":"Knocklaunch Zoho Mail "},{"name":"knocklaunch_zoho_mail_client_secret","description":"knocklaunch zoho mail "}]}