Error Handling at Message Normalization

Paano sini-standardize ng PayCal ang error reporting sa lahat ng frontend modules upang makatanggap ang users ng meaningful, secure, at consistent error feedback nang hindi nalalantad ang sensitibong details.

Overview at layunin

Kapag may error ang users, dapat malinaw ang feedback kung ano ang nangyari at paano ito aayusin. Kailangang i-normalize ang raw backend error messages para:

  • Alisin ang ingay: tanggalin ang redundant "Error:" prefixes at linisin ang whitespace
  • Pigilan ang leakage: tiyaking hindi umaabot sa user ang sensitive implementation details
  • Magbigay ng fallbacks: magpakita ng safe messages kapag empty o malformed ang errors
  • Panatilihin ang consistency: gamitin ang parehong logic sa lahat ng 11+ frontend modules
  • Pahusayin ang debugging: i-log ang full error details sa Phantom Wing habang safe summaries ang ipinapakita sa users

Ang problema: generic vs. meaningful errors

Bago ang standardization, ad-hoc error handling ang gamit ng PayCal modules:

// ❌ BAD: Exposes raw error, duplicates logic
PC.showToast(error?.message || 'Import failed.');
PW.error(`Import failed: ${error.message}`);

Mga problema sa approach na ito:

  • Nakakakita ang users ng confusing raw messages tulad ng "ECONNREFUSED: Connection refused"
  • May sariling fallback logic ang bawat module
  • Walang consistent whitespace trimming o prefix stripping
  • Maaaring lumabas bilang "undefined" sa UI ang empty error messages

Ang solution: standardized error resolver

Gumagamit na ngayon ang lahat ng PayCal frontend modules ng unified resolver function na nagno-normalize ng error messages:

// ✅ GOOD: Normalized, consistent, safe
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;
};

Usage:

// In catch blocks across modules
try {
  await updateProfile(data);
} catch (error) {
  const message = resolveThrownMessage(error, 'Unable to update profile.');
  PC.showToast(message, 'error');  // User sees meaningful feedback
  PW.error(message);                // Logged for debugging
}

Implementation scope

Noong April 2026, nailapat na ang standardized pattern na ito sa 11 frontend modules na may humigit-kumulang 40+ normalized catch blocks:

Authentication at Settings (7 modules)

  • 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 at Data Modules (4 modules)

  • 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)

High-value modules (10+ catch points):

  • html/js/organizations/index.php - Org management, access requests, audit trails (19+ catches)
  • html/js/sites/index.php - Site CRUD, earnings, orphan work recovery (10+ catches)
  • html/js/calendar/calendar.js - Day-entry operations, copy/paste/delete (2 catches)

Error categories at handling patterns

Consistent na ginagamit ang resolver sa ilang error categories:

1. Network request failures

// Network module: HTTP errors, timeouts, connection issues
async function deleteResource(ep, id) {
  try {
    // ...fetch logic...
  } catch (error) {
    const resolved = resolveThrownMessage(error, 'Network error');
    const msg = `[deleteResource] ${resolved}`;
    PW.error(msg);
    throw new Error(msg);
  }
}

2. API response handling

// Billing/Settings: Server returned error message in payload
try {
  const response = await fetch('/api/v1/billing/subscription');
  const payload = await response.json();
  if (!response.ok) {
    throw new Error(payload?.message || 'Unable to load billing status.');
  }
} catch (error) {
  const resolved = resolveThrownMessage(error, 'Unable to load billing status.');
  setScreenReaderStatus(resolved);
}

3. UI operation failures

// Calendar/Organizations: User-initiated actions (paste, delete, update)
button.addEventListener('click', async () => {
  try {
    await performAction();
    PC.showToast('Success!', 'save');
  } catch (error) {
    const message = resolveThrownMessage(error, 'Action failed. Try again.');
    PC.showToast(message, 'error');
  }
});

4. Async initialization

// Core modules: Startup or dependent initialization failures
try {
  NavigationToggle.init();
} catch (err) {
  const resolved = resolveThrownMessage(err, 'Navigation init failed');
  PW.warn(resolved);  // Logged but doesn't block page
}

Security considerations

Pinoprotektahan ng error message normalization ang user privacy at system integrity:

  • No database details: backend errors tulad ng "UNIQUE constraint failed on email" ay pinapalitan ng user-friendly messages sa API boundary
  • No file paths: tinatanggal ang system errors na naglalantad ng file paths o process details
  • No auth leakage: hindi kailanman inilalantad ng auth failures kung may account o wala
  • No CORS/network details: transport errors ay ginagawang generic connection messages
  • Secure fallbacks: may explicit fallback ang lahat ng catchers; hindi nagpapakita ng "undefined" o "null"

User experience benefits

Nagbibigay ang standardization na ito ng mas malinaw, mas ligtas, at mas consistent na feedback habang pinapadali ang support at debugging.

  • Naiintindihan ang messages nang hindi naglalantad ng implementation detail
  • Safe pa rin ang fallback text kapag missing o malformed ang backend error
  • Useful pa rin ang logging para sa debugging nang hindi nagle-leak ng sensitive values sa UI

Debugging at support workflow

Makakaasa ang support sa consistent resolver path at puwedeng tingnan ang Phantom Wing logs kapag kailangan ang full technical detail.

  • Nakikita ng user ang normalized message
  • Privately nire-record ng Phantom Wing ang full error context
  • Nakokorelate ng support ang issue class nang hindi inilalantad ang raw backend response

Testing at quality assurance

Covered ang normalization logic ng focused module tests at integration checks sa main frontend flows.

Maintenance at future extensions

Habang nagdadagdag ang PayCal ng modules, dapat gamitin muli ang parehong resolver pattern sa halip na mag-duplicate ng custom error formatting.

  • Dapat direktang tawagin ng bagong modules ang shared resolver
  • Dapat concise at user-facing ang module-specific fallback messages
  • Dapat may regression tests sa representative flows ang anumang resolver changes

Pinapanatili nitong predictable ang behavior habang lumalaki ang codebase at iniiwasan ang panibagong generation ng module-specific error handling.

Summary: ang PayCal error-handling standard

Sini-standardize ng PayCal ang frontend error handling para makatanggap ang users ng safe at consistent messages habang nakukuha pa rin ng developers ang kailangan para sa debugging.

  • I-normalize ang error messages bago ipakita
  • Itago ang implementation details mula sa users
  • Gumamit ng explicit fallback text para sa empty o malformed errors
  • I-log privately ang technical detail para sa support at debugging