From 906936a2d1ffb6cd6ee3f7094c4ece608341722e Mon Sep 17 00:00:00 2001 From: simonkoson <28867558@qq.com> Date: Mon, 11 May 2026 10:35:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20episodes.editor=5Fname=5Fsnapshot=20?= =?UTF-8?q?=E5=8A=A0=20NOT=20NULL=20=E7=BA=A6=E6=9D=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/sql/001_init.sql | 238 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 backend/sql/001_init.sql diff --git a/backend/sql/001_init.sql b/backend/sql/001_init.sql new file mode 100644 index 0000000..25e5bee --- /dev/null +++ b/backend/sql/001_init.sql @@ -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) +); + +-- ============================================================ +-- 初始化完成 +-- ============================================================ \ No newline at end of file