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.
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.
| Problem | Spreadsheet | This tool |
|---|---|---|
| Deadline urgency | Manual sorting, easy to miss | Auto-computed, color-coded red/yellow by proximity, surfaced every session |
| Recommender tracking | One row per person, no per-position state | One recommender × seven positions = seven independent states; flags overdue, offers one-click mailto |
| Materials readiness | Scattered notes | Per-position checklist (CV, cover letter, research statement, …); dashboard shows ready-to-submit count at a glance |
| Daily action items | You figure it out | Dashboard tells you |
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.pyPython ≥ 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.
KPI grid (Tracked / Applied / Interview / Next Interview), application funnel, materials readiness panel, upcoming deadlines, and recommender alerts — one screen, one daily answer.
Quick-add a position in under 30 seconds — nine fields including location, source, and portal URL. Full edit panel with four tabs (Overview / Requirements / Materials / Notes) covering every schema column. Filter by status, priority, field, or full-text search. Urgency-banded deadline column. Bulk actions expander: multi-select rows and flip status or set a requirement value across all of them in one batch.
Per-position card: applied date, confirmation, response, result, outcome. Inline multi-round interview log. Pipeline cascades automatically: saved → applied → interview → offer, with symmetric retraction when the last interview row is deleted.
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 by default who hasn't confirmed — tunable on the Settings page.
Tune alert thresholds (deadline window, recommender follow-up cadence, upcoming-panel default) and append new pipeline statuses without editing config files. Bounds-checked at save; removal of a status currently in use is blocked at the boundary.
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.
1000+ tests · 95% 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
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.
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.
- 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
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.
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.
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.
| Layer | Technology |
|---|---|
| UI | Streamlit 1.57 · Plotly |
| Data | SQLite · pandas |
| Language | Python 3.11+ |
| Dev tooling | pytest · ruff · pyright |
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 + bulk actions
2_Applications.py Application + interview tracking
3_Recommenders.py Recommender tracker + reminder helpers
4_Export.py Manual export trigger + per-file download buttons
5_Settings.py Tunable thresholds + append-only status vocabulary
scripts/
seed_demo_db.py Throwaway demo dataset for screenshots + manual QA
crop_screenshots.py Idempotent crop helper for the README captures
build_collage.py Headless-Chromium renderer for the marketing collage
collage.html CSS3D template loaded by build_collage.py
tests/ Full test suite (AppTest + unit + cohesion)
docs/
adr/ Architecture decision records
dev-notes/ Dev setup, extending guide, self-host guide, Streamlit gotchas, git workflow notes
ui/ Wireframes + screenshots
DESIGN.md Authoritative spec
GUIDELINES.md Coding conventions
CHANGELOG.md Per-release narrative log
- AI auto-fill — paste a job listing URL, get position details pre-populated
- Calendar integration (
.icsexport for deadlines and interviews) - Email notifications for approaching deadlines
- Bulk import from CSV / existing spreadsheets
- Analytics — time-to-response trends, success rates by field
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.
| Doc | Start here if… |
|---|---|
DESIGN.md |
You want to understand the schema, page contracts, cascade rules, or export format |
GUIDELINES.md |
You want to contribute or understand the coding conventions |
CHANGELOG.md |
You want the per-release development narrative |
docs/dev-notes/ |
You hit a Streamlit-specific gotcha or need dev setup details |