Skip to content

Joun-Mikhail/careerflow

Repository files navigation

CareerFlow

A modern SaaS platform for tracking job applications, interviews, tasks, and career opportunities.

Stop losing track of your job search across spreadsheets and inboxes — manage your entire pipeline, from wishlist to offer, in one professional workspace.

CI Mobile build Backend Frontend Coverage License

CareerFlow dashboard

The dashboard, captured from the running application with seeded demo data.


Table of contents

Why CareerFlow

A typical active job search runs 20–80 applications over several months. The information that matters — what stage each application is at, when the next interview is, who you spoke to, what follow-up is due — ends up scattered and forgotten. CareerFlow centralizes it into a single source of truth and turns it into something you can actually reason about, with a pipeline board, reminders, and analytics on what's converting.

Try it in 30 seconds

One link, every platform: app.careerflow.app/install — the page detects your device and points you at the App Store, Google Play, or the PWA install prompt.

Live demo on the web: frontend-jade-two-zfchqjb5ws.vercel.app — open it and press ▶ Try demo — no signup needed on the login screen.

App Store Google Play Install PWA

Native iOS and Android apps build from the same codebase via Capacitor — see docs/app-store-submission.md for how to ship them.

Want your own copy? Deploy the full stack (API + Postgres + web) with a single click:

Deploy to Render Deploy to Heroku Deploy with Vercel

Button What it provisions
Render Backend (Docker) + managed Postgres + static frontend, all from render.yaml.
Heroku Backend (container stack) + Heroku Postgres add-on, from app.json.
Vercel Frontend only (point VITE_API_BASE_URL at any CareerFlow API).

The seed routine creates a demo account on first boot — demo@careerflow.app / DemoPass123! — pre-wired to the Try-demo button.

Install as a native-feeling app

CareerFlow is a Progressive Web App. From any modern browser:

  • Chrome / Edge — click the install icon (⊕) in the address bar, or Menu → Install CareerFlow.
  • Safari (iOS / iPadOS)Share → Add to Home Screen.
  • Firefox (Android)Menu → Install.

It then launches in its own window, works offline for the shell, and shows up alongside your native apps. No store, no download.

Features

  • 🔐 Secure auth — email/password registration, bcrypt hashing, short-lived JWT access tokens with refresh-token rotation, and fully user-scoped data.
  • 🏢 Companies — CRUD with search, industry filtering, and pagination.
  • 💼 Application pipeline — eight stages (Wishlist → Applied → Assessment → Interview → Final → Offer → Rejected → Accepted), shown as a Kanban board or a sortable list, with salary, location, source, and links.
  • 🗓️ Interviews — multiple rounds per application plus a dedicated cross-pipeline list filtered by upcoming/past.
  • 💰 Offers — track base salary, bonus, equity, benefits, and your decision (pending/negotiating/accepted/declined).
  • Tasks — priorities, due dates, completion, and semantic priority sorting.
  • 📝 Notes — Markdown notes per application.
  • 📎 Attachments — secure resume/cover-letter uploads (validated, owner-only download).
  • 📊 Dashboard & analytics — headline stats, upcoming interviews, pending tasks, and Recharts visualizations (applications over time, status & industry distribution, conversion rates).
  • 📤 CSV export — download your whole pipeline as an RFC-4180 CSV (Excel/Sheets-ready) in one click.
  • 📁 Document vault — store multiple CVs (PDF/DOCX), certificates, and skills; durable object storage (Cloudflare R2 / S3) with a local-disk fallback.
  • AI CV tailoring — rewrite a CV (and optional cover letter) for a specific job via OpenAI (gpt-4o-mini), saved as a new versioned CV. Falls back to an offline stub with no API key.
  • 🔎 Job search — save search filters and fetch matching jobs from Adzuna (with a mock provider when no keys are set); tailor a CV straight from a fetched job.
  • ⚙️ Settings — update your profile and change your password.
  • 📱 Installable PWA + mobile UI — install to a phone/desktop home screen; on small screens the sidebar becomes a slide-in drawer.
  • 🌗 Polished UX — responsive layout, light/dark themes, Zod-validated forms, and proper loading / empty / error states throughout.

Screenshots

Captured from the running app (frontend/scripts/screenshot.mjs) against the seeded demo data.

CareerFlow walkthrough: dashboard, pipeline board, application detail, tasks, analytics

Dashboard Pipeline board
Dashboard with headline stats, upcoming interviews and pending tasks Kanban pipeline board
Application detail Analytics
Application detail with interviews, notes, attachments Analytics charts
Offers Interviews
Offers with salary, bonus, and decision status Global interviews list

CareerFlow on mobile with the slide-in navigation drawer

On phones the sidebar collapses into a slide-in drawer — the app installs to your home screen as a PWA.

Tech stack

Layer Technologies
Frontend React 18, TypeScript, Vite, React Router, TanStack Query, Recharts
Backend Python 3.11/3.12, FastAPI, SQLAlchemy 2.0, Alembic, Pydantic v2
Database PostgreSQL 16
Auth JWT (PyJWT), bcrypt
DevOps Docker, Docker Compose, Nginx, GitHub Actions
Quality Pytest, Vitest, Ruff, mypy, ESLint, Prettier, Bandit, pip-audit

Quick start

The entire platform runs with one command (requires Docker):

git clone <repo-url> careerflow
cd careerflow
docker compose up --build
Service URL
Web app http://localhost:5173
API (Swagger UI) http://localhost:8000/api/docs
API (ReDoc) http://localhost:8000/api/redoc
Health probe http://localhost:8000/health

The backend applies migrations and seeds the demo account automatically on first start.

Architecture

Three tiers: a React SPA, a layered FastAPI backend, and PostgreSQL. In production Nginx serves the built SPA and reverse-proxies /api to the backend, so the browser sees a single origin.

flowchart LR
    subgraph Browser
        SPA["React SPA<br/>Vite · TanStack Query · Recharts"]
    end
    subgraph Edge["Edge (production)"]
        NGINX["Nginx<br/>static assets + /api proxy"]
    end
    subgraph Backend["FastAPI backend"]
        direction TB
        ROUTERS["api/ routers<br/>(HTTP only)"]
        SERVICES["services/<br/>(business rules + authz)"]
        REPOS["repositories/<br/>(all SQL)"]
        MODELS["models/<br/>(SQLAlchemy 2.0)"]
        ROUTERS --> SERVICES --> REPOS --> MODELS
    end
    DB[("PostgreSQL")]
    FILES[["Local file storage<br/>(off web root)"]]
    SPA -->|HTTPS / JSON| NGINX
    NGINX -->|/api/v1| ROUTERS
    NGINX -->|static| SPA
    MODELS --> DB
    SERVICES --> FILES
Loading

The backend enforces a strict, inward-pointing dependency rule — routers do HTTP, services hold business logic and authorization, repositories own all data access. Details and rationale live in docs/02-technical-architecture.md.

Data model (ERD)

erDiagram
    USERS ||--o{ COMPANIES : owns
    USERS ||--o{ APPLICATIONS : owns
    USERS ||--o{ TASKS : owns
    COMPANIES ||--o{ APPLICATIONS : "linked to (nullable)"
    APPLICATIONS ||--o{ INTERVIEWS : has
    APPLICATIONS ||--o{ NOTES : has
    APPLICATIONS ||--o{ ATTACHMENTS : has
    APPLICATIONS |o--o{ TASKS : "may relate to"

    USERS {
        uuid id PK
        string email UK
        string hashed_password
        bool is_active
    }
    COMPANIES {
        uuid id PK
        uuid user_id FK
        string name
        string industry
        datetime deleted_at
    }
    APPLICATIONS {
        uuid id PK
        uuid user_id FK
        uuid company_id FK
        string role_title
        enum status
        int salary_min
        datetime deleted_at
    }
    INTERVIEWS {
        uuid id PK
        uuid application_id FK
        datetime scheduled_at
        enum result
    }
    TASKS {
        uuid id PK
        uuid application_id FK
        string title
        bool is_completed
    }
    NOTES {
        uuid id PK
        uuid application_id FK
        text body
    }
    ATTACHMENTS {
        uuid id PK
        uuid application_id FK
        enum kind
    }
Loading

Full schema, indexes, and referential rules: docs/03-database-design.md.

Request lifecycle

Creating an application, showing validation, authorization, and the layer hand-off:

sequenceDiagram
    autonumber
    participant B as Browser (SPA)
    participant R as Router (api/)
    participant S as ApplicationService
    participant Repo as Repositories
    participant DB as PostgreSQL
    B->>R: POST /api/v1/applications (Bearer JWT)
    R->>R: Validate body (Pydantic) + decode JWT
    R->>S: create(owner, data)
    opt company_id provided
        S->>Repo: company owned by user?
        Repo->>DB: SELECT company WHERE id AND user_id
        Repo-->>S: Company or NotFound(404)
    end
    S->>Repo: add(application)
    Repo->>DB: INSERT application
    S-->>R: Application
    R-->>B: 201 Created (ApplicationRead)
Loading

The authentication flow is diagrammed in docs/diagrams/sequence-auth.mmd.

Project structure

careerflow/
├── backend/            FastAPI service (layered: api · services · repositories · models)
│   ├── app/
│   ├── alembic/        database migrations
│   └── tests/          unit + integration tests
├── frontend/           React + TypeScript SPA (Vite)
│   └── src/            pages · components · hooks · services · contexts
├── docs/               PRD, architecture, DB & API design, security, diagrams
├── .github/workflows/  CI pipeline
└── docker-compose.yml  full-stack one-command startup

A deeper tour is in docs/06-folder-structure.md.

Development

Run the apps natively for a tighter feedback loop.

Backend (Python ≥ 3.11):

cd backend
python -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
cp .env.example .env
alembic upgrade head
uvicorn app.main:app --reload

Frontend (Node ≥ 20):

cd frontend
npm install
npm run dev      # http://localhost:5173, proxies /api to the backend

Testing & quality

Every change is gated by the same checks CI runs.

# Backend
cd backend
ruff check . && ruff format --check . && mypy app
bandit -r app && pip-audit
pytest --cov --cov-report=term-missing      # ~97% line coverage

# Frontend
cd frontend
npm run lint && npm run typecheck && npm test && npm run build

The backend suite (83 tests) runs against in-memory SQLite for speed and isolation; the production target is PostgreSQL. CI enforces a minimum 80% backend coverage and builds both Docker images.

Security

CareerFlow was built with a security-first mindset and audited in a dedicated phase:

  • All data is user-scoped; cross-user access returns 404 (no existence leak).
  • Passwords are bcrypt-hashed; auth errors are generic to prevent enumeration.
  • Inputs are validated by Pydantic and persisted via bound parameters (no SQL injection).
  • Uploads are type/size-validated, stored off the web root with opaque names, and served only to their owner.
  • Rate limiting on the auth endpoints (/auth/login, /auth/refresh, /auth/change-password) via SlowAPI, returning 429 with Retry-After and X-RateLimit-* headers.
  • bandit and pip-audit run in CI and are currently clean.

See docs/05-security-design.md and the audit in docs/security-review.md.

Reliability & observability

  • Global error boundary — render-time exceptions show a recoverable fallback ("Reload app") instead of a blank screen, and are reported to Sentry.
  • Loading skeletons — board, table, and detail views render shape-matching skeletons while data loads, keeping layout stable.
  • Toast notifications — non-blocking success/error toasts on login, profile and password changes, and offer/interview actions.
  • Structured audit logging — security-relevant actions (logins, password changes, profile updates, offer decisions) emit one JSON line each with timestamp, user_id, action, and status to a dedicated careerflow.audit logger.
  • Health probeGET /health reports database connectivity, app version, and uptime, and returns 503 when the database is unreachable.
  • Error monitoring (Sentry) — optional, env-gated on both the API (SENTRY_DSN) and the SPA (VITE_SENTRY_DSN); a no-op when unset.

Deployment

The repository is container-first. docker compose up --build is production-shaped: the backend image runs migrations on start, and Nginx serves the built SPA while proxying the API. For a real deployment, override the defaults in a root .env (see .env.example) — at minimum a strong JWT_SECRET and managed Postgres credentials; the app refuses to start in production with a placeholder secret.

Documentation

Document Contents
Product Requirements Problem, personas, journeys, functional & non-functional requirements
Technical Architecture Layering, technology rationale, boundaries
Database Design Tables, indexes, soft-delete & referential rules
API Design Endpoints, pagination, error format, examples
Security Design / Security Review Threat model, controls, audit findings
Deployment Guide Hosting the frontend, backend, and database
Runtime Verification Evidence from actual builds and runs
Folder Structure Repository layout and conventions
Backend Review / Repository Audit Self-reviews and refactors

Interactive API docs are generated from the code at /api/docs (Swagger) and /api/redoc.

Roadmap

  • Core domain: companies, applications, interviews, tasks, notes, attachments
  • Dashboard & analytics
  • Containerized stack + CI
  • Drag-and-drop status changes on the board
  • Email/calendar reminders for upcoming interviews
  • CSV/JSON export of the pipeline
  • Saved views and bulk actions

Known limitations

  • Single-user accounts only (no shared workspaces or collaboration).
  • Editing an application from its detail page lists only its current company in the picker; reassignment is available from the create flow.
  • Attachments are stored on local disk (a volume in Compose) rather than object storage.
  • The board groups rejected applications outside the visible pipeline columns (they remain in the list view).

Future improvements

  • Refresh-token rotation and token revocation.
  • Pluggable object storage (S3-compatible) for attachments.
  • Full-text search across notes and applications.
  • Optimistic UI updates and drag-and-drop on the pipeline board.

License

MIT © 2026 CareerFlow

About

A production-quality job-search tracker — FastAPI + React + Postgres, installable PWA with iOS/Android wrappers and one-click deploy. Track applications, interviews, tasks, and offers.

Topics

Resources

License

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors