Skip to content

About

app for myself

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Quick Application Tracker

A FastAPI application with a server-rendered Jinja2 UI for tracking job applications. You register or sign in (email/password or Google), upload a screenshot of a listing, and the app extracts structured fields with an OpenAI vision model, saves the row, and lets you mark jobs applied, saved, or rejected from the browser.

Product notes live in reqs.md. PostgreSQL table layout is summarized in db_tables.md; SQL migrations under supabase/migrations/ track schema changes (for example Google columns on users and location on jobs).

Stack (at a glance)

  • FastAPI — HTTP API and GET / dashboard
  • SQLAlchemy + psycopg2 — PostgreSQL (Supabase-friendly)
  • Jinja2 + static/ — HTML UI and styles
  • passlib/bcrypt, python-jose — password hashing and JWT session cookie
  • Pillow — validate, resize, and re-encode uploads before vision calls
  • OpenAI SDK — vision extraction from normalized images

Prerequisites

  • Python 3.11+
  • PostgreSQL with users and jobs tables compatible with db_tables.md and any applied supabase/migrations/ (optional location on jobs, Google-related columns on users)
  • OPENAI_API_KEY for extraction
  • Optional: Google OAuth client for “Continue with Google”

Shell examples use bash; on Windows, use the equivalent PowerShell commands and .venv\Scripts\activate.

Setup

From the repo root:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt

If psycopg2-binary fails to build on macOS, install Xcode Command Line Tools:

xcode-select --install

Environment

cp .env.example .env
Variable Purpose
DATABASE_URL SQLAlchemy PostgreSQL URL (preferred; Supabase “URI” from the dashboard)
DB_URL Legacy alias for DATABASE_URL if older .env files use it
SECRET_KEY Signs JWT session cookies — e.g. openssl rand -hex 32
OPENAI_API_KEY Required for /jobs/from-image extraction
OPENAI_VISION_MODEL Optional; defaults to gpt-4.1. Must accept images and structured JSON output.
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI Optional; all three must be set to enable Google sign-in

Do not commit .env or real secrets.

Google OAuth

Verified Google emails can link to an existing email/password account (google_sub is stored on that user). Google-only accounts have a nullable password.

  1. Google Cloud Console: OAuth consent screen + OAuth 2.0 Client ID (Web application).
  2. Authorized redirect URI must match exactly what you put in .env (for local dev: http://127.0.0.1:8000/auth/google/callback).
  3. Set GOOGLE_REDIRECT_URI to that same URL; use HTTPS and your production host in production.

Flow: browser hits GET /auth/google, then Google redirects to GET /auth/google/callback.

Run

uvicorn main:app --reload

Open http://127.0.0.1:8000. Unauthenticated requests to / redirect to /auth/login.

Web UI routes

Path Description
/ Pipeline dashboard (authenticated)
/auth/register, /auth/login Registration and login forms
/auth/logout POST — clears session cookie
/static/... CSS and other static assets

API / docs

Path Description
/docs, /redoc OpenAPI
/health { "ok": true } or 503 if the database ping fails

Authenticated JSON API (JWT session cookie)

Auth

Method Path Notes
GET /auth/me Current user

Jobs

Method Path Notes
POST /jobs/from-image multipart/form-data: required image (PNG, JPEG, or WebP); optional url (stored only, never fetched)
GET /jobs List current user’s jobs, newest first
PATCH /jobs/{id}/apply Status Applied, sets date_applied to today
PATCH /jobs/{id}/unapply From Applied back to Saved; clears date_applied
PATCH /jobs/{id}/reject Status Rejected
DELETE /jobs/{id} Remove row

POST /jobs/scrape is deprecated and returns 410 Gone (URL scraping disabled; use image upload).

Image upload and extraction

  • Upload limit after read: 8 MB; types PNG, JPEG, WebP (see app/services/images.py).
  • The server normalizes the image (decode, resize bound, re-encode), then calls the vision model.
  • Extracted fields: title, company, date_posted (relative phrases may be normalized to a date where possible), and location when visible (city/region/country or “Remote”).

Tests

pytest

Troubleshooting

  • /health returns 503 — Check DATABASE_URL, network/firewall, Supabase SSL/session vs pooler port, and that tables exist.
  • Vision errors — Confirm OPENAI_API_KEY and OPENAI_VISION_MODEL; try a clear listing screenshot within type/size limits.
  • Google sign-in unavailable — All three Google env vars must be non-empty; mis-matched redirect URI is a common mistake.

About

app for myself

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages