Skip to main content

Backend Overview

The Proxima Console backend is a Go 1.26+ API server that serves as the central hub for infrastructure data collection, storage, and retrieval. It exposes a RESTful API for the frontend, ingests telemetry data from agents via NATS JetStream, and provides observability through OpenTelemetry tracing and Prometheus metrics.

Technology Stack​

  • Language: Go 1.26+
  • HTTP Router: chi — lightweight, composable router
  • Database Access: sqlx with raw SQL (no ORM)
  • Logging: slog — structured JSON logging to stdout
  • Messaging: NATS 2.10+ with JetStream for agent data ingestion
  • Tracing: OpenTelemetry with OTLP exporter
  • Metrics: Prometheus exposition format at /metrics

Architecture​

The backend runs as a single process that combines the HTTP API server and background workers. This simplifies deployment for the MVP phase while still maintaining clean internal separation of concerns.

┌─────────────────────────────────────────────┐
│ Backend Process │
│ │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ HTTP API │ │ Workers │ │
│ │ (chi) │ │ (NATS consumers)│ │
│ └──────┬──────┘ └────────┬─────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ Domain / Store │ │
│ └──────────────┬──────────────────────┘ │
│ │ │
└─────────────────┼───────────────────────────┘
▼
┌───────────────┐ ┌────────────────────┐
│ PostgreSQL │ │ VictoriaMetrics │
│ (relational) │ │ (time-series) │
└───────────────┘ └────────────────────┘

Request Flow​

  1. HTTP requests arrive at the chi router.
  2. Middleware handles authentication, request ID injection, CORS, and logging.
  3. Handlers validate input, call the store layer, and return JSON responses.
  4. All responses follow a consistent envelope format with data, meta, and error fields.

Data Ingestion Flow​

  1. Agents publish inventory and telemetry data to NATS JetStream subjects.
  2. Workers subscribe to these subjects via durable consumers on the EVENTS and TELEMETRY streams.
  3. Messages are validated, transformed, and persisted to PostgreSQL (inventory/heartbeats) or VictoriaMetrics (metrics).

The ingest path is served by these workers (the composition root wires far more — roughly 57 worker constructors in total, covering escalation, notifications, triage, compliance, fleet updates and the auditors):

  • EventsWorker — creates two consumers. backend-events-worker on the EVENTS stream takes changes and healthcheck; backend-snapshots-worker on the SNAPSHOTS stream takes inventory, kubernetes and connections. It does not handle heartbeats.
  • HeartbeatWorker — its own consumer, backend-heartbeat-worker, on the HEARTBEAT stream.
  • TelemetryWorker — consumer backend-telemetry-worker on the TELEMETRY stream. Dispatches metrics to MetricsWorker, which imports into VictoriaMetrics via the Prometheus import API.
  • StaleDetectorWorker — periodically sweeps for agents that have not sent a heartbeat within the configured timeout (default 5 minutes) and sets their agent_status to offline.

Worker Architecture​

Workers follow an interface-driven pattern for testability and extensibility:

  • MessageProcessor interface — defined in worker/message.go. Every sub-worker (InventoryWorker, HeartbeatWorker, MetricsWorker) implements a single method: Process(ctx, *MessageEnvelope, *slog.Logger) error.
  • Parent workers accept processors via constructor — EventsWorker and TelemetryWorker receive their sub-workers as MessageProcessor interfaces, not concrete types. This decouples the NATS consumer logic from database or VictoriaMetrics dependencies.
  • Handler-local interfaces — StaleDetectorWorker defines a local staleMarker interface with a single MarkStaleOffline method, following the Go idiom of defining interfaces at the consumer, not the producer.
  • Composition root in main.go — Sub-workers are created with their concrete dependencies (e.g., NewInventoryWorker(db)) and injected into parent workers. The worker packages have zero knowledge of what backs their interfaces.

This architecture enables unit testing workers with mock processors (no real database or VictoriaMetrics needed) and supports splitting workers into separate processes in the future without changing the interface contracts.

Key Packages​

PackagePathResponsibility
apiinternal/api/HTTP handlers, middleware (auth, logging, CORS, request ID), router setup
domaininternal/domain/Domain models and types (Client, Environment, Host, Service, etc.)
storeinternal/store/Database access layer — raw SQL queries via sqlx
transportinternal/transport/NATS connection management, JetStream setup, message publishing/subscribing
workerinternal/worker/Background processors — EventsWorker (inventory, heartbeats), TelemetryWorker (metrics) consume NATS messages, and StaleDetectorWorker marks unresponsive agents offline
metricsinternal/metrics/VictoriaMetrics-backed MetricsService implementing metricStore and aggregateMetricStore interfaces using MetricsQL queries
vmclientinternal/vmclient/HTTP client for VictoriaMetrics Cluster (Import, QueryRange, Query, LabelValues, Health)
tenantcacheinternal/tenantcache/Thread-safe TTL cache for host→tenant resolution (avoids per-metric DB lookups)

Design Decisions​

  • Raw SQL over ORM: All database queries are written as plain SQL using sqlx. This provides full control over query performance, makes it easy to use PostgreSQL-specific features, and avoids the abstraction overhead of an ORM.
  • slog for logging: Structured JSON logs are written to stdout, following twelve-factor app principles. Every log entry includes a request_id for traceability.
  • Single process for MVP: The API server and workers run in the same process to reduce operational complexity. They can be separated into distinct services in a future phase if scaling demands it.
  • REST-first, with two deliberate exceptions: the API is REST with polling and SSE. WebSocket is used only for interactive terminal access (/api/v1/terminal/ws and the multi-party /ws/join), and gRPC serves the pc CLI's terminal, proxy-ssh and port-forward paths on PROXIMA_GRPC_PORT. There is no GraphQL.