Files
nuyue/docs/DESIGN.md
T
admin 7b339cd994 feat: 怒月(Nuyue)项目初始化 - Phase 1 基础框架
- 项目重命名为怒月(Nuyue)
- 服务端基础骨架 (Gin + GORM)
- 数据库支持 PostgreSQL/SQLite 双模式
- Redis 可选配置
- 加密工具包 (Argon2id + HKDF + AES-256-GCM)
- 统一响应封装
- 配置加载 (Viper)
- 安装向导 API 设计文档
- Termius 深色主题设计规范
- 开发设计文档完善
2026-06-22 17:53:54 +00:00

99 KiB
Raw Permalink Blame History

怒月 (Nuyue) - 服务器监控探针系统

Git 仓库git.viaeon.com/admin/nuyue

开发流程

每个模块开发完成后:

  1. Code Review - 检查代码质量、安全性、性能
  2. 测试验证 - 单元测试、集成测试
  3. 推送到 Git - git push origin main
  4. 更新文档 - 同步更新 DESIGN.md

1. 项目概述

怒月 (Nuyue) 是一个服务器监控探针系统,由 服务端(Server客户端(Agent 两部分组成。服务端集成于官网,提供用户注册、套餐购买、服务器管理、监控展示等功能;客户端部署在用户服务器上,通过 gRPC 上报系统指标。

核心设计原则

  • 零知识安全:服务端不存储用户明文密码和敏感配置,所有敏感信息由用户密码派生的密钥加密后存储
  • 配置下发:客户端所有运行配置(上报频率、TCPing 节点、备份策略等)均从服务端获取并缓存
  • 多租户隔离:用户数据严格隔离,每个用户拥有独立的探针展示页面

2. 技术选型

组件 技术方案 说明
服务端框架 Go (Gin) 高性能、gRPC 原生支持
客户端 Go 单二进制、跨平台、低资源占用
通信协议 gRPC + Protobuf 双向流、高效序列化
数据库 PostgreSQL (生产) / SQLite (单机)
缓存 Redis (生产可选)
前端 Vue 3 + TypeScript 管理后台 + 用户面板
UI 组件库 Naive UI 遵循 Termius 设计规范:深色终端风格 + 绿色品牌色 + JetBrains Mono 字体
探针页面 Nuxt 3 (SSR) 用户公开监控页面,支持自定义
消息通知 Telegram Bot API 告警通知
定时任务 Go 内置 ticker + cron 客户端本地调度
对象存储 S3 兼容 备份文件存储

3. 系统架构

┌─────────────────────────────────────────────────────────┐
│                      服务端 (Server)                      │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌─────────┐ │
│  │ 官网前端  │  │ 管理后台  │  │ 用户面板  │  │ 探针页面 │ │
│  │ (Vue3)   │  │ (Vue3)   │  │ (Vue3)   │  │ (Nuxt3) │ │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬────┘ │
│       └──────────────┴─────────────┴─────────────┘      │
│                         │ REST API                       │
│  ┌──────────────────────┴──────────────────────────┐    │
│  │              API Gateway (Gin)                   │    │
│  │  ┌─────────┐ ┌──────────┐ ┌────────────────┐   │    │
│  │  │ Auth    │ │ Plan     │ │ Server Mgmt    │   │    │
│  │  │ Module  │ │ Module   │ │ Module         │   │    │
│  │  └─────────┘ └──────────┘ └────────────────┘   │    │
│  │  ┌─────────┐ ┌──────────┐ ┌────────────────┐   │    │
│  │  │ Redeem  │ │ Monitor  │ │ Backup         │   │    │
│  │  │ Module  │ │ Module   │ │ Module         │   │    │
│  │  └─────────┘ └──────────┘ └────────────────┘   │    │
│  └──────────────────────┬──────────────────────────┘    │
│                         │                                │
│  ┌──────────────────────┴──────────────────────────┐    │
│  │              gRPC Service                        │    │
│  │  ┌──────────┐ ┌───────────┐ ┌───────────────┐  │    │
│  │  │ Report   │ │ Config    │ │ Backup        │  │    │
│  │  │ Stream   │ │ Fetch     │ │ Upload        │  │    │
│  │  └──────────┘ └───────────┘ └───────────────┘  │    │
│  └──────────────────────┬──────────────────────────┘    │
│                         │                                │
│  ┌──────────┐  ┌───────┴──────┐  ┌────────────────┐    │
│  │ PostgreSQL│  │    Redis     │  │  S3 Storage    │    │
│  └──────────┘  └──────────────┘  └────────────────┘    │
└─────────────────────────┬───────────────────────────────┘
                          │ gRPC (TLS)
          ┌───────────────┼───────────────┐
          │               │               │
    ┌─────┴─────┐   ┌─────┴─────┐   ┌─────┴─────┐
    │  Agent 1  │   │  Agent 2  │   │  Agent N  │
    │  (Go)     │   │  (Go)     │   │  (Go)     │
    └───────────┘   └───────────┘   └───────────┘

4. 数据库设计

4.0 数据库选型

场景 推荐方案 说明
生产环境 PostgreSQL 高并发、多租户、支持 TimescaleDB 扩展用于指标数据
小型部署 SQLite 单机、低资源、嵌入式部署,零依赖,适合个人使用
开发环境 SQLite 快速启动、零配置,无需安装数据库服务

SQLite 使用限制

  • 不支持 TimescaleDB,指标数据直接存储在 server_metrics 表(按天分区或定期清理)
  • 单写入连接,适合单实例部署,不支持多实例负载均衡
  • 备份功能建议使用本地文件备份而非 S3
  • 无 Redis 时,配置缓存使用内存缓存(进程重启后重新加载)

数据库兼容性设计

  • 使用 GORM 作为 ORM,自动适配 PostgreSQL 和 SQLite
  • 所有表结构使用通用类型,避免 PostgreSQL 特有类型(如 BYTEA 在 SQLite 中用 BLOB
  • 指标数据表在 SQLite 模式下使用普通表 + 定期清理策略

4.1 用户表 (users)

字段 类型 说明
id UUID 主键
username VARCHAR(50) 账号,唯一,注册后不可改
password_hash VARCHAR(255) Argon2id 哈希
email VARCHAR(255) 绑定邮箱,可换绑,唯一,可为 NULL
email_verified BOOLEAN 邮箱是否已验证
avatar_url VARCHAR(500) 头像
role VARCHAR(20) admin / user
status VARCHAR(20) active / disabled
encrypted_config_key BYTEA 加密密码加密的配置密钥(用于加解密客户端配置)
config_key_nonce BYTEA 加密 nonce
tg_chat_id BIGINT TG 绑定 Chat IDNULL 表示未绑定
tg_username VARCHAR(100) TG 用户名
tg_bound_at TIMESTAMP TG 绑定时间
preference_show_remaining_value BOOLEAN 是否显示套餐剩余价值,默认 true
preference_tg_notify_enabled BOOLEAN 是否开启 TG 告警通知,默认 false
created_at TIMESTAMP 创建时间
updated_at TIMESTAMP 更新时间

4.2 邮箱验证码表 (email_verification_codes)

字段 类型 说明
id UUID 主键
email VARCHAR(255) 邮箱
code VARCHAR(6) 验证码
purpose VARCHAR(20) register / bind / rebind / reset_password
expires_at TIMESTAMP 过期时间
used BOOLEAN 是否已使用
ip_address VARCHAR(45) 请求 IP
created_at TIMESTAMP

4.3 系统设置表 (system_settings)

键值对存储,管理员在后台配置,服务启动时加载到 Redis 缓存

字段 类型 说明
id UUID 主键
category VARCHAR(30) 分类:general / smtp / payment / security / telegram
key VARCHAR(100) 配置键,唯一索引
value TEXT 配置值(敏感值加密存储)
value_type VARCHAR(20) string / int / bool / json
description VARCHAR(255) 配置说明
is_encrypted BOOLEAN 值是否加密存储
updated_by UUID FK → users,最后修改者
updated_at TIMESTAMP

系统配置项清单

分类 key 说明 默认值
general site_name 站点名称 StatusProbe
general site_url 站点地址 https://status.example.com
general site_description 站点描述
smtp smtp_host SMTP 服务器
smtp smtp_port SMTP 端口 465
smtp smtp_username SMTP 用户名
smtp smtp_password SMTP 密码(加密存储)
smtp smtp_from_name 发件人名称 StatusProbe
smtp smtp_from_email 发件人邮箱
smtp smtp_encryption 加密方式 ssl/tls/starttls ssl
payment payment_alipay_enabled 支付宝是否启用 false
payment payment_alipay_app_id 支付宝 App ID
payment payment_alipay_private_key 支付宝私钥(加密存储)
payment payment_alipay_public_key 支付宝公钥
payment payment_wechat_enabled 微信支付是否启用 false
payment payment_wechat_mch_id 微信商户号
payment payment_wechat_api_key 微信 API 密钥(加密存储)
payment payment_wechat_cert_sn 微信证书序列号
payment payment_stripe_enabled Stripe 是否启用 false
payment payment_stripe_publishable_key Stripe 公钥
payment payment_stripe_secret_key Stripe 密钥(加密存储)
payment payment_stripe_webhook_secret Stripe Webhook 签名密钥(加密存储)
security register_enabled 是否开放注册 true
security captcha_enabled 注册是否开启验证码 false
security captcha_type 验证码类型 recaptcha/hcaptcha/turnstile turnstile
security captcha_site_key 验证码 Site Key
security captcha_secret_key 验证码 Secret Key(加密存储)
security email_verify_enabled 注册是否需要邮箱验证 false
security email_verify_bind 是否强制绑定邮箱 false
security login_captcha_enabled 登录是否开启验证码 false
security rate_limit_register 注册频率限制(IP/小时) 5
security rate_limit_login 登录频率限制(IP/小时) 20
telegram tg_bot_enabled 是否启用系统 TG Bot false
telegram tg_bot_token 系统 TG Bot Token(加密存储)
telegram tg_bot_username 系统 TG Bot 用户名
telegram tg_notify_enabled 系统全局 TG 通知开关 true
telegram tg_bind_welcome_msg 用户绑定 Bot 时的欢迎消息 欢迎绑定 StatusProbe 通知!

4.4 支付订单表 (payment_orders)

字段 类型 说明
id UUID 主键
user_id UUID FK → users
user_plan_id UUID FK → user_plans,支付成功后关联
order_no VARCHAR(32) 订单号,唯一索引
channel VARCHAR(20) alipay / wechat / stripe
amount DECIMAL(10,2) 金额
currency VARCHAR(10) 货币 CNY/USD
plan_id UUID FK → plans
billing_type VARCHAR(20) monthly / yearly / lifetime
type VARCHAR(20) purchase / upgrade
status VARCHAR(20) pending / paid / failed / refunded / expired
channel_trade_no VARCHAR(100) 第三方交易号
paid_at TIMESTAMP 支付时间
expires_at TIMESTAMP 订单过期时间(未支付自动关闭)
created_at TIMESTAMP
updated_at TIMESTAMP

4.5 套餐表 (plans)

字段 类型 说明
id UUID 主键
name VARCHAR(100) 套餐名称
description TEXT 套餐描述
max_clients INT 允许的客户端数量
max_tcping_nodes INT 最大 TCPing 节点数
allow_custom_theme BOOLEAN 是否允许自定义主题和组件
allow_tg_notify BOOLEAN 是否允许 TG 通知
allow_backup BOOLEAN 是否允许定时备份
max_backup_count INT 最大备份仓库数
max_backup_repos INT 最大 Restic 仓库数
allow_backup_docker BOOLEAN 是否允许 Docker 备份
allow_backup_database BOOLEAN 是否允许数据库备份
allow_upgrade BOOLEAN 是否允许升级
price_monthly DECIMAL(10,2) 月付价格,NULL 表示不可月付
price_yearly DECIMAL(10,2) 年付价格,NULL 表示不可年付
price_lifetime DECIMAL(10,2) 永久价格,NULL 表示不可永久
sort_order INT 排序
is_visible BOOLEAN 是否可见
status VARCHAR(20) active / archived
created_at TIMESTAMP
updated_at TIMESTAMP

4.6 用户套餐表 (user_plans)

字段 类型 说明
id UUID 主键
user_id UUID FK → users
plan_id UUID FK → plans
billing_type VARCHAR(20) monthly / yearly / lifetime
started_at TIMESTAMP 生效时间
expires_at TIMESTAMP 过期时间,NULL 表示永久
upgraded_from UUID FK → user_plans,升级来源
status VARCHAR(20) active / expired / cancelled
created_at TIMESTAMP

4.7 兑换码表 (redeem_codes)

字段 类型 说明
id UUID 主键
code VARCHAR(32) 兑换码,唯一索引
plan_id UUID FK → plans
billing_type VARCHAR(20) monthly / yearly / lifetime
max_use_count INT 最大使用次数
used_count INT 已使用次数,默认 0
created_by UUID FK → users,创建者
expires_at TIMESTAMP 兑换码过期时间
status VARCHAR(20) active / used_up / expired
created_at TIMESTAMP

4.8 兑换记录表 (redeem_records)

字段 类型 说明
id UUID 主键
redeem_code_id UUID FK → redeem_codes
user_id UUID FK → users
user_plan_id UUID FK → user_plans
created_at TIMESTAMP

4.9 服务器表 (servers)

字段 类型 说明
id UUID 主键
user_id UUID FK → users
name VARCHAR(100) 服务器名称
display_name VARCHAR(100) 展示名称
region VARCHAR(50) 地区标签
tags VARCHAR[] 标签数组
agent_token VARCHAR(64) 客户端认证令牌(随机生成,非用户密码)
encrypted_config BYTEA AES-256-GCM 加密的客户端配置
config_nonce BYTEA 加密 nonce
last_seen_at TIMESTAMP 最后上报时间
status VARCHAR(20) online / offline / unconnected
is_visible BOOLEAN 是否在探针页面展示
sort_order INT 排序
created_at TIMESTAMP
updated_at TIMESTAMP

4.10 服务器指标表 (server_metrics)

使用 TimescaleDB 扩展或按时间分区

字段 类型 说明
id BIGSERIAL 主键
server_id UUID FK → servers
cpu_usage REAL CPU 使用率 %
cpu_temp REAL CPU 温度 ℃,NULL 表示不支持/无法读取
gpu_info JSONB GPU 信息数组,如 [{"name":"RTX 4090","temp":65.0,"usage":45.0,"memory_total":24576,"memory_used":8192}]NULL 表示无 GPU
memory_total BIGINT 总内存 bytes
memory_used BIGINT 已用内存 bytes
disk_total BIGINT 总磁盘 bytes
disk_used BIGINT 已用磁盘 bytes
network_rx BIGINT 入站流量 bytes/s
network_tx BIGINT 出站流量 bytes/s
load_1 REAL 1分钟负载
load_5 REAL 5分钟负载
load_15 REAL 15分钟负载
uptime BIGINT 运行时间 seconds
os_info JSONB 操作系统信息
process_count INT 进程数
reported_at TIMESTAMP 上报时间

4.11 TCPing 记录表 (tcping_results)

字段 类型 说明
id BIGSERIAL 主键
server_id UUID FK → servers
target_host VARCHAR(255) 目标地址
target_port INT 目标端口
latency_ms REAL 延迟 ms-1 表示超时
success BOOLEAN 是否连通
checked_at TIMESTAMP 检测时间

4.12 TCPing 节点配置表 (tcping_nodes)

字段 类型 说明
id UUID 主键
name VARCHAR(100) 节点名称
host VARCHAR(255) 地址
port INT 端口
is_default BOOLEAN 是否默认节点
status VARCHAR(20) active / disabled
created_at TIMESTAMP

4.13 告警规则表 (alert_rules)

字段 类型 说明
id UUID 主键
server_id UUID FK → servers
metric_type VARCHAR(30) cpu / memory / disk / cpu_temp / gpu_temp / gpu_usage / tcping_offline
operator VARCHAR(10) gt / gte / lt / lte / eq
threshold REAL 阈值
duration_seconds INT 持续时间,0 表示即时
cooldown_seconds INT 冷却时间,默认 300
is_enabled BOOLEAN 是否启用
created_at TIMESTAMP

4.14 通知渠道表 (notify_channels)

用户无需自行配置 Bot Token,管理员统一配置系统 TG Bot,用户只需绑定自己的 TG 账号

字段 类型 说明
id UUID 主键
user_id UUID FK → users
type VARCHAR(20) telegram
name VARCHAR(100) 渠道名称
is_enabled BOOLEAN 是否启用
created_at TIMESTAMP

用户的 TG Chat ID 和 TG 用户名存储在 users 表(tg_chat_id, tg_username),不在 notify_channels 重复存储。 notify_channels 预留 type 字段为将来扩展其他通知渠道(如 Email、Webhook 等)。

4.15 告警记录表 (alert_events)

字段 类型 说明
id UUID 主键
alert_rule_id UUID FK → alert_rules
server_id UUID FK → servers
metric_value REAL 触发时的值
status VARCHAR(20) firing / resolved
notified BOOLEAN 是否已通知
fired_at TIMESTAMP
resolved_at TIMESTAMP

4.16 备份记录表 (backup_records)

字段 类型 说明
id UUID 主键
server_id UUID FK → servers
file_key VARCHAR(255) S3 对象 key
file_size BIGINT 文件大小
encrypted BOOLEAN 是否加密
created_at TIMESTAMP

4.17 探针页面配置表 (probe_pages)

字段 类型 说明
id UUID 主键
user_id UUID FK → users,唯一
slug VARCHAR(50) 页面路径标识,唯一
title VARCHAR(100) 页面标题
description TEXT 页面描述
logo_url VARCHAR(500) Logo URL
favicon_url VARCHAR(500) Favicon URL
footer_text VARCHAR(200) 页脚自定义文字
footer_link_url VARCHAR(500) 页脚链接
footer_link_text VARCHAR(50) 页脚链接文字
theme_id VARCHAR(30) 主题 ID,见 13.7 探针页面主题
primary_color VARCHAR(7) 主色调覆盖,如 #3B82F6,NULL 使用主题默认
layout_columns INT 卡片网格列数,0 表示自适应
visible_components JSONB 显示组件配置,见下方说明
visible_server_ids UUID[] 可见的服务器 ID 列表
is_published BOOLEAN 是否发布
created_at TIMESTAMP
updated_at TIMESTAMP

visible_components 配置示例

{
  "cpu": { "show": true, "show_temp": true },
  "gpu": { "show": true, "show_temp": true, "show_memory": true },
  "memory": { "show": true, "show_percentage": true },
  "disk": { "show": true, "show_percentage": false },
  "network": { "show": true, "show_speed": true },
  "uptime": { "show": true, "format": "auto" },
  "tcping": { "show": true, "show_latency": true },
  "os_info": { "show": false },
  "tags": { "show": true },
  "network_speed": { "show": true }
}

5. 安全设计

5.1 零知识加密架构

核心原则:服务端永远不接触用户的明文密码和敏感配置

系统中有两种密码,用途完全独立:

密码类型 用途 存储方式
账号密码 登录认证 Argon2id hash 存 DB
加密密码 加解密客户端配置、备份凭证等 不存储,仅用户记忆

加密密码由用户独立设定,不一定是账号密码。用户可以使用相同或不同的密码。

┌─────────────────────────────────────────────────────────────┐
│                      账号密码体系                            │
│                                                             │
│  账号密码 ──→ Argon2id(密码, random_salt) ──→ password_hash │
│                                              [存储到 DB]    │
│                                              [用于登录验证]  │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                      加密密码体系                            │
│                                                             │
│  加密密码 ──→ HKDF-SHA256(密码, user_id+"enc") ──→ enc_key │
│                                                   [内存中]  │
│                        │                                    │
│           ┌────────────┴────────────┐                       │
│           │                         │                       │
│   加密 enc_key               加密配置数据                    │
│   AES-256-GCM(enc_key,      AES-256-GCM(enc_key,           │
│     random_config_key)        config_json)                  │
│           │                         │                       │
│   encrypted_config_key      encrypted_config                │
│     [存储到 DB]               [存储到 DB]                    │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                config_key 用途(解密后仅在内存)              │
│                                                             │
│  config_key ──→ 解密 servers.encrypted_config               │
│  config_key ──→ 解密 notify_channels.encrypted_config       │
│  config_key ──→ 解密备份配置中的凭证                         │
│  config_key ──→ 加密 Agent 安装配置                          │
└─────────────────────────────────────────────────────────────┘

5.2 密码与密钥流程

  1. 注册

    • 前端:password_hash = Argon2id(账号密码, random_salt) → 发送到服务端
    • 前端:enc_key = HKDF-SHA256(加密密码, user_id + "enc") → 仅存内存
    • 前端:生成随机 config_key32 字节),encrypted_config_key = AES-256-GCM(enc_key, config_key)
    • 发送 { username, password_hash, encrypted_config_key, config_key_nonce } 到服务端存储
    • 如果加密密码与账号密码相同,用户只需输入一次;不同则需分别输入
  2. 登录

    • 前端:password_hash = Argon2id(账号密码, random_salt) → 发送验证
    • 验证通过后返回 encrypted_config_key
    • 前端提示用户输入加密密码 → enc_key = HKDF-SHA256(加密密码, user_id + "enc")
    • 前端:config_key = AES-256-GCM-Decrypt(enc_key, encrypted_config_key)
    • config_key 存于前端内存(sessionStorage),后续所有配置加解密使用 config_key
  3. 配置加密

    • 用户输入敏感配置(TG Token、备份凭证、S3 AK/SK 等)
    • 前端:encrypted_config = AES-256-GCM(config_key, config_json)
    • 发送 { encrypted_config, nonce } 到服务端,服务端只存密文
  4. 一键安装命令生成

    • 用户在前端输入加密密码 → 派生 enc_key → 解密 config_key
    • 前端组装 Agent 配置(含 agent_token 等)
    • 前端:encrypted_agent_config = AES-256-GCM(config_key, agent_config_json)
    • 生成安装命令:curl ... | bash -s -- --token=xxx --encrypted-config=base64(...)
    • Agent 安装后首次连接时,需输入加密密码解密配置
    • 服务端不存储、不接触加密密码和 config_key
  5. 修改加密密码

    • 前端:输入旧加密密码 → 解密得到 config_key
    • 前端:输入新加密密码 → new_enc_key = HKDF-SHA256(新密码, user_id + "enc")
    • 前端:new_encrypted_config_key = AES-256-GCM(new_enc_key, config_key)
    • 发送 { new_encrypted_config_key, new_config_key_nonce } 到服务端更新
    • config_key 不变,所有已加密配置无需重新加密

5.3 客户端认证

  • 每台服务器生成唯一的 agent_token64 字节随机),非用户密码
  • gRPC 连接使用 TLS + agent_token 认证
  • agent_token 通过加密配置下发,服务端明文存储(它本身不是用户密码)

5.4 安全要点

项目 方案
账号密码 Argon2id 哈希,前端计算,服务端只存 hash
加密密码 不存储,仅用户记忆,用于派生 enc_key 解密 config_key
敏感配置 AES-256-GCM 加密,密钥为 config_key(由加密密码派生的 enc_key 保护)
通信加密 gRPC 强制 TLS 1.3
API 认证 JWT (RS256)Access Token 15min + Refresh Token 7d
限流 Redis 令牌桶,API 按用户限流
SQL 注入 ORM 参数化查询
XSS CSP Header + 输入过滤

6. gRPC 协议设计

6.1 Proto 定义

syntax = "proto3";
package statusprobe;

// ============ 客户端上报服务 ============
service AgentService {
  // 双向流:客户端上报指标,服务端可下发指令
  rpc ReportStream(stream ReportRequest) returns (stream ServerCommand);

  // 客户端拉取配置
  rpc FetchConfig(ConfigRequest) returns (AgentConfig);

  // 备份文件上传
  rpc UploadBackup(stream BackupChunk) returns (UploadBackupResponse);

  // 心跳(轻量级,用于保活检测)
  rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
}

// ============ 上报请求 ============
message ReportRequest {
  string agent_token = 1;
  oneof payload {
    SystemMetrics metrics = 2;
    TcpingResults tcping = 3;
    BackupResult backup_result = 4;
  }
}

message SystemMetrics {
  double cpu_usage = 1;
  int64 memory_total = 2;
  int64 memory_used = 3;
  int64 disk_total = 4;
  int64 disk_used = 5;
  int64 network_rx = 6;
  int64 network_tx = 7;
  double load_1 = 8;
  double load_5 = 9;
  double load_15 = 10;
  int64 uptime = 11;
  string os_info = 12;       // JSON: {os, arch, kernel}
  int32 process_count = 13;
  double cpu_temp = 14;      // CPU 温度 ℃,-1 表示不支持
  repeated GpuInfo gpus = 15; // GPU 信息列表
}

message GpuInfo {
  string name = 1;           // GPU 名称,如 "NVIDIA RTX 4090"
  double temp = 2;           // GPU 温度 ℃,-1 表示不支持
  double usage = 3;          // GPU 使用率 %
  int64 memory_total = 4;    // 显存总量 MB
  int64 memory_used = 5;     // 显存已用 MB
}

message TcpingResult {
  string target_host = 1;
  int32 target_port = 2;
  double latency_ms = 3;     // -1 = timeout
  bool success = 4;
}

message TcpingResults {
  repeated TcpingResult results = 1;
}

// ============ 服务端下发指令 ============
message ServerCommand {
  oneof command {
    ConfigUpdateCommand config_update = 1;   // 配置变更通知
    RestartCommand restart = 2;              // 重启客户端
    BackupCommand backup = 3;                // 触发备份
    TcpingUpdateCommand tcping_update = 4;   // TCPing 节点更新
  }
}

message ConfigUpdateCommand {
  string config_version = 1;  // 配置版本号,客户端拉取新配置
}

message RestartCommand {}

message BackupCommand {
  string backup_id = 1;
}

message TcpingUpdateCommand {
  repeated TcpingTarget targets = 1;
}

message TcpingTarget {
  string host = 1;
  int32 port = 2;
}

// ============ 配置拉取 ============
message ConfigRequest {
  string agent_token = 1;
  string current_config_version = 2;  // 客户端当前配置版本
}

message AgentConfig {
  string config_version = 1;
  int32 report_interval_seconds = 2;       // 上报频率
  int32 tcping_interval_seconds = 3;       // TCPing 检测频率
  repeated TcpingTarget tcping_targets = 4; // TCPing 目标节点
  BackupConfig backup_config = 5;          // 备份配置
  bool config_changed = 6;                 // 配置是否有变更
}

message BackupConfig {
  bool enabled = 1;
  int32 interval_hours = 2;       // 备份间隔
  int32 max_count = 3;            // 最大保留数
  string encrypted_config_json = 4;  // 加密的完整备份配置 JSON(含 repos、tasks 等)
}

// ============ 备份上传 ============
message BackupChunk {
  string agent_token = 1;
  string backup_id = 2;
  string filename = 3;
  bytes data = 4;
  int64 total_size = 5;
  bool is_last = 6;
}

message UploadBackupResponse {
  bool success = 1;
  string file_key = 2;
  string message = 3;
}

// ============ 心跳 ============
message HeartbeatRequest {
  string agent_token = 1;
}

message HeartbeatResponse {
  bool ok = 1;
  string config_version = 2;  // 附带当前配置版本,客户端可判断是否需要拉取
}

6.2 通信流程

Agent 启动
    │
    ├─→ FetchConfig(agent_token, "") ──→ 获取完整配置
    │                                    └─→ 缓存到本地
    │
    ├─→ ReportStream (双向流)
    │     │
    │     ├─→ 定时发送 SystemMetrics (按 report_interval)
    │     ├─→ 定时发送 TcpingResults (按 tcping_interval)
    │     │
    │     └─← 接收 ServerCommand
    │           ├─← ConfigUpdateCommand → 重新 FetchConfig
    │           ├─← BackupCommand → 执行备份 → UploadBackup
    │           ├─← TcpingUpdateCommand → 更新 TCPing 目标
    │           └─← RestartCommand → 重启自身
    │
    └─→ Heartbeat (每 30s,当 ReportStream 断开时使用)

6.3 配置缓存机制

服务端:
  用户修改配置 → 写入 DB → 更新 Redis 缓存 (key: config:{server_id}, version 递增)
  Agent 请求配置 → 读 Redis 缓存 → 返回 (未命中则查 DB 并回填)

Redis 缓存结构:
  config:{server_id}       → AgentConfig protobuf 序列化
  config_version:{server_id} → 版本号 (递增整数)
  tcping_nodes:default     → 默认 TCPing 节点列表
  tcping_nodes:{user_id}   → 用户自定义 TCPing 节点

7. REST API 设计

7.1 认证模块

方法 路径 说明
POST /api/v1/auth/register 注册
POST /api/v1/auth/login 登录
POST /api/v1/auth/refresh 刷新 Token
POST /api/v1/auth/logout 登出
POST /api/v1/auth/send-code 发送邮箱验证码
POST /api/v1/auth/verify-email 验证邮箱
POST /api/v1/auth/reset-password 重置密码(需邮箱验证码)

注册请求示例

{
  "username": "alice",
  "password_hash": "argon2id$...",       // 前端 Argon2id 计算
  "email": "alice@example.com",          // 可选,取决于系统配置
  "email_code": "123456",                // 邮箱验证码(email_verify_enabled 时必填)
  "captcha_token": "...",                // 验证码 tokencaptcha_enabled 时必填)
  "encrypted_config_key": "base64...",   // AES-256-GCM(enc_key, config_key)
  "config_key_nonce": "base64..."
}

登录请求示例

{
  "username": "alice",
  "password_hash": "argon2id$...",
  "captcha_token": "..."                 // login_captcha_enabled 时必填
}

登录响应示例

{
  "access_token": "jwt...",
  "refresh_token": "jwt...",
  "user_id": "uuid",
  "encrypted_config_key": "base64...",
  "config_key_nonce": "base64..."
}

发送邮箱验证码

// 请求
{
  "email": "alice@example.com",
  "purpose": "register"     // register / bind / rebind / reset_password
}

// 响应
{
  "message": "验证码已发送"
}

注册流程(根据系统配置动态变化)

captcha_enabled?
  ├─ Yes → 前端展示验证码 → 验证通过后允许提交
  └─ No  → 直接下一步

email_verify_enabled?
  ├─ Yes → 先 send-code → 用户输入验证码 → 一起提交注册
  └─ No  → 邮箱可选填

register_enabled?
  ├─ Yes → 正常注册
  └─ No  → 返回 "注册已关闭"

7.2 用户账号模块

方法 路径 说明
GET /api/v1/user/profile 获取个人信息
PUT /api/v1/user/profile 更新个人信息(头像等)
PUT /api/v1/user/password 修改账号密码
PUT /api/v1/user/encryption-password 修改加密密码(重新加密 config_key)
POST /api/v1/user/bind-email 绑定邮箱
POST /api/v1/user/rebind-email 换绑邮箱(需旧邮箱验证码 + 新邮箱验证码)
POST /api/v1/user/resend-verify 重发邮箱验证
GET /api/v1/user/tg-bind-info 获取 TG 绑定状态和绑定链接
POST /api/v1/user/unbind-tg 解绑 TG
PUT /api/v1/user/preferences 更新用户偏好(剩余价值显示、TG 通知开关等)

绑定邮箱

{
  "email": "new@example.com",
  "code": "123456"
}

换绑邮箱

{
  "new_email": "new@example.com",
  "new_email_code": "123456",
  "old_email_code": "654321"            // 旧邮箱验证码确认身份
}

修改账号密码

{
  "old_password_hash": "argon2id$...",           // 旧密码哈希
  "new_password_hash": "argon2id$..."            // 新密码哈希
}

修改加密密码

{
  "new_encrypted_config_key": "base64...",       // 用新加密密码派生的 enc_key 重新加密 config_key
  "new_config_key_nonce": "base64..."
}

TG 绑定信息

// 响应
{
  "is_bound": true,
  "tg_username": "@alice",
  "bound_at": "2026-06-20T10:00:00Z",
  "bind_url": "https://t.me/StatusProbeBot?start=bind_abc123"  // 未绑定时返回,用户点击链接打开 TG
}

TG 绑定流程

1. 用户点击 "绑定 TG" → 前端调用 GET /api/v1/user/tg-bind-info
2. 返回 bind_url → 用户点击链接,打开 TG 与 Bot 对话
3. Bot 收到 /start bind_abc123 → 调用服务端回调 API 确认绑定
4. 服务端更新 users.tg_chat_id 和 tg_username
5. 前端轮询或 WebSocket 通知绑定成功

更新用户偏好

{
  "show_remaining_value": false,       // 关闭剩余价值显示
  "tg_notify_enabled": true            // 开启 TG 通知(需先绑定 TG)
}

7.3 套餐模块

方法 路径 说明
GET /api/v1/plans 套餐列表(公开)
GET /api/v1/plans/:id 套餐详情
POST /api/v1/admin/plans 创建套餐 (Admin)
PUT /api/v1/admin/plans/:id 更新套餐 (Admin)
DELETE /api/v1/admin/plans/:id 归档套餐 (Admin)

7.4 订阅与支付

方法 路径 说明
POST /api/v1/subscriptions/purchase 购买套餐
POST /api/v1/subscriptions/upgrade 升级套餐
GET /api/v1/subscriptions/current 当前订阅
GET /api/v1/subscriptions/history 订阅历史
POST /api/v1/redeem 兑换码兑换

升级逻辑

  • 计算剩余价值 = 原套餐价格 × (剩余天数 / 总天数)
  • 差价 = 新套餐价格 - 剩余价值
  • 差价 ≤ 0 时不收费,直接升级
  • 永久套餐不可升级(已是最高)

7.5 兑换码模块 (Admin)

方法 路径 说明
POST /api/v1/admin/redeem-codes/generate 批量生成兑换码
GET /api/v1/admin/redeem-codes 兑换码列表
DELETE /api/v1/admin/redeem-codes/:id 禁用兑换码

生成请求

{
  "plan_id": "uuid",
  "billing_type": "monthly",
  "count": 10,
  "max_use_count": 1,
  "expires_at": "2026-12-31T23:59:59Z"
}

7.6 服务器管理

方法 路径 说明
GET /api/v1/servers 服务器列表
POST /api/v1/servers 添加服务器
PUT /api/v1/servers/:id 更新服务器信息
DELETE /api/v1/servers/:id 删除服务器
GET /api/v1/servers/:id/metrics 获取指标数据
GET /api/v1/servers/:id/tcping 获取 TCPing 数据
POST /api/v1/servers/:id/install-command 生成安装命令(需前端传入密码解密)
PUT /api/v1/servers/:id/config 更新客户端配置(加密存储)

添加服务器

{
  "name": "HK-01",
  "display_name": "香港节点1",
  "region": "HK",
  "tags": ["production", "cdn"],
  "encrypted_config": "base64...",
  "config_nonce": "base64..."
}

生成安装命令

// 请求
{
  "password_hash": "argon2id$...",           // 用于派生 master_key
  "encrypted_master_key_verify": "base64..." // 前端用 master_key 加密一段已知文本验证密码正确
}

// 响应
{
  "install_command": "curl -sL https://status.example.com/install.sh | bash -s -- --token=abc123 --encrypted-config=base64...",
  "agent_token": "abc123..."
}

7.7 监控与告警

方法 路径 说明
GET /api/v1/alert-rules 告警规则列表
POST /api/v1/alert-rules 创建告警规则
PUT /api/v1/alert-rules/:id 更新告警规则
DELETE /api/v1/alert-rules/:id 删除告警规则
GET /api/v1/alert-events 告警事件列表

7.8 通知渠道

方法 路径 说明
GET /api/v1/notify-channels 通知渠道列表
POST /api/v1/notify-channels 添加通知渠道(配置加密存储)
PUT /api/v1/notify-channels/:id 更新通知渠道
DELETE /api/v1/notify-channels/:id 删除通知渠道
POST /api/v1/notify-channels/:id/test 测试通知

7.9 备份管理

方法 路径 说明
GET /api/v1/servers/:id/backups 备份列表
POST /api/v1/servers/:id/backups/trigger 手动触发备份
GET /api/v1/backups/:id/download 下载备份
DELETE /api/v1/backups/:id 删除备份

7.10 探针页面

方法 路径 说明
GET /api/v1/probe-page 获取自己的探针页面配置
PUT /api/v1/probe-page 更新探针页面配置
GET /probe/{slug} 公开探针页面 (SSR)

7.11 安装向导

首次部署时的安装流程,用于配置数据库、Redis(可选)、管理员账号。安装完成后锁定。

方法 路径 说明
GET /install 安装页面 (SSR)
GET /api/v1/install/status 检查系统是否已安装
POST /api/v1/install/database 配置数据库连接
POST /api/v1/install/redis 配置 Redis 连接(可选)
POST /api/v1/install/admin 创建管理员账号
POST /api/v1/install/complete 完成安装,锁定安装入口
GET /api/v1/install/test-db 测试数据库连接
GET /api/v1/install/test-redis 测试 Redis 连接(可选)

安装状态检查响应

{
  "installed": false,           // true 表示已安装,锁定所有安装 API
  "step": "database",           // 当前步骤:database / redis / admin / complete
  "database_type": null,        // 已配置的数据库类型:postgres / sqlite
  "redis_enabled": null         // 是否已配置 Redis
}

配置数据库请求

{
  "type": "sqlite",             // postgres 或 sqlite
  // SQLite 模式无需额外参数,数据文件默认存于 ./data/statusprobe.db
  // PostgreSQL 模式需要以下参数:
  "host": "localhost",          // PostgreSQL 参数(type=postgres 时必填)
  "port": 5432,
  "database": "statusprobe",
  "username": "postgres",
  "password": "secret",
  "ssl_mode": "disable"         // disable / require / verify-ca / verify-full
}

配置 Redis 请求(可选):

{
  "enabled": false,             // false 表示不使用 Redis,使用内存缓存
  "host": "localhost",          // enabled=true 时必填
  "port": 6379,
  "password": "",               // 可选
  "db": 0                       // 可选,默认 0
}

创建管理员账号请求

{
  "username": "admin",
  "password_hash": "argon2id$...",
  "email": "admin@example.com",    // 可选
  "encrypted_config_key": "base64...",
  "config_key_nonce": "base64..."
}

安装流程

用户访问 /install
    │
    ├─ GET /api/v1/install/status → 已安装? → 重定向到 /login
    │
    ├─ 步骤 1: 选择数据库类型
    │     ├─ SQLite → 直接 POST /api/v1/install/database (type=sqlite)
    │     ├─ PostgreSQL → 输入连接参数 → GET /api/v1/install/test-db 测试 → POST 配置
    │
    ├─ 步骤 2: Redis 配置(可选)
    │     ├─ 跳过 → POST /api/v1/install/redis (enabled=false)
    │     ├─ 配置 → 输入参数 → GET /api/v1/install/test-redis 测试 → POST 配置
    │
    ├─ 步骤 3: 创建管理员账号
    │     └─ POST /api/v1/install/admin
    │
    └─ 步骤 4: 完成安装
          └─ POST /api/v1/install/complete
              ├─ 写入 config.yaml(数据库、Redis 配置)
              ├─ 初始化数据库表(迁移)
              ├─ 创建默认套餐(Free 套餐)
              ├─ 设置 installed=true(写入 system_settings 或配置文件)
              └─ 重定向到 /login

安全要点

  • 安装完成后,所有 /api/v1/install/* API 返回 403 Forbidden
  • installed 状态存储在配置文件 config.yamlsystem_settings
  • 安装页面仅在 installed=false 时可访问
  • 管理员账号创建时自动设置 role=admin

7.12 管理员接口

7.12.1 用户管理

方法 路径 说明
GET /api/v1/admin/users 用户列表
PUT /api/v1/admin/users/:id 更新用户(禁用/启用/改角色)
DELETE /api/v1/admin/users/:id 删除用户

7.12.2 系统设置

方法 路径 说明
GET /api/v1/admin/settings 获取所有系统设置
GET /api/v1/admin/settings/:category 按分类获取设置 (general/smtp/payment/security/telegram)
PUT /api/v1/admin/settings 批量更新系统设置
PUT /api/v1/admin/settings/:key 更新单个设置项
POST /api/v1/admin/settings/test-smtp 测试 SMTP 发送
POST /api/v1/admin/settings/test-payment/:channel 测试支付通道连通性
POST /api/v1/admin/settings/test-tg-bot 测试 TG Bot 连通性
POST /api/v1/admin/settings/set-tg-webhook 设置 TG Bot Webhook

批量更新设置请求

{
  "settings": [
    {
      "key": "site_name",
      "value": "MyStatus"
    },
    {
      "key": "smtp_host",
      "value": "smtp.example.com"
    },
    {
      "key": "smtp_password",
      "value": "new_password"           // is_encrypted=true 的字段,服务端用系统密钥加密后存储
    },
    {
      "key": "captcha_enabled",
      "value": "true"
    }
  ]
}

测试 SMTP 请求

{
  "recipient": "test@example.com"        // 发送测试邮件到此地址
}

测试 SMTP 响应

{
  "success": true,
  "message": "测试邮件已发送",
  "latency_ms": 1250
}

7.12.3 支付管理

方法 路径 说明
GET /api/v1/admin/payment-orders 支付订单列表
GET /api/v1/admin/payment-orders/:id 订单详情
POST /api/v1/admin/payment-orders/:id/refund 退款
GET /api/v1/admin/payment-stats 支付统计(收入/订单数)

7.12.4 TCPing 节点管理

方法 路径 说明
GET /api/v1/admin/tcping-nodes TCPing 节点列表
POST /api/v1/admin/tcping-nodes 添加 TCPing 节点
PUT /api/v1/admin/tcping-nodes/:id 更新节点
DELETE /api/v1/admin/tcping-nodes/:id 删除节点

7.12.5 系统统计

方法 路径 说明
GET /api/v1/admin/stats 系统概览统计
GET /api/v1/admin/stats/realtime 实时在线 Agent 数

系统统计响应

{
  "total_users": 1250,
  "active_users": 890,
  "total_servers": 3200,
  "online_servers": 2800,
  "total_orders": 5600,
  "total_revenue": 125000.00,
  "active_subscriptions": 780
}

7.13 支付回调接口

方法 路径 说明
POST /api/v1/payment/notify/alipay 支付宝异步通知
POST /api/v1/payment/notify/wechat 微信支付异步通知
POST /api/v1/payment/notify/stripe Stripe Webhook

这些接口无需 JWT 认证,但需验证第三方签名

7.14 Telegram Bot Webhook

方法 路径 说明
POST /api/v1/tg/webhook TG Bot Webhook 回调(用户绑定、命令响应)

此接口由 Telegram 服务器调用,无需 JWT 认证,需验证 Bot Token 签名

TG Bot 支持的交互

用户操作 Bot 响应
点击绑定链接 /start bind_{token} 确认绑定成功,返回欢迎消息
发送 /status 返回用户所有服务器当前状态摘要
发送 /help 返回可用命令列表
告警触发时 Bot 主动推送告警消息到用户 Chat

8. 客户端 (Agent) 设计

agent/
├── main.go              # 入口,解析参数
├── config/
│   ├── config.go        # 配置管理(本地缓存 + 远程拉取)
│   └── cache.go         # 本地文件缓存
├── collector/
│   ├── system.go        # 系统指标采集 (CPU/Mem/Disk/Net/Load)
│   ├── temp.go          # 温度采集 (CPU/GPU 温度)
│   ├── gpu.go           # GPU 指标采集 (NVIDIA-SMI / rocm-smi)
│   ├── tcping.go        # TCPing 检测
│   └── process.go       # 进程信息采集
├── reporter/
│   ├── grpc.go          # gRPC 连接管理、重连
│   └── stream.go        # 上报流管理
├── backup/
│   ├── scheduler.go     # 备份调度
│   ├── restic.go        # Restic 封装 (init/backup/forget/prune)
│   ├── rclone.go        # Rclone 桥接 (FTP/WebDAV 适配器)
│   ├── task_runner.go   # 任务执行器 (folder/database/docker)
│   ├── docker.go        # Docker 备份逻辑
│   ├── database.go      # 数据库备份逻辑
│   ├── pre_post.go      # pre/post command 执行
│   ├── repo_manager.go  # 多仓库管理
│   ├── config_cache.go  # 备份配置解密与缓存
│   └── uploader.go      # gRPC 分片上传 (仅 local 类型)
├── crypto/
│   └── decrypt.go       # 配置解密(使用 server_key
└── selfupdate/
    └── update.go        # 自更新(可选)

8.2 启动流程

1. 解析命令行参数 (--token, --encrypted-config, --server-addr)
2. 用 server_key 解密 encrypted-config → 获取初始配置
3. 连接 gRPC 服务端 (TLS)
4. FetchConfig → 获取完整配置(覆盖本地缓存)
5. 启动采集协程:
   - SystemCollector (按 report_interval)
   - TcpingCollector (按 tcping_interval, 目标从配置获取)
   - BackupScheduler (按 backup_config)
6. 建立 ReportStream 双向流
7. 监听 ServerCommand
8. 启动 Heartbeat 保活

8.3 一键安装脚本

#!/bin/bash
# install.sh

AGENT_VERSION="1.0.0"
SERVER_ADDR="${1}"
AGENT_TOKEN="${2}"
ENCRYPTED_CONFIG="${3}"

# 检测架构
ARCH=$(uname -m)
case $ARCH in
  x86_64)  BINARY="statusprobe-agent-amd64" ;;
  aarch64) BINARY="statusprobe-agent-arm64" ;;
  *)       echo "Unsupported architecture"; exit 1 ;;
esac

# 下载
curl -sL "https://github.com/yourorg/statusprobe/releases/download/v${AGENT_VERSION}/${BINARY}" \
  -o /usr/local/bin/statusprobe-agent
chmod +x /usr/local/bin/statusprobe-agent

# 创建配置目录
mkdir -p /etc/statusprobe

# 写入加密配置
echo "${ENCRYPTED_CONFIG}" | base64 -d > /etc/statusprobe/encrypted_config.bin

# 创建 systemd service
cat > /etc/systemd/system/statusprobe.service << EOF
[Unit]
Description=StatusProbe Agent
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/statusprobe-agent \\
  --server-addr=${SERVER_ADDR} \\
  --token=${AGENT_TOKEN} \\
  --config-file=/etc/statusprobe/encrypted_config.bin
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable statusprobe
systemctl start statusprobe

echo "StatusProbe Agent installed and started!"

8.4 客户端资源限制

指标 限制
内存占用 ≤ 30MB
CPU 占用 ≤ 1% (空闲时)
网络流量 ≤ 1MB/hour (仅上报)
二进制大小 ≤ 15MB

9. 探针页面设计

9.1 页面结构

/probe/{slug}
├── 顶部: Logo + 标题 + 描述
├── 服务器卡片网格
│   ├── 服务器名称 + 地区标签
│   ├── 状态指示灯 (绿/红/灰)
│   ├── CPU 使用率 + 温度 (如: 45% / 62℃)
│   ├── GPU 卡片 (如有GPU: 名称 + 使用率 + 温度 + 显存,如: RTX 4090 45% / 65℃ / 8G/24G)
│   ├── 内存进度条
│   ├── 磁盘进度条
│   ├── 网络速度 (↑↓)
│   ├── 运行时间
│   └── TCPing 延迟 (展开)
└── 底部: Powered by StatusProbe

9.2 主题与组件自定义

9.2.1 内置主题

所有主题由服务端预置,前端只引用主题 ID,零安全风险

主题 ID 名称 风格 预览
default 经典 白底蓝调,圆角卡片,默认主题 ☁️
dark 暗夜 深色背景,护眼低对比 🌙
gruvbox Gruvbox 暖色调复古,米色底 + 橙红强调 🍂
catppuccin Catppuccin Mocha 柔和深色,粉蓝紫渐变 🌸
nord Nord 北极冷色调,蓝灰白 ❄️
solarized Solarized 经典 Solarized,黄底 + 蓝强调 ☀️
sakura 樱花 粉白渐变,日系清新 🌸
cyberpunk 赛博朋克 黑底霓虹,紫青黄高饱和 🎮
glass 毛玻璃 半透明卡片 + 模糊背景 🪟
minimal 极简 无边框无阴影,纯文字排版 📄

主题以 CSS 变量实现,切换主题只改变 CSS 变量值,不加载外部资源。

主题 CSS 变量体系

:root[data-theme="default"] {
  --sp-bg-page: #FFFFFF;
  --sp-bg-card: #FAFAFA;
  --sp-bg-card-hover: #F5F5F5;
  --sp-text-primary: #1E1E1E;
  --sp-text-secondary: #5C5C5C;
  --sp-text-muted: #909090;
  --sp-border: #E0E0E0;
  --sp-accent: #3B82F6;
  --sp-accent-hover: #2563EB;
  --sp-success: #10B981;
  --sp-warning: #F59E0B;
  --sp-error: #EF4444;
  --sp-radius: 8px;
  --sp-shadow: 0 1px 3px rgba(0,0,0,0.08);
  --sp-font: 'Inter', -apple-system, sans-serif;
}

用户可通过 primary_color 覆盖主题默认强调色,仅限合法 HEX 值 #[0-9a-fA-F]{6}

9.2.2 组件显示配置

用户在后台通过开关选择显示哪些组件,配置存储在 visible_components JSONB 中:

┌──────────────────────────────────────────────────────┐
│  探针页面配置面板                                      │
│                                                      │
│  📊 指标组件                                          │
│  ┌──────────────────────────────────────────────────┐│
│  │ ☑ CPU 使用率    ☑ CPU 温度                        ││
│  │ ☑ GPU 使用率    ☑ GPU 温度    ☑ GPU 显存          ││
│  │ ☑ 内存使用率    ☐ 内存百分比                       ││
│  │ ☑ 磁盘使用率    ☐ 磁盘百分比                       ││
│  │ ☑ 网络流量      ☑ 实时网速                         ││
│  │ ☑ 运行时间      ☐ 系统信息                         ││
│  └──────────────────────────────────────────────────┘│
│                                                      │
│  🌐 TCPing                                           │
│  ┌──────────────────────────────────────────────────┐│
│  │ ☑ 显示 TCPing    ☑ 显示延迟值                     ││
│  └──────────────────────────────────────────────────┘│
│                                                      │
│  🏷️ 其他                                             │
│  ┌──────────────────────────────────────────────────┐│
│  │ ☑ 显示标签                                       ││
│  └──────────────────────────────────────────────────┘│
└──────────────────────────────────────────────────────┘

9.2.3 页面基础配置

配置项 类型 限制
页面标题 文本 ≤ 100 字符
页面描述 文本 ≤ 500 字符
Logo URL 必须 https:// 开头,≤ 500 字符
Favicon URL 必须 https:// 开头,≤ 500 字符
页脚文字 文本 ≤ 200 字符,纯文本无 HTML
页脚链接 URL 必须 https:// 开头
布局列数 数字 0-60 自适应
可见服务器 多选 从用户已添加的服务器中勾选

9.2.4 安全保障

措施 说明
无自定义 JS 彻底杜绝 XSS、Cookie 窃取、挖矿等攻击
无自定义 CSS 杜绝 CSS 注入、数据外泄(url())、UI 覆盖
主题服务端预置 主题文件由开发者维护,用户只选 ID
URL 白名单 Logo/Favicon/链接仅允许 https:// 开头
文本纯文本 页脚等文本区域不解析 HTML
primary_color 校验 严格匹配 #[0-9a-fA-F]{6} 正则
visible_components 校验 服务端校验 JSONB 结构,忽略未知字段

9.3 实时更新

  • 公开页面使用 SSE (Server-Sent Events) 推送指标更新
  • 频率:每 5s 推送一次增量数据
  • 优势:SSE 基于 HTTP,天然兼容代理/CDN,自动重连,单向推送无需双向通信
  • 降级:SSE 不可用时,轮询 REST API

10. 告警与通知

10.1 告警流程

指标上报 → 滑动窗口评估 → 触发告警规则
    │
    ├─→ 首次触发 → 创建 alert_event (firing) → 尝试通知
    │
    ├─→ 持续触发 → 检查 cooldown → 跳过通知
    │
    └─→ 恢复正常 → 更新 alert_event (resolved) → 尝试通知恢复

通知前置条件检查

用户触发告警
  │
  ├─ 用户 preference_tg_notify_enabled == false → 跳过通知
  │
  ├─ 用户 tg_chat_id == NULL (未绑定 TG) → 跳过通知
  │
  ├─ 系统设置 tg_bot_enabled == false → 跳过通知
  │
  ├─ 系统设置 tg_notify_enabled == false → 跳过通知
  │
  └─ 全部通过 → 通过系统 Bot 发送 TG 通知

10.2 Telegram 通知模板

🔴 [告警] HK-01 CPU 使用率过高
服务器: HK-01 (香港)
指标: CPU 使用率
当前值: 95.2%
阈值: > 90%
持续时间: 5 分钟
时间: 2026-06-22 10:30:00 UTC

---
🟢 [恢复] HK-01 CPU 使用率恢复正常
当前值: 45.3%
时间: 2026-06-22 10:35:00 UTC

11. 定时备份设计

11.1 技术选型:Restic

对比项 Restic Rclone
增量备份 原生支持(内容寻址去重) 仅同步,非真正增量
加密 内置 AES-256-CTR + Poly1305 需外层加密或依赖存储端
去重 块级去重,相同内容只存一份 无去重
一致性快照 原子快照,支持并发读写安全 直接同步文件,可能不一致
数据库支持 pre-command 做 dump 后备份 需手动 dump
存储后端 S3/Local/SFTP/B2 等 40+ 云存储后端
资源占用 低,默认限速限并发 中等
成熟度 备份领域成熟 同步领域成熟

结论:选择 Restic。Restic 天然支持增量、去重、加密、原子快照,与本项目需求完全匹配。Rclone 更适合文件同步而非备份。

11.2 备份类型与策略

文件夹备份

用户配置: /data, /etc/myapp
Restic 命令: restic backup /data /etc/myapp
特点: 块级去重 + 增量,仅传输变更块

Docker 备份

1. 枚举运行中容器: docker ps --format '{{.Names}}'
2. 按用户配置过滤(容器名/标签)
3. 逐容器执行:
   a. docker commit {container} {container}:backup-snapshot   # 创建容器文件系统快照
   b. docker save {container}:backup-snapshot | restic backup --stdin --stdin-filename {container}.tar
   c. docker rmi {container}:backup-snapshot                  # 清理临时镜像
4. 可选: 备份 docker-compose.yml 和环境文件
   restic backup /opt/docker/ --include=docker-compose*.yml --include=.env

数据库备份

1. MySQL/MariaDB:
   mysqldump --all-databases --single-transaction --quick | \
     restic backup --stdin --stdin-filename mysql_all.sql

2. PostgreSQL:
   pg_dumpall -U postgres | \
     restic backup --stdin --stdin-filename pg_all.sql

3. MongoDB:
   mongodump --archive | \
     restic backup --stdin --stdin-filename mongo_all.archive

4. Redis:
   redis-cli BGSAVE && \
   restic backup /var/lib/redis/dump.rdb

11.3 运行期间数据一致性

场景 方案 说明
普通文件 Restic 原生快照 Restic 读取文件时使用并发安全策略,读到的是快照时刻的状态
数据库 pre-command dump 先 dump 到 stdout 通过管道送入 restic backup --stdin,避免锁表
Docker 容器 docker commit commit 是 CoW 快照,不暂停容器,写入时复制保证一致性
SQLite 等嵌入式 开启 WAL 模式 restic 备份 WAL + 主库文件,恢复后自动 replay

核心原则:对于有状态服务,永远使用 pre-command 做一致性导出,而非直接备份运行时文件。

11.4 备份配置模型

{
  "enabled": true,
  "interval_hours": 6,
  "max_count": 14,
  "retention_policy": {
    "keep_last": 7,
    "keep_daily": 14,
    "keep_weekly": 4,
    "keep_monthly": 6
  },
  "repos": [
    {
      "name": "s3-backup",
      "type": "s3",
      "s3_config": {
        "endpoint": "s3.amazonaws.com",
        "bucket": "my-backups",
        "prefix": "server-hk01",
        "access_key": "AKIA...",
        "secret_key": "wJalr...",
        "region": "us-east-1",
        "use_path_style": false
      },
      "backup_tasks": [ "..." ]
    },
    {
      "name": "ftp-backup",
      "type": "ftp",
      "ftp_config": {
        "host": "ftp.example.com",
        "port": 21,
        "username": "backup",
        "password": "s3cret",
        "path": "/backups/server-hk01"
      },
      "backup_tasks": [ "..." ]
    },
    {
      "name": "sftp-backup",
      "type": "sftp",
      "sftp_config": {
        "host": "sftp.example.com",
        "port": 22,
        "username": "backup",
        "password": "",
        "private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...",
        "private_key_password": "",
        "path": "/backups/server-hk01",
        "host_key": "ssh-ed25519 AAAA..."
      },
      "backup_tasks": [ "..." ]
    },
    {
      "name": "webdav-backup",
      "type": "webdav",
      "webdav_config": {
        "url": "https://dav.example.com/backups/server-hk01",
        "username": "backup",
        "password": "s3cret",
        "tls_skip_verify": false
      },
      "backup_tasks": [ "..." ]
    }
  ],
  "backup_tasks": [
    {
      "name": "web-data",
      "type": "folder",
      "paths": ["/data/www", "/data/logs"],
      "exclude": ["*.tmp", "*.log"],
      "pre_command": "",
      "post_command": ""
    },
    {
      "name": "mysql-dump",
      "type": "database",
      "db_type": "mysql",
      "pre_command": "mysqldump --all-databases --single-transaction -u root -p${DB_PASS}",
      "stdin_filename": "mysql_all.sql",
      "post_command": ""
    },
    {
      "name": "app-containers",
      "type": "docker",
      "containers": ["web-app", "api-server"],
      "backup_compose": true,
      "compose_paths": ["/opt/docker/"]
    }
  ]
}

整个配置 JSON 通过 server_key 加密后存储在服务端 servers.encrypted_config 中。 Agent 启动时通过 FetchConfig 拉取加密配置 → 用 server_key 解密 → 缓存到本地内存和文件。 后续备份任务直接使用本地缓存,避免每次执行都请求服务端。服务端配置变更时通过 ServerCommand 通知 Agent 重新拉取并刷新缓存。

11.5 Agent 备份模块架构

agent/
├── backup/
│   ├── scheduler.go        # 备份调度(定时触发)
│   ├── restic.go           # Restic 封装(init/backup/forget/prune
│   ├── rclone.go           # Rclone 桥接(FTP/WebDAV 适配器)
│   ├── task_runner.go      # 任务执行器(folder/database/docker 三种类型)
│   ├── docker.go           # Docker 备份逻辑(commit/save/cleanup
│   ├── database.go         # 数据库备份逻辑(dump via stdin
│   ├── pre_post.go         # pre/post command 执行
│   ├── repo_manager.go     # 多仓库管理
│   ├── config_cache.go     # 备份配置解密与缓存
│   └── uploader.go         # gRPC 分片上传(仅 local 类型需要)

11.6 备份执行流程

定时触发 / 服务端手动触发
    │
    ├─→ 1. 拉取最新备份配置(从服务端缓存)
    │
    ├─→ 2. 遍历 repos,逐 repo 执行
    │       │
    │       ├─→ 2a. 检查 repo 是否已初始化 (restic cat config)
    │       │    未初始化 → restic init (密码从配置解密获取)
    │       │
    │       ├─→ 2b. 遍历 backup_tasks,逐 task 执行
    │       │    │
    │       │    ├─→ [folder]  restic backup {paths} --exclude={exclude}
    │       │    │
    │       │    ├─→ [database] pre_command | restic backup --stdin --stdin-filename={name}
    │       │    │
    │       │    ├─→ [docker]  commit → save → restic backup --stdin → 清理临时镜像
    │       │    │
    │       │    └─→ 记录任务结果(成功/失败/大小/耗时)
    │       │
    │       ├─→ 2c. 执行保留策略: restic forget {policy} --prune
    │       │
    │       └─→ 2d. 上报备份结果到服务端 (gRPC)
    │
    └─→ 3. 所有 repo 完成后,汇总上报

11.7 存储后端类型

Restic 原生支持 S3/SFTPFTP 和 WebDAV 通过 rclone serve restic 适配:

仓库类型 Agent 行为 数据流向 适配方式
S3 (推荐) restic 直接读写 S3 Agent → S3 Restic 原生 rest 后端
SFTP restic 直接读写 SFTP Agent → SFTP 服务器 Restic 原生 sftp 后端
FTP rclone serve restic → restic 通过本地 HTTP Agent → rclone → FTP rclone 桥接
WebDAV rclone serve restic → restic 通过本地 HTTP Agent → rclone → WebDAV rclone 桥接

FTP/WebDAV 桥接原理

┌──────────┐    HTTP     ┌──────────────┐    FTP/WebDAV    ┌────────────┐
│  Restic  │ ──────────→ │ rclone serve │ ──────────────→ │ Remote     │
│  backup  │  localhost  │  restic      │  protocol       │ Storage    │
└──────────┘  :XXXX     └──────────────┘                  └────────────┘
  1. Agent 从解密后的配置中获取 FTP/WebDAV 参数
  2. 启动 rclone serve restic 子进程,监听本地随机端口,配置对应的远程存储
  3. Restic 使用 rest:http://localhost:XXXX/repo 作为仓库地址
  4. 所有数据经 rclone 透明传输到远程 FTP/WebDAV 存储
  5. rclone 进程随 Agent 退出自动清理

各存储后端配置参数(解密后明文,仅存在 Agent 内存中)

后端 必需参数 可选参数
S3 endpoint, bucket, prefix, access_key, secret_key region, use_path_style, tls_skip_verify
SFTP host, port, username, path password, private_key, private_key_password, host_key
FTP host, port, username, password, path tls_enabled (FTPS)
WebDAV url, username, password tls_skip_verify

所有参数均通过 server_key 加密存储在服务端,Agent 拉取后解密并缓存到本地,仅存于内存中。Restic 仓库密码同理。

11.8 备份安全

项目 方案
仓库密码 用户在前端设置,通过 server_key 加密存服务端,Agent 拉取配置后解密使用
存储凭证 所有后端凭证(S3 AK/SK、FTP/SFTP 密码、WebDAV 密码、SSH 私钥等)通过 server_key 加密存服务端
数据加密 Restic 内置 AES-256-CTR 加密,服务端和存储端均无法读取明文
传输加密 S3: HTTPS / SFTP: SSH 加密 / FTP: 明文(建议使用 FTPS/ WebDAV: HTTPS
密码隔离 每台服务器的 Restic 仓库使用独立密码,互不影响
配置缓存 Agent 解密后配置仅存内存,不落盘;进程退出后自动清除
rclone 凭证 FTP/WebDAV 凭证通过 rclone config 临时写入,使用后删除

11.9 资源控制

控制项 Restic 参数 默认值
CPU 限制 --limit-cpu (通过 cgroup 或 nice) nice 19
网络限速 --limit-upload (KB/s) 0 (不限,可用户配置)
并发读取 GOMAXPROCS 2
上传并发 restic 内部管理 2 connections
内存占用 默认 ~50MB

Agent 在执行备份时自动降低优先级 (nice/ionice),确保不影响业务正常运行。

11.10 备份记录上报 (gRPC)

更新 BackupConfig proto 定义:

message BackupConfig {
  bool enabled = 1;
  int32 interval_hours = 2;
  int32 max_count = 3;
  string encrypted_config_json = 4;  // 加密的完整备份配置 JSON(含 repos、tasks 等)
}

message BackupResult {
  string agent_token = 1;
  string repo_name = 2;
  string task_name = 3;
  bool success = 4;
  string snapshot_id = 5;            // Restic 快照 ID
  int64 files_new = 6;
  int64 files_changed = 7;
  int64 data_added_bytes = 8;        // 本次新增数据量
  int64 total_size_bytes = 9;        // 仓库总大小
  int64 duration_ms = 10;
  string error_message = 11;
  int64 timestamp = 12;
}

Agent 完成备份后通过 ReportStream 上报 BackupResult,服务端记录到 backup_records 表。

更新 backup_records 表结构:

字段 类型 说明
id UUID 主键
server_id UUID FK → servers
repo_name VARCHAR(100) 仓库名称
task_name VARCHAR(100) 任务名称
task_type VARCHAR(20) folder / database / docker
snapshot_id VARCHAR(64) Restic 快照 ID
success BOOLEAN 是否成功
files_new BIGINT 新增文件数
files_changed BIGINT 变更文件数
data_added_bytes BIGINT 新增数据量
total_size_bytes BIGINT 仓库总大小
duration_ms INT 耗时 ms
error_message TEXT 错误信息
created_at TIMESTAMP

12. 项目目录结构

statusprobe/
├── server/                        # 服务端
│   ├── cmd/
│   │   └── server/
│   │       └── main.go           # 入口:加载配置、初始化依赖、启动 HTTP/gRPC
│   │
│   ├── internal/
│   │   ├── config/                # [基础] 服务端配置加载
│   │   │   ├── config.go         # 配置结构体定义与加载(YAML/ENV)
│   │   │   └── validator.go      # 配置校验
│   │   │
│   │   ├── mod/                   # [模块化] 业务模块,每个模块自包含
│   │   │   │
│   │   │   ├── auth/             # 认证模块:注册/登录/JWT/密码重置
│   │   │   │   ├── handler.go    #   HTTP handler(路由注册)
│   │   │   │   ├── service.go    #   业务逻辑
│   │   │   │   ├── repository.go #   数据访问
│   │   │   │   ├── model.go      #   数据模型
│   │   │   │   └── router.go     #   路由定义
│   │   │   │
│   │   │   ├── user/             # 用户模块:个人信息/邮箱绑定/TG绑定/偏好
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   └── router.go
│   │   │   │
│   │   │   ├── plan/             # 套餐模块:套餐CRUD/权限
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   └── router.go
│   │   │   │
│   │   │   ├── subscription/     # 订阅模块:购买/升级/兑换码
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   ├── router.go
│   │   │   │   └── upgrade.go    #   套餐升级差价计算
│   │   │   │
│   │   │   ├── payment/          # 支付模块:订单/回调/多通道
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   ├── router.go
│   │   │   │   ├── alipay.go     #   支付宝通道
│   │   │   │   ├── wechat.go     #   微信支付通道
│   │   │   │   └── stripe.go     #   Stripe 通道
│   │   │   │
│   │   │   ├── server/           # 服务器模块:添加/删除/配置/安装命令
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   └── router.go
│   │   │   │
│   │   │   ├── monitor/          # 监控模块:指标存储/查询/聚合
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   ├── router.go
│   │   │   │   └── aggregator.go #   指标降采样聚合
│   │   │   │
│   │   │   ├── alert/            # 告警模块:规则/评估/事件
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   ├── router.go
│   │   │   │   └── evaluator.go  #   滑动窗口评估引擎
│   │   │   │
│   │   │   ├── notify/           # 通知模块:TG通知/通知渠道
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   ├── router.go
│   │   │   │   └── dispatcher.go #   通知分发器(检查前置条件)
│   │   │   │
│   │   │   ├── backup/           # 备份模块:备份记录/恢复/触发
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   └── router.go
│   │   │   │
│   │   │   ├── probepage/        # 探针页面模块:页面配置/SSR
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   └── router.go
│   │   │   │
│   │   │   ├── install/          # 安装向导模块:数据库配置/Redis配置/管理员创建
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   └── router.go
│   │   │   │
│   │   │   ├── setting/          # 系统设置模块:SMTP/支付/TG/安全配置
│   │   │   │   ├── handler.go
│   │   │   │   ├── service.go
│   │   │   │   ├── repository.go
│   │   │   │   ├── model.go
│   │   │   │   ├── router.go
│   │   │   │   └── smtp.go       #   SMTP 测试发送
│   │   │   │
│   │   │   └── admin/            # 管理员模块:用户管理/统计/汇总
│   │   │       ├── handler.go
│   │   │       ├── service.go
│   │   │       ├── repository.go
│   │   │       ├── router.go
│   │   │       └── stats.go      #   系统统计聚合
│   │   │
│   │   ├── grpc/                  # [gRPC] 客户端通信层
│   │   │   ├── server.go         # gRPC 服务注册与启动
│   │   │   ├── agent.go          # AgentService 实现(ReportStream/FetchConfig/Heartbeat
│   │   │   ├── backup.go         # 备份上传流处理
│   │   │   └── interceptor.go    # 认证拦截器(agent_token 校验)
│   │   │
│   │   ├── tgbot/                 # [TG Bot] Telegram 机器人
│   │   │   ├── bot.go            # Bot 初始化与 Webhook 处理
│   │   │   ├── bind.go           # 用户绑定流程
│   │   │   └── commands.go       # Bot 命令处理 (/status, /help)
│   │   │
│   │   ├── middleware/            # [中间件] HTTP 中间件
│   │   │   ├── auth.go           # JWT 认证中间件
│   │   │   ├── ratelimit.go      # 限流中间件
│   │   │   ├── cors.go           # 跨域中间件
│   │   │   ├── admin.go          # 管理员权限中间件
│   │   │   └── recovery.go       # Panic 恢复中间件
│   │   │
│   │   └── scheduler/            # [定时任务] 服务端定时任务
│   │       ├── scheduler.go      # 调度器
│   │       ├── subscription.go   # 订阅过期检查
│   │       ├── metrics.go        # 指标降采样
│   │       └── cleanup.go        # 过期数据清理
│   │
│   ├── pkg/                       # [公共包] 可被 internal 引用的通用工具
│   │   ├── crypto/                # 加密工具
│   │   │   ├── aes.go            # AES-256-GCM 加解密
│   │   │   └── hash.go           # Argon2id / HKDF / 随机令牌生成
│   │   ├── jwt/                   # JWT 工具
│   │   │   └── jwt.go            # RS256 Token 签发与验证
│   │   ├── response/              # 统一响应
│   │   │   └── response.go       # 标准化 JSON 响应封装
│   │   ├── validator/             # 参数校验
│   │   │   └── validator.go      # 通用校验规则
│   │   └── database/              # 数据库工具
│   │       ├── postgres.go       # PG 连接与迁移
│   │       └── redis.go          # Redis 连接与封装
│   │
│   ├── migrations/                # 数据库迁移文件
│   ├── proto/                     # Protobuf 定义
│   │   └── agent.proto
│   └── go.mod
│
├── agent/                     # 客户端
│   ├── cmd/
│   │   └── agent/
│   │       └── main.go
│   ├── internal/
│   │   ├── config/
│   │   ├── collector/
│   │   ├── reporter/
│   │   ├── backup/
│   │   └── crypto/
│   └── go.mod
│
├── web/                           # 前端
│   ├── admin/                     # 管理后台 (Vue3 + Naive UI)
│   │   ├── src/
│   │   │   ├── views/            # 页面
│   │   │   │   ├── dashboard/    #   仪表盘
│   │   │   │   ├── users/        #   用户管理
│   │   │   │   ├── plans/        #   套餐管理
│   │   │   │   ├── orders/       #   订单管理
│   │   │   │   ├── redeem/       #   兑换码管理
│   │   │   │   ├── tcping/       #   TCPing 节点管理
│   │   │   │   └── settings/     #   系统设置(通用/SMTP/支付/TG/安全)
│   │   │   ├── components/       # 通用组件
│   │   │   ├── stores/           # Pinia 状态管理
│   │   │   ├── api/              # API 请求封装
│   │   │   ├── router/           # 路由配置
│   │   │   └── utils/            # 工具函数
│   │   └── ...
│   │
│   ├── dashboard/                 # 用户面板 (Vue3 + Naive UI)
│   │   ├── src/
│   │   │   ├── views/
│   │   │   │   ├── overview/     #   总览
│   │   │   │   ├── servers/      #   服务器管理
│   │   │   │   ├── monitor/      #   监控详情
│   │   │   │   ├── alerts/       #   告警规则
│   │   │   │   ├── backup/       #   备份管理
│   │   │   │   ├── probepage/    #   探针页面配置
│   │   │   │   ├── subscription/ #   套餐/订阅
│   │   │   │   ├── settings/     #   账号设置/邮箱/TG绑定/偏好
│   │   │   │   └── install/      #   一键安装命令生成
│   │   │   ├── components/
│   │   │   │   ├── charts/       #   图表组件(CPU/Mem/Net 折线图)
│   │   │   │   ├── server-card/  #   服务器状态卡片
│   │   │   │   └── crypto/       #   前端加密组件(Argon2id/AES
│   │   │   ├── stores/
│   │   │   ├── api/
│   │   │   ├── router/
│   │   │   └── utils/
│   │   └── ...
│   │
│   ├── probe/                     # 探针页面 (Nuxt3 SSR)
│   │   ├── pages/
│   │   │   └── [slug].vue        #   公开探针页面
│   │   ├── components/
│   │   │   ├── server-grid.vue   #   服务器卡片网格
│   │   │   ├── server-card.vue   #   单服务器卡片
│   │   │   ├── gpu-card.vue      #   GPU 信息卡片
│   │   │   └── tcping-table.vue  #   TCPing 结果表
│   │   ├── composables/          # 组合式函数
│   │   └── ...
│   │
│   └── shared/                    # 前端共享代码
│       ├── crypto/               # 加密工具(Argon2id/HKDF/AES-256-GCM
│       │   ├── argon2id.ts       #   密码哈希
│       │   ├── hkdf.ts           #   密钥派生
│       │   └── aes-gcm.ts        #   配置加解密
│       ├── types/                # 共享类型定义
│       └── constants/            # 共享常量
│
├── install/
│   └── install.sh             # 一键安装脚本
│
├── docs/                      # 文档
└── docker/
    ├── docker-compose.yml
    ├── server.Dockerfile
    └── agent.Dockerfile

12.5 后端模块化开发规范

模块结构

每个业务模块位于 internal/mod/{module}/ 下,自包含四层:

mod/{module}/
├── model.go       # 数据模型:数据库表映射 struct + DTO(请求/响应结构体)
├── repository.go  # 数据访问:数据库 CRUD,封装 SQL 查询,不包含业务逻辑
├── service.go     # 业务逻辑:核心业务处理,调用 repository,可跨模块调用其他 service
└── handler.go     # HTTP handler:参数校验、调用 service、格式化响应,不含业务逻辑

模块间依赖规则

handler → service → repository
  │          │
  │          └──→ 可调用其他模块的 service(通过接口注入)
  │
  └──→ 不直接调用其他模块的 repository

禁止:
  - handler 直接调用 repository
  - service 直接操作 http.Request/Response
  - 循环依赖(A service 调 B serviceB service 又调 A service

接口注入示例

// mod/alert/service.go
type AlertService struct {
    alertRepo   repository.AlertRepository
    serverSvc   server.ServiceInterface   // 通过接口注入,不直接依赖 server 模块实现
    notifySvc   notify.ServiceInterface
}

func NewAlertService(
    alertRepo repository.AlertRepository,
    serverSvc server.ServiceInterface,
    notifySvc notify.ServiceInterface,
) *AlertService {
    return &AlertService{...}
}

代码注释规范

// Package auth 提供用户认证功能,包括注册、登录、JWT 签发、密码重置等。
//
// 主要流程:
//   - 注册:校验参数 → 检查用户名唯一 → 存储 password_hash + encrypted_config_key
//   - 登录:校验 password_hash → 签发 JWT + 返回 encrypted_config_key
//   - 修改密码:验证旧密码 → 更新 hash / 修改加密密码 → 重新加密 config_key
package auth

// UserService 处理用户相关的业务逻辑。
type UserService struct {
    repo repository.UserRepository  // 用户数据访问
}

// Register 注册新用户。
// 参数:
//   - req: 注册请求,包含 username、password_hash、email(可选)
// 返回:
//   - user: 创建的用户对象
//   - err: 参数校验失败返回 ErrInvalidParam,用户名已存在返回 ErrUserExists
func (s *UserService) Register(req *RegisterRequest) (*User, error) {
    // 1. 校验参数
    if err := validateRegister(req); err != nil {
        return nil, ErrInvalidParam
    }

    // 2. 检查用户名是否已存在
    exists, err := s.repo.ExistsByUsername(req.Username)
    if err != nil {
        return nil, err
    }
    if exists {
        return nil, ErrUserExists
    }

    // 3. 创建用户
    user := &User{...}
    if err := s.repo.Create(user); err != nil {
        return nil, err
    }

    return user, nil
}

依赖注入与初始化

// cmd/server/main.go
func main() {
    // 1. 加载配置
    cfg := config.Load()

    // 2. 初始化基础设施
    db := database.NewPostgres(cfg.DB)
    rdb := database.NewRedis(cfg.Redis)

    // 3. 初始化各模块(按依赖顺序)
    userRepo := user.NewRepository(db)
    userSvc := user.NewService(userRepo)
    userHandler := user.NewHandler(userSvc)

    authSvc := auth.NewService(userRepo, cfg.JWT)
    authHandler := auth.NewHandler(authSvc)

    serverSvc := server.NewService(server.NewRepository(db), userSvc)
    serverHandler := server.NewHandler(serverSvc)

    monitorSvc := monitor.NewService(monitor.NewRepository(db, rdb))
    monitorHandler := monitor.NewHandler(monitorSvc)

    alertSvc := alert.NewService(alert.NewRepository(db), serverSvc, notifySvc)
    alertHandler := alert.NewHandler(alertSvc)

    // 4. 注册路由
    r := gin.Default()
    auth.RegisterRoutes(r, authHandler)
    user.RegisterRoutes(r, userHandler)
    server.RegisterRoutes(r, serverHandler)
    // ...

    // 5. 启动
    r.Run(":8080")
}

13. 前端设计规范 (Termius 风格)

13.1 设计原则

遵循 Termius SSH 客户端的设计语言,核心特征:

原则 说明
深色终端美学 默认深色背景,护眼低对比度,符合 DevOps 工具定位
绿色品牌色 使用 #4ADE80 作为主品牌色,呼应终端/SSH 的技术感
JetBrains Mono 字体 等宽字体用于代码、IP 地址、路径等技术文本
紧凑高效 信息密度优先,减少视觉噪音,紧凑间距
圆角卡片 统一 8px 圆角,卡片阴影 subtle
状态可视化 使用颜色编码表示服务器状态(在线/离线/告警)

13.2 色彩体系

深色主题 (默认):
  背景:      #1A1D23 (页面) / #0F1115 (侧边栏) / #22262E (卡片内)
  文字:      #E4E4E7 (主) / #A1A1AA (次) / #71717A (辅助)
  边框:      #27272A (主) / #1F1F23 (微)
  品牌色:    #4ADE80 (绿色 - 主色) / #22C55E (悬停) / #16A34A (按下)
  状态色:    #4ADE80 (在线绿) / #EF4444 (离线红) / #F59E0B (告警黄) / #3B82F6 (信息蓝)
  强调色:    #4ADE80 (成功) / #EF4444 (错误) / #F59E0B (警告) / #3B82F6 (信息)

浅色主题 (可选):
  背景:      #FFFFFF (页面) / #F4F4F5 (侧边栏) / #FAFAFA (卡片内)
  文字:      #18181B (主) / #52525B (次) / #A1A1AA (辅助)
  边框:      #E4E4E7 (主) / #F4F4F5 (微)
  品牌色:    #22C55E (绿色 - 主色) / #16A34A (悬停) / #15803D (按下)
  状态色:    #22C55E (在线绿) / #DC2626 (离线红) / #D97706 (告警黄) / #2563EB (信息蓝)

13.3 字体规范

用途 字体 字号 字重
标题 H1 Inter / system-ui 24px 600
标题 H2 Inter / system-ui 20px 600
标题 H3 Inter / system-ui 16px 500
正文 Inter / system-ui 14px 400
辅助文字 Inter / system-ui 12px 400
代码/IP/路径 JetBrains Mono 13px 400
按钮文字 Inter / system-ui 14px 500

13.4 布局规范

元素 规范
侧边栏 宽度 240px,可折叠至 64px(图标模式),深色背景 #0F1115
顶栏 高度 48px,含面包屑 + 全局操作,背景 #1A1D23
内容区 内边距 24px,卡片间距 16px
卡片 内边距 16px,圆角 8px,背景 #22262E,边框 #27272A
表格 行高 40px,斑马纹 #1F2228,无边框
表单 标签宽度 80px,输入框高度 32px,背景 #1A1D23
按钮 高度 32px,圆角 6px,主按钮绿色实色,次按钮 outline
标签/徽章 圆角 4px,高度 20px,字号 12px

13.5 组件映射 (Naive UI)

场景 Naive UI 组件 定制
布局 NLayout + NLayoutSider 深色主题,sider 深色 #0F1115
导航 NMenu 深色主题,缩进 16px,图标+文字
数据展示 NDataTable 紧凑模式 (size=small),深色主题
表单 NForm + NInput + NSelect 统一 size=small,深色主题
卡片 NCard 8px 圆角,背景 #22262E
状态 NTag + NBadge 圆角 4px,使用状态色
图表 ECharts (自定义) 深色主题,品牌色 #4ADE80
反馈 NMessage + NModal 深色主题
加载 NSkeleton 深色骨架屏
图标 NIcon + @vicons/tabler Tabler Icons 线条风格

13.6 Naive UI 主题配置

// theme.ts
import { GlobalThemeOverrides } from 'naive-ui'

export const darkThemeOverrides: GlobalThemeOverrides = {
  common: {
    borderRadius: '8px',
    fontSize: '14px',
    height: '32px',
    primaryColor: '#4ADE80',
    primaryColorHover: '#22C55E',
    primaryColorPressed: '#16A34A',
    successColor: '#4ADE80',
    errorColor: '#EF4444',
    warningColor: '#F59E0B',
    infoColor: '#3B82F6',
    bodyColor: '#1A1D23',
    cardColor: '#22262E',
    borderColor: '#27272A',
    textColorBase: '#E4E4E7',
    textColor1: '#E4E4E7',
    textColor2: '#A1A1AA',
    textColor3: '#71717A',
  },
  Card: {
    borderRadius: '8px',
    paddingMedium: '16px',
    color: '#22262E',
    borderColor: '#27272A',
  },
  DataTable: {
    thColor: '#1A1D23',
    tdColor: '#22262E',
    borderColor: '#27272A',
    thTextColor: '#A1A1AA',
    tdTextColor: '#E4E4E7',
  },
  Button: {
    borderRadiusMedium: '6px',
    heightMedium: '32px',
    textColorPrimary: '#0F1115',
    colorPrimary: '#4ADE80',
    colorHoverPrimary: '#22C55E',
    colorPressedPrimary: '#16A34A',
  },
  Input: {
    height: '32px',
    borderRadius: '6px',
    color: '#1A1D23',
    borderColor: '#27272A',
    textColor: '#E4E4E7',
  },
  Menu: {
    borderRadius: '6px',
    itemHeight: '36px',
    color: '#0F1115',
    itemTextColor: '#A1A1AA',
    itemTextColorHover: '#E4E4E7',
    itemTextColorActive: '#4ADE80',
    itemColorActive: '#1A1D23',
  },
  Layout: {
    siderColor: '#0F1115',
    headerColor: '#1A1D23',
    contentColor: '#1A1D23',
  },
}

export const lightThemeOverrides: GlobalThemeOverrides = {
  common: {
    borderRadius: '8px',
    fontSize: '14px',
    height: '32px',
    primaryColor: '#22C55E',
    primaryColorHover: '#16A34A',
    primaryColorPressed: '#15803D',
    successColor: '#22C55E',
    errorColor: '#DC2626',
    warningColor: '#D97706',
    infoColor: '#2563EB',
  },
  Card: {
    borderRadius: '8px',
    paddingMedium: '16px',
  },
  DataTable: {
    thColor: '#FAFAFA',
    tdColor: '#FFFFFF',
    borderColor: '#E4E4E7',
  },
  Button: {
    borderRadiusMedium: '6px',
    heightMedium: '32px',
    textColorPrimary: '#FFFFFF',
    colorPrimary: '#22C55E',
    colorHoverPrimary: '#16A34A',
    colorPressedPrimary: '#15803D',
  },
  Input: {
    height: '32px',
    borderRadius: '6px',
  },
  Menu: {
    borderRadius: '6px',
    itemHeight: '36px',
    itemTextColorActive: '#22C55E',
  },
}

13.7 探针页面主题

探针公开页面默认使用深色主题,与 Termius 风格保持一致:

内置主题更新:
- default    → 经典白底蓝调(保留)
- dark       → Termius 深色(品牌色改为 #4ADE80
- gruvbox    → 暖色调复古(保留)
- catppuccin → 柔和深色(保留)
- nord       → 北极冷色调(保留)
- solarized  → 经典 Solarized(保留)
- sakura     → 樱花粉白(保留)
- cyberpunk  → 赛博朋克(保留)
- glass      → 毛玻璃(保留)
- minimal    → 极简(保留)

Termius 风格 CSS 变量

:root[data-theme="termius"] {
  --sp-bg-page: #1A1D23;
  --sp-bg-sidebar: #0F1115;
  --sp-bg-card: #22262E;
  --sp-bg-card-hover: #2A2F38;
  --sp-text-primary: #E4E4E7;
  --sp-text-secondary: #A1A1AA;
  --sp-text-muted: #71717A;
  --sp-border: #27272A;
  --sp-accent: #4ADE80;
  --sp-accent-hover: #22C55E;
  --sp-success: #4ADE80;
  --sp-warning: #F59E0B;
  --sp-error: #EF4444;
  --sp-info: #3B82F6;
  --sp-radius: 8px;
  --sp-shadow: 0 1px 3px rgba(0,0,0,0.3);
  --sp-font: 'Inter', -apple-system, sans-serif;
  --sp-font-mono: 'JetBrains Mono', 'Fira Code', monospace;
}

14. 开发阶段规划

Phase 1: 基础框架

  • 服务端骨架 (Gin + gRPC + GORM)
  • 安装向导(数据库选型:SQLite/PostgreSQL、Redis 可选、管理员创建)
  • 用户注册/登录 + JWT 认证(账号制,支持验证码/邮箱验证)
  • 管理员系统设置(SMTP、支付通道、安全配置)
  • 邮件服务(验证码、邮箱验证、密码重置)
  • 套餐 CRUD (Admin)
  • 前端基础框架搭建(Termius 风格深色主题)

Phase 2: 核心监控

  • Agent 开发 (系统指标采集 + gRPC 上报)
  • 服务器管理 (添加/删除/配置)
  • 配置下发与缓存机制
  • 探针页面基础版 (SSR + 实时数据)

Phase 3: 安全与加密

  • 前端加密体系实现 (Argon2id + HKDF + AES-256-GCM)
  • 加密配置存储
  • 一键安装命令生成
  • gRPC TLS 配置

Phase 4: 告警与通知

  • 告警规则引擎
  • Telegram 通知
  • 告警事件管理

Phase 5: 高级功能

  • 定时备份
  • 兑换码系统
  • 套餐升级
  • 探针页面自定义 (CSS/JS/主题)
  • 支付集成(支付宝/微信/Stripe

Phase 6: 优化与上线

  • 性能优化 (指标数据分区、缓存策略)
  • 监控面板图表优化
  • 多语言支持
  • 部署与运维文档

15. 关键技术细节

15.1 指标数据存储策略

  • 热数据(最近 1 小时):
    • 有 RedisRedis Sorted Set,精度 10s
    • 无 Redis:内存缓存(进程内 map + LRU 淘汰),精度 10s
  • 温数据(最近 7 天):PostgreSQL 按小时分区,精度 1min
  • 冷数据7 天以上):PostgreSQL 按天分区,精度 5min 聚合
  • 定时任务每小时执行一次降采样
  • SQLite 模式:直接存储到 server_metrics 表,配合定期清理策略(保留最近 30 天)

15.2 配置版本控制

  • 每次配置变更,config_version 递增
  • Agent 心跳时携带当前版本号,服务端对比后通知更新
  • Agent 本地缓存配置文件,断网时使用缓存运行

15.3 套餐限制检查

// 添加服务器时检查
func (s *ServerService) AddServer(userID uuid.UUID) error {
    plan, err := s.GetUserActivePlan(userID)
    if err != nil {
        return err
    }
    count, err := s.GetServerCount(userID)
    if count >= plan.MaxClients {
        return ErrPlanLimitExceeded
    }
    // ... 创建服务器
}

15.4 兑换码生成

func GenerateRedeemCode() string {
    // 格式: SP-XXXX-XXXX-XXXX (16位,易读)
    chars := "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" // 去除易混淆字符
    code := "SP-"
    for i := 0; i < 3; i++ {
        if i > 0 {
            code += "-"
        }
        for j := 0; j < 4; j++ {
            code += string(chars[rand.Intn(len(chars))])
        }
    }
    return code
}

15.5 gRPC 连接管理

  • Agent 维持长连接,自动重连(指数退避:1s, 2s, 4s, ... 60s
  • 服务端检测连接断开 → 标记服务器 offline → 触发离线告警
  • 双向流断开时,Agent 切换到 Heartbeat 模式保活
  • 服务端支持 graceful shutdown,通知 Agent 重连

16. 部署架构

                    ┌─────────────┐
                    │   Nginx     │
                    │  (反向代理)  │
                    └──────┬──────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
        ┌─────┴─────┐ ┌───┴────┐ ┌─────┴─────┐
        │  Server   │ │ Server │ │  Probe    │
        │  (API)    │ │ (gRPC) │ │  (Nuxt3)  │
        │  :8080    │ │ :9090  │ │  :3000    │
        └─────┬─────┘ └───┬────┘ └───────────┘
              │            │
        ┌─────┴────────────┴─────┐
        │                        │
   ┌────┴────┐            ┌──────┴──────┐
   │   PG    │            │    Redis    │
   │ :5432   │            │   :6379     │
   └─────────┘            └─────────────┘
  • API 和 gRPC 可部署为多实例,通过 Nginx 负载均衡
  • PostgreSQL 建议主从复制
  • Redis 建议哨兵模式
  • S3 使用 MinIO 自建或云服务