← Back to portfolio

Backend and GitOps platform system

RunState

Production-style uptime monitoring platform with Go, Redis Streams, workers, Postgres, Docker, Kubernetes, and GitOps.

RunState monitors websites at regular intervals, records uptime and response-time history, detects status transitions, tracks incidents, persists notification logs, and exposes user/admin dashboards. The backend is built in Go with authentication, RBAC, Postgres persistence, Redis Streams, and a reusable worker engine. The deployment is managed through a separate GitOps repo with Kubernetes, ArgoCD, External Secrets, ingress/TLS, Prometheus, HPA, and image automation.

Product problem

Website monitoring is not just storing URLs. A real monitoring platform needs periodic checks, background workers, response-time history, incident lifecycle tracking, notification logging, authentication, admin visibility, metrics, and production deployment.

What I built

RunState splits monitoring into a backend API and event-driven worker pipeline. The API handles users, auth, websites, incidents, notification logs, and dashboards. Redis Streams coordinate background work between the monitoring pusher, monitoring worker, status-change worker, and notification worker. Postgres stores durable operational state.

Architecture

System path

The product has five runtime services: API server, monitoring pusher, monitoring worker, status-change worker, and notification worker. Docker Compose runs the local stack, while the GitOps repo declares Kubernetes Deployments, Services, Ingress, External Secrets, HPA, monitoring resources, and ArgoCD applications.

01

API Server

02

Postgres

03

Monitoring Pusher

04

Redis Monitoring Stream

05

Monitoring Worker

06

Status Change Stream

07

Status Change Worker

08

Notification Stream

09

Notification Worker

Visual proof

Screenshots and architecture from the source repos

These assets are pulled from the project repositories so the case studies show the actual product workflow, architecture diagrams, dashboards, and runtime proof instead of placeholder cards.

Architecture

Monitoring stream

How website checks move through the Redis-backed monitoring pipeline.

Monitoring stream

Product workflow

How the product actually runs

  1. 01User signs up or signs in
  2. 02User adds a website URL to monitor
  3. 03API stores the website under that user
  4. 04Monitoring pusher publishes check jobs into Redis Streams
  5. 05Monitoring worker performs HTTP checks and records ticks
  6. 06Status transitions emit status-change events
  7. 07Status-change worker creates or resolves incidents
  8. 08Notification worker records notification attempts
  9. 09User and admin dashboards display operational state

Why it is not trivial

The hard parts are system boundaries

  • Models monitoring as a background processing system rather than simple CRUD.
  • Uses Redis Streams to separate pusher, worker, incident, and notification responsibilities.
  • Connects local Docker development with Kubernetes and GitOps deployment proof.

RunState proves backend/platform depth by connecting API design, auth, workers, Redis Streams, Postgres modeling, incident workflows, notification logs, metrics, Docker, CI, Kubernetes, and GitOps.

Subsystem deep dive

Why monitoring is not CRUD

A basic app can store website URLs, but a monitoring platform must continuously schedule checks, process them asynchronously, detect transitions, persist operational history, and make incidents and notifications visible.

  • Checks cannot run inside request/response paths.
  • Status transitions need incident lifecycle state.
  • Notifications need audit logs rather than invisible side effects.

Runtime services

RunState is split into separate runtime services so each process has one responsibility and can be deployed, restarted, or scaled independently.

  • API server handles auth, websites, incidents, notifications, health checks, and metrics.
  • Monitoring pusher schedules website checks.
  • Monitoring worker performs HTTP checks and records ticks.
  • Status-change worker manages incident transitions.
  • Notification worker handles notification delivery/log persistence.

Redis Streams pipeline

Redis Streams decouple the monitoring workflow. The pusher publishes check jobs, workers consume through consumer groups, and downstream workers react to status-change and notification events.

  • Monitoring Stream carries website-check jobs.
  • Status-change Stream carries transition events.
  • Notification Stream carries alert events.

Worker engine

The common worker engine abstracts long-running Redis Stream consumption and provides consistent runtime behavior across workers.

  • Consumer group setup and blocking stream reads.
  • Concurrent message processing and in-flight tracking.
  • ACK handling, panic recovery, graceful shutdown, heartbeat support, and reclaim loops.

GitOps deployment

The app repo builds and publishes the product image. The runstate-gitops repo declares the Kubernetes state. ArgoCD reconciles the cluster to the GitOps repo and image automation can update manifests when new tags are published.

  • Separate application and deployment state.
  • External Secrets pulls values from AWS Secrets Manager.
  • Ingress/TLS, prometheus ServiceMonitor, HPA, and image automation prove platform thinking.

Data model

Durable state behind the UI

  • Users store email, password hash, role, and timestamps for auth/RBAC.
  • Refresh Tokens store hashes, expiration, and revocation state.
  • Region makes monitoring extensible beyond one worker location.
  • Website stores monitored URLs, owner, current status, and time added.
  • Website Ticks store check status, response time, region, and timestamp.
  • Incidents store downtime periods with start, resolution, status, and active state.
  • Notification Logs store channel, recipient, previous/current status, delivery status, provider message ID, and sent time.

Engineering decisions

Tradeoffs and reliability boundaries

  • Rebuilt the backend in Go to deepen backend and systems understanding.
  • Split API, pusher, monitoring worker, status-change worker, and notification worker into separate processes.
  • Used Redis Streams for pipeline coordination instead of request-path checks.
  • Stored durable operational history in Postgres.
  • Modeled incidents separately from current website status.
  • Persisted notification logs.
  • Built a common worker engine.
  • Separated app repo from GitOps repo.
  • Used External Secrets instead of checked-in secrets.
  • Added Prometheus metrics and autoscaling.

What makes it more than a demo

  • Asynchronous background workers.
  • Redis Streams event pipeline with consumer groups.
  • Status transition detection.
  • Incident lifecycle modeling.
  • Notification delivery/logging.
  • Dockerized multi-service local setup.
  • CI image publishing.
  • Kubernetes GitOps deployment with secrets, ingress, TLS, monitoring, and HPA.

Next improvements

  • Add multi-region monitoring.
  • Add stronger retry/backoff and dead-letter handling for failed stream messages.
  • Add richer notification preferences and public status pages.
  • Add better SLO dashboards and integration tests around worker pipelines.
  • Add production-grade alerting around the monitoring system itself.

Proof links

Proof links connect to the source repos, demos, architecture assets, screenshots, and engineering journals used to build this case study.

Final takeaway

RunState proves backend/platform depth by connecting API design, auth, workers, Redis Streams, Postgres modeling, incident workflows, notification logs, metrics, Docker, CI, Kubernetes, and GitOps.