# Centralized Error Handling Architecture
**Project:** KROW Workforce Mobile App

## 1. Executive Summary
We have implemented a **Centralized Error Handling System** that ensures the entire application (Staff & Client) handles errors consistently, reliably, and with full localization support. 

Instead of writing error handling code in every single feature (which leads to bugs and inconsistent messages), we rely on a global safety net that catches **Network Failures**, **Server Errors (500)**, **Not Found Errors (404)**, and **Business Logic Violations** automatically.

### Key Benefits
*   **Safety:** The app never crashes due to unhandled API errors.
*   **Consistency:** A network error looks the same in "Shifts" as it does in "billing".
*   **Localization:** All error messages are automatically translated (English/Spanish).
*   **Speed:** Developers can build features faster without worrying about `try/catch` blocks.

### Technical Excellence (Status Code Handling)
We don't just catch "errors"; we understand them. The system automatically categorizes and handles:
*   **500 (Server Error):** "Our servers are having a moment. Please try again."
*   **404 (Not Found):** "The resource you're looking for (Shift/Profile) is missing."
*   **401 (Unauthorized):** "Your session expired. Please log in again." (Auto-redirect)
*   **403 (Forbidden):** "You don't have permission to access this area."
*   **503 (Unavailable):** "Maintenance mode or overloaded. Back in a bit!"

---

## 2. Architecture Overview

The error handling flows through three distinct layers, ensuring separation of concerns:

```mermaid
graph TD
    A[Data Layer / Repository] -->|Throws AppException| B[BLoC Layer / State Management]
    B -->|Emits Error Key| C[UI Layer / Presentation]
    
    subgraph "1. Data Layer (The Guard)"
    A -- Captures Exceptions --> D[DataErrorHandler Mixin]
    D -- Maps to --> E[NetworkException, ServerException, etc.]
    end
    
    subgraph "2. BLoC Layer (The Translator)"
    B -- Uses --> F[BlocErrorHandler Mixin]
    F -- Catches AppException --> G[converts to 'errors.category.type']
    end
    
    subgraph "3. UI Layer (The Messenger)"
    C -- Calls --> H["translateErrorKey()"]
    H -- Returns --> I["Localized String (e.g. 'Sin conexión')"]
    end
```

### 1. The Data Layer (The Guard)
**Location:** `packages/data_connect/lib/src/mixins/data_error_handler.dart`

This is where raw exceptions (from Firebase, network, etc.) are caught and converted into **typed exceptions** that the rest of the app can understand.

**Example:**
```dart
mixin DataErrorHandler {
  Future<T> handleDataOperation<T>(Future<T> Function() operation) async {
    try {
      return await operation();
    } on SocketException {
      throw NetworkException('errors.network.no_connection');
    } on HttpException catch (e) {
      if (e.statusCode == 500) throw ServerException('errors.server.internal');
      if (e.statusCode == 404) throw NotFoundException('errors.not_found.resource');
      // ... more mappings
    }
  }
}
```

### 2. The BLoC Layer (The Translator)
**Location:** `packages/core/lib/src/presentation/mixins/bloc_error_handler.dart`

BLoCs use this mixin to catch exceptions and convert them into **error keys** that can be localized.

**Example:**
```dart
mixin BlocErrorHandler {
  String handleError(Object error) {
    if (error is NetworkException) return error.message;
    if (error is ServerException) return error.message;
    return 'errors.unknown';
  }
}
```

### 3. The UI Layer (The Messenger)
**Location:** `packages/core_localization/lib/src/utils/error_translator.dart`

The UI calls `translateErrorKey()` to convert error keys into user-friendly, localized messages.

**Example:**
```dart
String translateErrorKey(String key) {
  final t = LocaleSettings.instance.currentTranslations;
  return t[key] ?? 'An error occurred';
}
```

---

## 3. Real-World Example: Submitting a Tax Form

Let's trace what happens when a user submits Form W-4 with no internet:

1. **User Action:** Clicks "Submit Form"
2. **BLoC:** `FormW4Bloc` calls `submitW4UseCase.call(formData)`
3. **Use Case:** Calls `taxFormsRepository.submitW4(formData)`
4. **Repository (Data Layer):**
   ```dart
   Future<void> submitW4(W4Data data) async {
     return handleDataOperation(() async {
       await _api.submitW4(data); // This throws SocketException
     });
   }
   ```
5. **DataErrorHandler Mixin:** Catches `SocketException` → throws `NetworkException('errors.network.no_connection')`
6. **BLoC:** Catches `NetworkException` → emits `FormW4State.error(errorMessage: 'errors.network.no_connection')`
7. **UI (FormW4Page):**
   ```dart
   BlocListener<FormW4Bloc, FormW4State>(
     listener: (context, state) {
       if (state.status == FormW4Status.error) {
         UiSnackbar.show(
           context,
           message: translateErrorKey(state.errorMessage!),
           type: UiSnackbarType.error,
         );
       }
     },
   )
   ```
8. **translateErrorKey:** Looks up `'errors.network.no_connection'` in `en.i18n.json` → returns `"No internet connection. Please check your network."`
9. **User Sees:** A friendly snackbar with the localized message

---

## 4. Simple Verification Tests (For Non-Developers)

### Test A: The "Tunnel" Test (Network)
1. Open the app to the **Shifts** page.
2. Toggle **Airplane Mode ON**.
3. Pull to refresh the list.
4. **Result:** App shows a gentle `snackbar` error: *"No internet connection"* (or Spanish equivalent). **No Crash.**

### Test B: The "Duplicate Data" Test (Smart Validation)
1. Log in on two devices with the same account (if possible) or simply use a known registered email.
2. Go to the **Sign Up** page.
3. Try to register a new account using that *existing* email.
4. **Result:** App instantly displays specific, helpful feedback: *"An account with this email already exists."* instead of a generic failure.
5. **Why it matters:** Proves the backend and frontend are synced to guide the user, not just block them.

### Test C: The "Crash Proof" Test (The Safety Net)
1. **Scenario:** Even if a developer introduces a bug (like a random exception) or the server returns a 500 status.
2. **Result:** The app catches the unknown error, logs it internally, and shows a safe default message: *"Something went wrong. Please try again."*
3. **Why it matters:** The app never crashes or closes unexpectedly, preserving user trust.

### Test D: The "Language" Test (Localization)
1. Trigger an error (like wrong password).
2. Change phone language to **Spanish**.
3. Trigger the same error.
4. **Result:** Message automatically translates: *"Correo electrónico o contraseña inválidos."*

---

## 5. Comprehensive Testing Guide for Client Verification

This section provides a complete testing checklist to verify that centralized error handling is working correctly across the entire Staff app.

### 🎯 **Testing Objectives**
- Verify all errors are caught and handled gracefully (no crashes)
- Confirm error messages are user-friendly and localized
- Ensure consistent error display using `UiSnackbar`
- Validate that error keys are properly translated

---

### 📱 **Test Suite A: Tax Forms (I-9 & W-4)**

These forms have been fully integrated with centralized error handling and localization.

#### **Test A1: Form Validation Errors**
1. Navigate to **Profile → Documents → Form W-4**
2. Try to proceed to next step **without filling required fields**
3. **Expected Result:** 
   - Validation error appears in a snackbar
   - Message is clear and specific (e.g., "First name is required")
   - Error is localized (Spanish: "Se requiere el nombre")

#### **Test A2: Network Error During Submission**
1. Fill out **Form I-9** completely
2. **Turn off WiFi/Mobile Data**
3. Click **Submit Form**
4. **Expected Result:**
   - Snackbar shows: "No internet connection. Please check your network."
   - Spanish: "Sin conexión a internet. Verifica tu red."
   - Form data is NOT lost

#### **Test A3: Server Error Simulation**
1. Fill out **Form W-4**
2. If backend is accessible, trigger a 500 error
3. **Expected Result:**
   - Snackbar shows: "Our servers are having issues. Please try again."
   - Spanish: "Nuestros servidores tienen problemas. Inténtalo de nuevo."

#### **Test A4: Language Switching**
1. Navigate to **Form I-9**
2. Trigger any error (validation or network)
3. Note the error message
4. **Change device language to Spanish** (Settings → Language)
5. Trigger the same error
6. **Expected Result:**
   - Error message appears in Spanish
   - All form labels and hints are also in Spanish

---

### 📱 **Test Suite B: Shifts & Availability**

#### **Test B1: Network Error on Shifts Page**
1. Navigate to **Shifts** tab
2. **Enable Airplane Mode**
3. Pull to refresh
4. **Expected Result:**
   - Snackbar: "No internet connection"
   - No crash or blank screen
   - Previous data (if any) remains visible

#### **Test B2: Shift Not Found (404)**
1. If possible, try to access a deleted/non-existent shift
2. **Expected Result:**
   - Snackbar: "Shift not found"
   - User is redirected back to shifts list

---

### 📱 **Test Suite C: Profile & Authentication**

#### **Test C1: Session Expiry (401)**
1. Let the app sit idle for extended period (or manually invalidate token)
2. Try to perform any action (update profile, submit form)
3. **Expected Result:**
   - Snackbar: "Your session has expired. Please log in again."
   - App automatically redirects to login screen

#### **Test C2: Profile Update Errors**
1. Navigate to **Profile → Personal Info**
2. Try to update with invalid data (e.g., invalid email format)
3. **Expected Result:**
   - Validation error in snackbar
   - Specific message about what's wrong

---

### 📱 **Test Suite D: Payments & Bank Account**

#### **Test D1: Bank Account Addition Error**
1. Navigate to **Profile → Bank Account**
2. Try to add account with invalid routing number
3. **Expected Result:**
   - Snackbar shows validation error
   - Error is localized

#### **Test D2: Payment History Network Error**
1. Navigate to **Payments** tab
2. **Turn off internet**
3. Try to load payment history
4. **Expected Result:**
   - Snackbar: "No internet connection"
   - No crash

---

### 📱 **Test Suite E: Clock In & Attendance**

#### **Test E1: Clock In Network Error**
1. Navigate to **Clock In** tab
2. **Disable network**
3. Try to clock in
4. **Expected Result:**
   - Snackbar: "No internet connection"
   - Clock in action is blocked until network returns

---

### 🌐 **Test Suite F: Localization Verification**

#### **Test F1: English Error Messages**
With device language set to **English**, verify these error keys translate correctly:

| Scenario | Expected English Message |
|----------|-------------------------|
| No internet | "No internet connection. Please check your network." |
| Server error (500) | "Our servers are having issues. Please try again." |
| Not found (404) | "The requested resource was not found." |
| Unauthorized (401) | "Your session has expired. Please log in again." |
| Validation error | Specific field error (e.g., "Email is required") |

#### **Test F2: Spanish Error Messages**
With device language set to **Español**, verify these error keys translate correctly:

| Scenario | Expected Spanish Message |
|----------|-------------------------|
| No internet | "Sin conexión a internet. Verifica tu red." |
| Server error (500) | "Nuestros servidores tienen problemas. Inténtalo de nuevo." |
| Not found (404) | "No se encontró el recurso solicitado." |
| Unauthorized (401) | "Tu sesión ha expirado. Inicia sesión nuevamente." |
| Validation error | Error específico del campo |

---

### ✅ **Success Criteria**

The centralized error handling is working correctly if:

1. **No Crashes**: App never crashes due to network/server errors
2. **Consistent Display**: All errors appear in `UiSnackbar` with same styling
3. **User-Friendly**: Messages are clear, specific, and actionable
4. **Localized**: All errors translate correctly to Spanish
5. **Graceful Degradation**: App remains usable even when errors occur
6. **Data Preservation**: Form data is not lost when errors happen

---

### 🐛 **What to Report if Tests Fail**

If any test fails, please report:
1. **Which test** (e.g., "Test A2: Network Error During Submission")
2. **What happened** (e.g., "App crashed" or "Error showed in English despite Spanish language")
3. **Screenshot** of the error (if visible)
4. **Steps to reproduce**

---

### 🔧 **Quick Debug Commands**

For developers debugging error handling:

```dart
// Test error translation directly
print(translateErrorKey('errors.network.no_connection'));
print(translateErrorKey('errors.server.internal'));
print(translateErrorKey('errors.not_found.shift'));

// Test in Spanish
LocaleSettings.setLocale(AppLocale.es);
print(translateErrorKey('errors.network.no_connection'));
```

---

## 6. Code Locations (Reference)
*   **Exceptions:** `packages/domain/lib/src/exceptions/app_exception.dart`
*   **Data Mixin:** `packages/data_connect/lib/src/mixins/data_error_handler.dart`
*   **Bloc Mixin:** `packages/core/lib/src/presentation/mixins/bloc_error_handler.dart`
*   **Translator:** `packages/core_localization/lib/src/utils/error_translator.dart`
*   **Strings:** `packages/core_localization/lib/src/l10n/*.i18n.json`
