ai-powered application tracker
JobTrack — Intelligent Job Search
A Gemini insights layer that walks six models down when the free quota runs out.
- role
- solo developer
- status
- ● live demo
- scale
- 6-model Gemini fallback
- stack
- React 19 · TypeScript · Firebase · Gemini
- type
- personal · open source
FIG.01 // JOBTRACK · MODEL FALLBACK
Six models deep, because the quota is free
The generation call walks an ordered chain and returns the first response that comes back. Any error, not only a 429, falls through to the next model; the rate-limit ledger is written, never read for routing.
A job-search tracker built as a static React 19 SPA on Firebase: a four-stage drag-and-drop pipeline, conversion analytics derived in the browser, and a Gemini layer that reads your own application history back to you. There is no server of mine in the path; the browser talks to Firestore and Gemini directly, so Firestore security rules are the authorisation boundary.
Six models deep, because the quota is free
The insights run on Gemini's free tier, where the failure that matters is a 429 at the moment someone opens the dashboard. So the generation call is a walk down an ordered chain of six models, gemini-3-pro-preview first and gemini-2.0-flash last, returning the first response that comes back.
Any error falls through to the next model, not only a rate limit. A failure whose message carries 429, 503, 'rate limit', 'quota exceeded' or 'resource exhausted' is also appended, with arrayUnion, to an ai_rate_limits document keyed by today's date. That ledger is logged only: nothing reads it to route, so every call still starts at the top of the chain.
If all six fail, the error raised carries the last model's message rather than a generic one, so the cause is still legible after six silent retries.
6 modelsany error → next model
The prompt asks, the parser guarantees
The prompt receives four fields per application: company, role, stage and application date. Applications still at Applied are dropped, the rest are sorted newest-first and capped at fifty, and if nothing survives the feature says so instead of calling a model to produce filler.
The prompt asks for two to four single-sentence observations with no bullets or numbering. The parser strips any line that starts with a dash or a list number anyway, and hard-slices to four: the instruction is a request, the parser is the guarantee.
Generated insights are cached per user and reused until they are seven days old, or until the user forces a refresh, so opening the dashboard does not spend a model call.
newest 50max 4 insights7-day cache