feat: expand module workflows, dynamic config, notifications and console API
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# 笔记主表(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` 外键重指向主表,删除三张旧表。
|
||||
Reference in New Issue
Block a user