Pipeline
The stages a vacancy goes through, from discovery on a job site to a sent application, and what each stage guarantees.
A vacancy moves through the same stages regardless of where it came from. Each stage reads the previous stage's stored result, so any step can be repeated or audited.
1. Discovery and crawl
Source adapters find postings. The adapters cover the Rabota.md and Delucru.md job boards, a generic HTML adapter, API, RSS and sitemap sources, and a fixture site used by tests.
Every crawl keeps a checkpoint. A recheck pass revisits known postings to see whether they changed or closed. A circuit breaker pauses a source that starts failing, so one broken site cannot waste the whole schedule.
2. Normalisation
Each posting becomes a SourceJob in a common shape: title, company, location, salary, description and a stable source key. The original is never overwritten.
3. Deduplication
The same vacancy often appears on several boards. Duplicates are merged into a CanonicalJob. The merge is reversible: every source posting stays stored, so a wrong merge can be split again.
4. Filters, then strict evaluation
Cheap, deterministic filters remove postings that break the hard requirements of the profile before any model is asked. What survives goes to a strict language-model evaluation against the confirmed profile.
The model is treated as an untrusted reader. It sees the vacancy as data, its answer is validated against a schema, and it never decides alone whether something is sent.
5. Contact and resume
An application needs a verified employer contact and a verified resume. If the posting has no public email, the vacancy is rejected rather than guessed at.
6. Application and policy
The application generator writes the message. A deterministic policy then makes the final decision from rules, not from model output. Only a policy-approved application reaches the sender, and the sender is given an application_id, not free text to send.
7. Sending
Gmail sending uses OAuth 2.0 with PKCE. Refresh tokens are encrypted at rest. Delivery results and delays are recorded, and bounded retries handle transient failures.
Daily minimum
A catch-up mechanism spreads applications across different companies so a daily minimum is met without flooding one employer. Employer relationships are tracked so that a company that already replied, or asked to stop, is released from further contact.
Data model
The schema holds UserProfile, Resume, JobPreference, JobSource, SourceCategory, SourceJob, CanonicalJob, JobSnapshot, ScanRun, BatchScanRun, MatchEvaluation, EmployerContact, Application, EmailDelivery, OAuthCredential, AuditEvent, Alert and DailyReport, among others.