A full-stack MVP web application for tracking job applications, discovering job opportunities, and managing your job search.
- 🔐 User Authentication - JWT-based auth with refresh tokens
- 👤 Profile Management - Build your profile with skills, keywords, and preferences
- 📄 Resume Parsing - Upload PDF/DOCX resumes with automatic text extraction
- 💼 Job Management - Add jobs by URL (with auto-extraction) or manual entry
- 🎯 Smart Recommendations - Skill/keyword matching with explainability
- 📊 Application Tracking - Kanban-style pipeline with status tracking
- 📅 Timeline & Events - Track every interaction and status change
- 🔔 Reminders - Automatic follow-up reminders and custom alerts
- 🌙 Modern Dark UI - Beautiful, responsive interface
- .NET 8 Web API (C#)
- Clean Architecture
- Entity Framework Core
- PostgreSQL
- Hangfire (background jobs)
- JWT Authentication
- FluentValidation
- Swagger/OpenAPI
- React 18 + TypeScript
- Vite
- TanStack Query
- React Router
- React Hook Form + Zod
- Tailwind CSS
- Radix UI components
- Docker
- Kubernetes
- Nginx
├── backend/
│ ├── src/
│ │ ├── Api/ # Controllers, middleware, entry point
│ │ ├── Application/ # DTOs, interfaces, validators
│ │ ├── Domain/ # Entities, enums
│ │ └── Infrastructure/ # EF Core, services, auth
│ └── tests/
├── frontend/
│ └── src/
│ ├── components/ # Reusable UI components
│ ├── contexts/ # React contexts
│ ├── lib/ # API client, utilities
│ ├── pages/ # Page components
│ └── types/ # TypeScript types
├── k8s/ # Kubernetes manifests
├── scripts/ # Dev helper scripts
└── docker-compose.yml
# Clone the repository
git clone <repo-url>
cd joby
# Start app + Postgres (profile `local` includes the database; Postgres is on host port 5300)
docker compose --profile local up --build -d
# Access the app
# Frontend: http://localhost:8080
# Backend API (host): http://localhost:5000
# Swagger: http://localhost:5000/swagger# Run the setup script
# Windows PowerShell:
.\scripts\dev-setup.ps1
# Linux/Mac:
chmod +x scripts/dev-setup.sh
./scripts/dev-setup.sh
# Start PostgreSQL (Compose profile `local`; published on host port 5300)
docker compose --profile local up -d postgres
# Start backend (terminal 1)
cd backend
dotnet run --project src/Api
# Start frontend (terminal 2)
cd frontend
npm run dev
# Access the app
# Frontend: http://localhost:5173
# Backend API: http://localhost:5000ConnectionStrings__DefaultConnection=Host=localhost;Port=5300;Database=joby;Username=postgres;Password=CHANGE_ME
Jwt__Secret=YOUR_SUPER_SECRET_KEY_MIN_32_CHARS
Jwt__Issuer=Joby
Jwt__Audience=JobyApp
Jwt__AccessTokenExpirationMinutes=60
Jwt__RefreshTokenExpirationDays=7
Cors__AllowedOrigins__0=http://localhost:5173VITE_API_URL=/apiOnce the backend is running, visit:
- Swagger UI: http://localhost:5000/swagger
- Health Check: http://localhost:5000/health/ready
| Endpoint | Method | Description |
|---|---|---|
/api/auth/register |
POST | Register new user |
/api/auth/login |
POST | Login |
/api/auth/refresh |
POST | Refresh token |
/api/auth/me |
GET | Get current user |
/api/profile |
GET/PUT | Get/update profile |
/api/profile/resumes |
POST | Upload resume |
/api/jobs |
GET/POST | List/create jobs |
/api/jobs/url |
POST | Create job from URL |
/api/jobs/recommended |
GET | Get recommended jobs |
/api/applications |
GET/POST | List/create applications |
/api/applications/pipeline |
GET | Get Kanban pipeline |
/api/reminders |
GET/POST | List/create reminders |
# Build images
chmod +x scripts/build-images.sh
./scripts/build-images.sh v1.0.0
# Or with a registry
REGISTRY=your-registry.com ./scripts/build-images.sh v1.0.0- Kubernetes cluster (local: minikube, kind, or Docker Desktop)
- kubectl configured
- Ingress controller (nginx)
# Create namespace and apply all manifests
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/
# Check deployment status
kubectl get pods -n joby
kubectl get services -n joby
# View logs
kubectl logs -f deployment/backend -n joby
kubectl logs -f deployment/frontend -n joby- Update
k8s/secret.yamlwith production secrets - Update
k8s/configmap.yamlwith your domain - Update
k8s/ingress.yamlwith your hostname and TLS settings
For production with managed PostgreSQL:
# Update the connection string in secrets
kubectl create secret generic joby-secrets \
--from-literal=ConnectionStrings__DefaultConnection="Host=your-db.example.com;..." \
--from-literal=Jwt__Secret="your-production-secret" \
-n jobycd backend
dotnet testMigrations are applied automatically on startup. To create a new migration:
cd backend
dotnet ef migrations add MigrationName --project src/Infrastructure --startup-project src/ApiEdit backend/src/Infrastructure/Services/ResumeParser.cs and add skills to the KnownSkills HashSet.
- JWT tokens stored in memory/localStorage (trade-off: XSS risk vs simplicity)
- Refresh tokens stored in HTTP-only cookies
- Automatic token refresh on 401 responses
- Simple skill/keyword overlap scoring (0-100)
- Computed on profile/job changes and via scheduled job
- Explainable: shows matched and missing skills
- PDF: UglyToad.PdfPig (open source)
- DOCX: OpenXML SDK
- Heuristic parsing for names, emails, skills
- User can edit/override all extracted data
- Secrets Management: Use Kubernetes secrets or external secrets management (Vault, AWS Secrets Manager)
- CORS: Configure allowed origins for production
- Rate Limiting: Consider adding rate limiting middleware
- Input Validation: All inputs validated with FluentValidation
- SQL Injection: Prevented by EF Core parameterized queries
MIT
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request