A production-ready Full-Stack Job Tracker built with React, TypeScript & PocketBase
JobTrack is a modern, multi-user job application tracking system designed to help users manage their job search efficiently.
It provides secure data isolation, intuitive analytics, and resume management, making it ideal for students, job seekers, and professionals.
Browser (React App)
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ Vercel Frontend โ (React + Vite + nginx)
โโโโโโโโโโโฌโโโโโโโโโโโโโ
โ REST API (HTTPS)
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ PocketBase API โ (Go binary on Railway)
โโโโโโโโโโโฌโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ SQLite DB + Files โ (Railway persistent volume)
โโโโโโโโโโโโโโโโโโโโโโโโ
| Layer | Role |
|---|---|
| ๐ Frontend | UI, routing, charts, state management โ hosted on Vercel |
| โ๏ธ Backend | Auth, REST API, file storage โ PocketBase on Railway |
| ๐๏ธ Database | SQLite embedded in PocketBase, persisted via Railway volume |
- Multi-user system with strict data isolation โ enforced at database level
- JWT-based authentication with auto-refresh via PocketBase SDK
- Server-side access rules prevent any cross-user data access
- Add / Edit / Delete job applications
- Fields: company, role, job link, status, location, CTC, company rating, notes
- Attach resume PDFs per application (max 5MB, PDF only)
- Search by company name or role
- Filter by status and location
- Paginated results (10 per page)
- Total applications count and per-status breakdown
- Donut chart visualization powered by Chart.js
- Fully responsive โ mobile and desktop
- Clean, minimal UI with dark mode (auto system preference)
| Layer | Technology |
|---|---|
| Frontend | React 18, TypeScript, Vite 5 |
| Backend | PocketBase 0.22 (Go) |
| Database | SQLite (embedded in PocketBase) |
| Charts | Chart.js 4 + react-chartjs-2 |
| Routing | React Router v6 |
| Frontend hosting | Vercel |
| Backend hosting | Railway |
| Containerization | Docker + nginx |
| Tool | Version |
|---|---|
| Node.js | 18+ |
| npm | Latest |
| PocketBase binary | Latest |
| Docker (optional, for local container testing) | Latest |
git clone <your-repo-url>
cd jobtrack
npm installDownload the PocketBase binary for your OS from pocketbase.io.
# macOS / Linux
chmod +x pocketbase
./pocketbase serve
# Windows
pocketbase.exe serveAdmin UI will be available at: http://127.0.0.1:8090/_/
- Open
http://127.0.0.1:8090/_/in your browser - Create your admin account (first time only)
- Go to Settings โ Import Collections
- Upload
pocketbase_schema.jsonfrom the project root - Click Review โ Confirm and import
cp .env.example .env.localThe default .env.local already points to local PocketBase โ no changes needed:
VITE_PB_URL=http://127.0.0.1:8090
npm run devApp runs at: http://localhost:5173
Keep both terminals running โ one for PocketBase (
./pocketbase serve) and one for Vite (npm run dev).
Data isolation is enforced at the PocketBase collection rule level, not just the frontend. Even direct API calls are rejected if the authenticated user doesn't own the record.
listRule: "@request.auth.id = user"
viewRule: "@request.auth.id = user"
createRule: "@request.auth.id != \"\""
updateRule: "@request.auth.id = user"
deleteRule: "@request.auth.id = user"
โ ๏ธ Note: Rules use= user(direct ID comparison), not= user.idโ this is correct for PocketBase's relation field syntax.
โ
Prevents unauthorized cross-user data access
โ
Server-side enforcement โ bypassing the frontend UI has no effect
The project includes two Dockerfiles โ one for each service.
# Build the image (VITE_PB_URL is required at build time)
docker build \
--build-arg VITE_PB_URL=http://127.0.0.1:8090 \
-t jobtrack-frontend .
# Run locally (nginx listens on $PORT, defaults to 8080)
docker run -p 8080:8080 jobtrack-frontend
VITE_PB_URLmust be passed as a build argument โ Vite bakes it into the JS bundle at compile time and cannot read it at runtime.
# Build
docker build -f Dockerfile.pocketbase -t jobtrack-pb .
# Run locally (data stored in ./pb_data on your host)
docker run -p 8090:8090 -v $(pwd)/pb_data:/pb/pb_data jobtrack-pbThere is no
docker-compose.ymlin this project. Services are deployed independently to Vercel (frontend) and Railway (backend).
-
Push the repo to GitHub
-
On railway.app, create a new project โ Deploy from GitHub repo
-
In the service Variables tab, add:
Variable Value RAILWAY_DOCKERFILE_PATHDockerfile.pocketbase -
Go to Settings โ Networking โ Generate Domain to get your public URL
-
Attach a persistent volume (right-click service on canvas โ Attach Volume):
- Mount path:
/pb/pb_data
- Mount path:
-
Open
https://your-pb-domain.up.railway.app/_/and importpocketbase_schema.json
-
On vercel.com, import the same GitHub repo
-
Add environment variable (mark it as a Build Variable):
Variable Value VITE_PB_URLhttps://your-pb-domain.up.railway.appNo trailing slash.
VITE_PB_URLmust be a Build Variable โ Vercel must pass it duringnpm run build, not at runtime. -
Deploy โ
vercel.jsonhandles SPA routing automatically
jobtrack/
โ
โโโ Dockerfile # Frontend โ multi-stage Node + nginx build
โโโ Dockerfile.pocketbase # Backend โ PocketBase binary on Alpine
โโโ docker-entrypoint.sh # Injects Railway $PORT into nginx at startup
โโโ nginx.conf # nginx config โ SPA routing + asset caching
โ
โโโ .env.example # Environment variable template
โโโ vercel.json # Vercel SPA rewrite rules
โโโ pocketbase_schema.json # PocketBase collection schema + access rules
โ
โโโ public/
โ โโโ favicon.svg
โ
โโโ src/
โ โโโ App.tsx # Root router + AuthProvider
โ โโโ main.tsx # React entry point
โ โโโ index.css # Global styles + CSS design tokens
โ โ
โ โโโ lib/
โ โ โโโ pb.ts # PocketBase client instance
โ โ
โ โโโ types/
โ โ โโโ index.ts # TypeScript types + constants
โ โ
โ โโโ hooks/
โ โ โโโ useAuth.tsx # Auth context โ login, register, logout
โ โ โโโ useJobs.ts # CRUD operations for job applications
โ โ
โ โโโ components/
โ โ โโโ JobModal.tsx # Add / Edit job form modal
โ โ โโโ ProtectedRoute.tsx # Auth guard โ redirects to /auth if not logged in
โ โ โโโ StatusBadge.tsx # Colour-coded status pill
โ โ โโโ StatsChart.tsx # Donut chart with legend
โ โ
โ โโโ pages/
โ โโโ Auth.tsx # Login + Register page
โ โโโ Dashboard.tsx # Main dashboard
โ
โโโ index.html
โโโ package.json
โโโ tsconfig.json
โโโ vite.config.ts
- ๐ Interview scheduling with calendar view
- ๐ง Email reminders (Resend / SMTP integration)
- ๐ Advanced analytics โ application rate over time, conversion by company
- ๐ Resume version tracking โ link multiple resume versions per application
- ๐ OAuth login (Google / GitHub) via PocketBase OAuth2
npm run dev # Start Vite dev server (http://localhost:5173)
npm run build # TypeScript check + production build โ dist/
npm run preview # Preview production build locally
npm run lint # Run ESLintโญ Built for developers & job seekers
๐ก Clean โข Secure โข Scalable