feat: integrate ITWorx branding and refine cockpit UX
deploy / deploy (push) Canceled after 0s

This commit is contained in:
Jens
2026-07-26 04:13:42 +02:00
parent eea74f97ef
commit 2a32e9fec9
27 changed files with 298 additions and 54 deletions
+1
View File
@@ -4,6 +4,7 @@ DJANGO_DEBUG=1
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
DJANGO_CSRF_TRUSTED_ORIGINS=http://localhost:1226
DJANGO_TIME_ZONE=Europe/Brussels
VACATURERADAR_OWNER_NAME=Jens
# Gebruik DATABASE_URL niet voor SQLite. Laat leeg voor lokale sqlite-ontwikkeling.
POSTGRES_DB=vacatureradar
+5
View File
@@ -6,6 +6,10 @@ Alle betekenisvolle wijzigingen worden hier bijgehouden. Het project volgt voorl
### Gewijzigd
- De ultrawide cockpit gebruikt één links verankerd grid tot 2800 px; headers, filters, pipeline, KPI's en detailpanelen delen daardoor op brede schermen hetzelfde startpunt zonder toevallige lege linkerkolom.
- De officiële ITWorx.tech-wordmark en het cloud-check-symbool uit het door de eigenaar aangeleverde asset pack vormen nu de merklaag van sidebar, bovenbalk, login, favicon en Dockermanicoon; VacatureRadar blijft zichtbaar als productnaam.
- VacatureRadar gebruikt nu één scherper radarbeeldmerk voor favicon, login en applicatieshell; de persoonlijke eigenaar is via `VACATURERADAR_OWNER_NAME` configureerbaar.
- De bovenbalk geeft naast zoeken ook eigenaar en actuele werkcontext aan; navigatie-, focus- en hoverstates zijn verfijnd zonder de compacte mobiele cockpit te verzwaren.
- Het zoekprofiel bevat een lokale interactieve radarillustratie met pointerparallax, een rustige scansweep, light/dark-kleuren en een statische reduced-motionvariant; de illustratie is decoratief en introduceert geen fictieve data.
- De Unraid-heruitrol gebruikt een gevalideerde SSH-hostalias met afzonderlijke deploysleutel en voert synchronisatie, build, healthwait en readiness-smoke als één reproduceerbaar commando uit.
- De cockpit heeft een premium “calm intelligence”-laag met zachtere oppervlaktescheidingen, selectief cyan, humane navigatietypografie en een duidelijkere componenthiërarchie in donker en licht thema.
@@ -14,6 +18,7 @@ Alle betekenisvolle wijzigingen worden hier bijgehouden. Het project volgt voorl
### Hersteld
- De Unraid-synchelper negeert verwijderde indexpaden bij een release vanuit een geldige dirty worktree; vervangen merkassets blokkeren de archiefopbouw daardoor niet meer.
- Rechtstreekse SSH naar het Unraid-IP koos lokaal de verkeerde gebruiker en identiteit; het gedocumenteerde aliasprofiel selecteert nu reproduceerbaar `root` met de afzonderlijke deploysleutel.
- Inloginteracties laden nu als lokale externe JavaScriptasset; de eigen Content Security Policy blokkeert wachtwoordweergave en submitfeedback niet langer.
- Het Unraid/Dockerman-containericoon gebruikt nu een lokale 256×256 PNG via de gepubliceerde webpoort in plaats van de fragiele SVG-favicon-URL.
+22 -1
View File
@@ -2,15 +2,36 @@ from __future__ import annotations
from typing import Any
from django.conf import settings
from django.http import HttpRequest
from apps.profiles.models import SearchProfile
def navigation_context(request: HttpRequest) -> dict[str, Any]:
match = request.resolver_match
route_key = (match.namespace, match.url_name) if match else (None, None)
page_contexts = {
("dashboard", "today"): "Dagoverzicht",
("dashboard", "system"): "Automatisering",
("jobs", "list"): "Vacatureverkenner",
("jobs", "detail"): "Vacatureanalyse",
("jobs", "applications"): "Sollicitatiepipeline",
("jobs", "application-edit"): "Sollicitatiedossier",
("jobs", "skill-insights"): "Skillsradar",
("jobs", "activity"): "Activiteit",
("jobs", "employers"): "Werkgevers",
("jobs", "employer-detail"): "Werkgeveranalyse",
("profiles", "list"): "Zoekprofiel",
("profiles", "edit"): "Radarconfiguratie",
("sources", "list"): "Bronbeheer",
}
context = {
"app_name": "VacatureRadar",
"app_version": "0.3.0",
"app_version": "0.3.3",
"app_brand_name": "ITWorx.tech",
"app_owner_name": settings.VACATURERADAR_OWNER_NAME,
"page_context_label": page_contexts.get(route_key, "Persoonlijke cockpit"),
}
if request.user.is_authenticated:
context["navigation_profile"] = (
+1
View File
@@ -64,6 +64,7 @@ DEBUG = env_bool("DJANGO_DEBUG", True)
ALLOWED_HOSTS = env_list("DJANGO_ALLOWED_HOSTS", "localhost,127.0.0.1,testserver")
CSRF_TRUSTED_ORIGINS = env_list("DJANGO_CSRF_TRUSTED_ORIGINS")
TIME_ZONE = os.getenv("DJANGO_TIME_ZONE", "Europe/Brussels")
VACATURERADAR_OWNER_NAME = os.getenv("VACATURERADAR_OWNER_NAME", "Jens").strip()[:40] or "Jens"
LANGUAGE_CODE = "nl-be"
USE_I18N = True
USE_TZ = True
+1 -1
View File
@@ -18,7 +18,7 @@ from apps.core.views import (
urlpatterns = [
path(
"favicon.ico",
RedirectView.as_view(url=static_url("favicon.svg"), permanent=True),
RedirectView.as_view(url=static_url("img/itworx-app-icon.png"), permanent=True),
name="favicon",
),
path("admin/", admin.site.urls),
+114
View File
@@ -1880,6 +1880,120 @@ tasks:
fail-fast deployhelper toegevoegd. Interactieve lokale SVG-radar met pointerparallax, dark/light en reduced-motionfallback
toegevoegd. Browsermatrix 390/1280 zonder overflow of consolefouten; 265 tests groen. Live image sha256:4d30e01e778777d5a2cde4339a9b2ad006edb25cae387293737420152d65069d
healthy en readiness/CSS/JS HTTP 200.
- id: VR-218
title: Personaliseer merkidentiteit en verfijn de globale UX
status: done
priority: P1
requirement_ids:
- NFR-004
- NFR-008
- NFR-009
depends_on:
- VR-217
summary: Vervang het generieke favicon door een herkenbaar radarsymbool, voeg configureerbare eigenaarssignatuur
toe en verfijn shell, oriëntatie, navigatie en micro-interacties tot een coherente persoonlijke premiumervaring.
acceptance_criteria:
- Favicon en hoofdlogo delen één scherp, lokaal en op 16 px herkenbaar radarsymbool met passende light/dark browsermetadata
en zonder externe assets.
- De shell en authenticatieschermen tonen VacatureRadar als product en een configureerbare eigenaarssignatuur
met veilige standaardwaarde Jens; deze branding wordt niet uit gebruikersdata of nepdata afgeleid.
- De topbar geeft compacte paginaoriëntatie, navigatie-/zoekinteracties hebben duidelijkere focus- en hoverstates
en mobiele bruikbaarheid blijft intact zonder extra bediening of JavaScriptafhankelijkheid.
- Browsercontrole op dashboard, verkenner, profiel en login bij 390 en 1280 px in donker en licht thema toont
geen overflow, consolefout of onduidelijke hiërarchie; live container en assets zijn healthy na deployment.
verification:
- uv run pytest tests/e2e/test_vr114_browser_and_accessibility.py tests/integration/test_auth_login.py tests/integration/test_views.py
- Browsermatrix 390x844 en 1280x800 in donker en licht thema
- Live favicon-, logo-, readiness- en containerhealth-smoke
- ./scripts/codex_verify.sh
primary_paths:
- apps/core/context_processors.py
- static/favicon.svg
- static/img/vacatureradar-logo.svg
- templates/base.html
- templates/registration
- static/css/premium.css
- static/css/auth.css
result:
completed_at: '2026-07-26'
note: Persoonlijke Jens-branding, vernieuwd radarbeeldmerk en favicon, contextuele bovenbalk en verfijnde navigatie/zoekfocus
zijn regressiegedekt, responsief in de browser gevalideerd en live uitgerold als healthy image sha256:5f25f00c9b7efb166587901ff39b02c56c98fb9946ddef0a4546a22f18dc0802.
- id: VR-219
title: Herstel ultrawide uitlijning en versterk persoonlijke merklock-up
status: done
priority: P1
requirement_ids:
- NFR-004
- NFR-008
depends_on:
- VR-218
summary: Breng de cockpit op brede schermen terug naar één voorspelbaar horizontaal grid en maak de persoonlijke
Jens-signatuur tot een herkenbaar onderdeel van de productbranding in plaats van losse metadata.
acceptance_criteria:
- Header, filters, hoofdpanelen en onderliggende secties delen op desktop en ultrawide hetzelfde startpunt en
dezelfde contentbreedte; er ontstaat geen grote toevallige lege linkerkolom.
- Verkenner en automatisering benutten 1920- en 3840-pixelbreedtes evenwichtig zonder uitgerekte leesregels, losgekoppelde
panelen of documentoverflow.
- Sidebar en bovenbalk tonen één consistente VacatureRadar-by-Jens-merklock-up; authenticatie en mobiele shell
behouden dezelfde eigenaarssignatuur zonder gebruikersnaam als merk te presenteren.
- Browsercontrole op 390, 1280, 1920 en 3840 px bevestigt consistente ankers, bruikbare paneelverhoudingen, schone
console en intacte toetsenbord-/mobiele flows.
verification:
- Browsermatrix dashboard, verkenner, automatisering en login op 390/1280/1920/3840 px
- uv run pytest tests/integration/test_auth_login.py tests/integration/test_views.py
- ./scripts/codex_verify.sh
primary_paths:
- templates/base.html
- static/css/layout.css
- static/css/premium.css
- static/css/responsive.css
result:
completed_at: '2026-07-26'
note: Ultrawide hoofdsecties delen één links verankerd 2800px-grid; explorer- en automationverhoudingen zijn
begrensd en Personal intelligence by Jens is de consistente lock-up. Browsermatrix 390/1280/1920/3840 schoon;
267 tests groen; live image sha256:86836f82cc543a7adb414e47b9667e9123bb9ceba10d629a53086273aaaae03f healthy
met readiness en asset-smokes.
- id: VR-220
title: Integreer de officiële ITWorx-merkidentiteit
status: done
priority: P1
requirement_ids:
- NFR-004
- NFR-008
- NFR-009
depends_on:
- VR-219
summary: Vervang de tijdelijke tekstuele Jens-branding door de door de eigenaar aangeleverde officiële ITWorx.tech-wordmark
en cloud-check-identiteit, met VacatureRadar herkenbaar als product binnen dat merk.
acceptance_criteria:
- Sidebar, login en herstelpagina's gebruiken de transparante officiële ITWorx.tech-wordmark uit het aangeleverde
asset pack; VacatureRadar blijft duidelijk als productnaam aanwezig.
- Browserfavicon en app-/Dockericoon gebruiken de officiële cloud-check-symboliek in een compacte transparante,
lokaal gehoste en voor klein formaat geoptimaliseerde variant.
- Merkassets hebben betekenisvolle alt-/toegankelijkheidslabels, laden zonder externe runtimebron en blijven scherp
en leesbaar in donker/licht thema en op mobiel.
- Browsercontrole op login, dashboard en verkenner bij 390, 1280 en 1920 px toont correcte assets, geen overflow
of consolefouten; de live container levert brandingassets en readiness met HTTP 200.
verification:
- Controleer afmetingen, transparantie en bestandsgrootte van de afgeleide merkassets
- uv run pytest tests/integration/test_auth_login.py tests/integration/test_views.py tests/unit/test_deployment_configuration.py
- Browsermatrix 390/1280/1920 voor login, dashboard en verkenner
- Live asset-, favicon-, readiness- en containerhealth-smoke
- ./scripts/codex_verify.sh
primary_paths:
- static/img/itworx-wordmark.png
- static/img/itworx-app-icon.png
- static/img/vacatureradar-docker.png
- templates/base.html
- templates/registration
- static/css/premium.css
- static/css/auth.css
result:
completed_at: '2026-07-26'
note: Officiële aangeleverde ITWorx.tech-wordmark geïntegreerd in sidebar, topbar, login en herstel; cloud-check
exact afgeleid voor 512px favicon/app-icon en 256px Dockermanicoon. Browsermatrix 390/1280/1920 schoon, 267
tests groen en live image sha256:daf34407813b37cdf2d0fc65a482ded65375f89eedd3f0144a8c0ce206d41565 healthy
met readiness/PNG-smokes.
- id: VR-301
title: Multi-tenant SaaS, teams en billing
status: deferred
+28
View File
@@ -34,6 +34,34 @@ Het volledige scherm- en afwijkingsrapport staat in `docs/design/STITCH_INTEGRAT
## Laatste onderhoudsaudit
VR-220 op 2026-07-26:
- “eigen branding” is gecorrigeerd naar de door de eigenaar aangeleverde officiële ITWorx.tech-identiteit in plaats van een tijdelijke tekstuele Jens-signatuur;
- sidebar, bovenbalk, login en wachtwoordherstel gebruiken de transparante opgeschoonde ITWorx.tech-wordmark; VacatureRadar blijft herkenbaar als product en intelligence cockpit;
- favicon/app-icon (512×512) en Dockermanicoon (256×256) zijn exact uit het officiële cloud-check-symbool gecropt en Lanczos geschaald, zonder generatieve wijziging;
- merkassets zijn lokaal, transparant, geoptimaliseerd en met herkomst vastgelegd in `static/img/README.md`;
- browsercontrole op 390, 1280 en 1920 px toont correcte assets, geen overflow en een schone console; 29 gerichte regressies en de volledige gate zijn groen met 267 geslaagde tests, 2 optionele skips en 83,45% branch-aware dekking;
- de deployhelper negeert nu veilig verwijderde indexpaden; de twee vervangen SVG-assets zijn expliciet uit de gevalideerde remote sourceboom verwijderd en de uiteindelijke image bevat 147 in plaats van 149 static files;
- live image `sha256:daf34407813b37cdf2d0fc65a482ded65375f89eedd3f0144a8c0ce206d41565` via `unraid-itworx` uitgerold; container healthy, readiness HTTP 200 en wordmark-, app-icon- en Dockermanassets leveren `image/png` met HTTP 200. Volgende uitvoerbare taak: geen.
VR-219 op 2026-07-26:
- de door gebruikersscreenshots aangetoonde ultrawide-uitlijningsfout is hersteld: directe hoofdsecties zijn niet langer afzonderlijk gecentreerd op 1860 px, maar delen één links verankerd grid tot 2800 px;
- op 3840 px beginnen heading, filters, explorer, systeemstatus, pipeline, KPI's en automationdetail op x=296; dezelfde gridbreedte schaalt zonder overflow naar 1920, 1280 en 390 px;
- de resultatenkolom en automationlograil hebben begrensde ultrawide-verhoudingen zodat primaire inhoud niet onnodig uitrekt;
- sidebar, bovenbalk, login en herstelpagina's gebruiken consistent `Personal intelligence by Jens` en `Jens Intelligence`, los van de accountgebruikersnaam;
- browsermatrix schoon zonder consolewaarschuwingen; gerichte regressies 23 tests groen en volledige gate groen met 267 geslaagde tests, 2 optionele skips en 83,45% branch-aware dekking;
- live image `sha256:86836f82cc543a7adb414e47b9667e9123bb9ceba10d629a53086273aaaae03f` via `unraid-itworx` uitgerold; container healthy, readiness HTTP 200 en de nieuwe branding plus 2800px-grid-CSS live gevalideerd. Volgende uitvoerbare taak: geen.
VR-218 op 2026-07-26:
- favicon, login en applicatieshell delen één verfijnd lokaal radarbeeldmerk met een sterker silhouet op klein formaat;
- de persoonlijke signatuur `Jens · private intelligence` is zichtbaar op publieke en ingelogde schermen en via `VACATURERADAR_OWNER_NAME` configureerbaar;
- de desktopbovenbalk toont eigenaar plus actuele routecontext; navigatie- en zoekfocus zijn verfijnd en de aanvullende context verdwijnt doelbewust op mobiel;
- gerichte regressies: Ruff groen, 29 tests geslaagd en 2 optionele skips; browsercontrole van dashboard, verkenner, profiel en login op 1280×850 en 390×844 zonder documentoverflow of consolewaarschuwingen;
- live image `sha256:5f25f00c9b7efb166587901ff39b02c56c98fb9946ddef0a4546a22f18dc0802` via `unraid-itworx` uitgerold; container healthy, readiness HTTP 200 en persoonlijke loginbranding plus SVG-favicon live gevalideerd;
- volledige gate groen met 266 geslaagde tests, 2 optionele skips en 83,45% branch-aware dekking; volgende uitvoerbare taak: geen, alleen bestaande externe blokkades en uitgestelde productkeuzes resteren.
VR-217 op 2026-07-26:
- de vermeende Unraid-authenticatiefout bleek een clientprofielkeuze: rechtstreeks IP gebruikte gebruiker `jens`, terwijl `unraid-itworx` correct `root`, `IdentitiesOnly` en de afzonderlijke deploysleutel selecteert;
+18
View File
@@ -104,3 +104,21 @@ De geïntegreerde browsercontrole dekte dashboard, verkenner, pipeline en profie
### Interactieve illustratielaag
Het zoekprofiel gebruikt een herbruikbare lokale SVG-radar als projectillustratie. Scan, signalen en orbitale details bewegen langzaam; pointerbeweging geeft maximaal tien pixels parallax. De visual is `aria-hidden`, bevat geen metric of statusclaim en laat alle profielinformatie en acties zelfstandig intact. Zonder JavaScript blijft de compositie bruikbaar en `prefers-reduced-motion: reduce` verwijdert animatie en parallax volledig. Op 390 px staat de illustratie onder de primaire profielactie, zodat zij de kernflow niet uit de eerste leesvolgorde verdringt.
## Persoonlijke merklaag (VR-218)
Favicon, login en shell gebruiken één compact radarbeeldmerk met een donker fundament, cyan scansignaal en emerald detectiepunt. De tekstsignatuur noemt standaard `Jens · private intelligence`; `VACATURERADAR_OWNER_NAME` maakt deze eigenaar expliciet configureerbaar zonder templatefork. De bovenbalk combineert eigenaar en routecontext met de bestaande zoekactie, zodat gebruikers sneller herkennen in welke werkruimte en flow zij zich bevinden.
De actieve navigatie, merklock-up en zoekfocus hebben preciezere gewicht-, contrast- en motionstates gekregen. Op smalle viewports verdwijnt de aanvullende werkruimtecontext zodat zoeken en primaire navigatie voorrang houden. De browsercontrole van dashboard, verkenner, profiel en login op 1280×850 en 390×844 bevestigt een schone console, geladen lokale assets en geen documentoverflow.
## Ultrawide gridcorrectie (VR-219)
De eerdere premiumlaag centreerde ieder direct hoofdonderdeel afzonderlijk op maximaal 1860 px. Op een 3840-pixelviewport ontstond daardoor links van de inhoud ruim 1100 px lege ruimte, terwijl de vaste bovenbalk een ander anker gebruikte. Alle directe hoofdsecties delen nu één links verankerde contentzone van maximaal 2800 px. Op 3840 px beginnen heading, filters, explorer, systeemstatus, pipeline, KPI's en automationdetail exact op x=296; op 1920 px vullen zij de beschikbare 1576 px en op 390 px de beschikbare 350 px.
De verkenner begrenst zijn resultatenkolom op ultrawide tot 880 px en geeft de resterende ruimte aan vacature-intelligence. De automationlograil blijft tussen 340 en 430 px, zodat tabellen en logs een voorspelbare verhouding houden. De merklock-up is tegelijk geharmoniseerd tot `VacatureRadar — Personal intelligence by Jens` en de desktopwerkruimte tot `Jens Intelligence`; login en herstelpagina's gebruiken dezelfde eigenaarssignatuur.
## Officiële ITWorx-merklaag (VR-220)
De projecteigenaar verduidelijkte dat “eigen branding” verwijst naar de officiële ITWorx.tech-identiteit. De tijdelijke tekstuele Jens-lock-up is daarom vervangen door de transparante, opgeschoonde wordmark uit het aangeleverde `ITWorx_Logo_Asset_Pack_2026-07-25.zip`. In de sidebar staat ITWorx.tech als hoofdmerk met `VacatureRadar · intelligence cockpit` als productdescriptor; de bovenbalk combineert ITWorx.tech met de bestaande routecontext. Login en wachtwoordherstel tonen eerst de officiële wordmark en vervolgens VacatureRadar als product.
Het favicon/app-icon en Dockermanicoon zijn deterministische crops van het cloud-check-symbool uit dezelfde goedgekeurde wordmark, op respectievelijk 512×512 en 256×256. Er is geen nieuw beeldmerk gegenereerd of nagetekend. Alle assets zijn lokaal, transparant en gedocumenteerd in `static/img/README.md`. De browsermatrix op 390, 1280 en 1920 px bevestigt correcte wordmarkverhoudingen, geladen PNG-assets, geen documentoverflow en een schone console.
+5 -2
View File
@@ -63,8 +63,8 @@ Legenda: **I** = geïmplementeerd en getest in de huidige MVP; **P** = gedeeltel
| NFR-005 | I | domeinapps/services/adapters/ADRs | continue review |
| NFR-006 | I | offline pytest + coveragegate | VR-114 verbreedt e2e |
| 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 en toegankelijke interactieve radarillustratie | `tests/e2e/test_vr114_browser_and_accessibility.py`, `tests/integration/test_intelligence_views.py`, `artifacts/visual-validation/`, VR-209213, VR-216/217 |
| NFR-009 | I | lokale SQLite, Docker/Unraidconfig, gevalideerde SSH-deployalias, release-smoke en restore | VR-117 en VR-217 afgerond |
| NFR-008 | I | volledige negen-schermen-Stitch-cockpit, acht viewports, dark/light, toetsenborddrawer, premium visuele hiërarchie, officiële lokale ITWorx.tech-merklaag en toegankelijke interactieve radarillustratie | `tests/e2e/test_vr114_browser_and_accessibility.py`, `tests/integration/test_intelligence_views.py`, `tests/integration/test_views.py`, `artifacts/visual-validation/`, VR-209213, VR-216220 |
| NFR-009 | I | lokale SQLite, configureerbare eigenaarbranding, Docker/Unraidconfig, gevalideerde SSH-deployalias, release-smoke en restore | `tests/unit/test_deployment_configuration.py`, VR-117, VR-217/218 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 |
## Systeemacceptatie
@@ -106,3 +106,6 @@ Iedere backlogtaak die een requirement wijzigt, werkt in dezelfde commit deze ma
- VR-215 corrigeert het Dockerman-downloadcontract: het icoonlabel gebruikt een concrete loopback-URL omdat Dockerman placeholders alleen voor WebUI resolveert; live bewijs omvat de aangemaakte `VacatureRadar-icon.png`-cache.
- VR-216 verfijnt de Stitch-cockpit naar “calm intelligence”: minder visuele ruis, selectief cyan, compactere mobiele KPI's, responsieve filters, intern scrollende pipeline en een CSP-veilige logininteractie.
- VR-217 borgt de werkende Unraid-hostalias en afzonderlijke deploysleutel in een fail-fast releasehelper en voegt een lokale decoratieve radarillustratie met pointerrespons en reduced-motionfallback toe.
- VR-218 verenigt favicon, login en shell onder één radarbeeldmerk, maakt de persoonlijke eigenaarssignatuur configureerbaar en voegt contextuele oriëntatie aan de bovenbalk toe zonder mobiele overflow.
- VR-219 verankert alle hoofdsecties op één ultrawide grid, begrenst paneelverhoudingen voor leesbaarheid en maakt `Personal intelligence by Jens` tot de consistente productlock-up op publieke en ingelogde schermen.
- VR-220 vervangt die tijdelijke tekstlock-up door de aangeleverde officiële ITWorx.tech-wordmark en een exact daaruit afgeleid cloud-check-appicoon voor browser, shell en Dockerman; VacatureRadar blijft de productnaam.
+3
View File
@@ -23,6 +23,9 @@ fi
ssh -o BatchMode=yes -o ConnectTimeout=8 "$unraid_host" "test \"\$(id -un)\" = root && docker info >/dev/null"
git ls-files --cached --others --exclude-standard -z \
| while IFS= read -r -d '' tracked_path; do
[[ -e "$tracked_path" ]] && printf '%s\0' "$tracked_path"
done \
| tar --null --files-from=- --create --gzip --file="$local_archive"
scp -q "$local_archive" "$unraid_host:/tmp/$archive_name"
+9 -8
View File
@@ -125,11 +125,9 @@ body.auth-page {
.auth-brand-logo {
display: block;
width: 64px;
height: 64px;
margin-bottom: 16px;
border-radius: 16px;
box-shadow: 0 10px 24px rgba(0, 124, 131, 0.28), 0 2px 6px rgba(18, 38, 43, 0.08);
width: min(274px, 78vw);
height: auto;
margin-bottom: 18px;
}
.auth-brand-name {
@@ -142,9 +140,12 @@ body.auth-page {
}
.auth-brand-tagline {
margin: 4px 0 0;
font-size: 14px;
line-height: 20px;
margin: 6px 0 0;
font-size: 11px;
line-height: 18px;
font-weight: 700;
letter-spacing: .12em;
text-transform: uppercase;
color: var(--on-surface-variant);
}
+18 -1
View File
@@ -34,7 +34,13 @@ body::before {
.cockpit-sidebar { background: color-mix(in srgb, var(--surface-lowest) 97%, black); }
.cockpit-main { padding-top: calc(var(--topbar-height) + 42px); }
.cockpit-main > * { max-width: 1860px; }
.cockpit-main > * { max-width: 2800px; margin-right: auto; margin-left: 0; }
.brand-lockup { display: grid; min-width: 0; gap: 5px; }
.brand-wordmark { display: block; width: 174px; height: auto; padding: 5px 8px; border-radius: 7px; background: rgba(255, 255, 255, .94); }
.cockpit-brand small { margin: 0 2px; color: var(--text-faint); font-size: 8px; font-weight: 700; letter-spacing: .08em; }
.workspace-identity { display: grid; min-width: 176px; padding-right: 18px; border-right: 1px solid var(--divider); line-height: 1.1; }
.workspace-identity span { color: var(--text-strong); font-size: 14px; font-weight: 740; letter-spacing: -.015em; }
.workspace-identity small { margin-top: 5px; color: var(--text-faint); font: 650 9px var(--font-body); letter-spacing: .075em; text-transform: uppercase; }
.nav-caption,
.nav-item,
@@ -45,6 +51,9 @@ body::before {
.nav-item:hover { transform: none; background: color-mix(in srgb, var(--surface-high) 70%, transparent); }
.nav-item.is-active { background: var(--surface-high); box-shadow: inset 0 0 0 1px var(--divider); }
.nav-item.is-active::after { inset: 9px auto 9px 0; width: 3px; border-radius: 0 3px 3px 0; box-shadow: none; }
.nav-item .icon { transition: color .16s ease, transform .16s ease; }
.nav-item:hover .icon { transform: scale(1.06); color: var(--text-strong); }
.nav-item.is-active span { font-weight: 680; }
.cockpit-heading { margin-bottom: 30px; }
.cockpit-heading h1 { max-width: 900px; }
@@ -65,6 +74,8 @@ input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
select,
textarea,
.command-search { border-color: var(--divider-strong); border-radius: 9px; background: color-mix(in srgb, var(--surface-low) 90%, transparent); }
.command-search { transition: width .2s ease, border-color .16s ease, background .16s ease, box-shadow .16s ease; }
.command-search:focus-within { width: min(620px, 65vw); border-color: color-mix(in srgb, var(--cyan) 58%, var(--outline)); background: var(--surface-container); box-shadow: 0 0 0 3px color-mix(in srgb, var(--cyan) 8%, transparent); }
.field-label,
label > span:first-child { font-family: var(--font-body); font-weight: 700; letter-spacing: .065em; }
@@ -151,6 +162,11 @@ label > span:first-child { font-family: var(--font-body); font-weight: 700; lett
.pill { border-color: transparent; border-radius: 999px; }
.empty-state { border-color: var(--divider-strong); border-radius: var(--radius-md); }
@media (min-width: 1800px) {
.explorer-shell { grid-template-columns: minmax(650px, 880px) minmax(760px, 1fr); }
.automation-layout { grid-template-columns: minmax(0, 1fr) minmax(340px, 430px); }
}
@media (max-width: 1450px) {
.filter-console { grid-template-columns: minmax(250px, 1.5fr) repeat(3, minmax(135px, 1fr)); }
.filter-console > :nth-last-child(-n+3) { grid-row: 2; }
@@ -171,6 +187,7 @@ label > span:first-child { font-family: var(--font-body); font-weight: 700; lett
.profile-index-card { grid-template-columns: 1fr; }
.profile-index-art { min-height: 230px; border-top: 1px solid var(--divider); border-left: 0; }
.profile-index-art .radar-illustration { width: 220px; }
.command-search:focus-within { width: min(100%, 510px); }
}
@media (max-width: 560px) {
-8
View File
@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<rect width="64" height="64" rx="10" fill="#00f5ff"/>
<g fill="none" stroke="#003739" stroke-linecap="round" stroke-linejoin="round" stroke-width="4">
<circle cx="32" cy="32" r="20"/>
<circle cx="32" cy="32" r="11"/>
<path d="m32 32 15-15M32 8v5M8 32h5M32 51v5M51 32h5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 363 B

+7
View File
@@ -0,0 +1,7 @@
# Lokale merkassets
`itworx-wordmark.png` is de transparante, opgeschoonde officiële ITWorx.tech-wordmark uit `ITWorx_Logo_Asset_Pack_2026-07-25.zip`, door de projecteigenaar aangeleverd op 2026-07-26.
`itworx-app-icon.png` en `vacatureradar-docker.png` zijn deterministisch uitgesneden en met Lanczos geschaalde varianten van het cloud-check-symbool uit dezelfde goedgekeurde wordmark. Ze bevatten geen nieuw of gegenereerd beeldmerk. Het app-icon is 512×512; de Dockermanvariant is 256×256.
Deze assets zijn uitsluitend voor de eigen VacatureRadar-installatie en worden niet als generiek herbruikbare of publiek gelicenseerde merkset aangeboden.
Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 31 KiB

-8
View File
@@ -1,8 +0,0 @@
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="VacatureRadar">
<rect width="64" height="64" rx="12" fill="#007c83"/>
<g fill="none" stroke="#f2ffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="4">
<circle cx="32" cy="32" r="20"/>
<circle cx="32" cy="32" r="11"/>
<path d="m32 32 15-15M32 8v5M8 32h5M32 51v5M51 32h5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 424 B

+8 -6
View File
@@ -5,9 +5,11 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark light">
<meta name="theme-color" content="#060e20">
<meta name="theme-color" content="#071327" media="(prefers-color-scheme: dark)">
<meta name="theme-color" content="#f4f7f7" media="(prefers-color-scheme: light)">
<meta name="application-name" content="VacatureRadar · {{ app_brand_name }}">
<title>{% block title %}{{ app_name }}{% endblock %}</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="icon" href="{% static 'img/itworx-app-icon.png' %}?v={{ app_version }}" type="image/png" sizes="512x512">
<link rel="stylesheet" href="{% static 'css/app.css' %}?v={{ app_version }}">
<script src="{% static 'js/app.js' %}?v={{ app_version }}" defer></script>
{% block extra_head %}{% endblock %}
@@ -19,9 +21,8 @@
<div class="cockpit" data-app-frame>
<aside class="cockpit-sidebar" data-sidebar aria-label="Hoofdnavigatie">
<div class="sidebar-heading">
<a class="cockpit-brand" href="{% url 'dashboard:today' %}" aria-label="VacatureRadar dashboard">
<span class="brand-radar" aria-hidden="true"><svg class="icon"><use href="#icon-radar"></use></svg></span>
<span><strong>VacatureRadar</strong><small>Intelligence cockpit</small></span>
<a class="cockpit-brand" href="{% url 'dashboard:today' %}" aria-label="ITWorx.tech VacatureRadar dashboard">
<span class="brand-lockup"><img class="brand-wordmark" src="{% static 'img/itworx-wordmark.png' %}" alt="ITWorx.tech"><small>VacatureRadar · intelligence cockpit</small></span>
</a>
<button class="icon-button nav-close mobile-only" type="button" data-nav-close aria-label="Menu sluiten"><svg class="icon"><use href="#icon-close"></use></svg></button>
</div>
@@ -48,7 +49,7 @@
</div>
<div class="sidebar-account">
<span class="avatar" aria-hidden="true">{{ user.first_name|default:user.username|slice:":1"|upper }}</span>
<span><strong>{{ user.get_full_name|default:user.username }}</strong><small>Persoonlijke radar</small></span>
<span><strong>{{ user.get_full_name|default:user.username }}</strong><small>Eigen werkruimte</small></span>
</div>
</aside>
@@ -57,6 +58,7 @@
<header class="cockpit-topbar">
<div class="topbar-start">
<button class="icon-button mobile-only" type="button" data-nav-toggle aria-label="Menu openen" aria-expanded="false"><svg class="icon"><use href="#icon-menu"></use></svg></button>
<div class="workspace-identity desktop-label"><span>{{ app_brand_name }}</span><small>VacatureRadar · {{ page_context_label }}</small></div>
<form class="command-search" method="get" action="{% url 'jobs:list' %}" role="search">
<label class="sr-only" for="global-search">Zoek door vacatures</label>
<svg class="icon" aria-hidden="true"><use href="#icon-search"></use></svg>
+5 -4
View File
@@ -4,18 +4,19 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<meta name="theme-color" content="#fbf8ff">
<meta name="theme-color" content="#071327">
<meta name="application-name" content="VacatureRadar · {{ app_brand_name }}">
<title>Inloggen · VacatureRadar</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="icon" href="{% static 'img/itworx-app-icon.png' %}?v={{ app_version }}" type="image/png" sizes="512x512">
<link rel="stylesheet" href="{% static 'css/auth.css' %}?v={{ app_version }}">
</head>
<body class="auth-page">
{% include "components/icon_sprite.html" %}
<main class="auth-shell">
<div class="auth-brand">
<img class="auth-brand-logo" src="{% static 'img/vacatureradar-logo.svg' %}" alt="VacatureRadar logo" width="64" height="64">
<img class="auth-brand-logo" src="{% static 'img/itworx-wordmark.png' %}" alt="ITWorx.tech" width="274" height="60">
<p class="auth-brand-name">VacatureRadar</p>
<p class="auth-brand-tagline">Intelligence cockpit</p>
<p class="auth-brand-tagline">Persoonlijke intelligence cockpit</p>
</div>
<div class="auth-card">
@@ -5,16 +5,16 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<title>Wachtwoord gewijzigd · VacatureRadar</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="icon" href="{% static 'img/itworx-app-icon.png' %}?v={{ app_version }}" type="image/png" sizes="512x512">
<link rel="stylesheet" href="{% static 'css/auth.css' %}?v={{ app_version }}">
</head>
<body class="auth-page">
{% include "components/icon_sprite.html" %}
<main class="auth-shell">
<div class="auth-brand">
<img class="auth-brand-logo" src="{% static 'img/vacatureradar-logo.svg' %}" alt="VacatureRadar logo" width="64" height="64">
<img class="auth-brand-logo" src="{% static 'img/itworx-wordmark.png' %}" alt="ITWorx.tech" width="274" height="60">
<p class="auth-brand-name">VacatureRadar</p>
<p class="auth-brand-tagline">Intelligence cockpit</p>
<p class="auth-brand-tagline">Persoonlijke intelligence cockpit</p>
</div>
<div class="auth-card">
@@ -5,16 +5,16 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<title>Nieuw wachtwoord · VacatureRadar</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="icon" href="{% static 'img/itworx-app-icon.png' %}?v={{ app_version }}" type="image/png" sizes="512x512">
<link rel="stylesheet" href="{% static 'css/auth.css' %}?v={{ app_version }}">
</head>
<body class="auth-page">
{% include "components/icon_sprite.html" %}
<main class="auth-shell">
<div class="auth-brand">
<img class="auth-brand-logo" src="{% static 'img/vacatureradar-logo.svg' %}" alt="VacatureRadar logo" width="64" height="64">
<img class="auth-brand-logo" src="{% static 'img/itworx-wordmark.png' %}" alt="ITWorx.tech" width="274" height="60">
<p class="auth-brand-name">VacatureRadar</p>
<p class="auth-brand-tagline">Intelligence cockpit</p>
<p class="auth-brand-tagline">Persoonlijke intelligence cockpit</p>
</div>
<div class="auth-card">
@@ -5,16 +5,16 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<title>Herstel-link verstuurd · VacatureRadar</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="icon" href="{% static 'img/itworx-app-icon.png' %}?v={{ app_version }}" type="image/png" sizes="512x512">
<link rel="stylesheet" href="{% static 'css/auth.css' %}?v={{ app_version }}">
</head>
<body class="auth-page">
{% include "components/icon_sprite.html" %}
<main class="auth-shell">
<div class="auth-brand">
<img class="auth-brand-logo" src="{% static 'img/vacatureradar-logo.svg' %}" alt="VacatureRadar logo" width="64" height="64">
<img class="auth-brand-logo" src="{% static 'img/itworx-wordmark.png' %}" alt="ITWorx.tech" width="274" height="60">
<p class="auth-brand-name">VacatureRadar</p>
<p class="auth-brand-tagline">Intelligence cockpit</p>
<p class="auth-brand-tagline">Persoonlijke intelligence cockpit</p>
</div>
<div class="auth-card">
@@ -5,16 +5,16 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<title>Wachtwoord herstellen · VacatureRadar</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="icon" href="{% static 'img/itworx-app-icon.png' %}?v={{ app_version }}" type="image/png" sizes="512x512">
<link rel="stylesheet" href="{% static 'css/auth.css' %}?v={{ app_version }}">
</head>
<body class="auth-page">
{% include "components/icon_sprite.html" %}
<main class="auth-shell">
<div class="auth-brand">
<img class="auth-brand-logo" src="{% static 'img/vacatureradar-logo.svg' %}" alt="VacatureRadar logo" width="64" height="64">
<img class="auth-brand-logo" src="{% static 'img/itworx-wordmark.png' %}" alt="ITWorx.tech" width="274" height="60">
<p class="auth-brand-name">VacatureRadar</p>
<p class="auth-brand-tagline">Intelligence cockpit</p>
<p class="auth-brand-tagline">Persoonlijke intelligence cockpit</p>
</div>
<div class="auth-card">
+12
View File
@@ -25,6 +25,18 @@ def test_login_page_renders_stitch_design(client):
assert reverse("password_reset") in body
assert 'src="/static/js/login.js?' in body
assert "<script>" not in body
assert "Persoonlijke intelligence cockpit" in body
assert 'alt="ITWorx.tech"' in body
assert 'src="/static/img/itworx-wordmark.png"' in body
assert 'sizes="512x512"' in body
@override_settings(VACATURERADAR_OWNER_NAME="Eigen merk")
def test_login_page_keeps_official_brand_separate_from_owner_setting(client):
body = client.get(reverse("login")).content.decode("utf-8")
assert "Eigen merk" not in body
assert 'content="VacatureRadar · ITWorx.tech"' in body
def test_login_with_email(client, user):
+24 -2
View File
@@ -1,4 +1,5 @@
import pytest
from django.conf import settings
from django.core.cache import cache
from django.test import override_settings
from django.urls import reverse
@@ -17,10 +18,17 @@ def test_today_requires_login(client):
@pytest.mark.integration
@pytest.mark.django_db
def test_browser_favicon_fallback_uses_local_svg(client):
def test_browser_favicon_and_brand_assets_are_local_pngs(client):
response = client.get("/favicon.ico")
assert response.status_code == 301
assert response.url.endswith("/static/favicon.svg")
assert response.url.endswith("/static/img/itworx-app-icon.png")
favicon = settings.BASE_DIR / "static" / "img" / "itworx-app-icon.png"
wordmark = settings.BASE_DIR / "static" / "img" / "itworx-wordmark.png"
assert favicon.read_bytes().startswith(b"\x89PNG\r\n\x1a\n")
assert wordmark.read_bytes().startswith(b"\x89PNG\r\n\x1a\n")
assert favicon.stat().st_size < 150_000
assert wordmark.stat().st_size < 100_000
@pytest.mark.integration
@@ -30,6 +38,20 @@ def test_today_loads_for_user(client, user, profile):
response = client.get(reverse("dashboard:today"))
assert response.status_code == 200
assert "Vandaag" in response.content.decode()
body = response.content.decode()
assert 'alt="ITWorx.tech"' in body
assert "VacatureRadar · intelligence cockpit" in body
assert "ITWorx.tech" in body
assert "VacatureRadar · Dagoverzicht" in body
assert "Dagoverzicht" in body
assert 'content="VacatureRadar · ITWorx.tech"' in body
def test_premium_layout_uses_one_left_aligned_ultrawide_grid():
css = (settings.BASE_DIR / "static" / "css" / "premium.css").read_text(encoding="utf-8")
assert "max-width: 2800px; margin-right: auto; margin-left: 0" in css
assert "@media (min-width: 1800px)" in css
assert "minmax(650px, 880px) minmax(760px, 1fr)" in css
@pytest.mark.integration
+5 -1
View File
@@ -74,14 +74,18 @@ def test_deployment_examples_use_per_platform_mailbox_configuration() -> None:
for key in required_keys:
assert f"{key}=" in content
env_example = (ROOT / ".env.example").read_text(encoding="utf-8")
assert "VACATURERADAR_OWNER_NAME=Jens" in env_example
def test_unraid_deploy_requires_dedicated_ssh_alias() -> None:
deploy_script = (ROOT / "scripts" / "deploy_unraid.sh").read_text(encoding="utf-8")
assert 'UNRAID_SSH_HOST:-unraid-itworx' in deploy_script
assert "UNRAID_SSH_HOST:-unraid-itworx" in deploy_script
assert "ssh -G" in deploy_script
assert '[[ "$ssh_user" != "root" ]]' in deploy_script
assert "itworx_unraid_deploy" in deploy_script
assert "BatchMode=yes" in deploy_script
assert "git ls-files --cached --others --exclude-standard -z" in deploy_script
assert '[[ -e "$tracked_path" ]]' in deploy_script
assert "/health/ready/" in deploy_script