-- BOC Initial Schema
-- Business Operations Center — Full schema for all modules
-- Created: 2026-07-12

-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- Core: Tenants (multi-tenant support)
CREATE TABLE IF NOT EXISTS boc_tenants (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name        TEXT NOT NULL,
    slug        TEXT UNIQUE NOT NULL,
    domain      TEXT,
    settings    JSONB DEFAULT '{}',
    status      TEXT NOT NULL DEFAULT 'active',
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Core: Users
CREATE TABLE IF NOT EXISTS boc_users (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    email       TEXT NOT NULL,
    name        TEXT NOT NULL,
    role        TEXT NOT NULL DEFAULT 'user',
    avatar_url  TEXT,
    settings    JSONB DEFAULT '{}',
    last_login  TIMESTAMPTZ,
    status      TEXT NOT NULL DEFAULT 'active',
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE(tenant_id, email)
);

-- Core: Audit log (immutable)
CREATE TABLE IF NOT EXISTS boc_audit_log (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    user_id     UUID REFERENCES boc_users(id),
    action      TEXT NOT NULL,
    entity_type TEXT NOT NULL,
    entity_id   TEXT NOT NULL,
    old_value   JSONB,
    new_value   JSONB,
    ip_address  INET,
    user_agent  TEXT,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- CRM: Customers
CREATE TABLE IF NOT EXISTS boc_customers (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    name        TEXT NOT NULL,
    email       TEXT,
    phone       TEXT,
    company     TEXT,
    org_number  TEXT,
    address     JSONB,
    status      TEXT NOT NULL DEFAULT 'lead',
    source      TEXT,
    tags        TEXT[] DEFAULT '{}',
    metadata    JSONB DEFAULT '{}',
    assigned_to UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- CRM: Customer interactions
CREATE TABLE IF NOT EXISTS boc_customer_interactions (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    customer_id UUID REFERENCES boc_customers(id) ON DELETE CASCADE,
    type        TEXT NOT NULL, -- call, email, meeting, note, task
    direction   TEXT, -- inbound, outbound
    subject     TEXT,
    content     TEXT,
    metadata    JSONB DEFAULT '{}',
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- CRM: Contacts (people within customer orgs)
CREATE TABLE IF NOT EXISTS boc_contacts (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    customer_id UUID REFERENCES boc_customers(id) ON DELETE CASCADE,
    name        TEXT NOT NULL,
    email       TEXT,
    phone       TEXT,
    title       TEXT,
    is_primary  BOOLEAN DEFAULT FALSE,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Sales: Deals
CREATE TABLE IF NOT EXISTS boc_deals (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    customer_id     UUID REFERENCES boc_customers(id),
    contact_id      UUID REFERENCES boc_contacts(id),
    name            TEXT NOT NULL,
    description     TEXT,
    value           DECIMAL(15,2) NOT NULL DEFAULT 0,
    currency        TEXT NOT NULL DEFAULT 'USD',
    status          TEXT NOT NULL DEFAULT 'open',
    stage           TEXT NOT NULL DEFAULT 'prospect',
    probability     INTEGER NOT NULL DEFAULT 0,
    expected_close  DATE,
    actual_close    TIMESTAMPTZ,
    won_reason      TEXT,
    lost_reason     TEXT,
    tags            TEXT[] DEFAULT '{}',
    metadata        JSONB DEFAULT '{}',
    assigned_to     UUID REFERENCES boc_users(id),
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Sales: Deal timeline / activities
CREATE TABLE IF NOT EXISTS boc_deal_activities (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    deal_id     UUID REFERENCES boc_deals(id) ON DELETE CASCADE,
    type        TEXT NOT NULL, -- call, email, meeting, proposal, note, stage_change
    description TEXT,
    metadata    JSONB DEFAULT '{}',
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Sales: Products/Services
CREATE TABLE IF NOT EXISTS boc_products (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    name        TEXT NOT NULL,
    description TEXT,
    sku         TEXT,
    price       DECIMAL(15,2) NOT NULL DEFAULT 0,
    currency    TEXT NOT NULL DEFAULT 'USD',
    unit        TEXT DEFAULT 'piece',
    is_recurring BOOLEAN DEFAULT FALSE,
    billing_period TEXT, -- monthly, quarterly, yearly
    status      TEXT NOT NULL DEFAULT 'active',
    metadata    JSONB DEFAULT '{}',
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Sales: Deal line items
CREATE TABLE IF NOT EXISTS boc_deal_items (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    deal_id     UUID REFERENCES boc_deals(id) ON DELETE CASCADE,
    product_id  UUID REFERENCES boc_products(id),
    quantity    DECIMAL(10,2) NOT NULL DEFAULT 1,
    unit_price  DECIMAL(15,2) NOT NULL DEFAULT 0,
    discount    DECIMAL(5,2) DEFAULT 0,
    total       DECIMAL(15,2) NOT NULL DEFAULT 0,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Finance: Invoices
CREATE TABLE IF NOT EXISTS boc_invoices (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    customer_id UUID REFERENCES boc_customers(id),
    deal_id     UUID REFERENCES boc_deals(id),
    invoice_number TEXT NOT NULL,
    amount      DECIMAL(15,2) NOT NULL DEFAULT 0,
    tax_amount  DECIMAL(15,2) DEFAULT 0,
    currency    TEXT NOT NULL DEFAULT 'USD',
    status      TEXT NOT NULL DEFAULT 'draft',
    due_date    DATE,
    paid_at     TIMESTAMPTZ,
    paid_amount DECIMAL(15,2) DEFAULT 0,
    notes       TEXT,
    metadata    JSONB DEFAULT '{}',
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Finance: Invoice items
CREATE TABLE IF NOT EXISTS boc_invoice_items (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    invoice_id  UUID REFERENCES boc_invoices(id) ON DELETE CASCADE,
    description TEXT NOT NULL,
    quantity    DECIMAL(10,2) NOT NULL DEFAULT 1,
    unit_price  DECIMAL(15,2) NOT NULL DEFAULT 0,
    tax_rate    DECIMAL(5,2) DEFAULT 0,
    total       DECIMAL(15,2) NOT NULL DEFAULT 0,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Finance: Payments
CREATE TABLE IF NOT EXISTS boc_payments (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    invoice_id  UUID REFERENCES boc_invoices(id),
    amount      DECIMAL(15,2) NOT NULL,
    currency    TEXT NOT NULL DEFAULT 'USD',
    method      TEXT, -- bank_transfer, card, cash, stripe, etc
    reference   TEXT,
    status      TEXT NOT NULL DEFAULT 'completed',
    metadata    JSONB DEFAULT '{}',
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Finance: Expenses
CREATE TABLE IF NOT EXISTS boc_expenses (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    category    TEXT NOT NULL,
    description TEXT NOT NULL,
    amount      DECIMAL(15,2) NOT NULL,
    currency    TEXT NOT NULL DEFAULT 'USD',
    vendor      TEXT,
    receipt_url TEXT,
    status      TEXT NOT NULL DEFAULT 'pending',
    approved_by UUID REFERENCES boc_users(id),
    approved_at TIMESTAMPTZ,
    metadata    JSONB DEFAULT '{}',
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Finance: Budgets
CREATE TABLE IF NOT EXISTS boc_budgets (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    name        TEXT NOT NULL,
    fiscal_year INTEGER NOT NULL,
    category    TEXT,
    amount      DECIMAL(15,2) NOT NULL,
    currency    TEXT NOT NULL DEFAULT 'USD',
    spent       DECIMAL(15,2) DEFAULT 0,
    status      TEXT NOT NULL DEFAULT 'active',
    metadata    JSONB DEFAULT '{}',
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- HR: Employees
CREATE TABLE IF NOT EXISTS boc_employees (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    user_id     UUID REFERENCES boc_users(id),
    first_name  TEXT NOT NULL,
    last_name   TEXT NOT NULL,
    email       TEXT NOT NULL,
    phone       TEXT,
    department  TEXT,
    position    TEXT,
    employment_type TEXT DEFAULT 'full_time',
    salary      DECIMAL(15,2),
    currency    TEXT DEFAULT 'USD',
    start_date  DATE,
    end_date    DATE,
    manager_id  UUID REFERENCES boc_employees(id),
    address     JSONB,
    bank_info   JSONB,
    documents   JSONB DEFAULT '{}',
    status      TEXT NOT NULL DEFAULT 'active',
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- HR: Time off / Leave
CREATE TABLE IF NOT EXISTS boc_leaves (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    employee_id UUID REFERENCES boc_employees(id) ON DELETE CASCADE,
    type        TEXT NOT NULL, -- vacation, sick, parental, unpaid
    start_date  DATE NOT NULL,
    end_date    DATE NOT NULL,
    days        DECIMAL(4,1) NOT NULL,
    status      TEXT NOT NULL DEFAULT 'pending',
    approved_by UUID REFERENCES boc_users(id),
    approved_at TIMESTAMPTZ,
    notes       TEXT,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- HR: Timesheets
CREATE TABLE IF NOT EXISTS boc_timesheets (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    employee_id UUID REFERENCES boc_employees(id) ON DELETE CASCADE,
    date        DATE NOT NULL,
    hours       DECIMAL(4,2) NOT NULL DEFAULT 0,
    project     TEXT,
    task        TEXT,
    description TEXT,
    status      TEXT NOT NULL DEFAULT 'draft',
    approved_by UUID REFERENCES boc_users(id),
    approved_at TIMESTAMPTZ,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE(tenant_id, employee_id, date)
);

-- Legal: Contracts
CREATE TABLE IF NOT EXISTS boc_contracts (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    title       TEXT NOT NULL,
    counterparty TEXT NOT NULL,
    type        TEXT NOT NULL, -- service, employment, nda, partnership, etc
    status      TEXT NOT NULL DEFAULT 'draft',
    value       DECIMAL(15,2),
    currency    TEXT DEFAULT 'USD',
    start_date  DATE,
    end_date    DATE,
    renewal_date DATE,
    document_url TEXT,
    metadata    JSONB DEFAULT '{}',
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Legal: Contract reminders
CREATE TABLE IF NOT EXISTS boc_contract_reminders (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    contract_id UUID REFERENCES boc_contracts(id) ON DELETE CASCADE,
    type        TEXT NOT NULL, -- renewal, expiration, payment, review
    due_date    DATE NOT NULL,
    status      TEXT NOT NULL DEFAULT 'pending',
    sent_at     TIMESTAMPTZ,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Marketing: Campaigns
CREATE TABLE IF NOT EXISTS boc_campaigns (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    name        TEXT NOT NULL,
    description TEXT,
    type        TEXT NOT NULL, -- email, social, content, event, ad
    status      TEXT NOT NULL DEFAULT 'draft',
    budget      DECIMAL(15,2),
    spent       DECIMAL(15,2) DEFAULT 0,
    currency    TEXT DEFAULT 'USD',
    start_date  DATE,
    end_date    DATE,
    metrics     JSONB DEFAULT '{}',
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Marketing: Content items
CREATE TABLE IF NOT EXISTS boc_content (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    campaign_id UUID REFERENCES boc_campaigns(id),
    title       TEXT NOT NULL,
    type        TEXT NOT NULL, -- blog, social, email, video, whitepaper
    status      TEXT NOT NULL DEFAULT 'draft',
    publish_at  TIMESTAMPTZ,
    published_at TIMESTAMPTZ,
    url         TEXT,
    metrics     JSONB DEFAULT '{}',
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Support: Tickets
CREATE TABLE IF NOT EXISTS boc_tickets (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    customer_id UUID REFERENCES boc_customers(id),
    contact_id  UUID REFERENCES boc_contacts(id),
    subject     TEXT NOT NULL,
    description TEXT,
    status      TEXT NOT NULL DEFAULT 'open',
    priority    TEXT NOT NULL DEFAULT 'medium',
    category    TEXT,
    source      TEXT, -- email, chat, phone, web
    assigned_to UUID REFERENCES boc_users(id),
    resolved_at TIMESTAMPTZ,
    resolution  TEXT,
    metadata    JSONB DEFAULT '{}',
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Support: Ticket comments
CREATE TABLE IF NOT EXISTS boc_ticket_comments (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    ticket_id   UUID REFERENCES boc_tickets(id) ON DELETE CASCADE,
    content     TEXT NOT NULL,
    is_internal BOOLEAN DEFAULT FALSE,
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Automation: Workflows
CREATE TABLE IF NOT EXISTS boc_workflows (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    name        TEXT NOT NULL,
    description TEXT,
    trigger_type TEXT NOT NULL, -- schedule, event, webhook, manual
    trigger_config JSONB DEFAULT '{}',
    actions     JSONB NOT NULL DEFAULT '[]',
    status      TEXT NOT NULL DEFAULT 'active',
    last_run_at TIMESTAMPTZ,
    next_run_at TIMESTAMPTZ,
    run_count   INTEGER DEFAULT 0,
    fail_count  INTEGER DEFAULT 0,
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Automation: Workflow runs
CREATE TABLE IF NOT EXISTS boc_workflow_runs (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    workflow_id UUID REFERENCES boc_workflows(id) ON DELETE CASCADE,
    status      TEXT NOT NULL DEFAULT 'running',
    input       JSONB DEFAULT '{}',
    output      JSONB DEFAULT '{}',
    error       TEXT,
    started_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    completed_at TIMESTAMPTZ
);

-- Automation: Scheduled jobs
CREATE TABLE IF NOT EXISTS boc_scheduled_jobs (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    name        TEXT NOT NULL,
    description TEXT,
    cron_expr   TEXT NOT NULL,
    timezone    TEXT DEFAULT 'UTC',
    job_type    TEXT NOT NULL, -- report, reminder, sync, cleanup, backup
    job_config  JSONB DEFAULT '{}',
    status      TEXT NOT NULL DEFAULT 'active',
    last_run_at TIMESTAMPTZ,
    next_run_at TIMESTAMPTZ,
    run_count   INTEGER DEFAULT 0,
    fail_count  INTEGER DEFAULT 0,
    created_by  UUID REFERENCES boc_users(id),
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Automation: Scheduled job runs
CREATE TABLE IF NOT EXISTS boc_scheduled_job_runs (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id   UUID REFERENCES boc_tenants(id) ON DELETE CASCADE,
    job_id      UUID REFERENCES boc_scheduled_jobs(id) ON DELETE CASCADE,
    status      TEXT NOT NULL DEFAULT 'running',
    output      JSONB DEFAULT '{}',
    error       TEXT,
    started_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    completed_at TIMESTAMPTZ
);

-- Indexes
CREATE INDEX IF NOT EXISTS idx_audit_tenant ON boc_audit_log(tenant_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_customers_tenant ON boc_customers(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_customers_assigned ON boc_customers(assigned_to);
CREATE INDEX IF NOT EXISTS idx_interactions_customer ON boc_customer_interactions(customer_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_deals_tenant ON boc_deals(tenant_id, status, stage);
CREATE INDEX IF NOT EXISTS idx_deals_customer ON boc_deals(customer_id);
CREATE INDEX IF NOT EXISTS idx_deals_assigned ON boc_deals(assigned_to);
CREATE INDEX IF NOT EXISTS idx_deals_expected_close ON boc_deals(expected_close);
CREATE INDEX IF NOT EXISTS idx_invoices_tenant ON boc_invoices(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_invoices_due ON boc_invoices(due_date);
CREATE INDEX IF NOT EXISTS idx_expenses_tenant ON boc_expenses(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_employees_tenant ON boc_employees(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_leaves_employee ON boc_leaves(employee_id, start_date);
CREATE INDEX IF NOT EXISTS idx_timesheets_employee ON boc_timesheets(employee_id, date);
CREATE INDEX IF NOT EXISTS idx_contracts_tenant ON boc_contracts(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_contracts_renewal ON boc_contracts(renewal_date);
CREATE INDEX IF NOT EXISTS idx_tickets_tenant ON boc_tickets(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_tickets_assigned ON boc_tickets(assigned_to);
CREATE INDEX IF NOT EXISTS idx_workflows_tenant ON boc_workflows(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_scheduled_jobs_tenant ON boc_scheduled_jobs(tenant_id, status);

-- Functions
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ language 'plpgsql';

-- Triggers for updated_at
DO $$
BEGIN
    CREATE TRIGGER update_boc_tenants_updated_at BEFORE UPDATE ON boc_tenants FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_users_updated_at BEFORE UPDATE ON boc_users FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_customers_updated_at BEFORE UPDATE ON boc_customers FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_deals_updated_at BEFORE UPDATE ON boc_deals FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_invoices_updated_at BEFORE UPDATE ON boc_invoices FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_expenses_updated_at BEFORE UPDATE ON boc_expenses FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_budgets_updated_at BEFORE UPDATE ON boc_budgets FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_employees_updated_at BEFORE UPDATE ON boc_employees FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_leaves_updated_at BEFORE UPDATE ON boc_leaves FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_timesheets_updated_at BEFORE UPDATE ON boc_timesheets FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_contracts_updated_at BEFORE UPDATE ON boc_contracts FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_campaigns_updated_at BEFORE UPDATE ON boc_campaigns FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_content_updated_at BEFORE UPDATE ON boc_content FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_tickets_updated_at BEFORE UPDATE ON boc_tickets FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_workflows_updated_at BEFORE UPDATE ON boc_workflows FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
    CREATE TRIGGER update_boc_scheduled_jobs_updated_at BEFORE UPDATE ON boc_scheduled_jobs FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
EXCEPTION WHEN duplicate_object THEN
    -- Triggers already exist, ignore
END;
$$;
