Skip to main content

PatchMon Architecture Documentation

Table of Contents

  1. System Overview
  2. Nginx Reverse Proxy
  3. BullMQ Queue System
  4. Database Schema
  5. API Credential Scoping
  6. WebSocket Communication
  7. Agent Communication Flow
  8. Authentication & Authorization

System Overview

graph TB
    subgraph "Client Layer"
        Browser[Web Browser]
        Agent[PatchMon Agent<br/>Go Binary]
    end

    subgraph "Reverse Proxy Layer"
        Nginx[Nginx<br/>Port 80/443]
    end

    subgraph "Application Layer"
        Frontend[React Frontend<br/>Vite + Tailwind]
        Backend[Node.js Backend<br/>Express Server<br/>Port 3001]
    end

    subgraph "Queue System"
        Redis[(Redis<br/>Queue Storage)]
        BullMQ[BullMQ Queues]
        Workers[BullMQ Workers]
    end

    subgraph "Data Layer"
        PostgreSQL[(PostgreSQL<br/>Primary Database)]
    end

    subgraph "External Services"
        OIDC[OIDC Provider<br/>Optional]
        DNS[DNS Server<br/>Version Check<br/>server.vcheck.patchmon.net]
    end

    Browser -->|HTTPS/HTTP| Nginx
    Agent -->|HTTPS/HTTP<br/>WebSocket| Nginx
    Nginx -->|"Proxy /api/*"| Backend
    Nginx -->|"Proxy /bullboard"| Backend
    Nginx -->|Serve Static| Frontend
    Backend -->|Read/Write| PostgreSQL
    Backend -->|Queue Jobs| BullMQ
    BullMQ -->|Store Jobs| Redis
    Workers -->|Process Jobs| BullMQ
    Workers -->|Read/Write| PostgreSQL
    Backend -->|WebSocket| Agent
    Backend -->|OAuth| OIDC
    Backend -->|DNS TXT Query| DNS

Nginx Reverse Proxy

Request Routing Flow

graph LR
    Client[Client Request] --> Nginx{Nginx<br/>Port 80/443}
    
    Nginx -->|"Location: /"| Frontend[Frontend<br/>Static Files<br/>/usr/share/nginx/html]
    Nginx -->|"Location: /api/*"| Backend[Backend API<br/>http://backend:3001]
    Nginx -->|"Location: /bullboard"| Backend[Bull Board UI<br/>http://backend:3001/bullboard]
    Nginx -->|"Location: /assets/*"| Assets[Custom Branding<br/>/usr/share/nginx/html/assets/]
    Nginx -->|"Location: /health"| Health[Health Check<br/>200 OK]
    
    Backend -->|WebSocket Upgrade| WS[WebSocket Handler]

Nginx Configuration Details

Key Features:

  • Port 3000 (Docker) or 80/443 (Production)
  • SSL/TLS support with Let's Encrypt
  • WebSocket upgrade support for real-time communication
  • Security headers (HSTS, X-Frame-Options, CSP)
  • Cookie passthrough for authentication
  • IP forwarding (X-Real-IP, X-Forwarded-For)
  • Large file uploads (10MB limit for API routes)

Location Blocks:

  1. / - Frontend SPA (try_files for client-side routing)
  2. /api/* - Backend API proxy with WebSocket support
  3. /bullboard - Bull Board queue monitoring UI
  4. /assets/* - Custom branding assets (logos, favicons)
  5. /health - Health check endpoint

BullMQ Queue System

Queue Architecture

graph TB
    subgraph "Queue Manager"
        QM[QueueManager<br/>Singleton]
    end

    subgraph "Queues (BullMQ)"
        Q1[version-update-check]
        Q2[session-cleanup]
        Q3[orphaned-repo-cleanup]
        Q4[orphaned-package-cleanup]
        Q5[docker-inventory-cleanup]
        Q6[docker-image-update-check]
        Q7[metrics-reporting]
        Q8[system-statistics]
        Q9[social-media-stats]
        Q10[agent-commands]
        Q11[alert-cleanup]
        Q12[host-status-monitor]
    end

    subgraph "Workers"
        W1[VersionUpdateCheck Worker]
        W2[SessionCleanup Worker]
        W3[OrphanedRepoCleanup Worker]
        W4[OrphanedPackageCleanup Worker]
        W5[DockerInventoryCleanup Worker]
        W6[DockerImageUpdateCheck Worker]
        W7[MetricsReporting Worker]
        W8[SystemStatistics Worker]
        W9[SocialMediaStats Worker]
        W10[AgentCommands Worker]
        W11[AlertCleanup Worker]
        W12[HostStatusMonitor Worker]
    end

    subgraph "Storage Layer"
        Redis[(Redis<br/>Job Storage)]
    end

    subgraph "Database"
        DB[(PostgreSQL)]
    end

    QM --> Q1
    QM --> Q2
    QM --> Q3
    QM --> Q4
    QM --> Q5
    QM --> Q6
    QM --> Q7
    QM --> Q8
    QM --> Q9
    QM --> Q10
    QM --> Q11
    QM --> Q12

    Q1 --> Redis
    Q2 --> Redis
    Q3 --> Redis
    Q4 --> Redis
    Q5 --> Redis
    Q6 --> Redis
    Q7 --> Redis
    Q8 --> Redis
    Q9 --> Redis
    Q10 --> Redis
    Q11 --> Redis
    Q12 --> Redis

    W1 --> Q1
    W2 --> Q2
    W3 --> Q3
    W4 --> Q4
    W5 --> Q5
    W6 --> Q6
    W7 --> Q7
    W8 --> Q8
    W9 --> Q9
    W10 --> Q10
    W11 --> Q11
    W12 --> Q12

    W1 --> DB
    W2 --> DB
    W3 --> DB
    W4 --> DB
    W5 --> DB
    W6 --> DB
    W7 --> DB
    W8 --> DB
    W9 --> DB
    W10 --> DB
    W11 --> DB
    W12 --> DB

    W10 -->|WebSocket Commands| AgentWS[Agent WebSocket]

Queue Details

Queue Name Purpose Schedule Worker
version-update-check Check for PatchMon updates Daily VersionUpdateCheck
session-cleanup Clean expired user sessions Hourly SessionCleanup
orphaned-repo-cleanup Remove unused repositories Daily OrphanedRepoCleanup
orphaned-package-cleanup Remove unused packages Daily OrphanedPackageCleanup
docker-inventory-cleanup Clean Docker inventory Daily DockerInventoryCleanup
docker-image-update-check Check Docker image updates Daily DockerImageUpdateCheck
metrics-reporting Report anonymous metrics Daily MetricsReporting
system-statistics Generate system statistics Hourly SystemStatistics
social-media-stats Fetch social media stats On boot SocialMediaStats
agent-commands Send commands to agents On demand AgentCommands
alert-cleanup Clean old alerts Daily AlertCleanup
host-status-monitor Monitor host status Every 5 min HostStatusMonitor

Worker Configuration

  • Concurrency: 1 job at a time per worker
  • Retry Policy: 3 attempts with exponential backoff
  • Job Retention: 50 completed, 20 failed jobs
  • Connection: Shared Redis connection pool

Version Check Mechanism

The version update check uses DNS TXT records instead of GitHub API to avoid rate limiting and provide a lightweight, fast version checking mechanism.

DNS Domains:

  • Server version: server.vcheck.patchmon.net
  • Agent version: agent.vcheck.patchmon.net

How it works:

  1. Worker queries DNS TXT record for the appropriate domain
  2. DNS returns version string (e.g., "1.4.0") in TXT record
  3. Version is validated against semantic versioning format
  4. Compared with current version from package.json (server) or agent binary
  5. Update alerts created if newer version available

Benefits:

  • No API rate limits
  • Fast DNS lookups (cached by DNS resolvers)
  • No authentication required
  • Works even if GitHub API is unavailable

Implementation:

  • Uses Node.js dns.resolveTxt() for DNS queries
  • Validates version format: ^\d+\.\d+\.\d+
  • Falls back to cached version from database if DNS lookup fails

Database Schema

Core Entity Relationships

erDiagram
    users ||--o{ user_sessions : has
    users ||--o{ dashboard_preferences : has
    users ||--o{ auto_enrollment_tokens : creates
    users ||--o{ alerts : assigned_to
    users ||--o{ alerts : resolved_by
    users ||--o{ alert_history : creates
    
    hosts ||--o{ host_packages : has
    hosts ||--o{ host_repositories : has
    hosts ||--o{ host_group_memberships : belongs_to
    hosts ||--o{ update_history : has
    hosts ||--o{ job_history : has
    hosts ||--o{ docker_containers : has
    hosts ||--o{ docker_volumes : has
    hosts ||--o{ docker_networks : has
    hosts ||--o{ compliance_scans : has
    
    packages ||--o{ host_packages : "installed on"
    repositories ||--o{ host_repositories : "used by"
    
    host_groups ||--o{ host_group_memberships : contains
    host_groups ||--o{ auto_enrollment_tokens : "default group"
    
    compliance_profiles ||--o{ compliance_scans : used_in
    compliance_profiles ||--o{ compliance_rules : contains
    compliance_scans ||--o{ compliance_results : produces
    compliance_rules ||--o{ compliance_results : evaluated_in
    
    docker_images ||--o{ docker_containers : used_by
    docker_images ||--o{ docker_image_updates : has
    
    alerts ||--o{ alert_history : has
    alert_config ||--o| users : "auto_assign_to"

Key Tables

Core Tables

users

  • Authentication (password_hash, tfa_secret)
  • OIDC integration (oidc_sub, oidc_provider)
  • Preferences (theme, dashboard layout)
  • Role-based permissions

hosts

  • Unique API credentials (api_id, api_key) - scoped per host
  • System information (OS, hardware, network)
  • Status tracking (status, last_update)
  • Feature flags (docker_enabled, compliance_enabled)

packages

  • Package metadata (name, description, category)
  • Version tracking (latest_version)

host_packages

  • Package instances on hosts
  • Update status (needs_update, is_security_update)
  • Version tracking (current_version, available_version)

repositories

  • Repository definitions (URL, distribution, components)
  • Security status (is_secure, is_active)

Docker Tables

docker_images

  • Image metadata (repository, tag, digest)
  • Source tracking (docker-hub, etc.)

docker_containers

  • Container instances per host
  • Status and state tracking

docker_image_updates

  • Available updates per image
  • Security update flags

Compliance Tables

compliance_profiles

  • Scan profiles (OpenSCAP, Docker Bench)
  • OS family and version mapping

compliance_scans

  • Scan execution records
  • Results summary (passed, failed, score)

compliance_rules

  • Rule definitions per profile
  • Severity and remediation info

compliance_results

  • Individual rule results per scan
  • Findings and remediation details

Alert System Tables

alerts

  • Alert records (type, severity, status)
  • Assignment and resolution tracking

alert_history

  • Audit trail of alert actions
  • User actions (created, resolved, silenced)

alert_config

  • Per-alert-type configuration
  • Auto-assignment rules
  • Retention policies

Job Tracking

job_history

  • BullMQ job execution records
  • Status tracking (active, completed, failed)
  • Linked to hosts via api_id

API Credential Scoping

Credential Types

graph TB
    subgraph "Credential Types"
        HostCreds[Host API Credentials<br/>api_id + api_key<br/>Per-host scoped]
        TokenCreds[Auto Enrollment Tokens<br/>token_key + token_secret<br/>Scoped with permissions]
    end

    subgraph "Host Credentials"
        HostCreds -->|Stored in| HostTable["hosts table<br/>api_id: unique<br/>api_key: hashed"]
        HostCreds -->|Used by| Agent[Agent Authentication<br/>X-API-ID + X-API-KEY headers]
        HostCreds -->|Validated by| HostAuth[validateApiCredentials<br/>middleware]
    end

    subgraph "Token Credentials"
        TokenCreds -->|Stored in| TokenTable["auto_enrollment_tokens table<br/>token_key: unique<br/>token_secret: bcrypt hashed"]
        TokenCreds -->|Scopes| Scopes["JSON scopes object<br/>resource: action array"]
        TokenCreds -->|IP Restrictions| IPRanges[allowed_ip_ranges<br/>CIDR blocks]
        TokenCreds -->|Used by| API[API Integration<br/>Basic Auth]
        TokenCreds -->|Validated by| TokenAuth[authenticateApiToken<br/>+ requireApiScope]
    end

Authentication Flow

Host Authentication (Agent)

sequenceDiagram
    participant Agent
    participant Nginx
    participant Backend
    participant DB

    Agent->>Nginx: POST /api/v1/hosts/update<br/>Headers: X-API-ID, X-API-KEY
    Nginx->>Backend: Proxy request
    Backend->>Backend: validateApiCredentials middleware
    Backend->>DB: Find host by api_id
    DB-->>Backend: Host record
    Backend->>Backend: Verify api_key (bcrypt)
    alt Valid credentials
        Backend->>Backend: Attach hostRecord to req
        Backend->>Backend: Process request
        Backend-->>Nginx: 200 OK + Response
        Nginx-->>Agent: Response
    else Invalid credentials
        Backend-->>Nginx: 401 Unauthorized
        Nginx-->>Agent: 401 Error
    end

Token Authentication (API Integration)

sequenceDiagram
    participant Client
    participant Nginx
    participant Backend
    participant DB

    Client->>Nginx: POST /api/v1/hosts<br/>Authorization: Basic base64(token_key:token_secret)
    Nginx->>Backend: Proxy request
    Backend->>Backend: authenticateApiToken middleware
    Backend->>DB: Find token by token_key
    DB-->>Backend: Token record
    Backend->>Backend: Verify token_secret (bcrypt)
    Backend->>Backend: Check token.is_active
    Backend->>Backend: Check token.expires_at
    Backend->>Backend: Check IP restrictions (CIDR)
    alt Valid token
        Backend->>Backend: requireApiScope middleware
        Backend->>Backend: Validate scope permissions
        alt Has permission
            Backend->>Backend: Attach apiToken to req
            Backend->>Backend: Process request
            Backend-->>Nginx: 200 OK + Response
            Nginx-->>Client: Response
        else No permission
            Backend-->>Nginx: 403 Forbidden
            Nginx-->>Client: 403 Error
        end
    else Invalid token
        Backend-->>Nginx: 401 Unauthorized
        Nginx-->>Client: 401 Error
    end

Scope Structure

Token scopes are stored as JSON in auto_enrollment_tokens.scopes:

{
  "host": ["get", "post", "put", "patch", "delete"],
  "package": ["get", "post"],
  "compliance": ["get", "post"]
}

Scope Validation:

  • Only applies to tokens with metadata.integration_type === "api"
  • Validates scopes[resource].includes(action)
  • Returns 403 if scope not found

WebSocket Communication

WebSocket Architecture

graph TB
    subgraph "Client Layer"
        Browser[Web Browser]
        Agent[PatchMon Agent]
    end

    subgraph "Nginx"
        NginxProxy[Nginx<br/>WebSocket Upgrade]
    end

    subgraph "Backend WebSocket Handlers"
        AgentWS["Agent WebSocket<br/>/ws/agent"]
        SSHWS["SSH Terminal WebSocket<br/>/ws/ssh/:hostId"]
        BullWS[Bull Board WebSocket<br/>/bullboard]
    end

    subgraph "WebSocket Server"
        WSS[WebSocket.Server<br/>noServer: true]
    end

    subgraph "HTTP Server"
        HTTPServer[Express HTTP Server]
    end

    Browser -->|WebSocket Upgrade| NginxProxy
    Agent -->|WebSocket Upgrade| NginxProxy
    NginxProxy -->|Upgrade Request| HTTPServer
    HTTPServer -->|Upgrade Event| WSS
    WSS -->|Route by pathname| AgentWS
    WSS -->|Route by pathname| SSHWS
    WSS -->|Route by pathname| BullWS

Agent WebSocket Flow

sequenceDiagram
    participant Agent
    participant Nginx
    participant Backend
    participant WSS
    participant DB

    Agent->>Nginx: WebSocket Upgrade<br/>/ws/agent?api_id=xxx&api_key=yyy
    Nginx->>Backend: Upgrade request
    Backend->>Backend: HTTP upgrade event handler
    Backend->>DB: Validate api_id + api_key
    alt Valid credentials
        Backend->>WSS: Accept WebSocket connection
        WSS->>Agent: Connection established
        Agent->>WSS: Ping every 30s
        WSS->>Agent: Pong response
        
        Note over WSS,Agent: Bidirectional communication
        
        WSS->>Agent: Command: report_now
        Agent->>WSS: Response: update_data
        
        WSS->>Agent: Command: update_agent
        Agent->>WSS: Response: update_status
        
        WSS->>Agent: Command: compliance_scan
        Agent->>WSS: Progress: compliance_scan_progress
        
        WSS->>Agent: Command: docker_inventory_refresh
        Agent->>WSS: Event: docker_status
    else Invalid credentials
        Backend->>Agent: Connection rejected
    end

SSH Terminal WebSocket Flow

sequenceDiagram
    participant Browser
    participant Nginx
    participant Backend
    participant SSHWS
    participant AgentWS
    participant Agent
    participant SSHHost

    Browser->>Nginx: WebSocket Upgrade<br/>/ws/ssh/:hostId<br/>Cookie: session_token
    Nginx->>Backend: Upgrade request
    Backend->>Backend: Authenticate user session
    alt Authenticated
        Backend->>SSHWS: Accept WebSocket connection
        SSHWS->>Browser: Connection established
        
        Browser->>SSHWS: {type: "connect", connection_mode: "proxy"}
        SSHWS->>SSHWS: Generate proxy session ID
        SSHWS->>AgentWS: Forward to agent WebSocket
        AgentWS->>Agent: SSH proxy request
        Agent->>SSHHost: SSH connection
        Agent->>AgentWS: SSH data stream
        AgentWS->>SSHWS: Forward SSH data
        SSHWS->>Browser: Display terminal
        
        Browser->>SSHWS: Terminal input
        SSHWS->>AgentWS: Forward input
        AgentWS->>Agent: Forward to SSH
        Agent->>SSHHost: Send input
    end

WebSocket Message Types

Agent → Backend

  • docker_status - Docker container status events
  • compliance_scan_progress - Compliance scan progress updates
  • ssh_proxy_data - SSH terminal data (proxy mode)
  • ssh_proxy_connected - SSH connection established
  • ssh_proxy_error - SSH connection error
  • ssh_proxy_closed - SSH connection closed

Backend → Agent

  • report_now - Force immediate update report
  • update_agent - Update agent binary
  • settings_update - Update agent settings (update_interval)
  • refresh_integration_status - Refresh integration status
  • docker_inventory_refresh - Refresh Docker inventory
  • compliance_scan - Start compliance scan
  • remediate_rule - Remediate specific compliance rule
  • ssh_proxy_request - SSH proxy connection request

Agent Communication Flow

Agent Registration & Enrollment

sequenceDiagram
    participant Agent
    participant Nginx
    participant Backend
    participant DB

    Note over Agent: Agent installed on host
    
    Agent->>Nginx: POST /api/v1/hosts/enroll<br/>Authorization: Basic (token_key:token_secret)
    Nginx->>Backend: Proxy request
    Backend->>Backend: authenticateApiToken middleware
    Backend->>DB: Validate enrollment token
    Backend->>DB: Check IP restrictions
    Backend->>DB: Check max_hosts_per_day
    Backend->>DB: Create host record<br/>Generate api_id + api_key
    DB-->>Backend: Host created
    Backend->>DB: Assign to default host group
    Backend-->>Nginx: 201 Created<br/>{api_id, api_key}
    Nginx-->>Agent: Credentials
    Agent->>Agent: Save credentials to<br/>/etc/patchmon/credentials.yaml

Agent Update Reporting

sequenceDiagram
    participant Agent
    participant Nginx
    participant Backend
    participant DB
    participant BullMQ

    Note over Agent: Scheduled update check<br/>(every update_interval minutes)
    
    Agent->>Nginx: POST /api/v1/hosts/update<br/>Headers: X-API-ID, X-API-KEY<br/>Body: {packages, repositories, ...}
    Nginx->>Backend: Proxy request
    Backend->>Backend: validateApiCredentials
    Backend->>DB: Update host record
    Backend->>DB: Upsert packages
    Backend->>DB: Upsert repositories
    Backend->>DB: Create update_history record
    Backend->>BullMQ: Queue system-statistics job
    Backend-->>Nginx: 200 OK
    Nginx-->>Agent: Response

Agent Command Execution

sequenceDiagram
    participant User
    participant Frontend
    participant Backend
    participant BullMQ
    participant Worker
    participant AgentWS
    participant Agent

    User->>Frontend: Click "Update Agent" button
    Frontend->>Backend: POST /api/v1/hosts/:id/update-agent
    Backend->>Backend: Authenticate user (session)
    Backend->>Backend: Check permissions
    Backend->>BullMQ: Add job to agent-commands queue<br/>{api_id, type: "update_agent"}
    Backend-->>Frontend: 202 Accepted
    Frontend-->>User: "Update queued"
    
    BullMQ->>Worker: Process job
    Worker->>Backend: Check agent WebSocket connection
    Worker->>AgentWS: Send command via WebSocket
    AgentWS->>Agent: WebSocket message<br/>{type: "update_agent"}
    Agent->>Agent: Download new binary
    Agent->>Agent: Restart with new binary
    Agent->>AgentWS: Update status
    AgentWS->>Worker: Command completed
    Worker->>DB: Update job_history status

Authentication & Authorization

User Authentication Flow

graph TB
    subgraph "Authentication Methods"
        LocalAuth[Local Auth<br/>Username + Password]
        TFA[Two-Factor Auth<br/>TOTP]
        OIDC[OIDC/OAuth2<br/>Optional]
    end

    subgraph "Session Management"
        Session[User Session<br/>httpOnly cookie]
        RefreshToken[Refresh Token<br/>Database stored]
        AccessToken[Access Token<br/>JWT in cookie]
    end

    subgraph "Authorization"
        Roles[Role-Based<br/>admin, user, viewer]
        Permissions[Permission Matrix<br/>role_permissions table]
    end

    LocalAuth -->|+ TFA| TFA
    LocalAuth -->|+ OIDC| OIDC
    TFA --> Session
    OIDC --> Session
    Session --> RefreshToken
    RefreshToken --> AccessToken
    AccessToken --> Roles
    Roles --> Permissions

Permission Matrix

Permission Admin User Viewer
View Dashboard
View Hosts
Manage Hosts
View Packages
Manage Packages
View Users
Manage Users
Manage Superusers
View Reports
Export Data
Manage Settings

Security Features

  1. Password Security

    • Bcrypt hashing (10 rounds)
    • Password strength requirements
  2. Session Security

    • HttpOnly cookies (XSS protection)
    • Secure flag (HTTPS only)
    • SameSite protection (CSRF mitigation)
    • Device fingerprinting
    • IP address tracking
  3. Two-Factor Authentication

    • TOTP (Time-based One-Time Password)
    • Backup codes
    • Remember device option
  4. API Security

    • Rate limiting
    • IP restrictions (CIDR blocks)
    • Token expiration
    • Scope-based permissions
    • Brute force protection
  5. WebSocket Security

    • Authentication before upgrade
    • API credential validation
    • Message size limits (64KB)
    • Connection timeout handling

Data Flow Examples

Package Update Detection Flow

sequenceDiagram
    participant Agent
    participant Backend
    participant DB
    participant BullMQ
    participant Worker
    participant Frontend

    Note over Agent: Agent checks for updates
    
    Agent->>Backend: POST /api/v1/hosts/update<br/>packages: [{name, current_version, available_version}]
    Backend->>DB: Upsert packages table
    Backend->>DB: Upsert host_packages table<br/>Set needs_update, is_security_update flags
    Backend->>DB: Create update_history record
    Backend-->>Agent: 200 OK
    
    Backend->>BullMQ: Queue system-statistics job
    BullMQ->>Worker: Process job
    Worker->>DB: Aggregate statistics
    Worker->>DB: Create system_statistics record
    
    Frontend->>Backend: GET /api/v1/hosts/:id/packages
    Backend->>DB: Query host_packages with filters
    DB-->>Backend: Package list
    Backend-->>Frontend: Packages with update status

Compliance Scan Flow

sequenceDiagram
    participant User
    participant Frontend
    participant Backend
    participant BullMQ
    participant Worker
    participant AgentWS
    participant Agent
    participant OpenSCAP

    User->>Frontend: Start compliance scan
    Frontend->>Backend: POST /api/v1/compliance/scans/start
    Backend->>Backend: Authenticate user
    Backend->>BullMQ: Queue agent-commands job<br/>{type: "compliance_scan", profile_id}
    Backend-->>Frontend: 202 Accepted
    
    BullMQ->>Worker: Process job
    Worker->>AgentWS: Send WebSocket command
    AgentWS->>Agent: {type: "compliance_scan", profile_id}
    
    Agent->>OpenSCAP: Run oscap scan
    OpenSCAP-->>Agent: Scan results (ARF/XML)
    Agent->>AgentWS: Progress updates<br/>{type: "compliance_scan_progress"}
    AgentWS->>Backend: Forward progress
    Backend->>Frontend: WebSocket broadcast
    
    Agent->>Backend: POST /api/v1/compliance/scans<br/>Scan results
    Backend->>Backend: Parse results
    Backend->>DB: Create compliance_scans record
    Backend->>DB: Create compliance_results records
    Backend-->>Agent: 200 OK
    
    Frontend->>Backend: GET /api/v1/compliance/scans/:id
    Backend->>DB: Query scan results
    DB-->>Backend: Scan details
    Backend-->>Frontend: Results with pass/fail status

Component Details

Backend Structure

backend/
├── src/
│   ├── server.js              # Main Express server
│   ├── middleware/
│   │   ├── auth.js            # User authentication
│   │   ├── apiAuth.js         # API token authentication
│   │   └── apiScope.js        # API scope validation
│   ├── routes/                # API route handlers
│   ├── services/
│   │   ├── automation/        # BullMQ queue management
│   │   ├── agentWs.js         # Agent WebSocket handler
│   │   └── sshTerminalWs.js   # SSH terminal WebSocket
│   └── utils/                 # Utilities
└── prisma/
    └── schema.prisma          # Database schema

Frontend Structure

frontend/
├── src/
│   ├── components/            # React components
│   ├── pages/                 # Page components
│   ├── hooks/                 # Custom React hooks
│   ├── utils/
│   │   └── api.js            # API client (axios)
│   └── App.jsx               # Main app component
└── dist/                      # Built static files

Agent Structure

agent-source-code/
├── cmd/patchmon-agent/
│   └── commands/
│       └── serve.go           # WebSocket server
├── internal/
│   ├── client/                # HTTP client
│   ├── config/                # Configuration management
│   ├── integrations/          # Docker, compliance integrations
│   └── packages/              # Package manager interfaces
└── pkg/models/                # Data models

Deployment Architecture

Docker Compose Setup

graph TB
    subgraph "Docker Network"
        NginxContainer[Nginx Container<br/>Port 3000]
        BackendContainer[Backend Container<br/>Port 3001]
        FrontendContainer[Frontend Container<br/>Static Files]
        PostgresContainer[PostgreSQL Container<br/>Port 5432]
        RedisContainer[Redis Container<br/>Port 6379]
    end

    NginxContainer -->|Proxy| BackendContainer
    NginxContainer -->|Serve| FrontendContainer
    BackendContainer -->|Connect| PostgresContainer
    BackendContainer -->|Connect| RedisContainer

Production Setup

graph TB
    subgraph "Server"
        Nginx[Nginx<br/>System Service<br/>Port 80/443]
        Backend[Node.js Backend<br/>PM2/Systemd<br/>Port 3001]
        Frontend[Static Files<br/>/opt/patchmon/frontend/dist]
        Postgres[PostgreSQL<br/>System Service<br/>Port 5432]
        Redis[Redis<br/>System Service<br/>Port 6379]
    end

    Internet -->|HTTPS| Nginx
    Nginx -->|Proxy| Backend
    Nginx -->|Serve| Frontend
    Backend -->|Connect| Postgres
    Backend -->|Connect| Redis

Performance Considerations

  1. Database Connection Pooling

    • Prisma connection pool (default: 10 connections)
    • Optimized for multiple worker instances
  2. Redis Connection Optimization

    • Shared connection pool for BullMQ
    • Connection reuse across queues and workers
  3. WebSocket Connection Management

    • Connection tracking by api_id
    • Automatic reconnection handling
    • Ping/pong keepalive (30s interval)
  4. Job Processing

    • Low concurrency (1 job/worker) to reduce load
    • Exponential backoff for retries
    • Job retention limits (50 completed, 20 failed)
  5. Caching

    • Integration state cache (60s TTL)
    • Static asset caching (1 year)
    • API response caching where appropriate

Security Architecture

Defense in Depth

  1. Network Layer

    • Nginx reverse proxy
    • SSL/TLS encryption
    • Security headers
    • Rate limiting
  2. Application Layer

    • Input validation
    • SQL injection prevention (Prisma ORM)
    • XSS protection (React escaping)
    • CSRF protection (SameSite cookies)
  3. Authentication Layer

    • Password hashing (bcrypt)
    • Token encryption
    • Session management
    • 2FA support
  4. Authorization Layer

    • Role-based access control
    • API scope validation
    • IP restrictions
    • Resource-level permissions
  5. Data Layer

    • Encrypted credentials storage
    • Audit logging
    • Data retention policies
    • Secure credential transmission

Monitoring & Observability

Bull Board

  • URL: /bullboard (secured, requires authentication)
  • Features:
    • Queue status (waiting, active, completed, failed)
    • Job details and logs
    • Worker status
    • Retry management

Health Checks

  • Endpoint: /health
  • Checks:
    • Database connectivity
    • Redis connectivity
    • Service status

Logging

  • Winston logger (configurable)
  • Log levels: error, warn, info, debug
  • File and console outputs
  • Structured JSON logging

Conclusion

This architecture provides:

  • Scalability: Queue-based job processing, connection pooling
  • Security: Multi-layer security, credential scoping, audit trails
  • Reliability: Retry mechanisms, health checks, graceful shutdown
  • Maintainability: Clear separation of concerns, modular design
  • Observability: Bull Board monitoring, comprehensive logging

For specific implementation details, refer to the source code in the respective directories.