製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗AI-assisted job search + application CRM for the Swedish market. Polls Arbetsförmedlingen's JobStream API into one shared ad pool, scores ads in two layers against your CV and stated criteria, drafts cover letters you revise in a chat loop, sends them via your own Gmail only after explicit confirmation, and tracks replies via IMAP IDLE.
Architecture, invariants, and design decisions: see CLAUDE.md.
npm install
cp .env.example .env # fill in DATABASE_URL, ANTHROPIC_API_KEY, GMAIL_*
Local Postgres (or use a free Neon/Supabase connection string):
docker run -d --name jobbjakt-pg --restart unless-stopped -e POSTGRES_USER=jobbjakt -e POSTGRES_PASSWORD=jobbjakt -e POSTGRES_DB=jobbjakt -p 6543:5432 pgvector/pgvector:pg16
(Then set DATABASE_URL=postgres://jobbjakt:jobbjakt@localhost:6543/jobbjakt.)
Port 6543 rather than the more obvious 5433: Windows reserves blocks of
ports for Hyper-V on boot, and 5433 landed inside one (5355-5454). Docker
then refuses to start with "an attempt was made to access a socket in a
way forbidden by its access permissions", which reads like a permissions
problem and is really a port-range collision. 6543 sits outside the
ranges Windows hands out. pgvector rather than plain postgres
because ads carry an embedding column.
Put your real CV in db/seed.local.sql first — a copy of
db/seed.sql, which git ignores and db:seed prefers. Scoring quality
depends entirely on it. Then:
npm run db:init # schema: db/baseline.sql + db/migrations/, recorded
npm run db:seed # profile + projects
To understand the data model, read db/schema.sql — it is generated
from the migrations, so it is always current.
npm run try fetches and scores 15 real ads.
Read the output. If scores are wrong, iterate on the prompt in
src/score.js — everything else is a wrapper around that call.npm run dev → http://localhost:3000Optional: npm run db:demo loads fake demo data so the UI is explorable
without an API key or mailbox (dev only).
Two deployables — IMAP IDLE needs a long-lived process, so the worker cannot run on Vercel:
| Process | Command | Hosts |
|---|---|---|
| UI + API | npm run dev / npm run build && npm start | Vercel (or Railway) |
| Worker | npm run worker | Railway / Fly / Render |
| Both (local) | npm run restart | — |
npm run restart kills any running dev/worker processes for this repo and
starts both again detached, logging to %TEMP%\jobbflo-dev.log and
%TEMP%\jobbflo-worker.log (Windows only).
The worker runs the JobStream poll (one global cursor in poll_state), the
scoring queue (per-search scan_interval), the IMAP IDLE loop with
reconnect + catch-up, and the follow-up checker (drafts only — nothing sends
without your click).
Use an app password, not your
real password. Searches can use plus-aliases ([email protected]) so
replies trace back to the search that sent them.
The /stream endpoint may require a free API key from
jobtechdev.se (JOBSTREAM_API_KEY). The JobSearch
backfill used when creating a new search works without one.