24 KiB
Mindflux — Refine 2: Light-Mode-Konzept, Scroll-Verhalten, Restpunkte
Kontext
Folgeplan zu mindfluxrefine.md. Die Code-Verifikation (2026-07-21) bestätigt: alle „vollständig"-Claims aus Refine 1 halten der Prüfung stand; offen sind AP 1e (Glow im Light Mode), der AP-7-Rest sowie einige Zusatzfunde (s. AP R5). Dieser Plan liefert das, was Refine 1 offen ließ: ein echtes Light-Mode-Konzept, das alle Probleme an der Wurzel behebt (statt Glow-Alphas weiter zu dimmen), plus das neue Thema Scroll-Verhalten (Ergebnisanzeigen u. ä. müssen oben starten, nicht unten).
Audit-Kurzbefunde (2026-07-21, drei unabhängige Durchgänge):
- Light-Mode-Strukturfehler: Der Light-Block in
theme.csstauscht nur Farbwerte/Alphas der Glow-Tokens. Die Geometrie der Effekte (box-shadow:0 0 20px …,text-shadow:0 0 12px …,drop-shadow(0 0 8px …)) steht hart in ~70 Komponentenregeln quer durchtheme.css, alle Spiele-CSS und Template-<style>-Blöcke. Ein Halo mit reduziertem Alpha bleibt ein Halo — auf Fast-Weiß liest er sich als Schmutz/Haze. Einzige strukturell adaptierte Stelle heute:--g-soft(0 0 18pxdark →0 6px 18pxlight,theme.css:31/53). Genau eine Regel neutralisiert einen Glow explizit im Light Mode (auth.css:127–128). - 5 im Light Mode kaputte Stellen: Login-Overlay weiß-auf-weiß (auth.css:123–127 × platform-neural.css:94), SyntaxSaga-Bühne bleibt schwarz (
syntaxsaga.css:250–251), CodeEscape-Eingaben dunkel-auf-dunkel (codeescape.css.esc-input#080604), NetWorker-Guide-Panel dunkelnavy mit Light---muted(networker-guide.css), Farbenblind-Palette × Light = Hellgelb/Hellblau auf Weiß (accessibility.css:15–23,!importantschlägt die Light-Kartenakzente). - Theme-Bootstrap-Lücken:
color-schemefehlt komplett (native Scrollbars/Form-Controls folgen dem UA-Default), keintheme-color-Meta, keinprefers-color-scheme-Fallback (Erstbesucher mit OS-Light starten dunkel), alle Templates hardcodendata-theme="dark". - Scroll: Im gesamten Projekt existiert kein einziger
scrollTo/scrollIntoView/scrollRestoration-Aufruf (außer Chat-Autoscrollneuralnet.js:84, der korrekt ist). Die vier SPA-Spiele (BugHunter, CodeEscape, NetWorker, ServiceClash) ersetzen Views perinnerHTMLohne Reset; der FinalProtocol-Quiz kollabiert am Ende einer langen Lernseite (Browser clampt ans neue Seitenende); SyntaxSaga/DevLab fokussieren Inputs ohnepreventScroll. - CSS-Leichen:
achievements.css,progress.css,settings.css,soziales.csswerden nirgends mehr referenziert (repo-weiter Grep leer);style.csswird nur noch vonfinalflux.htmlgeladen, ~90 % davon ist toter Dark-Code.
Basis-Pfad: RES = src\main\resources
Das Konzept: „Licht statt Leuchten"
Prinzip: Dark Mode und Light Mode sind Geschwister mit derselben Farbidentität, aber unterschiedlicher Physik:
| Dark Mode | Light Mode | |
|---|---|---|
| Metapher | Neon in der Nacht — Elemente emittieren Licht | Druck/Material am Tag — Elemente werfen Schatten |
| Betonung | farbiger Glow (Halo) | Elevation (weicher, warm getönter neutraler Schatten) |
| Identität/Wiedererkennung | Glow-Farbe | Akzentfarbe direkt am Element (Border, Text, Icon) — ist durch --border-accent, Icon-Farben und Kartenakzente bereits überall vorhanden |
| Text-Halos | ja (text-shadow) |
nie (liest sich als Unschärfe) |
| Fokus-Ringe | farbig, weich | farbig, crisp (Ring statt Blur — funktional, bleibt farbig) |
| Scrims/Overlays | dunkel | dunkel (funktional), aber leicht entschärft |
Mechanik: Effekte werden zu Primitives — komplette box-shadow/filter/text-shadow-Werte als Tokens, nicht nur Farben. Komponenten schreiben nie mehr 0 0 20px var(--glow-s), sondern var(--g-strong). Der Light-Block tauscht dann die Kategorie des Effekts (Glow → Elevation), nicht nur die Farbe. Dark bleibt visuell gleich (Blur-Radien werden auf die Primitive normalisiert; ±4 px sind nicht unterscheidbar). --glow-s/--glow-w bleiben als Farb-Tokens bestehen — die Spiele-CSS remappen sie bereits per color-mix auf ihre Akzente, und die Primitives referenzieren sie per var(), sodass Spiel-Glows im Dark Mode automatisch die Spielfarbe behalten.
AP R0 — Aufräumen (erledigt 2026-07-22)
- Erledigt: Verwaiste CSS gelöscht:
achievements.css,progress.css,settings.css,soziales.css. Die Referenzprüfung ergab 0 Treffer; STYLEGUIDE bereinigt. - Erledigt:
style.cssauf eine vierzeilige Basis für die 40 statischen FinalProtocol-Lernseiten reduziert; FinalProtocol-Hub lädt sie nicht mehr. - Erledigt: Nicht eingebundenes
finalflux-check.jsentfernt.fluxtimer.cssbleibt separat offen, da die Datei in diesem Paket nicht geändert wurde.
AP R1 — Effekt-Primitives (Kern des Light-Konzepts)
R1a. Tokens in RES\static\css\theme.css — erledigt 2026-07-22
In den Dark-Block (Z. 11–32) und Light-Block (Z. 33–54) ergänzen. Schattenfarbe Light ist warmes Braun rgb(67,48,26) (zur Creme-Palette passend, kein totes Grau/Schwarz):
:root, [data-theme="dark"] {
/* … bestehende Tokens … */
color-scheme:dark;
--g-text:0 0 12px var(--glow-s); /* Text-Halo: Logo, Headline-Akzent, *-brand b */
--g-icon:drop-shadow(0 0 8px var(--glow-s)); /* leuchtende Glyphen/Embleme */
--g-strong:0 0 20px var(--glow-s); /* starke Betonung: aktive Nav/Tabs, Primär-Btn */
--g-amb:0 0 14px var(--glow-w); /* dezenter Schein: Icon-Hover, Toggle, Burger */
--g-card:drop-shadow(0 0 7px var(--glow-w)); /* Spielkarten-Grundzustand */
--g-card-hover:drop-shadow(0 0 16px var(--glow-s));
--g-overlay:0 24px 60px rgba(0,0,0,.5); /* schwebende Panels: Guide, Drawer, A11y */
--g-focus:0 0 0 3px var(--glow-w); /* Fokus-Ring (bleibt in beiden Themes farbig) */
--scroll-thumb:var(--line);
}
[data-theme="light"] {
/* … bestehende Tokens … */
color-scheme:light;
--bg-glow: radial-gradient(900px 420px at 60% -10%, rgba(214,81,22,.05), transparent 60%); /* statt .10 — Haze halbieren */
--g-text:none;
--g-icon:none;
--g-strong:0 2px 10px rgba(67,48,26,.18), 0 1px 3px rgba(67,48,26,.10);
--g-amb:0 1px 5px rgba(67,48,26,.10);
--g-card:drop-shadow(0 2px 5px rgba(67,48,26,.10));
--g-card-hover:drop-shadow(0 8px 18px rgba(67,48,26,.16));
--g-overlay:0 18px 44px rgba(67,48,26,.20);
--g-focus:0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent);
--scroll-thumb:#d9cbb2; /* --line #f1e8d8 ist auf #fbf6ec unsichtbar */
}
Scrollbar-Regel theme.css:64 auf background:var(--scroll-thumb) umstellen.
R1b. Mechanische Migration in theme.css
| Zeile | Selektor | Alt | Neu |
|---|---|---|---|
| 79 | .mf-logo .mark |
drop-shadow(0 0 8px var(--glow-s)) |
filter:var(--g-icon) |
| 80 | .mf-logo .txt b |
text-shadow:0 0 12px var(--glow-s) |
text-shadow:var(--g-text) |
| 87 | .mf-nav a.active |
0 0 20px var(--glow-s) |
box-shadow:var(--g-strong) |
| 94 | .mf-avatar |
0 0 14px var(--glow-s) |
box-shadow:var(--g-strong) (gleiche Farbstärke-Familie wie heute) |
| 102/104 | .mf-streak .fire / .mf-brain |
drop-shadows | filter:var(--g-icon) |
| 109 | .mf-hello h1 .nm |
text-shadow:0 0 16px var(--glow-s) |
text-shadow:var(--g-text) |
| 113/120/202 | iconbtn-Hover / .mf-theme / .mf-burger |
0 0 14px var(--glow-w) |
box-shadow:var(--g-amb) |
| 128/130 | .mf-card / :hover |
drop-shadow 7/16px | filter:var(--g-card) / var(--g-card-hover) |
| 131 | .mf-card .ico |
drop-shadow | filter:var(--g-icon) |
| 136 | .mf-card:hover .mf-play |
0 0 16px var(--glow-s) |
box-shadow:var(--g-strong) |
| 146 | .mf-panel.accent |
0 0 20px var(--glow-w) |
box-shadow:var(--g-amb) |
| 151 | .mf-bar > i |
0 0 10px var(--glow-s) |
eigenes Primitive --g-bar (dark 0 0 10px var(--glow-s) / light none) — der Balken trägt seine Farbe selbst, im Light braucht er keinen Hof |
| 154 | .mf-btn |
0 0 18px var(--glow-s) |
box-shadow:var(--g-strong) |
| 168 | Input-Fokus | 0 0 0 3px var(--glow-w) |
box-shadow:var(--g-focus) |
| 182 | .mf-cardbox |
0 0 30px var(--glow-w) |
Hero-Aura: Zweizeiler — Basis box-shadow:var(--g-strong), plus [data-theme="dark"] .mf-cardbox{box-shadow:0 0 30px var(--glow-w)} |
| 223 | Mobile .mf-sidebar |
0 18px 50px rgba(0,0,0,.55) |
box-shadow:var(--g-overlay) |
| 238 | .mf-tab.active |
0 0 18px var(--glow-s) |
box-shadow:var(--g-strong) |
R1c. platform-neural.css
Hat als einzige Datei schon gute Struktur-Overrides (Z. 91 ersetzt Schwarz- durch Grünschatten — Vorbild). Nachziehen: Z. 87 Logo-Drop-Shadow im Light auf filter:none; Z. 90 äußeren 0 0 13px-Glow der aktiven Nav im Light streichen (Inset-Ring reicht). Die --glow-s-Kartenwerte (Z. 41–49/99–107) bleiben — sie speisen nach R1b nur noch Dark-Effekte.
R1d. Spiele-CSS + Guide/Widget-CSS migrieren
Gleiches Muster in allen Dateien; die Spiel---glow-s-Remaps (z. B. mindmatch.css:364) bleiben unverändert und speisen die Primitives automatisch mit der Spielfarbe. Betroffene Stellen (Audit-Inventar):
- Text-Halos →
text-shadow:var(--g-text):syntaxsaga.css:40,mindmatch.css:53,techtacular.css:48,devlab.css(.dl-tube span),devlabgame.css(Header-Titel),codeescape.css(.esc-brand b,.esc-result .score),bughunter.css(.bh-brand b, Stamp),networker.css(.nw-brand b,.nw-final-score),serviceclash.css(.sc-brand b,.sc-score),auth.css:74(.auth-head b),style.css:89(falls nach R0 noch vorhanden), Template-<style>:progress.html:14(Prozentzahl). - Box-Glows →
var(--g-strong)/var(--g-amb)nach Gewicht:syntaxsaga.css:37/70/100/125/136/200/229/233,mindmatch.css:40/106/226/237/280/287/299/324,techtacular.css:39/75/174/207/299,devlab.css:102/158/173,devlabgame.css:10/12/23/49/61/70/78/106/108,codeescape.css(Buttons/Dialog/Hero — Hero-0 0 50pxals Dark-only-Zweizeiler wie.mf-cardbox),codeescape-guide.css(.esc-how .active,.esc-door.ready,.esc-input.bad),bughunter.css,networker.css,serviceclash.css(.sc-meter i),fluxtimer.css:6/7,accessibility.css:29,accessibility-placement.css:2/16,auth.css:14/34/88/98(.neon-btninkl.: den::before-Conic-Blur-Rotor Z. 95/99 im Light perdisplay:none). - Fokus-Ringe →
var(--g-focus):syntaxsaga.css:160,devlabgame.css:35/39, CodeEscape-Inputs. - Schwarz-Schatten →
var(--g-overlay)bzw. warm getönt:game-guide.css:72,accessibility.css:30,accessibility-placement.css:17,fluxtimer.css:8(+ Z. 14inset-Schwarz auf hellem Display im Light entfernen),serviceclash.css(.sc-card),bughunter.css(Drawer, dort auch die im Light unsichtbarenrgba(255,255,255,.09–.16)-Inset-Highlights auf Light-Varianten umstellen). - Scrims (funktional, bleiben dunkel, aber vereinheitlichen):
mindmatch.css:309,techtacular.css:192,syntaxsaga.css:216,devlabgame.css:104— im Light auf das Mustergame-guide.css:138(rgba(15,23,42,.5)) wechseln, damit sich nicht zusätzlich der warme--bg-glow-Radial über den Scrim legt (var(--bg-glow)aus den Scrim-Deklarationen entfernen). - Hint-Glow
game-guide.css:155/160–161(#ffd54a): Light-Override[data-theme="light"] .mm-card.hinted { box-shadow:0 0 0 2px #8a6a06, 0 4px 12px rgba(67,48,26,.18); filter:none; }(Warn-Ton aus dem Light-Block).
R1e. Chart/Dashboard-<style>-Blöcke
dashboard.html:14/16/18/20/29/31/43/46/171, achievements.html:12–16, admin/dashboard.html:17–19, impressum.html:12, profile.html:11: alle text-shadow/drop-shadow/0 0 Npx-Vorkommen auf die Primitives umstellen (Suchmuster: grep -n "glow\|text-shadow\|drop-shadow" RES\templates -r).
AP R2 — Kaputte Light-Stellen (kritische Punkte erledigt 2026-07-22)
R2a. Login/Registrierung: Overlay weiß-auf-weiß (kritisch)
Ursache: auth.css:123–127 setzt für Light #fff-Text/weiße Ghost-Border (Annahme: kräftiges Orange-Panel), aber auf der Plattform übersteuert platform-neural.css:94 den Overlay-Grund mit Fast-Weiß. Fix in platform-neural.css (Light-Sektion, höhere Spezifität durch .sn-platform gewinnt gegen auth.css):
html[data-theme="light"].sn-platform body .overlay-panel h3 { color:#10291f; text-shadow:none; }
html[data-theme="light"].sn-platform body .overlay-panel p { color:#3c554a; }
html[data-theme="light"].sn-platform body .ghost-btn { color:#167a52; border-color:rgba(22,122,82,.55); }
html[data-theme="light"].sn-platform body .ghost-btn:hover { background:rgba(22,122,82,.10); }
R2b. SyntaxSaga: Bühne bleibt schwarz (kritisch)
syntaxsaga.css:250–251 hardcodet #07100b + grüne Scanlines. Light-Block ergänzen (Palette: helles Bühnen-Grün zur Light---ss-accent #277d49):
[data-theme="light"] body.ss-body {
background:radial-gradient(1100px 500px at 50% -10%, rgba(39,125,73,.08), transparent 60%), #eef6f0;
}
[data-theme="light"] body.ss-body::before {
background:repeating-linear-gradient(0deg, rgba(16,64,40,.05) 0 1px, transparent 1px 4px);
}
R2c. CodeEscape: Terminal-Eingaben & Dark-Inks (kritisch)
.esc-input, .esc-select(#080604): Light-Override[data-theme="light"] .esc-input, [data-theme="light"] .esc-select { background:#fffaf0; color:var(--text); border-color:var(--border); }— Dark behält den Terminal-Look.- Hardcodierte Dark-Inks auf Akzentflächen durch das Token ersetzen (funktioniert in beiden Themes):
.esc-btn:hover/.primary#160d00→var(--accent-ink);codeescape-guide.css.esc-fragment small#160d00→var(--accent-ink);.esc-how .done b#06120a→var(--accent-ink). - Tote Scanlines
rgba(255,255,255,.018)(codeescape.css,theme.css:138): im Light-Override aufrgba(67,48,26,.04)drehen oder streichen.
R2d. NetWorker-Guide: dunkles Panel (kritisch)
networker-guide.css (.nw-guide color-mix(#0b2540 74%, var(--surface))): Light-Block ergänzen:
[data-theme="light"] .nw-guide { background:var(--surface); border-color:#d3e2f0; box-shadow:var(--g-soft); }
(Textfarben laufen dort über var(--muted)/var(--text) und stimmen dann automatisch.)
R2e. Farbenblind-Palette × Light (kritisch)
accessibility.css:15–23 erzwingt helle Okabe-Ito-Akzente per !important — auf weißen Karten < 1.5:1. Neuen Satz html[data-theme="light"][data-mf-color="safe"] mit abgedunkelten Okabe-Ito-Entsprechungen ergänzen (gleiche Zuordnung Spiel→Farbfamilie wie im Dark-Satz, Werte rechnerisch ≥ 4.5:1 auf Weiß, beim Umsetzen mit Kontrast-Tool gegenprüfen):
| Okabe-Ito (dark) | Light-safe |
|---|---|
#e69f00 Orange |
#8a5f00 |
#56b4e9 Himmelblau |
#19607f |
#009e73 Grün |
#007054 |
#f0e442 Gelb |
#7a6a00 |
#0072b2 Blau |
#0072b2 (bleibt) |
#d55e00 Vermillion |
#a94500 |
#cc79a7 Purpur |
#9c4f79 |
Die zugehörigen Glow-Alphas entfallen im Light automatisch über die Primitives (R1).
R2f. Kleinere Light-Fixes
- Cancel-Hover
mindmatch.css:128–129,techtacular.css:94(#fffauf Blassrosa): Light-Override[data-theme="light"] .mm-cancel:hover, …→background:var(--danger); color:#fff;(Light-Danger#be123c, 7:1). Dark bleibt unverändert. - A11y-Widget-Inks:
accessibility-placement.css:7–15hardcodet dunkle--mf-a11y-ink-Werte — im Light sind die Akzente selbst dunkel. Eine Regel ergänzt:html[data-theme="light"] body { --mf-a11y-ink:#fff; }(gewinnt per Spezifität gegen die Skin-Zuweisungen). Panel-Kopf optional angleichen:[data-theme="light"] .mf-a11y-head { background:var(--surface-2); color:var(--heading); }. - finalflux-Altlast:
finalflux.css:345(#0b0d1b-Hardcode) funktioniert nur über die fragilebackground:transparent-Kaskade ausplatform-neural.css:61. Hardcode durchvar(--bg)-basierte Deklaration ersetzen, damit die Seite auch ohnesn-platformbeide Themes überlebt.
Erledigt: Login-Overlay, SyntaxSaga-Bühne, CodeEscape-Eingaben und Akzent-Inks, NetWorker-Guide, Farbenblind-Palette für Light Mode, A11y-Widget-Inks sowie der FinalProtocol-Hintergrund. Die noch offenen kleineren Cancel-Hover- und Detaileffekte werden zusammen mit der vollständigen CSS-Migration aus R1 abgeschlossen.
AP R3 — Theme-Bootstrap (erledigt 2026-07-22)
In RES\static\js\theme.js:
- Erledigt:
prefers-color-schemewird verwendet, wenn noch keine lokale Auswahl gespeichert ist. - Erledigt:
theme-colorwird beim initialen Anwenden und Umschalten auf#0a0806bzw.#fbf6ecaktualisiert. - Erledigt:
color-schemewird im Dark-/Light-Tokenblock gesetzt. - Teilweise erledigt: geänderte FinalProtocol-Assets tragen neue Versionen; die übrigen Template-Referenzen werden bei ihrer jeweiligen Migration angehoben.
AP R4 — Scroll: Ergebnisanzeigen & Ansichten starten oben (weitgehend erledigt 2026-07-22)
Es gibt projektweit keinen Scroll-Reset. Drei Schichten (zentraler Helper + gezielte Aufrufe), Chat-Autoscroll neuralnet.js:84 bleibt unangetastet:
R4a. Helper in theme.js (läuft auf jeder Seite)
window.MindfluxUX = {
toTop: function () { window.scrollTo(0, 0); },
focusQuiet: function (el) { if (el) el.focus({ preventScroll: true }); }
};
Umsetzungshinweis: Der zentrale Helper ist vorhanden. Die vier SPA-Spiele setzen
history.scrollRestoration nur auf Spielrouten auf manual; ein zentraler,
ereignisbasierter Übergangs-Reset deckt Ansichtswechsel ab und lässt Antwort- bzw.
Zeilenfeedback unverändert. FinalProtocol, SyntaxSaga, DevLab, MindMatch und
TechTacular haben die zusätzlich beschriebenen gezielten Resets/Fokusoptionen.
Offen für die visuelle E2E-Prüfung: die asynchron gerenderten Ergebniswechsel von
CodeEscape, NetWorker und BugHunter müssen im Browser gegen die Scroll-Checkliste
validiert und bei Bedarf direkt in den jeweiligen Render-Funktionen präzisiert werden.
R4b. SPA-Spiele — Reset bei jedem Ansichtswechsel
Muster pro Spiel: Mini-Wrapper function setView(html){ view.innerHTML = html; window.scrollTo(0,0); }, alle Render-Funktionen darüber. Zusätzlich nur in diesen vier Skripten beim Init: if ('scrollRestoration' in history) history.scrollRestoration = 'manual'; window.scrollTo(0,0); — verhindert, dass der Browser nach Reload/Back die alte, untere Position auf den neu aufgebauten Katalog anwendet. (Nicht global in theme.js: auf Lernseiten/Dashboard ist die Back-Position erwünscht.)
| Spiel | Funktionen |
|---|---|
BugHunter (bughunter.js) |
renderBriefing :29, renderHunt :36 (nur bei Fallwechsel, nicht bei Zeilen-Re-Render), showDebrief :82, renderResult :88 |
CodeEscape (codeescape.js) |
renderLobby :6, renderRoom :8, renderResult :17 |
NetWorker (networker.js) |
renderCatalog :3, renderIntro :5, renderLevel :6, finish :11 |
ServiceClash (serviceclash.js) |
renderCatalog :2, renderRun :4 (nur bei Ticket-/Indexwechsel, nicht beim Feedback-Re-Render), finish :9 |
R4c. FinalProtocol-Quiz (finalflux-test.js)
finishIfDone()Z. 101–104: nachtestResult.hidden = false→elements.testResult.scrollIntoView({ block: 'start' });(Auswertung beginnt oben im Blick, statt dass der Viewport ans geclampte Seitenende fällt).restartTest()Z. 151–158: nach dem Wiedereinblenden →elements.testRoot.scrollIntoView({ block: 'start' });
R4d. Fokus ohne Scroll-Sprung
syntaxsaga.js:renderMission()—window.scrollTo(0,0)vor Z. 209, dann Z. 210first.focus({preventScroll:true}). (nextBtn.focus()Z. 297 bleibt — Nutzeraktion am selben Ort.)devlabgame.js:renderTask()Z. 243 —window.scrollTo(0,0)am Ende; Z. 83 und Z. 233focus({preventScroll:true}).codeescape.js:8/15bleiben (Fokus am Türterminal ist dort korrekt).
R4e. Niedrige Prio (nur Mobile relevant)
mindmatch.js newGame() :332 und techtacular.js newGame() :265: window.scrollTo(0,0) — Desktop-Bodys sind overflow:hidden, mobil scrollt die Seite.
AP R5 — Carry-over: Rest aus Refine 1 + Zusatzfunde der Verifikation
Aus Refine 1 (dort AP 7 / offen):
- Bean Validation:
@Valid+ Constraints auf alle Request-DTOs —BugHunterApiController:17–18,DevLabApiController:37/43,SyntaxSagaApiController:32/38,TechtacularApiController:50/75,CodeEscapeApiController(4 DTOs),NetworkerApiController(2),ServiceClashApiController(2);NeuralNetApiController:14/19Map<String,String>→ typisierte DTOs. - Spring Boot 3.4.4 → aktuelles 3.4.x-Patch (
pom.xml:11), Testlauf. - CSRF: Blanket-Exemption
/api/**(SecurityConfig:46) durch Cookie-basierte Tokens ersetzen. - Web-Layer-Test für
GET /profile/export.
Zusatzfunde (neu):
5. UserController:25/45 bindet die Entity User direkt als @RequestBody ohne Validierung → auf DTO + @Valid umstellen (gehört in die Runde von Punkt 1).
6. 5 Admin-Templates ohne Footer: admin\bughunter.html, admin\bughunter-hunt.html, admin\codeescape.html, admin\codeescape-room.html, admin\codeescape-scenario.html → th:replace="~{fragments/layout :: footer}" ergänzen.
7. HSTS explizit für Prod konfigurieren statt Spring-Default (SecurityConfig:56–57).
8. Optional (unverändert Phase 2): BugHunter progressive Hinweise (Refine 1, AP 4d).
Reihenfolge
- AP R0 Aufräumen → 2. AP R1 Primitives + Migration (theme.css zuerst, dann platform-neural, dann Spiele-CSS, dann Templates) → 3. AP R2 kaputte Light-Stellen → 4. AP R3 Bootstrap → 5. AP R4 Scroll (unabhängig von 1–4, parallelisierbar) → 6. AP R5 Carry-over → 7. Gesamtverifikation. STYLEGUIDE.md (Abschnitt „Glow, Schatten & Radien" → Primitives-Tabelle) und CHANGELOG nach R1–R3 nachziehen.
Verifikation
- Build:
mvn testbleibt grün (54/54); App-Boot gegen Wegwerf-Postgres wie gehabt. - Grep-Gates nach R1:
grep -rnE "0 0 [0-9]+px var\(--" RES\static\css→ Treffer nur noch in den Primitive-Definitionen vontheme.css;grep -rn "text-shadow:0 0" RES\static\css RES\templates→ nur--g-text-Definition;grep -rn "rgba(0,0,0,.5" RES\static\css→ nur Scrims/--g-overlay-Definition. - Visuell (hell UND dunkel): Dashboard (Karten + Hover), Login/Registrierung (insb. Overlay-Panel!), Settings, Progress, Soziales, NeuralNet, alle 9 Spiele (insb. SyntaxSaga-Bühne, CodeEscape-Eingaben, NetWorker-Guide), FinalProtocol-Lernseite + Quiz, A11y-Panel. Dark Mode muss vor/nach R1 visuell deckungsgleich sein (Stichprobe per Screenshot-Vergleich).
- A11y-Kombinationen: Light × Hochkontrast (bleibt bewusst dunkel), Light × Farbenblind (neue dunkle Okabe-Ito-Werte sichtbar, Kontrast-Tool ≥ 4.5:1), Light × Mono.
- Native Controls: Light Mode → helle Scrollbars und helle
<select>-Dropdowns (Chrome + Firefox); mobile Adressleiste folgttheme-color. - Erstbesuch: localStorage leeren, OS auf Light stellen → Seite startet hell; OS Dark → dunkel; Umschalter persistiert weiter.
- Scroll: je SPA-Spiel: langes Board nach unten scrollen → Aktion abschließen → Ergebnis-/Folge-View beginnt oben; ServiceClash-Antwort-Feedback und BugHunter-Zeilenauswahl dürfen nicht nach oben springen; FinalProtocol: langen Lernartikel bis zum Quiz scrollen, Quiz abschließen → Auswertung oben im Viewport; Reload mitten im Spiel → Katalog startet oben; SyntaxSaga/DevLab: Missions-/Taskwechsel startet oben, Fokus springt nicht; NeuralNet-Chat scrollt weiterhin ans Ende.
Offene Punkte (unverändert aus Refine 1, vor Launch)
- Echte Impressumsdaten (
impressum.html:44–52) + §1 Datenschutzerklärung. - Support-/Feedback-Adressen bestätigen (
fragments/layout.html:88–89).
Nachtrag 2026-07-22 — E-Mail-Diagnose (erledigt)
- Der Versand von Bestätigungs- und Reset-Links protokolliert nun korrelierbare Ereignisse: Token-Ausstellung, SMTP-Übergabe begonnen/angenommen/fehlgeschlagen, erneute Anforderung und erfolgreiche Verifikation. Logs enthalten User-/Token-IDs sowie einen gekürzten E-Mail-Fingerprint, niemals den Link oder das Roh-Token.
- Wichtig für die Analyse:
SMTP_SUBMISSION_ACCEPTEDbedeutet nur, dass der konfigurierte SMTP-Server die Nachricht angenommen hat. Spamfilter, Bounces und die finale Postfachzustellung müssen zusätzlich im Mailserver bzw. über DSN geprüft werden. - Der Registrierungsabschluss meldet keinen Versand-Erfolg mehr, falls der gerade
angelegte Benutzer beim Versand nicht geladen werden kann oder bereits als bestätigt
vorliegt; der Grund erscheint als
VERIFICATION_SKIPPEDim Betriebslog.