# Product Requirements Document — VacatureRadar ## 1. Productvisie VacatureRadar vermindert de tijd en mentale belasting van persoonlijk vacaturezoeken. Na een eenmalige configuratie verzamelt het systeem zelfstandig vacatures uit toegestane bronnen, verwijdert het duplicaten en duidelijke mismatches, verklaart het waarom een vacature relevant is en helpt het de opvolging structureren. Het product is geen massale scraper en geen automatische sollicitatiebot. Het is een persoonlijke vacancy-intelligencehub met menselijke eindcontrole. ## 2. Doelgebruiker Primaire gebruiker: één persoon in België die gericht werk zoekt en slechts enkele keren per week de beste resultaten wil bekijken. De implementatie blijft technisch user-scoped zodat later meerdere geïsoleerde gebruikers mogelijk zijn, maar multi-tenancy, billing en teams zijn geen MVP-doel. ## 3. Succesdefinitie Het product is succesvol wanneer: - de gebruiker na onboarding geen zoekopdrachten of broncontroles handmatig hoeft te herhalen; - nieuwe passende vacatures binnen 24 uur zichtbaar zijn voor dagelijks gecontroleerde bronnen; - dubbele vermeldingen als één canonieke vacature verschijnen; - iedere aanbeveling een begrijpelijke score, bewijs en aandachtspunten bevat; - harde uitsluitregels nooit door AI worden genegeerd; - bronfalen zichtbaar is zonder dat één fout de rest van de pipeline stopt; - normale bediening beperkt blijft tot bekijken, interessant/bewaren/verbergen/gesolliciteerd; - geen sollicitatie zonder bewuste gebruikersactie wordt verstuurd. ## 4. Scope ### 4.1 In scope - zoekprofielen met titels, skills, regio, afstand, werkvorm en contract; - harde uitsluitingen en gewogen voorkeuren; - werkgeverspagina's, publieke ATS-pagina's, RSS/Atom, sitemaps en vacaturemails; - handmatige/browserimport als veilige aanvulling; - bronbeleid, rate limiting, health en quarantaine; - extractie, normalisatie, taalherkenning en provenance; - deduplicatie en canonieke bronselectie; - uitlegbare deterministische score; - optionele lokale AI voor begrensde classificatie/samenvatting; - dagelijkse digest en sluitings-/opvolgherinneringen; - sollicitatiedossiers, notities en statussen; - self-hosting op Unraid via containers; - back-up, herstel, tests en observability. ### 4.2 Buiten scope - inloggen op of geautomatiseerd bedienen van vacatureplatformen; - CAPTCHA-, paywall- of blokkadeomzeiling; - massaal herpubliceren van vacaturedatabanken; - automatisch invullen/versturen van sollicitaties; - recruitment-CRM, multi-tenant SaaS of werkgeverstoegang; - garanties dat letterlijk iedere vacature wordt gevonden; - juridisch advies over een bron; - een taalmodel dat definitief bepaalt of iets wordt verwijderd. ## 5. Functionele requirements De IDs zijn stabiel en worden gebruikt in tests en traceability. ### Profiel en onboarding - **PR-001** — De gebruiker kan minstens één zoekprofiel aanmaken en één actief profiel kiezen. - **PR-002** — Het profiel ondersteunt gewenste/uitgesloten titels en skills, regio's, maximale afstand, contracttypes, werkvormen, drempels en digesttijd. - **PR-003** — Iedere betekenisvolle profielwijziging krijgt een versioned snapshot. - **PR-004** — Feedbackleren is opt-in/uitschakelbaar, begrensd en wijzigt geen harde regels. - **PR-005** — De onboarding levert bruikbare defaults zonder dat AI of externe API's nodig zijn. ### Bronnen en collectie - **PR-010** — Iedere bron heeft type, domein, status, policy, parser, planning en healthmetadata. - **PR-011** — Alleen expliciet toegestane bronnen worden automatisch opgehaald. - **PR-012** — Denylistplatformen worden nooit rechtstreeks gecrawld; vacaturemails mogen wel worden verwerkt. - **PR-013** — Iedere URL en redirect wordt vóór toegang op schema, credentials, poort, DNS en IP-bereik gevalideerd. - **PR-014** — Fetches hanteren timeouts, contenttype- en groottelimieten en conditionele headers. - **PR-015** — Bronnen worden idempotent gepland met begrensde retries en backoff. - **PR-016** — Vacaturemails worden idempotent op Message-ID of contenthash verwerkt. - **PR-017** — Nieuwe kandidaatbronnen kunnen worden ontdekt, maar gaan pas na policychecks naar trial/active. - **PR-018** — Een bron met herhaald falen wordt gedegradeerd of in quarantaine geplaatst zonder andere bronnen te stoppen. ### Extractie en data - **PR-020** — JSON-LD `JobPosting` is de voorkeursparser voor individuele vacaturepagina's. - **PR-021** — HTML, RSS/Atom en e-mail hebben deterministische fallbackadapters. - **PR-022** — Iedere parser levert een gemeenschappelijk extractiecontract en confidence. - **PR-023** — Externe HTML wordt gesanitized vóór opslag/rendering. - **PR-024** — Canonieke velden omvatten titel, werkgever, URL, locatie, tekst, contract, werkvorm, data, skills en bronbewijs. - **PR-025** — Wijzigingen aan een bestaande vacature bewaren een versie/snapshot. - **PR-026** — Ruwe documenten hebben een korte instelbare retentie en kunnen worden gequarantained. - **PR-027** — Veldherkomst is zichtbaar voor audit en debugging. ### Deduplicatie - **PR-030** — Exacte external ID, canonieke URL en canonieke sleutel hebben voorrang. - **PR-031** — Fuzzy matching gebruikt titel, werkgever, locatie en inhoud met conservatieve drempel. - **PR-032** — De directe werkgeversbron krijgt waar mogelijk canonieke voorkeur boven recruiter/platformalias. - **PR-033** — Deduplicatie is herhaalbaar en creëert geen extra canonieke vacature bij dezelfde input. ### Matching en ranking - **PR-040** — Harde regels worden vóór scoring toegepast en zijn uitlegbaar. - **PR-041** — Scorecomponenten omvatten inhoud, skills, locatie, voorwaarden, werkgever en voorkeuren. Ervaringsduur en senioriteitslabels blijven uitsluitend informatieve context en beïnvloeden score, aanbeveling of uitsluiting niet. - **PR-042** — Onbekende data verlaagt confidence en wordt niet automatisch als negatief feit behandeld. - **PR-043** — Iedere score bewaart componenten, positives, concerns, uitsluitingen en evidence. - **PR-044** — Profielversie en model-/promptversie worden aan een score gekoppeld. - **PR-045** — AI is optioneel, temperatuurarm/gestructureerd en mag alleen aanvullende features/samenvatting leveren. - **PR-046** — Prompt injection in vacaturetekst mag geen tool- of beleidsactie veroorzaken. ### Gebruik en opvolging - **PR-050** — Het dashboard toont een kleine lijst van de beste actuele niet-uitgesloten vacatures. - **PR-051** — De detailpagina toont score, redenen, bronaliassen, provenance en vacaturestatus. - **PR-052** — De gebruiker kan interessant, bewaren, verbergen en gesolliciteerd registreren. - **PR-053** — Gesolliciteerd maakt of actualiseert een sollicitatiedossier met snapshot en opvolgdatum. - **PR-054** — Een dagelijkse digest bevat sterke/mogelijke matches en verzendt idempotent via outbox. - **PR-055** — Verlopen, onzekere en verwijderde vacatures worden automatisch gemarkeerd. - **PR-056** — Geen enkele gebruikersactie verstuurt automatisch een sollicitatie naar een werkgever. ### Beheer - **PR-060** — Liveness/readiness endpoints zijn beschikbaar. - **PR-061** — Bronruns bewaren aantallen, HTTP-status en foutcategorie. - **PR-062** — Back-up en restore zijn scriptbaar en gedocumenteerd. - **PR-063** — De app kan volledig lokaal zonder externe AI draaien. - **PR-064** — Configuratie komt uit environmentvariables; secrets staan niet in de repository. ## 6. Niet-functionele requirements - **NFR-001 Beveiliging** — Fail-closed voor bronbeleid en URL-validatie. - **NFR-002 Privacy** — Dataminimalisatie, korte ruwe retentie en eenvoudige verwijderbaarheid. - **NFR-003 Betrouwbaarheid** — Imports en meldingen zijn idempotent; fouten blijven per bron/taak geïsoleerd. - **NFR-004 Uitlegbaarheid** — Iedere zichtbare beslissing heeft bewijs en een onderscheid tussen feit, inferentie en onbekend. - **NFR-005 Onderhoudbaarheid** — Modulaire monoliet, servicescheiding, versieerbare adapters en fixtures. - **NFR-006 Testbaarheid** — Geen live internet nodig voor de standaardtests; minimaal 70% branch-aware dekking. - **NFR-007 Performance** — Dashboard p95 onder 1 seconde bij 25.000 vacatures op aanbevolen hardware; bronwerk asynchroon. - **NFR-008 Toegankelijkheid** — Toetsenbordbruikbaar, semantische HTML, zichtbare focus, voldoende contrast en reduced-motionrespect. - **NFR-009 Portabiliteit** — Lokale Pythonmodus en containerdeployment op x86_64; geen cloudvendorlock-in. - **NFR-010 Observability** — Gestructureerde logs, healthstatus, bronmetrics en herstelbare foutcontext zonder secrets. ## 7. Productdefaults - taal: `nl-BE`; - tijdzone: `Europe/Brussels`; - dagelijkse digest: 07:30 lokale tijd; - ruwe-documentretentie: 7 dagen; - standaard maximumafstand: 45 km; - aanbevelingsdrempel: 65; - topmatchdrempel: 90; - onbekende bronpolicy: `review`; - AI: uit; - browserautomatisering: uit; - automatisch solliciteren: niet beschikbaar. ## 8. Productmetrics Te meten zonder tracking naar derden: - nieuwe canonieke vacatures per bron/dag; - duplicaatratio; - parserconfidence en velddichtheid; - aandeel vacatures per recommendation; - hide/interessant/sollicitatiefeedback per scoreband; - tijd van publicatie/first-seen tot digest; - bronfoutpercentage en herstelduur; - gemiste vacatures in een handmatige benchmarksteekproef; - false-positive harde uitsluitingen via gebruikersundo.