feat: expand module workflows, dynamic config, notifications and console API
This commit is contained in:
@@ -46,15 +46,14 @@
|
||||
| `shop.douyin_price_appeal` | 每日 08:00、16:00、22:00 | 复用店铺周采集登录态,扫描全部待改价列表并对可申诉商品提交固定原因申诉。 |
|
||||
| `shop.jd_self_operated.daily` | 每日 16:00,业务日 -1 | 京东自营数据从下午开始推送;预留刷新窗口后先采集品牌,再采集商品,品牌失败后商品仍继续。 |
|
||||
|
||||
### 商品经营(7)
|
||||
### 商品经营(6)
|
||||
|
||||
| 工作流 | 时间 | 用途 |
|
||||
|---|---|---|
|
||||
| `product.daily` | 每日 08:40,业务日 -1 | 编排 ERP 与三平台采集、分析、导出和入库。 |
|
||||
| `product.daily` | 每日 08:40,业务日 -1 | 编排 ERP 与三平台采集、原始商品日报幂等入 PostgreSQL、分析、导出和飞书写入。 |
|
||||
| `product.persona.daily` | 每日 10:00 | 并行采集天猫、抖音和京东商品画像。 |
|
||||
| `product.import.daily` | 每日 19:00 | 幂等导入三平台商品日报。 |
|
||||
| `product.alert.daily` | 每日 23:00 | 独立检测商品异常并按条件通知。 |
|
||||
| `product.style_analysis.interval` | 每 3 天 11:00 | 使用本地 Hermes 分析到期款式。 |
|
||||
| `product.style_analysis.interval` | 每 3 天 11:00 | 直连 MiniMax 分析到期款式;不依赖本地 Hermes 分析端。 |
|
||||
| `product.main_image.weekly` | 周日 08:30 | 并行启动 JD、TM 两个独立主图分支,各自写入本地 PG 和飞书;一个平台失败不阻断另一平台,全部结束后汇总整体状态和平台级具体错误。 |
|
||||
| `product.market_rank` | 周一 10:00 | 并行采集天猫、京东、抖音市场排行并汇总归档。 |
|
||||
|
||||
@@ -136,4 +135,4 @@ flowchart TD
|
||||
- [x] 不可执行历史项不再参与目录、注册和数量统计。
|
||||
- [x] 最终全量测试、Ruff、构建、doctor、调度 dry-run 与敏感信息扫描通过。
|
||||
|
||||
真实浏览器登录、飞书写入、Hermes 分析和 ERP 修改不由本次结构合并自动触发。各业务链路最近一次实跑结果与未通过原因见 [工作流验收测试报告](workflow-acceptance-test-report.md)。
|
||||
真实浏览器登录、仍依赖 Hermes 的分析和 ERP 修改不由本次结构合并自动触发;款式周期分析的 MiniMax 直连及其飞书/Base/PostgreSQL 写入已单独完成实跑验证。各业务链路最近一次实跑结果与未通过原因见 [工作流验收测试报告](workflow-acceptance-test-report.md)。
|
||||
|
||||
+28
-3
@@ -67,9 +67,34 @@ flowchart TD
|
||||
## 外部系统
|
||||
|
||||
- PostgreSQL:云端模式不提供地址、数据库、用户或密码的源码默认值;由 `GYXX_POSTGRES_DSN` 在运行时注入,并拒绝回环数据库地址。
|
||||
- Hermes:保留本机 `data-analyzer` 和 `data-collector` 两个角色,以及各自 API 和 gateway。
|
||||
- 飞书:复用现有 lark-cli profile、应用身份、表格和消息调用方式。
|
||||
- 浏览器:每个脚本从 `config/runtime-bindings.json` 获得唯一 CDP 端口及独立 Profile、Cookie、storage state 路径,不共享可写 Profile。
|
||||
- Hermes:保留本机 `data-analyzer` 和 `data-collector` 两个角色,以及各自 API 和 gateway;Hermes 只承担需要大模型的分析,不作为飞书消息投递身份。
|
||||
- 飞书:表格写入和业务消息统一使用 `lark-cli --profile hermes-analyzer --as user`。消息发送必须校验真实 `message_id` 回执;卡片图片预上传因上游接口仅支持 tenant token,保留同一 profile 的 bot 媒体上传例外,但最终卡片仍由 user 身份投递。
|
||||
- 浏览器:每个脚本从 `config/runtime-bindings.json` 获得唯一 CDP 端口及独立 Profile、Cookie、storage state 路径,不共享可写 Profile;多个脚本若属于同一登录身份,则通过 `state/accounts/<account_id>/` 的账号 vault 合并 Cookie,仍保持 Profile 隔离。像商品经营日报这类按品牌动态路由的包装脚本,会在运行时选择对应账号 vault,但仍为每个品牌保留独立 Profile。
|
||||
- 账号保活:`accounts.<account_id>.keepalive` 由唯一的 `gyxx schedule run` 常驻进程错峰执行;只有安全页面确认未跳转登录页且必需 Cookie 仍有效时,才原子发布新 vault 并同步成员脚本。京东 `jd-shop`、`jd-self-operated`、`jd-market-rank` 以及天猫 `tmall-shop`、`tmall-ozko` 都使用独立 vault,避免同域不同店铺相互覆盖。
|
||||
|
||||
### Scrapling 采集边界
|
||||
|
||||
浏览器和公开 HTTP 采集统一使用 `scrapling[fetchers]==0.4.13`。生产代码不得直接
|
||||
导入或启动 Playwright、Patchright、Selenium;静态接口使用 `Fetcher`,普通动态
|
||||
页面使用 `DynamicSession`,需要隐身能力的页面使用 `StealthySession`。Scrapling 的
|
||||
动态抓取器内部仍分别使用 Playwright/Patchright,因此它们会作为传递依赖出现,但
|
||||
不是项目业务 API。官方选型说明见
|
||||
<https://scrapling.readthedocs.io/en/latest/fetching/choosing.html>。
|
||||
|
||||
`gyxx_flow.adapters.scrapling.ScraplingBrowser` 是统一浏览器边界,负责:
|
||||
|
||||
- 默认只执行一次,避免上传、申诉等有副作用动作被框架静默重放;
|
||||
- 从绑定专属 Cookie/storage-state 文件恢复状态,并在关闭前原子保存;
|
||||
- 用持久 Profile 启动自有浏览器,或借用外部 CDP 中唯一已有 context;
|
||||
- 借用 CDP 时只关闭本次页面和连接,不关闭远端 browser/context;
|
||||
- 将 Scrapling 回调中被记录后吞掉的异常重新抛给工作流;
|
||||
- 在业务代码不导入底层引擎的前提下统一识别浏览器超时。
|
||||
|
||||
Scrapling 0.4.13 当前要求 `curl-cffi==0.16.1b1`,项目显式锁定该版本。部署安装锁定
|
||||
依赖后运行 `uv run scrapling install` 准备浏览器运行时;定时采集任务本身不得执行
|
||||
安装。`tests/test_no_native_browser_automation.py` 负责阻止原生浏览器调用回流,唯一
|
||||
排除项是不可执行的上游 Scrapling 源码快照
|
||||
`vendors/dy-data-flow/dynamic_session_src.py`。
|
||||
|
||||
## 数据布局
|
||||
|
||||
|
||||
+57
-2
@@ -16,7 +16,7 @@
|
||||
- Python 3.12 和 `uv`
|
||||
- 可访问的 PostgreSQL 13+ 云端实例及运行时注入的 `GYXX_POSTGRES_DSN`
|
||||
- 本机 Hermes `data-analyzer` 与 `data-collector`
|
||||
- Chrome/Playwright,以及个别业务入口仍需要的 PowerShell 运行条件
|
||||
- Chrome 与 Scrapling 浏览器运行时,以及个别业务入口仍需要的 PowerShell 运行条件
|
||||
- 可访问现有飞书身份的专用系统用户
|
||||
|
||||
创建生产目录和服务账户:
|
||||
@@ -33,14 +33,67 @@ sudo install -d -o root -g gyxx-flow -m 0750 /etc/gyxx-flow
|
||||
```bash
|
||||
cd /opt/gyxx-flow
|
||||
sudo -u gyxx-flow uv sync --python 3.12 --no-group dev --frozen
|
||||
sudo -u gyxx-flow uv run scrapling install
|
||||
```
|
||||
|
||||
业务采集代码只使用 Scrapling;其动态与隐身抓取器所需的底层浏览器由
|
||||
Scrapling 安装和管理。具体边界与验证命令见
|
||||
[`architecture.md`](architecture.md#scrapling-采集边界)。
|
||||
|
||||
凭据放入 `/etc/gyxx-flow/gyxx-flow.env`,权限设为 `0640`。该文件不提交到 Git,至少按实际环境注入数据库密码、飞书身份和可选 Hermes 密钥。
|
||||
|
||||
控制台和调度器都支持可重复的 `--env-file`,只加载显式列出的文件。systemd 的
|
||||
`EnvironmentFile=` 或当前进程环境优先于文件中的同名值,避免本地文件意外覆盖密钥系统
|
||||
注入值。
|
||||
|
||||
## 三平台电商费用日报部署边界
|
||||
|
||||
`product.ecommerce_costs.daily` 是包含天猫万相台、京东京准通和抖音千川分支的电商费用工作流;三个
|
||||
平台下载节点并行,导入节点分别等待本平台下载完成。当前项目对其中天猫万相台这条
|
||||
浏览器链路按 Windows Server + NSSM 验收;Linux 上的通用调度器说明不等于万相台浏览器流程
|
||||
已经完成 Linux/无头浏览器验收。部署到 Windows Server 时使用项目内的 NSSM 服务包装器,业务
|
||||
时间仍只由 `config/schedules.json` 管理,不创建 Windows Task Scheduler 条目。
|
||||
|
||||
该工作流需要由服务账户注入以下环境变量,真实值不要写入 Git、命令参数或文档:
|
||||
|
||||
```text
|
||||
GYXX_DATA_ROOT=D:\gyxx-flow-data
|
||||
GYXX_POSTGRES_DSN=<云端 PostgreSQL DSN>
|
||||
WANXIANG_ACCOUNT=<万相台账号>
|
||||
WANXIANG_PASSWORD=<万相台密码>
|
||||
```
|
||||
|
||||
未显式设置 `WANXIANG_USER_DATA_DIR` 时,登录态保存在
|
||||
`<GYXX_DATA_ROOT>\state\browser-profiles\wanxiang-ads`。这个 Profile 是该脚本的独立登录态,
|
||||
不要与其他淘宝/万相台脚本共用。使用 NSSM 的 `AppEnvironmentExtra` 或服务器密码管理器注入
|
||||
凭据;不要把真实密码写进 PowerShell 脚本或 `nssm` 命令历史。
|
||||
|
||||
安装 Windows 常驻服务:
|
||||
|
||||
```powershell
|
||||
cd D:\gyxx-flow
|
||||
uv sync --python 3.12 --group dev
|
||||
.\deploy\windows-service\install.ps1 -ProjectRoot D:\gyxx-flow -DataRoot D:\gyxx-flow-data
|
||||
# 按服务器密码管理器的方式为 gyxx-flow-scheduler 注入上述环境变量
|
||||
nssm start gyxx-flow-scheduler
|
||||
```
|
||||
|
||||
首次上线先在有头浏览器中建立登录态并导入一日数据;验证码或滑块必须在同一 Profile 中人工
|
||||
完成:
|
||||
|
||||
```powershell
|
||||
$env:GYXX_DATA_ROOT = 'D:\gyxx-flow-data'
|
||||
$env:WANXIANG_ACCOUNT = '<从密码管理器读取>'
|
||||
$env:WANXIANG_PASSWORD = '<从密码管理器读取>'
|
||||
uv run gyxx doctor --json
|
||||
uv run gyxx scripts run product.tmall_wanxiang_ads.collect --date 2026-08-17 --execute
|
||||
uv run gyxx scripts run product.import.tmall_ads --date 2026-08-17 --execute
|
||||
```
|
||||
|
||||
确认手工链路成功后,再让唯一的 `gyxx schedule run` 常驻服务接管;不要为 19:30 另建系统定时
|
||||
任务。完整的服务重启和 dry-run 流程见本文件的“systemd 调度服务”章节以及
|
||||
[`runbook.md`](runbook.md) 的万相台小节。
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
从受限环境文件加载云端数据库连接:
|
||||
@@ -66,7 +119,9 @@ data-collector: API base http://127.0.0.1:8643/v1
|
||||
|
||||
`28790/28791` 不作为工作流业务端点。
|
||||
|
||||
运行时配置必须保持回环地址。Hermes 不可用时,纯采集、文件处理和数据库同步仍可运行;依赖 Hermes 分析或通知的工作流应保持停用或手工执行,不得静默改用远程 AI。
|
||||
运行时配置必须保持回环地址。Hermes 不可用时,纯采集、文件处理、数据库同步和不依赖大模型的确定性通知仍可运行;仍依赖 Hermes 的工作流应保持停用或手工执行,不得静默改用远程 AI。飞书消息投递本身统一依赖运行服务账户的 `hermes-analyzer` lark-cli user 授权。
|
||||
|
||||
例外:`content.summary.weekly` / `content.summary.monthly` 的内容报告、`product.style_analysis.interval` 的款式周期分析,以及 `product.video_upload` / `product.jd_video_upload` 的视频标题与视觉颜色识别,均配置为显式直连 MiniMax。内容报告使用 `CONTENT_ANALYSIS_LLM_BASE_URL`、`CONTENT_ANALYSIS_LLM_MODEL` 和 `CONTENT_ANALYSIS_LLM_API_KEY`;商品/视频链路使用 `STYLE_ANALYSIS_LLM_*`(视频链路也支持 `GYXX_DIRECT_LLM_*` 覆盖)。这些链路不读取 Hermes 分析端口,但仍保留本地结果校验、断点、EffectLedger、飞书和 PostgreSQL 写入链路。
|
||||
|
||||
## 上线前验证
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# 工作流动态配置
|
||||
|
||||
## 配置源
|
||||
|
||||
商品 ID、ERP 款式编码和各业务飞书目标表现在统一保存在云端 PostgreSQL。
|
||||
控制台“配置中心 → 款式平台配置”提供查询、新增、编辑、
|
||||
停用和删除。工作流运行时只读取这些项目表,不再读取旧配置主表
|
||||
`TtoCb1NuQaDy3NsZWTpc0GIvnph/tblKCjplVAFrRwMC`。
|
||||
|
||||
目标飞书表仍是工作流的业务输入或输出,例如销量表、主图表、人群画像表和合作达人表;
|
||||
本次下线的是集中维护这些地址和商品 ID 的旧飞书索引表,不是业务目标表本身。
|
||||
|
||||
## 受影响工作流
|
||||
|
||||
| 工作流 | 动态读取内容 | 生效入口 |
|
||||
| --- | --- | --- |
|
||||
| `content.summary.monthly` | 款式与每周笔记分析/生命进程目标表 | `monthly_summary_all.py`(复用周汇总配置加载器) |
|
||||
| `content.summary.weekly` | 款式与每周笔记分析/生命进程目标表 | `weekly_summary_all.py` |
|
||||
| `content.metrics.daily` | 合作达人目标表(自营采集暂缓) | `run_all.py`、`sync_metrics_to_cmt_notes.py` |
|
||||
| `content.metrics.backfill` | 合作达人目标表 | `run_all.py` |
|
||||
| `content.notes_master.daily` | 各款式合作达人及自营笔记表 | `sync_notes_master.py` |
|
||||
| `product.persona.daily` | 三平台商品 ID 与人群画像目标表 | 三个平台画像采集脚本 |
|
||||
| `product.daily` | 天猫/京东/抖音商品 ID、ERP 编码、销量目标表 | `orchestrate_daily_collection.py` 及平台采集脚本 |
|
||||
| `product.style_analysis.interval` | 款式与平台单品分析目标表 | `analyze_style.py` |
|
||||
| `product.main_image.weekly` | 京东 SPU、天猫款式和主图目标表 | 两个平台主图采集入口 |
|
||||
| `product.sales_sheet.daily` | 款式与 ERP 编码 | `sync_monthly_sales_sheet.py` |
|
||||
| `product.erp_all_shop_daily` | 全部款式与 ERP 编码 | `backfill_erp_all_shop_daily.py` |
|
||||
|
||||
共 11 个定时工作流依赖这套动态配置。维护脚本 `feishu_comment_batch.py` 和
|
||||
`db/sync_sku_master.py` 也已改为读取同一项目数据库,避免从非定时入口绕回旧主表。
|
||||
|
||||
`product.alert.daily`、商品导入、万相台广告、视频发布和市场排行使用各自数据库或专用配置,
|
||||
不依赖旧配置主表,因此不在本次切换范围内。
|
||||
|
||||
## 字段归属与数据模型
|
||||
|
||||
新模型不再把共享字段重复放在每个平台行:
|
||||
|
||||
| 层级 | 字段 | 使用目的 |
|
||||
| --- | --- | --- |
|
||||
| 款式 | 款式名、品牌、ERP 款式编码 | 统一业务身份;ERP 日采、月度销量表和款式主数据使用 |
|
||||
| 款式 | 销量表、主图表 | 商品日报和天猫/京东主图工作流的款式目标表 |
|
||||
| 款式 | 合作达人表、自营合作达人表 | 内容采集、合作同步和笔记清单使用 |
|
||||
| 款式 | 每周/每月笔记分析、平台单品分析 | 内容周月报和款式周期分析使用 |
|
||||
| 平台 | 平台名、商品 ID、启用状态 | 天猫商品 ID、京东 SPU、京东自营 SKU、抖音/PDD 商品 ID |
|
||||
| 平台 | 本平台人群画像表 | 天猫、京东、抖音画像采集分别写入自己的目标表 |
|
||||
|
||||
数据库使用父子表:
|
||||
|
||||
- `workflow_dynamic_styles`:一个款式一行,保存 ERP 和共享飞书目标。
|
||||
- `workflow_dynamic_style_platforms`:一个款式可有多个平台子行,只保存平台商品 ID、平台画像表和启停状态。
|
||||
- 旧 `workflow_dynamic_configs` 保留为原始迁移审计,不再参与运行时读取。
|
||||
- `erp_codes`、`item_ids` 使用 PostgreSQL 数组,页面接受中英文逗号或换行并自动去重。
|
||||
- `destinations` 使用通用 JSONB 目标列表,每项包含 `key`、`label`、`url`、`description`、`enabled`;六个旧目标字段仍同步保留,保证已有工作流兼容。后续新增分析逻辑只需增加一个稳定的 `key` 和对应飞书表地址。
|
||||
- 款式带递增 `revision`;整页保存和删除必须提交 `If-Match`,避免并发覆盖。
|
||||
|
||||
## 首次迁移
|
||||
|
||||
`config/workflow-dynamic-config-seed.json` 是 2026-08-19 从旧 Base 分页导出的只读迁移快照,
|
||||
共 215 条源记录。项目第一次连接一个空数据库时会:
|
||||
|
||||
1. 幂等创建旧迁移审计表、款式父表和平台子表;
|
||||
2. 在事务和 PostgreSQL advisory lock 内导入 215 条记录;
|
||||
3. 写入迁移标记 `feishu-style-config-20260819-v1`;
|
||||
4. 运行 v2 归一化迁移:按款式合并共享字段,按平台合并商品 ID;旧表中集中在天猫行的三平台画像地址分别迁入对应平台子行;
|
||||
5. 写入迁移标记 `workflow-style-platform-config-20260819-v2`,此后不会重复迁移。
|
||||
|
||||
服务器必须注入 `GYXX_POSTGRES_DSN`,或完整的 `PG_HOST/PG_PORT/PG_DB/PG_USER/PG_PASSWORD`。
|
||||
没有数据库且没有数据库生成的运行缓存时,相关工作流会明确失败,不会静默回读旧飞书主表。
|
||||
|
||||
## 运行时路径
|
||||
|
||||
```text
|
||||
控制台分组 CRUD
|
||||
↓
|
||||
workflow_dynamic_styles + workflow_dynamic_style_platforms (PostgreSQL)
|
||||
├─ 兼容聚合输出 → StyleConfigLoader → 商品经营工作流
|
||||
└─ 兼容聚合输出 → feishu_mapping → 内容营销工作流 → 各业务飞书目标表
|
||||
```
|
||||
|
||||
`StyleConfigLoader` 只在数据库短暂不可用时使用最近一次数据库成功读取后生成的本地缓存;
|
||||
`feishu_mapping` 的目标表字段缓存仍保留,用来减少对各业务飞书表的字段查询。
|
||||
@@ -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` 外键重指向主表,删除三张旧表。
|
||||
+125
-1
@@ -6,8 +6,14 @@
|
||||
uv run gyxx doctor --json
|
||||
uv run gyxx schedule status
|
||||
uv run gyxx list
|
||||
lark-cli --profile hermes-analyzer auth status --json --verify
|
||||
lark-cli --profile hermes-analyzer auth check --scope "im:message.send_as_user im:message" --json
|
||||
```
|
||||
|
||||
两条 lark-cli 检查必须在实际运行调度服务的系统账户下执行。业务消息统一由该 profile 的
|
||||
user 身份投递;只有日报卡片的图片预上传因接口限制使用同 profile 的 bot 身份。不要用
|
||||
交互登录账户的授权结果代替 NSSM/systemd 服务账户验证。
|
||||
|
||||
Linux 服务同时检查:
|
||||
|
||||
```bash
|
||||
@@ -27,7 +33,7 @@ uv run gyxx scripts run <command_id> --date 2026-08-01
|
||||
uv run gyxx scripts run <command_id> --date 2026-08-01 --execute
|
||||
```
|
||||
|
||||
`gyxx run` 只接受 22 个调度工作流;补采和维护操作使用 `gyxx scripts run`。两类入口都默认 dry-run,只有业务日期、凭据、浏览器登录态、PostgreSQL 和对应 Hermes 角色全部确认后才使用 `--execute`。
|
||||
`gyxx run` 接受 23 个调度工作流和已注册的手动工作流;补采和维护操作使用 `gyxx scripts run`。两类入口都默认 dry-run,只有业务日期、凭据、浏览器登录态、PostgreSQL、lark-cli user 身份,以及工作流确实需要大模型时对应的 Hermes 角色全部确认后才使用 `--execute`。
|
||||
|
||||
| 手动场景 | 命令 ID | 日期行为 |
|
||||
|---|---|---|
|
||||
@@ -37,16 +43,106 @@ uv run gyxx scripts run <command_id> --date 2026-08-01 --execute
|
||||
| 京东自营品牌单日回采 | `shop.jd_self_operated.collect_brand` | `--date` 自动成为起止日期 |
|
||||
| 商品历史补采 | `product.backfill.run` | `--date` 自动成为 `--from/--to` |
|
||||
| 商品评价补采 | `product.review.orchestrate` | `--date` 自动成为目标日期 |
|
||||
| 天猫旗舰店和箱包店视频上传 | `product.video_upload.run` | 业务日期用于运行审计;默认顺序扫描两店,由 PostgreSQL 附件级账本防重 |
|
||||
| 京东旗舰店视频上传 | `product.jd_video_upload.run` | 业务日期只用于运行审计;从固定凌云air记录锚点按飞书视图顺序扫描,日期可为空 |
|
||||
| 采购单更新 | `supply.workflow.run` | 自动选择 `mcp-run purchase-order-update` |
|
||||
|
||||
命令的额外脚本参数使用可重复的 `--arg=<值>` 传入。`supply.workflow.run --execute` 会进入真实 ERP 修改链路,必须在任务文件、目标范围和回滚条件全部复核后执行。
|
||||
|
||||
### 天猫视频上传工作流
|
||||
|
||||
天猫视频上传注册为手动幂等工作流 `product.video_upload`,不会被常驻调度器自动触发。前端“立即运行”窗口会显示“光影行星旗舰店 / 光影行星鑫华达专卖店:龙虾仔”单选下拉框,并允许填写天猫话题完整名称或关键词;正式执行只处理所选店铺,话题搜索结果按包含关系选中。默认 dry-run 只生成运行记录并跳过浏览器节点;确认飞书待传记录、对应淘宝光合店铺的登录态和 PostgreSQL 后,再显式正式执行:
|
||||
|
||||
```bash
|
||||
uv run gyxx run product.video_upload --date 2026-08-07
|
||||
uv run gyxx run product.video_upload --date 2026-08-07 --execute
|
||||
```
|
||||
|
||||
前端把店铺选择作为受限运行参数传给脚本,只允许 `flagship` 或 `luggage`。脚本先读取飞书并应用所选店铺路由,再写入/读取附件级账本;只有存在可领取的未上传附件时才启动有头 Chrome、登录对应账号并上传。旗舰店只选择“天猫上传”未勾选且有附件的光影行星男/女记录;箱包店只选择女性、全部款式命中箱包店白名单且有附件的记录。两店分别使用 `GUANGHE_USERNAME` / `GUANGHE_PASSWORD` 和 `GUANGHE_LUGGAGE_USERNAME` / `GUANGHE_LUGGAGE_PASSWORD`,箱包店当前账号为 `光影行星鑫华达专卖店:龙虾仔`,密码配置保持不变,并保留独立浏览器 Profile。发生登录或页面错误时保留窗口供人工定位,排查完成后手动关闭。
|
||||
|
||||
每次正式扫描都会把视频附件写入 PostgreSQL 附件级发布账本,防重身份由视频 `file_token + 目标账号 + 飞书记录` 构成。账本状态为 `published` 的附件在下次执行时自动跳过,因此同一业务日期可以安全重跑并发现新增附件。旗舰店仍只在一条飞书记录的全部附件发布成功后回写“天猫上传”;箱包店不借用该勾选状态,是否已上传完全以自己的目标账号账本为准。
|
||||
|
||||
首次正式执行会读取 `config/tmall-video-publication-backfill.json`,将 2026-07-26 箱包店旧日志中可按 `record_id + file_token + 文件名` 再次核验的 25 个明确成功附件回填为 `published`。配置与当前飞书任一身份不一致都会停止,不会静默猜测。该回填不依赖部署机保留旧 `var/` 日志文件;证据路径与成功行号已固化在配置中供审计。
|
||||
|
||||
只有淘宝光合页面出现明确成功回执后才把附件记为 `published`。点击发布后超时、浏览器中断或回执无法确认时,必须记为 `ambiguous` 并停止自动重发;先在对应店铺的作品管理中按账号、附件和飞书记录人工核对,再做审计式对账,不能通过更换业务日期或重复运行绕过。
|
||||
|
||||
单条续跑或指定附件使用公开命令,并通过可重复的 `--arg` 传参。下面的命令会停在正式发布前,核对无误后才能去掉 `--stop-before-publish`:
|
||||
|
||||
```bash
|
||||
uv run gyxx scripts run product.video_upload.run --date 2026-08-07 --arg=--record-id --arg=RECORD_ID --arg=--stop-before-publish --execute
|
||||
```
|
||||
|
||||
### 京东视频上传工作流
|
||||
|
||||
京东视频上传注册为手动幂等工作流 `product.jd_video_upload`。它不会被常驻调度器自动触发;同一业务日期可以重复执行。每次都从飞书视图中的固定凌云air记录 `recvrXTRWWFXeJ`(含)扫描到视图末尾,不依赖“日期”字段。真正的防重键是 PostgreSQL 中的 `视频 file_token + 目标账号 + 飞书记录`:
|
||||
|
||||
```bash
|
||||
uv run gyxx run product.jd_video_upload --date 2026-08-07
|
||||
uv run gyxx run product.jd_video_upload --date 2026-08-07 --execute
|
||||
```
|
||||
|
||||
框架 dry-run 不启动子进程,不下载附件、不写数据库也不打开京东。前端控制台点击“京东视频上传”会重新扫描锚点之后的视图后缀:新建的记录即使日期为空也能被发现;既有后缀记录后来新增第二个视频附件时,新 `file_token` 也会形成独立任务。已入账的同一 `record_id + file_token` 不会重复发布。锚点丢失或重复时脚本拒绝退化为全表扫描,避免误发历史内容。组合款在下载素材前直接跳过。正式执行按视图顺序逐条处理:有图片时设置飞书封面;没有图片时保留京东从视频生成的默认封面;生成 5-27 字标题、关联同款同色商品、选择相关话题和标签。只有页面出现明确成功回执后才把账本写为 `published`;点击发布后超时或浏览器中断会写为 `ambiguous` 并停止,必须先在京东内容管理中人工核对,不能自动重发。
|
||||
|
||||
商品关联只按页面商品标题中的款式名做受控模糊匹配,再由直连多模态大模型判断包体颜色;价格和 SPU 不参与查询或勾选。同款同色商品可多选,整个表单最多 10 个。SPU 仅作为可选审计信息;组合款视频当前主动跳过。
|
||||
|
||||
首次登录或遇到验证码时,使用公开命令限定一条记录并停在发布按钮前:
|
||||
|
||||
```bash
|
||||
uv run gyxx scripts run product.jd_video_upload.run --date 2026-08-07 --arg=--record-id --arg=RECORD_ID --arg=--manual-login --arg=--stop-before-publish --execute
|
||||
```
|
||||
|
||||
首次部署或多京东账号部署必须显式配置稳定且不可变的 `JD_VIDEO_ACCOUNT_KEY`;已有单账号账本时,前端运行会从 JD 渠道唯一账号 cohort 自动解析,数据库不保存登录账号明文。浏览器由 Scrapling 隐身会话启动真实 Chrome,默认使用该命令独立的 Profile、Cookie 和 Storage State,不能改成其他京东采集任务的共享目录。需要复用一个已启动且已验证的京麦 Chrome 会话时,使用运行时绑定注入的 `GYXX_BROWSER_CDP_URL`;脚本只借用唯一的现有 context,并在退出时保留原浏览器及其页面。
|
||||
|
||||
### 主图周工作流
|
||||
|
||||
主图调度的唯一工作流 ID 是 `product.main_image.weekly`,每周日 08:30 启动。图同时运行 JD、TM 两个无依赖分支;一个平台失败不会取消、跳过或回滚另一个平台的采集、PG upsert 和飞书插入。两个分支全部结束后再汇总工作流状态:任一平台失败时整体状态为失败,并在错误摘要中标明具体平台和错误,另一平台已经成功的结果继续保留。
|
||||
|
||||
两个平台默认都在采集后执行飞书主图表插入和本地 PostgreSQL `main_image_creatives` upsert。执行前必须同时确认两套浏览器登录态、飞书身份和本地数据库;排障时分别检查 `jd`、`tmall` 节点以及对应插入脚本日志,不能只以采集文件存在判断双 sink 已完成。
|
||||
|
||||
### 三平台电商费用日报
|
||||
|
||||
唯一工作流 ID 是 `product.ecommerce_costs.daily`,每天 10:00 由项目内 Python 调度器运行,
|
||||
业务日期为前一天;天猫、京东、抖音三个下载分支并行启动,各自完成下载后再导入。天猫流程先进入万相台商品报表选择昨日,提交下载任务;任务在下载列表显示“生成成功”
|
||||
后下载 ZIP、做路径安全校验并解压 CSV,随后将商品级广告指标幂等写入
|
||||
`product_daily_metrics.raw_data.tm_ad_metrics`。商品款式先按 `dim_style.tm_spus` 的商品 ID 匹配,
|
||||
匹配不到再按商品名称做精确包含匹配,并在节点内保留 `style_name` 与
|
||||
`style_match_method`(`product_id`/`product_name`/`ambiguous`/`unmatched`)。它不会覆盖同一商品日期
|
||||
已有的访客、成交等经营日报字段;data-hub 产品生命进程从该节点读取广告成交金额和花费并计算投产比、电商费比。
|
||||
|
||||
正式服务必须注入 `WANXIANG_ACCOUNT`、`WANXIANG_PASSWORD`、`GYXX_DATA_ROOT` 和
|
||||
`GYXX_POSTGRES_DSN`。默认浏览器 Profile 是
|
||||
`<GYXX_DATA_ROOT>\state\browser-profiles\wanxiang-ads`,登录失效时不能在另一个 Profile 中登录后
|
||||
期待服务自动获得状态。
|
||||
|
||||
手工验证或补采某一天时,先 dry-run,再显式执行完整工作流:
|
||||
|
||||
```powershell
|
||||
uv run gyxx run product.ecommerce_costs.daily --date 2026-08-17
|
||||
uv run gyxx run product.ecommerce_costs.daily --date 2026-08-17 --execute
|
||||
```
|
||||
|
||||
如果登录态失效,使用有头的采集命令(不要给它加 `--headless`)完成验证码/滑块,再单独导入:
|
||||
|
||||
```powershell
|
||||
uv run gyxx scripts run product.tmall_wanxiang_ads.collect --date 2026-08-17 --execute
|
||||
uv run gyxx scripts run product.import.tmall_ads --date 2026-08-17 --execute
|
||||
```
|
||||
|
||||
原始文件位于 `<GYXX_DATA_ROOT>\data\raw\product_commerce\tmall_wanxiang_ads\<date>\`,其中
|
||||
`manifest.json` 记录 ZIP 和解压出的 CSV。定时工作流每次都会进入商品报表点击“下载报表”,在日期范围
|
||||
选择“昨日”并点击“确定”,再到下载列表等待“生成成功”。若只需重新解析已下载文件,可以跳过采集步骤
|
||||
重跑导入;默认导入以 manifest 列出的本次 CSV 为准,避免同一日期目录中历史 CSV 被重复合并;重复导入同一日期和商品不会产生重复行。采集命令手工重试时若不加 `--force-request`,仍可
|
||||
复用下载列表中已有的“生成成功”任务。
|
||||
|
||||
排障顺序:
|
||||
|
||||
1. 检查 `gyxx schedule status`、服务日志和对应 `run_id`,确认失败发生在申请、下载、解压还是入库。
|
||||
2. 检查同一 Profile 是否仍能打开万相台商品报表;登录失效时在有头命令中人工完成验证。
|
||||
3. 检查日期目录中的 `manifest.json`、CSV 表头和 `日期/主体ID/主体名称`;ZIP 存在不代表数据库已导入。
|
||||
4. 检查 PostgreSQL 的 `product_daily_metrics` 是否存在 `platform='tm'`、目标日期和商品 ID,且
|
||||
`raw_data->'tm_ad_metrics'` 已更新;确认经营日报其他 JSON 节点仍保留。
|
||||
5. 只有在外部状态核对清楚后才按同一业务日期重跑,不能用换日期或重复申请掩盖下载结果不明。
|
||||
|
||||
## 调度操作
|
||||
|
||||
```bash
|
||||
@@ -73,9 +169,37 @@ uv run gyxx schedule run --env-file /etc/gyxx-flow/gyxx-flow.env
|
||||
- `data/normalized`、`data/curated`:清洗、标准化和聚合数据。
|
||||
- `data/exports`:Markdown、Excel 等交付文件。
|
||||
- `state/browser/<module>/<script>`:独立 Cookie、Profile 和 storage state。
|
||||
- `state/accounts/<account>`:账号级登录态主库(同一账号多个脚本共用,`runtime-bindings.json` 中声明 `account` 的脚本每次运行前自动合并同步)。
|
||||
- `state/scheduler`、`state/locks`、运行账本:调度和幂等状态。
|
||||
- `tmp`:仅存放可重建临时文件。
|
||||
|
||||
账号级登录态管理:
|
||||
|
||||
- `gyxx accounts list`:查看账号、登录态有效性、成员脚本。
|
||||
- `gyxx accounts login <account_id>`:打开该账号的登录浏览器(独立 Profile),人工扫码/验证码登录后自动保存 `cookies.json`/`storage_state.json` 到账号主库,并同步到全部成员脚本;`--timeout` 控制等待时长,`--force` 强制重登。
|
||||
- `gyxx accounts sync [<account_id>]`:把账号主库 cookie 推送到成员脚本(不打开浏览器)。
|
||||
- `gyxx accounts seed <account_id> --source-binding <binding_id>`:一次性把已有脚本的登录态按平台域名过滤后导入账号主库;仅用于迁移,不替代后续的账号级登录。
|
||||
|
||||
同一账号只需登录一次:之后任何成员脚本运行前都会从账号主库合并最新登录态到自己的独立 Cookie 文件,无需逐脚本登录。
|
||||
|
||||
当前配置按登录身份拆分为以下账号,避免同一平台不同店铺互相覆盖 Cookie:
|
||||
|
||||
- `douyin-shop`:抖店,600 秒;
|
||||
- `jd-shop`、`jd-self-operated`、`jd-market-rank`:京东三个独立登录身份,各 900 秒;
|
||||
- `tmall-shop`:天猫/淘宝/万相台光影行星账号,900 秒;
|
||||
- `tmall-ozko`:商品经营日报 ozko 账号,900 秒;
|
||||
- `xiaohongshu-content`:小红书,900 秒;
|
||||
- `douyin-content`:抖音内容侧,900 秒;
|
||||
- `xingtu`:星图,900 秒;
|
||||
- `chanmama`:蝉妈妈,900 秒;
|
||||
- `bilibili-content`:B 站,900 秒。
|
||||
|
||||
商品经营日报 `product_commerce:taobao_sycm_collect.py` 会在同一次运行中按品牌路由账号:光影行星使用 `tmall-shop`,ozko 使用 `tmall-ozko`,两边各自使用独立 Profile 和账号 vault。`tmall-ozko` 没有静态成员脚本是有意设计,因为它由这个按品牌拆分的包装工作流动态选择;登录态成功后仍会回写 `state/accounts/tmall-ozko/`,由同一套 keepalive 负责续期。
|
||||
|
||||
账号需要在 `config/runtime-bindings.json` 的 `accounts.<account_id>.keepalive` 中显式开启续期,并配置一个不会产生业务副作用的已登录页面 URL。所有账号由唯一的 `gyxx schedule run` 常驻进程在后台维护;每个账号使用独立 CDP 端口、独立 Profile 和账号级 Cookie vault,启动后按 `initial_delay_seconds` 错峰访问,避免同时打开多个登录页面。访问成功且没有跳转到登录页时,Scrapling 才会把最新 Cookie/storage state 原子写回 `state/accounts/<account_id>/`,并同步给成员脚本;不需要另建 Windows 任务计划、cron 或 timer。
|
||||
|
||||
Cookie 续期只能延长站点支持滑动续期的会话,不能突破服务端硬过期、主动退出、风控或验证码。keepalive 检测到登录页/无效 Cookie 时会停止发布,不会用失效状态覆盖最后一份有效 vault;此时按 `gyxx accounts list` 检查 `keepalive.status`,必要时重新执行 `gyxx accounts login <account_id>`。
|
||||
|
||||
项目不会自动搬动或删除已有 `var/`。迁移数据根时应停止调度器,完整备份和复制原目录,修改环境变量后依次运行 doctor、dry-run 和一次指定日期的对账执行。
|
||||
|
||||
## 清理和保留
|
||||
|
||||
@@ -109,10 +109,9 @@
|
||||
| 完成 | 工作流 | 调度 | 用途 | 最终状态、run_id 与关键证据 |
|
||||
|---|---|---|---|---|
|
||||
| ⬜ | `product.persona.daily` | 每天 10:00 | 三平台商品人群画像采集 | `PARTIAL_FAILED`;`product.persona.daily__20260815__20260801T103908Z__2d6028`;天猫缺 DMP、抖音缺搜索控件、京东完成 19/30 后浏览器崩溃 |
|
||||
| ⬜ | `product.daily` | 每天 08:40,业务日 -1 | ERP/三平台采集、分析、导出、入库 | `PARTIAL_TIMEOUT`;`product.daily__20260731__20260801T113513Z__b59304`;ERP/JD/TM 完成,DY 超时,raw 257;独立下游完成分析、导出 32、本地 upsert 与 32 个飞书写跳过 |
|
||||
| ⬜ | `product.daily` | 每天 08:40,业务日 -1 | ERP/三平台采集、原始日报入库、分析、导出、飞书写入 | `PARTIAL_TIMEOUT`;`product.daily__20260731__20260801T113513Z__b59304`;ERP/JD/TM 完成,DY 超时,raw 257;独立下游完成分析、导出 32、本地 upsert 与 32 个飞书写跳过;原 `product.import.daily` 已并入 `product.daily` 的 `import` 阶段 |
|
||||
| ✅ | `product.alert.daily` | 每天 23:00 | 商品异常检测和条件通知 | `PASS`;`script.product_commerce.955b1dfb0cdf__20260801__20260801T085614Z__4fefb3`;真实读取本地库,无符合阈值异常,未产生通知 |
|
||||
| ✅ | `product.import.daily` | 每天 19:00 | 三平台日报幂等导入本地 PG | `PASS`;`script.product_commerce.9137239938d5__20260727__20260801T085541Z__59c16c`;抖音/京东/天猫 163/90/173 行,无重复 |
|
||||
| ✅ | `product.style_analysis.interval` | 每 3 天 11:00 | 本地 Hermes 分析到期款式 | `PASS_WITH_SKIPS`;`product.style_analysis.interval__20260801__20260801T084137Z__952204`;数据库/Hermes 检查和实现入口 dry-run 成功,外部写关闭 |
|
||||
| ✅ | `product.style_analysis.interval` | 每 3 天 11:00 | 直连 MiniMax 分析到期款式 | `PASS_WITH_SKIPS`;历史基线 `product.style_analysis.interval__20260801__20260801T084137Z__952204` 保留;本次 `星云2` 2026-08-26~2026-08-28 真实直连 MiniMax、飞书、Base、PostgreSQL 均成功 |
|
||||
| ⬜ | `product.main_image.weekly` | 周日 08:30 | JD、Tmall 主图并行采集,两边独立 PG 入库与飞书插入 | `PENDING_RETEST_AFTER_MERGE`;尚无合并后新图的业务 run_id。工程结构要求为两个无依赖且资源隔离的分支;任一分支受控失败不阻断另一分支,全部结束后整体失败并报告平台级具体错误。合并前 run 仅见下方历史证据表 |
|
||||
| ⬜ | `product.market_rank` | 周一 10:00 | 三平台周市场排行采集、归档 | `FAIL_AUTH_OR_UI`;`product.market_rank__20260814__20260801T103628Z__5a9024`;天猫认证、京东类目配置、抖音控件分别失败;目标与来源脚本哈希一致 |
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
3. 飞书 Base、Bitable、Sheets 的新增、更新、删除全部物理跳过并留证;飞书读取可以执行。
|
||||
4. 通知收件人只允许王云龙;不得向原业务群、原收件人或其他用户发送。通用 `production_sink` 只能证明进入副作用边界,不能据此推断消息正文或投递回执。
|
||||
5. 每个浏览器入口保留独立 CDP、Profile、Cookie 和 storage state。登录策略固定为“本项目状态 → 已复制的来源状态 → 受支持的账号密码回退 → 安全跳过”;不弹出二维码、不人工通过验证码。
|
||||
6. 本机 Hermes 分析端和采集端只通过回环地址访问,不得回退到远程 AI。
|
||||
6. 仍使用 Hermes 的工作流,其分析端和采集端只通过回环地址访问,不得静默回退到远程 AI;`product.style_analysis.interval` 是已登记的例外,显式直连 MiniMax。
|
||||
7. JSON、Markdown、CSV、Excel、图片、日志和 journal 必须按模块、工作流、业务日期落入 `GYXX_DATA_ROOT`;来源目录只读且不得成为运行时依赖。
|
||||
8. 凭据只允许运行时注入。历史遗留 `db.env`、`analyze.env` 必须删除,仓库和验收报告不得记录账号、密码、Cookie、token 或密钥。
|
||||
|
||||
@@ -62,10 +62,10 @@
|
||||
## 7. 商品工作流
|
||||
|
||||
- [ ] `product.persona.daily`:并行采集天猫、抖音、京东商品人群画像。`PARTIAL_FAILED`;run_id `product.persona.daily__20260815__20260801T103908Z__2d6028`。天猫缺少 DMP 入口,抖音缺少搜索控件,京东完成 19/30 后浏览器崩溃,部分结果不能代表三平台完成。
|
||||
- [ ] `product.daily`:ERP 与三平台采集、分析、导出和入库。`PARTIAL_TIMEOUT`;run_id `product.daily__20260731__20260801T113513Z__b59304`。ERP、京东、天猫完成,抖音超时;保留 257 个 raw 文件。独立下游验证完成分析、32 条导出、本地 PG upsert 和 32 次飞书写跳过,但不把下游成功升级为整体通过。
|
||||
- [ ] `product.daily`:ERP 与三平台采集、原始日报入库、分析、导出和飞书写入。`PARTIAL_TIMEOUT`;run_id `product.daily__20260731__20260801T113513Z__b59304`。ERP、京东、天猫完成,抖音超时;保留 257 个 raw 文件。独立下游验证完成分析、32 条导出、本地 PG upsert 和 32 次飞书写跳过,但不把下游成功升级为整体通过。原 `product.import.daily` 定时任务已并入本流程的 `import` 阶段。
|
||||
- [x] `product.alert.daily`:读取商品数据并检测销量异常、按条件通知。`PASS`;实际入口 run_id `script.product_commerce.955b1dfb0cdf__20260801__20260801T085614Z__4fefb3`。本地库读取成功,当次无符合阈值的异常,因此没有告警新增或通知。
|
||||
- [x] `product.import.daily`:把三平台商品日报幂等导入本地 PG。`PASS`;实际入口 run_id `script.product_commerce.9137239938d5__20260727__20260801T085541Z__59c16c`。抖音、京东、天猫分别处理 163、90、173 行,无重复。
|
||||
- [x] `product.style_analysis.interval`:使用本地 Hermes 分析到期款式。`PASS_WITH_SKIPS`;workflow run_id `product.style_analysis.interval__20260801__20260801T084137Z__952204`。数据库表/权限与 Hermes 健康检查通过,单款实现入口内部 dry-run 成功,未写外部副作用目标。
|
||||
- [x] 商品日报导入阶段:把三平台商品日报幂等导入本地 PG。`PASS`;历史独立入口 run_id `script.product_commerce.9137239938d5__20260727__20260801T085541Z__59c16c`。抖音、京东、天猫分别处理 163、90、173 行,无重复;现由 `product.daily` 的 `import` 阶段承载。
|
||||
- [x] `product.style_analysis.interval`:直连 MiniMax 分析到期款式,不依赖本地 Hermes 分析端。历史验收 run_id `product.style_analysis.interval__20260801__20260801T084137Z__952204` 保留作迁移基线;本次已用 `星云2` 的 2026-08-26~2026-08-28 窗口完成真实 MiniMax、飞书、Base 和 PostgreSQL 写入验证。
|
||||
- [ ] `product.main_image.weekly`:周日 08:30 并行启动 JD、Tmall 两个无依赖且资源隔离的主图分支,两个子链均独立执行本地 PG 入库与飞书插入逻辑。`PENDING_RETEST_AFTER_MERGE`;当前没有可归属于合并后新图的业务 run_id。工程结构要求为:任一分支受控失败时,另一分支仍完成自己的采集和双 sink 写入;全部结束后整体聚合为失败,并在错误摘要中标明具体平台和错误。下一轮需在现有飞书零写门禁下完成受控业务复测。
|
||||
- [ ] `product.market_rank`:并行采集天猫、京东、抖音三平台周市场排行。`FAIL_AUTH_OR_UI`;run_id `product.market_rank__20260814__20260801T103628Z__5a9024`。天猫认证失败、京东缺配置类目、抖音目标控件缺失;目标脚本与来源哈希一致,当前证据不支持判定为迁移改坏。
|
||||
|
||||
|
||||
@@ -17,9 +17,15 @@ uv run gyxx console
|
||||
uv run gyxx console --env-file D:\secure\gyxx-flow.env
|
||||
```
|
||||
|
||||
商品经营正式执行会在启动子进程前校验云端 PostgreSQL、`hermes-analyzer` 飞书身份、
|
||||
所需 Hermes 密钥和负责人 `open_id`。缺少任一必需项时,前端会返回明确的配置错误,
|
||||
不会创建一个注定失败的“正式运行”。
|
||||
商品经营正式执行会在启动子进程前校验云端 PostgreSQL 和该工作流实际需要的运行时配置。
|
||||
需要 Hermes 分析或业务通知的工作流仍会校验 `hermes-analyzer` lark-cli user 身份和负责人
|
||||
通知路由;天猫/京东视频上传则校验 `STYLE_ANALYSIS_LLM_BASE_URL`(或
|
||||
`GYXX_DIRECT_LLM_BASE_URL`)与对应 API Key,直接调用 MiniMax,不解析或转发 Hermes API
|
||||
凭据;内容周度/月度汇总校验 `CONTENT_ANALYSIS_LLM_API_KEY`,使用
|
||||
`CONTENT_ANALYSIS_LLM_BASE_URL` 指定的 MiniMax Anthropic 兼容接口。缺少任一实际必需项时,
|
||||
前端会返回明确的配置错误,不会创建一个注定失败的“正式运行”。
|
||||
运行调度服务的 Windows/NSSM 账户必须持有同一 profile 的有效 user 授权与
|
||||
`im:message.send_as_user`、`im:message` scope。
|
||||
|
||||
默认地址为 `http://127.0.0.1:8765`。控制台进程与调度进程职责分离;服务器仍只运行一个
|
||||
项目内调度服务:
|
||||
@@ -30,9 +36,13 @@ uv run gyxx schedule run
|
||||
|
||||
页面可以:
|
||||
|
||||
- 在顶部查看调度服务状态;显示“调度服务未运行”时,可点击“启动调度器”拉起唯一的常驻 Python 调度进程。启动会继承控制台的 `--env-file`,并在页面中持续刷新真实服务状态;若已有到期但尚未执行的计划,调度器会按现有补偿窗口评估并启动对应任务;
|
||||
- 按内容营销、商品经营、店铺洞察和供应链分别展示全部工作流;
|
||||
- 查看工作流定义、执行步骤、定时规则和下一次启动时间;
|
||||
- 修改定时类型、一个或多个时间、日期规则、启停状态和业务日期偏移;
|
||||
- 配置实际支持业务通知的工作流、发送应用和一个或多个收件人;
|
||||
- 在云端数据库中增删改查商品 ID、ERP 款式编码和各业务飞书目标表;
|
||||
- 查看昨天或指定执行日的逐工作流运行汇总、异常原因和修复建议;
|
||||
- 以安全预演或正式执行方式手动触发已注册工作流;
|
||||
- 查看最近运行状态、步骤统计和经过脱敏的错误详情。
|
||||
|
||||
@@ -40,12 +50,78 @@ uv run gyxx schedule run
|
||||
加载配置,不需要创建或修改 Windows Task Scheduler 任务。若新规则在错过触发补偿窗口
|
||||
内已经到期,下一次轮询可能立即启动该工作流。
|
||||
|
||||
## 商品与款式配置
|
||||
|
||||
侧栏“商品与款式配置”维护商品经营和内容营销共用的动态配置。页面提供款式、品牌、平台、
|
||||
商品 ID、ERP 编码、启停状态和各业务飞书目标表的查询与 CRUD;保存后从下一次新启动的工作流
|
||||
生效。编辑和删除带行版本校验,旧页面不能覆盖其他操作员已保存的新版本。
|
||||
|
||||
配置存储在云端 PostgreSQL,旧飞书配置主表不再属于运行路径。首次迁移、字段模型、受影响
|
||||
工作流和失败回退边界见 [工作流动态配置](dynamic-workflow-config.md)。
|
||||
|
||||
## 每日运行汇总
|
||||
|
||||
侧栏“每日运行汇总”默认按 `config/schedules.json` 的时区读取昨天。统计窗口以工作流实际
|
||||
`started_at` 所在的本地执行日为准,不会把“昨天执行、业务日期为前天”的采集任务漏掉。
|
||||
汇总范围包含当天应由调度器触发的工作流,以及当天实际发生过正式执行、安全预演或控制台/
|
||||
调度日志的工作流。
|
||||
|
||||
成功、失败、取消、仍在运行、计划未执行和失败后恢复等状态由运行索引、`run.json` 与计划
|
||||
时点确定,大模型无权改写这些事实。分析端 Hermes 在服务端读取已脱敏、限长的调度/控制台
|
||||
日志,并把技术信息翻译成非技术人员能理解的执行结果、异常影响和修复步骤。Hermes 未配置或
|
||||
暂时不可用时,接口仍返回不含原始错误的通俗规则说明,页面会明确标记分析降级,不会整页失败。
|
||||
|
||||
接口如下:
|
||||
|
||||
- `GET /api/daily-summary`:读取昨天的缓存或生成汇总;可用 `date=YYYY-MM-DD` 指定执行日;
|
||||
- `POST /api/daily-summary/refresh`:正文可传 `{"date":"YYYY-MM-DD"}`,强制重新读取日志并分析。
|
||||
|
||||
缓存位于 `GYXX_DATA_ROOT/state/ops/daily-summaries/<date>.json`。工作流/计划配置、当天运行
|
||||
索引、相关日志或分析器配置发生变化时,指纹会失效并自动重建。日志原文、堆栈、路径、技术
|
||||
错误载荷和步骤错误只作为服务端模型输入,不写入汇总缓存,也不返回浏览器;页面只收到运行
|
||||
状态、时间等结构化事实和翻译后的中文结论。
|
||||
|
||||
## 通知路由
|
||||
|
||||
侧栏“通知路由”只展示代码中已经接入动态业务通知的工作流,不会让没有发送行为的工作流
|
||||
凭空获得通知能力。当前范围为营销日报、内容平台登录态刷新、销量下滑告警、市场排行,以及
|
||||
采购确认、补货结果、库存阈值预警共 7 条工作流。登录态刷新配置控制扫码二维码和失败汇总;
|
||||
其余路由控制各自满足发送条件后的业务结果。每条路由有三种状态:
|
||||
|
||||
- “恢复沿用”继续使用该工作流已有的命令行或环境变量收件人;
|
||||
- “动态接管”使用页面中选择的多人名单;
|
||||
- “关闭通知”仍执行并保存工作流产出,但跳过该路由声明的业务消息。
|
||||
|
||||
页面不接管临时手工分析工具,也不改写策略固定的群通知。例如
|
||||
`purchase-order-update` 的审单群消息继续由供应链策略维护,不会因为它能发消息就自动出现在
|
||||
路由页面;这正是“不是所有工作流都要通知、也不是所有消息都允许在线改收件人”的边界。
|
||||
|
||||
人员的 `open_id` 按飞书应用隔离,不能跨应用复用。页面只允许选择配置中声明为分析端 Hermes
|
||||
且服务器安装 profile 与 App ID 完全匹配的应用。可用手机号调用飞书通讯录接口解析该应用
|
||||
作用域内的 `open_id`;应用密钥仍只存在于服务端运行时,不会进入浏览器或通知配置。解析结果
|
||||
需要随“保存全部配置”一起提交才会生效;手工改写 OpenID 会自动取消手机号验证标记,服务端
|
||||
也不会信任没有本次查询证明的“已验证”声明。
|
||||
|
||||
版本库中的 `config/notification-routing.json` 是首次启动的人员、应用和通知能力基线。页面
|
||||
修改会带版本号原子写入 `GYXX_DATA_ROOT/state/notifications/routing.json`,不会修改源码配置;
|
||||
冲突时页面会重新加载最新版本。每次工作流启动时会固定本次路由快照,所以保存后的配置从
|
||||
下一次运行开始生效,不会在正在执行的任务中途改变收件人。声明了通知能力的公开手工命令也
|
||||
会在启动时绑定到对应工作流路由;没有明确归属的通用命令不会误用其他工作流的快照。
|
||||
|
||||
## 执行安全
|
||||
|
||||
手动运行默认选择“安全预演”,不会产生真实外部副作用。只有在页面中选择“正式执行”并
|
||||
确认影响后,控制台才会通过固定的 `python -m gyxx_flow run ... --execute` 入口启动独立
|
||||
子进程。浏览器不能提交脚本路径、命令参数、环境变量或凭据。
|
||||
|
||||
运行弹窗中的“业务日期/业务月份”可手动选择,默认按定时配置的业务日期偏移预填;正式执行
|
||||
时还可勾选“强制重跑”,控制台通过 `GYXX_FORCE_REFRESH=true` 环境变量让工作流忽略幂等
|
||||
跳过并重新采集覆盖该业务日期。卡片与抽屉的“正式执行/强制重跑”按钮均先打开弹窗确认
|
||||
日期与影响,不会未经确认直接提交。
|
||||
|
||||
天猫百亿补贴批量报名是例外:它按每次运行重新下载模板并提交所选入口,不使用按业务日期
|
||||
划分的效果账本,也不要求核对旧导入回执;运行记录中的日期仅用于平台内部归档。
|
||||
|
||||
控制台沿用 `GYXX_DATA_ROOT`,因此运行日志、工作流锁、运行索引和副作用账本与 CLI、调度
|
||||
服务保持同一边界。生产部署必须为所有进程设置同一个外部数据根。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user