AI Job Copilot
Source catalog · Knowledge graph
Facts
| Fact | Value |
|---|---|
| Status | active |
| Hosting platform | cloudflare |
| Repository | https://github.com/meta4m/ai-job-mvp |
| Tech stack | language: typescript, language: python, framework: nextjs, ui: react, styling: tailwindcss, runtime: cloudflare-workers, database: cloudflare-d1, build_tool: opennextjs-cloudflare, crawler: scrapling, scheduler: github-actions |
| Tags | job-search, ai, career, web-scraping, cloudflare-workers, mvp |
| Last audited | 2026-09-15 |
| Upstream dependencies | None declared |
| Downstream dependencies | None declared |
Secrets manifest
Key names and metadata only. Encrypted records are available in this project’s vault below.
| Key | Description | Environments | Required |
|---|---|---|---|
AUTH_SECRET | JWT 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, development | Yes |
GEMINI_API_KEY | Google 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, development | Yes |
GEMINI_API_KEY_2 | Second Google Gemini API key slot read by /api/jobs/search to expand the direct-call key pool (optional capacity rotation). | production, development | No |
GEMINI_API_KEY_3 | Third Google Gemini API key slot read by /api/jobs/search to expand the direct-call key pool (optional capacity rotation). | production, development | No |
GROQ_API_KEY | Groq 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, development | No |
CF_CLIENT_TOKEN | Cloudflare 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, development | Yes |
SCRAPLING_MCP_TOKEN | Bearer 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, development | Yes |
SCRAPER_PROXY | Egress 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, development | No |
INDEED_PROXY | Optional dedicated egress proxy URL with embedded credentials for Indeed requests only; Indeed falls back to a direct stealth connection when unset. | production, development | No |
CRON_SECRET | Shared 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). | production | Yes |
CLOUDFLARE_API_TOKEN | Cloudflare 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, development | Yes |
RAPIDAPI_KEY | RapidAPI JSearch key (alias JSEARCH_API_KEY) for the optional secondary international job-search fallback in lib/jobs/aggregator.ts and the cron refresh route. | production | No |
SCRAPLING_SYNC_SECRET | Bearer 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. | production | No |
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 Workeraijobsathttps://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/healthreporting 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 nameaijobsinwrangler.jsoncand 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"] --> WUncertainty: 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:
/dashboardUI, 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 withprofile-extraction/job-requirements/job-ranking/tailoringaliases), 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/canvasmarked server-external innext.config.ts. - Data access (
lib/db/index.ts): three-tierexecuteD1Query— native D1 binding (edge) → D1 REST API (needs CF token) → local JSON store.data/local_db.jsonfor 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(bindingDB): legacyusers,resumes,job_matchestables (schema.sql); additive v3 tablesv3_jobs,v3_candidate_profiles,v3_matches(UNIQUE resume+job+ranker_version, versionedv3-rank-1),v3_scrape_runs— created idempotently byensureV3Schema()on every ingestion run; jobs deduplicated bycanonical_url/(source, source_job_id); stale jobs evicted on a 14-day TTL. - Local dev:
.data/local_db.jsonpersistent 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/cloudflareto 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/completionsendpoint usingcustom-gemini-<pool>/<task>aliases andCF_CLIENT_TOKEN; keys and models live behind the gateway. - Consequences: No provider keys in v3 code paths; misconfiguration surfaces as explicit
misconfigurederrors; 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 unlessINDEED_PROXYis 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.txtremains).
Deployment
Deployment & Operational Runbook: AI Job Copilot
1. Hosting & Environments
| Environment | Platform | URL / Endpoint | Auto-Deploy Branch |
|---|---|---|---|
| Production | Cloudflare Workers (OpenNext), Worker aijobs | https://aijobs.iu8.workers.dev (README + wrangler name; live status unverified) | main — push-triggered GitHub Actions |
| Local dev | next dev (Node 22) | http://localhost:3000 | N/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-dbD1 database (id pinned inwrangler.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.txtdeclares Python scraping deps (scrapling/playwright) but no Python scripts exist in the repo.
3. Local Development Setup
git clone https://github.com/meta4m/ai-job-mvpcd ai-job-mvpnpm installcp .env.example .env.local # fill in keys (see spec.yml)npm run dev # http://localhost:3000Without 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 indeploy.yml. - ⚠️ Drift to fix:
wrangler.jsonccommits inlinevarsforAUTH_SECRETandGEMINI_API_KEY(the latter looks like a live key), contradicting.env.example’s “NEVER commit a real value here”.SCRAPLING_SYNC_SECRETguards a/api/jobs/sync-scrapedendpoint that no longer exists in code (README-only).
5. Deployment Commands
# 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 bundlegit push origin main # CI: npm ci → tsc --noEmit → build:worker → wrangler-action deploy6. Verification & Health Checks
curl -f https://aijobs.iu8.workers.dev/api/health→ JSON withstatus,v3SchemaInitialized, andaiEngine.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 --noEmitandbuild:workermust 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 putplus GitHub repo secrets, then push a commit to redeploy. Priority: the committedGEMINI_API_KEYinwrangler.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.