跳转到内容

02-当前系统现实

文档性质:当前系统唯一真相源 + 目标理想差距总账
用途:统一记录 Yomiya 当前服务端已经存在的内容对象、字段、关系、标签机制、唯一性约束,以及后续研究要补齐的目标理想与行动项
适用范围01-当前目标与范围.md03-新资源入库流程.md04-内容样本池.md 之间所有涉及“当前现实 / 目标理想 / 差距动作”的讨论
规则

  • 凡涉及当前服务端已存在什么对象、字段、关系、标签、唯一性约束,以本文件为准
  • 凡涉及目标理想与改造动作,也先回写本文件,再同步 03-新资源入库流程.md04-内容样本池.md
  • archive/specs/ 负责保留旧规格,不负责证明某个对象已经在服务端落库
  • archive/research/ 负责保留研究样本与判断,不直接改写当前现实 最后更新:2026-04-06

如果第一次读 Yomiya 内容系统,先只记这 8 句:

  1. 当前真正承载内容条目的正式主表,还是 news
  2. 当前唯一长期归属是 news.channel_id -> channels
  3. 当前 scene 不是 news 主表字段,而是 scenes + news_scenes 关系层能力
  4. 当前公开 Tag 机制只正式暴露 level / scene / premium
  5. news.source 当前只表达进入路径:news / imports,不表达平台来源
  6. 当前服务端已经正式区分 collected/newsuser_imported/imports 两条内容进入路径
  7. 我们提供的官方内容会跑风控、难度、scene;用户导入内容当前不会跑风控和难度
  8. 当前前台公开内容读取默认只取 source = news,且服务端里还没有正式 collections / collection_items / series / topic

本文件不靠概念讨论落结论,主要证据来自 yomiya-service 当前仓库。

证据文件说明本文件用它证明什么
internal/infrastructure/database/migration/20250519052734_news_sentences_tokens.sql初始 news 表结构news 是当前正式内容主表;visibility 早已存在
internal/infrastructure/database/migration/20250729092341_create_channels.sqlchannels 表 migrationchannels 已正式存在,且 channels.name 有唯一键
internal/infrastructure/database/migration/20250729210800_create_scenes.sqlscenes 表 migrationscenes 已正式存在,但只有索引,没有三元唯一键
internal/infrastructure/database/migration/20250813190617_create_news_scenes.sqlnews_scenes 关系表 migrationscene 当前通过关系表挂在 news 上,且 (news_id, scene_id) 有唯一约束
internal/infrastructure/database/migration/20260109120000_create_content_import_tables.sqluser_content_importstranscription_tasks migration用户导入链路当前已有正式支持对象,不只是文档概念
internal/infrastructure/database/migration/20260120000000_add_source_and_type_to_news.sqlnews.sourcenews.type migrationsource 当前现实是 news / importstype 当前现实是 webpage / video / audio
internal/application/dto/news.go对外 DTO当前公开 TagType 只有 level / scene / premium;Admin API 暴露 primary_scenes / secondary_scenes
internal/application/news.goDTO 组装逻辑scene 标签来自 news_scenespremium 标签来自 visibility 衍生
internal/application/content_processing/profile_resolver.go内容处理 profile 解析当前已经正式区分官方供给与用户导入的处理策略;官方内容会跑风控 / 难度,用户导入不会
internal/application/content_processing/raw_lifecycle.goRaw 内容状态收口风控结果当前会落到 raw_news.status / risk_check_status,被拦截内容会进入 REJECTED / BLOCKED
internal/repository/news_repo_impl.go前台公开内容查询当前公开内容读取默认只取 news.source = newsimports 不会自动进入官方分发池
internal/infrastructure/database/migration/20260328074037_create_youtube_channels.sqlYouTube 频道映射表当前只有 YouTube 有正式外部品牌映射表,播客 / B 站还没有统一品牌层落库
internal/crawler/youtube_channel/youtube_channel_crawler.go系统级 YouTube 自动抓取系统抓取会直接进入统一处理链路,但不会创建 user_content_imports 记录

补充判断:

  • 截至 2026-04-04,yomiya-service 当前 migration 树里没有 collectionscollection_itemsseriestopics 相关正式 DDL
  • 当前官方分发链路与用户导入链路已经在服务端分开,但“分发资格”仍未独立成正式字段或状态机
  • 因此,Collection / Series / Topic 现在仍属于目标理想与执行目标,不是当前后端现实

变更对象动作现在的问题为什么这样改不这样改会怎样关联系统证据后续动作
当前系统现实新增唯一真相源目标文档和研究文档都可能写“系统现在有什么”,口径容易漂移把“现实 / 理想 / 差距动作”收进一份总账,后续只维护一处新研究一进来就会继续复制旧误差news / channels / scenes / news_scenes 当前模型已经能给出真实边界后续所有结构升级先回写本文件
yomiya-canonical-naming.md降级为名词冻结命名文档里写了很多“目标承载”,容易被误读成当前已经存在命名继续保留,但不再承担“当前现实证明”职责团队会把“应该叫什么”误读成“现在已经怎么建模”服务端当前没有 collections / series / topic 正式表名词继续保留,现实统一引用本文件
yomiya-implementation-spec-core.md聚焦执行目标实施规格里既写目标页面与目标容器,又容易被当成当前后端真相让它只回答“当前阶段按什么目标落地”,不再自证现实研发会把目标表结构当成现网事实,研究会把现网事实当成目标已完成当前 news 现实与 collections 目标并不在同一层以后任何目标模型先在本文件登记 Gap + Actions
03 / 04固定为研究映射层研究文档为了方便,经常把平台字段、研究字段和系统正式字段混写让研究层只负责样本、判断、映射建议,不再自创系统字段真相后续 YouTube / 播客研究越多,误差越会扩散sourcetypescene 的现实含义已经和研究层旧写法不一致研究稳定后,先回写本文件再改研究文档

对象当前现实关键字段 / 关系当前约束状态
News当前正式内容主对象idnews_idlevelchannel_idsourcetypevisibility主键在 idnews_id 当前未见数据库唯一键已完成
Channel当前正式长期归属层idnamedisplay_namedescriptionis_visiblechannels.name 唯一已完成
Scene当前正式场景标签主表idcategoryscenesub_sceneavailable只有索引,没有 (category, scene, sub_scene) 唯一键已完成
NewsScene当前 newsscene 关系表news_idscene_idscene_primary(news_id, scene_id) 唯一;scene_primary 当前只区分 primary / secondary已完成
Tag DTO当前对外公开标签机制TagTypeLevelTagTypeSceneTagTypePremium公开层只暴露这 3 类 TagType已完成
RawNews当前统一原始内容暂存对象unique_idstatusdatarisk_check_statuschannelstatus 当前可到 REJECTEDrisk_check_status 当前可到 BLOCKED已完成
UserContentImport当前正式用户导入记录对象pluto_user_idunique_idchannel_idcontent_typeurlnews_id只承接用户导入,不承接系统抓取已完成
TranscriptionTask当前统一转写 / 重处理任务对象unique_idstatuscontent_typenews_iderror_codeunique_id 唯一已完成
YouTubeChannel当前唯一正式外部品牌映射表youtube_channel_idnamechannel_idyoutube_channel_id 唯一,映射到内部 channels已完成

明确不应误读为“当前正式对象”的概念:

  • Collection
  • Series
  • Topic
  • 跨媒介统一的 Source Brand
  • 跨媒介统一的 Series Unit

这些概念现在仍然属于目标理想 / 研究映射 / 后续建模动作,不是当前服务端现实。

flowchart LR
  A[News] -->|channel_id| B[Channel]
  A -->|news_id / source / type / visibility| A1[正式内容核心字段]
  A --> C[NewsScene]
  C --> D[Scene]
  A --> E[公开 DTO]
  E --> F[level Tag]
  E --> G[scene Tag]
  E --> H[premium Tag]
  I[YouTubeChannel] -->|映射到内部 channel| B
  J[UserContentImport] -->|导入后回填 news_id| A
  K[TranscriptionTask] -->|作用于 news| A

这张图的重点是:news 现在仍是正式主内容对象;scene 通过关系表挂接;YouTubeChannel 只是外部品牌映射,不是新的内容主表。


这一节只写“当前已经存在什么”,不写“理论上应该有什么”。

字段 / 能力当前现实目标理想差距与动作状态
news.id当前正式主键继续保持主键无需改动已完成
news.news_id当前有字段,用于上游内容 ID,但未见数据库唯一键明确它到底是“外部来源唯一 ID”还是“可重复抓取源 ID”需要补一条唯一性策略:要么加唯一键,要么文档明确允许重复并给出去重规则待定义
news.channel_id当前正式长期归属字段,指向 channels.id,可为空继续作为唯一长期归属层需要补“空值何时允许、何时必须补齐”的执行规则已完成
news.source当前现实只表示内容来源类型:news / imports如果未来要表达平台来源,不能复用这个字段不允许把 source 直接拿来表示 podcast / youtube / bilibili;平台信息应留在研究层或后续独立品牌层已完成
news.type当前现实值域来自服务端 migration:webpage / video / audio后续若要支持更复杂媒介语义,应先评估是否真要扩字段03 / 04 不能把 text / mixed 写成当前系统已存在值;若研究发现需要,先回写 Gap 表已完成
news.level当前正式难度字段是数值型;公开层已稳定映射 N5 / N4 / N3 / N2 / N1 / N1+继续保持单一难度字段,不额外并行造第二套等级体系研究层可暂时写 待定,但 待定 不等于正式系统值已完成
news.visibility当前正式可见性字段,公开枚举已存在继续保留内容可见性能力不能把 visibility 直接等同于“能否被分发”已完成
scene当前不是 news 主表字段,而是 scenes + news_scenes 关系层能力继续沿用关系层表达场景标签所有文档都不能把 scene 写成当前正式的 news.scene已完成
primary_scenes / secondary_scenes当前已在 Admin DTO 与更新逻辑中暴露,但它们是 API 表达,不是 news 表字段继续作为后台编辑接口表达文档必须明确这是“关系层编辑接口”,不是“主表新增两列”已完成

处理能力当前现实目标理想差距与动作状态
内容进入路径当前持久化边界仍使用 news.source = news / imports;应用层内部已映射为 collected / user_imported继续保持“进入路径”和“平台来源”分离不能把 source 重写成平台名;平台来源仍应由 channel / source_brand 一侧解决已完成
官方供给处理当前 collected 内容会跑 risk_review -> difficulty -> add_scene,并走通知型发布继续作为官方内容的默认处理链路文档应明确这是“我们提供的内容”的现实,不要再把它遗漏成只有字段扩充已完成
用户导入处理当前 user_imported 内容会走统一处理流水线,但 NeedRiskReview=falseNeedDifficultyLevel=falsePublishModeSilent继续和官方供给分开文档不能把用户导入链路误写成官方内容扩充链路已完成
风控落库当前风控结果会写回 raw_news.status / risk_check_status;被拦截内容会进入 REJECTED / BLOCKED继续作为官方供给的前置准入信息后续若要讨论“分发资格”,不能直接拿 risk_check_status 代替全部分发规则已完成
前台公开读取当前公开内容列表默认只查询 source = news继续把 imports 排除在官方内容池之外这说明“用户导入内容已落到 news”不等于“自动进入官方分发层”已完成
flowchart LR
  A[官方供给 / 系统抓取] --> B[RawNews]
  Y[YouTube channel crawler] --> B
  B --> C[risk_review]
  C --> D[difficulty]
  D --> E[add_scene]
  E --> F[写入 news<br/>source = news]

  G[用户导入] --> H[UserContentImport]
  H --> I[统一处理流水线]
  I --> J[写入 news<br/>source = imports<br/>跳过 risk_review / difficulty]

  F --> K[前台公开查询]
  J --> K
  K -->|默认只取| L[source = news]

这张图专门解释 3 个最容易混掉的事实:

  • 官方供给和用户导入最终都会落到 news
  • 但两条处理策略并不相同
  • 前台默认只取 source = news,所以 imports 不会自动变成官方分发内容

标签能力当前现实目标理想差距与动作状态
level Tag来自 news.level,公开 TagType 是 level保持当前统一难度描述能力无需新造并行 difficulty_tag 体系已完成
scene Tag来自 scenes + news_scenes;公开 Tag 名当前取 sub_scene继续作为主内容方向标签能力,但要补稳定治理规则后续如果研究要扩 scene 体系,应优先补 scenes 治理与唯一性,而不是新建第二套主标签已完成
premium Tag不是独立表,而是由 visibility == MEMBERSHIP_VISIBLE 衍生如后续需要更多会员态,仍应先看 visibility 体系不要在研究层自造“高级会员标签主模型”已完成
operator_tag当前只是文档概念,不是正式后端 TagType后续若真要长期运营标签,需要明确是否独立建模目前不能把它写成当前服务端已支持能力待定义

这一节专门回答你提出的“冻结表还没有形成完全唯一性约束,导致很乱”的问题。

对象 / 约束当前现实风险为什么重要建议动作状态
channels.name已有唯一键 UK_channels_name长期归属层已经有稳定唯一性保持现状已完成
scenes(category, scene, sub_scene)当前只有索引,没有唯一键同义或重复场景可能进入系统,研究与后台会越用越乱scene 是当前主标签体系,缺唯一约束会直接污染样本映射与标签编辑如果确认这三列就是当前最小唯一单位,应补唯一键;若不够,再先补场景治理规则待迁移
news_scenes(news_id, scene_id)已有唯一键同一条内容不能重复挂同一个 scene,基础关系去重已存在这是当前最可靠的一条标签关系约束保持现状已完成
news_scenes(news_id, scene_primary)当前只有索引,不是唯一约束一条内容当前可以拥有多个 primary scene如果团队希望“一个 Item 只有一个主 scene”,数据库现在并没有强制保证先在文档规则里写清;若要硬约束,需要补更细约束或改表结构待定义
news.news_id当前未见唯一键同一上游内容是否可能重复入库,没有数据库层强保证这会影响“唯一内容条目”的边界、去重和运营判断明确 news_id 语义,再决定是否补唯一键或保留软去重待定义
youtube_channels.youtube_channel_id已有唯一键YouTube 品牌层至少已经有正式唯一入口可作为未来统一外部品牌治理的参考样板已完成

这一节不是在说“现在已经有”,而是在说“接下来要补什么”。
后续播客 / YouTube / B 站研究的新结论,应主要回写这一节。

概念当前现实目标理想差距为什么要补建议动作状态
Channel已正式存在,且是当前唯一长期归属层继续保持一级长期归属层目前缺的是治理规则,不是主模型缺失这是当前最稳的正式层,后续扩容应尽量沿用它继续以 channel_id 为长期归属,不并行发明第二套一级归属已完成
Collection当前服务端未正式建模成为长期发现容器,承接首页、列表页、详情页的核心发现层文档目标很多,但后端真实模型还没落地不补这层,首页和持续发现只能停在“单条内容分发”新增 collections + collection_items 主表、Admin CRUD、读接口、排序与可见性规则待建模
Series当前未正式独立建模成为连续更新容器,服务追更预期现在只有概念,没有现实模型,也没有正式唯一边界播客 / YouTube 研究越深入,这层越重要先让 04-内容样本池.md 稳定 Series Unit 判断,再决定是独立表还是 Collection 特化待定义
Topic当前未正式独立建模成为时效性运营容器现在只停留在概念层不补清楚,会持续和 Collection 混用先在文档里保持为目标概念;若要落地,优先评估是否复用 Collection + 时效字段待定义
Source Brand当前只有 YouTube 有正式映射表,播客 / B 站没有统一品牌层建立跨媒介统一的外部来源品牌治理当前研究可以识别品牌,但系统无法统一承接后续多平台内容进入后,没有品牌层会很难维护来源、风格和抓取策略短期继续在 04-内容样本池.md 使用 source_brand;中期评估统一品牌主表或扩展现有 channel 体系待迁移
Series Unit当前完全是研究层概念成为 Series 候选或 Collection 组织判断依据没有正式承接位置YouTube 播放列表、播客栏目、B 站合集很容易继续被混成一层先在 04-内容样本池.md 中稳定判断标准,再回写本表决定正式承载方式待定义
Distribution Eligibility当前只是文档规则,没有正式独立字段visibility 分离,成为“能否进入分发层”的正式能力现在最容易和 visibility 混掉不拆开的话,“看得见”和“值得分发”会长期混用先把规则写清;后续再决定是独立字段、状态表还是规则层待定义
Scene 治理当前已有正式标签表,但治理和唯一性不够硬scene 成为稳定、可扩容的主方向标签体系研究会不断带来新方向,但底层唯一性与治理规则不足不补治理,研究输入越多,主标签越容易失控优先补 scenes 唯一性策略、命名规则、废弃规则,再谈扩字段待迁移

研究里新出现的信号先更新哪里不应该怎么做
某个平台样本让 Collection / Series / Topic 边界更清楚了回写本文件第 9 节的 目标理想 / 差距 / 动作不要直接在样本文档里把它写成“系统已支持”
某个新方向证明 scene 体系需要扩容或重命名回写本文件第 7 节和第 8 节不要直接在研究表里新增一套并行主标签体系
某类平台来源需要正式品牌层回写本文件第 9 节的 Source Brand不要把 news.source 改写成平台字段
研究发现当前字段不够表达先回写本文件第 5 节、第 6 节或第 9 节不要先在样本表里把临时列写成“系统已有字段”

更新顺序固定为:

  1. 先在 03 / 04 里形成证据、样本和判断
  2. 再回写本文件的 目标理想 / 差距 / 动作
  3. 最后根据本文件的最新口径,调整入库流程文档与样本池

Yomiya 当前正式内容系统的现实仍然是 news + channels + scenes + news_scenes + Tag(level/scene/premium) + source(news/imports);官方 collected 内容已有风控 / 难度 / scene 处理链路,前台默认只分发 source = newsCollection / Series / Topic / Source Brand / Series Unit 现在都还属于目标理想与后续动作。