Academic Application Tracker

Open-source · github.com/YuZh98/academic-application-tracker

A local Streamlit dashboard that answers one question every morning: “What do I do today?”

Track dozens of postdoc, PhD, faculty, and fellowship applications in parallel — deadlines, recommendation letters, materials checklists, interview rounds — without a single missed follow-up.

https://raw.githubusercontent.com/YuZh98/academic-application-tracker/main/docs/ui/screenshots/v0.11.0/dashboard-1280.png

https://github.com/YuZh98/academic-application-tracker/actions/workflows/ci.yml/badge.svg?branch=main https://img.shields.io/badge/python-3.11%E2%80%933.14-blue https://img.shields.io/badge/coverage-97%25-brightgreen https://img.shields.io/badge/License-MIT-yellow.svg


Who is this for?

Anyone juggling academic job applications at scale — postdocs, PhD candidates approaching graduation, faculty applicants, fellowship seekers. If you’re tracking 5–100+ positions with overlapping deadlines, different document requirements, and multiple recommenders, this replaces the spreadsheet you’ve outgrown.


Why not a spreadsheet?

ProblemSpreadsheetThis tool
Deadline urgencyManual sorting, easy to missAuto-computed, color-coded red/yellow by proximity, surfaced every session
Recommender trackingOne row per person, no per-position stateOne recommender × seven positions = seven independent states; flags overdue, offers one-click mailto
Materials readinessScattered notesPer-position checklist (CV, cover letter, research statement, …); dashboard shows ready-to-submit count at a glance
Daily action itemsYou figure it outDashboard tells you

Quick start

1
2
3
4
5
6
git clone https://github.com/YuZh98/academic-application-tracker.git
cd academic-application-tracker
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
streamlit run app.py

Python ≥ 3.11. Open the URL Streamlit prints (default http://localhost:8501).
The SQLite database is created on first run — the empty-state screen walks you through adding your first position.

Your data lives in a postdoc.db file that appears in the project folder after your first save — copy that file to back it up (stop the app first to avoid a torn copy). To update later, git pull && pip install -r requirements.txt. See docs/dev-notes/self-host-setup.md for backup, troubleshooting, and update details.


Features

Dashboard

KPI grid (Tracked / Applied / Interview / Next Interview), application funnel, materials readiness panel, upcoming deadlines, and recommender alerts — one screen, one daily answer.

Opportunities

Quick-add a position in under 30 seconds. Full edit panel with four tabs (Overview / Requirements / Materials / Notes). Filter by status, priority, field, or full-text search. Urgency-banded deadline column.

https://raw.githubusercontent.com/YuZh98/academic-application-tracker/main/docs/ui/screenshots/v0.11.0/opportunities-1280.png

Applications

Per-position card: applied date, confirmation, response, result, outcome. Inline multi-round interview log. Pipeline cascades automatically: saved → applied → interview → offer.

https://raw.githubusercontent.com/YuZh98/academic-application-tracker/main/docs/ui/screenshots/v0.11.0/applications-1280.png

Recommenders

Pending-alert cards with mailto and LLM-prompt helpers to draft a follow-up. Full (position × recommender) matrix with inline edit. Flags anyone asked more than 7 days ago who hasn’t confirmed.

https://raw.githubusercontent.com/YuZh98/academic-application-tracker/main/docs/ui/screenshots/v0.11.0/recommenders-1280.png

Export

Every database write auto-regenerates plaintext markdown files (OPPORTUNITIES.md, PROGRESS.md, RECOMMENDERS.md) in the exports/ folder — always a fresh, portable backup of your entire job-search state. Manual regenerate + per-file download also available.


Built to last

800+ tests · 97% coverage · strict four-layer architecture · CI on every PR · spec-first development. This is a production-grade tool, not a weekend script.

Engineering deep-dive

Architecture — four strict layers

1
2
3
4
config.py     constants, vocabularies, import-time invariants
database.py   SQL only  never imports streamlit
exports.py    markdown writers  called by database, never by pages
pages/*.py    display only  no raw SQL, no direct exports import

Layer contracts are enforced by cohesion tests that fail CI if any rule drifts.

Testing

Integration tests use the official streamlit.testing.v1.AppTest harness against real page files; unit tests run against per-test temp SQLite files via a db fixture. A second test pass with -W error::DeprecationWarning catches Streamlit-API drift before it surfaces on upgrades.

CI pipeline (every PR)

  • ruff lint (zero warnings)
  • pyright strict-basic (zero errors)
  • pytest (two passes: normal + deprecation-as-error)
  • Status-literal grep — no hardcoded status strings in page code; all vocabulary routed through config.py

Config-driven schema

Adding a new required document type (e.g. “Portfolio”) = one tuple appended to config.REQUIREMENT_DOCS. init_db() adds the columns automatically on next start. No other file changes needed.

Import-time invariants

config.py asserts structural integrity at module load — every status has a color and a label, urgency thresholds are ordered, funnel buckets cover all statuses exactly once. Misconfiguration aborts startup with a clear traceback before any page renders.

Spec-first development

DESIGN.md is the authoritative spec for the schema, page contracts, cascade rules, and export format. Implementation tracks the spec; deviations land as spec amendments with commit references.


Stack

LayerTechnology
UIStreamlit 1.57 · Plotly
DataSQLite · pandas
LanguagePython 3.11+
Dev toolingpytest · ruff · pyright

Project structure

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
app.py                 Dashboard home page
config.py              Constants  statuses, thresholds, vocabularies
database.py            SQL reads/writes; calls exports.write_all() on every write
exports.py             Markdown generators (OPPORTUNITIES / PROGRESS / RECOMMENDERS)
pages/
  1_Opportunities.py   Position CRUD
  2_Applications.py    Application + interview tracking
  3_Recommenders.py    Recommender tracker + reminder helpers
  4_Export.py          Manual export trigger + per-file download buttons
tests/                 Full test suite (AppTest + unit + cohesion)
docs/
  adr/                 Architecture decision records
  dev-notes/           Streamlit gotchas, dev setup, git workflow notes
  ui/                  Wireframes + screenshots
DESIGN.md              Authoritative spec
GUIDELINES.md          Coding conventions
CHANGELOG.md           Per-release narrative log

Roadmap

  • AI auto-fill — paste a job listing URL, get position details pre-populated
  • Calendar integration (.ics export for deadlines and interviews)
  • Email notifications for approaching deadlines
  • Bulk import from CSV / existing spreadsheets
  • Analytics — time-to-response trends, success rates by field

Contributing

Contributions welcome! Read GUIDELINES.md for coding conventions and TDD workflow, then check the issue tracker for open tasks. Every PR runs the full CI pipeline — lint, type-check, and all tests must pass.


Documentation

DocStart here if…
DESIGN.mdYou want to understand the schema, page contracts, cascade rules, or export format
GUIDELINES.mdYou want to contribute or understand the coding conventions
CHANGELOG.mdYou want the per-release development narrative
docs/dev-notes/You hit a Streamlit-specific gotcha or need dev setup details

License

MIT