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).

Three top-level workers run in the backend process:

  • EventsWorker — Consumes from the EVENTS stream. Dispatches inventory messages to InventoryWorker and heartbeat messages to HeartbeatWorker.
  • TelemetryWorker — Consumes from the TELEMETRY stream. Dispatches metrics messages to MetricsWorker, which sends metrics to 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 constructorEventsWorker 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 interfacesStaleDetectorWorker 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.
  • No WebSocket/GraphQL/gRPC: The backend uses REST with polling and SSE only. This keeps the API surface simple and widely compatible.