-- 日内新闻候选与验证持久化结构 CREATE TABLE IF NOT EXISTS intraday_news_candidate ( id BIGSERIAL PRIMARY KEY, candidate_date DATE NOT NULL, discovered_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, event_type TEXT NOT NULL, provider_name TEXT NOT NULL, model_name TEXT, provider_country TEXT, title TEXT NOT NULL, summary TEXT, candidate_urls JSONB NOT NULL DEFAULT '[]'::jsonb, discovery_source TEXT NOT NULL, discovery_query TEXT, discovery_evidence JSONB NOT NULL DEFAULT '{}'::jsonb, normalized_key TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'candidate', verification_confidence TEXT NOT NULL DEFAULT 'candidate', verification_notes TEXT, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM pg_constraint WHERE conname = 'chk_intraday_news_candidate_status' ) THEN ALTER TABLE intraday_news_candidate ADD CONSTRAINT chk_intraday_news_candidate_status CHECK (status IN ('candidate', 'verifying', 'verified', 'rejected', 'stale')); END IF; IF NOT EXISTS ( SELECT 1 FROM pg_constraint WHERE conname = 'chk_intraday_news_candidate_confidence' ) THEN ALTER TABLE intraday_news_candidate ADD CONSTRAINT chk_intraday_news_candidate_confidence CHECK (verification_confidence IN ('candidate', 'secondary_confirmed', 'official_confirmed')); END IF; END $$; CREATE UNIQUE INDEX IF NOT EXISTS idx_intraday_news_candidate_normalized_key ON intraday_news_candidate(normalized_key); CREATE INDEX IF NOT EXISTS idx_intraday_news_candidate_date ON intraday_news_candidate(candidate_date DESC, discovered_at DESC); CREATE INDEX IF NOT EXISTS idx_intraday_news_candidate_status ON intraday_news_candidate(status); CREATE INDEX IF NOT EXISTS idx_intraday_news_candidate_provider_event ON intraday_news_candidate(provider_name, event_type, candidate_date DESC); COMMENT ON TABLE intraday_news_candidate IS '搜索引擎与 LLM 发现的日内新闻候选池,尚未直接进入正式日报事实层'; COMMENT ON COLUMN intraday_news_candidate.candidate_urls IS '候选来源 URL 数组,按发现层输出原样保留'; COMMENT ON COLUMN intraday_news_candidate.discovery_evidence IS '发现阶段原始证据 JSONB,例如搜索命中、LLM 归纳结果'; COMMENT ON COLUMN intraday_news_candidate.normalized_key IS '同日同事件的去重键,避免重复发现候选'; CREATE TABLE IF NOT EXISTS intraday_news_verification ( id BIGSERIAL PRIMARY KEY, candidate_id BIGINT NOT NULL REFERENCES intraday_news_candidate(id) ON DELETE CASCADE, verified_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, verifier_source TEXT NOT NULL, verifier_url TEXT, verifier_status TEXT NOT NULL, extracted_facts JSONB NOT NULL DEFAULT '{}'::jsonb, notes TEXT, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM pg_constraint WHERE conname = 'chk_intraday_news_verification_status' ) THEN ALTER TABLE intraday_news_verification ADD CONSTRAINT chk_intraday_news_verification_status CHECK (verifier_status IN ('matched', 'contradicted', 'insufficient', 'error')); END IF; END $$; CREATE INDEX IF NOT EXISTS idx_intraday_news_verification_candidate_verified_at ON intraday_news_verification(candidate_id, verified_at DESC); CREATE INDEX IF NOT EXISTS idx_intraday_news_verification_source ON intraday_news_verification(verifier_source); CREATE INDEX IF NOT EXISTS idx_intraday_news_verification_status ON intraday_news_verification(verifier_status); COMMENT ON TABLE intraday_news_verification IS '日内新闻候选的验证轨迹,记录验证来源、状态和提取事实'; COMMENT ON COLUMN intraday_news_verification.extracted_facts IS '验证阶段提取出的结构化事实 JSONB'; DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM pg_trigger WHERE tgname = 'intraday_news_candidate_updated_at' ) THEN CREATE TRIGGER intraday_news_candidate_updated_at BEFORE UPDATE ON intraday_news_candidate FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; END $$;