493 Commits

Author SHA1 Message Date
ryan f960511cc0 chore(release): v3.5.3
### 新增
- 访问日志「日志明细」支持按 HTTP 状态码筛选,可直接输入任意状态码。
- 访问日志「日志明细」支持自定义时间范围筛选,可按起止时间检索日志。
- 首页看板改版:24 小时请求趋势拆分展示请求总量与 2xx/4xx/5xx 状态码类请求量并独占一行;移除宿主机磁盘指标,24 小时容量趋势(CPU/内存)并入业务流量卡片展示。

### 🛠 修复
- 修复首页「来源分布」卡片在 PostgreSQL/SQLite 日志库下无数据的问题。
- 修复源站错误页「仅针对 GET 请求」未真正透传非 GET 响应的问题:POST/PUT 等非 GET 请求现可完整看到源站原始报错内容。
2026-08-13 11:44:08 +08:00
ryan 465440fa5b fix(access-logs): 修复状态码自定义 2026-08-13 11:33:12 +08:00
ryan a4dd5ca9e1 feat(dashboard): 首页请求趋势拆分状态码并合并容量到业务流量
- 24 小时请求趋势拆分展示请求总量与 200/400/500 状态码请求量,独占一行;
  时间桶聚合新增 status_200/400/500_count(CH countIf、PG FILTER),
  请求趋势改为基于原始桶聚合(小时 rollup 无状态码口径)
- 首页移除宿主机磁盘指标,容量趋势(CPU/内存)并入业务流量卡片展示
- 压缩协议 traffic_24h 扩展为 7 元组,前端归一化同步更新
2026-08-13 11:10:37 +08:00
ryan a9e4237bbf feat(access-logs): 状态码支持手动输入,新增时间范围筛选
- 状态码筛选支持预设快捷选项 + 手动输入任意 100-599 状态码(数字校验)
- 新增时间范围筛选:shadcn 日期+时间选择器(Popover+Calendar+时分 Select),
  起止时间以 RFC3339 成对传入,后端校验格式与先后关系,非法值返回 400
- 默认显示来源 IP/访问域名/状态码,节点 ID/请求路径/时间范围折叠进「更多筛选」
2026-08-13 10:27:40 +08:00
ryan 75d1fcf345 feat(access-logs): 日志明细支持按状态码筛选并折叠次要搜索项,修复首页来源分布无数据
- 修复 PostgreSQL/SQLite 日志库下首页「来源分布」卡片无数据:RegionCounts 对空
  节点 ID 误拼 node_id = '' 恒空条件,改为空节点 ID 表示全节点聚合(对齐 CH 语义),
  并过滤空白归属地
- /access-logs?tab=list 新增状态码筛选:状态码下拉含常用 2xx/3xx/4xx/5xx 选项,
  校验 100-599,非法值返回 400;ClickHouse 与 PostgreSQL/SQLite 日志库均支持
- 搜索框折叠:默认仅显示来源 IP 与状态码,节点 ID/访问域名/请求路径折叠进
  「更多筛选」
2026-08-13 09:59:32 +08:00
ryan f1577bf092 fix(openresty): 修复源站错误页「仅针对 GET 请求」覆盖非 GET 原始报错数据
proxy_intercept_errors 会在 Lua 判断前丢弃源站错误响应体,POST/PUT 等
请求收到 503 时被 OpenResty 自带错误页覆盖原始报错数据。现改为在代理
location 内用 Lua header/body 过滤器仅对 GET 请求替换错误页,非 GET
请求完整透传源站原始状态码与响应体;非仅 GET 模式继续使用命名 location
承载错误页。
2026-08-09 19:38:44 +08:00
ryan 3d4d99081e fix(log): PG 日志库批量写入为零 ID 行生成雪花 ID
PostgreSQL 日志表 id 为 NOT NULL 且无默认值,而 GORM 将零值 uint64
主键视为自增并省略 id 列,导致 node access log / 可观测指标等批量
落库持续报 "null value in column id violates not-null constraint"。
在 BatchInsert* 落库前为零 ID 行生成雪花 ID(与 ClickHouse 写入路径
一致),并新增单元回归与 PG 集成回归测试覆盖六张日志表。
2026-08-09 13:47:13 +08:00
ryan 0639855653 fix(openresty): 修复源站错误页「仅针对 GET 请求」未生效
error_page 的 URI 内部重定向会把请求方法改写成 GET,导致内部
Lua 中 ngx.req.get_method() 恒为 GET,get_only 判断永不命中,
POST/PUT 等请求仍返回自定义错误页。

改为命名 location(@__openflare_origin_error)承载错误页:
命名 location 保留原始请求方法与原始错误状态码,非 GET 请求
直接以原状态码退出、不再注入自定义 HTML。附带回归断言,禁止
回退到 URI 内部重定向形式。
2026-08-09 13:42:38 +08:00
ryan 0524ae1da4 chore(release): v3.5.1
### ✨ 新功能
- 日志存储解耦:ClickHouse 变为可选项,不启用时由 PostgreSQL/SQLite 承担全部日志功能;新增「切换日志数据库」任务支持 PostgreSQL/SQLite 与 ClickHouse 间数据迁移(迁移期间冻结日志写入,成功后自动切换主库并保留源数据);`log_database` / `log_db_migration` 设为受保护配置;ClickHouse 改为默认关闭。
- 新增 PostgreSQL/SQLite 日志存储实现:节点访问日志按月分区,统计查询合并为单次扫描、IP 汇总归属地取查询窗口内最新记录、WAF 按 IP 聚合减少扫描次数,并新增 `logged_at` 前导索引与主机名小写表达式索引;过期清理直接删除完全过期的整月分区,启动时兜底预建当月及未来 2 个月分区。
- 性能指标与访问日志的保留时长解耦:新增三库共用的 `metric_retention_days` 配置(默认 3 天),每日垃圾清理按独立短留存清理指标快照。

### 🛠 修复
- 修复 UptimeKuma 同步调试日志泄露凭据:Socket.IO 事件日志不再打印 payload 内容(仅记录长度),避免凭据进入日志。
- 修复日志保留天数配置继承旧键导致的误删风险:`log_retention_days_*` 不再继承 `database_auto_cleanup_retention_days`,统一默认 30 天。

### ⚡️ 优化与改进
- 系统定期垃圾清理由每 2 小时改为每日执行一次(凌晨 3 点,Asia/Shanghai),降低非必要高频扫描。

### 💄 其他/体验
- 服务工作者(SW)注入挑战页改为前台无感知:不再显示「加载中…」文案,页面空白,仅通过浏览器控制台输出 `[sw-challenge]` 调试信息,注入过程不打扰访客。
- 用户访问日志(`w_user_access_logs`)记录禁用:不再采集与写入新的用户访问日志,存量数据与管理端访问日志统计页面保留。
2026-08-09 11:39:28 +08:00
ryan adee4f7b27 docs: update 2026-08-09 11:22:35 +08:00
ryan 1d0f2d6342 fix(log): hard-set log retention days default to 30, drop legacy inheritance
log_retention_days_* 迁移不再继承旧键 database_auto_cleanup_retention_days
的值,统一默认 30 天。此前若旧键残留异常小值(如 2 天)会被静默带入,
导致升级后首次垃圾清理把大部分日志直接删掉。PG/SQLite 双方言同步修改,
文档默认值 90 -> 30。
2026-08-09 10:48:45 +08:00
ryan e3f603f72a fix(security): stop logging UptimeKuma socket payload content 2026-08-09 10:42:21 +08:00
ryan 3b010bb15e feat(log): disable user access log recording
- 移除全局用户访问日志采集中间件与批写入 writer(risk_control 包整包删除),
  不再写入 w_user_access_logs;存量数据与管理端访问日志统计页面保留
- 日志库迁移任务不再排空用户访问日志队列,状态接口不再展示其缓冲队列统计
- 迁移测试的系统配置 seed 计数断言更新为当前实际值(86 → 95),
  注释改为提示新增配置 seed 时同步更新
2026-08-09 10:35:39 +08:00
ryan f530cd4025 perf(log): optimize PG log store queries and expired partition cleanup
- Count/节点访问日志统计改为单次扫描聚合,WAF 按 IP 聚合由三次扫描合并为两次
- IPSummaries 归属地改为取过滤窗口内最新记录(对齐 ClickHouse argMax 口径),
  子查询带窗口条件,可分区裁剪并命中索引
- 新增 goose 迁移:of_node_access_logs (logged_at DESC, id DESC) 前导索引与
  lower(trim(host)) 表达式索引,加速列表排序与主机过滤
- 过期日志清理先按数据校验直接 DROP 完全过期整月分区,再对边界月逐行删除;
  启动时兜底预建当月及未来 2 个月分区,跨月停机重启后首次写入不再报
  "no partition of relation found"
2026-08-09 10:20:58 +08:00
ryan 08d28c2c8e feat(log): drop empty old-month PG partitions during cleanup
系统垃圾清理任务删除过期日志后,顺带清理旧月份空分区表:
PostgreSQL 按月分区的访问日志表(节点/用户)在数据删除后若该月
分区已无数据,则自动删除对应分区表,避免历史分区表无限累积。

- 仅删除「当前月之前」且为空的月份分区,当月/未来月及仍有数据的分区保留
- ClickHouse/SQLite 为 no-op(CH 分区随数据删除自动消失)
- 修复既有集成测试 pg_inherits 查询(inhrelid → inhparent)
- 新增单元测试与 PG 集成测试
2026-08-09 09:33:59 +08:00
ryan 34a0896ff8 chore(task): run system garbage cleanup once daily
系统定期垃圾清理 cron 由每 2 小时(0 */2 * * *)改为每日凌晨 3 点
(0 3 * * *,Asia/Shanghai),降低非必要高频扫描。新增 PG/SQLite
双方言 goose 迁移(含 Down 回滚)与迁移测试。
2026-08-09 09:25:30 +08:00
ryan 0c22e76f4b fix(frontend): optimization 2026-08-09 09:14:54 +08:00
ryan bd2183c8bb feat(log): add independent short retention for performance metrics
性能指标(CPU/内存/磁盘/网络)不再跟随 log_retention_days_*,新增三库共用
的 metric_retention_days 配置(默认 3 天),系统垃圾清理按独立短留存清理
指标快照;访问日志保留时长不变。新增 PG/SQLite 双方言 goose 迁移 seed。
2026-08-09 09:04:33 +08:00
ryan 9df2437e47 fix(config): set ClickHouse to disabled by default and update related documentation 2026-08-09 08:54:26 +08:00
ryan e8c414aa12 fix: ch migrate 2026-08-09 08:47:56 +08:00
ryan 7e8aa5fa0f Merge branch 'codex/log-database-decoupling'
# Conflicts:
#	docs/changelog/index.md
#	frontend/app/(main)/error-pages/page.tsx
#	internal/infra/persistence/migrator/migrator_test.go
2026-08-09 08:37:37 +08:00
ryan 7e518987de chore(release): v3.5.0
### 🛠 修复
- 修复 PoW 挑战页潜在 XSS 风险,状态与错误文案改用纯文本渲染,并限制跳转 URL 仅允许 http/https 协议。
- 修复邮件发送的邮件头注入风险,写入邮件头前自动清除 CR/LF 换行符(CWE-93)。
- 修复 UptimeKuma 同步调试日志泄露凭据问题,输出日志前对密码和 Token 等敏感字段打码。

### ⚡️ 优化与改进
- 新增 Service Worker 离线兜底功能,为启用 HTTPS 的网站自动下发 Service Worker 并缓存离线页,域名不可达时展示离线兜底页面。
- 重构响应页面设置,将源站错误页与 Service Worker 离线页整合至统一的「响应页面」(/responses)标签页,并增加 URL 查询参数 tab 状态同步。

### 💄 其他/体验
- 新增离线页内置预制模板套件(「极简白底」、「线框拓扑」、「包豪斯」),与源站错误页模板风格保持一致,支持编辑界面一键加载与预览。
2026-08-08 23:08:12 +08:00
ryan 61484090f9 fix: 修复源站错误页「仅针对 GET 请求」导致配置发布失败并回滚 2026-08-08 22:37:40 +08:00
ryan 6487ce666d fix(security): harden PoW XSS, email header injection and UptimeKuma log redaction 2026-08-08 21:52:46 +08:00
ryan fda727cf53 docs: rename contact page references to offline page in changelog
refactor(frontend): rename contact page to offline page and update routes/components

feat(frontend): add preset templates suite for offline contact page
2026-08-08 21:36:58 +08:00
ryan f083da20f2 feat(frontend): add dedicated edit and preview routes for response pages and sync tab state to url 2026-08-08 21:18:53 +08:00
ryan 9797fcdb2f fix(openflare): improve SWOfflineDomains validation and snapshot diff logic 2026-08-08 20:52:07 +08:00
ryan b675038bba refactor(frontend): unify error pages into responses page and remove error-pages route 2026-08-08 20:43:58 +08:00
ryan d17ec9d17d fix(docs): resolve vitepress build error by escaping raw tags and excluding superpowers dir 2026-08-08 20:43:56 +08:00
ryan 7d93d3d2a1 fix(log): address remaining CodeRabbit suggestions for log database switch and migrations 2026-08-08 20:36:04 +08:00
ryan a6fc2b7737 fix(log): address CodeRabbit review findings for log database decoupling 2026-08-08 20:15:36 +08:00
ryan ca21ff3a5b feat(option): add sw offline
fix(openresty): scope sw injection per cert partition

fix(lint): satisfy revive and biome format for sw offline feature

docs: sw offline scope changelog

fix(frontend): use scoped query key for sw scope zones

fix(frontend): hide preview link in sw contact page editor

feat(frontend): add sw scope domain picker and contact page fields

refactor(frontend): generalize html editor workspace for reuse

feat(openresty): scope sw offline injection by route domains

feat(openresty): add sw offline domains snapshot field

feat(option): add sw offline domains scope option

docs: fill html editor workspace generalization detail

docs: sw offline scope implementation plan

docs: sw offline scope design

test(openresty): assert single merged access block in sw enabled servers

fix(openresty): restrict sw intercept to https server blocks

fix(openresty): version sw offline cache by html content

fix(agent): escape redir in sw challenge page to prevent xss

fix(agent): return sw.runtime module table and add lua spec

docs: sw offline fallback changelog

fix(frontend): memoize option map to preserve unsaved contact page edits

feat(frontend): add response pages module with contact page tab

feat(agent): ship sw offline lua assets and placeholder substitution

feat(config): wire sw offline options into config snapshot

feat(openresty): render sw offline assets and challenge intercept

feat(openresty): add sw offline ConfigSnapshot fields and placeholder

feat(db): seed sw offline options

feat(option): add sw offline config keys and validation

docs: add service worker offline fallback implementation plan

docs: adopt global-option pattern for SW offline fallback (matches origin error page)

docs: unify offline contact page with error pages as response pages

docs: service worker offline fallback design (issue #23)
2026-08-08 20:14:28 +08:00
ryan 7d71f1e4e1 feat(log): decouple log storage from ClickHouse with switchable logstore
- New internal/repository/logstore abstraction: exported domain interfaces
  (AccessLogStore/ObservabilityStore/UserAccessLogStore/StatusStore),
  config-driven provider (Active/Build/Migrating/SetConfigReader), GORM
  implementation for PostgreSQL/SQLite (incl. hourly rollups computed in
  real time, migration listers, PG partition maintenance), and a ClickHouse
  wrapper preserving the native batch path; repository facade delegates to
  logstore; import-lint test enforces apps never import analyticsrepo.
- ClickHouse is now optional: the log DB is either the main DB (postgres
  when database.enabled, else sqlite) or clickhouse; boot validation +
  first-run seed; log_database / log_db_migration are protected keys.
- New user task 切换日志数据库 (of_log_db_switch): freeze log writes,
  drain batch writers, copy all 6 raw log tables by id (preserving IDs)
  with target-partition pre-creation for PG, flip log_database on success,
  clear the freeze flag on failure.
- Per-store retention (log_retention_days_*) with expiry cleanup folded
  into the daily system_cleanup task; legacy database_auto_cleanup_* and
  of_database_auto_cleanup decommissioned.
- goose migrations: 6 log tables in PG (2 monthly-partitioned) + SQLite,
  retention config seeds, schedule cleanup; GET
  /api/v1/admin/status/log-database endpoint; frontend retention settings,
  switch-task UI and status badge; changelog and docs updated.

docs(plan): log database decoupling implementation plan

docs(design): log database decoupling design (ClickHouse optional)
2026-08-08 19:43:01 +08:00
ryan 734fe45baa chore(release): v3.4.5
### ⚡️ 优化与改进

- 源站错误页新增「仅针对 GET 请求」开关:开启后仅对 GET 请求的匹配错误状态码返回自定义错误页,其它 HTTP 方法透传源站响应。
- 升级前后端依赖至最新稳定版
- Agent 不再将 GeoLite2 Country/City MMDB 嵌入二进制:Docker 镜像在默认数据目录 COPY 数据库文件,裸二进制首次启动时按需下载,显著减小 Agent 包体积;OpenResty 仍从磁盘路径读取 MMDB,Server 控制面仍仅内嵌 Country MMDB(不含 City)。
2026-08-08 11:25:42 +08:00
ryan ef22ecc5dc refactor(error-pages): merge trigger policy into one card
Combine enable, GET-only, and status code settings into a single
strategy card with the save action in the header for a cleaner layout.
2026-08-06 22:29:09 +08:00
ryan 6738abdec1 feat(openresty): add origin error page GET-only option
Allow restricting custom origin error HTML to GET requests so other
methods pass through origin responses. Adds option seed, snapshot field,
edge limit_except/Lua handling, and admin UI switch.
2026-08-06 20:22:44 +08:00
ryan d17d8457f3 chore: upgrade dependence 2026-08-06 17:41:06 +08:00
ryan 3328d3d121 refactor(agent): stop embedding GeoIP MMDB in agent binary
Agent ships without City/Country MMDB in the binary; Docker images COPY
databases into data_dir, bare installs seed via download on first start.
Server keeps Country-only embed for optional MaxMind control-plane use.
Also harden fetch script nonempty check and reject non-file MMDB paths.
2026-08-06 16:24:57 +08:00
ryan fb08002e99 chore(release): v3.4.4
### 新增

- 新增全局源站错误页:可在「网站管理 → 错误页」配置开关、触发状态码(支持 `500-599` 区间与单码)与自定义 HTML;默认启用 OpenFlare 极简错误页并保持真实 HTTP 状态码,修改后随配置版本发布下发到边缘,关闭后恢复透传。
- 新增 Cloudflare DNS 指向管理:可复用现有 Cloudflare DNS 账号或配置独立 Token,按分组将 ZoneDomain 的单条 A 记录异步同步到边缘节点 IPv4,并支持成员橙云、同步状态与节点 IP 变更联动。

### 修复

- 修复 Agent 在配置已对齐但磁盘校验和不一致时,Pages 等对账成功后仍保留 `LastError` 的问题,避免偶发网络失败被健康事件长期显示为「活动中」且无法自动恢复。

### 改进

- 删除、撤销与未保存离开等确认操作统一改用页面内 AlertDialog,不再使用浏览器原生 `confirm` 弹窗,交互风格与系统其余对话框保持一致。
2026-08-06 15:52:26 +08:00
ryan f650214bbb fix(openresty): preserve origin error status on custom error pages
Remove error_page '=' form that adopted the internal URI status (often 200)
and left ngx.status as 0. Resolve the original code from $status/upstream
and set ngx.status before rendering the HTML body.
2026-08-06 15:45:41 +08:00
ryan ba1c9222c2 refactor(error-pages): preset templates with OpenFlare branding 2026-08-06 15:25:39 +08:00
ryan 076bf8b95c Merge branch 'feat/origin-error-page' 2026-08-06 14:16:28 +08:00
ryan 835c50dbaa docs: origin error page configuration and changelog
Document three origin error page Option keys in configuration reference
and merge the unreleased changelog entry into a user-readable description.
2026-08-06 14:10:03 +08:00
ryan 7d47db1f34 feat(option): seed and validate origin error page options 2026-08-06 13:59:54 +08:00
ryan 9d93dc0b9f merge: fix/agent-clear-last-error-on-sync-success
Merge agent sticky LastError clear fix into main.
2026-08-06 13:48:14 +08:00
ryan 1a4a03a20d fix(agent): clear sticky LastError on successful sync paths
Pages reconcile could succeed while agent state retained a previous
network error, so health events stayed active indefinitely. Clear
LastError whenever sync completes successfully without re-applying
config, and cover the paths with regression tests.
2026-08-06 13:47:48 +08:00
ryan 1f5bebd18a docs(plan): add origin error page implementation plan
拆分为状态码解析、OpenResty 渲染、Option/快照、前端设置页与文档验收五步任务。
2026-08-06 13:44:45 +08:00
ryan fd62570431 docs(design): add origin error page design
全局可配置源站错误页:默认 500-599、Cloudflare 风格模板、
状态码透传与在线 HTML;配置进 Option 与配置版本快照。
2026-08-06 13:42:41 +08:00
ryan 484b49d79d fix(frontend): replace browser confirm dialogs with AlertDialog
统一删除、撤销与未保存离开等确认操作为 shadcn AlertDialog,避免
window.confirm/alert 打断界面风格;同步更新 WAF 编辑器相关单测与 changelog。
2026-08-06 13:08:43 +08:00
ryan 4eced2b721 feat(cloudflare): add DNS pointing integration 2026-08-04 13:30:40 +08:00