Files
VacatureRadar/docs/architecture/SYSTEM_ARCHITECTURE.md
T
Jens b8091e59bd
deploy / deploy (push) Canceled after 0s
Initial deploy setup
2026-07-21 14:00:00 +02:00

5.1 KiB

Systeemarchitectuur

1. Architectuurstijl

VacatureRadar gebruikt een modulaire Django-monoliet. De domeinen delen één relationele database maar hebben duidelijke model-, service-, task- en UI-grenzen. Dit houdt deployment en beheer eenvoudig op Unraid, terwijl de kernlogica testbaar en later splitsbaar blijft.

2. Context

flowchart LR
  U[Gebruiker] -->|browser| W[VacatureRadar web]
  M[Vacaturemailbox] -->|IMAP| C[Collectielaag]
  E[Publieke werkgevers- en ATS-pagina's] -->|HTTP(S)| C
  C --> P[Extractie en normalisatie]
  P --> D[(PostgreSQL)]
  D --> S[Scoring en dedupe]
  S --> W
  S --> N[Digest/outbox]
  N -->|SMTP| U
  O[Optionele Ollama] <--> S

3. Containerarchitectuur

flowchart TB
  RP[Reverse proxy / LAN] --> WEB[web: Gunicorn + Django]
  WEB --> PG[(PostgreSQL)]
  WEB --> REDIS[(Redis)]
  WORKER[Celery worker] --> PG
  WORKER --> REDIS
  WORKER --> NET[Goedgekeurde publieke bronnen]
  BEAT[Celery beat] --> REDIS
  OLLAMA[Ollama optioneel] <--> WORKER
  MAIL[IMAP/SMTP optioneel] <--> WORKER

Containerrollen:

  • web — authenticatie, dashboard, detailpagina's, profiel- en beheerflows;
  • worker — bronfetches, parsing, scoring, lifecycle, mailbox en verzending;
  • scheduler — periodieke planning, geen bedrijfslogica;
  • postgres — canonieke data, historie en outbox;
  • redis — broker/resultbackend, geen bron van waarheid;
  • ollama — optioneel lokaal model, niet nodig voor kern.

4. Domeinmodules

apps/core

  • liveness/readiness;
  • dashboardaggregatie;
  • systeemstatus;
  • securityheaders en navigatiecontext.

apps/profiles

  • user-scoped zoekprofielen;
  • harde regels, soft preferences en scoregewichten;
  • profielversies en gecontroleerde feedbackdelta's.

apps/sources

  • bronregister en policy/status;
  • veilige fetcher;
  • adapters en source discovery;
  • raw document, source run en e-mailrecord;
  • Celery-orkestratie.

apps/jobs

  • canonieke vacature- en werkgevermodellen;
  • normalisatie, features, dedupe en provenance;
  • scoreberekening en scorehistorie;
  • feedback, lifecycle en sollicitatiedossier.

apps/notifications

  • dagelijkse payloadselectie;
  • idempotente outbox;
  • rendering en SMTP-verzending.

5. Laagregels

views/templates -> application services -> domain models / adapter interfaces
Celery tasks     -> application services -> domain models / adapter interfaces
adapters         -> pure extraction DTOs (geen ORM writes)
fetcher          -> policy + URL security (geen parserlogica)
AI service       -> gestructureerde optionele features (geen beslissingsbevoegdheid)

Verboden afhankelijkheden:

  • template/view die externe websites fetcht;
  • adapter die direct JobPosting schrijft;
  • AI die Feedback, Application, Source.policy of hard rules wijzigt;
  • task met verborgen businessregels die niet in een service testbaar zijn;
  • model save-hook die netwerkverkeer uitvoert.

6. Verwerkingsflow

sequenceDiagram
  participant B as Beat
  participant T as Source task
  participant F as Safe fetcher
  participant A as Adapter registry
  participant P as Pipeline
  participant DB as PostgreSQL
  participant S as Scoring

  B->>T: schedule due source
  T->>DB: create SourceRun
  T->>F: fetch approved URL
  F->>F: policy + DNS/IP + redirect checks
  F-->>T: bounded document / 304 / error
  T->>DB: save RawDocument
  T->>A: extract(document)
  A-->>P: ExtractionResult
  P->>P: normalize + sanitize + features
  P->>DB: find exact/fuzzy existing job
  P->>DB: upsert job, alias, evidence, version
  P->>S: score for active profiles
  S->>DB: append ScoreRun
  T->>DB: finish SourceRun + schedule next

7. Consistentie en transacties

  • process_raw_document en persist_draft zijn transactioneel;
  • unieke sleutels beschermen races op canonieke vacature, e-mail en outbox;
  • scorehistorie is append-only;
  • raw document en source run vormen debugcontext;
  • een mislukte individuele e-maillink wordt in het e-mailrecord vastgelegd zonder andere links te verliezen;
  • externe calls gebeuren buiten lange database-locks waar mogelijk.

8. Schaalpad

De eerste schaalgrens ligt niet bij HTTP-requestvolume maar bij het aantal bronjobs. Tot ongeveer tienduizenden vacatures en honderden bronnen volstaat de monoliet. Optimalisaties vóór opsplitsing:

  1. indexes en querysetprofiling;
  2. chunked scoring;
  3. task queues per prioriteit;
  4. per-domain rate limit en distributed lock;
  5. materialized/latest scoreselectie;
  6. raw-bodycompressie/objectstorage.

Pas na aantoonbare bottleneck kan collection worker als aparte service worden afgesplitst. De adapter- en DTO-grenzen maken dat mogelijk zonder nu operationele complexiteit toe te voegen.

9. Deploymenttrust boundaries

  • browser ↔ web: authenticated session + CSRF;
  • web/worker ↔ database/Redis: intern containernetwerk;
  • worker ↔ internet: alleen goedgekeurde URL's via safe fetcher;
  • worker ↔ IMAP/SMTP/Ollama: expliciete environmentconfiguratie;
  • reverse proxy ↔ internet: TLS, host filtering en toegangsbeleid buiten de app.

Zie SECURITY_ARCHITECTURE.md en docs/quality/THREAT_MODEL.md.