Skip to content

AI Job Copilot

Source catalog · Knowledge graph

Facts

FactValue
Statusactive
Hosting platformcloudflare
Repositoryhttps://github.com/meta4m/ai-job-mvp
Tech stacklanguage: typescript, language: python, framework: nextjs, ui: react, styling: tailwindcss, runtime: cloudflare-workers, database: cloudflare-d1, build_tool: opennextjs-cloudflare, crawler: scrapling, scheduler: github-actions
Tagsjob-search, ai, career, web-scraping, cloudflare-workers, mvp
Last audited2026-09-15
Upstream dependenciesNone declared
Downstream dependenciesNone declared

Secrets manifest

Key names and metadata only. Encrypted records are available in this project’s vault below.

KeyDescriptionEnvironmentsRequired
AUTH_SECRETJWT session-signing secret for the jose-based auth cookie (lib/auth/session.ts); README requires >=32 chars. A placeholder is currently committed inline in wrangler.jsonc vars instead of a Worker secret.production, developmentYes
GEMINI_API_KEYGoogle AI Studio key for direct Gemini calls: legacy v2 analysis fallback, and the /api/jobs/search key pool (supports comma-separated rotation). The v3 managed path does not use it.production, developmentYes
GEMINI_API_KEY_2Second Google Gemini API key slot read by /api/jobs/search to expand the direct-call key pool (optional capacity rotation).production, developmentNo
GEMINI_API_KEY_3Third Google Gemini API key slot read by /api/jobs/search to expand the direct-call key pool (optional capacity rotation).production, developmentNo
GROQ_API_KEYGroq Cloud key (Llama 3.3 70B) used as the free-tier failover provider in the legacy AI config resolver when no Gemini key is present.production, developmentNo
CF_CLIENT_TOKENCloudflare AI Gateway runtime client token (cf-aig-authorization Bearer) required by the v3 managed-AI client to call the Gateway /compat/chat/completions endpoint; v3 AI features throw ‘misconfigured’ without it.production, developmentYes
SCRAPLING_MCP_TOKENBearer token authenticating the server-side client to the remote Scrapling MCP scraping service (Rozee.pk / Indeed Pakistan stealthy_fetch); endpoint must be HTTPS in production.production, developmentYes
SCRAPER_PROXYEgress proxy pool URLs with embedded user:pass credentials (residential/ISP nodes, e.g. Webshare) required for Rozee scraping through Cloudflare-challenged sources; comma-separated rotation pool. Do not reuse for Indeed.production, developmentNo
INDEED_PROXYOptional dedicated egress proxy URL with embedded credentials for Indeed requests only; Indeed falls back to a direct stealth connection when unset.production, developmentNo
CRON_SECRETShared secret checked against the x-cron-secret header on POST /api/cron/refresh, guarding the scheduled v3 job-ingestion endpoint (403 when unset or mismatched).productionYes
CLOUDFLARE_API_TOKENCloudflare API token (Workers deploy, D1 edit, AI Gateway) used by the GitHub Actions deploy workflow and by the local-dev D1 REST fallback in lib/db/index.ts.production, developmentYes
RAPIDAPI_KEYRapidAPI JSearch key (alias JSEARCH_API_KEY) for the optional secondary international job-search fallback in lib/jobs/aggregator.ts and the cron refresh route.productionNo
SCRAPLING_SYNC_SECRETBearer token for the legacy POST /api/jobs/sync-scraped ingestion endpoint documented in the README (wrangler + GitHub secret); that endpoint no longer exists in the current code, so this secret is likely vestigial.productionNo

Overview

Project Overview: AI Job Copilot

1. Executive Summary

  • Mission: A serverless “career acceleration” platform — ingest job openings from Pakistan-focused and global-remote boards, extract a candidate profile from an uploaded resume PDF, AI-score transferable capability fit, and generate tailored application materials with 1-click email apply.
  • Target Audience: Job seekers (primarily the Pakistan market plus global remote roles); the operator dogfoods it for their own search.
  • Primary Maintainer: The operator (meta4m) — private solo project, authored with the Google Antigravity CLI harness.

2. Current Status & Roadmap

  • Lifecycle State: active — all 5 commits land on 2026-09-08 (Kinetic Brutalism redesign, high-contrast readability overhaul, responsive-layout pass, an immutable GitHub-Actions-only deployment rule); production Worker aijobs at https://aijobs.iu8.workers.dev.
  • Ongoing: a dual-track codebase — the original v2 dashboard (real-time aggregator + match analysis) and an additive v3 pipeline (Scrapling-MCP ingestion, ranked matches, managed AI Gateway with opaque task aliases, one-off URL import). The README still documents a GitHub Actions Python scraper (scrape-regional-jobs.yml, scripts/scrapling_sync.py) that is absent from the repo — v3 moved that scraping behind a remote MCP service.

3. Core Capabilities

  • Resume capture: PDF upload with text extraction (pdfjs-dist) → AI semantic profile including a 4-vector title cluster (direct / methodology / lateral / umbrella titles); multi-resume lifecycle management.
  • Job ingestion: real-time aggregator over 8+ sources (LinkedIn PK, Rozee.pk, Indeed PK, ProPakistani, Science Careers/AAAS, WeWorkRemotely, Jobicy, Remotive, RemoteOK, Arbeitnow + optional RapidAPI JSearch); v3 adds Rozee/Indeed stealth scraping via a remote Scrapling MCP service and per-URL job import.
  • Scoring & review: transferable-capability fit score 0–100 with strengths, ATS keyword gaps, and matched keywords; v3 ranked match list carrying fit score, eligibility, freshness, and confidence; client-side caching for instant re-review of analyzed jobs.
  • Apply: tailored resume bullets, cover-letter hook, step-by-step application guide, and a 1-click email draft (Gmail / mail-client buttons) shown only when a posting exposes a direct contact email.
  • Platform: bcryptjs + jose JWT cookie auth, Cloudflare D1 persistence, /api/health reporting schema and AI-provider status.

Implements the same capture → score → review → apply workflow as the operator’s nextrole project; no code, config, or git references connect the two repos.

4. Key References

  • Repository: meta4m/ai-job-mvp
  • Production URL: https://aijobs.iu8.workers.dev — Worker name aijobs in wrangler.jsonc and README; live status not independently verified from the repo.
  • Architecture Docs: architecture.md · Deployment Guide: deployment.md

Architecture

Architecture & System Design: AI Job Copilot

1. System Topology

graph TD
U["Candidate browser"] --> W["Cloudflare Worker aijobs<br/>Next.js 16 App Router via OpenNext"]
W --> V2["v2 legacy API<br/>/api/auth · /api/jobs · /api/resume · /api/cron"]
W --> V3["v3 API<br/>/api/v3/jobs · matches/rank · tailor · ai/smoke"]
V2 --> AGG["Real-time aggregator lib/jobs/aggregator.ts<br/>LinkedIn PK · Rozee · Indeed · ProPakistani · AAAS · WWR · Jobicy · Remotive · RemoteOK · Arbeitnow"]
V3 --> MCP["Remote Scrapling MCP service<br/>stealthy_fetch Rozee/Indeed + egress proxy pool"]
V2 --> GW["Cloudflare AI Gateway /compat<br/>opaque custom-gemini task aliases"]
V3 --> GW
GW --> MODELS["Hidden Gemini model pools<br/>key rotation behind the gateway"]
V2 --> D1[("Cloudflare D1 ai-job-db")]
V3 --> D1
GHA["GitHub Actions deploy.yml<br/>tsc + build:worker + wrangler deploy"] --> W

Uncertainty: wrangler.jsonc declares three daily cron triggers (02:00/09:00/14:00 UTC) but no scheduled handler exists in the app code (OpenNext config is stock); /api/cron/refresh is a POST route guarded by CRON_SECRET, so how the triggers reach it is not evidenced in the repo.

2. Core Components & Subsystems

  • v2 legacy stack: /dashboard UI, aggregator (lib/jobs/aggregator.ts, 10+ parallel fetchers), semantic profiler (lib/ai/semantic-profiler.ts), job match/search/import APIs, resume upload/download, auth routes.
  • v3 stack (app/(v3), lib/v3, /api/v3/*): managed AI client (lib/v3/ai/client.ts — gateway-only, never provider keys; task registry with profile-extraction/job-requirements/job-ranking/tailoring aliases), Scrapling MCP client + Rozee/Indeed source adapters (lib/v3/scraping/), URL import, rank + tailor endpoints.
  • Auth (lib/auth/session.ts): bcryptjs password hashing + jose JWT in an HTTP-only cookie.
  • PDF pipeline (lib/pdf/parser.ts): pdfjs-dist extraction; unpdf/pdfjs-dist/canvas marked server-external in next.config.ts.
  • Data access (lib/db/index.ts): three-tier executeD1Query — native D1 binding (edge) → D1 REST API (needs CF token) → local JSON store .data/local_db.json for offline dev.
  • UI: “Kinetic Brutalism” design system — Tailwind v4, dark/light themes, Space Grotesk + DM Sans via next/font, WCAG AA/AAA contrast targets.

3. Data Flow & Storage Contracts

  • D1 ai-job-db (binding DB): legacy users, resumes, job_matches tables (schema.sql); additive v3 tables v3_jobs, v3_candidate_profiles, v3_matches (UNIQUE resume+job+ranker_version, versioned v3-rank-1), v3_scrape_runs — created idempotently by ensureV3Schema() on every ingestion run; jobs deduplicated by canonical_url / (source, source_job_id); stale jobs evicted on a 14-day TTL.
  • Local dev: .data/local_db.json persistent JSON fallback when no D1 binding or credentials exist; browser-side caches for analyzed jobs (0 ms reload) and a “recently reviewed” drawer.
  • No migrations directory — schema is ensured at runtime, never applied by deploy.

4. Architectural Decision Records (ADRs)

ADR-01: Single-platform Cloudflare monolith
  • Context: Next.js app + SQL + AI inference with a preference for one account and one deploy unit.
  • Decision: Ship via @opennextjs/cloudflare to a Worker; D1 for storage; AI through Cloudflare AI Gateway; no R2/KV bindings (R2 incremental cache left commented out).
  • Consequences: Edge-native single deployment; local dev needs the REST/JSON fallbacks to mirror D1 behavior.
ADR-02: Managed AI via opaque gateway aliases
  • Context: Avoid baking provider API keys and model names into app code (free-tier quotas, key rotation).
  • Decision: v3 calls only the AI Gateway /compat/chat/completions endpoint using custom-gemini-<pool>/<task> aliases and CF_CLIENT_TOKEN; keys and models live behind the gateway.
  • Consequences: No provider keys in v3 code paths; misconfiguration surfaces as explicit misconfigured errors; the v2 direct-Gemini/Groq fallback remains as resilience.
ADR-03: Additive v3 alongside untouched v2
  • Context: Rewrite ingestion and scoring without breaking the live dashboard.
  • Decision: All v3 tables and routes are purely additive (v3_* prefix, idempotent schema, versioned ranker).
  • Consequences: Zero-downtime experimentation at the cost of duplication (two authenticated UIs, two AI paths).
ADR-04: Scraping via remote MCP + proxy egress
  • Context: Rozee/Indeed sit behind Cloudflare challenges; Workers cannot run Playwright.
  • Decision: Server-side Scrapling MCP client (stealthy_fetch, HTTPS-only, bearer token) with a residential/ISP proxy pool (SCRAPER_PROXY); Indeed defaults to direct stealth unless INDEED_PROXY is set.
  • Consequences: Ingestion depends on an external MCP service and a paid proxy pool; the README’s GitHub-Actions Python scraper is gone from the repo (only requirements.txt remains).

Deployment

Deployment & Operational Runbook: AI Job Copilot

1. Hosting & Environments

EnvironmentPlatformURL / EndpointAuto-Deploy Branch
ProductionCloudflare Workers (OpenNext), Worker aijobshttps://aijobs.iu8.workers.dev (README + wrangler name; live status unverified)main — push-triggered GitHub Actions
Local devnext dev (Node 22)http://localhost:3000N/A

No staging environment exists. CI is .github/workflows/deploy.yml only — the README’s scrape-regional-jobs.yml cron workflow is not present in the repo.

2. Prerequisites & Toolchain

  • Node.js 22 (.nvmrc, engines.node) and npm.
  • Cloudflare account holding the ai-job-db D1 database (id pinned in wrangler.jsonc) and an AI Gateway; GitHub repo secrets for CI (see §4).
  • Optional: a remote Scrapling MCP service and an egress proxy pool for Rozee/Indeed scraping. requirements.txt declares Python scraping deps (scrapling/playwright) but no Python scripts exist in the repo.

3. Local Development Setup

Terminal window
git clone https://github.com/meta4m/ai-job-mvp
cd ai-job-mvp
npm install
cp .env.example .env.local # fill in keys (see spec.yml)
npm run dev # http://localhost:3000

Without D1 credentials the app persists to a local JSON store (.data/local_db.json); with CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_D1_DATABASE_ID + CLOUDFLARE_API_TOKEN set it queries D1 over the REST API instead.

4. Environment & Secrets Provisioning

Refer to spec.yml for the 13 declared secret keys (AUTH_SECRET, GEMINI_API_KEY, GEMINI_API_KEY_2/_3, GROQ_API_KEY, CF_CLIENT_TOKEN, SCRAPLING_MCP_TOKEN, SCRAPER_PROXY, INDEED_PROXY, CRON_SECRET, CLOUDFLARE_API_TOKEN, RAPIDAPI_KEY, SCRAPLING_SYNC_SECRET).

  • Secret Injection: Retrieve ciphertext from 2Brain vault and decrypt locally into .env.local.
  • Production: README prescribes npx wrangler secret put <NAME>; CI injects the same keys as build env in deploy.yml.
  • ⚠️ Drift to fix: wrangler.jsonc commits inline vars for AUTH_SECRET and GEMINI_API_KEY (the latter looks like a live key), contradicting .env.example’s “NEVER commit a real value here”. SCRAPLING_SYNC_SECRET guards a /api/jobs/sync-scraped endpoint that no longer exists in code (README-only).

5. Deployment Commands

Terminal window
# IMMUTABLE RULE (AGENTS.md + README): never run `wrangler deploy` locally.
npm run build # next build (compile + typecheck)
npm run build:worker # opennextjs-cloudflare build — local dry-run bundle
git push origin main # CI: npm ci → tsc --noEmit → build:worker → wrangler-action deploy

6. Verification & Health Checks

  • curl -f https://aijobs.iu8.workers.dev/api/health → JSON with status, v3SchemaInitialized, and aiEngine.activeProvider/model/gatewayConfigured.
  • Smoke test: register → upload resume PDF → profile extraction runs → matches list populates → open a job → fit score, strengths/gaps, and tailored bullets render → 1-click email box appears only when the posting has a contact email.
  • CI gates on main: tsc --noEmit and build:worker must pass before the deploy step runs.

7. Incident Response & Rollback

  • Bad deploy: git revert <sha> && git push origin main — CI redeploys the previous good bundle; there is intentionally no manual deploy path.
  • Red CI: deploys run only on pushes to main (PRs build/verify without deploying), so fix forward on a branch.
  • Secret exposure: rotate via wrangler secret put plus GitHub repo secrets, then push a commit to redeploy. Priority: the committed GEMINI_API_KEY in wrangler.jsonc.
  • D1 incidents: schema is runtime-ensured and additive only — no destructive migrations ship in this repo; rollback means redeploying old code, data survives.

Project vault

Cloudflare Access authorization and your passphrase are required to retrieve and decrypt stored values.

Client-Side Encrypted Secret Vault

Zero-knowledge architecture. Secrets are encrypted client-side using Web Crypto AES-256-GCM before leaving this browser tab. Edge databases store only ciphertext, IV, and salt.

Encrypted Records for ai-job-mvp (0)

Encrypted records have not been loaded.

Add / Rotate Encrypted Secret