Files
gyxx-flow/docs/note-inventory.md
T

90 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 笔记主表(cmt_notes_master)设计文档
> 原 `cmt_notes` / `cmt_note_inventory` / `cmt_cooperations` 三张表已合并为
> `cmt_notes_master`migration 007)。本文替代原“完整笔记清单同步”文档。
## 口径
`cmt_notes_master` 是合作达人和自营笔记的唯一主表,一行 = 一条飞书来源记录
(合作达人表 / 自营笔记表),或一条采集补建笔记(`source_*` 列为 NULL)。
飞书来源行同时具备“发布笔记标题”“发布时间”“发布链接”时,
`is_countable = TRUE`,才计入笔记数。
三张表合一后:
- 笔记数:统计 `cmt_notes_master``source_active AND is_countable` 的去重链接;
- 曝光/互动指标:同一行的 `view_count` / `like_count` 等列,由
`sync_metrics_to_cmt_notes.py`(曝光)与评论采集链路(互动、评论)按
URL / 记录写回;
- 合作财务:同一行的 `cooperation_cost` / `ad_spend` / `cpm` 等列,由
飞书同步与合作字段一并写入(仅合作表记录有值,自营为 NULL);
- 没采到曝光的笔记仍计入笔记数,曝光为空;
- 覆盖率:有 `view_count` 的有效笔记数 / 完整笔记数。
同一 URL 在飞书可能被多条记录重复登记,主表按记录粒度保留全部行,
`url` 不再唯一;按 URL 读取时以最早 `id` 为规范行。
来源记录被删除时只将 `source_active` 置为 `FALSE`,保留审计历史,不物理删除。
## 调度
项目常驻 Python 调度器每天执行:
- `09:00``content.notes_master.daily`(合并原 `content.cooperations.daily`
`content.note_inventory.daily`,一次飞书拉取落全量字段)
- `10:00``content.marketing_report.daily`
时间表位于 `config/schedules.json`,不创建 Windows Task Scheduler 任务。
也可以在工作流控制台搜索“笔记清单与合作同步”,点击“手动同步”。弹窗支持
“同步预演”和“正式同步”;正式同步会先检查云端 PostgreSQL 运行时凭据,
再异步扫描全部来源表,进度、错误和运行历史均在控制台展示。
手动预演(只读飞书,不写数据库):
```powershell
uv run gyxx scripts run content.notes_master.sync
```
正式执行:
```powershell
uv run gyxx scripts run content.notes_master.sync --execute --arg=--execute
```
正式执行前,服务器运行环境必须提供 `PG_HOST``PG_PORT``PG_DB``PG_USER`
`PG_PASSWORD`。凭据只放在服务运行环境或外部 `GYXX_DATA_ROOT` 状态配置中,不写入源码。
## 覆盖率查询
```sql
SELECT
s.name AS style_name,
COUNT(DISTINCT n.url) AS note_count,
COUNT(DISTINCT n.url) FILTER (WHERE n.view_count IS NOT NULL) AS metric_note_count,
ROUND(
COUNT(DISTINCT n.url) FILTER (WHERE n.view_count IS NOT NULL)::numeric
/ NULLIF(COUNT(DISTINCT n.url), 0),
4
) AS metric_coverage_rate,
SUM(n.view_count) AS collected_exposure
FROM cmt_notes_master n
JOIN cmt_styles s ON s.id = n.style_id
WHERE n.source_active = TRUE
AND n.is_countable = TRUE
GROUP BY s.name
ORDER BY s.name;
```
## 数据迁移(007
`migrations/007_notes_master.sql` 执行内容:
1. 创建 `cmt_notes_master`(笔记身份 + 合作字段 + 采集指标 + 审计列);
2. `cmt_notes` 行保留原 `id` 迁入(`cmt_comments.note_id` 零改值);
3. `cmt_note_inventory``(style_id, feishu_record_id)` 归并来源身份,
未匹配行直接成为新行;
4. `cmt_cooperations``(style_id, feishu_record_id)` 回填合作字段,
未匹配记录保留为 `source_active=FALSE` 的历史行;
5. `cmt_comments.note_id` 外键重指向主表,删除三张旧表。