The Problem

Businesses need a single pane that can ingest metrics, logs, and traces from any source, surface them in real‑time dashboards, and alert before an issue escalates. Existing tools often require multiple products or heavyweight agents, creating operational overhead and blind spots.

What This Does

deepops is a portfolio of four loosely coupled projects that together form “XO”, an observability platform aimed at developers:

  • datav – the UI and API server (≈ 1 072 files). It renders dashboards, panels, and large‑screen views. Core entry points are datav/frontend/src/index.tsx and datav/frontend/src/App.tsx. The UI is built with React/TypeScript, bundled by Vite (datav/frontend/vite.config.js).
  • otel-collector – a Go‑based OpenTelemetry collector (≈ 187 files) that receives spans, metrics and logs, then forwards them to the datav backend.
  • examples – sample Go applications (e.g., examples/hotrod) that emit OTLP data for quick validation.
  • deploy – minimal Helm‑style manifests and scripts for deploying the stack in Kubernetes.

Common techniques across the suite are Go modules (go.mod), Docker multi‑stage builds (datav/Dockerfile, datav/frontend/Dockerfile), and a shared TypeScript type layer for dashboard definitions.

How It Is Wired

Execution starts with the frontend Docker image built from datav/frontend/Dockerfile. The image runs Vite’s production build (npm run build) and serves index.html via an Nginx template (datav/frontend/nginx.template). The compiled bundle calls src/index.tsx, which mounts the React app onto the DOM and registers routes such as /dashboard/:id (handled in src/pages/dashboard/index.tsx).

When a dashboard loads, the UI contacts the backend API (served by the same Go binary in datav/Dockerfile). The API reads configuration from datav/.env (currently committed) and opens a gRPC server that the otel‑collector talks to. The collector (otel-collector/main.go) subscribes to OTLP over gRPC, normalizes data, and writes it into the internal time‑series store used by the UI.

Key wiring points:

ModuleResponsibilityBlast‑radius
datav/frontend/src/views/dashboard/plugins/built-in/pluginsRegisters all built‑in panel plugins (imports 27 other modules)High – any change ripples through most dashboards
datav/frontend/src/components/largescreen/autoResizeProvides responsive layout utilities (imported by 24 modules)Low – stable helper
datav/frontend/src/views/dashboard/edit-panel/EditPanelHandles panel edit UI (imports 15 modules, only 1 inbound)Very high instability (0.94) – prone to breakage

The static import graph shows 27 import cycles (e.g., plugins.ts ↔ query_runner.ts ↔ PanelGrid.tsx). These cycles inflate compile time and hinder refactoring because a change forces recompilation of many unrelated modules.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/deepops
cd deepops

# Build the UI container
docker build -t datav-frontend -f datav/frontend/Dockerfile .

# Build the backend/API container
docker build -t datav-backend -f datav/Dockerfile .

# (Optional) Run the OpenTelemetry collector
docker build -t otel-collector -f otel-collector/Dockerfile .
docker run -p 4317:4317 otel-collector

The UI expects environment variables defined in datav/frontend/.env (e.g., VITE_API_URL). Remove this file from the repository, replace it with a template (.env.example), and supply the variables at container start:

docker run -e VITE_API_URL=http://localhost:8080 -p 80:80 datav-frontend

The backend API runs on port 8080 by default; start it with:

docker run -p 8080:8080 datav-backend

The example applications can be built with Go modules:

cd examples/hotrod
go build -o hotrod .
./hotrod

Real‑World Use

A SaaS provider can deploy the three containers (frontend, backend, collector) into a Kubernetes namespace using the manifests in deploy/. The collector receives OTLP data from microservices, the backend stores it, and the UI lets operators assemble custom dashboards without leaving the platform.

Code Health & Issues

  • High – No CI/CD – 1069 source files lack any GitHub Actions or other pipeline.
  • High – No build gate for datav/Dockerfile – Docker image is never validated automatically.
  • High – Committed .env – Secrets are tracked in source history; must be removed and rotated.
  • Medium – Dependabot missing – No automated dependency updates for package.json, go.mod, or Docker images.
  • Medium – Base images not pinnedgolang:1.21.4-alpine3.18, node:16, alpine:3.18 are mutable tags.
  • Medium – No pre‑commit secret scan – Increases risk of future leaks.
  • Medium – Container runs as rootdatav/Dockerfile lacks a non‑root USER.
  • Low – Missing repo conventions – No .editorconfig, .gitattributes, or shared formatter config.

Additional static findings (192 total) include 27 import cycles, several hub modules with > 20 inbound imports, deep nesting (up to 8 levels), and a 611‑line PanelGrid.tsx file that should be split.

The Bottom Line

deepops offers a functional, UI‑rich observability stack that can be containerised and deployed with minimal effort, but the codebase suffers from architectural debt (import cycles, oversized modules) and a lack of production‑grade hygiene (no CI, secret leakage, root containers). It is suitable for teams that need a quick, customizable dashboard layer and are prepared to invest in refactoring and adding CI/security gates.