OSS health dashboard
A full-stack dashboard that tracks the health of open-source repositories, syncing pull requests, issues, commits and contributors from the GitHub API on a schedule, then reporting how long PRs take to merge, whether the issue backlog is growing, and who is active over the last 90 days. Repos are tracked per user, compared side by side and drilled into individually. Built on my own published component library, and deployed to a real Kubernetes cluster.
- TypeScript
- React 19
- FastAPI
- PostgreSQL
- Redis
- Celery
- Kubernetes (k3s)
By the numbers
- 71ms
- Dashboard load, p50
- 21x faster, from 1,510ms
- 368 KB
- Initial JavaScript
- 53% smaller, from 782 KB
- 0.98
- Lighthouse performance
- CLS 0, signed out and in
- £0
- Monthly hosting cost
- down from $39 on managed services
Key features
- Scheduled ingestion pipeline
- Celery beat triggers a sync every 15 minutes; a worker paginates the GitHub API across pull requests, issues, commits, contributors, reviews and issue comments, caching responses to stay well inside the rate limit.
- Repos tracked, compared and drilled into
- Each user keeps their own watchlist, sees every tracked repo side by side over a chosen window, and can open one for its full contributor and trend breakdown. Syncs can be triggered and stopped from the UI rather than only on the schedule.
- Measured performance work, not asserted
- Every optimisation was benchmarked against 1,000 to 1,800 PRs per repository and written up in PERFORMANCE.md, including the places where the expected win turned out not to exist.
- 21x faster dashboard load
- Redis caching takes the landing request from 1,510ms to 71ms at p50, and from 6.5 to 136 requests per second under concurrency. Measuring the uncached path honestly needed a distinct cache key per request, since hammering one URL only ever misses once.
- Aggregation pushed into SQL
- Moving per-repo statistics from Python-side loops into SQL aggregates is 2.3x faster on a 1,048-PR repository and 4.3x on an 1,818-PR one — and, unlike the naive version, roughly flat in the number of rows rather than growing with them.
- 53% smaller initial bundle
- Route-level and chart-library code splitting cuts initial JavaScript from 782KB to 368KB, worth around 0.4s of LCP on a simulated mobile connection. Lighthouse scores 0.98 with a CLS of 0 on both the login page and the signed-in dashboard.
- Three ways in, one account
- Email and password, Continue with GitHub, and Continue with Google, driven off one provider table so a fourth is a line of config plus two functions. A provider signing in with a verified email links onto the existing account rather than forking a second one — unverified addresses are refused, since accepting them would let anyone set a victim's address at some provider and sign straight in. Providers can be unlinked again, unless it would remove the account's last way back in.
- Revocable sessions by design
- Authentication uses opaque random tokens in Redis rather than JWTs, because a JWT is only as revocable as its expiry; sign-out is a single DEL. Sessions are httpOnly cookies, the OAuth round trip is CSRF-protected by a state cookie compared in constant time, and failed logins are rate limited per email and IP pair — both, so neither a shared IP nor a targeted email can be used to lock someone out.
- Real Kubernetes, not a demo
- A single-node k3s cluster running Postgres as a StatefulSet with a PersistentVolumeClaim, Redis in-cluster, migrations as a one-off Job, readiness and liveness probes on every workload, and the API, worker and scheduler as three Deployments of one image so each restarts independently. Beat is pinned to one replica — a second would double-fire every sync.
- One origin, no CORS
- nginx serves the built SPA and proxies /api to the API Service, so the browser sees a single origin and the session cookie stays first-party. Nothing in the build knows the deployment's address, which is what lets the whole stack be destroyed and recreated at a different IP.
- Cost engineering as an explicit decision
- The managed-services design (RDS + ElastiCache + always-on compute) would have cost about $39/month. Moving the data tier into the cluster took it to ~$11, and moving the cluster onto an always-free ARM host took it to £0/month — with a permanently live URL rather than one that exists only during a demo, and the trade-offs documented rather than hidden.
Tech stack
Backend
- FastAPI + SQLAlchemy 2.0 with Alembic migrations, running on PostgreSQL
- Celery worker and beat scheduler over Redis, which doubles as response cache and session store
- Opaque-token session auth with bcrypt password hashing, login rate limiting keyed on email and IP, and GitHub/Google OAuth alongside email and password, with multiple providers linkable to one account
Frontend
- React 19 + TypeScript + Vite with React Router 7, styled with Tailwind CSS 4
- Built on neelam-ui, my own published component library, consumed as a real npm dependency
- Recharts for trend visualisation, lazy-loaded so it stays out of the initial bundle; web-vitals reporting in the browser
Infrastructure
- Docker Compose for local development, driven by a Taskfile so setup is two commands
- Kubernetes (k3s) in production: separate Deployments for API, worker and scheduler, nginx serving the SPA and proxying the API from one origin, and Caddy terminating TLS with automatically renewed certificates on a free DuckDNS subdomain
- Multi-architecture container images (arm64 + amd64) published to Docker Hub
- Scripted, idempotent deployments to either an always-free ARM host or an on-demand cloud instance
CI
- GitHub Actions running pytest against live Postgres and Redis service containers with migrations applied first, frontend lint, typecheck and build, and Lighthouse CI asserting performance, accessibility, CLS, LCP and blocking-time budgets over three runs
Skills demonstrated
Backend API design and data modelling, background job scheduling and third-party API integration, query optimisation and cache strategy backed by benchmarks, authentication and session security, Kubernetes manifest authoring and cluster operation, infrastructure automation, CI pipeline configuration, and cost-aware architecture decisions with the trade-offs written down.