From 9d44a265ca786602ea84c1bec9fdc65cbd458ede Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Thu, 19 Mar 2026 14:44:04 +0100 Subject: [PATCH] Refactor backend CORS settings to include default origins and improve error handling in chat services: Introduce dynamic CORS origin handling, enhance RabbitMQ message sending with fallback mechanisms, and update WebSocket service to manage pending messages. Update UI components for better accessibility and responsiveness, including adjustments to dialog and navigation elements. Enhance styling for improved user experience across various components. --- backend/app.js | 10 +- backend/services/chatService.js | 8 +- backend/services/falukantService.js | 8 +- backend/services/webSocketService.js | 59 ++- docs/UI_REDESIGN_PLAN.md | 30 ++ docs/USABILITY_AUDIT_U1.md | 389 +++++++++++++++ docs/USABILITY_CONCEPT.md | 401 +++++++++++++++ frontend/src/assets/styles.scss | 106 +++- frontend/src/components/AppContent.vue | 17 +- frontend/src/components/AppFooter.vue | 97 +++- frontend/src/components/AppHeader.vue | 74 ++- frontend/src/components/AppNavigation.vue | 463 +++++++++++++++--- frontend/src/components/AppSectionBar.vue | 198 ++++++++ frontend/src/components/Character3D.vue | 61 ++- frontend/src/components/DialogWidget.vue | 111 +++-- frontend/src/components/MessageboxWidget.vue | 53 +- frontend/src/components/SettingsWidget.vue | 10 +- .../src/components/falukant/StatusBar.vue | 18 +- .../dialogues/auth/PasswordResetDialog.vue | 31 +- .../src/dialogues/auth/RegisterDialog.vue | 76 ++- .../dialogues/falukant/CreateBranchDialog.vue | 19 +- .../src/dialogues/standard/ErrorDialog.vue | 28 +- .../src/dialogues/standard/MessageDialog.vue | 48 +- frontend/src/i18n/locales/de/falukant.json | 1 + frontend/src/i18n/locales/en/falukant.json | 1 + frontend/src/i18n/locales/es/falukant.json | 1 + frontend/src/main.js | 2 + frontend/src/router/adminRoutes.js | 26 +- frontend/src/router/authRoutes.js | 2 +- frontend/src/router/blogRoutes.js | 6 +- frontend/src/router/falukantRoutes.js | 30 +- frontend/src/router/index.js | 3 +- frontend/src/router/settingsRoutes.js | 12 +- frontend/src/router/socialRoutes.js | 30 +- frontend/src/utils/feedback.js | 67 +++ frontend/src/views/HomeView.vue | 8 +- frontend/src/views/admin/MinigamesView.vue | 210 +++++++- frontend/src/views/admin/UsersView.vue | 137 +++++- .../src/views/admin/falukant/EditUserView.vue | 34 +- frontend/src/views/blog/BlogListView.vue | 117 ++++- frontend/src/views/blog/BlogView.vue | 164 +++++-- frontend/src/views/falukant/BranchView.vue | 60 ++- frontend/src/views/falukant/FamilyView.vue | 83 +++- frontend/src/views/falukant/OverviewView.vue | 248 +++++++++- frontend/src/views/home/LoggedInView.vue | 280 ++++++++--- frontend/src/views/home/NoLoginView.vue | 232 +++++++-- frontend/src/views/minigames/Match3Game.vue | 221 +++++++-- frontend/src/views/personal/CalendarView.vue | 46 +- .../src/views/public/FalukantLandingView.vue | 4 +- .../src/views/public/MinigamesLandingView.vue | 4 +- .../src/views/public/VocabLandingView.vue | 4 +- frontend/src/views/settings/AccountView.vue | 213 ++++++-- frontend/src/views/social/DiaryView.vue | 122 +++-- frontend/src/views/social/ForumTopicView.vue | 74 ++- frontend/src/views/social/ForumView.vue | 184 +++++-- frontend/src/views/social/FriendsView.vue | 107 +++- frontend/src/views/social/GalleryView.vue | 146 ++++-- frontend/src/views/social/GuestbookView.vue | 86 +++- frontend/src/views/social/SearchView.vue | 188 ++++--- .../src/views/social/VocabChapterView.vue | 202 ++++++-- .../src/views/social/VocabCourseListView.vue | 43 +- frontend/src/views/social/VocabCourseView.vue | 108 +++- .../src/views/social/VocabLanguageView.vue | 112 ++++- .../src/views/social/VocabNewLanguageView.vue | 151 ++++-- .../src/views/social/VocabSubscribeView.vue | 94 +++- .../src/views/social/VocabTrainerView.vue | 313 ++++++++++-- frontend/vite.config.js | 34 +- 67 files changed, 5426 insertions(+), 1099 deletions(-) create mode 100644 docs/USABILITY_AUDIT_U1.md create mode 100644 docs/USABILITY_CONCEPT.md create mode 100644 frontend/src/components/AppSectionBar.vue create mode 100644 frontend/src/utils/feedback.js diff --git a/backend/app.js b/backend/app.js index 6f565fe..ee5d441 100644 --- a/backend/app.js +++ b/backend/app.js @@ -36,10 +36,18 @@ const app = express(); // - LOG_ALL_REQ=1: Logge alle Requests const LOG_ALL_REQ = process.env.LOG_ALL_REQ === '1'; const LOG_SLOW_REQ_MS = Number.parseInt(process.env.LOG_SLOW_REQ_MS || '500', 10); +const defaultCorsOrigins = [ + 'http://localhost:3000', + 'http://localhost:5173', + 'http://127.0.0.1:3000', + 'http://127.0.0.1:5173' +]; const corsOrigins = (process.env.CORS_ORIGINS || process.env.FRONTEND_URL || '') .split(',') .map((origin) => origin.trim()) .filter(Boolean); +const effectiveCorsOrigins = corsOrigins.length > 0 ? corsOrigins : defaultCorsOrigins; +const corsAllowAll = process.env.CORS_ALLOW_ALL === '1'; app.use((req, res, next) => { const reqId = req.headers['x-request-id'] || (crypto.randomUUID ? crypto.randomUUID() : crypto.randomBytes(8).toString('hex')); @@ -61,7 +69,7 @@ const corsOptions = { return callback(null, true); } - if (corsOrigins.length === 0 || corsOrigins.includes(origin)) { + if (corsAllowAll || effectiveCorsOrigins.includes(origin)) { return callback(null, true); } diff --git a/backend/services/chatService.js b/backend/services/chatService.js index 5d6c59b..fb6f757 100644 --- a/backend/services/chatService.js +++ b/backend/services/chatService.js @@ -145,7 +145,13 @@ class ChatService { }); } if (this.channel && this.amqpAvailable) { - this.channel.sendToQueue(QUEUE, Buffer.from(JSON.stringify(messageBundle))); + try { + this.channel.sendToQueue(QUEUE, Buffer.from(JSON.stringify(messageBundle))); + } catch (error) { + console.warn('[chatService] sendToQueue fehlgeschlagen, Queue-Bridge vorübergehend deaktiviert:', error.message); + this.channel = null; + this.amqpAvailable = false; + } } } diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index 77d4576..f2ea61b 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -389,6 +389,8 @@ class FalukantService extends BaseService { one: { min: 50, max: 5000 }, all: { min: 400, max: 40000 } }; + static WOOING_PROGRESS_TARGET = 70; + static WOOING_GIFT_COOLDOWN_MS = 30 * 60 * 1000; static HEALTH_ACTIVITIES = [ { tr: "barber", method: "healthBarber", cost: 10 }, { tr: "doctor", method: "healthDoctor", cost: 50 }, @@ -3311,8 +3313,8 @@ class FalukantService extends BaseService { order: [['createdAt', 'DESC']], limit: 1 }); - if (lastGift && (lastGift.createdAt.getTime() + 3_600_000) > Date.now()) { - const retryAt = new Date(lastGift.createdAt.getTime() + 3_600_000); + if (lastGift && (lastGift.createdAt.getTime() + FalukantService.WOOING_GIFT_COOLDOWN_MS) > Date.now()) { + const retryAt = new Date(lastGift.createdAt.getTime() + FalukantService.WOOING_GIFT_COOLDOWN_MS); const err = new PreconditionError('tooOften'); err.meta = { retryAt: retryAt.toISOString() }; throw err; @@ -3381,7 +3383,7 @@ class FalukantService extends BaseService { async checkProposalProgress(relation) { const { nextStepProgress } = relation; - if (nextStepProgress >= 100) { + if (nextStepProgress >= FalukantService.WOOING_PROGRESS_TARGET) { const engagedStatus = await RelationshipType.findOne({ where: { tr: 'engaged' } }); await relation.update({ nextStepProgress: 0, relationshipTypeId: engagedStatus.id }); const user = await User.findOne({ diff --git a/backend/services/webSocketService.js b/backend/services/webSocketService.js index 636b864..589a05b 100644 --- a/backend/services/webSocketService.js +++ b/backend/services/webSocketService.js @@ -4,10 +4,50 @@ import amqp from 'amqplib/callback_api.js'; const RABBITMQ_URL = process.env.AMQP_URL || 'amqp://localhost'; const QUEUE = 'chat_messages'; +const MAX_PENDING_MESSAGES = 500; + +function routeMessage(io, message) { + if (!message || typeof message !== 'object') return; + + if (message.socketId) { + io.to(message.socketId).emit('newMessage', message); + return; + } + if (message.recipientSocketId) { + io.to(message.recipientSocketId).emit('newMessage', message); + return; + } + if (message.roomId) { + io.to(String(message.roomId)).emit('newMessage', message); + return; + } + if (message.room) { + io.to(String(message.room)).emit('newMessage', message); + return; + } + + io.emit('newMessage', message); +} export function setupWebSocket(server) { const io = new Server(server); let channel = null; + let pendingMessages = []; + + const flushPendingMessages = () => { + if (!channel || pendingMessages.length === 0) return; + const queued = pendingMessages; + pendingMessages = []; + for (const message of queued) { + try { + channel.sendToQueue(QUEUE, Buffer.from(JSON.stringify(message))); + } catch (err) { + console.warn('[webSocketService] Flush fehlgeschlagen, Nachricht bleibt im Fallback:', err.message); + pendingMessages.unshift(message); + break; + } + } + }; amqp.connect(RABBITMQ_URL, (err, connection) => { if (err) { @@ -36,8 +76,9 @@ export function setupWebSocket(server) { channel.consume(QUEUE, (msg) => { if (!msg) return; const message = JSON.parse(msg.content.toString()); - io.emit('newMessage', message); + routeMessage(io, message); }, { noAck: true }); + flushPendingMessages(); }); }); @@ -46,11 +87,21 @@ export function setupWebSocket(server) { socket.on('newMessage', (message) => { if (channel) { - channel.sendToQueue(QUEUE, Buffer.from(JSON.stringify(message))); - return; + try { + channel.sendToQueue(QUEUE, Buffer.from(JSON.stringify(message))); + } catch (err) { + console.warn('[webSocketService] sendToQueue fehlgeschlagen, nutze In-Memory-Fallback:', err.message); + channel = null; + } } - io.emit('newMessage', message); + if (!channel) { + pendingMessages.push(message); + if (pendingMessages.length > MAX_PENDING_MESSAGES) { + pendingMessages = pendingMessages.slice(-MAX_PENDING_MESSAGES); + } + return; + } }); socket.on('disconnect', () => { diff --git a/docs/UI_REDESIGN_PLAN.md b/docs/UI_REDESIGN_PLAN.md index 8a9c36d..e0fde69 100644 --- a/docs/UI_REDESIGN_PLAN.md +++ b/docs/UI_REDESIGN_PLAN.md @@ -1,5 +1,16 @@ # UI Redesign Plan +## Status + +- Prioritaet 1 ist umgesetzt. +- Prioritaet 2 ist umgesetzt. +- Phase 3 ist abgeschlossen. +- Phase 4 ist abgeschlossen. +- Phase 5 ist abgeschlossen. +- Das Redesign ist damit insgesamt abgeschlossen. +- Optionaler technischer Nachlauf: +- weiterer Performance-Feinschliff rund um den separaten three-Chunk + ## Ziel Das Frontend von YourPart soll visuell und strukturell modernisiert werden, ohne die bestehende Funktionsbreite zu verlieren. Der Fokus liegt auf einem klareren Designsystem, besserer Informationshierarchie, konsistenter Navigation, responsiver Nutzung und einer deutlich hochwertigeren Wahrnehmung auf Startseite, Community-Bereichen und Spiele-/Lernseiten. @@ -138,11 +149,23 @@ Aktueller Stand aus dem Code: - Danach Vokabeltrainer-Landing/Kernseiten. - Danach Falukant- und Minigame-Einstiege. +Aktueller Stand: + +- abgeschlossen +- umgesetzt fuer Home, Blogs, zentrale Social-/Community-Flaechen, Vokabeltrainer-Kernseiten, Kalender und zentrale Falukant-Einstiege +- Restpunkte in tieferen Vokabel-, Minigame-, Settings- und Admin-Ansichten sind nachgezogen + ### Phase 4: Tiefere Produktbereiche - Sekundaere Ansichten und Admin-Bereiche nachziehen. - Visuelle Altlasten in Randbereichen bereinigen. +Aktueller Stand: + +- abgeschlossen +- zentrale Produktbereiche, tiefere Community-/Vokabel-/Kalender-Ansichten sowie zentrale Falukant-Einstiege und Dialog-Basis sind modernisiert +- verbleibende Rand- und Spezialansichten aus Settings, Admin und Minigames sind visuell angeglichen + ### Phase 5: QA und Verfeinerung - Responsive Review. @@ -150,6 +173,13 @@ Aktueller Stand aus dem Code: - Performance-Pruefung auf unnötige visuelle Last. - Konsistenz-Check ueber das gesamte Produkt. +Aktueller Stand: + +- abgeschlossen +- globale Bewegungsreduktion, verbesserte Fokusfuehrung und Tastaturzugang in der Hauptnavigation umgesetzt +- Build-Chunking verbessert; Haupt-Chunk bereits reduziert +- 3D-Runtime in Character3D auf Lazy-Loading umgestellt; verbleibende Warnung betrifft den separaten three-Chunk selbst + ## Empfohlene technische Arbeitspakete ### Paket A: Design Tokens diff --git a/docs/USABILITY_AUDIT_U1.md b/docs/USABILITY_AUDIT_U1.md new file mode 100644 index 0000000..a4b3d13 --- /dev/null +++ b/docs/USABILITY_AUDIT_U1.md @@ -0,0 +1,389 @@ +# UX Audit U1 + +## Ziel + +Dieser Audit bildet Phase U1 des Bedienbarkeitskonzepts ab. Er dient als priorisierte Arbeitsgrundlage fuer die eigentliche UX-Ueberarbeitung. + +Untersucht wurden: + +- Shell und Navigation +- Einstieg ohne Login +- Registrierung/Login +- Forum +- Vokabeltrainer +- Falukant +- Admin +- Match3/Minigames + +## Bewertungslogik + +- `P1`: blockiert Kernnutzung oder fuehrt sehr leicht zu Fehlbedienung +- `P2`: verlangsamt oder verkompliziert Kernnutzung merklich +- `P3`: Konsistenz-, Lesbarkeits- oder Komfortproblem +- `P4`: Feinschliff + +## Gepruefte Hauptaufgaben + +1. Einloggen und Einstieg verstehen +2. Registrieren +3. Forum finden, Thema erstellen und lesen +4. Vokabelsprache finden, anlegen, abonnieren und lernen +5. Falukant-Status erfassen und Folgeaktion auswaehlen +6. Admin-Nutzer oder Match3-Daten bearbeiten +7. Match3 starten, pausieren und Kampagnenstatus verstehen + +## Ergebnisuebersicht + +- P1: 4 Punkte +- P2: 11 Punkte +- P3: 13 Punkte +- P4: 6 Punkte + +## P1-Probleme + +### P1-1: Historische innere Scrollkonzepte in Teilbereichen + +Bereiche: + +- Falukant +- Admin +- Minigames + +Beobachtung: + +- Mehrere Views arbeiten weiterhin mit eigenen `contenthidden/contentscroll`-Strukturen innerhalb des bereits scrollbaren App-Contents. +- Das fuehrt zu falschen Sticky-Bezuegen, abgeschnittenen Bereichen und inkonsistenter Scrolllogik. + +Risiko: + +- Nutzer verlieren Orientierung. +- statische Leisten oder Footer/Header verhalten sich unerwartet. + +Empfehlung: + +- alle View-internen Scrollcontainer systematisch inventarisieren +- entscheiden, welche Bereiche echte lokale Scrollflaechen brauchen und welche komplett auf die Shell-Scrolllogik gehen + +### P1-2: Fehler- und Erfolgsfeedback ist nicht konsistent genug + +Bereiche: + +- Auth +- Settings +- Admin +- Vokabeltrainer + +Beobachtung: + +- Mischung aus `alert`, MessageDialog, ErrorDialog, DialogWidget-internem Feedback und stillen `console.error`-Pfaden. +- Beispiel: [RegisterDialog.vue](/mnt/share/torsten/Programs/YourPart3/frontend/src/dialogues/auth/RegisterDialog.vue) nutzt fehleranfaellig `errrorDialog` statt eines klar vereinheitlichten Feedbackpfads. + +Risiko: + +- Nutzer verstehen nicht sicher, ob eine Aktion fehlgeschlagen ist oder erfolgreich war. +- Fehler werden in einzelnen Flows inkonsistent oder gar nicht sichtbar. + +Empfehlung: + +- gemeinsames Feedbacksystem definieren +- `success`, `warning`, `error`, `info`, `loading` als einheitliche Muster durchziehen + +### P1-3: Formvalidierung erfolgt oft zu spaet oder zu unsichtbar + +Bereiche: + +- Registrierung +- Account-Settings +- Admin +- Falukant-Formulare + +Beobachtung: + +- viele Formulare validieren erst beim Absenden +- Feldfehler sitzen selten direkt am Eingabepunkt +- Pflichtlogik ist nicht durchgaengig erkennbar + +Risiko: + +- hohe Reibung beim Ausfuellen +- Wiederholschleifen und Frust bei laengeren Formularen + +Empfehlung: + +- Validierung naeher ans Feld bringen +- Pflichtfelder, Eingabeformat und Fehltext systematisch sichtbar machen + +### P1-4: Komplexe Arbeitsflaechen haben zu wenig gefuehrte Primaeraktionen + +Bereiche: + +- Falukant +- Admin Match3 + +Beobachtung: + +- Fachflaechen zeigen viele Optionen gleichzeitig, ohne klare Priorisierung. +- Beispiel: [MinigamesView.vue](/mnt/share/torsten/Programs/YourPart3/frontend/src/views/admin/MinigamesView.vue) ist funktionsreich, aber als Bearbeitungsfluss kaum gefuehrt. + +Risiko: + +- Nutzer verstehen den naechsten sinnvollen Schritt nicht. +- Bedienfehler in fachlich dichten Bereichen steigen. + +Empfehlung: + +- pro komplexer View den eigentlichen Arbeitsfluss definieren +- Primaeraktionen, Sekundaeraktionen und Expertenaktionen sichtbarer trennen + +## P2-Probleme + +### P2-1: Hauptnavigation ist funktional, aber noch nicht ausreichend auf Aufgaben priorisiert + +Beobachtung: + +- Navigation ist technisch konsistenter als vorher, aber die inhaltliche Priorisierung der Menuepunkte ist noch stark historisch gewachsen. +- Der Unterschied zwischen Kernzielen und Tiefenfunktionen ist nicht deutlich genug. + +Empfehlung: + +- Menueaufbau gegen echte Nutzungsszenarien pruefen +- seltene Spezialpunkte staerker entlasten + +### P2-2: Login-Einstieg ist reich an Inhalt, aber nicht maximal fokussiert + +Beobachtung: + +- [NoLoginView.vue](/mnt/share/torsten/Programs/YourPart3/frontend/src/views/home/NoLoginView.vue) erzaehlt Produkt und Zugang parallel. +- Fuer Erstnutzer ist die Seite informativ, aber die eigentliche Primaerhandlung konkurriert mit vielen Begleitinhalten. + +Empfehlung: + +- Zugangspfad noch klarer vom Story-Bereich trennen +- Login, Registrierung und Passwort-Reset als zusammenhaengenden Entscheidungsraum denken + +### P2-3: Registrierung ist bedienbar, aber noch nicht robust genug gefuehrt + +Beobachtung: + +- [RegisterDialog.vue](/mnt/share/torsten/Programs/YourPart3/frontend/src/dialogues/auth/RegisterDialog.vue) ist funktional, aber nutzt wenig Hilfetext, kaum Inline-Validierung und schwer lesbare Fehlerpfade. + +Empfehlung: + +- Feldgruppen strukturieren +- Passwortlogik und Sprachwahl klarer erklaeren +- Fehler am Feld statt nur global rueckmelden + +### P2-4: Forum hat guten Einstieg, aber zu wenig Orientierung im Schreiben-und-Lesen-Wechsel + +Beobachtung: + +- [ForumView.vue](/mnt/share/torsten/Programs/YourPart3/frontend/src/views/social/ForumView.vue) mischt Themenliste und Neuerstellung in einem einfachen Toggle. +- Es fehlt eine staerkere Fuehrung, wann man lesen und wann man schreiben soll. + +Empfehlung: + +- Schreibmodus staerker vom Lesemodus absetzen +- Entwurf, Abbruch und Rueckkehr klarer machen + +### P2-5: Vokabeltrainer ist funktional breit, aber als Lernpfad noch nicht klar genug + +Beobachtung: + +- Anlegen, Abonnieren, Kapitel, Kurs, Lektion und Uebung sind einzeln verbessert, bilden aber noch keinen vollkommen klaren End-to-End-Lernpfad. + +Empfehlung: + +- Informationsarchitektur entlang von: +- entdecken +- beitreten +- lernen +- ueben +- bearbeiten + +### P2-6: Falukant ist visuell stark, aber in taeglichen Routineablaeufen noch nicht effizient genug + +Beobachtung: + +- Statusleiste und Einstiege sind besser, aber Arbeitsablaeufe ueber mehrere Unterseiten bleiben kognitiv schwer. + +Empfehlung: + +- Top-5-Routinen definieren +- dafuer direkte Folgeaktionen aus Status und Uebersichten anbieten + +### P2-7: Admin-Flaechen haben zu wenig gemeinsame Bedienlogik + +Beobachtung: + +- einzelne Admin-Seiten sind moderner, aber Such-, Editier- und Speichermuster unterscheiden sich weiterhin. + +Empfehlung: + +- gemeinsames Admin-Muster fuer Suche, Detailansicht, Editieren und Speichern definieren + +### P2-8: Match3 hat gute Spieloberflaeche, aber Meta-Interaktion ist noch zu verstreut + +Beobachtung: + +- Spielstatus, Levelbeschreibung, Statistiken und Steuerung konkurrieren um Aufmerksamkeit. + +Empfehlung: + +- klare Prioritaet: +- Spielbrett +- aktuelles Ziel +- verbleibende Zuege +- Meta-Infos nur sekundär + +### P2-9: Rueckwege sind nicht ueberall gleich gut sichtbar + +Bereiche: + +- Vokabel-Unterseiten +- Forum-Themen +- Falukant-Unterseiten +- Admin-Details + +Empfehlung: + +- gemeinsames Rueckwegmuster definieren +- nicht nur einzelne Buttons, sondern konsistente Bereichsorientierung + +### P2-10: Leere Zustände sind nicht systematisch genug + +Beobachtung: + +- teilweise vorhanden, aber sehr uneinheitlich in Ton, Handlungsangebot und Sichtbarkeit. + +Empfehlung: + +- Standard fuer: +- keine Daten +- keine Treffer +- noch nicht gestartet +- keine Berechtigung + +### P2-11: Mobile Nutzbarkeit ist verbessert, aber nicht abschließend entlang echter Kernaufgaben geprüft + +Empfehlung: + +- echter Geräte-/Viewport-Durchgang entlang der Kernszenarien + +## P3-Probleme + +### P3-1: Button-Semantik und Farblogik sind noch nicht vollkommen systematisch + +Beobachtung: + +- globale Buttons sind modernisiert, lokale Altvarianten bestehen weiter. + +### P3-2: Teilweise alte Feld- und Listenmuster in Spezialbereichen + +### P3-3: Headline-Hierarchien sind nicht in allen Ansichten gleich klar + +### P3-4: Dialoginhalte wirken je nach Bereich unterschiedlich dicht + +### P3-5: Tabellen haben uneinheitliche Leselogik und Aktionsplatzierung + +### P3-6: In einigen Bereichen ist unklar, welche Aktion primaer und welche optional ist + +### P3-7: Beta-/Systemhinweise koennen in Teilen ruhiger und weniger redundant werden + +### P3-8: Einige Views nutzen sehr lange vertikale Inhaltsflaechen ohne Zwischenanker + +### P3-9: Inline-Hilfen und Tooltips sind in komplexen Bereichen noch unterentwickelt + +### P3-10: Touch-/Hover-Verhalten ist nicht in allen Spezialviews gleich robust + +### P3-11: Message- und Error-Wording ist noch nicht konsistent + +### P3-12: Manche Dialoge und Formulare sind auf Desktop gut, aber auf enger Breite nur ausreichend + +### P3-13: Such- und Filterbereiche koennten staerker standardisiert werden + +## P4-Punkte + +### P4-1: Mikrointeraktionen in Karten, Listen und Toolbars weiter harmonisieren + +### P4-2: Badge- und Statusdarstellungen semantisch weiter schaerfen + +### P4-3: Fokus- und Hover-Zustaende in Spezialkomponenten weiter angleichen + +### P4-4: Editorbereiche visuell und bedienlogisch weiter vereinheitlichen + +### P4-5: Leichte Textkuerzungen fuer schnellere Scanbarkeit in Hero-Bereichen + +### P4-6: Weitere Feinarbeit an Footer/Fensterleiste in langen Nutzungssessions + +## Bereichsspezifische Kurzbewertung + +### Shell und Navigation + +- deutlich verbessert +- noch offen: inhaltliche Priorisierung, Rueckwege, Endabnahme kleiner Screens + +### Einstieg ohne Login + +- stark verbessert +- noch offen: Zugangspfad fokussierter gegen Story-Inhalt absetzen + +### Registrierung/Login + +- funktional ok +- UX-seitig noch zu wenig gefuehrt und rueckmeldearm + +### Forum + +- guter Ueberblick, aber Schreib-/Lesefluss noch nicht ideal getrennt + +### Vokabeltrainer + +- optisch konsistent, aber noch kein vollkommen klarer End-to-End-Lernpfad + +### Falukant + +- visuell stark, fachlich noch der anspruchsvollste Bedienbereich + +### Admin + +- einzelne Ansichten verbessert, gemeinsame Admin-Bedienlogik fehlt noch + +### Minigames + +- Match3 solide, aber Status-/Metaebene kann bedienlogisch weiter fokussiert werden + +## Priorisierte Umsetzung nach U1 + +### Paket U1-A + +- Feedbacksystem vereinheitlichen +- Formularvalidierung sichtbar machen +- Scroll- und Sticky-Logik historischer Sonderfaelle bereinigen + +### Paket U1-B + +- Navigation und Rueckwege nach Aufgaben priorisieren +- Leere Zustände und Systemzustände standardisieren + +### Paket U1-C + +- Vokabeltrainer-Lernpfad schärfen +- Falukant-Routinen entschlacken +- Admin-Bedienmuster vereinheitlichen + +### Paket U1-D + +- Mobile Kernaufgaben-Endabnahme +- Konsistenz-Feinschliff auf P3/P4-Niveau + +## Fazit + +Die App ist gestalterisch deutlich weiter als vor dem Redesign, aber bedienlogisch noch nicht auf demselben Reifegrad. Die größten UX-Hebel liegen nicht mehr in Farben oder Layout, sondern in: + +- konsistentem Feedback +- klareren Aufgabenflüssen +- sichtbarerer Validierung +- entschlackten Fachbereichen +- sauberer Priorisierung von Aktionen + +Phase U1 ist damit abgeschlossen. Die naechste sinnvolle Arbeitsphase ist `U2: Shell, Navigation und Feedback`. diff --git a/docs/USABILITY_CONCEPT.md b/docs/USABILITY_CONCEPT.md new file mode 100644 index 0000000..bba6c75 --- /dev/null +++ b/docs/USABILITY_CONCEPT.md @@ -0,0 +1,401 @@ +# Bedienbarkeitskonzept + +## Ziel + +Die Bedienbarkeit von YourPart soll systematisch verbessert werden, ohne die vorhandene Funktionsbreite oder den neuen UI-Stand wieder aufzubrechen. Der Fokus liegt auf Orientierung, Vorhersagbarkeit, Aufgabenfluss, Fehlertoleranz und effizienter Nutzung auf Desktop und Mobile. + +Das Dokument ist bewusst als Arbeitsgrundlage aufgebaut: + +- Was genau verbessert werden soll +- nach welchen Prinzipien entschieden wird +- in welcher Reihenfolge gearbeitet wird +- woran ein Punkt als erledigt gilt + +## Leitprinzipien + +### 1. Weniger Reibung + +- Haeufige Aufgaben muessen mit moeglichst wenig Entscheidungen und moeglichst wenig Klicks erreichbar sein. +- Sekundaere Funktionen duerfen nicht die Kernaufgabe stoeren. + +### 2. Klare Orientierung + +- Nutzer muessen jederzeit erkennen: +- wo sie sich befinden +- was hier moeglich ist +- was der naechste sinnvolle Schritt ist + +### 3. Konsistente Interaktion + +- Gleiche Interaktionsmuster muessen sich in der gesamten App gleich verhalten. +- Buttons, Dialoge, Tabs, Listen, Formulare und Menues duerfen nicht je Bereich eigene Bedienlogiken entwickeln. + +### 4. Fehlertoleranz statt Bestrafung + +- Fehlbedienungen muessen auffangbar sein. +- Kritische Aktionen brauchen klare Rueckmeldung, wo sinnvoll Bestätigung und wenn moeglich Undo oder sichere Rueckwege. + +### 5. Geschwindigkeit fuer geuebte Nutzer + +- Power-User sollen die App schnell nutzen koennen. +- Haeufige Wege duerfen nicht durch uebermaessige Zwischenschritte ausgebremst werden. + +## Nicht-Ziele + +- Keine komplette Informationsarchitektur-Neuerfindung in einem Schritt. +- Kein sofortiger Umbau jedes Workflows gleichzeitig. +- Keine reine Accessibility-Checklistenarbeit ohne echten Nutzwert. + +## Ausgangsprobleme + +Aus dem aktuellen Projektstand und den bisherigen Umbauten ergeben sich fuer die Bedienbarkeit vor allem diese Problemklassen: + +- Uneinheitliche Bedienmuster zwischen alten und neueren Bereichen +- zu viele tiefe Menues und bereichsspezifische Sonderlogiken +- einige Seiten mit hoher Funktionsdichte, aber schwacher Priorisierung +- Mischformen aus statischen Shell-Bereichen und historischen inneren Scrollkonzepten +- lokale Alt-Dialoge und Formmuster mit uneinheitlicher Rueckmeldung +- Desktop-zentrierte Denkweise in Teilen von Admin, Minigames und Falukant + +## Zielbild + +Am Ende soll die App folgendes Nutzungsgefuehl bieten: + +- Shell, Navigation und Dialoge verhalten sich vorhersagbar +- jede Hauptseite zeigt klar eine Primaeraufgabe und erkennbare Sekundaeraufgaben +- Formulare fuehren sauber durch Eingabe, Validierung und Abschluss +- Statusaenderungen und Systemreaktionen sind sichtbar und verstaendlich +- Falukant, Community, Blog und Lernen bleiben fachlich unterschiedlich, aber bedienbar aus einem Guss + +## Arbeitsbereiche + +### Bereich A: Navigation und Orientierung + +Ziel: + +- Nutzer finden schneller zum Ziel und verstehen Menuehierarchien besser. + +Arbeitspunkte: + +- Hauptnavigation auf tatsaechliche Primaerbereiche pruefen +- Untermenues auf Redundanzen und Leerpfade pruefen +- aktive Position und Kontext pro Bereich klarer machen +- in tiefen Bereichen Rueckwege, Breadcrumb-artige Hinweise oder Bereichstitel konsistent gestalten +- Schnellzugriffe nur dort einsetzen, wo sie echte Beschleunigung bringen + +Abnahmekriterien: + +- jeder Hauptmenuepunkt hat einen klaren Zweck +- Menuepunkte ohne Untermenue verhalten sich direkt +- tiefe Ansichten haben einen klaren Rueckweg +- Nutzer muessen nicht raten, in welchem Bereich sie sich befinden + +### Bereich B: Seitenhierarchie und Aufgabenfluss + +Ziel: + +- jede Seite hat einen erkennbaren Einstieg, eine Hauptaufgabe und einen lesbaren Aufbau + +Arbeitspunkte: + +- pro View Primaeraktion definieren +- Informationsdichte dort reduzieren, wo gleichrangige Bloecke konkurrieren +- visuelle Prioritaet zwischen Lesen, Auswaehlen, Bearbeiten und Absenden schaerfen +- Tabellen, Listen und Karten jeweils auf ihren eigentlichen Einsatzzweck pruefen + +Abnahmekriterien: + +- Nutzer erkennen in wenigen Sekunden den Zweck einer Seite +- Hauptaktionen sind oberhalb oder in unmittelbarer Naehe des relevanten Inhalts +- Nebenfunktionen dominieren die Seite nicht mehr + +### Bereich C: Formulare und Eingaben + +Ziel: + +- Formulare sollen verstaendlich, fehlertolerant und effizient sein + +Arbeitspunkte: + +- Labels, Hilfetexte, Pflichtfelder und Fehlermeldungen vereinheitlichen +- Validierung naeher an den Eingabepunkt bringen +- unklare Zustandswechsel vermeiden +- Speichern, Abbrechen und gefaehrliche Aktionen konsistent platzieren +- Checkboxen, Radios und Selects auf Lesbarkeit und Trefferflaechen pruefen + +Abnahmekriterien: + +- jeder Eingabefehler ist erkennbar und nachvollziehbar +- Speichern fuehlt sich in allen Bereichen gleich an +- keine Form wirkt wie ein historischer Sonderfall + +### Bereich D: Dialoge, Feedback und Systemstatus + +Ziel: + +- Systemreaktionen muessen sichtbar, verstaendlich und nicht stoerend sein + +Arbeitspunkte: + +- Dialogarten unterscheiden: +- bestaetigend +- informierend +- bearbeitend +- kritisch +- Messagebox/Dialog-Rueckmeldungen vereinheitlichen +- Ladezustaende, Erfolg, Fehler und Leere Zustaende standardisieren +- offene Dialoge und Fensterleiste auf Priorisierung pruefen + +Abnahmekriterien: + +- Nutzer verstehen, was gerade passiert ist oder noch passiert +- kritische Aktionen sind klar markiert +- Modale Interaktionen blockieren nur, wenn es wirklich noetig ist + +### Bereich E: Mobile und kleine Viewports + +Ziel: + +- zentrale Aufgaben muessen auch auf kleineren Screens robust funktionieren + +Arbeitspunkte: + +- Shell mit Header, Navigation, Content und Footer auf reale Nutzungsszenarien pruefen +- Tabellen und breite Steuermasken auf mobile Alternativen oder horizontale Strategien prüfen +- Touch-Ziele und Abstaende angleichen +- Hover-abhaengige Muster fuer Touch absichern + +Abnahmekriterien: + +- Kernaufgaben sind auf Tablet und Smartphone ohne Layoutbruch nutzbar +- keine kritische Funktion ist nur via Hover oder Pixel-Präzision erreichbar + +### Bereich F: Komplexe Produktbereiche + +Ziel: + +- Falukant, Vokabeltrainer, Minigames und Admin sollen fachlich komplex bleiben, aber leichter steuerbar werden + +Arbeitspunkte: + +- Falukant: +- Schnellzugriffsleiste, Tab-Struktur, Statusfeedback und Arbeitsablaeufe priorisieren +- Vokabeltrainer: +- Lernpfad, Bearbeitung, Suche, Uebung und Fortschritt klarer trennen +- Minigames: +- Einstieg, Pause, Statusanzeige und Kampagnenfluss vereinfachen +- Admin: +- Such-, Editier- und Bestaetigungsfluesse entlasten + +Abnahmekriterien: + +- komplexe Bereiche sind ohne Einlernen nicht sofort trivial, aber deutlich besser fuehrend +- wiederkehrende Aktionen sind schneller und sicherer bedienbar + +## Methodik + +### 1. Bedienbarkeits-Audit + +Pro Hauptbereich wird ein kurzer Audit gemacht: + +- Primaeraufgabe der Seite +- haeufigste Nutzeraktion +- groesste Reibung +- groesstes Fehlerrisiko +- mobile Schwachstelle + +Empfohlene Cluster: + +- Shell und Navigation +- Home und Einstieg +- Community/Social +- Blog +- Vokabeltrainer +- Falukant +- Admin +- Minigames +- Dialoge/Formulare + +### 2. Aufgabenorientierte Review-Szenarien + +Die App wird nicht nur nach Komponenten, sondern nach Aufgaben geprueft: + +- registrieren und einloggen +- Profil/Freunde finden +- Forumsthema finden und beantworten +- Vokabelsprache erstellen, abonnieren, lernen +- Falukant-Status pruefen und Folgeaktion ausfuehren +- Admin-Nutzer suchen und aendern +- Match3 starten, pausieren, neu starten + +### 3. Fix-Kategorien + +Alle Probleme werden in vier Kategorien eingeordnet: + +- P1: blockiert oder verwirrt Kernnutzung deutlich +- P2: verlangsamt Nutzung oder erzeugt Fehlbedienung +- P3: stoert Konsistenz oder Lesbarkeit +- P4: Feinschliff ohne unmittelbaren Schaden + +## Umsetzungsphasen + +### Phase U1: Audit und Problemkatalog + +Ergebnis: + +- kompakte Liste realer Bedienprobleme pro Hauptbereich +- priorisiert nach P1 bis P4 + +Arbeit: + +- 1 Durchgang Desktop +- 1 Durchgang kleiner Viewport +- 1 Durchgang fuer Tastatur-/Dialognutzung + +Aktueller Stand: + +- abgeschlossen +- Audit dokumentiert in `docs/USABILITY_AUDIT_U1.md` +- priorisierte Folgephase: `U2 Shell, Navigation und Feedback` + +### Phase U2: Shell, Navigation, Feedback + +Ergebnis: + +- globale Bedienmuster sind konsistent + +Arbeit: + +- Navigation +- Rueckwege +- Fokuslogik +- Dialog-/Feedbacksystem +- Lade- und Leerezustaende + +Aktueller Stand: + +- abgeschlossen +- Shell-Kontextbereich mit Bereichstitel und Rueckweg umgesetzt +- Navigation um klareren Seitenkontext ergaenzt +- zentrales Feedback-API eingefuehrt +- Standard-Feedbackdialoge visuell und technisch vereinheitlicht +- Kernfluesse aus Auth und Settings auf das neue Feedbackmuster umgestellt + +### Phase U3: Formulare und Abschlussfluesse + +Ergebnis: + +- Eingaben, Speichern, Validierung und Rueckmeldung sind vereinheitlicht + +Arbeit: + +- Auth +- Settings +- Admin +- Falukant-Formulare +- Vokabel-Bearbeitungsfluesse + +Aktueller Stand: + +- abgeschlossen +- gemeinsames Formularmuster fuer Hinweise, Fehler und Action-Row eingefuehrt +- Dialogbuttons respektieren Disabled-Zustaende +- Auth-Dialoge, Account-Settings, zentrale Admin-/Falukant-Formulare und Vokabel-Bearbeitungsfluesse auf sichtbarere Validierung und konsistentere Abschlusslogik umgestellt + +### Phase U4: Komplexe Fachbereiche + +Ergebnis: + +- Falukant, Vokabeltrainer, Minigames und Admin sind auf Nutzbarkeit statt nur Funktion geprüft + +Arbeit: + +- Arbeitsablaeufe entlasten +- Primaeraktionen schaerfen +- Informationslast reduzieren + +Aktueller Stand: + +- abgeschlossen +- Vokabeltrainer als Aufgabenhub mit getrennten Bereichen fuer eigene und abonnierte Sprachen +- Falukant-Uebersicht um Routinekarten, verdichtete Kennzahlen und schnellere Folgeaktionen erweitert +- Match3-Spiel um Ziel-/Statusleiste fuer den naechsten sinnvollen Schritt ergaenzt +- Match3-Admin um klaren 3-Schritt-Arbeitsfluss, Formzusammenfassung und sicherere Speicherlogik erweitert + +### Phase U5: Mobile und Endabnahme + +Ergebnis: + +- Kernaufgaben sind auf Standard-Viewports belastbar + +Arbeit: + +- letzte Layoutkorrekturen +- Touch und Fokus +- Abschlussreview entlang echter Nutzerszenarien + +Aktueller Stand: + +- abgeschlossen +- Hauptnavigation auf kleinen Viewports zu einer verlässlich aufklappbaren Mobilnavigation mit Touch-gerechten Zielgroessen umgebaut +- Header und Footer auf kleine Breiten mit stabileren Status- und Linkblöcken angepasst +- Dialoge fuer kleine Viewports auf sichere Maximalgroessen und mobile Button-Stacks begrenzt +- breite Tabellen auf kleinen Screens per horizontalem Scroll-Fallback abgesichert +- globale Touch-Ziele fuer Buttons leicht vergroessert und letzte Shell-Kanten geglaettet + +## Konkreter Arbeitskatalog + +### 1. Shell und Navigation + +- Menuepunkte auf Nutzungsprioritaet sortieren +- Untermenues auf direkte Zielerreichung pruefen +- Bereichskontext pro Seite konsistent machen +- globale Ruecksprunglogik definieren + +### 2. Dialog- und Feedbacksystem + +- Dialogtypen definieren und dokumentieren +- Standard fuer Erfolg, Fehler, Warnung, Leere, Laden festlegen +- Inline-Feedback vor modalem Feedback bevorzugen, wenn kein harter Block noetig ist + +### 3. Formsystem + +- ein gemeinsames Muster fuer Label, Hilfetext, Fehlermeldung, Pflichtfeld +- ein gemeinsames Muster fuer Save/Cancel/Delete +- ein gemeinsames Muster fuer Tabellenfilter und Suchformulare + +### 4. Bereichsreviews + +- Social/Friends/Search/Forum entlang echter Aufgaben pruefen +- Vokabeltrainer entlang des Lernpfads pruefen +- Falukant entlang taeglicher Routinen pruefen +- Admin entlang Such-/Editier-Routinen pruefen +- Minigames entlang Einstieg/Pause/Neustart pruefen + +### 5. Mobile Review + +- Header/Nav/Footer mit realen Hoehen pruefen +- breite Inhalte auf kleine Screens pruefen +- Dialoge und Tabellen fuer Touch pruefen + +## Definition of Done + +Das Bedienbarkeitsprojekt gilt als abgeschlossen, wenn: + +- fuer alle Hauptbereiche ein Audit stattgefunden hat +- P1- und P2-Probleme aus dem Audit abgearbeitet sind +- Navigation, Formulare, Dialoge und Feedback nach gemeinsamen Regeln funktionieren +- Kernaufgaben auf Desktop und kleinem Viewport ohne strukturelle Reibung moeglich sind +- Restpunkte nur noch P3/P4-Feinschliff sind + +## Empfohlene Reihenfolge + +1. Audit ueber Kernaufgaben +2. Shell/Navigation/Feedback +3. Formulare und Abschlusslogik +4. Falukant, Vokabeltrainer, Admin, Minigames +5. Mobile Endabnahme + +## Naechster konkreter Schritt + +Der erste sinnvolle Umsetzungsschritt ist nicht sofort Code, sondern ein kurzer UX-Audit-Durchgang ueber die wichtigsten Aufgabenfluesse. Daraus entsteht ein priorisierter Problemkatalog, auf dessen Basis die Bedienbarkeitsarbeit strukturiert umgesetzt wird. diff --git a/frontend/src/assets/styles.scss b/frontend/src/assets/styles.scss index ff7da05..136a581 100644 --- a/frontend/src/assets/styles.scss +++ b/frontend/src/assets/styles.scss @@ -45,9 +45,9 @@ --space-10: 40px; --space-12: 48px; - --radius-sm: 10px; - --radius-md: 16px; - --radius-lg: 24px; + --radius-sm: 5px; + --radius-md: 8px; + --radius-lg: 12px; --radius-pill: 999px; --shadow-soft: 0 12px 30px rgba(47, 29, 14, 0.08); @@ -118,7 +118,7 @@ span.button { align-items: center; justify-content: center; gap: var(--space-2); - min-height: 42px; + min-height: 44px; padding: 0 18px; border: 1px solid transparent; border-radius: var(--radius-pill); @@ -147,11 +147,23 @@ span.button:active { transform: translateY(0); } +button:disabled, +.button:disabled, +span.button:disabled { + opacity: 0.55; + cursor: not-allowed; + transform: none; + box-shadow: none; +} + button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, -a:focus-visible { +a:focus-visible, +[role="button"]:focus-visible, +[role="menuitem"]:focus-visible, +[tabindex]:focus-visible { outline: 3px solid rgba(120, 195, 138, 0.32); outline-offset: 2px; } @@ -263,11 +275,72 @@ main, overflow: auto; } +.app-content__inner > .contenthidden { + height: auto; + overflow: visible; +} + +.app-content__inner > .contenthidden > .contentscroll { + height: auto; + overflow: visible; +} + .surface-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); box-shadow: var(--shadow-soft); + overflow: hidden; +} + +.form-stack { + display: grid; + gap: 14px; +} + +.form-field { + display: grid; + gap: 8px; +} + +.form-field > label, +.form-field > span:first-child { + font-weight: 600; + color: var(--color-text-secondary); +} + +.form-hint { + font-size: 0.88rem; + color: var(--color-text-muted); +} + +.form-error { + font-size: 0.88rem; + color: var(--color-danger); +} + +.field-error { + border-color: rgba(177, 59, 53, 0.44) !important; + box-shadow: 0 0 0 4px rgba(177, 59, 53, 0.12) !important; +} + +.form-actions-row { + display: flex; + flex-wrap: wrap; + gap: 10px; + justify-content: flex-end; +} + +.button-secondary { + background: rgba(255, 255, 255, 0.86); + color: var(--color-text-primary); + border-color: var(--color-border); + box-shadow: none; +} + +.button-secondary:hover { + background: rgba(255, 255, 255, 0.96); + box-shadow: none; } .link { @@ -338,4 +411,27 @@ main, h2 { font-size: clamp(1.35rem, 5vw, 2rem); } + + .contentscroll table { + display: block; + width: 100%; + overflow-x: auto; + white-space: nowrap; + -webkit-overflow-scrolling: touch; + } +} + +@media (prefers-reduced-motion: reduce) { + html:focus-within { + scroll-behavior: auto; + } + + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } } diff --git a/frontend/src/components/AppContent.vue b/frontend/src/components/AppContent.vue index bf3a45d..aff7d49 100644 --- a/frontend/src/components/AppContent.vue +++ b/frontend/src/components/AppContent.vue @@ -2,6 +2,7 @@
+
@@ -9,14 +10,20 @@ diff --git a/frontend/src/components/AppFooter.vue b/frontend/src/components/AppFooter.vue index 07df752..bc65db2 100644 --- a/frontend/src/components/AppFooter.vue +++ b/frontend/src/components/AppFooter.vue @@ -1,18 +1,31 @@