feat: publish sqlite click gap dashboard
This commit is contained in:
@@ -1,62 +1,71 @@
|
||||
# AppsFlyer Click Gap
|
||||
# Click Gap 数据看板
|
||||
|
||||
运行目标是 **mac2**。流水线复用 `appsflyer/af_click_gap.py` 的 Superset 查询、AppsFlyer payload、特殊包名映射和差值公式,但新入口增加 timeout/重试、严格错误边界、AppsFlyer 重复键按 `dt+pkg_name` 求和,并将日志写到仓库外 `~/Library/Logs/af-click-gap/pipeline.log`。固定数据库:`/Users/ads-center/Documents/database/af_click_gap.db`;不复制或提交数据库、cookie、token、`.env`、日志和缓存。
|
||||
运行目标是 **mac2**。另一个独立的外部 AppsFlyer 任务每天把汇总结果写入 SQLite;本项目不调用该任务、不访问 AppsFlyer、Superset 或其它提取 API,只从固定数据库只读查询并发布静态 JSON。
|
||||
|
||||
## 文件和字段
|
||||
固定数据库:`/Users/ads-center/Documents/database/af_click_gap.db`。数据库必须预先存在 `click_gap` 表,脚本不建表、不迁移、不写入数据库。表要求包含:
|
||||
|
||||
- `scripts/af_click_gap_pipeline.py`:提取、校验、发布和 Git 操作。
|
||||
- `data/YYYYMMDD.json`:**直接 JSON 数组**;无数据日期也写 `[]`。每行字段为 `dt`(`YYYYMMDD` 字符串)、`attr_platform`、`pkg_name`(非空字符串)、`shareit_clicks`、`af_clicks`、`installs_ua`、`clicks_diff`(有限 number)、`clicks_diff_rate`(有限 number 或 `null`)。业务键为 `pid + dt + pkg_name`。
|
||||
- `data/index.json`:版本、生成时间及 `data/YYYYMMDD.json` 清单。
|
||||
- `index.html`:无构建依赖的静态看板。
|
||||
```text
|
||||
pid TEXT NOT NULL, dt TEXT NOT NULL, attr_platform TEXT NOT NULL,
|
||||
pkg_name TEXT NOT NULL, shareit_clicks REAL NOT NULL, af_clicks REAL NOT NULL,
|
||||
installs_ua REAL NOT NULL, clicks_diff REAL NOT NULL,
|
||||
clicks_diff_rate REAL, updated_at TEXT NOT NULL
|
||||
```
|
||||
|
||||
默认窗口是 mac2 本地运行日及前 6 天,首尾包含,共 7 天;这是对旧脚本实际可能覆盖 8 个日期的修正。空 Superset 结果、无达标包或 AppsFlyer 合法空数组都是成功空结果(退出码 0),仍生成日期数组、同步清空 SQLite 窗口并可提交;HTTP、认证、响应格式、SQLite schema 或文件校验错误退出码 1,不覆盖正式文件。
|
||||
主键必须为 `(pid, dt, pkg_name)`。脚本只读取 `pid='shareit'`,并校验字段、日期、数值、重复业务键和有限数值。
|
||||
|
||||
SQLite 必须预先存在 `click_gap` 表,列类型为 `pid TEXT NOT NULL, dt TEXT NOT NULL, attr_platform TEXT NOT NULL, pkg_name TEXT NOT NULL, shareit_clicks REAL NOT NULL, af_clicks REAL NOT NULL, installs_ua REAL NOT NULL, clicks_diff REAL NOT NULL, clicks_diff_rate REAL, updated_at TEXT NOT NULL`,主键严格为 `(pid, dt, pkg_name)`。脚本不建表、不迁移;每次成功运行先删除窗口内 `shareit` 旧行再插入完整新结果,因此消失日期/业务键也会清零。
|
||||
## 输出协议
|
||||
|
||||
- `data/YYYYMMDD.json`:直接 JSON 数组;最近 7 天每天生成一个文件,即使当天无数据也生成 `[]`。
|
||||
- `data/index.json`:包含 `schema_version`、`generated_at` 和最近 7 天的 `data/YYYYMMDD.json` 清单。
|
||||
- 每行字段为 `dt`(`YYYYMMDD`)、`attr_platform`、`pkg_name`、`shareit_clicks`、`af_clicks`、`installs_ua`、`clicks_diff`、`clicks_diff_rate`;最后一项可以为 `null`。
|
||||
|
||||
默认日期边界为运行日往前 6 天至运行日,首尾包含,共 7 天。手工补数使用 `--start-date` 和 `--end-date`,两者必须同时提供且最多 7 天。
|
||||
|
||||
## 手工运行
|
||||
|
||||
在 mac2 先确认依赖和登录环境(`pandas`、`requests`、`requests_toolbelt`、`af_browser`、`superset_login`):
|
||||
|
||||
```sh
|
||||
cd /Users/shareit./Library/CloudStorage/OneDrive-个人/ubuntu/Gitea/af-click-gap
|
||||
python3 -m py_compile scripts/af_click_gap_pipeline.py
|
||||
python3 scripts/af_click_gap_pipeline.py --help
|
||||
python3 scripts/af_click_gap_pipeline.py --dry-run
|
||||
# 正式写入并提交、push(默认行为)
|
||||
python3 scripts/af_click_gap_pipeline.py --push
|
||||
# 只写 data 和 SQLite,不操作 Git
|
||||
python3 scripts/af_click_gap_pipeline.py --no-push
|
||||
# 手工补数,日期首尾包含且最多 7 天
|
||||
python3 scripts/af_click_gap_pipeline.py --push # 写 JSON,commit 并 push
|
||||
python3 scripts/af_click_gap_pipeline.py --no-push # 写 JSON 和 commit,不 push
|
||||
python3 scripts/af_click_gap_pipeline.py --start-date 2026-10-10 --end-date 2026-10-16 --no-push
|
||||
```
|
||||
|
||||
`--dry-run` 只生成仓库外临时 JSON 并校验,不写 data、数据库或执行 Git。正式文件先原子替换,再提交 SQLite,最后才 `git add/commit/push`;数据库提交失败时不执行 Git。commit/push 失败会保留本地文件和数据库,下一次可重跑或手工 `git add data index.html ... && git commit && git push`;不会伪造认证或 force push。工作区在 push 模式有非本任务改动时拒绝继续。
|
||||
`--dry-run` 只读取数据库并在仓库外临时目录生成、校验 JSON,不写 `data` 或 Git。正式运行先原子替换数据文件,再执行 Git;数据库查询或校验失败不会发布文件。push 失败会保留本地 commit,不会 force push。工作区存在本任务之外的未提交改动时,脚本拒绝继续。
|
||||
|
||||
## 看板
|
||||
|
||||
直接打开 `index.html` 或运行 `python3 -m http.server` 后访问。页面读取并校验 `data/index.json` 及清单路径,只执行安全 JSON 解析;缺失/损坏文件显示“数据不完整”并跳过该文件,清单本身失败则不展示数据。默认最近 30 天,可选有效开始/结束日期和 `pkg_name`;默认 `dt` 降序、同日期 `shareit_clicks` 降序,点击表头切换排序。
|
||||
`index.html` 是无构建依赖的静态页面,读取并校验 `data/index.json` 及其清单,支持日期范围、包名筛选和表头排序。直接打开文件或执行 `python3 -m http.server` 后访问即可。
|
||||
|
||||
## mac2 launchd
|
||||
|
||||
`launchd/com.roasbloom.af-click-gap.plist.template` 明确为 `TEMPLATE_ONLY`。当前开发机不能证明自己是 mac2,因此没有伪造最终 plist、解释器或安装结果。必须在 mac2 执行并记录:
|
||||
模板文件为 `launchd/com.roasbloom.af-click-gap.plist.template`,必须在 mac2 使用实际 Python 路径和项目路径渲染后安装:
|
||||
|
||||
```sh
|
||||
hostname
|
||||
command -v python3
|
||||
python3 --version
|
||||
python3 -c 'import pandas,requests,requests_toolbelt,af_browser,superset_login; print("dependencies ok")'
|
||||
cd /Users/shareit./Library/CloudStorage/OneDrive-个人/ubuntu/Gitea/af-click-gap
|
||||
mkdir -p "$HOME/Library/Logs/af-click-gap"
|
||||
PY=$(command -v python3); sed -e "s#__MAC2_PYTHON3__#$PY#" -e "s#__PROJECT_DIR__#$PWD#g" -e "s#__LOG_DIR__#$HOME/Library/Logs/af-click-gap#g" launchd/com.roasbloom.af-click-gap.plist.template > /tmp/com.roasbloom.af-click-gap.plist
|
||||
mkdir -p "$HOME/Library/Logs/af-click-gap" "$HOME/Library/LaunchAgents"
|
||||
PY=$(command -v python3)
|
||||
sed -e "s#__MAC2_PYTHON3__#$PY#" -e "s#__PROJECT_DIR__#$PWD#g" -e "s#__LOG_DIR__#$HOME/Library/Logs/af-click-gap#g" launchd/com.roasbloom.af-click-gap.plist.template > /tmp/com.roasbloom.af-click-gap.plist
|
||||
plutil -lint /tmp/com.roasbloom.af-click-gap.plist
|
||||
cp /tmp/com.roasbloom.af-click-gap.plist "$HOME/Library/LaunchAgents/"
|
||||
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.roasbloom.af-click-gap.plist"
|
||||
launchctl print "gui/$(id -u)/com.roasbloom.af-click-gap"
|
||||
# 卸载:launchctl bootout "gui/$(id -u)/com.roasbloom.af-click-gap"; rm "$HOME/Library/LaunchAgents/com.roasbloom.af-click-gap.plist"
|
||||
```
|
||||
|
||||
定时任务失败不会触发成功 push;stdout/stderr 位于 mac2 用户日志目录。Git remote、SSH/HTTPS credential helper 或 Gitea token 必须由用户在 mac2 预先配置。若 `git remote -v` 为空,请按组织 Git 文档创建仓库并绑定 remote 后再运行;本项目不会猜测仓库名称或修改 git config。
|
||||
卸载:`launchctl bootout "gui/$(id -u)/com.roasbloom.af-click-gap"` 后删除 LaunchAgents 中的 plist。日志写在 mac2 用户日志目录;数据库、`.env`、密钥、日志和缓存均不会提交。
|
||||
|
||||
## 安全和验证
|
||||
## Git 创建和推送
|
||||
|
||||
允许提交的路径仅为脚本、README、看板、`data/*.json`、`data/index.json`、模板和 `.gitignore`。提交前禁止 `.env*`、SQLite、日志、浏览器状态,脚本还扫描 `cookie`、`authorization`、`password`、`api-key`、`token` 文本。建议验证:`python3 -m py_compile ...`、`--help`、mac2 上 `--dry-run`、`python3 -m json.tool data/index.json`,以及浏览器/静态 HTTP 打开页面。当前环境未验证 mac2 依赖、固定数据库、外部登录、launchd 安装和远程 push;这些不能以本机结果冒充。不要新增测试套件。
|
||||
远程仓库约定为 Gitea `https://git.ops.roasbloom.site/liuji/af-click-gap.git`。创建前应检查仓库是否已存在,确认不存在后使用 macOS Keychain 中已有的 Git 凭证创建,再在本地配置 `origin` 并推送当前 `main` 分支。认证信息只通过现有 credential helper 使用,不写入本项目或命令输出。
|
||||
|
||||
## 验证和安全
|
||||
|
||||
```sh
|
||||
python3 -m py_compile scripts/af_click_gap_pipeline.py
|
||||
python3 scripts/af_click_gap_pipeline.py --help
|
||||
plutil -lint launchd/com.roasbloom.af-click-gap.plist.template
|
||||
python3 -m json.tool data/index.json
|
||||
```
|
||||
|
||||
禁止提交数据库文件、`.env*`、密钥、日志、浏览器状态、缓存或临时文件;`.gitignore` 已覆盖这些类型。
|
||||
|
||||
Reference in New Issue
Block a user