Horizon Social Network - Microservices Backend
Overview
What it is
Horizon Social Network is a Go backend for a campus social platform. It has two services: Posts stores user posts in MongoDB, and Followers stores the social graph in Neo4j.
Both services run on Kubernetes behind Istio. Keycloak handles identity, the Istio ingress gateway validates JWTs, and the mesh encrypts service-to-service traffic with mTLS.
Why it exists
I built it as part of a university workshop project to apply microservices and Kubernetes concepts in practice. I treated it like a production backend: posts and follower relationships have different data shapes, so I split them into separate services with separate databases instead of forcing both workloads into one model.
The workshop gave me room to apply the parts I care about as a cloud and DevOps engineer: container builds, Kubernetes deployment, service mesh policy, auth at the edge, and clear service boundaries.
Outcome
- Distroless images under 10MB per service, about 90% smaller than the distro-base build
- One database per workload: MongoDB for posts and timelines, Neo4j for the follower graph
- Istio validates Keycloak JWTs at ingress and enforces mTLS; the Go services carry no auth code
- Full Kubernetes deployment: manifests, config, secrets, and Istio routing
Architecture
High-Level Flow
The client enters through the Istio ingress gateway. Istio validates the Keycloak JWT before the request reaches a service, then routes traffic through the mesh. Posts reads and writes MongoDB documents. Followers handles graph queries in Neo4j.
Implementation Highlights
- Both services follow the same Go layout (handler, service, repository) with OpenAPI specs, built through one Dockerfile that selects the target service with a build arg.
- MongoDB stores post documents with a
user_idindex for timeline reads. Neo4j storesUsernodes and directionalFOLLOWSrelationships, so friend suggestions stay in Cypher instead of application-side joins. - Istio enforces mTLS between services and validates Keycloak JWTs at ingress through
RequestAuthenticationandAuthorizationPolicy. Services read identity headers instead of parsing tokens. - Kubernetes manifests cover Deployments, ClusterIP services, Istio routing, ConfigMaps for connection settings, and Secrets for database credentials.
Key Challenges & Solutions
Challenge 1: Choosing the Right Database Per Workload
Problem: Posts fit a document model. Followers fit a graph model. Putting both in one database would either complicate timeline reads or push graph traversal into application code.
Solution: I split the backend by workload. Posts uses MongoDB for document storage and indexed timeline reads. Followers uses Neo4j for relationship traversal and friend suggestions. When a feature needs both sides, one service calls the other over REST.
Each service uses a database that matches its query pattern. Friend suggestions stay in Cypher instead of turning into nested application-side joins.
Challenge 2: Keeping Auth Out of Each Service
Problem: Adding JWT parsing to each service would duplicate security code. A third service would need the same middleware again.
Solution: I moved authentication to Istio. The ingress gateway validates Keycloak JWTs through RequestAuthentication, and AuthorizationPolicy blocks unauthenticated traffic before it reaches Go. Services read the identity headers Istio passes through.
The Go services do not carry JWT parsing code. A new service can join the mesh and inherit the same auth policy.