CLAUDE.md — monitor.tlyq.ai 告警监控中心
项目概述
monitor-ai 是独立部署的统一告警监控中心,监控 tlyq.ai 基础设施所有容器(Authelia、Redis、LLDAP、OA、assets、issue、Gitea、Nginx、www、cloud、token)的健康状态,通过企业微信 Webhook 推送告警。部署在腾讯云(txjp 服务器),域名 monitor.tlyq.ai。
快速参考
| 属性 |
值 |
| 站点域名 |
monitor.tlyq.ai |
| 服务器 |
txjp(IP: 43.133.38.210) |
| 代码路径 |
/root/docker/monitor-ai/ |
| 本地端口 |
6181 |
| 容器名 |
monitor-ai |
| 数据库 |
SQLite:data/monitor.db |
| 默认账号 |
localadmin / 首次部署自动生成 |
常用命令
cd /Users/niuniu/programs/docker/monitor-ai
npm run dev # 本地开发(http://localhost:6181)
npm run build # 生产构建
npm run start # 启动生产服务
技术栈
| 技术 |
版本 |
用途 |
| Next.js |
15 App Router |
Web 框架(standalone 输出) |
| SQLite |
3.x |
数据库(通过 execFileSync + sqlite3 CLI) |
| Tailwind CSS |
v4 |
样式(@tailwindcss/postcss) |
| lucide-react |
^1.8.0 |
图标库 |
| ldapts |
^6.0.0 |
LDAP 认证客户端 |
| openid-client |
^5.7.1 |
OIDC 认证 |
| tsx |
^4.0.0 |
Worker TypeScript 执行 |
目录结构
monitor-ai/
├── Dockerfile # 两阶段构建(node:22-alpine)
├── docker-compose.yml # 容器编排(webnet external)
├── entrypoint.sh # Docker 入口(双进程守护:Worker + Server)
├── next.config.ts # output: standalone, transpilePackages
├── shared -> ../shared # 共享库符号链接
├── scripts/
│ ├── monitor-worker.ts # Worker 独立入口
│ ├── deploy-monitor.sh # 部署脚本
│ └── monitor-watchdog.sh # 健康检查兜底脚本
├── src/
│ ├── middleware.ts # Edge Runtime 路由守卫
│ ├── app/
│ │ ├── page.tsx # 仪表盘(四层:标题 + 状态条 + KPI + 服务卡片)
│ │ ├── login/page.tsx # 登录页
│ │ ├── services/page.tsx # 服务管理
│ │ ├── settings/page.tsx # 告警设置
│ │ ├── alerts/page.tsx # 告警历史
│ │ ├── status-history/page.tsx # 状态变更历史
│ │ ├── admin/ # 管理页面(users/roles/audit-logs)
│ │ └── api/ # API 路由
│ ├── components/
│ │ ├── Sidebar.tsx # 侧边栏导航
│ │ ├── ThemeProvider.tsx # 主题上下文
│ │ └── ThemeToggle.tsx # 主题切换
│ └── lib/
│ ├── config.ts # 配置常量
│ ├── db.ts # 数据库操作封装(execFileSync + escapeSql)
│ ├── auth-config.ts # 认证配置
│ ├── permissions.ts # RBAC 权限定义
│ ├── audit.ts # 审计日志封装
│ └── monitor-worker.ts # MonitorWorker 核心类
└── data/
└── monitor.db # SQLite 数据库
关键文件
| 文件 |
职责 |
src/lib/monitor-worker.ts |
MonitorWorker 核心类(30s tick,健康检查 + 状态管理 + 告警推送) |
src/lib/db.ts |
SQLite 操作封装(execFileSync + escapeSql,无 ORM) |
src/lib/permissions.ts |
RBAC 权限定义(11 个权限点,admin/editor/viewer/localadmin) |
src/lib/audit.ts |
审计日志封装(调用 @shared/lib/audit) |
src/lib/auth-config.ts |
认证配置(OIDC + LDAP) |
src/middleware.ts |
Edge Runtime 路由守卫(Cookie JWT 验证,公开/管理路径控制) |
scripts/monitor-worker.ts |
Worker 独立入口(信号处理、优雅退出) |
entrypoint.sh |
Docker 入口(双进程守护:Worker + Server,任一退出则容器退出) |
shared/lib/alert/ |
告警引擎(AlertManager、HealthChecker、类型定义) |
shared/lib/wechat/ |
企业微信推送(WeChatPusher、消息格式化) |
数据库 Schema
表概览
| 表名 |
说明 |
来源 |
services |
被监控服务列表 |
@shared/lib/db/alert-schema |
alert_channels |
Webhook 告警渠道配置 |
@shared/lib/db/alert-schema |
alert_settings |
全局设置 + 冷却状态持久化 |
@shared/lib/db/alert-schema |
status_history |
服务状态变更事件 |
@shared/lib/db/alert-schema |
alert_history |
告警推送记录 |
@shared/lib/db/alert-schema |
users |
用户账号 |
src/lib/db.ts(内联) |
permissions |
权限定义 |
src/lib/db.ts(内联) |
role_permissions |
角色-权限映射 |
src/lib/db.ts(内联) |
audit_logs |
审计日志 |
@shared/lib/audit/audit-schema |
services 表
| 字段 |
类型 |
说明 |
id |
INTEGER PK |
主键 |
name |
TEXT |
服务名称 |
category |
TEXT |
分类(endpoint / container / custom) |
alert_level |
TEXT |
告警级别(critical / warning / info) |
checks |
TEXT |
检查配置(JSON 数组,HealthCheckConfig[]) |
check_interval |
INTEGER |
检查间隔秒数(默认 30) |
check_timeout |
INTEGER |
检查超时秒数(默认 10) |
enabled |
INTEGER |
是否启用(默认 1) |
current_status |
TEXT |
当前状态(normal / abnormal / unknown) |
status_since |
TEXT |
状态持续起始时间 |
display_order |
INTEGER |
显示排序 |
alert_channels 表
| 字段 |
类型 |
说明 |
id |
INTEGER PK |
主键 |
name |
TEXT |
渠道名称 |
channel_type |
TEXT |
渠道类型(默认 'wechat') |
webhook_url |
TEXT |
Webhook 地址 |
enabled |
INTEGER |
是否启用 |
level_critical |
INTEGER |
是否接收 critical 告警 |
level_warning |
INTEGER |
是否接收 warning 告警 |
level_info |
INTEGER |
是否接收 info 告警 |
quiet_enabled |
INTEGER |
是否启用免打扰 |
quiet_start |
TEXT |
免打扰开始时间 |
quiet_end |
TEXT |
免打扰结束时间 |
quiet_bypass_critical |
INTEGER |
critical 是否绕过免打扰 |
cooldown_minutes |
INTEGER |
冷却时间(分钟) |
status_history 表
| 字段 |
类型 |
说明 |
id |
INTEGER PK |
主键 |
service_id |
INTEGER FK |
关联服务 |
from_status |
TEXT |
原状态 |
to_status |
TEXT |
新状态 |
started_at |
TEXT |
状态开始时间 |
ended_at |
TEXT |
状态结束时间 |
duration_seconds |
INTEGER |
持续时长 |
error_message |
TEXT |
错误信息 |
failed_checks |
TEXT |
失败检查详情(JSON) |
truncated_by_restart |
INTEGER |
是否被重启截断 |
alert_history 表
| 字段 |
类型 |
说明 |
id |
INTEGER PK |
主键 |
channel_id |
INTEGER FK |
告警渠道 |
service_id |
INTEGER FK |
关联服务 |
status_event_id |
INTEGER FK |
关联状态事件 |
alert_type |
TEXT |
告警类型(alert / recovery / flapping) |
level |
TEXT |
告警级别 |
title |
TEXT |
标题 |
content |
TEXT |
内容 |
sent_at |
TEXT |
发送时间 |
success |
INTEGER |
是否成功 |
response_code |
INTEGER |
HTTP 响应码 |
users 表
| 字段 |
类型 |
说明 |
id |
INTEGER PK |
主键 |
username |
TEXT UNIQUE |
用户名 |
display_name |
TEXT |
显示名 |
email |
TEXT |
邮箱 |
role |
TEXT |
角色(admin / editor / viewer) |
password_hash |
TEXT |
密码哈希 |
is_active |
INTEGER |
是否启用 |
默认用户:localadmin(admin 角色,BCrypt 密码哈希)
预置角色
| 角色 |
权限 |
说明 |
admin |
全部 11 个权限 |
管理员 |
editor |
dashboard:view, services:view, alerts:view, status_history:view, status_history:stats |
编辑者 |
viewer |
dashboard:view, services:view, status_history:view |
只读 |
localadmin |
硬编码绕过(hasPermission 始终返回 true) |
应急管理员 |
权限列表
dashboard:view、services:view、services:manage、alerts:view、alerts:manage、status_history:view、status_history:stats、audit:view、users:view、users:manage、roles:manage
API 路由
公开 API
| 方法 |
路径 |
说明 |
| GET |
/api/health |
自身健康检查(返回 {status:'OK'}) |
认证
登录逻辑:OIDC SSO 优先 + LDAP 本地登录 + localadmin 应急用户。
登录成功签发 tlyq_session cookie(共享 JWT,domain=.tlyq.ai)。
中间件验证 JWT payload(Edge Runtime,不解密签名,仅解码 payload 检查过期时间)。
| 方法 |
路径 |
说明 |
| GET |
/api/auth/login/oidc |
OIDC SSO 重定向到 Authelia |
| POST |
/api/auth/login |
LDAP 或 localadmin 登录 |
| GET |
/api/auth/callback |
OIDC 回调处理 |
| POST |
/api/auth/logout |
登出(清除 cookie,重定向 Authelia end_session) |
| GET |
/api/auth/me |
当前用户信息 |
服务管理
| 方法 |
路径 |
权限 |
说明 |
| GET |
/api/services |
登录 |
服务列表(含解析后的 JSON checks) |
| POST |
/api/services |
services:manage |
新增服务 |
| PUT |
/api/services/[id] |
services:manage |
更新服务 |
| DELETE |
/api/services/[id] |
services:manage |
删除服务 |
| POST |
/api/services/[id]/check |
services:manage |
手动触发单次健康检查 |
告警渠道
| 方法 |
路径 |
权限 |
说明 |
| GET |
/api/alert-channels |
alerts:manage |
渠道列表(webhook_url 脱敏) |
| POST |
/api/alert-channels |
alerts:manage |
新增渠道 |
| PUT |
/api/alert-channels/[id] |
alerts:manage |
更新渠道 |
| DELETE |
/api/alert-channels/[id] |
alerts:manage |
删除渠道 |
| POST |
/api/alert-channels/[id]/test |
alerts:manage |
测试推送 |
告警历史 / 状态历史
| 方法 |
路径 |
权限 |
说明 |
| GET |
/api/alerts |
alerts:view |
告警历史(分页) |
| GET |
/api/status-history |
登录 |
状态变更历史(分页,可按 service_id 筛选) |
| GET |
/api/status |
登录 |
所有服务实时状态汇总 |
内部 API(x-internal-key 鉴权)
| 方法 |
路径 |
说明 |
| GET |
/api/internal/users |
返回用户列表 |
| POST |
/api/internal/users |
OA 同步用户角色 |
管理
| 方法 |
路径 |
权限 |
说明 |
| GET |
/api/admin/worker-status |
dashboard:view |
Worker 运行状态 |
Worker 架构
MonitorWorker 核心类
位置:src/lib/monitor-worker.ts
MonitorWorker
├── HealthChecker(@shared/lib/alert/health-checker)
│ ├── HttpChecker — HTTP 状态码 + 响应体匹配
│ └── DockerChecker — docker ps 容器状态检查
├── AlertManager(@shared/lib/alert/alert-manager)
│ ├── evaluate() — 三阶段告警决策(级别匹配 → 免打扰 → 冷却)
│ └── CooldownProvider — alert_settings 表持久化冷却状态
└── WeChatPusher(@shared/lib/wechat/wechat-pusher)
└── pushMarkdown() — 企业微信 Webhook 推送
运行机制
| 阶段 |
间隔 |
说明 |
| 健康检查 |
30 秒 tick |
遍历所有 enabled 服务,并发执行检查(Promise.allSettled) |
| 抖动检测 |
10 分钟窗口 |
同一服务 10 分钟内状态切换 >= 5 次 → 触发 flapping 告警,抑制后续告警 |
| 持续异常提醒 |
30 分钟 |
服务持续 abnormal 状态,每 30 分钟发送提醒 |
| 恢复通知 |
即时 |
服务恢复正常时发送 recovery 通知,绕过免打扰和冷却 |
| WAL 检查点 |
1 小时 |
被动 WAL checkpoint(PASSIVE) |
| 数据清理 |
每天 |
删除 180 天前的 status_history 和 alert_history(每批 LIMIT 1000) |
Docker 入口(entrypoint.sh)
entrypoint.sh
├── npx tsx scripts/monitor-worker.ts & # 后台启动 Worker
├── node server.js & # 后台启动 Next.js Server
└── 守护循环:任一进程退出则容器退出 # 保证双进程存活
└── trap SIGTERM/SIGINT → 清理退出
认证机制
- OIDC SSO:通过 Authelia 进行 PKCE 授权码流程,登录成功后签发
tlyq_session 共享 JWT cookie
- LDAP 本地登录:通过 LLDAP 进行 bind 认证,签发
tlyq_session cookie
- localadmin:纯本地 BCrypt 认证,不依赖 LLDAP/OIDC,用于应急登录
- Edge Runtime 中间件:
src/middleware.ts 运行在 Edge Runtime,使用 atob 解码 JWT payload 检查过期时间,不验证签名(签名验证在 route handler 层)
环境配置
本地与云端差异
| 环境变量 |
本地开发 |
云服务器(txjp) |
说明 |
DATABASE_PATH |
./data/monitor.db |
/app/data/monitor.db |
Docker volume 挂载 |
MONITOR_MODE |
dev |
local |
运行模式 |
AUTHELIA_URL |
https://127.0.0.1:6180 |
https://sso.tlyq.ai |
Authelia 地址 |
OIDC_CLIENT_ID |
monitor-oidc |
同 |
OIDC 客户端 ID |
OIDC_CLIENT_SECRET |
本地生成的值 |
服务器生成的值 |
OIDC 客户端密钥(每个环境独立) |
OIDC_REDIRECT_URI |
http://localhost:6181/api/auth/callback |
https://monitor.tlyq.ai/api/auth/callback |
OIDC 回调地址 |
JWT_SECRET |
dev-jwt-secret-change-in-production |
部署脚本自动生成 |
JWT 签名密钥 |
COOKIE_DOMAIN |
.tlyq.ai |
同 |
Cookie 域 |
LDAP_URL |
ldap://ldap-ai:3890 |
ldap://ldap-ai:3890 |
LLDAP 地址(Docker 内网) |
LOCALADMIN_PASSWORD |
admin123 |
部署脚本自动生成 |
应急管理员密码 |
NODE_TLS_REJECT_UNAUTHORIZED |
0 |
0 |
TLS 证书验证(Authelia 自签名) |
.env.local 示例
DATABASE_PATH=./data/monitor.db
MONITOR_MODE=dev
AUTHELIA_URL=https://127.0.0.1:6180
OIDC_CLIENT_ID=monitor-oidc
OIDC_CLIENT_SECRET=<本地生成的值>
OIDC_REDIRECT_URI=http://localhost:6181/api/auth/callback
JWT_SECRET=dev-jwt-secret-change-in-production
COOKIE_DOMAIN=.tlyq.ai
LDAP_URL=ldap://ldap-ai:3890
LOCALADMIN_PASSWORD=admin123
NODE_TLS_REJECT_UNAUTHORIZED=0
共享库引用
| 库 |
用途 |
导入路径 |
@shared/lib/auth/jwt-v2 |
JWT 签名/验证(HS256,含 iss) |
import { signJwtV2, verifyJwtV2 } from '@shared/lib/auth/jwt-v2' |
@shared/lib/auth/jwt |
JWT 签名/验证(V1 兼容,无 iss) |
import { signJwt, verifyJwt } from '@shared/lib/auth/jwt' |
@shared/lib/auth/middleware-v2 |
路由守卫工厂(V2:单 cookie 模型) |
import { createMiddlewareV2 } from '@shared/lib/auth/middleware-v2' |
@shared/lib/auth/middleware |
路由守卫工厂(V1,已废弃) |
import { createMiddleware } from '@shared/lib/auth/middleware' |
@shared/lib/auth/oidc |
OIDC PKCE 流程 |
import { discoverOidcConfig, buildAuthorizeUrl } from '@shared/lib/auth/oidc' |
@shared/lib/auth/ldap |
LDAP 认证 |
import { ldapAuth } from '@shared/lib/auth/ldap' |
@shared/lib/alert/alert-manager |
告警决策引擎 |
import { AlertManager } from '@shared/lib/alert/alert-manager' |
@shared/lib/alert/health-checker |
健康检查引擎 |
import { HealthChecker, HttpChecker, DockerChecker } from '@shared/lib/alert/health-checker' |
@shared/lib/audit/write-audit-log |
审计日志 |
import { writeAuditLog } from '@shared/lib/audit/write-audit-log' |
@shared/lib/wechat/wechat-pusher |
企业微信推送 |
import { WeChatPusher } from '@shared/lib/wechat/wechat-pusher' |
@shared/lib/wechat/message-formatter |
消息格式化 |
import { formatAlertLevel } from '@shared/lib/wechat/message-formatter' |
@shared/lib/db/alert-schema |
数据库 Schema 常量 |
import { ALL_TABLES_SQL } from '@shared/lib/db/alert-schema' |
@shared/ui |
UI 组件库 |
import { Button, Card, Badge } from '@shared/ui' |
@shared/ui/login-page |
统一登录页 |
import LoginPage from '@shared/ui/login-page' |
路径映射:tsconfig.json 中配置 "@shared/*": ["./shared/*"],shared 是指向 ../shared 的符号链接。
关键设计决策
execFileSync 数组参数
数据库操作使用 execFileSync('sqlite3', [dbPath, '-json', sql]) 而非 ORM。SQL 通过数组参数传递,避免 shell 注入。所有用户输入通过 escapeSql() 函数转义(单引号双写)。
Edge Runtime 中间件
src/middleware.ts 运行在 Edge Runtime,不能使用 Node.js crypto 模块。JWT 验证仅解码 payload 检查过期时间,签名验证留给 route handler 层处理。
双进程守护
entrypoint.sh 同时启动 Worker 和 Server,使用 bash 守护循环监控。任一进程退出则整个容器退出,由 Docker 重启策略接管。
冷却状态持久化
告警冷却状态存储在 alert_settings 表中(key 格式:cooldown:{channel_id}:{service_id}:{level}),容器重启后冷却状态不丢失。
Docker 部署
txjp 服务器
├── monitor-ai(容器) ← Next.js standalone + Worker,监听 6181
├── nginx-ai ← 反向代理 monitor.tlyq.ai → monitor-ai:6181
└── webnet(external) ← 共享网络
部署:bash deploy-monitor.sh(本地模式)或 bash deploy-monitor.sh --remote --host <IP>。
源码打包上传 → 服务器 npm install + npm run build → .next 挂载进容器生效。
生产环境变量
DATABASE_PATH=/app/data/monitor.db
MONITOR_MODE=local
AUTHELIA_URL=https://sso.tlyq.ai
OIDC_CLIENT_ID=monitor-oidc
OIDC_CLIENT_SECRET=<部署脚本自动生成>
OIDC_REDIRECT_URI=https://monitor.tlyq.ai/api/auth/callback
JWT_SECRET=<部署脚本自动生成>
COOKIE_DOMAIN=.tlyq.ai
LDAP_URL=ldap://ldap-ai:3890
LOCALADMIN_PASSWORD=<部署脚本自动生成>
NODE_ENV=production
NODE_TLS_REJECT_UNAUTHORIZED=0
开发规范
- 新增 API:在
src/app/api/ 下创建路由 → 顶部调用 initDatabase() → getCurrentUser() 验证 → checkPermission() 校验
- 新增页面:在
src/app/ 下创建 → 布局由 client-layout.tsx 提供(Sidebar + ThemeProvider)
- 权限格式:
resource:action,如 checkPermission(user, 'services:manage')
- 审计日志:所有写操作 API(POST/PUT/DELETE)必须添加审计日志:
import { writeAuditLog } from '@/lib/audit'
writeAuditLog({
userId: user.id,
action: 'create' | 'update' | 'delete',
entityType: 'service' | 'alert_channel' | 'user',
entityId: id,
details: { ... },
ipAddress: getClientIP(request)
})
- 日期处理(时区规范):整个系统统一使用 UTC+8(北京时间)。必须遵守:
- JavaScript/TypeScript:禁止使用
Date.toISOString() 格式化本地日期,应使用本地时间方法拼接
- SQLite:所有
datetime('now') 必须写成 datetime('now', '+8 hours')
- INSERT 时间列:数据库表 DEFAULT 已统一为
datetime('now', '+8 hours'),INSERT 时可省略
健康检查兜底
scripts/monitor-watchdog.sh 是独立于 monitor-ai 的兜底脚本,通过 crontab 每 5 分钟执行:
*/5 * * * * /root/docker/monitor-ai/scripts/monitor-watchdog.sh >> /var/log/monitor-watchdog.log 2>&1
当 /api/health 连续失败时,直接通过企业微信 Webhook 发送告警,并尝试重启容器。
故障排查
# 容器日志
ssh txjp "docker logs monitor-ai"
# Worker 日志(实时)
ssh txjp "docker logs -f monitor-ai 2>&1 | grep -i worker"
# 数据库查看
ssh txjp "docker exec monitor-ai sqlite3 /app/data/monitor.db 'SELECT id, name, current_status FROM services;'"
# 健康检查
ssh txjp "curl -s -k https://monitor.tlyq.ai/api/health"
# 手动触发检查
ssh txjp "docker exec monitor-ai sqlite3 /app/data/monitor.db 'UPDATE services SET current_status=\"unknown\";'"
# 重建镜像(新增依赖后)
ssh txjp "cd /root/docker/monitor-ai && docker compose build --no-cache && docker compose down && docker compose up -d"
Git Tag 规范
使用日期版本号 vYYYY.MM.DD(如 v2026.07.01)。提交后打 tag 再推送:
git tag v$(date +%Y.%m.%d) && git push origin main && git push origin v$(date +%Y.%m.%d)
同一天多次提交只打一个 tag。详见根目录 CLAUDE.md。