@@ -0,0 +1,159 @@
|
||||
# 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
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
```mermaid
|
||||
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`.
|
||||
Reference in New Issue
Block a user