Full-Stack + AI

JobMatch: Semantic Job-Matching Platform

Multi-tenant platform ranking remote jobs against your résumé via Gemini vector embeddings and pgvector.

Next.js 15FastAPISupabase/pgvectorGoogle Geminin8nDockerCloudflare Tunnel
01

Problem

Keyword job boards flood candidates with noise while the roles that actually fit their experience get buried. Matching by keyword overlap fails to capture whether a job truly aligns with a résumé, and single-user automation scripts cannot serve multiple users with isolated, private data.

02

Approach

Treated matching as a semantic retrieval problem: embedded both résumés and job descriptions into the same 768-dimension Gemini vector space and ranked every job by pgvector cosine similarity. Built an idempotent n8n ingestion pipeline pulling from Adzuna and RemoteOK daily with SHA-256 URL-hash deduplication, and enforced true multi-tenancy with Postgres Row-Level Security and asymmetric ES256/JWKS JWT verification.

03

Outcome

Shipped a live multi-user product self-hosted on a DigitalOcean droplet behind a Cloudflare Tunnel (zero open inbound ports) with the Next.js frontend on Vercel. First live ingestion pulled 72 real jobs into the shared pool; matching, auth isolation, dedup, ingestion, and the opt-in nightly email digest were each verified end to end.

Technical Highlights

(7)
  • 01

    Semantic matching over keyword search — Gemini 768-d L2-normalized embeddings (RETRIEVAL_QUERY for résumés, RETRIEVAL_DOCUMENT for jobs) ranked by pgvector ivfflat cosine index

  • 02

    Database-enforced multi-tenancy via Postgres Row-Level Security — per-request transaction sets request.jwt.claims and SET LOCAL role authenticated so auth.uid() resolves inside the DB

  • 03

    Asymmetric JWT verification — caches Supabase JWKS public keyset and verifies ES256 tokens locally, no per-request round-trip to the auth server

  • 04

    Idempotent daily ingestion in n8n from Adzuna + RemoteOK with SHA-256 url_hash dedup enforced at the DB level (ON CONFLICT DO NOTHING)

  • 05

    Multi-résumé support with best-fit attribution — DISTINCT ON … ORDER BY score DESC surfaces each job once under its strongest-matching résumé

  • 06

    Opt-in nightly email digest (off by default) of top matches, enforced at the query layer and toggled per user

  • 07

    Self-hosted FastAPI in Docker Compose behind a Cloudflare Tunnel on a custom .me domain — API binds only to loopback, no inbound ports open

Kumar Priyam — AI Engineer · SDE · Data Engineer