feat: episodes.editor_name_snapshot 加 NOT NULL 约束
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
-- ============================================================
|
||||
-- 001_init.sql — 《军事科技》栏目内部工作台 数据库初始化脚本
|
||||
-- 一次性建完所有核心表骨架(Phase 1-4 全部表)
|
||||
-- 执行方式: psql -U postgres -d milsci_dev -f 001_init.sql
|
||||
-- ============================================================
|
||||
|
||||
-- 扩展: pgvector(向量检索)
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
|
||||
-- ============================================================
|
||||
-- 1. users — 用户表(Phase 1 用)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(50) NOT NULL UNIQUE,
|
||||
display_name VARCHAR(100) NOT NULL,
|
||||
password_hash VARCHAR(128) NOT NULL,
|
||||
-- 角色: zhipianren=制片人/管理员, zebian=责编, biandao=编导
|
||||
role VARCHAR(20) NOT NULL DEFAULT 'biandao'
|
||||
CHECK (role IN ('zhipianren', 'zebian', 'biandao')),
|
||||
profile_text TEXT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_users_role ON users (role);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. episodes — 节目期次(Phase 2 用,字段完整按 dev_plan.md 8.1 节)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS episodes (
|
||||
id SERIAL PRIMARY KEY,
|
||||
episode_number INTEGER NOT NULL UNIQUE,
|
||||
program_name VARCHAR(200) NOT NULL,
|
||||
air_date DATE NOT NULL,
|
||||
-- 编导(软引用 + 快照模式)
|
||||
editor_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
editor_name_snapshot VARCHAR(100) NOT NULL,
|
||||
-- 收视数据
|
||||
audience_share NUMERIC(6,4),
|
||||
audience_rating NUMERIC(6,4),
|
||||
-- 重播相关
|
||||
is_rerun BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
original_episode_id INTEGER REFERENCES episodes(id) ON DELETE SET NULL,
|
||||
is_time_sensitive BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
-- 外拍信息
|
||||
is_outdoor_shoot BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
outdoor_contact_person VARCHAR(100),
|
||||
outdoor_contact_info VARCHAR(200),
|
||||
-- 线索
|
||||
lead_source VARCHAR(300),
|
||||
-- 责编备注
|
||||
notes TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_episodes_air_date ON episodes (air_date);
|
||||
CREATE INDEX idx_episodes_editor_id ON episodes (editor_id);
|
||||
CREATE INDEX idx_episodes_is_rerun ON episodes (is_rerun);
|
||||
|
||||
-- ============================================================
|
||||
-- 3. yearly_targets — 年度收视目标(Phase 2 用,只增不改)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS yearly_targets (
|
||||
id SERIAL PRIMARY KEY,
|
||||
year INTEGER NOT NULL UNIQUE,
|
||||
base_target NUMERIC(6,4) NOT NULL,
|
||||
stretch_target NUMERIC(6,4) NOT NULL,
|
||||
issued_date DATE,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- ============================================================
|
||||
-- 4. topics — 选题 / 报题单(Phase 4a 用)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS topics (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title VARCHAR(200) NOT NULL,
|
||||
-- 内容概要(双段结构: 引子 + 列举)
|
||||
content_summary TEXT,
|
||||
-- 编导关联(软引用 + 快照)
|
||||
editor_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
editor_name_snapshot VARCHAR(100),
|
||||
-- 选题状态: draft=草稿, submitted=已提交, reviewing=审阅中, approved=通过, rejected=退回
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'draft'
|
||||
CHECK (status IN ('draft', 'submitted', 'reviewing', 'approved', 'rejected')),
|
||||
-- AI 反馈(JSON 格式,含查重/画像/知识库参考等模块结果)
|
||||
ai_feedback JSONB,
|
||||
-- 关联的 episodes / knowledge_items id 列表
|
||||
related_episodes JSONB,
|
||||
related_knowledge JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_topics_editor_id ON topics (editor_id);
|
||||
CREATE INDEX idx_topics_status ON topics (status);
|
||||
|
||||
-- ============================================================
|
||||
-- 5. topic_embeddings — 选题语义向量(Phase 4a 用,pgvector)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS topic_embeddings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
topic_id INTEGER NOT NULL REFERENCES topics(id) ON DELETE CASCADE,
|
||||
embedding vector(1536) NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_topic_embeddings_topic_id ON topic_embeddings (topic_id);
|
||||
-- pgvector 向量索引(IVFFlat,数据量上去后可用 HNSW)
|
||||
-- CREATE INDEX idx_topic_embeddings_vector ON topic_embeddings USING ivfflat (embedding vector_cosine_ops);
|
||||
|
||||
-- ============================================================
|
||||
-- 6. schedules — 排期(Phase 4b 用)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS schedules (
|
||||
id SERIAL PRIMARY KEY,
|
||||
episode_id INTEGER REFERENCES episodes(id) ON DELETE SET NULL,
|
||||
planned_air_date DATE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'planned'
|
||||
CHECK (status IN ('planned', 'confirmed', 'completed', 'cancelled')),
|
||||
editor_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_schedules_air_date ON schedules (planned_air_date);
|
||||
|
||||
-- ============================================================
|
||||
-- 7. knowledge_items — 知识库条目(Phase 3 用,2.0 兼容预埋)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS knowledge_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title VARCHAR(300) NOT NULL,
|
||||
-- Markdown 格式正文(向 2.0 Karpathy LLM Wiki 形态靠拢)
|
||||
content_md TEXT,
|
||||
-- 来源信息
|
||||
source_type VARCHAR(30) NOT NULL DEFAULT 'manual'
|
||||
CHECK (source_type IN ('baoti', 'manuscript', 'military_report', 'manual', 'rss')),
|
||||
source_file_name VARCHAR(300),
|
||||
source_url VARCHAR(1000),
|
||||
-- 作者 / 编导
|
||||
author VARCHAR(100),
|
||||
publish_date DATE,
|
||||
-- ⚠️ 2.0 兼容预埋字段(1.0 不用但要建)
|
||||
tags JSONB DEFAULT '[]'::jsonb,
|
||||
related_entities JSONB DEFAULT '[]'::jsonb,
|
||||
related_concepts JSONB DEFAULT '[]'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_knowledge_items_source_type ON knowledge_items (source_type);
|
||||
CREATE INDEX idx_knowledge_items_tags ON knowledge_items USING gin (tags);
|
||||
|
||||
-- ============================================================
|
||||
-- 8. knowledge_embeddings — 知识库向量(Phase 3 用,pgvector)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS knowledge_embeddings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
knowledge_id INTEGER NOT NULL REFERENCES knowledge_items(id) ON DELETE CASCADE,
|
||||
chunk_index INTEGER NOT NULL DEFAULT 0,
|
||||
chunk_text TEXT NOT NULL,
|
||||
embedding vector(1536) NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_knowledge_embeddings_knowledge_id ON knowledge_embeddings (knowledge_id);
|
||||
-- pgvector 向量索引
|
||||
-- CREATE INDEX idx_knowledge_embeddings_vector ON knowledge_embeddings USING ivfflat (embedding vector_cosine_ops);
|
||||
|
||||
-- ============================================================
|
||||
-- 9. review_comments — 审片意见(Phase 4b 用)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS review_comments (
|
||||
id SERIAL PRIMARY KEY,
|
||||
episode_id INTEGER NOT NULL REFERENCES episodes(id) ON DELETE CASCADE,
|
||||
comment_text TEXT NOT NULL,
|
||||
reviewer VARCHAR(100),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_review_comments_episode_id ON review_comments (episode_id);
|
||||
|
||||
-- ============================================================
|
||||
-- 10. shooting_resources — 拍摄资源 / 人脉(Phase 4b 用)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS shooting_resources (
|
||||
id SERIAL PRIMARY KEY,
|
||||
contact_person VARCHAR(100) NOT NULL,
|
||||
contact_info VARCHAR(200),
|
||||
organization VARCHAR(200),
|
||||
-- 资源类型: personnel=人员, location=场地, equipment=设备, other=其他
|
||||
resource_type VARCHAR(20) DEFAULT 'other'
|
||||
CHECK (resource_type IN ('personnel', 'location', 'equipment', 'other')),
|
||||
notes TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- ============================================================
|
||||
-- 11. radar_items — 热点雷达条目(Phase 4c 用)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS radar_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title VARCHAR(300) NOT NULL,
|
||||
source_url VARCHAR(1000),
|
||||
source_name VARCHAR(100),
|
||||
summary TEXT,
|
||||
-- AI 处理结果
|
||||
ai_summary TEXT,
|
||||
style_summary TEXT,
|
||||
published_at TIMESTAMPTZ,
|
||||
fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- ============================================================
|
||||
-- 12. radar_user_actions — 编导对热点的操作(Phase 4c 用)
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS radar_user_actions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
radar_item_id INTEGER NOT NULL REFERENCES radar_items(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
-- 操作类型: deep_dive=深入了解, bookmark=收藏, ignore=忽略
|
||||
action_type VARCHAR(20) NOT NULL
|
||||
CHECK (action_type IN ('deep_dive', 'bookmark', 'ignore')),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (radar_item_id, user_id, action_type)
|
||||
);
|
||||
|
||||
-- ============================================================
|
||||
-- 初始化完成
|
||||
-- ============================================================
|
||||
Reference in New Issue
Block a user