这一版没有新功能,只还欠账。2026 年 11 月 9 日给全站做全量审计,第二遍专查暗病,重点对一类问题:写在文档里的承诺,代码到底有没有照做。第一条就对出了回收站——README 白纸黑字写着媒体回收站保留 30 天,代码里却根本没给这个期限留位置。这篇是修复记录。

项目地址:ym-blog 仓库

问题:删进回收站的图片,当晚就真没了

原来:在媒体库里删掉一张图,它先进回收站,看起来和别家产品一个流程——先躺着,后悔了能还原。但本站有个每天凌晨自动跑的清理任务,它判断「要不要真删」时只看一条:这条媒体是不是回收站状态。是,就删,完全不看它是哪天删进去的。

换句话说,这个回收站只是一个「当晚生效」的删除确认框:上午手滑删错,中午想起来还能救回来;睡一觉,第二天凌晨三点多,它已经被清得干干净净,连文件带记录一起没了。而 README 里对部署本站的人承诺的是「回收站保留 30 天」——承诺和实现,两张皮。

为什么一直没发现:删除、还原这两个动作本身都是好的,平时测试也只测到这一层。「保留多少天」这种约定藏在定时任务的判断条件里,不把文档和代码摆在一起逐条对,谁也想不起来去查。这正是这次专门安排一遍「对承诺」检查的原因。

修法:给「删掉」这个动作落一个时间戳

  • 数据库给媒体表加了一列删除时间(trashed_at),配套加了索引。这是一次正经的表结构迁移(编号 0004),已有数据不受影响。
  • 移入回收站时写入当前时间,还原时清空——还原过的图日后再删,重新起算,不会拿着上一次的时间被误删。
  • 清理任务的口径改成:处于回收站状态、且删除时间超过 30 天,才真正删文件和记录。其余清理口径(比如没上传完的半成品媒体)原样未动。
  • 回收站里原先躺着的 8 条媒体没有删除时间记录,这次统一按修复上线的时间回填起算——按新规矩它们能完整躺满 30 天,不会因为「没时间戳」在当晚被当成过期货清掉。

顺手修的两件小事

同一遍检查里还对出两处「配置早就写了、代码却没接上」:

  • 登录限流没按配置档位生效:限流配置里早就定义好了按来源 IP 的登录上限——普通档每小时 20 次、严格档每小时 10 次——但登录入口实际上没读这份配置,走的是另一套写死的口径。这次把登录入口接到配置上,以后调档位改一处就行;恢复码入口也接进同一个限流口径,连续输错一样会触发上限,不再是绕开限流的口子。
  • 搜索接口没用上全文检索:v1.1.0 给页面搜索换上了中文全文检索(FTS5 + trigram 分词),但给程序调用的搜索接口 /api/search 还停在老式的逐篇子串匹配,搜正文深处的一个词组捞不出来。这次让接口和页面走同一条检索通道,老匹配保留作兜底,两边一个口径。

验证情况

老规矩,改完不算数、测过才算:

  • 自动化自检从 149 项扩到 166 项,全部通过;新增的十几项专测回收站:刚删的不删、把时间回拨 31 天的真删、还原后时间戳清零、存量回填,一项一项验过。
  • 上线后拿一条测试媒体在生产环境完整走了一遍:上传 → 删除进回收站 → 查数据库确认时间戳落对了 → 还原,时间戳随之清空,全程无异常;站里原有的 96 条真实媒体一条没动。
  • 清理任务本身要等今晚凌晨才第一次按新口径跑:白天先用一模一样的条件在生产数据库里干跑了一遍,回收站里的媒体全部未到期,选中 0 条,确认不会误删。
  • 搜索接口上线后实测:搜一个只出现在正文里的词,命中 8 条,和页面搜索的结果一致。

小结

这一版的版本号只动了最后一位,但我觉得它比加新功能更值得记一篇:新功能是锦上添花,承诺对不上是地基问题。文档里写下的每一句「保留 30 天」「每小时限 20 次」,都应该能在代码里找到对应的那一行;找不到,就是欠账。这次的三笔账已经还清,改动同步写进了 ym-blog 仓库 的版本历史(v1.1.2),欢迎对照。