Files
csm/docs/superpowers/specs/2026-04-03-csm-enterprise-terminal-manager-design.md
iven fd6fb5cca0 feat: 初始化项目基础架构和核心功能
- 添加项目基础结构:Cargo.toml、.gitignore、设备UID和密钥文件
- 实现前端Vue3项目结构:路由、登录页面、设备管理页面
- 添加核心协议定义(crates/protocol):设备状态、资产、USB事件等
- 实现客户端监控模块:系统状态收集、资产收集
- 实现服务端基础API和插件系统
- 添加数据库迁移脚本:设备管理、资产跟踪、告警系统等
- 实现前端设备状态展示和基本交互
- 添加使用时长统计和水印功能插件
2026-04-05 00:57:51 +08:00

55 KiB

CSM - Enterprise Terminal Management System Design

Date: 2026-04-03 Status: Draft Scope: MVP (50-500 Windows terminals, on-premise deployment)

1. Overview

CSM (Corporate System Manager) is a locally deployable enterprise terminal management system inspired by Tencent PC Manager Small Team Edition. It provides IT operations teams with centralized visibility and control over company Windows computers.

Key Design Decisions

Decision Choice Rationale
System positioning IT operations management Compliance-friendly, employee-visible client, focused on ops efficiency
Deployment scale 50-500 terminals Single-server deployment, monolithic architecture
Target OS Windows 7+ only Simplifies client development (single platform API)
Database SQLite Zero-ops, single-file, sufficient for small-scale
Management UI Web (embedded SPA) Browser-based access from any device, no desktop app needed
Notification Email (SMTP) + Webhook Fully local, no third-party dependencies
Architecture Axum monolith with embedded frontend Single binary deployment, zero configuration

MVP Features (Phase 1)

  1. Terminal Status Monitoring - CPU/memory/disk/process real-time monitoring, online/offline tracking
  2. USB Device Control - USB event logging, whitelist/blacklist policies, read-only enforcement
  3. Asset Management - Hardware/software inventory auto-collection, change tracking

Plugin Modules (Phase 2 — Tencent Manager Parity)

These modules are modeled after Tencent PC Manager Small Team Edition's plugin marketplace. Each is an independent module that can be enabled/disabled per device group.

# Plugin Description Windows Complexity
1 Web Filter (上网拦截) URL blacklist/whitelist, category-based filtering, browsing time control Medium
2 Usage Timer (时长记录) Track computer usage duration, application usage statistics, idle detection Low
3 Software Blocker (软件禁止安装) Blacklist-based software install prevention, unauthorized software auto-uninstall Medium
4 Popup Blocker (弹窗拦截) Intercept popup ads and notifications, configurable allow-list Low
5 USB File Audit (U盘文件操作记录) Log all file copy/delete/rename operations on USB storage devices Medium
6 Screen Watermark (水印管理) Display customizable screen watermark (company name, username, timestamp) Medium

Future Features (Phase 3+)

  • Software distribution (remote install/uninstall)
  • Scheduled antivirus scanning
  • Vulnerability patching
  • Remote desktop assistance
  • System announcements
  • Scheduled shutdown

2. System Architecture

2.1 Cargo Workspace Structure

csm/
├── Cargo.toml                    # Workspace root
├── crates/
│   ├── protocol/                 # Shared protocol definitions
│   │   └── src/
│   │       ├── lib.rs
│   │       ├── message.rs        # Message types (enum-based)
│   │       └── device.rs         # Device data structures
│   │
│   ├── client/                   # Windows client (Service + System Tray)
│   │   └── src/
│   │       ├── main.rs           # Entry point + Windows Service registration
│   │       ├── tray.rs           # System tray icon
│   │       ├── monitor/          # Status monitoring
│   │       │   ├── mod.rs
│   │       │   ├── system.rs     # CPU/memory/disk/network via Windows API
│   │       │   └── process.rs    # Process enumeration
│   │       ├── asset/            # Asset collection
│   │       │   ├── mod.rs
│   │       │   ├── hardware.rs   # Hardware info (WMI queries)
│   │       │   └── software.rs   # Software list (registry reading)
│   │       ├── usb/              # USB control
│   │       │   ├── mod.rs
│   │       │   ├── monitor.rs    # WM_DEVICECHANGE listener
│   │       │   └── policy.rs     # Policy enforcement
│   │       └── network/          # Communication
│   │           ├── mod.rs
│   │           ├── connection.rs # TCP + TLS connection
│   │           └── heartbeat.rs  # Keep-alive with exponential backoff
│   │
│   └── server/                   # Server (Axum + embedded frontend)
│       └── src/
│           ├── main.rs           # Entry point
│           ├── api/              # REST API handlers
│           │   ├── mod.rs
│           │   ├── auth.rs       # JWT authentication
│           │   ├── devices.rs    # Device CRUD + status queries
│           │   ├── assets.rs     # Asset queries + change history
│           │   ├── usb.rs        # USB policy management
│           │   └── alerts.rs     # Alert rules + records
│           ├── ws/               # WebSocket real-time push
│           │   ├── mod.rs
│           │   └── handler.rs    # Device status updates, USB events
│           ├── tcp/              # Client connection management
│           │   ├── mod.rs
│           │   └── session.rs    # Per-client session handler
│           ├── db/               # Database layer
│           │   ├── mod.rs
│           │   ├── schema.rs     # Refdb migration definitions
│           │   └── repository.rs # Query functions
│           ├── alert/            # Alert engine
│           │   ├── mod.rs
│           │   ├── engine.rs     # Rule matching against incoming events
│           │   └── notify.rs     # Email (lettre) + Webhook dispatch
│           └── config.rs         # TOML-based configuration
│
├── web/                          # Vue.js management frontend
│   ├── package.json
│   ├── vite.config.ts
│   └── src/
│       ├── views/
│       │   ├── Dashboard.vue     # Overview: online stats, alerts, recent events
│       │   ├── Devices.vue       # Device list with real-time status
│       │   ├── DeviceDetail.vue  # Single device detail (hardware, software, history)
│       │   ├── Assets.vue        # Asset inventory and change log
│       │   ├── UsbPolicy.vue     # USB policy configuration
│       │   ├── UsbEvents.vue     # USB event timeline
│       │   ├── Alerts.vue        # Alert center
│       │   ├── AlertRules.vue    # Alert rule configuration
│       │   ├── Login.vue         # Authentication
│       │   └── Settings.vue      # System settings (notifications, users)
│       ├── components/
│       │   ├── DeviceStatusBadge.vue
│       │   ├── CpuChart.vue
│       │   ├── MemoryChart.vue
│       │   └── AlertCard.vue
│       ├── stores/               # Pinia state management
│       │   ├── auth.ts
│       │   ├── devices.ts
│       │   └── alerts.ts
│       └── router/
│           └── index.ts
│
├── migrations/                   # SQLite migration SQL files
│   ├── 001_init.sql              # Users, devices, device_status
│   ├── 002_assets.sql            # Hardware/software assets, asset_changes
│   ├── 003_usb.sql               # USB events, USB policies
│   ├── 004_alerts.sql            # Alert rules, alert records
│   ├── 005_plugins_web_filter.sql    # Web filter rules + access log
│   ├── 006_plugins_usage_timer.sql   # Daily usage + app usage
│   ├── 007_plugins_software_blocker.sql # Software blacklist + violations
│   ├── 008_plugins_popup_blocker.sql # Popup filter rules
│   ├── 009_plugins_usb_file_audit.sql # USB file operations log
│   └── 010_plugins_watermark.sql     # Watermark config
│
└── docs/

2.2 Communication Architecture

Client (Windows Service, system tray visible)
  │
  ├─ TCP+TLS persistent ──→ Server :9999 (client gateway)
  │   ├─ Heartbeat (30s interval, ~50 bytes each)
  │   ├─ StatusReport (every 60s, ~500 bytes JSON)
  │   ├─ AssetReport (on change or forced collection)
  │   ├─ UsbEvent (on device change notification)
  │   └─ Receives: PolicyUpdate, ConfigUpdate, TaskExecute
  │
  └─ Initial registration ──→ POST /api/register (over HTTPS)

Admin (Browser)
  │
  ├─ HTTPS ──→ Server :8080 (web management)
  │   ├─ REST API (CRUD operations)
  │   └─ Static file serving (Vue.js SPA from embedded dist/)
  │
  └─ WSS ──→ Server :8080/ws (real-time push)
      ├─ Device status updates (online/offline, metric changes)
      ├─ USB alerts (unauthorized device, policy violations)
      └─ New device registration notifications

2.3 Single Binary Deployment

The server binary embeds:

  • Vue.js SPA (compiled dist/ via include_dir! macro from include_dir crate)
  • SQLite database (auto-created on first run)
  • Default configuration (overridable via config.toml)

Deployment process:

# 1. Copy single binary
scp csm-server target-server:/usr/local/bin/

# 2. Create config
cat > config.toml << EOF
[server]
http_addr = "0.0.0.0:8080"
tcp_addr = "0.0.0.0:9999"

[database]
path = "./csm.db"

[auth]
jwt_secret = "change-me-in-production"

[notify.smtp]
host = "smtp.company.com"
port = 587
username = "alerts@company.com"
password = "secret"
from = "CSM Alerts <alerts@company.com>"
EOF

# 3. Run
./csm-server --config config.toml

3. Communication Protocol

3.1 Binary Frame Format

┌──────────┬──────────┬──────────┬──────────────┐
│ Magic(4B)│ Ver(1B)  │ Type(1B) │ Length(4B)   │
│ 0x43534D │ 0x01     │          │ payload size │
├──────────┴──────────┴──────────┴──────────────┤
│         Payload (variable)                      │
│         JSON-encoded message body               │
└─────────────────────────────────────────────────┘
  • Magic bytes: 0x43 0x53 0x4D = "CSM" in ASCII
  • Protocol version: 0x01 (current). Both sides verify version during registration handshake. If versions differ, the server sends a ConfigUpdate(ProtocolVersion) with the highest common version, or rejects the connection if incompatible.

3.2 Message Types

#[repr(u8)]
pub enum MessageType {
    // Client → Server
    Heartbeat       = 0x01,
    Register        = 0x02,
    StatusReport    = 0x03,
    AssetReport     = 0x04,
    AssetChange     = 0x05,
    UsbEvent        = 0x06,
    AlertAck        = 0x07,

    // Server → Client
    PolicyUpdate    = 0x10,
    ConfigUpdate    = 0x11,
    TaskExecute     = 0x12,
}

3.3 Bandwidth Estimation (500 terminals)

Message Frequency Size Bandwidth
Heartbeat 30s ~50B ~8 KB/s
StatusReport 60s ~500B ~4 KB/s
UsbEvent On event ~300B Negligible
AssetReport On change ~5KB Negligible
Total (steady state)

~12 KB/s

4. Database Schema (SQLite)

4.1 Core Tables

users - Administrator accounts

CREATE TABLE users (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    username    TEXT NOT NULL UNIQUE,
    password    TEXT NOT NULL,          -- bcrypt hash
    role        TEXT NOT NULL DEFAULT 'admin',
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
);

devices - Registered terminals

CREATE TABLE devices (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL UNIQUE,  -- Client-generated UUID
    hostname        TEXT NOT NULL,
    ip_address      TEXT NOT NULL,
    mac_address     TEXT,
    os_version      TEXT,
    client_version  TEXT,
    status          TEXT NOT NULL DEFAULT 'offline',
    last_heartbeat  TEXT,
    registered_at   TEXT NOT NULL DEFAULT (datetime('now')),
    group_name      TEXT DEFAULT 'default'
);

device_status - Latest status snapshot (upsert on each heartbeat)

CREATE TABLE device_status (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL REFERENCES devices(device_uid),
    cpu_usage       REAL,
    memory_usage    REAL,
    memory_total    INTEGER,
    disk_usage      REAL,
    disk_total      INTEGER,
    network_rx_rate INTEGER,
    network_tx_rate INTEGER,
    running_procs   INTEGER,
    top_processes   TEXT,               -- JSON array
    updated_at      TEXT NOT NULL DEFAULT (datetime('now')),
    FOREIGN KEY (device_uid) REFERENCES devices(device_uid)
);

4.2 Asset Tables

hardware_assets - Hardware inventory (one row per device)

CREATE TABLE hardware_assets (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL REFERENCES devices(device_uid),
    cpu_model       TEXT,
    cpu_cores       INTEGER,
    memory_total    INTEGER,
    disk_model      TEXT,
    disk_total      INTEGER,
    gpu_model       TEXT,
    motherboard     TEXT,
    serial_number   TEXT,
    updated_at      TEXT NOT NULL DEFAULT (datetime('now')),
    UNIQUE(device_uid)
);

software_assets - Software inventory (many rows per device)

CREATE TABLE software_assets (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL REFERENCES devices(device_uid),
    name            TEXT NOT NULL,
    version         TEXT,
    publisher       TEXT,
    install_date    TEXT,
    install_path    TEXT,
    updated_at      TEXT NOT NULL DEFAULT (datetime('now')),
    UNIQUE(device_uid, name, version)
);

asset_changes - Change audit log

CREATE TABLE asset_changes (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL REFERENCES devices(device_uid),
    change_type     TEXT NOT NULL,       -- 'hardware' | 'software_added' | 'software_removed'
    change_detail   TEXT NOT NULL,       -- JSON: {field, old_value, new_value}
    changed_at      TEXT NOT NULL DEFAULT (datetime('now'))
);

4.3 USB Control Tables

usb_events - USB device activity log

CREATE TABLE usb_events (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL REFERENCES devices(device_uid),
    usb_vendor_id   TEXT,
    usb_product_id  TEXT,
    usb_serial      TEXT,
    usb_name        TEXT,
    event_type      TEXT NOT NULL,       -- 'inserted' | 'removed' | 'blocked'
    event_time      TEXT NOT NULL DEFAULT (datetime('now'))
);

usb_policies - USB access policies

CREATE TABLE usb_policies (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    name            TEXT NOT NULL,
    policy_type     TEXT NOT NULL,       -- 'whitelist' | 'blacklist' | 'readonly' | 'all_block'
    target_type     TEXT NOT NULL,       -- 'global' | 'group' | 'device'
    target_id       TEXT,               -- Group name or device UID (NULL for global)
    rules           TEXT NOT NULL,       -- JSON: vendor_id/product_id/serial patterns
    enabled         INTEGER NOT NULL DEFAULT 1,
    created_at      TEXT NOT NULL DEFAULT (datetime('now'))
);

4.4 Alert Tables

alert_rules - Alert rule definitions

CREATE TABLE alert_rules (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    name            TEXT NOT NULL,
    rule_type       TEXT NOT NULL,       -- 'device_offline' | 'cpu_high' | 'memory_high' | 'disk_high' | 'usb_unauthorized' | 'asset_change'
    condition       TEXT NOT NULL,       -- JSON: threshold, duration, etc.
    notify_method   TEXT NOT NULL,       -- 'email' | 'webhook' | 'both'
    notify_target   TEXT NOT NULL,       -- Email address or webhook URL
    enabled         INTEGER NOT NULL DEFAULT 1,
    created_at      TEXT NOT NULL DEFAULT (datetime('now'))
);

alert_records - Alert history

CREATE TABLE alert_records (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    rule_id         INTEGER REFERENCES alert_rules(id),
    device_uid      TEXT,
    alert_type      TEXT NOT NULL,
    severity        TEXT NOT NULL DEFAULT 'warning',
    content         TEXT NOT NULL,
    notified        INTEGER NOT NULL DEFAULT 0,
    handled         INTEGER NOT NULL DEFAULT 0,
    handler         TEXT,
    handle_remark   TEXT,
    created_at      TEXT NOT NULL DEFAULT (datetime('now'))
);

4.5 Indexes

CREATE INDEX idx_devices_status ON devices(status);
CREATE INDEX idx_device_status_uid ON device_status(device_uid);
CREATE INDEX idx_software_device ON software_assets(device_uid);
CREATE INDEX idx_usb_events_device_time ON usb_events(device_uid, event_time);
CREATE INDEX idx_usb_policies_target ON usb_policies(target_type, target_id);
CREATE INDEX idx_alert_records_time ON alert_records(created_at);
CREATE INDEX idx_asset_changes_time ON asset_changes(changed_at);
CREATE INDEX idx_alert_records_device ON alert_records(device_uid, created_at);
CREATE INDEX idx_asset_changes_device ON asset_changes(device_uid);

4.6 Status History (Time-Series)

The device_status table only holds the latest snapshot. For history charts, a separate table stores periodic samples with automatic pruning.

-- Status history samples (insert every 60s per device, auto-pruned after 7 days)
CREATE TABLE device_status_history (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL REFERENCES devices(device_uid),
    cpu_usage       REAL,
    memory_usage    REAL,
    disk_usage      REAL,
    network_rx_rate INTEGER,
    network_tx_rate INTEGER,
    running_procs   INTEGER,
    sampled_at      TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE INDEX idx_status_history_device_time ON device_status_history(device_uid, sampled_at);

Retention policy: A background task runs every hour and deletes rows where sampled_at < datetime('now', '-7 days'). The 7-day retention window is configurable via config.toml.

4.7 SQLite Configuration

SQLite requires specific configuration for concurrent server workloads:

-- Applied on every connection via SQLx setup
PRAGMA journal_mode = WAL;           -- Write-Ahead Logging: allows concurrent reads during writes
PRAGMA synchronous = NORMAL;         -- Balance between safety and performance (WAL handles durability)
PRAGMA busy_timeout = 5000;          -- Wait up to 5s for locked database instead of immediate SQLITE_BUSY
PRAGMA wal_autocheckpoint = 1000;    -- Auto-checkpoint WAL every 1000 pages
PRAGMA cache_size = -64000;          -- 64MB page cache
PRAGMA foreign_keys = ON;            -- Enforce foreign key constraints

Connection pooling (sqlx):

  • Max connections: 8 (sufficient for 500 devices — SQLite serializes writes anyway)
  • Write operations are funneled through a single tokio::sync::Mutex<SqlitePool> to prevent write contention. Reads are unrestricted (WAL allows concurrent reads).
  • Status report writes (the highest-frequency write) use batch INSERT with INSERT OR REPLACE to minimize lock duration.

5. Client Design (Windows Service)

5.1 Runtime Model

main.rs
  ├─ windows_service::start()        # Register as Windows Service
  ├─ tray_icon::show()               # System tray with status icon
  ├─ tokio::spawn(monitor_task)      # Collect system metrics every 60s
  ├─ tokio::spawn(asset_task)        # Collect assets on startup + schedule
  ├─ tokio::spawn(usb_task)          # Listen for WM_DEVICECHANGE
  ├─ tokio::spawn(network_task)      # TCP connection + message loop
  └─ tokio::spawn(config_watcher)    # Watch for config/policy updates

5.2 Status Monitoring (monitor/system.rs)

  • CPU: GetSystemTimes() or NtQuerySystemInformation() for per-CPU usage
  • Memory: GlobalMemoryStatusEx() for total/available
  • Disk: GetDiskFreeSpaceExW() for each drive
  • Network: GetIfTable2() from iphlpapi for bytes sent/received
  • Processes: CreateToolhelp32Snapshot() for enumeration, top 10 by CPU/memory
  • Collection interval: 60 seconds (configurable)
  • Payload: ~500 bytes JSON per report

5.3 Asset Collection (asset/)

  • Hardware: WMI queries (Win32_Processor, Win32_PhysicalMemory, Win32_DiskDrive, Win32_VideoController, Win32_BaseBoard)
  • Software: Registry enumeration (HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall)
  • Change detection: Hash comparison on collected data; only send deltas after initial full report
  • Collection trigger: On startup, daily scheduled, or server-initiated

5.4 USB Control (usb/)

  • Detection: RegisterDeviceNotification() for WM_DEVICECHANGE messages
  • Policy enforcement:
    • all_block: Set HKLM\SYSTEM\CurrentControlSet\Services\USBSTOR\Start = 4 (disabled)
    • whitelist: Allow only specific vendor_id/product_id combinations
    • blacklist: Block specific devices
    • readonly: Deferred to Phase 3 — enforcing USB read-only at the OS level requires a kernel-mode storage filter driver, which is a significant development effort (WHQL signing, driver testing). For MVP, only block/allow modes are supported.
  • Event logging: Every insert/remove event sent to server

5.5 Client Lifecycle

  1. Installation: MSI installer or standalone exe with --install flag
  2. First run: Generate device_uid (UUID v4), register with server (using registration token), full asset report
  3. Normal operation:
    • TCP+TLS connection to server (auto-reconnect with exponential backoff: 1s, 2s, 4s, ..., max 60s)
    • Heartbeat every 30s
    • Status report every 60s
    • USB events immediately
    • Asset changes on detection
  4. Policy sync: Server pushes policy updates; client acknowledges and applies
  5. Update: Server can trigger client self-update (download new binary, verify Ed25519 signature, atomic replace)
  6. Offline resilience: Client buffers up to 1000 events locally (sled embedded database) when server is unreachable. Buffered events are sent on reconnection. If buffer overflows, oldest events are dropped. Alert events are prioritized over status reports.
  7. De-provisioning: When admin deletes a device via DELETE /api/devices/:uid:
    • Server adds device_uid to revocation list
    • If client is connected, server sends ConfigUpdate(SelfDestruct) → client stops its Windows Service and removes its credentials from the Windows Credential Store
    • If client is offline, it is rejected on next reconnection attempt (HMAC verification fails because device record is deleted)

5.6 Device Groups

Device groups are managed as a first-class entity (not ad-hoc strings):

CREATE TABLE device_groups (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    name        TEXT NOT NULL UNIQUE,
    description TEXT,
    parent_id   INTEGER REFERENCES device_groups(id),  -- Optional hierarchy
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
);

The devices.group_name column references device_groups.name. This enables proper group management, hierarchical grouping, and group-level policy application in the web UI.

6. Server Design (Axum)

6.1 HTTP API Routes

Authentication model: All routes except /api/auth/* require a valid JWT in the Authorization: Bearer <token> header. The JWT middleware (axum::middleware::from_fn(auth_guard)) validates the token and injects the user's role into request extensions. Routes marked [viewer] are accessible to both admin and viewer roles; unmarked routes require admin role.

# Public (no auth required)
POST   /api/auth/login                      # JWT token generation
POST   /api/auth/refresh                    # Refresh access token
POST   /api/register                        # Client registration (uses registration token, not JWT)

# Devices [viewer for GET, admin for DELETE]
GET    /api/devices                         # List all devices (pagination, filters)
GET    /api/devices/:uid                    # Device detail
GET    /api/devices/:uid/status             # Current status metrics
GET    /api/devices/:uid/history            # Status history (time range query)
DELETE /api/devices/:uid                    # Remove device (de-provision)

# Assets [viewer]
GET    /api/assets/hardware                 # Hardware inventory (filters)
GET    /api/assets/software                 # Software inventory (filters)
GET    /api/assets/changes                  # Asset change log

# USB Control [viewer for GET, admin for CUD]
GET    /api/usb/events                      # USB event log
GET    /api/usb/policies                    # List USB policies
POST   /api/usb/policies                    # Create policy
PUT    /api/usb/policies/:id                # Update policy
DELETE /api/usb/policies/:id                # Delete policy

# Alerts [viewer for GET, admin for CUD]
GET    /api/alerts/rules                    # List alert rules
POST   /api/alerts/rules                    # Create rule
PUT    /api/alerts/rules/:id                # Update rule
DELETE /api/alerts/rules/:id                # Delete rule
GET    /api/alerts/records                  # Alert history (filters)
PUT    /api/alerts/records/:id/handle       # Handle an alert

# Settings [admin only]
GET    /api/settings                        # System settings
PUT    /api/settings                        # Update settings
POST   /api/settings/registration-token     # Generate client registration token
PUT    /api/settings/tls                    # Upload new TLS certificate

# Admin [admin only]
GET    /api/admin/audit-log                 # Admin audit trail
POST   /api/admin/users                     # Create user
PUT    /api/admin/users/:id                 # Update user

# WebSocket (auth via first message)
GET    /ws                                  # WebSocket real-time updates

# Health & Operations (no auth, for load balancer / monitoring)
GET    /health                              # Returns { status: "ok", uptime, connected_clients, db_size }

Server operational monitoring: The /health endpoint returns JSON with the server's own metrics:

{
  "status": "ok",
  "uptime_seconds": 86400,
  "connected_clients": 342,
  "db_size_bytes": 52428800,
  "pending_alerts": 3,
  "version": "1.0.0"
}

6.2 WebSocket Events (Server → Browser)

// Device status update
{ type: "device_status", device_uid: "...", cpu: 45.2, memory: 62.1, ... }

// Device online/offline
{ type: "device_state", device_uid: "...", status: "online" | "offline" }

// USB event
{ type: "usb_event", device_uid: "...", event: "inserted", usb_name: "..." }

// New alert
{ type: "alert", alert_id: 123, severity: "warning", content: "..." }

// New device registered
{ type: "device_new", device_uid: "...", hostname: "..." }

6.3 Alert Engine

Rule evaluation happens in the TCP session handler, immediately when data arrives:

Incoming StatusReport → parse metrics → check alert rules (in-memory cache) →
  if threshold breached:
    1. INSERT into alert_records
    2. dispatch notification (email/webhook) asynchronously
    3. push WebSocket event to connected admins

Incoming UsbEvent → check USB policies →
  if unauthorized:
    1. Send PolicyUpdate to client (block device)
    2. INSERT into alert_records
    3. dispatch notification
    4. push WebSocket event

Alert cooldown: Same rule + same device triggers at most once per 5 minutes (configurable) to prevent alert storms.

7. Web Frontend Design

7.1 Technology Stack

  • Vue.js 3 with Composition API + TypeScript
  • Vite for development and build
  • Vue Router 4 for SPA routing
  • Pinia for state management
  • Element Plus for UI components
  • ECharts 5 for charts (CPU/memory/disk history)
  • Axios for HTTP requests

7.2 Key Pages

Dashboard: Overview cards (device count, online/offline, alerts), recent USB events timeline, top alert devices, real-time updates via WebSocket.

Devices: Table with hostname, IP, group, status badge (green/red), CPU/memory mini-sparklines. Click row → DeviceDetail with hardware info, software list, metric history charts.

Assets: Two tabs - hardware inventory (filterable table) and software inventory (searchable). Change log view with diff highlighting.

USB Control: Policy editor (drag-and-drop rule ordering), event timeline with device/USB details, policy test simulator.

Alerts: Split view - rules on left, alert list on right. Severity badges (info/warning/critical). Inline handling with notes.

Settings: SMTP config, Webhook URLs, user management, system info.

7.3 Build Integration

The Vue.js SPA builds to web/dist/ and is embedded into the server binary at compile time:

// server/src/main.rs
use include_dir::{include_dir, Dir};

static FRONTEND: Dir = include_dir!("$CARGO_MANIFEST_DIR/../../web/dist");

// Serve embedded SPA
app.route("/", get(|| async { /* serve index.html */ }))
   .route("/assets/{*path}", get(|| async { /* serve static files */ }))
   .fallback_service(ServeDir::from(FRONTEND))

8. Security Design

8.1 Communication Security

  • Client ↔ Server: TLS 1.3 over TCP (rustls, no OpenSSL dependency)
  • Browser ↔ Server: HTTPS (rustls), JWT tokens in HTTP-only cookies
  • Certificate lifecycle:
    • Initial setup: Server generates a self-signed CA + server certificate on first run, stored in config/cert.pem + config/key.pem
    • Client trust: The CA certificate fingerprint is embedded in the client installer at build time. On first connection, the client verifies the server cert against this known CA. This prevents MITM attacks without requiring a public CA.
    • Certificate rotation: Admin uploads new cert via PUT /api/settings/tls. Server signals all connected clients via ConfigUpdate(TlsCertRotate). Clients download the new CA cert over the existing trusted TLS connection before reconnecting with the new cert. Old cert remains valid for a 24-hour overlap window.
    • Custom CA: Admin can replace the self-signed CA with a company PKI cert at any time via the settings API or config file (PEM format).

8.2 Authentication & Authorization

Admin Authentication (Browser → Server)

  • Login: Username + bcrypt password → JWT access token (30min expiry) + refresh token (7 days, stored in HTTP-only Secure cookie)
  • JWT transport: Access token in Authorization: Bearer <token> header
  • Token refresh: POST /api/auth/refresh with refresh token cookie → new access token
  • RBAC: Two roles - admin (full access) and viewer (read-only)
  • Rate limiting: Login endpoint limited to 5 attempts per minute per IP
  • WebSocket auth: Client sends { type: "auth", token: "<jwt>" } as the first message after connection. Server closes the connection if auth fails within 5 seconds.

Client Authentication (Agent → Server)

  • Registration flow:
    1. Admin generates a registration token via POST /api/settings/registration-token (returns a single-use token valid for 24h)
    2. Token is embedded in the client installer or provided during manual setup
    3. Client sends Register message with payload: { device_uid, hostname, registration_token, os_info }
    4. Server validates the registration token, creates the device record, and returns a device-specific secret (random 256-bit key)
    5. Client stores the secret in the Windows Credential Store (encrypted with DPAPI)
    6. All subsequent connections include a HMAC-SHA256 signature of the message using this device secret
  • Session auth: After registration, every message from the client includes { device_uid, timestamp, hmac } where hmac = HMAC-SHA256(device_secret, timestamp + payload). Server verifies HMAC before processing.
  • De-provisioning: DELETE /api/devices/:uid revokes the device's record. Server adds the device_uid to a revocation list (in-memory + SQLite). If the decommissioned client reconnects, the server sends a ConfigUpdate(SelfDestruct) command that causes the client to stop its service and delete its local credentials.

8.3 Data Security

  • Passwords: bcrypt with cost factor 12
  • JWT secrets: Configurable, random if not set
  • Database: SQLite file permissions 0600 (owner read/write only)
  • Logs: No sensitive data in logs (no passwords, no full content)
  • HTTPS enforced: HTTP requests redirect to HTTPS

8.4 Client Integrity

  • Code signing: Recommended to sign client binary with company certificate
  • Anti-tampering: Client verifies its own SHA-256 checksum on startup against the value stored in the Windows Credential Store (set during installation)
  • Secure update: Server provides update with Ed25519 signature. Client verifies signature before replacing binary. Update is atomic: download to temp file → verify → rename (crash-safe on Windows via MoveFileEx with MOVEFILE_REPLACE_EXISTING)

8.5 Admin Audit Trail

All admin actions are logged for compliance:

CREATE TABLE admin_audit_log (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id         INTEGER NOT NULL REFERENCES users(id),
    action          TEXT NOT NULL,       -- 'login' | 'create_policy' | 'delete_device' | etc.
    target_type     TEXT,               -- 'device' | 'policy' | 'rule' | 'user' | 'setting'
    target_id       TEXT,
    detail          TEXT,               -- JSON: what changed
    ip_address      TEXT NOT NULL,
    created_at      TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE INDEX idx_audit_log_user_time ON admin_audit_log(user_id, created_at);
CREATE INDEX idx_audit_log_time ON admin_audit_log(created_at);

9. Technology Stack Summary

9.1 Shared (protocol crate)

Dependency Version Purpose
serde 1 Serialization framework
serde_json 1 JSON serialization
thiserror 1 Error types

9.2 Client (Windows)

Dependency Version Purpose
tokio 1 (full) Async runtime
windows 0.54 Windows API bindings (modern, replaces winapi)
wmi 0.14 WMI queries for hardware info
rustls 0.23 TLS (no OpenSSL)
sysinfo 0.30 Cross-platform system info (fallback)
serde 1 Message serialization
tracing 0.1 Structured logging
anyhow 1 Error handling
uuid 1 Device UID generation
windows-service 0.7 Windows Service integration

9.3 Server

Dependency Version Purpose
axum 0.7 Web framework
tokio 1 (full) Async runtime
sqlx 0.7 (sqlite) Database (compile-time checked queries)
rustls 0.23 TLS
tower-http 0.5 CORS, compression, static file serving
serde 1 JSON serialization
tracing 0.1 Structured logging
tracing-subscriber 0.3 Log formatting
anyhow 1 Error handling
jsonwebtoken 9 JWT token handling
bcrypt 0.15 Password hashing
lettre 0.11 Email sending (SMTP)
reqwest 0.12 Webhook HTTP calls
include_dir 0.7 Embed frontend into binary
toml 0.8 Configuration file parsing
uuid 1 ID generation

9.4 Web Frontend

Package Version Purpose
vue ^3.4 UI framework
vue-router ^4.2 SPA routing
pinia ^2.1 State management
element-plus ^2.5 UI components
echarts ^5.4 Charts and visualizations
axios ^1.6 HTTP client
typescript ^5.3 Type safety
vite ^5.0 Build tool
@vueuse/core ^10.7 Composable utilities

10. Plugin Modules (Phase 2) — Detailed Design

Each plugin is an independent client-side module with its own server API and database tables. Plugins can be enabled/disabled per device group via the admin web UI.

10.1 Plugin Architecture

Client Plugin System
├── plugin_manager.rs              # Load/start/stop plugins based on server policy
├── plugins/
│   ├── web_filter/                # 上网拦截
│   │   ├── mod.rs
│   │   ├── hosts.rs               # Modify hosts file for DNS blocking
│   │   └── proxy.rs               # Local proxy for URL filtering
│   ├── usage_timer/               # 时长记录
│   │   ├── mod.rs
│   │   ├── tracker.rs             # Track active/idle time
│   │   └── reporter.rs            # Aggregate and report
│   ├── software_blocker/          # 软件禁止安装
│   │   ├── mod.rs
│   │   ├── registry_watch.rs      # Monitor registry for new installations
│   │   └── process_kill.rs        # Kill blacklisted processes
│   ├── popup_blocker/             # 弹窗拦截
│   │   ├── mod.rs
│   │   └── window_filter.rs       # Enumerate windows, hide known popup patterns
│   ├── usb_file_audit/            # U盘文件操作记录
│   │   ├── mod.rs
│   │   └── file_watcher.rs        # Monitor file ops on removable drives
│   └── screen_watermark/          # 水印管理
│       ├── mod.rs
│       └── overlay.rs             # Transparent overlay window

10.2 Plugin: Web Filter (上网拦截)

Purpose: Block or allow specific URLs/websites based on admin-defined rules.

Client Implementation:

  • Method 1: DNS-level blocking — Modify C:\Windows\System32\drivers\etc\hosts to redirect blocked domains to 127.0.0.1
  • Method 2: Windows Filtering Platform (WFP) — Use WFP API to intercept and block HTTP/HTTPS connections at the network level
  • Preferred: WFP approach (more reliable, doesn't interfere with hosts file)

Server-side:

-- Web filter rules
CREATE TABLE web_filter_rules (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    rule_type   TEXT NOT NULL,       -- 'blacklist' | 'whitelist' | 'category'
    pattern     TEXT NOT NULL,       -- Domain, URL pattern, or category name
    target_type TEXT NOT NULL,       -- 'global' | 'group' | 'device'
    target_id   TEXT,
    enabled     INTEGER NOT NULL DEFAULT 1,
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
);

-- Web access log (for reporting)
CREATE TABLE web_access_log (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid  TEXT NOT NULL REFERENCES devices(device_uid),
    url         TEXT NOT NULL,
    action      TEXT NOT NULL,       -- 'allowed' | 'blocked'
    timestamp   TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE INDEX idx_web_access_log_device_time ON web_access_log(device_uid, timestamp);
CREATE INDEX idx_web_access_log_time ON web_access_log(timestamp);

API:

GET/POST/PUT/DELETE  /api/plugins/web-filter/rules
GET                  /api/plugins/web-filter/log

10.3 Plugin: Usage Timer (时长记录)

Purpose: Track when computers are actively used vs idle, and which applications are used.

Client Implementation:

  • Idle detection: GetLastInputInfo() to detect user idle time
  • Active window tracking: GetForegroundWindow() + GetWindowText() every 5 seconds
  • Session tracking: Log login/logoff events via Windows Session Change notifications
  • Report: Aggregate daily usage data (total active time, per-app time) sent to server every 10 minutes

Server-side:

-- Daily usage summary per device
CREATE TABLE usage_daily (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL REFERENCES devices(device_uid),
    date            TEXT NOT NULL,       -- 'YYYY-MM-DD'
    total_active_minutes INTEGER,
    total_idle_minutes   INTEGER,
    first_active_at TEXT,
    last_active_at  TEXT,
    UNIQUE(device_uid, date)
);

-- Per-app usage (aggregated daily)
CREATE TABLE app_usage_daily (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL REFERENCES devices(device_uid),
    date            TEXT NOT NULL,
    app_name        TEXT NOT NULL,
    usage_minutes   INTEGER,
    UNIQUE(device_uid, date, app_name)
);

API:

GET  /api/plugins/usage-timer/daily          # Daily usage summary
GET  /api/plugins/usage-timer/app-usage      # Per-app usage breakdown
GET  /api/plugins/usage-timer/leaderboard    # Usage ranking across devices

10.4 Plugin: Software Blocker (软件禁止安装)

Purpose: Prevent installation of blacklisted software; auto-uninstall if detected.

Client Implementation:

  • Registry monitoring: Watch HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall for new entries
  • Process monitoring: Periodically scan running processes against blacklist
  • Enforcement:
    1. Detect blacklisted software installation → terminate installer process
    2. Report to server → admin gets alert
    3. Optionally auto-uninstall via msiexec /x or UninstallString from registry

Server-side:

-- Software blacklist
CREATE TABLE software_blacklist (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    name_pattern    TEXT NOT NULL,       -- Regex or glob pattern to match software name
    category        TEXT,               -- 'game', 'social', 'vpn', 'custom'
    action          TEXT NOT NULL DEFAULT 'block', -- 'block' | 'alert'
    target_type     TEXT NOT NULL,       -- 'global' | 'group' | 'device'
    target_id       TEXT,
    enabled         INTEGER NOT NULL DEFAULT 1,
    created_at      TEXT NOT NULL DEFAULT (datetime('now'))
);

-- Software violation log
CREATE TABLE software_violations (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL REFERENCES devices(device_uid),
    software_name   TEXT NOT NULL,
    action_taken    TEXT NOT NULL,       -- 'blocked_install' | 'auto_uninstalled' | 'alerted'
    timestamp       TEXT NOT NULL DEFAULT (datetime('now'))
);

API:

GET/POST/PUT/DELETE  /api/plugins/software-blocker/blacklist
GET                  /api/plugins/software-blocker/violations

10.5 Plugin: Popup Blocker (弹窗拦截)

Purpose: Suppress popup ads and unwanted notification windows.

Client Implementation:

  • Window enumeration: EnumWindows() to list all visible windows
  • Pattern matching: Match window title/class against known popup patterns (configurable from server)
  • Suppression: ShowWindow(hwnd, SW_HIDE) or PostMessage(hwnd, WM_CLOSE, 0, 0) for matched popups
  • Built-in list: Common popup patterns (Flash ads, browser notifications, update nags)
  • Allow list: Admin can specify windows that should never be blocked

Server-side:

-- Popup filter rules
CREATE TABLE popup_filter_rules (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    rule_type       TEXT NOT NULL,       -- 'block' | 'allow'
    window_title    TEXT,               -- Pattern for window title
    window_class    TEXT,               -- Pattern for window class name
    process_name    TEXT,               -- Pattern for process name
    target_type     TEXT NOT NULL,
    target_id       TEXT,
    enabled         INTEGER NOT NULL DEFAULT 1,
    created_at      TEXT NOT NULL DEFAULT (datetime('now'))
);

API:

GET/POST/PUT/DELETE  /api/plugins/popup-blocker/rules
GET                  /api/plugins/popup-blocker/stats   # Block count statistics

10.6 Plugin: USB File Audit (U盘文件操作记录)

Purpose: Log all file operations (copy, delete, rename, move) on USB storage devices.

Client Implementation:

  • Drive detection: Monitor for new removable drives via WM_DEVICECHANGE + DBT_DEVICEARRIVAL
  • File monitoring: ReadDirectoryChangesW() on the detected USB drive letter
  • Logged operations: File name, operation type (create/delete/rename), file size, timestamp
  • Report: Batch send to server every 30 seconds while USB is mounted

Server-side:

-- USB file operation log
CREATE TABLE usb_file_operations (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    device_uid      TEXT NOT NULL REFERENCES devices(device_uid),
    usb_serial      TEXT,               -- Identify which USB device
    operation       TEXT NOT NULL,       -- 'create' | 'delete' | 'rename' | 'modify'
    file_path       TEXT NOT NULL,       -- Path on USB drive
    file_size       INTEGER,
    timestamp       TEXT NOT NULL DEFAULT (datetime('now'))
);

API:

GET  /api/plugins/usb-file-audit/log          # File operation log
GET  /api/plugins/usb-file-audit/summary      # Per-device USB file activity summary

10.7 Plugin: Screen Watermark (水印管理)

Purpose: Display a transparent, non-removable watermark overlay on the screen showing company name, username, and timestamp.

Client Implementation:

  • Overlay window: Create a layered, transparent, click-through window (WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST) covering the entire screen
  • Rendering: GDI+ or Direct2D to draw semi-transparent text (company name, {username}, {hostname}, {date}, {time})
  • Persistence: Re-create overlay on display change events (WM_DISPLAYCHANGE)
  • Tamper resistance: Monitor overlay window existence, re-create if closed

Server-side:

-- Watermark configuration
CREATE TABLE watermark_config (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    target_type     TEXT NOT NULL,       -- 'global' | 'group' | 'device'
    target_id       TEXT,
    content         TEXT NOT NULL,       -- Template: "Company: {company} | User: {username} | {date}"
    font_size       INTEGER DEFAULT 14,
    opacity         REAL DEFAULT 0.15,   -- 0.0 to 1.0
    color           TEXT DEFAULT '#808080',
    angle           INTEGER DEFAULT -30, -- Rotation angle in degrees
    enabled         INTEGER NOT NULL DEFAULT 1,
    updated_at      TEXT NOT NULL DEFAULT (datetime('now'))
);

API:

GET/POST/PUT/DELETE  /api/plugins/watermark/config

10.8 Plugin Message Types (Protocol Extension)

// Additional message types for plugins
#[repr(u8)]
pub enum PluginMessageType {
    // Web Filter
    WebFilterRuleUpdate  = 0x20,
    WebAccessLog         = 0x21,

    // Usage Timer
    UsageReport          = 0x30,
    AppUsageReport       = 0x31,

    // Software Blocker
    SoftwareBlacklist    = 0x40,
    SoftwareViolation    = 0x41,

    // Popup Blocker
    PopupRules           = 0x50,

    // USB File Audit
    UsbFileOp            = 0x60,

    // Screen Watermark
    WatermarkConfig      = 0x70,

    // Generic plugin control
    PluginEnable         = 0x80,
    PluginDisable        = 0x81,
}

11. Build & Deploy

11.1 Build Process

# Build frontend
cd web && npm install && npm run build

# Build server (embeds frontend)
cd crates/server && cargo build --release

# Build client
cd crates/client && cargo build --release --target x86_64-pc-windows-msvc

11.2 Deployment Checklist

Server:

  • Copy csm-server.exe to target directory
  • Create config.toml with production values
  • Generate JWT secret: openssl rand -hex 32
  • Configure SMTP credentials for alert emails
  • Set up TLS certificate (or use self-signed for testing)
  • Create initial admin user: csm-server --init-admin
  • Start as Windows Service or use nssm to register

Client:

  • Build MSI installer (via cargo-wix or WiX Toolset)
  • Configure server address in installer
  • Deploy via GPO, SCCM, or manual installation
  • Verify client appears in web dashboard

12. Performance Targets

Metric Target Notes
Client CPU usage < 2% Steady state, excluding asset collection
Client memory < 50MB Including all monitoring modules
Client disk < 10MB Binary + local cache
Server memory < 200MB 500 connected clients
Server CPU < 5% Steady state with 500 clients
API response time < 100ms Typical CRUD operations
WebSocket latency < 500ms Alert to browser
Database size ~500MB/year 500 devices, 90-day retention
Deployment size ~20MB Server binary with embedded frontend

13. Data Retention & Cleanup

A background task (tokio::spawn(cleanup_task)) runs every hour and prunes data based on configurable retention windows:

Table Default Retention Cleanup Method
device_status Current only (upsert) N/A
device_status_history 7 days DELETE WHERE sampled_at < datetime('now', '-7 days')
usb_events 90 days DELETE WHERE event_time < datetime('now', '-90 days')
asset_changes 365 days (forever by default) DELETE WHERE changed_at < datetime('now', '-365 days')
alert_records 90 days (unhandled kept) DELETE WHERE handled = 1 AND created_at < datetime('now', '-90 days')
admin_audit_log 365 days DELETE WHERE created_at < datetime('now', '-365 days')
web_access_log (P2) 30 days High-volume, aggressive pruning
usb_file_operations (P2) 90 days Standard retention

Retention windows are configurable via config.toml:

[retention]
status_history_days = 7
usb_events_days = 90
asset_changes_days = 365
alert_records_days = 90
audit_log_days = 365

SQLite backup: Admin can trigger a manual backup via POST /api/settings/backup, which creates a timestamped copy of the SQLite file using sqlite3 .backup command (via sqlx VACUUM INTO). Auto-backup can be configured to run daily.

14. Error Handling & Resilience

Client-Side Failure Modes

Failure Detection Recovery
Server unreachable TCP connect timeout (10s) Exponential backoff reconnect (1s → 60s max). Buffer events locally (up to 1000).
TLS certificate changed Cert mismatch on handshake If new cert is signed by known CA, accept and update local cache. If unknown, alert admin via tray notification and retry in 5 minutes.
Client binary update fails Hash/signature verification failure Discard update, keep running version, report failure to server.
Local sled database corruption sled auto-recovery on open If unrecoverable, clear local buffer and re-register with server.
Service crash Windows Service recovery options Configured to auto-restart after 30 seconds (via Windows Service recovery settings).

Server-Side Failure Modes

Failure Detection Recovery
SQLite database lock SQLITE_BUSY error busy_timeout = 5000ms handles most cases. If still fails after 5s, log error and return 503 to API client. Client data is buffered and retried.
SQLite database corruption sqlx connection error on startup Attempt PRAGMA integrity_check. If failed, restore from latest backup. If no backup, reinitialize schema (data loss).
Email notification failure SMTP connection error Retry 3 times with 30s interval. Log failure. Alert is still stored in DB (just not delivered). Admin can see undelivered alerts in the UI.
Webhook notification failure HTTP timeout or non-2xx response Retry 3 times with exponential backoff (1s, 5s, 30s). Log failure. Same as email — alert is stored regardless.
WebSocket disconnect Client heartbeat timeout (60s) Remove session from active viewers list. Client reconnects automatically. No data loss — missed events are fetched via REST API on reconnect.