A local-first, privacy-focused job application tracker built with Next.js, React, TypeScript, and SQLite.
Track your search like a pipeline, not a spreadsheet. Manage opportunities, follow-ups, and monitor momentum from one workspace—all without leaving your browser.
- Local-First Storage — All data stays on your device in a real SQLite file (
data/job-tracker.sqliteby default) - Privacy — No cloud dependencies, data remains local on disk
- Full CRUD — Add, edit, view, and delete job applications
- Smart Filtering — Status, date range, salary range, and contact person filters
- Sortable Columns — Click headers to sort by company, role, status, dates
- Bulk Operations — Select multiple jobs, delete across filters with visibility controls
- Multiple Views — Analytics (default), Table, Kanban board, Calendar, Today, and This Week
- AI Re-Analyze — Re-run AI scoring directly from the job detail modal when you want a refreshed analysis
- Import/Export — JSON, CSV export; JSON import with merge strategies (append/upsert/replace)
- Pagination — Configurable page sizes (5/10/20) for large datasets
- Overdue Tracking — Quick metric shortcut to find jobs requiring follow-up
- Storage Logging — Debug visibility with console logs and downloadable .log files
- Refined UI Theme — Clean, paper-toned interface with productivity-focused layout
- Node.js 20+ and pnpm
# Install dependencies
pnpm install
# Start development server (http://127.0.0.1:4173)
pnpm dev
# Run tests
pnpm test:run
# Build for production
pnpm build
# Preview/serve the production build (requires pnpm build first)
pnpm serveYou can also run as a macOS daemon. See docs/DAEMON_SETUP.md for instructions.
app/
├── layout.tsx # Next.js root layout
├── page.tsx # Root page (renders AppClient)
├── AppClient.tsx # 'use client' bridge to src/App
├── globals.css # Global styles
└── api/
├── config/route.ts # POST /api/config
├── profile/route.ts # POST /api/profile
├── jobs/route.ts # GET/PUT /api/jobs
└── database/
├── create/route.ts # POST /api/database/create
├── info/route.ts # GET /api/database/info
└── test/route.ts # GET /api/database/test
backend/
├── data/ # SQLite schema and default profile/config data
├── jobStore.ts # Lazy-init SQLite store proxy (used by API routes)
├── sqliteStore.ts # Public SQLite facade used by the rest of the app
├── sqlite/ # DB connection, schema, and repository modules
└── jobValidation.ts # Backend job payload validation
src/
├── App.tsx # Main app orchestrator
├── domain.ts # Core types: Job, JobDraft, JobStatus, JobPriority
├── components/ # Reusable UI components (table, kanban, form, toast, AI config)
├── hooks/ # Custom state and behavior hooks (~20 specialized hooks)
├── services/ # Business logic (scoring, notifications, storage, AI, import/export)
├── storage/ # Storage adapters (API client, localStorage fallback, logger)
├── views/ # Page-level view components (Analytics, Table, Calendar, etc.)
│ ├── settings/ # Extracted settings sections
│ └── table/ # Table-specific view pieces
├── features/ # Self-contained feature modules (analytics, backup, savedViews, search, tasks)
├── types/ # Shared TypeScript types (ai, filters, errors, componentProps)
├── utils/ # Date, accessibility, drag/drop, formatting helpers
└── test/setup.ts # Vitest setup
docs/
├── ARCHITECTURE.md # Technical architecture overview
├── DAEMON_SETUP.md # macOS daemon setup guide
├── PERFORMANCE_BASELINE.md # Performance measurement framework
├── REFACTORING_ANALYSIS.md # Code quality audit
├── REFACTORING_STATUS.md # Refactoring progress tracker
├── releases/ # Historical release notes (latest: v2.7.4)
├── planning/ # Roadmaps and release plans (v2.7, v2.8)
└── safari-plugin/ # Safari browser plugin architecture and planning
scripts/
├── generate-version.ts # Auto-generates src/version.ts from git metadata
├── require-pnpm.mjs # Fails installs launched without pnpm
├── withColor.ts # Forces colored CLI output for repo scripts
├── package-standalone.sh # Builds standalone deployment bundle
└── launchd/ # macOS launchd helpers (plist template, install/uninstall scripts)
e2e/ # Playwright end-to-end tests
sample-data/ # Demo JSON files for import testing
public/ # Static assets (favicon, logo)
Tests are run with Vitest, React Testing Library, and Playwright:
# Run tests in watch mode
pnpm test
# Run tests once
pnpm test:run
# Run coverage
pnpm test:coverage
# Run end-to-end tests
pnpm test:e2eThe test suite covers app workflows, hooks, backend repositories and API flows, services, and end-to-end profile/settings persistence scenarios. For one-off runs, use pnpm exec vitest run src/path/to/file.test.ts or pnpm exec playwright test e2e/path/to/spec.ts.
# Production build (optimized, minified, tree-shaken)
pnpm build
# Next.js outputs server/client artifacts in .next/
# Start production server with:
pnpm startWorkflow files are located in .gitea/workflows/:
Triggers on: push to main/develop, pull_request against main/develop
Steps:
- Build frontend CI images with Podman Compose
- Run lint, tests, and build inside each container build pipeline
- Package standalone and OCI artifacts from generated images
- Upload build artifacts (7-day retention)
Triggers on: git tag (e.g., git tag v1.0.0 && git push origin v1.0.0)
Steps:
- Build and test frontend service inside Podman using Podman Compose
- Package source tarball (
.tar.gz) - Package frontend standalone distribution archives (
.zipand.tar.gz) - Export frontend OCI image archives (
.tar.gz) - Generate release notes
- Upload packaged artifacts for download from workflow run
Artifacts:
job-tracker-vX.Y.Z-source.tar.gz— Source code archivejob-tracker-vX.Y.Z-standalone.zip— Standalone Next.js deployment bundle withserver.js,.next/static,public/, andmacos/startup helpersjob-tracker-vX.Y.Z-standalone.tar.gz— Tarball version of the standalone deployment bundlejob-tracker-vX.Y.Z-oci-image.tar.gz— Podman-built OCI image archive for frontend runtime deployment
Manual local release packaging with Podman:
pnpm run release:podman -- vX.Y.ZTriggers on: Successful Build & Test workflow on main, or manual workflow_dispatch
Steps:
- Build deployment image with Podman Compose
- Extract deployment bundle from the image with metadata
- Upload to artifacts (30-day retention)
Status: Produces a standalone Next.js deployment artifact for a Node-capable target or the included macOS launchd helper scripts
Manual local deployment bundle packaging with Podman:
pnpm run deploy:podman -- vX.Y.Z deploy- Fill out the "Add Job" form (Company, Role, Status, etc.)
- Click Add Job to add to pipeline
- Metric cards update instantly
- Open a job from table/kanban/calendar
- In the job modal, click Re-Analyze
- AI scoring runs again in the background and refreshes the score fields
- Status Filter — Quick drop-down for All statuses, Overdue Follow-ups, Applied, Phone Screen, Interview, Offer, Rejected, Withdrawn
- Advanced Filters — Click "Filters" to refine by:
- Application date range
- Salary range
- Contact person name
- Overdue Follow-ups — Click "View" in the overdue metric card to see jobs past their due date
- Select jobs via checkboxes (or select-all)
- Manage selections across pagination
- Click "Delete Selected on Page" — only visible selected rows are removed
- Hidden selections preserved and reported
- Export — JSON or CSV from toolbar; CSV opens in Excel/Sheets
- Import — JSON file with merge strategy:
- Append — Add imported jobs to existing
- Upsert — Update existing by ID, add new ones
- Replace — Clear all, keep only imported
- Job data is stored in
data/job-tracker.sqlite(orJOB_TRACKER_DB_PATHif set) - The SQLite file can be opened with DB Browser for SQLite,
sqlite3, and other compatible readers - Click Export DB Logs in form panel to download debug logs
- Logs include: API operations, timing, error details
- Enable debug mode:
localStorage.setItem('job-tracker.debug', 'true')in console
src/version.tsis auto-generated byscripts/generate-version.ts- Generation runs before
dev,build,test:run, andtest:coverage - App UI shows current version badge for quick runtime verification
- Chrome/Edge 90+
- Firefox 88+
- Safari 15+
| Layer | Technology |
|---|---|
| UI Framework | React 19 |
| Language | TypeScript 5 |
| Build Tool | Next.js 16 (App Router) |
| Database | SQLite (file-backed via better-sqlite3) |
| Testing | Vitest + React Testing Library + userEvent |
| Linting | ESLint 9 |
| CI/CD | Gitea Actions |
- Bundle Size: App bundle only (SQLite engine runs server-side)
- Startup: <1s (network) + storage hydration
- Page Transitions: Instant (React in-browser)
- Pagination: Optimized for 1000+ jobs
- ✅ No analytics tracking — Zero telemetry
- ✅ No cloud sync — Data stays on your device
- ✅ Full export capability — JSON, CSV at any time
- ✅ SQLite portability — Open the
.sqlitefile with standard SQLite tools
This project is licensed under a custom non-commercial license.
See LICENSE for details. Commercial use is not permitted without prior written permission.
Report issues, suggest features, or contribute pull requests on the project repository.
Last Updated: March 24, 2026
Current Release Tag: v2.7.4