Files
2026-07-22 05:12:07 +02:00

175 lines
7.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Bron- en adapterarchitectuur
## 1. Adaptercontract
Iedere adapter implementeert conceptueel:
```python
class SourceAdapter(Protocol):
parser_key: str
parser_version: str
def extract(self, content: str, *, url: str) -> ExtractionResult: ...
```
`ExtractionResult` bevat:
- `jobs: list[ExtractedJob]`;
- stabiele parser key/version;
- confidence 0..1;
- machine-/mensleesbare warnings.
Adapters:
- doen geen netwerkrequests;
- schrijven niet naar ORM;
- voeren geen scoring of bronpolicy uit;
- werken deterministisch op aangeleverde fixtures;
- bewaren alleen beperkte raw payload voor debugging;
- leveren evidence per belangrijk veld.
## 2. Parservolgorde
Voor HTML:
1. JSON-LD `JobPosting`;
2. gespecialiseerde adapter op expliciete source parser key;
3. generieke HTML-fallback;
4. geen vacature wanneer minimumvelden ontbreken.
Voor XML/feed:
1. RSS/Atom;
2. sitemapdiscovery (backlog);
3. geen generieke HTMLparser.
Voor e-mail:
1. MIME decode zonder attachments;
2. linkextractie met unsubscribe/privacyfilter;
3. bij een platformmailbox uitsluitend gelabelde HTTPS-links op het gekozen jobboarddomein aanvaarden;
4. externe tracking-, account-, help-, privacy- en uitschrijflinks verwerpen;
5. platformalias en provenance bewaren;
6. oorspronkelijke werkgever proberen te resolveren in een aparte begrensde taak.
## 3. Minimumvelden
Een jobdraft is verwerkbaar wanneer minstens aanwezig:
- titel;
- HTTP(S)-URL of stabiele externe identiteit.
Employer, locatie en beschrijving mogen tijdelijk ontbreken, maar verlagen confidence. Een generieke pagina zonder herkenbare titel wordt niet als job opgeslagen.
## 4. Confidence
Richtwaarden:
| Methode | Baseline |
|---|---:|
| JSON-LD geldig individueel JobPosting | 0,95 |
| gespecialiseerde publieke ATS-adapter | 0,90 |
| RSS/Atom | 0,82 |
| vacaturemailanchor | 0,650,75 |
| generieke HTMLselectors | 0,450,75 |
Fieldconfidence en extractionconfidence zijn gescheiden. Een perfecte titel maakt een ontbrekende werkgever niet betrouwbaar.
## 5. Nieuwe adapter toevoegen
1. Maak `apps/sources/adapters/<naam>.py`.
2. Geef vaste parser key en semverachtige version.
3. Parse alleen de aangeleverde content.
4. Maak geanonimiseerde fixture onder `fixtures/`.
5. Test happy path, ontbrekende velden, gewijzigd markup en malafide HTML.
6. Registreer uitsluitend voor een expliciete source/parserdetectie.
7. Documenteer bronbeleid, rate limit en canonical URL-gedrag.
8. Voeg traceability toe.
## 6. ATS-strategie
Gespecialiseerde adapters mogen publieke HTML of publieke, documenteerbare endpoints gebruiken wanneer:
- geen login/token nodig is;
- bronpolicy `allow` is;
- gebruiksvoorwaarden/robots zijn beoordeeld;
- het endpoint rechtstreeks vacatures van de werkgever publiceert;
- rate limiting en identifiers stabiel zijn;
- fallback naar HTML mogelijk is.
Een endpoint mag technisch JSON zijn zonder een commerciële platform-API-integratie te vormen. De policybeslissing blijft per bron vereist.
## 7. Bronpromotie
```text
candidate
-> policy/robots/terms review
-> trial (kleine frequentie, parserconfidence meten)
-> active (voldoende succesvolle runs)
-> quarantined (policy, security of herhaalde parsefout)
-> trial/active na expliciet herstel
```
Automatische promotie naar `active` vereist minimaal:
- meerdere succesvolle runs;
- geen private/deny redirect;
- voldoende extractieconfidence;
- geen onverwachte volumepiek;
- policy nog geldig.
Juridische voorwaarden mogen niet door een taalmodel als definitief toegestaan worden verklaard.
## 8. Rate limiting
Per eTLD+1/domein:
- concurrency standaard 1;
- minimum interval standaard 30 seconden;
- respecteer `Retry-After`;
- conditionele GET met ETag/Last-Modified;
- exponentiële backoff bij fout;
- geen retry op policyblokkade;
- adaptieve lagere frequentie bij stabiele, zelden wijzigende bron.
## 9. Parserdrift
Bronhealth detecteert:
- leeg resultaat waar eerder vacatures waren;
- sterke daling in velddichtheid/confidence;
- nieuwe foutstatus/contenttype;
- wijziging in jobvolume;
- ontbrekende title/URL;
- veel nieuwe canonical keys door URLtrackingwijziging.
Automatisch herstel mag veilige selectorvarianten proberen, maar nieuwe logica moet eerst op opgeslagen fixture/snapshot draaien. Geen live agressieve exploratie.
## Publieke ATS-providers (VR-106)
| Provider | Hostherkenning | Parserbenadering | Opmerking | Rate limit (advies) |
|---|---|---|---|---|
| Greenhouse | `*.greenhouse.io`, `*.boards.greenhouse.io` | gespecialiseerd endpoint/JSON + detailstructuren | gebruik alleen publieke boardpagina's/feeds, geen private/persoonlijke endpoints | 15 requests/min met conditional request indien beschikbaar |
| Lever | `jobs.lever.co` | gespecialiseerd JSON/HTML listing+detail | alleen publieke postings, geen recruiter login flow | 60 requests/min per domein |
| Recruitee | `*.recruitee.com` | gespecialiseerd listing+detail parser | parse alleen door werkgever geïntendeerde publieke vacature-URLs | 60 requests/min per domein |
| SmartRecruiters | `*.smartrecruiters.com` | gespecialiseerd listing+detail parser | geen interne API-auth nodig; stop bij CAPTCHA/anti-bot | 30 requests/min per domein |
| Workable | `apply.workable.com` | gespecialiseerd listing+detail parser | alleen publieke vacaturepagina/JSON; geen private endpoints | 30 requests/min per domein |
Gedeelde ATS-hosts zijn geen bronidentiteit: meerdere werkgevers mogen hetzelfde providerdomein gebruiken zolang iedere bron een unieke publieke `base_url` heeft. De scheduler blijft per origin coördineren, zodat deze extra bronrecords de providerlimiet niet omzeilen.
Voor Corda Campus is een begrensde regionale listingadapter beschikbaar. Die leest uitsluitend de expliciete `/jobs/`-kaarten, bewaart de vermelde werkgever en weigert iedere joblink buiten `cordacampus.com`. Vacaturedetail en sollicitatie-URL's worden niet automatisch gevolgd.
Voor elke provider-adapter:
- `supports()` kijkt eerst op host/marker om andere pagina's niet te matchen;
- listingpayloads produceren kandidaten zonder fetch van detail;
- detailpayloads vullen een enkele vacaturestructuur;
- elke veldafklaring krijgt veld-evidence met method-labels en confidence.
## Regionale Mol-adapter (VR-126)
`MolRegionEmployerAdapter` verwerkt uitsluitend vijf vooraf gereviewde HTTPS-lijstroutes rond postcode 2400: SCK CEN, Cipal Schaubroeck, VanRoey, NTX/Netropolix en Thomas More. De adapter doet geen netwerkrequests en accepteert alleen same-host vacaturelinks. Cipal, NTX en Thomas More vereisen een expliciete lokale marker; bij Thomas More wordt bovendien de vaste publieke werkgever-GUID gecontroleerd. VanRoey-detailpaden zijn door robots uitgesloten en worden daarom nooit door VacatureRadar gefetcht; alleen de toegestane overzichtspagina dient als bron.
## Kempen-werkgeversadapter (VR-201)
`KempenEmployerAdapter` voegt zeven gereviewde werkgeversroutes toe voor Ziekenhuis Geel, lokaal bestuur Geel, Stad Turnhout, Group Renotec, Ravago, Sanofi en DAF Trucks Westerlo. Iedere route heeft een vaste HTTPS-host en een toegestaan lijstpad; vacaturelinks moeten same-host zijn. Voor gedeelde of landelijke lijsten blijft alleen een kaart met de expliciete gereviewde vestiging over. Gemeente Mol wordt via de officiële same-host RSS-feed verwerkt. Interessante werkgevers zonder stabiele fail-closed parser blijven als niet-scanbare waaklijstbron zichtbaar.