{"id":50248298,"url":"https://github.com/yuzh98/academic-application-tracker","last_synced_at":"2026-05-27T00:01:48.757Z","repository":{"id":356786728,"uuid":"1214617478","full_name":"YuZh98/academic-application-tracker","owner":"YuZh98","description":"Local Streamlit dashboard that answers \"what do I do today?\" for academics juggling dozens of applications, deadlines, and recommendation letters.","archived":false,"fork":false,"pushed_at":"2026-05-21T05:47:39.000Z","size":17830,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-21T05:51:20.608Z","etag":null,"topics":["academic","application-tracker","dashboard","deadline-tracker","job-tracker","phd","postdoc","productivity","python","recommendation-letters","sqlite","streamlit"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/YuZh98.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-18T20:21:59.000Z","updated_at":"2026-05-13T00:55:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/YuZh98/academic-application-tracker","commit_stats":null,"previous_names":["yuzh98/academic-application-tracker"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/YuZh98/academic-application-tracker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YuZh98%2Facademic-application-tracker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YuZh98%2Facademic-application-tracker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YuZh98%2Facademic-application-tracker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YuZh98%2Facademic-application-tracker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/YuZh98","download_url":"https://codeload.github.com/YuZh98/academic-application-tracker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YuZh98%2Facademic-application-tracker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33543973,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"ssl_error","status_checked_at":"2026-05-26T15:22:15.568Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["academic","application-tracker","dashboard","deadline-tracker","job-tracker","phd","postdoc","productivity","python","recommendation-letters","sqlite","streamlit"],"created_at":"2026-05-27T00:01:46.483Z","updated_at":"2026-05-27T00:01:48.750Z","avatar_url":"https://github.com/YuZh98.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Academic Application Tracker\n\n[![CI](https://github.com/YuZh98/academic-application-tracker/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/YuZh98/academic-application-tracker/actions/workflows/ci.yml) [![Live demo](https://img.shields.io/badge/demo-live-E63946?style=flat-square)](https://academic-application-tracker.streamlit.app) [![Python](https://img.shields.io/badge/python-3.11%E2%80%933.14-blue)](pyproject.toml) [![Coverage](https://img.shields.io/badge/coverage-95%25-brightgreen)](pyproject.toml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nA local Streamlit dashboard that answers one question every morning: **\"What do I do today?\"**\n\nTrack dozens of postdoc, PhD, faculty, and fellowship applications in parallel — deadlines, recommendation letters, materials checklists, interview rounds — without a single missed follow-up.\n\n![Academic Application Tracker — isometric composite of the four primary pages on a paper-crease backdrop, with light-mode tiles on the dark half and dark-mode tiles on the bright half](docs/ui/screenshots/v0.14.0/collage.png)\n\n\n---\n\n## Who is this for?\n\nAnyone 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.\n\n---\n\n## Why not a spreadsheet?\n\n| Problem | Spreadsheet | This tool |\n|---------|-------------|-----------|\n| Deadline urgency | Manual sorting, easy to miss | Auto-computed, color-coded red/yellow by proximity, surfaced every session |\n| Recommender tracking | One row per person, no per-position state | One recommender × seven positions = seven independent states; flags overdue, offers one-click mailto |\n| Materials readiness | Scattered notes | Per-position checklist (CV, cover letter, research statement, …); dashboard shows ready-to-submit count at a glance |\n| Daily action items | You figure it out | Dashboard tells you |\n\n---\n\n\u003e **Try it now** — [open the live demo](https://academic-application-tracker.streamlit.app). No install, no sign-up. Each session gets its own sandbox data that resets when you close the tab.\n\n---\n\n## Quick start\n\n```bash\ngit clone https://github.com/YuZh98/academic-application-tracker.git\ncd academic-application-tracker\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -r requirements.txt\nstreamlit run app.py\n```\n\nPython ≥ 3.11. Open the URL Streamlit prints (default `http://localhost:8501`).  \nThe SQLite database is created on first run — the empty-state screen walks you through adding your first position.\n\nYour 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 \u0026\u0026 pip install -r requirements.txt`. See [`docs/dev-notes/self-host-setup.md`](docs/dev-notes/self-host-setup.md) for backup, troubleshooting, and update details.\n\n---\n\n## Features\n\n### Dashboard\nKPI grid (Tracked / Applied / Interview / Next Interview), application funnel, materials readiness panel, upcoming deadlines, and recommender alerts — one screen, one daily answer.\n\n![Dashboard](docs/ui/screenshots/v0.14.0/dashboard.png)\n\n### Opportunities\nQuick-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.\n\n![Opportunities](docs/ui/screenshots/v0.14.0/opportunities.png)\n\n### Applications\nPer-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.\n\n![Applications](docs/ui/screenshots/v0.14.0/applications.png)\n\n### Recommenders\nPending-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.\n\n![Recommenders](docs/ui/screenshots/v0.14.0/recommenders.png)\n\n### Settings\nTune 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.\n\n![Settings](docs/ui/screenshots/v0.14.0/settings.png)\n\n### Export\nEvery 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.\n\n---\n\n## Built to last\n\n1000+ tests · 95% coverage · strict four-layer architecture · CI on every PR · spec-first development. This is a production-grade tool, not a weekend script.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eEngineering deep-dive\u003c/strong\u003e\u003c/summary\u003e\n\n### Architecture — four strict layers\n\n```\nconfig.py     constants, vocabularies, import-time invariants\ndatabase.py   SQL only — never imports streamlit\nexports.py    markdown writers — called by database, never by pages\npages/*.py    display only — no raw SQL, no direct exports import\n```\n\nLayer contracts are enforced by cohesion tests that fail CI if any rule drifts.\n\n### Testing\n\nIntegration 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.\n\n### CI pipeline (every PR)\n\n- ruff lint (zero warnings)\n- pyright strict-basic (zero errors)\n- pytest (two passes: normal + deprecation-as-error)\n- Status-literal grep — no hardcoded status strings in page code; all vocabulary routed through `config.py`\n\n### Config-driven schema\n\nAdding 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.\n\n### Import-time invariants\n\n`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.\n\n### Spec-first development\n\n[`DESIGN.md`](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.\n\n\u003c/details\u003e\n\n---\n\n## Stack\n\n| Layer | Technology |\n|-------|-----------|\n| UI | Streamlit 1.57 · Plotly |\n| Data | SQLite · pandas |\n| Language | Python 3.11+ |\n| Dev tooling | pytest · ruff · pyright |\n\n---\n\n## Project structure\n\n```\napp.py                 Dashboard home page\nconfig.py              Constants — statuses, thresholds, vocabularies\ndatabase.py            SQL reads/writes; calls exports.write_all() on every write\nexports.py             Markdown generators (OPPORTUNITIES / PROGRESS / RECOMMENDERS)\npages/\n  1_Opportunities.py   Position CRUD + bulk actions\n  2_Applications.py    Application + interview tracking\n  3_Recommenders.py    Recommender tracker + reminder helpers\n  4_Export.py          Manual export trigger + per-file download buttons\n  5_Settings.py        Tunable thresholds + append-only status vocabulary\nscripts/\n  seed_demo_db.py      Throwaway demo dataset for screenshots + manual QA\n  crop_screenshots.py  Idempotent crop helper for the README captures\n  build_collage.py     Headless-Chromium renderer for the marketing collage\n  collage.html         CSS3D template loaded by build_collage.py\ntests/                 Full test suite (AppTest + unit + cohesion)\ndocs/\n  adr/                 Architecture decision records\n  dev-notes/           Dev setup, extending guide, self-host guide, Streamlit gotchas, git workflow notes\n  ui/                  Wireframes + screenshots\nDESIGN.md              Authoritative spec\nGUIDELINES.md          Coding conventions\nCHANGELOG.md           Per-release narrative log\n```\n\n---\n\n## Roadmap\n\n- [ ] AI auto-fill — paste a job listing URL, get position details pre-populated\n- [ ] Calendar integration (`.ics` export for deadlines and interviews)\n- [ ] Email notifications for approaching deadlines\n- [ ] Bulk import from CSV / existing spreadsheets\n- [ ] Analytics — time-to-response trends, success rates by field\n\n---\n\n## Contributing\n\nContributions welcome! Read [`GUIDELINES.md`](GUIDELINES.md) for coding conventions and TDD workflow, then check the [issue tracker](https://github.com/YuZh98/academic-application-tracker/issues) for open tasks. Every PR runs the full CI pipeline — lint, type-check, and all tests must pass.\n\n---\n\n## Documentation\n\n| Doc | Start here if… |\n|-----|---------------|\n| [`DESIGN.md`](DESIGN.md) | You want to understand the schema, page contracts, cascade rules, or export format |\n| [`GUIDELINES.md`](GUIDELINES.md) | You want to contribute or understand the coding conventions |\n| [`CHANGELOG.md`](CHANGELOG.md) | You want the per-release development narrative |\n| [`docs/dev-notes/`](docs/dev-notes/) | You hit a Streamlit-specific gotcha or need dev setup details |\n\n---\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyuzh98%2Facademic-application-tracker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyuzh98%2Facademic-application-tracker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyuzh98%2Facademic-application-tracker/lists"}