Personal Project

AccessBridge — Unified Session & Access Broker

A six-service backend, modeled on how companies like Imprivata handle unified access management: authenticate once, then get short-lived, audited access into a set of downstream applications, with every access-relevant event streamed for a permanent audit trail and rule-based anomaly detection.

Spring Boot Kafka PostgreSQL Kubernetes React

Why I built this

I spent two years as a junior full-stack engineer working with Spring Boot and relational databases, but Docker and Kubernetes never came up on the job — and almost every role I was looking at afterward wanted both. Rather than list a skill I couldn't actually back up in an interview, I built something big enough that I'd have to learn it properly: a system made of several services that genuinely have to talk to each other, not another single-app CRUD project.

Architecture

Built in six phases, each one verified working end to end before the next started. Every service validates a JWT statelessly using the same signing secret auth-service used to mint it — no service ever calls back to auth-service to check who's asking.

Phase 1

auth-service

Registration, login, password hashing, JWT access/refresh token issuance. Owns identity, not sessions.

Phase 2

session-service

Tracks active sessions and time-boxed access grants into registered target apps. Auto-expires stale sessions and cascades to revoke their grants.

Phase 3

audit-service

Kafka consumer building an immutable, append-only audit log with a filterable query API. No update or delete path — only inserts.

Phase 4

anomaly-service

A second, independent consumer of the same event stream. Rule-based detection: failed-login bursts, impossible travel via IP geolocation, unusual access hours.

Phase 5

policy-service & dashboard

A pure REST facade for RBAC admin (users, roles, target apps) with no database of its own, plus a React dashboard calling every service directly from the browser.

Phase 6

Kubernetes & AWS

Kustomize base + local/AWS overlays, deployed and driven end to end on a real kind cluster, plus a Terraform skeleton for EKS/RDS/MSK.

The dashboard

Screenshots from a real run against the live stack — Kafka, Postgres, and all five backend services actually running, not mocked.

What actually went wrong (and what it taught me)

The interesting parts of this project weren't the features — they were the handful of real bugs that only show up once you have more than one service, or once you deploy to something more real than docker-compose.

A cross-phase Kafka bug, not a hypothetical one

Adding anomaly-service's new event type in Phase 4 would have broken the already-shipped audit-service the moment it shipped, since its deserializer had no idea what to do with an event type it had never seen. Fixed by wrapping every full-stream consumer's deserializer so unrecognized types are skipped, not fatal.

Kubernetes found two bugs docker-compose never could

A Kafka pod crash traced back to Kubernetes auto-injecting a KAFKA_PORT env var that collided with the image's own config convention. A separate liveness-probe race killed JVM services that were merely slow to start, not broken, under CPU contention. Neither would have surfaced if I'd stopped at "the yaml builds."

CORS reminded me the browser isn't curl

Every caller through Phase 4 was curl or another backend service. The moment the dashboard called five services directly from the browser in Phase 5, same-origin policy became a real, unavoidable requirement for the first time in this project.

Read the full writeup

Tech stack

Java 21 Spring Boot 3 Spring Security Kafka (KRaft) PostgreSQL Flyway React + Vite + TypeScript Docker Kubernetes (kind) Kustomize Terraform GitHub Actions
Current status: all six phases are complete and verified — the full stack runs end to end both on docker-compose and on a real local Kubernetes cluster. The AWS path (Terraform for EKS/RDS/MSK, an ALB Kustomize overlay) is structurally validated but hasn't been applied against a real AWS account, since that costs real money to leave running just to prove a point.