Jobby is a full-stack job application tracker with a kanban pipeline, calendar, recruiter CRM, AI resume tools, and an admin approval workflow. The stack is ASP.NET Core 10 (API + SPA host) and React 19 / Vite / TypeScript.
jobby.client/ React SPA (Vite, Tailwind, shadcn/ui)
Jobby.Server/ ASP.NET Core Web API, EF Core, Identity + JWT
Jobby.Server.Tests/ xUnit tests for shared helpers and constants
In development, the Vite dev server runs on https://localhost:60922 and proxies /api to the backend at https://localhost:7048. In production, the API serves the built SPA from jobby.client/dist.
| Area | Description |
|---|---|
| Dashboard / Kanban | Drag-and-drop pipeline of job applications across custom stages |
| Applications | Company, title, URL, location, salary, notes, status, archive |
| Calendar | Interview and follow-up events tied to applications |
| Recruiters | Track recruiter contacts, agencies, and follow-up dates |
| Resume rating | Upload a .docx resume for ATS-style scoring via Ollama |
| Resume tailoring | Paste a job posting + upload .docx to generate a tailored resume |
| Archive | View and restore archived applications |
| Admin | Approve users, manage roles (User, Admin), edit accounts |
- ASP.NET Core Identity with JWT bearer tokens
- New registrations require admin approval (
IsApproved) before login succeeds - Password rules: 8+ chars, uppercase, digit
- Frontend stores token and user in
localStorage; axios attachesAuthorization: Beareron each request
- User — standard access to own data
- Admin — access to
/adminuser management
All routes are under /api and require authentication unless noted.
| Controller | Base route | Key endpoints |
|---|---|---|
| Auth | /api/auth |
POST register, POST login, GET user |
| App | /api/app |
GET all, POST new, POST update, POST move/{id}, POST gen, GET archive, DELETE {id} |
| Stage | /api/stage |
GET pipeline, POST new, POST update, DELETE delete/{id} |
| Recruiter | /api/recruiter |
GET all, GET {id}, POST new, POST update, DELETE {id} |
| Events | /api/events |
GET get, POST new, DELETE delete/{id} |
| History | /api/history |
GET {appId} |
| Resume | /api/resume |
POST review |
| Admin | /api/admin |
User and role management |
Multipart uploads: POST /api/app/gen and POST /api/resume/review accept file (.docx) via multipart/form-data. Resume generation also requires a posting field.
Resume features use Ollama Cloud through OllamaSharp:
- Tailoring (
AppService.EditDocxAsync) — extracts resume blocks from Word, analyzes the job posting, applies targeted edits, returns base64 docx + change list - Rating (
ResumeService.RateResumeAsync) — extracts text from Word, returns structured JSON analysis
Configure in appsettings.Development.json (gitignored):
"Ollama": {
"ApiKey": "<your-key>",
"BaseUrl": "https://ollama.com",
"TextModel": "gpt-oss:120b"
}- PostgreSQL via EF Core (
Npgsql) - Migrations run automatically on startup
- Key entities:
JobApp,AppStage,JobEvent,JobHistory,Recruiter,ApplicationUser
- .NET 10 SDK
- Node.js 20+
- PostgreSQL connection string in
Jobby.Server/appsettings.Development.json
-
Start the backend (also launches Vite via SPA proxy):
cd Jobby.Server dotnet run --launch-profile https -
Open
https://localhost:60922(or the URL shown in the console). -
Register an account, then approve it via an existing admin user or directly in the database.
jobby.client/.env.development:
VITE_API_URL=/api
DEV_SERVER_PORT=60922
dotnet test Jobby.Server.Tests/Jobby.Server.Tests.csprojIf the server is running, stop it first so the build can copy
Jobby.Server.exe.
cd jobby.client
npm test- Controllers use
[ApiController]+[Route("api/...")] - Services use
IDbContextFactory<AppDbContext>for scoped database access - Async methods use the
Asyncsuffix - User-scoped operations filter by
userIdfrom JWT claims
- API calls go through
src/api.ts(axios instance) - Feature services live in
src/services/ - Types in
src/types/ - Protected routes via
ProtectedRoute; admin routes viaAdminRoute AuthProviderwraps the app once inApp.tsx
Private / not specified.