CREATE TABLE kol_profiles ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), user_id BIGINT NOT NULL REFERENCES users(id), display_name VARCHAR(100) NOT NULL, bio TEXT, avatar_url TEXT, market_enabled BOOLEAN NOT NULL DEFAULT FALSE, status VARCHAR(20) NOT NULL DEFAULT 'active', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE UNIQUE INDEX uk_kol_profile_user_active ON kol_profiles(user_id) WHERE deleted_at IS NULL; CREATE INDEX idx_kol_profile_tenant ON kol_profiles(tenant_id) WHERE deleted_at IS NULL; CREATE TABLE kol_packages ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), kol_profile_id BIGINT NOT NULL REFERENCES kol_profiles(id), name VARCHAR(200) NOT NULL, description TEXT, cover_url TEXT, industry VARCHAR(100), tags JSONB NOT NULL DEFAULT '[]', price_note VARCHAR(200), status VARCHAR(20) NOT NULL DEFAULT 'draft', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE INDEX idx_kol_package_profile ON kol_packages(kol_profile_id, created_at DESC) WHERE deleted_at IS NULL; CREATE INDEX idx_kol_package_status ON kol_packages(status, created_at DESC) WHERE deleted_at IS NULL; CREATE TABLE kol_prompts ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), package_id BIGINT NOT NULL REFERENCES kol_packages(id), name VARCHAR(200) NOT NULL, platform_hint VARCHAR(100), status VARCHAR(20) NOT NULL DEFAULT 'draft', sort_order INT NOT NULL DEFAULT 0, published_revision_no INT, draft_revision_no INT, created_by BIGINT NOT NULL REFERENCES users(id), updated_by BIGINT NOT NULL REFERENCES users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE INDEX idx_kol_prompt_package ON kol_prompts(package_id, sort_order, created_at) WHERE deleted_at IS NULL; CREATE INDEX idx_kol_prompt_tenant_status ON kol_prompts(tenant_id, status, created_at DESC) WHERE deleted_at IS NULL; CREATE TABLE kol_prompt_revisions ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), prompt_id BIGINT NOT NULL REFERENCES kol_prompts(id), revision_no INT NOT NULL, prompt_asset_key TEXT NOT NULL, schema_json JSONB NOT NULL DEFAULT '{}', card_config_json JSONB NOT NULL DEFAULT '{}', created_by BIGINT NOT NULL REFERENCES users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE (prompt_id, revision_no) ); CREATE INDEX idx_kol_prompt_revision_prompt ON kol_prompt_revisions(prompt_id, revision_no DESC); CREATE TABLE kol_subscriptions ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), package_id BIGINT NOT NULL REFERENCES kol_packages(id), status VARCHAR(20) NOT NULL DEFAULT 'pending', approved_by BIGINT REFERENCES users(id), start_at TIMESTAMPTZ, end_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE UNIQUE INDEX uk_kol_subscription_active ON kol_subscriptions(tenant_id, package_id) WHERE status IN ('pending', 'active'); CREATE INDEX idx_kol_subscription_package ON kol_subscriptions(package_id, status, created_at DESC); CREATE TABLE kol_subscription_prompts ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), subscription_id BIGINT NOT NULL REFERENCES kol_subscriptions(id), package_id BIGINT NOT NULL REFERENCES kol_packages(id), prompt_id BIGINT NOT NULL REFERENCES kol_prompts(id), status VARCHAR(20) NOT NULL DEFAULT 'active', granted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), revoked_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE UNIQUE INDEX uk_kol_subscription_prompt ON kol_subscription_prompts(subscription_id, prompt_id); CREATE INDEX idx_kol_subscription_prompt_tenant ON kol_subscription_prompts(tenant_id, status, created_at DESC); CREATE TABLE kol_usage_logs ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), subscription_id BIGINT REFERENCES kol_subscriptions(id), subscription_prompt_id BIGINT REFERENCES kol_subscription_prompts(id), package_id BIGINT NOT NULL REFERENCES kol_packages(id), prompt_id BIGINT NOT NULL REFERENCES kol_prompts(id), prompt_revision_no INT NOT NULL, article_id BIGINT REFERENCES articles(id), generation_task_id BIGINT REFERENCES generation_tasks(id), status VARCHAR(20) NOT NULL DEFAULT 'pending', variables_snapshot JSONB, schema_snapshot JSONB, rendered_prompt_hash VARCHAR(64), error_message TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), finished_at TIMESTAMPTZ ); CREATE INDEX idx_kol_usage_package ON kol_usage_logs(package_id, created_at DESC); CREATE INDEX idx_kol_usage_tenant ON kol_usage_logs(tenant_id, created_at DESC); CREATE INDEX idx_kol_usage_prompt ON kol_usage_logs(prompt_id, created_at DESC); CREATE TABLE kol_assist_tasks ( id VARCHAR(64) PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), kol_profile_id BIGINT NOT NULL REFERENCES kol_profiles(id), prompt_id BIGINT REFERENCES kol_prompts(id), operator_id BIGINT NOT NULL REFERENCES users(id), task_type VARCHAR(50) NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'queued', request_json JSONB NOT NULL DEFAULT '{}'::jsonb, result_json JSONB, error_message TEXT, started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_kol_assist_tenant_profile ON kol_assist_tasks(tenant_id, kol_profile_id, created_at DESC); CREATE INDEX idx_kol_assist_status ON kol_assist_tasks(status, created_at DESC);