CHANGELOG

更新记录

Utterlog 每次推送到 main 的改动都会自动构建镜像并发布版本。下面列出最近的 30 个发布。

v1.6.0
2026年8月9日

新增

  • 暂无。

优化

  • 暂无。

修复

  • AI 评论审核实际从未生效:审核排在「评论需要审核」这个总开关之后,而该开关默认关闭时会先把评论标记为已通过,导致审核条件永远不成立——站长打开「启用 AI 审核」、配好模型、测试通过,线上却一条都没有真正审过。现在审核与该开关解耦,只要启用就会执行。
  • AI 审核会误杀正常评论:模型只要没有严格按 {"passed": true, "confidence": 0.95} 的格式回复(例如省略置信度、用字符串 "true"、字段名写成 pass),一律被判定为不通过,而默认动作是直接标记为垃圾评论,访客那边却显示「已提交,审核通过后显示」。现在这些常见写法都能正确识别;置信度不足时按「未审核」处理而不是拒绝;解析不出结果时同样不再误判。
  • AI 调用失败无迹可循:模型超时、未配置服务商、返回空内容三种情况此前既不记录日志也不提示,站长会误以为审核在正常工作,实际每条评论都在静默跳过。现在这些失败都会记入 AI 日志与服务日志。
  • AI 回复可能发出空内容:队列里回复正文为空时,点「发布」会插入一条只有「AI 辅助回复」标记、没有正文的评论。现在为空时直接拒绝发布。
  • 后台 AI 统计看不到自动调用:统计只算管理员手动触发的那几类,而评论审核、自动回复、AI 陪读、语义搜索记录的调用者为空,全部被过滤掉——线上实测 16 条日志里有 12 条不可见,而它们恰恰是唯一无人值守、唯一会持续产生费用的调用。同时补上评论侧调用缺失的 Token 计数,此前这两类的 Token 消耗恒为 0。
  • 审核结论无处追溯:审核结果原本只写进 AI 回复队列,而队列只在同时启用「AI 智能回复」时才有记录,只开审核的站点判定结果完全不留痕,用户反馈评论发不出来时无法区分是关键词、频率还是 AI 拦的。现在每次审核都会单独记录判定结果与最终状态。
  • AI 回复限流在配置延迟时形同虚设:限流统计的是调用日志,而日志要等 AI 返回后才写入——配了延迟发布(最长 1 小时)时,窗口内涌入的评论全部通过检查;后台「重新生成」还与访客评论共享同一份配额。现在改为统计入队记录,入队即计数,后台操作不再挤占访客侧限额。
  • 并发提交可能生成两条 AI 回复:去重是先查询后插入、两步之间无锁,双击或客户端重试会给同一条评论各生成一次回复。现在由数据库唯一约束兜底。
  • 删除评论后 AI 回复队列残留孤儿记录:全新安装的数据库缺少外键,硬删评论后队列记录原地残留,点「发布」会插出一条回复对象已不存在的评论。升级时自动清理孤儿并补上级联删除。
  • 进程重启导致 AI 回复永久卡住:延迟等待挂在进程内存里,重启或部署会让该窗口内的回复永远停留在「待审核」且没有任何后续。现在启动时和每 10 分钟扫描一次,把确认中断的记录标记为错误并说明原因,可在后台一键重新生成。判定时间随配置的延迟自适应,不会把还在正常等待的记录误标。
  • 垃圾关键词误杀正常评论:英文词此前按子串匹配(sex 命中 Essex、adult 命中 adulthood),中文单字「药」把中药、药店等正常讨论全部拦截,且命中即定为垃圾、后续 AI 审核无从平反。英文改为按词边界匹配,中文换成明确的垃圾短语。
  • 被自动过滤拦下的访客看到误导性提示:评论被判为垃圾时前台仍显示「审核通过后将显示」,被误杀的用户会一直等一条永远不会出现的评论。现在如实提示未通过自动过滤,并给出联系站长的途径。
  • 自动回复会覆盖管理员的拒绝:延迟发布期间管理员若已拒绝该条回复,延迟结束后仍会照常发出,并把状态改回已通过。现在发布前会重新确认状态。

移除

  • 下线段落点评:读者对文章单个段落做批注的功能整体移除,包括前台弹窗、后台「段落点评」管理页与相关接口。升级时会删除 ul_annotations 表;如果站点用过这个功能且想留存数据,升级前请先备份:

```bash

set -a && . ./.env && set +a

PGPASSWORD="$DB_PASSWORD" pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \

-t "${DB_PREFIX}annotations" > annotations-backup.sql

```

v1.5.1
2026年7月30日

新增

  • 暂无。

优化

  • 通知邮件的视觉统一为直角、去掉符号图标:状态标记原先是方块里放对号、省略号、垃圾桶等符号,各家邮件客户端的字形和基线差异很大,垃圾桶在部分 Windows 客户端还会渲染成彩色图案;现在一律改为「已通过」「待审核」这样的中文字样。头像此前在回复通知里是圆形、新评论通知里是方形,连同卡片、按钮、徽章一起统一为直角。按钮也收敛成同一套规格——此前正文按钮与审核按钮的内边距、字重各写各的,四个按钮排在一起宽窄不齐,描边的那个还会比实心的高出一点。
  • 后台回复评论会说明通知结果:回复成功后的提示里一并说明邮件通知的去向——发出去了显示通知给了谁,没发则说明原因(对方没留邮箱、已退订、被回复的是管理员自己,或发信失败的具体报错)。此前无论发没发都只显示「回复成功」。

修复

  • 前台回复评论不发通知:文章页下的回复此前完全没有邮件提醒——无论访客之间互相回复,还是博主在文章页下直接回复,被回复的人都收不到任何消息,只有后台评论管理页的「回复」按钮才会发信。现在两条路径一致:任何人回复一条留了邮箱的评论,对方都会收到通知(自己回复自己、对方已退订、被回复的是博主本人时除外,博主另有新评论提醒)。待审核的评论不发,避免把未公开的内容提前漏出去。
  • 已通过的评论仍显示「通过」按钮:新评论通知里的一键审核按钮只看链接是否存在,不看评论当前状态,于是自动通过的评论也会带一个点了没有任何作用的「通过」按钮。现在按状态给:已通过只留「标记垃圾」,已是垃圾只留「通过」用于恢复,待审核两个都给,回收站里的不给审核入口。
  • 全站浏览量把鼠标悬停也算成了一次访问:前台链接会在鼠标划过时预取目标页面,而预取会执行页面的取数逻辑,恰好也是浏览量累加的地方——在首页扫一眼文章列表,一篇没点也能记下十几次浏览。现在预取不再计数,只有真正打开页面(含刷新)才算,与文章阅读量口径一致。已经累计的历史数字保持不变。
  • 回复通知的发信失败被静默丢弃:管理员在后台或 Telegram 回复评论时,通知邮件一旦发送失败就被直接忽略,既不提示也不记录,事后无法判断对方是否收到。现在失败会写入服务日志,后台还会直接显示原因。

移除

  • 暂无。
v1.5.0
2026年7月26日

新增

  • PostgreSQL 版本可选:安装器新增 PG_MAJOR 环境变量,可指定本机自动安装的 PostgreSQL 主版本。
  • 站点图标自动生成整套 PNG 与 PWA manifest:后台上传 Favicon 时,除原有的多尺寸 .ico 外,另按各客户端约定生成 favicon-16x16、favicon-32x32、apple-touch-icon(iOS 添加到主屏)、android-chrome-192x192、android-chrome-512x512,全部由同一张原图渲染,一次上传全部更新。同时提供 /site.webmanifest(亦响应 /manifest.json),站点名、描述、主题色随后台设置变化,图标列表只列磁盘上真实存在的文件。
  • 评论通知邮件支持一键审核:新评论通知里新增「通过」「标记垃圾」两个按钮,点开是确认页,确认后才生效。链接带签名,评论 ID、动作、有效期一并签入,改任一参数即失效,有效期 7 天。之所以不做成点开即生效:邮件网关会自动预取链接做安全扫描,那样垃圾评论会在站长看到邮件前就被扫描器自动通过。
  • 评论标注友链好友:评论者填的网址命中友链库时,昵称后显示一枚方形标记,悬停显示对方站名。域名比对忽略协议、www、端口和路径,友链填子域、评论填主域也认得出;github.io、vercel.app 这类托管平台下的不同子域不会互相误认。
  • 从历史评论匹配友链邮箱:友链页新增「从评论匹配邮箱」,按域名把评论者留下的邮箱聚合到对应友链,列出出处与条数供逐条确认后保存,不自动写入。同一域名出现多个邮箱时会标出以便人工判断。
  • 友链站点图标本地缓存:「刷新 ico」由刷新浏览器缓存改为真正抓取——解析对方页面的图标声明,回退到 /favicon.ico,转成 64 像素 WebP 存在本站。友链与订阅页的头像依次取手填图标、邮箱对应的 Gravatar、本地缓存图标,都没有时才回落到外部 favicon 服务。
  • 顶部导航进度条:点击站内链接后,视口最上沿显示一条跟随主题色的细进度条,走满后淡出,补上此前站内切换毫无反馈的空档。150 毫秒内完成的导航不显示,避免一闪而过;五个主题共用同一实现,不需要各自改导航栏。

优化

  • 默认数据库升级到 PostgreSQL 19:一行安装、scripts/deploy.sh 与 CI 默认改装 PostgreSQL 19 + pgvector;19 的服务端包只在 PGDG 的 -pgdg-testing 套件里,脚本会按需自动启用并按主版本号限定组件,不影响其它 PGDG 包。19 目前仍是 beta,官方不建议用于生产,装机时用 PG_MAJOR=18 即可退回上一个正式版。
  • 依赖瘦身:移除 4 个未被引用的依赖,并删除若干无引用的静态资源与一次性维护脚本。
  • 全站浏览量统一口径:后台概览与 Telegram /stats 改用同一个统计函数,不再一处按访问日志、另一处按文章阅读量求和,同名指标在两处显示同一个数字。
  • 全站浏览量改为按页面加载计数:页脚的总浏览量改由服务端在渲染公开页时累加,与文章阅读量同一口径——打开算一次、刷新算一次,不再做时间窗口去重与频率限制,也不再依赖浏览器脚本,此前关闭脚本或被拦截插件挡下的访问会整个漏计。独立访客数仍按浏览器标识去重,访客明细的去重与限流保持不变。
  • 首屏体积减小三分之一:页面数据不再重复携带整份站点上下文。此前根路由与页面路由各返回一份,菜单、分类、标签、归档统计(含整年热力图)、站点设置会被完整序列化两遍;文章页由此从 101.6 KB 降到 65.9 KB,其中内嵌数据脚本从 79.3 KB 降到 42.6 KB。压缩后传输差异有限,省下的主要是浏览器解析和建对象的开销。

修复

  • 评论接口向匿名访客返回了邮箱与 IP(建议尽快升级):公开的评论列表接口把评论表整行下发,其中包含每条评论的邮箱、IP、客户端标识,无需登录即可读取。现按登录状态分流,匿名访客拿不到这些字段;头像仍正常显示,因为 Gravatar 地址由服务端算好后下发,不需要暴露邮箱。友链的邮箱字段同样收口,只对后台可见。
  • 订阅页显示的文章数与实际不符:页面统计的是订阅库里的全部条目,而不少站点的 RSS 输出的是全站历史文章,导致显示上千篇、实际近期更新只有一百来篇。现在时间线与计数统一只看最近 30 天内发布的文章,并按发布时间而非抓取时间过滤。
  • 文章阅读量口径统一为页面加载量:阅读量在文章详情页读取时同步 +1,页面上的数字就是这次访问之后的值;点进来算一次、刷新一次算一次,不再做时间窗口去重(只挡爬虫 UA)。累计数与按天明细由同一次判定写入,两个数字必然对得上;浏览器 /track 不再碰任何文章维度统计,只负责访客明细和全站访问量。
  • 文章详情页被公共缓存冻结:文章页不再下发共享缓存头,是否属于文章详情按站点当前的固定链接结构判断,不再写死 /archives/ 前缀;分类、标签、归档等页面的缓存保持不变。
  • 后台首屏体积下降:侧边栏 33 个动效图标改用 CSS 动画,移除了整个动画库依赖,布局代码块从 194 KB 降到 68 KB。此前该库随侧边栏进入首屏必经路径,连登录页也会一并下载。其中 7 个图标的描边生长效果受 CSS 能力限制,降级为缩放或旋转。
  • 后台页面切换更快:侧边栏链接改为悬停即预取目标页面的代码与数据,此前要等点击后才开始下载。单个页面的代码只有几 KB,但一次网络往返在跨境访问时要半秒以上,这半秒原本每次切换都要等。预取结果缓存 30 秒,来回切换不重复请求。
  • 后台表格操作按钮统一:列表行里的编辑、删除、通过、精选等操作收敛为同一个组件,按语义分五档配色(中性 / 危险 / 成功 / 警示 / 次要),平时保持中性、悬停时才显示语义色,避免整行按钮各自彩色喧宾夺主;已激活的状态(如已精选、已隐藏)常驻显色。此前 60 余处按钮各自手写颜色,同一种操作在不同页面深浅不一。
  • 后台浮层阴影减轻:对话框、下拉菜单、通知面板等浮层此前使用框架默认的重阴影(最大 20 像素扩散),现统一收敛为两档规范阴影。
  • 后台卡片去掉阴影:卡片此前边框与阴影同时存在,现只保留 1 像素描边。后台整体维持直角视觉,头像、开关、状态圆点、侧边栏折叠按钮等正圆元素不受影响。
  • 第三方服务凭据支持一键测试:Mapbox、GitHub、Google 地图、高德、腾讯地图、TinyPNG 六项凭据各自新增「测试连接」按钮,会真实调用对方的官方接口校验,而非只检查格式——密钥被吊销、配额用尽、限制来源等情况只有实际请求才能发现。失败时给出可直接排查的原因(如未启用对应 API、被限流、网络不通),成功时附带额度信息。输入框留空则测试已保存的配置。GitHub 与 TinyPNG 会在打开页面时自动显示剩余额度——这两家把用量放在响应头里;其余几家的配额只在各自控制台,接口不返回。同时移除了 Mapbox API 地址设置项,四处消费点均已内置默认地址。
  • 后台图标按钮尺寸统一:方形图标按钮新增 32 像素与 28 像素两档,表格行与密集列表不必再各自覆盖默认的 40 像素;站内 66 处手写覆盖已收进组件。同时移除仅做名称映射、不提供额外能力的按钮兼容层,全站只保留一个按钮实现。
  • 后台设置页标签栏没有选中态:设置页与 AI 设置页的标签栏,当前所在的标签与其它标签看起来完全一样。原因是选中态样式挂在 data-selected 上,而组件库实际输出的是 aria-selected,样式一直没有生效。现在选中标签为主色文字加下边框,标签栏在窄屏改为横向滚动,不再换行挤压表单。
  • 老库缺列导致统计整体停摆:补上 access_logs 的访客标识等字段迁移,并把文章日维度统计拆成独立事务,单张统计表出问题不再连带访客明细和全站访问量一起回滚。
  • 首屏封面图闪一下模糊:图片效果的相关属性改为随首屏 HTML 一起下发,不再等前端脚本补写。此前 html[data-img-effect] 由客户端脚本在 hydration 后才写入,淡入规则晚一步生效,慢网络下首屏封面会出现「图已显示 → 突然模糊 → 再清晰」。
  • 部分主题的封面图没有淡入:Renascent 的文章封面、Utterlog 的上/下篇缩略图与相关文章卡片,主题样式里各自声明的 transition: transform 特异性高于全局淡入规则,简写又把 filter、opacity 的过渡一并覆盖,导致模糊到清晰是瞬间跳变。这几处的悬停缩放统一交给全局 .cover-zoom。
  • 封面图不再显示加载圆圈:文章卡片封面、上/下篇缩略图和相关文章缩略图去掉了转圈指示器,只保留淡入。转圈表达的是「还没加载好」,而封面几乎总是命中缓存,圆圈在那种情况下只是噪音;且它的隐藏依赖前端脚本改写加载标记,页面脚本稍慢,圆圈就会盖在已经画好的图上,调延迟也堵不住。图片未就绪时由容器的浅灰底色占位。
  • 相关文章缩略图无视动画时长设置:三处组件的行内过渡时长由硬编码 0.5s 改为读取 --img-effect-duration,后台「图片处理 → 动画时长」对这些图同样生效。
  • 评论回复通知的文案分行:原本「你好 XX,YY 回复了你在《文章标题》的评论」挤成一句,标题一长就折成三行,要读到最后才知道发生了什么。现在称呼与主句合并为一行,文章标题降为下方的附属信息单独成行。
  • 通知邮件恢复排版模板:验证码、密码重置、评论回复、新评论通知、测试邮件此前都退化成没有样式的纯文本片段,现已恢复统一外壳——站点标识、卡片式排版、操作按钮、页脚,评论回复邮件保留退订入口。评论相关的通知补上了头像、评论时间与状态标记,站点 Logo 填相对路径时会自动补成绝对地址(邮件客户端无法解析相对路径)。用户填写的内容一律转义,评论正文无法注入 HTML。

移除

  • 下线安全中心(不可逆,升级前请先备份):后台「安全」页及其全部功能移除——IP 封禁、安全事件时间线、CC 防护、GeoIP 地域封锁、全站 API 速率限制与 require_login 全站登录墙。请求链上的安全中间件一并摘除,/api/v1/security/* 接口不再存在。

升级会删除 ul_ip_bans、ul_security_events、ul_ip_reputation 三张表(第三张自上线以来就无代码引用)。应用一启动即执行,无法回滚,需要留档请在升级前导出:

```bash

set -a && . ./.env && set +a

PGPASSWORD="$DB_PASSWORD" pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \

-t "${DB_PREFIX}ip_bans" -t "${DB_PREFIX}security_events" -t "${DB_PREFIX}ip_reputation" \

> security-tables-backup.sql

```

受影响的防护能力请在反向代理层补齐,Nginx 用 limit_req、Caddy 用 rate_limit,登录接口尤其需要——原先 /auth/login 有 10 次/分钟的暴力破解限制。GeoIP 数据源选择(访客统计、评论归属地、足迹等仍在使用)已迁到「设置 → 第三方服务」,原有取值不变。

v1.4.0
2026年7月23日

新增

  • Bun 主机部署:新增 systemd 应用服务、后台更新监听单元和统一的 Bun 更新脚本。

优化

  • 部署链路统一:安装、更新、Makefile、远程同步、CI、发布构建和文档统一使用 Bun 1.4;默认监听端口统一为 9260。
  • 后台一键升级:改为请求受限的 systemd 更新任务,依次拉取源码、校验构建、重启服务并执行健康检查。
  • 统一统计入口:文章阅读量改为仅在客户端访问通过统计校验后递增,Umami 可通过 utterlog:pageview-tracked 事件复用同一可信访问结果。
  • 后台通知轮询:隐藏标签页暂停请求,重新可见后立即同步通知数量,减少长期打开后台产生的无效请求。
  • 公开内容页缓存:文章、分类、标签、归档等对所有访客一致的页面允许 CDN 短期缓存,减少重复回源;首页与分页含访客个性化内容,仍不缓存。
  • 图标库升级:FontAwesome 升级至 7.3.1。

修复

  • 伪装浏览器爬虫刷量:恢复迁移时遗漏的 30 秒同页去重和行为限速;同一访客 60 秒内达到 8 次访问后暂停统计一小时,并对同 IP 轮换身份增加独立保护。
  • 后台登录过期错误:过期访问令牌改为返回 401,并对并发请求合并刷新,修复仪表盘与通知接口持续 500、重复刷新和无法回到登录页的问题。
  • 后台路由预加载异常:关闭后台意图预加载,规避懒加载路由切换时读取 _nonReactive 的竞态错误。
  • 首页标题缺少副标题:首页浏览器标签只显示站点名称,现恢复为「站点名称 - 副标题」;其他页面标题格式不变。

移除

  • 移除旧应用打包、编排、镜像发布与镜像同步文件,生产运行方式收敛为 Bun + systemd。
v1.3.8
2026年7月23日

新增

  • TanStack Start 全栈架构:完成前台、后台、服务端 API、认证、安全中间件和静态资源路由迁移,统一由 TanStack Start + React 19 + Bun 提供服务。
  • AI 配置能力:支持手动输入模型名称、兼容自定义服务地址、更新文章与聊天提示词,并增加文章 AI 伴读开关。

优化

  • 后台加载性能:减少仪表盘往返请求、选项重复加载和非必要轮询,地图等重资源改为按需加载。
  • 品牌图片处理:Logo、深色 Logo 与 Favicon 上传后自动压缩并转换为现代图片格式。
  • Codex 前端开发规范:补充颜色、字号、间距、组件与图标等设计约束,统一后续界面修改标准。

修复

  • 腾讯 EdgeOne 访客地址:正确读取真实客户端 IP,修复天气和页脚访客位置显示 CDN 或服务器地址的问题。
  • 后台与资源路由:修复后台入口、品牌资源、Favicon、主题样式和历史图片资源的路由及缓存问题。
  • Azure 移动端页脚:总浏览量与在线人数改为同一行,版权、访客信息、备案号和快捷按钮统一居中。

移除

  • 移除 Hono 网关兼容层及已完成迁移的旧服务路径,运行时统一使用 TanStack Start。
v1.3.7
2026年6月24日

新增

  • Bun 单进程运行时:以 Bun + Hono 替代 Go API,合并网关、管理后台与博客 SSR。
  • Azure 中国红配色:删除独立 Chred 主题,改为 Azure data-accent=red。
  • 路由模块化:拆分 telegram / security / footprints / extensions 等路由模块。

优化

  • 部署拓扑:默认仅需 app + postgres,移除 Redis 运行时依赖。
  • 组织 Profile README:更新为 Bun 技术栈说明。

修复

  • compat 路由:修复提取脚本损坏的 WXR / RSS 辅助函数。

移除

  • 删除 api/ Go 后端与 Chred 独立主题目录。