Logo
JobTracker icon

Project 01

JobTracker

I built a personal job search tool that keeps every stage of an application in one place. It stores applications, CVs and cover letters, generates the cover letter PDFs, and reads replies straight from Gmail to move each application forward on its own.

Role

  • Product Design
  • Full Stack Development

Stack

  • Next.js
  • TypeScript
  • Supabase
  • Gmail API
  • LLM
JobTracker

Overview

Applying for jobs in Vienna meant a spreadsheet, a folder full of PDFs and an inbox where every reply slowly disappeared under everything else. Keeping track of who had answered, which CV I had sent and what needed a follow-up took more effort than writing the applications themselves.

So I built one tool for all of it. Applications live in a table or on a board, documents sit next to them, and every change is recorded in a timeline. Cover letters are written in the app and rendered onto my own Figma layout, so the design stays exactly as drawn while only the text changes.

Goal

The tool should do the bookkeeping I kept forgetting. Not another place to maintain by hand, but something that picks up what happens in my inbox and keeps the board honest without me touching it.

At the same time it was a chance to build a small product end to end, from the data model and row level security in Postgres to the drag and drop board and the PDF rendering, and to treat a private tool with the same care for detail as a public one.

Gmail sync

Once a Gmail account is connected, the app looks for replies from companies I actually applied to. Matching runs in three stages with decreasing confidence, starting with a known email thread, then the sender domain, and finally the company name in the text combined with a job related keyword. Applicant tracking systems like Personio or Greenhouse are handled as well, since many companies never send from their own domain.

A language model then decides whether a message is a rejection, an interview invitation, an offer or just a confirmation of receipt. When the match is strong and the model is confident, the status changes on its own and the email appears in the timeline. When it is not, the app offers a suggestion I can accept or dismiss with one click. A wrong status would be worse than none, so the automation only acts where it is sure.

The model never sees my inbox. The search is scoped to my own applications, message bodies are only loaded for emails that already matched, and what gets sent is a shortened snippet with links, addresses, phone numbers and quoted history removed. The classifier sits behind an interface, so switching to a local model instead of a cloud API is a single environment variable.

Screens

JobTracker screen 1
JobTracker screen 2
JobTracker screen 3
JobTracker screen 4
JobTracker screen 5
JobTracker screen 6
JobTracker screen 7

More Work