Pick a skill: the parts where I used it light up on the map and I tell you what for.
- NestJS
- The whole API: one module per domain, JWT and role guards, transactions when awarding XP and the WebSocket gateway.
- JavaScript / TypeScript
- Backend and frontend in TypeScript, sharing the same types in the monorepo.
- Next.js
- I contributed to the frontend: server components for the leaderboards and the NextAuth session in an HTTP-only cookie.
- PostgreSQL
- UUID schema, questions in JSONB, indexes for the leaderboard and the unique constraint that ended double XP.
- Keycloak
- OIDC login with PKCE, its own realm, admin and student roles, and JWT validation with its public keys.
- Redis
- Socket.io bridge between replicas and leaderboard cache: from 150 ms to 2 ms.
- Kubernetes / K3s
- Single-node K3s cluster: Deployments, PostgreSQL as a StatefulSet, volumes, migration Jobs and Traefik routes.
- Argo CD
- GitOps: Argo CD kept the cluster exactly as described in Git. Nothing was applied by hand.
- GitLab CI · GitHub Actions
- Lint, tests (Jest and Playwright with JUnit reports), multi-stage builds and images published with the commit tag.
- Prometheus · Grafana · Loki
- Prometheus with cAdvisor, Loki and Promtail for logs, and seven alert rules in Grafana.
- Docker
- Multi-stage images from 1.2 GB down to 180 MB; locally everything started with docker-compose.
- Traefik
- K3s Ingress with Let's Encrypt, behind my home Traefik. The Keycloak loop was fixed with X-Forwarded-Proto.
- Linux (Debian, Alpine, Arch)
- I set the node up from scratch: system, firewall and K3s.
- Proxmox VE
- The cluster VM lived on my Proxmox server, next to the rest of the homelab.
- Git
- Monorepo with feature branches and hooks (husky and lint-staged) that refused commits with errors.