1- # 📋 Job Tracker
1+ # Job Tracker
22
3- A personal job application tracker built with modern fullstack tooling. Track your applications, visualize progress in Kanban view, and never miss a follow-up.
3+ A personal job application tracker built with modern fullstack tooling. Track applications, manage contacts and documents , visualize progress in Kanban view, and never miss a follow-up.
44
55** Live:** [ jobs.vasudev.xyz] ( https://jobs.vasudev.xyz )
66
77---
88
9- ## ✨ Features
9+ ## Features
1010
11- - ** Table View** — sortable, filterable applications list with status color coding
12- - ** Kanban View** — drag & drop cards between status columns with optimistic UI updates
13- - ** Follow-up Dates** — set reminders per application, get overdue alerts
14- - ** Quick Stats** — at-a-glance count by status
15- - ** CSV Export** — one-click export, Excel-compatible
11+ - ** Table & Kanban Views** — sortable, filterable table or drag & drop Kanban board with optimistic updates
12+ - ** Follow-up Reminders** — set dates per application, get overdue alerts
13+ - ** Contact Management** — track contacts per application (name, role, email, LinkedIn)
14+ - ** Document Storage** — upload PDFs and images, link to applications, shareable download links
15+ - ** Share Page** — read-only public view for family/AMS with token-based access
16+ - ** Dark / Light / System Theme** — three-way toggle, persisted in localStorage, no flash on load
1617- ** DE/EN Language Switcher** — full i18n via next-intl
18+ - ** CSV Export** — one-click export, Excel-compatible
19+ - ** Quick Stats** — at-a-glance count by status
1720- ** Google OAuth** — secure login, single-user access
21+ - ** API Docs** — OpenAPI 3.1 spec with Swagger UI at ` /api-docs `
1822
19- ## 🛠 Tech Stack
23+ ## Tech Stack
2024
21- - ** [ Next.js 16] ( https://nextjs.org ) ** — App Router, SSR, Standalone
25+ - ** [ Next.js 16] ( https://nextjs.org ) ** — App Router, React 19, standalone output
26+ - ** [ Prisma 6] ( https://prisma.io ) ** + PostgreSQL — database (with swappable adapter layer for Firestore)
27+ - ** [ better-auth] ( https://better-auth.com ) ** — Google OAuth
2228- ** [ TanStack Table v8] ( https://tanstack.com/table ) ** — headless table with sort & filter
23- - ** [ TanStack Query v5] ( https://tanstack.com/query ) ** — data fetching & optimistic updates
29+ - ** [ TanStack Query v5] ( https://tanstack.com/query ) ** — data fetching & cache
2430- ** [ @dnd-kit ] ( https://dndkit.com ) ** — drag & drop for Kanban
25- - ** [ Prisma 6] ( https://prisma.io ) ** + SQLite — database
26- - ** [ better-auth] ( https://better-auth.com ) ** — Google OAuth
2731- ** [ next-intl] ( https://next-intl-docs.vercel.app ) ** — i18n (DE/EN)
28- - ** [ Tailwind CSS v3] ( https://tailwindcss.com ) ** — styling
32+ - ** [ Tailwind CSS v3] ( https://tailwindcss.com ) ** — styling with class-based dark mode
33+ - ** [ Google Cloud Run] ( https://cloud.google.com/run ) ** — container hosting
34+ - ** [ Google Cloud Storage] ( https://cloud.google.com/storage ) ** — file storage (optional, falls back to local filesystem)
35+ - ** [ Neon] ( https://neon.tech ) ** — serverless PostgreSQL
36+
37+ ## Architecture
38+
39+ ### Database Adapter Layer
40+
41+ The data layer uses a factory pattern (` lib/db/index.ts ` ) that switches between backends at runtime via the ` DB_PROVIDER ` env var:
42+
43+ - ** ` prisma ` ** (default) — Prisma ORM with PostgreSQL
44+ - ** ` firestore ` ** — Firebase Admin SDK with Firestore collections
2945
30- ## 🚀 Self-Hosting
46+ All API routes call ` getDb() ` which returns a ` DatabaseAdapter ` interface, making the backend transparent to application code.
47+
48+ ### Storage Abstraction
49+
50+ File storage (` lib/storage.ts ` ) switches between:
51+
52+ - ** Google Cloud Storage** — when ` GCS_BUCKET ` is set
53+ - ** Local filesystem** — default fallback, stores in ` uploads/ `
54+
55+ ## Self-Hosting
3156
3257### Prerequisites
3358- Node.js 20+
34- - A Google OAuth Client ID ([ create here] ( https://console.cloud.google.com/apis/credentials ) )
59+ - PostgreSQL database (or [ Neon] ( https://neon.tech ) free tier)
60+ - Google OAuth Client ID ([ create here] ( https://console.cloud.google.com/apis/credentials ) )
3561
3662### Setup
3763
@@ -44,28 +70,47 @@ cp .env.example .env
4470# Fill in your values in .env
4571
4672npx prisma db push
47- npx prisma db seed
4873npm run build
74+ npm start
4975```
5076
5177### Environment Variables
5278
5379``` env
54- DATABASE_URL="file:./prisma/dev.db"
55- BETTER_AUTH_SECRET="your-random-secret"
80+ # Database
81+ DB_PROVIDER="prisma" # "prisma" or "firestore"
82+ DATABASE_URL="postgresql://user:pass@host/db" # PostgreSQL connection string
83+
84+ # Auth
85+ BETTER_AUTH_SECRET="$(openssl rand -hex 32)"
5686BETTER_AUTH_URL="https://your-domain.com"
5787GOOGLE_CLIENT_ID="xxx.apps.googleusercontent.com"
5888GOOGLE_CLIENT_SECRET="GOCSPX-xxx"
5989ALLOWED_EMAIL="your@email.com"
90+
91+ # Optional
92+ GCS_BUCKET="your-bucket" # omit for local filesystem storage
93+ PUBLIC_READ_TOKEN="random-token" # token for the /share read-only page
6094```
6195
62- ### Deploy
96+ ### Docker
6397
6498``` bash
65- bash deploy.sh
99+ docker build -t job-tracker .
100+ docker run -p 8080:8080 --env-file .env job-tracker
66101```
67102
68- ## 📊 Application Statuses
103+ ### GCP Cloud Run (CI/CD)
104+
105+ The repo includes a GitHub Actions workflow (` .github/workflows/deploy-gcp.yml ` ) that on push to ` main ` :
106+
107+ 1 . Builds a Docker image
108+ 2 . Pushes to Artifact Registry
109+ 3 . Deploys to Cloud Run with secrets from Secret Manager
110+
111+ Uses Workload Identity Federation — no service account keys needed.
112+
113+ ## Application Statuses
69114
70115| Status | Meaning |
71116| --------| ---------|
0 commit comments