Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 2 min read

I built a study tracker on a $12/month Kubernetes cluster. Here's the stack and what I learned

I kept starting learning roadmaps (DSA, system design, AI engineering) and then losing track: what I'd covered, how much time I'd really put in, and what was next. Spreadsheets didn't stick. So I built Gradiaqo, a free a

I kept starting learning roadmaps (DSA, system design, AI engineering) and then losing track: what I'd covered, how much time I'd really put in, and what was next. Spreadsheets didn't stick. So I built Gradiaqo, a free app that turns any subject into a study plan and tracks your progress.

What it does

  • Ready-made paths: DSA, System Design, AI Engineer and Data Scientist
  • Your own paths: build one in the app, or import it from a spreadsheet or YAML file
  • Study sessions: log your time and watch your progress add up
  • Streaks and analytics to keep you going, plus an "interview ready" view
  • Organizations, so a team or a coding club can share paths

The stack

It's a Turborepo monorepo with Yarn 4:

  • API: NestJS, TypeORM and Postgres. Request and response schemas use TypeBox, and CASL handles permissions (who can edit which path).
  • Web: React 19 and Vite.
  • Shared packages: the database entities, the schemase in their own packages, so the API, the web app and a small CLI all use the same code.
  • Tests: Vitest with a 100% coverage requirement, Planst a real database, and Stryker mutation testing to check that the tests actually catch bugs.

Hosting: one small node

Production is a single-node k3s cluster on Civo (1 CPU, 2ncluding the storage volume.

  • Traefik takes the traffic and cert-manager getses.
  • Caddy serves the built React app and proxies everything else to the API, so the app and the API share one origin. That keeps the refresh-token cookie simple: no cross-site cookie headach
  • GitHub Actions builds the images and pushes them to A deploy is a kubectl rollout restart.
  • Backups: a nightly CronJob runs pg_dump, encryptsnd uploads it to OneDrive. It keeps 30 days. I tested a restore before trusting it.

Things that surprised me

1. My cloud provider blocks outgoing email ports. Civverification emails just timed out. Brevo, my SMTP
provider, also accepts port 2525, which fixed it. Check t it.

2. Postgres reorders your JSON. I store some item detmporter compared the stored value with the file to decide
whether anything changed, and every re-import "changed" eep key order. Comparing with sorted keys fixed it.

3. Old Traefik on managed k3s. The provider's Traefik custom resource definitions or an IngressClass. Middleware
like the http β†’ https redirect needed the older `traefik. Ingress is silently ignored, check your Traefik version
first.

**4. A single-page app is invisible to search engines by al robots.txt, a sitemap.xml, page titles, canonical
links and Open Graph tags, Google showed "No information and link previews were blank. Build those into the buildstep: my Vite config now generates robots.txt and the sitemap for the production domain.

5. CI doesn't need to run for a README change. A smalged and skips the test jobs when only docs or deploy files
changed. Branch protection still passes, because the skip

What's next

  • Public pages for each learning path, so people can brow
  • Pre-rendering the homepage for search engines
  • Study reminders

Try it and tell me what's broken

It's early, and I'd love feedback from anyone preparing fething new: what's confusing, what's missing, and what
would make you open it every day?

πŸ‘‰ gradiaqo.com

I'm happy to go deeper on any part of the stack in the comments.

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.