docs(memory): 记录数据面板与图片压缩的实现、验证与踩坑
This commit is contained in:
@@ -145,3 +145,53 @@ gzip 实现质量高、后台移动端短标签方案做得细。
|
||||
- 无备份脚本(图片全在对象存储,只备份 DB 恢复后全是裂图)
|
||||
- 32 个 `<label>` 无 `for=`、语义标签对比度 1.9:1
|
||||
- 箱主数据面板(全站无 page view 数据)、Telegram/Webhook 通知、JSON-LD + RSS、图片前端压缩
|
||||
|
||||
## 箱主数据面板 + 图片前端压缩(本轮完成)
|
||||
|
||||
把「待办」里的两项落地,其余(AutoMigrate 版本化、备份脚本、label/对比度、Telegram/Webhook、JSON-LD)仍未做。
|
||||
|
||||
### 箱主数据面板(/user/insights)
|
||||
|
||||
- 新表 `box_views`(`internal/db/box_views.go`):一行 = 一访客×一天×一箱,唯一索引
|
||||
`(user_id, viewed_on, visitor)`,`views` 累加。**刻意不内嵌 `dbutil.Model`**——
|
||||
软删除 + 唯一索引会让被删行永久占槽(老坑)。
|
||||
- 访客标识 = `HMAC(日盐, IP)` 前 32 hex(`internal/insights/recorder.go`):同日可去重(UV 准)、
|
||||
跨日不可关联(隐私)。代价:近 7/30 天 UV = 各日 UV 之和,文案里已写明。
|
||||
- 异步记录器:buffered channel 512 + 2s flush,构造即启动 goroutine(避免 Close/Run 竞态),
|
||||
队列满即丢(统计尽力而为)。过滤:箱主本人、空 UA、爬虫 UA 子串、预取头(Sec-Purpose 等)。
|
||||
- 聚合层 `internal/db/box_analytics.go`:BoxTrend(提问/回答按日)、BoxHours(24h 分布)、
|
||||
BoxFunnel(已回答/已读未答/未读 + 回答率 + 24h 回复占比)。复用 analyticsDialectFor 的时区处理。
|
||||
- 展示层 `internal/insights/page.go`:30 天 PV/UV 双柱趋势(CSS 高度百分比)、时段分布、
|
||||
漏斗 + 回答率进度条、自动结论(`FormatInsights`)。**百分比整数值不带 .0**(formatPct)。
|
||||
- 打点:`route/question/page.go` 的 Pager 末尾(所有错误分支/密码页已 return 之后),
|
||||
`!ctx.IsLogged || ctx.User.ID != pageUser.ID` 才记。
|
||||
- 挂载:`/user/insights` 在 reqUserSignIn 组内;`pageScope` 加 `/user/insights → admin`。
|
||||
- 密钥复用 `server.xsrf_key`;`StartMaintenance` 每日清 400 天前的明细。
|
||||
- 测试:`internal/db/box_views_test.go`(4 项,含「同批同键先内存合并」——PG 的 ON CONFLICT
|
||||
不允许同条 INSERT 二次命中同一行)、`internal/insights/page_test.go`(pct/窗口切分/visitorID/爬虫过滤)。
|
||||
|
||||
### 图片前端压缩(templates/base/footer.html)
|
||||
|
||||
- 选图即压:canvas → WebP(长边 1600、质量 0.8,与服务端 GeneralEncodeSpec 对齐)。
|
||||
- 三条边界:GIF/SVG 跳过(canvas 会把 GIF 变静止首帧)、压完不更小退回原图(<85% 才采用)、
|
||||
透明 PNG 走 WebP(不支持 WebP 编码时退回 PNG 而非 JPEG,否则透明变黑)。
|
||||
- `createImageBitmap(..., {imageOrientation:'from-image'})` 摆正 EXIF,老浏览器回退不带选项。
|
||||
- submit capture 兜底:选图立刻提交时 `preventDefault` + `Promise.all(压缩)` + `form.submit()`,
|
||||
避免二次触发防重复。
|
||||
- 实测(CDP + 自写 WebSocket 客户端 `dev/_cdp.py`):4.6MB PNG → 11.7KB WebP(0.3%),
|
||||
小图原样保留、GIF 跳过,三断言全过。
|
||||
|
||||
### 踩坑(本轮新)
|
||||
|
||||
- **同步脚本把 WSL 的 `conf/app.ini` 删了**:Windows 侧用 `tar | wsl rsync --delete` 同步源码,
|
||||
目标机那份含 DB 密码/对象存储密钥的 app.ini 不在源目录里,被当多余文件删掉 → 服务重启起不来。
|
||||
修:`dev/sync-wsl.sh` 里 `rsync --exclude "conf/app.ini"`,模板放 `dev/wsl-app.ini`(已 gitignore)。
|
||||
- **配置丢了怎么找回**:进程内存 dump(`/proc/PID/mem` 扫描 `key = "value"` 模式)能捞出启动时
|
||||
加载的全部 ini 键值(salt/xsrf_key/上传密钥/DB DSN 都在),配回 `conf/app.ini` 即可。
|
||||
- **headless 里 canvas 编码大图超时是假象**:Windows Chrome 的 `--dump-dom` + `--virtual-time-budget`
|
||||
会把 3000×2000 噪声图压得解码超时,`#out` 永远停在 running。换 WSL 内 `apt install chromium`
|
||||
走 CDP 轮询(`Runtime.evaluate` 非 await 反复读结果)才拿到真值。
|
||||
- **自写 CDP 的 WebSocket 客户端必须处理 continuation 分片**:CDP 大事件(console/DOM 属性)会
|
||||
把一帧拆成多段,按「一帧=一消息」解析会让缓冲区永久错位,evaluate 永远等不到响应。修了 `_cdp.py`。
|
||||
- **awaitPromise 长轮询会挂死自写 WS 客户端**:验证异步结果改用「navigate + 非 await 轮询读 DOM」。
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
`honeypot` 蜜罐多家族伪装 / `stats` 全站数据页 / `sec` 安全评估·客户端 IP 信任 /
|
||||
`quality` 业务正确性·运维·前端(2026-10-29) / `misc` 其它约定。
|
||||
|
||||
新增(2026-10-29 数据面板批次):`insights` 箱主数据面板(box_views 表 + 异步记录器 +
|
||||
`/user/insights` 页面 + 图片前端压缩)—— 详见 topics 可暂并入 quality,或另起 topic。
|
||||
|
||||
## 协作
|
||||
|
||||
- 结论分级 P0/P1/P2;先根因取证 + 实测复现,别只静态推断。
|
||||
|
||||
Reference in New Issue
Block a user