Fehlerbehandlung und Nachrichten-Normalisierung

Wie PayCal Fehlerberichte über alle Frontend-Module hinweg standardisiert, damit Nutzer aussagekräftiges, sicheres und konsistentes Feedback erhalten, ohne sensible Details offenzulegen.

Überblick und Zweck

Wenn Nutzer Fehler sehen, verdienen sie klare Rückmeldungen darüber, was passiert ist und wie es behoben werden kann. Rohe Backend-Fehlermeldungen müssen normalisiert werden, um:

  • Rauschen zu entfernen: Redundante "Error:"-Präfixe und Leerraum bereinigen
  • Lecks zu verhindern: Sicherstellen, dass sensible Implementierungsdetails niemals den Nutzer erreichen
  • Fallbacks bereitzustellen: Sichere Meldungen anzeigen, wenn Fehler leer oder fehlerhaft sind
  • Konsistenz sicherzustellen: Dieselbe Logik auf alle 11+ Frontend-Module anwenden
  • Debugging zu verbessern: Vollständige Fehlerdetails in Phantom Wing protokollieren, während Nutzern sichere Zusammenfassungen gezeigt werden

Das Problem: Generische vs. aussagekräftige Fehler

Vor der Standardisierung verwendeten PayCal-Module ad-hoc Fehlerbehandlung:

// ❌ SCHLECHT: Gibt den rohen Fehler preis, dupliziert Logik
PC.showToast(error?.message || 'Import fehlgeschlagen.');
PW.error(`Import fehlgeschlagen: ${error.message}`);

Probleme mit diesem Ansatz:

  • Nutzer sehen verwirrende Rohmeldungen wie "ECONNREFUSED: Verbindung verweigert"
  • Jedes Modul implementiert seine eigene Fallback-Logik unabhängig
  • Kein konsistentes Abschneiden von Leerraum oder Entfernen von Präfixen
  • Leere Fehlermeldungen können in der UI als "undefined" erscheinen

Die Lösung: Standardisierter Fehler-Resolver

Alle PayCal-Frontend-Module verwenden jetzt eine einheitliche Resolver-Funktion, die Fehlermeldungen normalisiert:

// ✅ GUT: Normalisiert, konsistent, sicher
const resolveThrownMessage = (error, fallbackMessage) => {
  const raw = typeof error?.message === 'string' 
    ? error.message 
    : String(error || '');
  const normalized = raw.replace(/^Error:\s*/i, '').trim();
  return normalized !== '' ? normalized : fallbackMessage;
};

Verwendung:

// In Catch-Blöcken über Module hinweg
try {
  await updateProfile(data);
} catch (error) {
  const message = resolveThrownMessage(error, 'Profil konnte nicht aktualisiert werden.');
  PC.showToast(message, 'error');  // Nutzer sieht aussagekräftiges Feedback
  PW.error(message);                // Für Debugging protokolliert
}

Implementierungsumfang

Stand April 2026 wurde dieses standardisierte Fehlerbehandlungsmuster auf 11 Frontend-Module mit etwa 40+ normalisierten Catch-Blöcken angewendet:

Authentifizierung und Einstellungen (7 Module)

  • html/js/auth-recovery/index.php (4 catches)
  • html/js/signin/index.php (2 catches)
  • html/js/signin/verification-reminder.js (2 catches)
  • html/js/signin/verification-status-banner.js (1 catch)
  • html/js/settings/index.php (8+ catches)

Core- und Datenmodule (4 Module)

  • html/js/core/network.js (3 catches)
  • html/js/core/index.php (5 catches)
  • html/js/core/billing.js (5 catches)
  • html/js/earnings/index.php (4 catches)

Hochwertige Module (10+ Catch-Punkte):

  • html/js/organizations/index.php - Organisationsverwaltung, Zugriffsanfragen, Audit-Trails (19+ catches)
  • html/js/sites/index.php - Site CRUD, Einnahmen, Wiederherstellung verwaister Arbeit (10+ catches)
  • html/js/calendar/calendar.js - Day-Entry-Operationen, Copy/Paste/Löschen (2 catches)

Fehlerkategorien und Behandlungsmuster

Der Resolver wird konsistent über mehrere Fehlerkategorien angewendet:

1. Netzwerkanforderungsfehler

// Netzwerkmodul: HTTP-Fehler, Timeouts, Verbindungsprobleme
async function deleteResource(ep, id) {
  try {
    // ...fetch-Logik...
  } catch (error) {
    const resolved = resolveThrownMessage(error, 'Netzwerkfehler');
    const msg = `[deleteResource] ${resolved}`;
    PW.error(msg);
    throw new Error(msg);
  }
}

2. API-Antwortverarbeitung

// Billing/Settings: Server gab Fehlermeldung in der Nutzlast zurück
try {
  const response = await fetch('/api/v1/billing/subscription');
  const payload = await response.json();
  if (!response.ok) {
    throw new Error(payload?.message || 'Abrechnungsstatus konnte nicht geladen werden.');
  }
} catch (error) {
  const resolved = resolveThrownMessage(error, 'Abrechnungsstatus konnte nicht geladen werden.');
  setScreenReaderStatus(resolved);
}

3. UI-Fehler bei Operationen

// Calendar/Organizations: Nutzerinitiierte Aktionen (Einfügen, Löschen, Aktualisieren)
button.addEventListener('click', async () => {
  try {
    await performAction();
    PC.showToast('Erfolg!', 'save');
  } catch (error) {
    const message = resolveThrownMessage(error, 'Aktion fehlgeschlagen. Bitte erneut versuchen.');
    PC.showToast(message, 'error');
  }
});

4. Asynchrone Initialisierung

// Core-Module: Start- oder abhängige Initialisierungsfehler
try {
  NavigationToggle.init();
} catch (err) {
  const resolved = resolveThrownMessage(err, 'Navigation initialisierung fehlgeschlagen');
  PW.warn(resolved);  // Protokolliert, blockiert die Seite aber nicht
}

Sicherheitsaspekte

Die Normalisierung von Fehlermeldungen schützt Privatsphäre und Systemintegrität:

  • Keine Datenbankdetails: Backend-Fehler wie "UNIQUE constraint failed on email" werden an der API-Grenze abgefangen und durch benutzerfreundliche Meldungen ersetzt
  • Keine Dateipfade: Systemfehler, die Dateipfade oder Prozessdetails offenlegen, werden entfernt
  • Kein Auth-Leak: Antworten auf Authentifizierungsfehler verraten nie, ob ein Konto existiert (nur zeitlich sichere generische Meldungen)
  • Keine CORS-/Netzwerkdetails: Transportfehler werden auf generische "Verbindungsfehler"-Meldungen normalisiert
  • Sichere Fallbacks: Alle Catcher haben explizite Fallback-Meldungen; "undefined" oder "null" werden nie angezeigt

Vorteile für die Nutzererfahrung

Diese Standardisierung gibt Nutzern klareres, sichereres und konsistenteres Feedback und erleichtert dem Team Support und Debugging.

  • Meldungen sind verständlich, ohne Implementierungsdetails preiszugeben
  • Fallback-Text bleibt sicher, wenn der Backend-Fehler fehlt oder fehlerhaft ist
  • Logging bleibt fürs Debugging nützlich, ohne sensible Werte in die UI zu leaken

Debugging- und Support-Workflow

Der Support kann sich auf einen konsistenten Resolver-Pfad verlassen und bei Bedarf die vollständigen technischen Details in Phantom Wing prüfen.

  • Nutzer sieht normalisierte Meldung
  • Phantom Wing protokolliert den vollständigen Fehlerkontext privat
  • Support kann die Fehlerklasse korrelieren, ohne die rohe Backend-Antwort offenzulegen

Testing und Qualitätssicherung

Die Normalisierungslogik wird durch fokussierte Modultests und Integrationsprüfungen über die wichtigsten Frontend-Flows abgedeckt.

Wartung und zukünftige Erweiterungen

Wenn PayCal weitere Module hinzufügt, sollte dasselbe Resolver-Muster wiederverwendet statt eigener Fehlerformatierung dupliziert werden.

  • Neue Module sollten direkt den gemeinsamen Resolver aufrufen
  • Modulspezifische Fallback-Meldungen sollten kurz und nutzerorientiert bleiben
  • Jede Änderung am Resolver sollte regressionsgetestet werden über repräsentative Flows

Das hält das Verhalten vorhersagbar, wenn die Codebasis wächst, und verhindert eine zweite Generation modulspezifischer Fehlerbehandlung.

Zusammenfassung: Der PayCal-Fehlerbehandlungsstandard

PayCal hat die Fehlerbehandlung im Frontend standardisiert, damit Nutzer sichere, konsistente Meldungen erhalten, während Entwickler die Informationen bekommen, die sie zum Debuggen brauchen.

  • Fehlermeldungen vor der Anzeige normalisieren
  • Implementierungsdetails vor Nutzern verbergen
  • Expliziten Fallback-Text für leere oder fehlerhafte Fehler verwenden
  • Technische Details privat für Support und Debugging protokollieren