Files
tamabox/.workbuddy/memory/2026-10-29.md
T
tamakyi d4e6da76f1 docs(memory): 记录第二轮复查结论与六项修复的验证方式
- 新增 topics/quality.md:业务正确性 / 运维 / 前端体验四类结论,含
  「私聊取最早 50 条」「Classic() 的 Logger 记 RequestURI」这两个坑的成因,
  以及处置覆盖面、Redis 两种故障模式、产品缺口(无 page view / 提问者找不回自己的提问)
- 2026-10-29.md:本轮六项修复的改动与验证结果,另记两个实现坑
  (limit 兜底不该抬大用户配置;Python bytes 字面量不支持 \uXXXX)
- topics/sec.md / 2026-10-27.md:补上一轮遗漏的字体自动发现与 CSP enforce 结论
- MEMORY.md:索引加 quality,处置覆盖面一条标注投票链路已补齐
2026-10-29 15:53:57 +08:00

67 lines
4.8 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.
# 2026-10-29
## 第二轮综合复查(非安全向)
用户要求「再确认还存在什么问题与风险点」+「从用户角度有什么值得改进和增加的功能」。
前一轮是安全专项(P1/P2/P3 全修完),这轮换到**业务正确性 / 运维 / 前端体验 / 产品能力**四个面。
产出:`outputs/review-2026-10-29.md`(分级清单 + 复现方式 + 产品建议)。
### 实测复现的两条 P0
1. **私聊 50 条截断**:`GetByConversationID` 是 `Order("created_at ASC") + Limit(50)`,
唯一调用方永远传 nil cursor;会话上限 200 → 第 51 条起**写库成功但永久不可见**。
本地造 55 条实测:页面只渲染 #1–#50。这不是性能问题,是「数据在库里但用户看不到」。
2. **访问日志泄露 token**:`flamego.Classic()` = `Use(Logger(), Recovery(), Static())`,
Logger 记 `RequestURI`(含 query)。实测日志出现 `path=/_/tblocal/4?t=SECRETTOKEN123`。
`?t=` 是私密题钥匙、`?code=` 是改密凭证。**tracing 中间件早就为同一风险避开了 RequestURI
并写了注释,框架默认 Logger 漏了。**
### 代码确认的 P1
- **无优雅关闭**:全仓 `signal.Notify`/`Shutdown` 零命中,SIGTERM 直接杀进程 → 每次重启掐断在途 POST。
- **提问入库后图片失败不回滚**(`page.go:660` → `:680`),叠加 DuplicateGuard 5 分钟 → 用户以为没发出、5 分钟内不能重提。
- **Redis 两种故障**:session 在 Redis 上宕机即全站 500(flamego session load 直接 panic);
`cache.Cacher` **没有** `if conf.Redis.Addr != ""`,空 Addr 被 go-redis 回退到 localhost:6379 → 没配 Redis 时找回密码静默坏掉。
- **处置不覆盖投票**:提问链路 7 处 `ActiveLevel`,投票链路 0 处。L4 处置后 `/_/domain` 已 302 到 /restricted,
但 `/vote/{token}` 照常可投、可发新投票、探索页照常曝光。
### 产品缺口(重要,别忘)
- **完全没有访问量数据**:`SiteAnalytics` 是全站聚合,无 per-user 维度,也没有 page view 表。
箱主无法知道自己被看了多少次。
- **提问者找不回自己的提问**:不填邮箱时唯一手段是成功页那条链接,关页即失联;全仓 `localStorage` 零命中。
→ 建议前端用 localStorage 记 `{domain, id, token}`,箱主页显示「你有 N 条提问已被回答」。
- `NotifyType` 只有 `email` / `none`,无 Telegram / Webhook。
- 模板零 `application/ld+json`(SEO 富摘要缺失),无 RSS。
- 图片原图直传(无前端压缩),配合 ReadTimeout 30s → 手机端 8MB 图必超时。
### 顺带确认的「不用动」
四语言字典 917 条完全对齐(`TestDictionaryComplete` PASS)、深色模式正文对比度 4.8–6.8:1 达标、
gzip 实现质量高、后台移动端短标签方案做得细。
### 已修(同日,六项全部端到端验证)
| # | 改动 | 验证 |
|---|---|---|
| 1 | `GetByConversationID` 改 `id DESC` 取最新 + 内存反转,limit 取 `conf.Limits.ChatMaxMessages`;游标配 DESC | 55 条会话实测渲染 55 条(改前 50);单测 3 项 + 变异(改回 ASC 变红) |
| 2 | 弃 `flamego.Classic()`,`flamego.New()` + 自写 `accessLogMiddleware`(只记 `URL.Path`;静态成功不记、4xx/5xx 记) | 日志 `msg=access path=/_/tblocal/4`,token 计数 0 |
| 3 | `signal.NotifyContext` + `srv.Shutdown(15s)` + 关连接池 | 8 个并发分享图请求中 SIGTERM → 8/8 成功 |
| 4 | 图片失败分支 `Questions.DeleteByID` 回滚 | 6MB 图 → 提问增量 0 且 `deleted_at` 非空;无图对照增量 1 |
| 5 | `cache.Cacher` 加 `if conf.Redis.Addr != ""`(否则 MemoryIniter);启动 `PingRedis` fail-fast | 停 Redis 后启动立即失败并指向 Redis |
| 6 | 投票 Page/Submit 加 L4、VotePublish 加 L2、探索页用 `ActiveLevels` 批量过滤 | L4 → `/vote` 302 到 /restricted;探索页该投票 0→2(撤销后);L2 下发布停 draft,撤销后 published |
新增 `vote.err.restrictedPublish` 四语言 key。回归:4/4、19/19、6/6、3/3,全量单测 + `go build ./...` 通过。
**踩到的两个坑**(值得记):
- 消息加载的兜底写成 `limit < 50 → 50`,会把箱主显式配置的小上限抬大,测试直接测出这个语义错误。
兜底只该处理**零值**(未初始化),不该替用户改配置。
- Python 的 **bytes 字面量不支持 `\uXXXX`**(只有 str 支持),写字面量 `b'...\uff08'` 会原样写入
`\uff08` 六个字符。CRLF 文件的字节级替换要用 `\xef\xbc\x88` 或 `.encode()`。
### 待办
六项改动仍未 commit;P2/P3 清单在 `outputs/review-2026-10-29.md` 第四、五节。
建议下一批:投票结果聚合 O(N²)、三处幂等缺陷、ReadTimeout 30s 与 8MB 上传冲突、Dockerfile 构建不出来。