A microservices-based Electric Vehicle simulation platform running on Kubernetes.
Note: A weekend project built to practice gRPC streaming, the LGTM Stack (Loki, Grafana, Prometheus), Kubernetes, and PostGIS. Intentionally over-engineered.
- Visualization: Renders a graph of devices surrounding a user-selected coordinate.
- Management: Allows adding, editing, and connecting devices.
- Streaming: Bridges gRPC streams to SSE for live charge/status updates.
Background worker managing the charging logic:
- Cut-off: Charging stops automatically at 100%.
- Drain: Idle devices lose 1% battery per tick.
- Load Balancing: Devices under 20% attempt to charge. Access is denied if the local grid cell (1km radius) has > 5 active chargers.
flowchart TB
User((Browser))
subgraph K8s [Kubernetes Cluster]
direction TB
subgraph Ingress [Service Layer]
Web[HTTP Service<br/>Go]
end
subgraph Backend [Private Network]
NodeAPI[Core API<br/>Node]
Engine[<b>Sim Engine</b><br/>Go]
Migrator([Migration Job<br/>Ephemeral])
DB[(Postgres<br/>PostGIS)]
end
subgraph Obs [Observability Namespace]
direction TB
Grafana
Loki
Prometheus
Promtail([Promtail<br/>DaemonSet])
end
end
%% Real-time User Flow (SSE + HTTP)
User <-->|HTTP/SSE| Web
Web <-->|"ConnectRPC<br/>(Unary + Stream)"| NodeAPI
%% Operational Access
User -.->|Port Forward<br/>localhost:3000| Grafana
%% Database Access
NodeAPI -->|Read/Write| DB
Engine -->|Tick/Update| DB
Migrator -->|Schema Updates| DB
%% Metrics Pipeline (Prometheus Scrapes Services)
Prometheus -->|Scrape Metrics| Web & NodeAPI & Engine
%% Logging Pipeline (Promtail tails containers)
Web & NodeAPI & Engine -.->|Stdout| Promtail
Promtail -->|Push Logs| Loki
%% Visualization
Grafana -->|LogQL| Loki
Grafana -->|PromQL| Prometheus
%% Styling
classDef go fill:#00add8,stroke:#333,color:white;
classDef node fill:#68a063,stroke:#333,color:white;
classDef db fill:#336791,stroke:#333,color:white;
classDef obs fill:#e6522c,stroke:#333,color:white;
classDef sim fill:#f96,stroke:#333,color:white;
class Web go;
class NodeAPI node;
class DB,Loki,Prometheus db;
class Promtail,Grafana obs;
class Engine sim;
- Language: Go 1.25
- Role: Backend-for-Frontend (BFF) & Charting.
- Security: No DB access. Communicates via ConnectRPC.
- Language: Node.js (>=24) / TypeScript
- Role: Domain logic and persistence.
- Transport: ConnectRPC (Unary + Server Streaming).
- Database: Postgres 16 + PostGIS.
- Language: Go 1.25
- Role: Simulation ticker.
- Logic: Handles battery decay and
ST_SnapToGridspatial capacity checks. - Testing: Integration tests via Testcontainers.
- Engine writes new charge state to DB.
- Browser opens EventSource to Go HTTP.
- Go HTTP opens gRPC Stream to Node API.
- Node API streams DB updates to Go.
- Go HTTP pushes updates to Browser via SSE.
Uses the loki-stack Helm chart to deploy a self-hosted telemetry suite.
Management via Makefile.monitoring:
| Target | Description |
|---|---|
make -f Makefile.monitoring deploy |
Install grafana/loki-stack (Loki, Prom, Grafana) |
make -f Makefile.monitoring port-forward |
Access Grafana (localhost:3000) |
make -f Makefile.monitoring password |
Retrieve Grafana admin password |
make -f Makefile.monitoring delete |
Uninstall Stack |
make build-rest
make build-http
make build-engineApplies Kustomize overlay, migration jobs, and network policies.
make deploy-dev# Go Web UI (http://localhost:30080)
make port-forward-http# Stream all logs
make logs ENV=dev
# Stream specific service
kubectl logs -f -l app=engine -n ev-sim-devSource: /proto/device.proto.
# Regenerate code
cd http && make proto
cd rest && pnpm protoMost useful operations are standardized across the project via Makefiles.
- Root Makefile: Handles high-level K8s operations (deploy, delete, status).
- Module Makefiles: Each service (
/http,/engine,/rest) contains a dedicated Makefile for component-level tasks likemake deps,make test, ormake help.
Root Makefile Reference:
| Target | Description |
|---|---|
deploy-dev |
Apply Kustomize overlay |
delete-dev |
Delete resources |
restart-dev |
Rollout restart |
status |
Show Pod/Service status |

