Architecture Overview
System Diagram
┌──────────────────────────────────────────────────────────────────────────┐
│ Data Sources │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────────────┐ │
│ │ voltage │ │ suricata │ │ aws-s3 │ │ aws-s3-lambda │ │
│ │(endpoint)│ │(network) │ │ (batch) │ │ (real-time / Lambda) │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────────┬─────────────┘ │
└───────┼─────────────┼─────────────┼───────────────────┼──────────────────┘
│ │ │ │
│ ┌────┴─────┐ │ S3 event → CloudTrail
│ │ Redis │ │ → EventBridge (StackSet)
│ │ Pub/Sub │ │ → Central event bus
│ └────┬─────┘ │ │
│ │ │ STS AssumeRole (member acct)
│ │ │ S3 GetObject (cross-account)
└─────────────┴─────────────┴───────────────────┘
│
│ HTTPS (JWT)
▼
┌────────────────────────────────┐
│ highvolt-server │
│ │
│ POST /submit ──► Queue │
│ POST /query ──► OpenSearch │
│ │
│ Workers │
│ (goroutines) │
└──────────┬─────────────────────┘
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────────┐
│ LLM │ │OpenSearch│ │ JSONAir │
│(OpenAI │ │(results │ │(config store)│
│ compat.) │ │ storage) │ │ │
└──────────┘ └──────────┘ └──────────────┘Configuration Management (JSONAir)
All components fetch their runtime configuration from JSONAir, an external configuration service. This separates configuration from deployment. On startup each component:
Authenticates to JSONAir using a Personal Access Token (PAT) from the environment.
Downloads its JSON configuration blob.
Starts a background goroutine (
Monitor_Config) that polls JSONAir on a configurable interval and hot-reloads if the config changes.
Request Lifecycle
A client (Voltage, Suricata, AWS-S3) discovers a file matching a configured MIME type.
The client computes MD5, SHA1, and SHA256 hashes of the file.
The client queries
highvolt-serverwith the SHA256 — if the file has already been analyzed, it is skipped.The client base64-encodes the file and submits it to
highvolt-serveras a JSON payload.highvolt-servervalidates the payload, places it on an internal in-memory queue, and returns immediately (async).A worker goroutine dequeues the work, classifies the MIME type, and routes it to the appropriate processor (IMAGE, TEXT, PDF, OFFICE, or ARCHIVE).
The processor sends the file to the LLM via an OpenAI-compatible
POST /chat/completionsrequest.The LLM returns a JSON verdict. The worker merges the verdict into the original submission JSON and indexes it to OpenSearch, using the SHA256 as the document ID.
The raw
file_datafield is stripped before storage — only metadata and LLM results are saved.
Deduplication
Most clients maintain a local GOB binary registry (a map[string]bool serialized to disk) keyed by SHA256 hash (Voltage) or S3 path (aws-s3). Before submitting a file, the client checks this local cache first, then confirms with the server via the /query endpoint. This two-layer approach avoids re-downloading large files unnecessarily.
The aws-s3-lambda client is stateless and has no local registry. It relies solely on the server-side SHA256 query for deduplication. Because the Lambda is only invoked for newly created objects, re-processing existing objects is not a concern.
Concurrency Model
highvolt-server uses a bounded worker pool. The pool size (max_workers) and queue depth (max_queue_size) are both configurable. Submissions that arrive when the queue is full are rejected with HTTP 503.
Authentication Flow
JWT tokens are short-lived (configurable expiry). Clients detect 401 responses and automatically re-authenticate.
Last updated