@@ -14,7 +14,8 @@ Alle betekenisvolle wijzigingen worden hier bijgehouden. Het project volgt voorl
|
||||
### Gewijzigd
|
||||
|
||||
- De repository-README volgt nu de gebruikersreis van doel en dagelijkse workflow naar quickstart, configuratie, veiligheidsgrenzen, beheer en pas daarna architectuur en agentoverdracht.
|
||||
- Vier actuele, compacte productbeelden documenteren dagoverzicht, vacatureverkenner, automatisering en het mobiele zoekprofiel in dark/light zonder externe runtime-assets.
|
||||
- Negen actuele, compacte productbeelden vertellen nu de volledige gebruikersreis: dagoverzicht, vacatureverkenner, beslisanalyse, Skillsradar, werkgevers, sollicitaties, bronnen, automatisering en mobiel zoekprofiel.
|
||||
- De README-galerij gebruikt taakgerichte captions, klikbare beelden, een consistente 1920×1080-desktopviewport en een gebalanceerde dark/light-compositie.
|
||||
- Het VacatureRadar-productlogo is hertekend als transparante vier-elementenradar zonder donkere tegel, rand of schaduw; login en sidebar gebruiken hetzelfde cleaner beeldmerk.
|
||||
- De sidebarfooter combineert radarstatus en een transparante, themabewuste ITWorx-credit; de dubbele demo-/accountidentiteit is verwijderd en blijft uitsluitend via het topbarmenu bereikbaar.
|
||||
- Widescreencontent schaalt nu gecontroleerd naar 2.200 px en op 4K naar 2.480 px, terwijl dashboardverhoudingen, korte viewports en mobiele layouts begrensd blijven.
|
||||
@@ -32,6 +33,7 @@ Alle betekenisvolle wijzigingen worden hier bijgehouden. Het project volgt voorl
|
||||
|
||||
### Hersteld
|
||||
|
||||
- De productieconfiguratiehelper voldoet opnieuw aan Ruff en de `.env`-bestandmodustest houdt rekening met Windows, waar POSIX-modusbits niet afdwingbaar zijn.
|
||||
- Publieke Nginx-hostnamen veroorzaken niet langer `DisallowedHost` wanneer `PUBLIC_BASE_URL` correct staat.
|
||||
- HTTPS-deployment gebruikt de externe poort in plaats van de interne applicatiepoort voor CSRF en publieke URL’s.
|
||||
- Interne healthchecks blijven bereikbaar bij `SECURE_SSL_REDIRECT=1`; productie-rate-limiting gebruikt een gedeelde Redis-cache.
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# VacatureRadar
|
||||
<p align="center">
|
||||
<img src="static/img/vacatureradar-logo.svg" width="88" alt="VacatureRadar-logo">
|
||||
</p>
|
||||
|
||||
**Van vacature-overload naar een kleine, uitlegbare selectie die bij jou past.**
|
||||
<h1 align="center">VacatureRadar</h1>
|
||||
|
||||
<p align="center"><strong>Van vacature-overload naar een kleine, uitlegbare selectie die bij jou past.</strong></p>
|
||||
|
||||
VacatureRadar is een persoonlijke vacature-assistent voor België. De applicatie volgt toegestane werkgeversbronnen, ATS-pagina’s, feeds en vacaturemails, verwijdert dubbels en irrelevante resultaten en rangschikt de overblijvende kansen tegen jouw zoekprofiel. Jij behoudt altijd de controle: VacatureRadar helpt zoeken en opvolgen, maar solliciteert nooit automatisch.
|
||||
|
||||
@@ -36,18 +40,65 @@ VacatureRadar is bedoeld voor één persoon of een eigen, afgeschermde installat
|
||||
| Bronnenbeheer | Veilige bronconfiguratie, gezondheid, handmatige import en mailboxkoppelingen |
|
||||
| Automatisering | Eerlijke 24-uursmetingen; niet-gemeten informatie blijft expliciet onbekend |
|
||||
|
||||
## Productbeelden
|
||||
## Bekijk de volledige productflow
|
||||
|
||||
De beelden hieronder komen uit de lokale demo-omgeving. De getoonde cijfers zijn omgevingsdata, geen marketingclaims.
|
||||
De beelden komen uit de lokale demo-omgeving. De getoonde cijfers zijn omgevingsdata, geen marketingclaims. Klik op een beeld voor de volledige resolutie.
|
||||
|
||||
| Vacatureverkenner | Automatisering |
|
||||
|---|---|
|
||||
|  |  |
|
||||
### 1. Vind de relevante kansen
|
||||
|
||||
De verkenner brengt zoeken, filters, gerangschikte resultaten en de belangrijkste matchcontext samen. Zo hoef je niet tussen lijst- en detailpagina’s te blijven wisselen.
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/screenshots/readme/profile-mobile-light.png" width="390" alt="Mobiel zoekprofiel van VacatureRadar">
|
||||
<a href="docs/screenshots/readme/matches-dark.png"><img src="docs/screenshots/readme/matches-dark.png" alt="Vacatureverkenner met gerangschikte matches en directe intelligence"></a>
|
||||
</p>
|
||||
|
||||
### 2. Begrijp waarom een vacature past
|
||||
|
||||
Een analyse maakt score, datakwaliteit, beslissignalen, aandachtspunten en broninformatie afzonderlijk zichtbaar. Ervaring en senioriteitslabels worden als context getoond, niet als verborgen scorefactor.
|
||||
|
||||
<p align="center">
|
||||
<a href="docs/screenshots/readme/job-analysis-dark.png"><img src="docs/screenshots/readme/job-analysis-dark.png" alt="Uitlegbare vacatureanalyse met scorecomponenten en besliscontext"></a>
|
||||
</p>
|
||||
|
||||
### 3. Bouw markt- en werkgeversinzicht op
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%"><strong>Skillsradar</strong><br><sub>Vergelijk aantoonbare marktvraag met je profiel, zonder ontbrekende skills als afwijzingsregel te behandelen.</sub></td>
|
||||
<td width="50%"><strong>Werkgeversradar</strong><br><sub>Bekijk werkgevers, actieve IT-vacatures, bronnen en eerdere dossiers in één genormaliseerd overzicht.</sub></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="docs/screenshots/readme/skills-light.png"><img src="docs/screenshots/readme/skills-light.png" alt="Skillsradar met profieldekking en actuele marktvraag"></a></td>
|
||||
<td><a href="docs/screenshots/readme/employers-light.png"><img src="docs/screenshots/readme/employers-light.png" alt="Werkgeversradar met vacature- en broninformatie"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### 4. Volg trajecten op en houd bronnen gezond
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%"><strong>Sollicitatiepipeline</strong><br><sub>Bewaar status, deadlines, notities en tijdlijn per dossier; de uiteindelijke sollicitatie blijft altijd handmatig.</sub></td>
|
||||
<td width="50%"><strong>Bronnenbeheer</strong><br><sub>Zie policyreview, laatste scans, volgende runs en brongezondheid zonder technische logs te moeten doorzoeken.</sub></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="docs/screenshots/readme/applications-dark.png"><img src="docs/screenshots/readme/applications-dark.png" alt="Sollicitatiepipeline met persoonlijke dossiers"></a></td>
|
||||
<td><a href="docs/screenshots/readme/sources-light.png"><img src="docs/screenshots/readme/sources-light.png" alt="Bronnenbeheer met policy- en gezondheidsstatus"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### 5. Controleer de radar — ook mobiel
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="72%"><strong>Automation center</strong><br><sub>Volg de echte verwerkingspipeline, bronruns en systeemstatus. Niet-gemeten runtime-informatie blijft expliciet onbekend.</sub></td>
|
||||
<td width="28%"><strong>Mobiel zoekprofiel</strong><br><sub>Controleer je persoonlijke radar en navigeer door de kernflow vanaf een smal scherm.</sub></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="docs/screenshots/readme/automation-dark.png"><img src="docs/screenshots/readme/automation-dark.png" alt="Automation center met pipeline en bronruns"></a></td>
|
||||
<td align="center"><a href="docs/screenshots/readme/profile-mobile-light.png"><img src="docs/screenshots/readme/profile-mobile-light.png" width="240" alt="Mobiel zoekprofiel van VacatureRadar"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Snel starten
|
||||
|
||||
### Optie 1 — lokale demo
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
schema_version: 1
|
||||
project: VacatureRadar
|
||||
updated_at: '2026-07-27'
|
||||
updated_at: '2026-07-28'
|
||||
execution_policy:
|
||||
order: file-order, then first ready task whose dependencies are done
|
||||
no_product_questions: true
|
||||
@@ -2215,13 +2215,14 @@ tasks:
|
||||
summary: Maak de bestaande persoonlijke installatie veilig en reproduceerbaar bereikbaar achter Nginx Proxy Manager,
|
||||
herstel publieke host- en CSRF-configuratie en voorkom dat een gedeeld demoaccount persistente data wijzigt.
|
||||
acceptance_criteria:
|
||||
- Eén publieke HTTPS-URL configureert hostvalidatie, CSRF, secure cookies, SSL-detectie en redirect zonder de interne
|
||||
containerpoort in de externe origin op te nemen.
|
||||
- Eén publieke HTTPS-URL configureert hostvalidatie, CSRF, secure cookies, SSL-detectie en redirect zonder de
|
||||
interne containerpoort in de externe origin op te nemen.
|
||||
- Productie start fail-fast bij debugmodusgerelateerde onveiligheid, een zwakke secret, onveilige cookies, ontbrekende
|
||||
HTTPS-origin of een schrijfbare publieke demo.
|
||||
- Login- en importlimieten gebruiken in productie een gedeelde cache; forwarded client-IP’s worden alleen vanaf
|
||||
expliciet vertrouwde proxy-CIDR’s geaccepteerd.
|
||||
- Het gastaccount is server-side alleen-lezen, heeft een begrensde sessie, kan afmelden en toont de beperking zichtbaar.
|
||||
- Het gastaccount is server-side alleen-lezen, heeft een begrensde sessie, kan afmelden en toont de beperking
|
||||
zichtbaar.
|
||||
- Unraid-envpad, Nginx Proxy Manager, healthchecks, noindex, heruitrol en terugdraaien zijn exact gedocumenteerd.
|
||||
verification:
|
||||
- PYTHONPATH=/mnt/data/vr_windows_site/site-packages pytest -q
|
||||
@@ -2244,3 +2245,41 @@ tasks:
|
||||
note: Publieke host/CSRF/HTTPS-configuratie, gedeelde Redis-rate-limiting, proxy-IPvertrouwen, cache-readiness,
|
||||
noindex en read-only gastdemo geïmplementeerd. 295 tests groen met 2 correcte Playwrightskips; Django check,
|
||||
migratiecheck, repositoryvalidatie, YAML-, syntax- en packagechecks groen. Live servervalidatie blijft extern.
|
||||
- id: VR-226
|
||||
title: Verdiep de user-first README met een volledige productgalerij
|
||||
status: done
|
||||
priority: P1
|
||||
requirement_ids:
|
||||
- NFR-006
|
||||
- NFR-008
|
||||
- NFR-009
|
||||
depends_on:
|
||||
- VR-225
|
||||
summary: Maak de productpresentatie overtuigender met een logisch opgebouwde, actuele galerij die de volledige
|
||||
gebruikersreis toont zonder de README traag, repetitief of marketingmatig te maken.
|
||||
acceptance_criteria:
|
||||
- De README bevat minstens acht actuele beelden die dashboard, zoeken/analyse, skills, sollicitatieopvolging,
|
||||
profiel, bronnen, automatisering en mobiel gebruik als één samenhangende productreis tonen.
|
||||
- Desktopbeelden gebruiken een consistente professionele viewport en rustige uitsnede; dark/light en mobiel zijn
|
||||
doelbewust verdeeld, zonder overgangsoverlays, overflow, consolefouten, secrets of persoonlijke gegevens.
|
||||
- De galerij heeft korte taakgerichte captions, een scanbare compositie en compacte lokale assets; duplicatieve
|
||||
beelden of losse decoratieve screenshots worden verwijderd of vervangen.
|
||||
- De eerder aangetroffen VR-225-baselinefouten in lint en platformafhankelijke bestandsmoduscontrole zijn hersteld;
|
||||
repositoryvalidatie en de volledige kwaliteitsgate slagen.
|
||||
verification:
|
||||
- Browsercontrole van alle vastgelegde routes op desktop en mobiel in dark/light
|
||||
- uv run pytest tests/unit/test_public_configuration.py
|
||||
- python scripts/validate_repository.py
|
||||
- ./scripts/codex_verify.sh
|
||||
primary_paths:
|
||||
- README.md
|
||||
- docs/screenshots/readme/
|
||||
- scripts/configure_public_url.py
|
||||
- tests/unit/test_public_configuration.py
|
||||
- docs/quality/TRACEABILITY_MATRIX.md
|
||||
- docs/ai/PROJECT_STATE.md
|
||||
result:
|
||||
completed_at: '2026-07-28'
|
||||
note: README verdiept tot een klikbare user-first productreis met negen actuele beelden op 1920x1080 en 390x844
|
||||
in dark/light; alle routes zonder overflow of consolewaarschuwingen. VR-225-lint en Windows-modusassertie
|
||||
hersteld; 296 tests groen, 2 skips en 83,44% dekking.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Projectstatus
|
||||
|
||||
- Laatst bijgewerkt: 2026-07-27
|
||||
- Laatst bijgewerkt: 2026-07-28
|
||||
- Repositoryversie: 0.3.12 productie- en reverse-proxyhardening
|
||||
- Uitvoeringsmodus: autonome backlog
|
||||
- Eerste uitvoerbare taak: controleer met `python scripts/backlog.py next`
|
||||
@@ -46,6 +46,13 @@ Het volledige scherm- en afwijkingsrapport staat in `docs/design/STITCH_INTEGRAT
|
||||
|
||||
## Laatste onderhoudsaudit
|
||||
|
||||
VR-226 op 2026-07-28:
|
||||
|
||||
- README-presentatie verdiept van vier losse beelden naar een klikbare productreis met negen actuele screenshots: overzicht, zoeken, analyse, skills, werkgevers, sollicitaties, bronnen, automatisering en mobiel profiel;
|
||||
- alle desktopbeelden opnieuw vastgelegd op 1920×1080, doelbewust verdeeld over dark/light en gecombineerd met 390×844 mobiel; geen overgangsoverlays, horizontale overflow, secrets of consolewaarschuwingen;
|
||||
- de onrustige mobiele dashboardcapture is afgekeurd en verwijderd; de volledige galerij blijft lokaal en samen circa 1,1 MB;
|
||||
- vier aangetroffen VR-225-lintproblemen en de ongeldige POSIX-modusassertie op Windows zijn hersteld; volledige gate groen met 296 geslaagde tests, 2 optionele skips en 83,44% branch-aware dekking. Volgende uitvoerbare taak: geen.
|
||||
|
||||
VR-224 op 2026-07-27:
|
||||
|
||||
- README volledig herordend rond doelgroep, dagelijkse workflow, concrete productwaarde, veilige quickstart en eerste configuratie; architectuur, beheer en Codex-overdracht volgen pas daarna;
|
||||
|
||||
@@ -61,9 +61,9 @@ Legenda: **I** = geïmplementeerd en getest in de huidige MVP; **P** = gedeeltel
|
||||
| NFR-003 | I/P | replay-, mail- en outboxtests; per-bronfouten | VR-103/112 |
|
||||
| NFR-004 | I | ScoreRun, provenance, skillvraag met expliciet veld-/tekstonderscheid en UI-copy | VR-109/208 uitgebreid evidence |
|
||||
| NFR-005 | I | domeinapps/services/adapters/ADRs | continue review |
|
||||
| NFR-006 | I | offline pytest + coveragegate | VR-114 verbreedt e2e |
|
||||
| NFR-006 | I | offline pytest + coveragegate, inclusief platformbewuste productieconfiguratietests | VR-114 e2e; `tests/unit/test_public_configuration.py`; VR-225/226 |
|
||||
| NFR-007 | P | `scripts/benchmark.py`, `tests/benchmark/test_benchmark.py` | VR-116 |
|
||||
| NFR-008 | I | volledige negen-schermen-Stitch-cockpit, acht viewports, dark/light, toetsenborddrawer, premium visuele hiërarchie, zelfstandig VacatureRadar-productmerk, lokale ITWorx-ontwikkelaarscredit, toegankelijke interactieve radarillustratie en actuele user-first productdocumentatie | `tests/e2e/test_vr114_browser_and_accessibility.py`, `tests/integration/test_intelligence_views.py`, `tests/integration/test_views.py`, `artifacts/visual-validation/`, `docs/screenshots/readme/`, VR-209–224 |
|
||||
| NFR-008 | I | volledige negen-schermen-Stitch-cockpit, acht viewports, dark/light, toetsenborddrawer, premium visuele hiërarchie, zelfstandig VacatureRadar-productmerk, lokale ITWorx-ontwikkelaarscredit, toegankelijke interactieve radarillustratie en actuele user-first productdocumentatie | `tests/e2e/test_vr114_browser_and_accessibility.py`, `tests/integration/test_intelligence_views.py`, `tests/integration/test_views.py`, `artifacts/visual-validation/`, negen beelden in `docs/screenshots/readme/`, VR-209–224/226 |
|
||||
| NFR-009 | I | lokale SQLite, configureerbare eigenaarbranding, Docker/Unraidconfig, publieke URL-helper, Nginx Proxy Manager-runbook, gevalideerde SSH-deployalias, release-smoke en restore | `tests/unit/test_deployment_configuration.py`, `tests/unit/test_public_configuration.py`, VR-117, VR-217/218/225 afgerond |
|
||||
| NFR-010 | I | `apps/sources/services/health.py`, `apps/sources/tasks.py`, `apps/core/views.py`, `config/settings.py` | `tests/integration/test_source_health.py` | VR-112 observability |
|
||||
|
||||
@@ -113,3 +113,4 @@ Iedere backlogtaak die een requirement wijzigt, werkt in dezelfde commit deze ma
|
||||
- VR-224 maakt de repository-ingang user-first: de README volgt de dagelijkse productflow, bevat gecontroleerde lokale quickstarts en gebruikt vier actuele dark/light- en desktop/mobielscreenshots zonder secrets of externe assets.
|
||||
|
||||
- VR-225 hardent de publieke installatie met `PUBLIC_BASE_URL`, exacte host/CSRF-afleiding, veilige proxy-HTTPS-detectie, vertrouwde client-IPchains, gedeelde Redis-rate-limiting, cache-readiness en een server-side alleen-lezen gastdemo. Bewijs staat in de productie-audit, Nginx-runbook en de settings-, network-, health-, auth- en deploymenttests.
|
||||
- VR-226 verdiept de README tot een visuele productreis met negen actuele beelden op consistente desktop- en mobiele viewports. Dezelfde taak herstelt de VR-225-lintbaseline en maakt de POSIX-bestandsmodusassertie terecht platformafhankelijk.
|
||||
|
||||
|
After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 121 KiB |
@@ -16,11 +16,17 @@ def normalize_public_url(value: str) -> tuple[str, str]:
|
||||
raw = value.strip().rstrip("/")
|
||||
parsed = urlparse(raw)
|
||||
if parsed.scheme not in {"http", "https"} or not parsed.hostname:
|
||||
raise ConfigurationError("Gebruik een volledige http(s)-URL, bijvoorbeeld https://jobs.example.be")
|
||||
raise ConfigurationError(
|
||||
"Gebruik een volledige http(s)-URL, bijvoorbeeld https://jobs.example.be"
|
||||
)
|
||||
if parsed.username or parsed.password or parsed.query or parsed.fragment:
|
||||
raise ConfigurationError("De publieke URL mag geen credentials, query of fragment bevatten.")
|
||||
raise ConfigurationError(
|
||||
"De publieke URL mag geen credentials, query of fragment bevatten."
|
||||
)
|
||||
if parsed.path not in {"", "/"}:
|
||||
raise ConfigurationError("De applicatie moet op de root van het domein gepubliceerd worden.")
|
||||
raise ConfigurationError(
|
||||
"De applicatie moet op de root van het domein gepubliceerd worden."
|
||||
)
|
||||
try:
|
||||
port = parsed.port
|
||||
except ValueError as exc:
|
||||
|
||||
@@ -43,6 +43,7 @@ def test_public_url_rejects_unsafe_or_unsupported_values(raw):
|
||||
with pytest.raises((ImproperlyConfigured, ConfigurationError)):
|
||||
normalize_public_base_url(raw)
|
||||
|
||||
|
||||
def test_configure_public_url_updates_only_public_security_settings(tmp_path: Path):
|
||||
env_file = tmp_path / ".env"
|
||||
env_file.write_text(
|
||||
@@ -66,20 +67,22 @@ def test_configure_public_url_updates_only_public_security_settings(tmp_path: Pa
|
||||
assert "DJANGO_DEBUG=0" in content
|
||||
assert "vacatureradar.itworx.tech" in content
|
||||
assert (
|
||||
"DJANGO_CSRF_TRUSTED_ORIGINS="
|
||||
"http://192.168.10.150:1226,https://vacatureradar.itworx.tech"
|
||||
"DJANGO_CSRF_TRUSTED_ORIGINS=http://192.168.10.150:1226,https://vacatureradar.itworx.tech"
|
||||
) in content
|
||||
assert "CACHE_URL=redis://127.0.0.1:6379/1" in content
|
||||
assert "TRUSTED_PROXY_CIDRS=172.18.0.0/16" in content
|
||||
assert "DJANGO_SECRET_KEY=keep-this-secret" in content
|
||||
assert "POSTGRES_PASSWORD=keep-this-password" in content
|
||||
if os.name != "nt":
|
||||
assert env_file.stat().st_mode & 0o777 == 0o600
|
||||
assert "DJANGO_SECRET_KEY" not in changed
|
||||
|
||||
|
||||
def test_configure_public_url_rejects_plain_http(tmp_path: Path):
|
||||
with pytest.raises(ConfigurationError, match="HTTPS"):
|
||||
configure_env(tmp_path / ".env", "http://vacatureradar.example.be")
|
||||
|
||||
|
||||
def test_public_base_url_populates_django_host_and_csrf_settings():
|
||||
environment = os.environ.copy()
|
||||
environment.update(
|
||||
@@ -91,7 +94,7 @@ def test_public_base_url_populates_django_host_and_csrf_settings():
|
||||
"SECURE_HSTS_SECONDS": "300",
|
||||
}
|
||||
)
|
||||
result = subprocess.run(
|
||||
result = subprocess.run( # noqa: S603 - fixed interpreter and static assertion program
|
||||
[
|
||||
sys.executable,
|
||||
"-c",
|
||||
@@ -111,9 +114,10 @@ def test_public_base_url_populates_django_host_and_csrf_settings():
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
) # noqa: S603 - fixed interpreter and static assertion program
|
||||
)
|
||||
assert result.returncode == 0, result.stderr
|
||||
|
||||
|
||||
def test_configure_public_url_is_idempotent(tmp_path: Path):
|
||||
env_file = tmp_path / ".env"
|
||||
env_file.write_text("DJANGO_ALLOWED_HOSTS=localhost\n", encoding="utf-8")
|
||||
|
||||