# Error Handling Guide

This document describes the error handling patterns implemented in the VIP Coordinator application.

## Backend Error Handling

### Global Exception Filters

The backend uses two global exception filters for consistent error responses:

#### 1. HttpExceptionFilter
Handles all HTTP exceptions (4xx, 5xx errors) and formats them consistently.

**Features:**
- Standardized error response format
- Automatic logging with appropriate levels (error/warn/log)
- Request context logging (params, query, body)
- Sensitive data redaction (passwords, tokens, API keys)

**Error Response Format:**
```json
{
  "statusCode": 400,
  "timestamp": "2026-01-25T10:30:00.000Z",
  "path": "/api/v1/events",
  "method": "POST",
  "message": "Validation failed",
  "error": "Bad Request",
  "details": { ... }
}
```

#### 2. AllExceptionsFilter
Catch-all filter for unhandled errors (database errors, runtime exceptions, etc.).

**Features:**
- Catches all non-HTTP exceptions
- Prevents server crashes from unhandled errors
- Logs full stack traces
- Returns 500 Internal Server Error to client
- In development: includes stack trace in response

### Using Exceptions in Controllers/Services

**Example:**
```typescript
import { BadRequestException, NotFoundException } from '@nestjs/common';

// Simple error
throw new NotFoundException('VIP not found');

// Error with details
throw new BadRequestException({
  message: 'Driver has conflicting events',
  conflicts: [
    { id: '123', title: 'Airport Pickup', startTime: '...' }
  ]
});
```

### Logging Best Practices

```typescript
import { Logger } from '@nestjs/common';

export class MyService {
  private readonly logger = new Logger(MyService.name);

  async doSomething() {
    this.logger.log('Starting operation...');
    this.logger.warn('Conflict detected');
    this.logger.error('Operation failed', error.stack);
  }
}
```

## Frontend Error Handling

### ErrorHandler Utility

The `ErrorHandler` class provides centralized error handling for the frontend.

**Location:** `frontend/src/lib/errorHandler.ts`

### Quick Usage

```typescript
import { handleError } from '@/lib/errorHandler';

try {
  await api.createVIP(data);
  toast.success('VIP created successfully');
} catch (error) {
  handleError('VIP Creation', error, 'Failed to create VIP');
}
```

### Advanced Usage

#### Extract Error Message Only
```typescript
import { ErrorHandler } from '@/lib/errorHandler';

try {
  await api.get('/vips');
} catch (error) {
  const message = ErrorHandler.getMessage(error, 'Failed to load VIPs');
  setErrorMessage(message);
}
```

#### Show Toast Only
```typescript
ErrorHandler.showError(error, 'Operation failed');
```

#### Log Only (No Toast)
```typescript
ErrorHandler.log('VIP Fetch', error, { vipId: '123' });
```

#### Check Error Type
```typescript
try {
  await api.updateVIP(id, data);
} catch (error) {
  if (ErrorHandler.isAuthError(error)) {
    // Redirect to login
    navigate('/login');
  } else if (ErrorHandler.isConflict(error)) {
    // Show conflict resolution UI
    const conflicts = ErrorHandler.getConflicts(error);
    setConflicts(conflicts);
  } else {
    ErrorHandler.showError(error);
  }
}
```

### Available Methods

| Method | Description | Example |
|--------|-------------|---------|
| `getMessage(error, fallback?)` | Extract user-friendly message | `const msg = ErrorHandler.getMessage(error)` |
| `showError(error, fallback?)` | Show error toast | `ErrorHandler.showError(error)` |
| `log(context, error, info?)` | Log to console with context | `ErrorHandler.log('API', error, { id })` |
| `handle(context, error, fallback?, info?)` | Log + toast | `ErrorHandler.handle('Save', error)` |
| `isAuthError(error)` | Check if 401/403 | `if (ErrorHandler.isAuthError(error))` |
| `isConflict(error)` | Check if 409 | `if (ErrorHandler.isConflict(error))` |
| `isValidationError(error)` | Check if 400 | `if (ErrorHandler.isValidationError(error))` |
| `getConflicts(error)` | Extract conflicts array | `const conflicts = ErrorHandler.getConflicts(error)` |

### API Client Logging

The axios client automatically logs all requests and responses in development mode.

**Console output format:**
```
[API] → POST /api/v1/vips { data: {...} }
[API] ← 201 POST /api/v1/vips { data: {...} }
[API] ✖ 400 POST /api/v1/events { status: 400, data: {...} }
```

**Error types logged:**
- 401: Authentication required
- 403: Permission denied
- 404: Resource not found
- 409: Conflict (with conflict details)
- 500+: Server error

### Migration Guide

#### Before (Old Pattern)
```typescript
try {
  await api.createVIP(data);
  toast.success('VIP created');
} catch (error: any) {
  console.error('Failed to create VIP:', error);
  toast.error(error.response?.data?.message || 'Failed to create VIP');
}
```

#### After (New Pattern)
```typescript
import { handleError } from '@/lib/errorHandler';

try {
  await api.createVIP(data);
  toast.success('VIP created');
} catch (error) {
  handleError('VIP Creation', error, 'Failed to create VIP');
}
```

**Benefits:**
- ✅ Consistent error messages across app
- ✅ Automatic console logging with context
- ✅ Handles all error types (Axios, Error, unknown)
- ✅ Type-safe error checking
- ✅ Less code duplication

## Common Error Scenarios

### 1. Network Error (Backend Down)
**Backend logs:** None (backend not reachable)
**Frontend logs:** `[API] ✖ Network error - no response received`
**User sees:** Toast: "Network error. Please check your connection."

### 2. Authentication Error (401)
**Backend logs:** `[WARN] [GET] /api/v1/vips - 401 - Unauthorized`
**Frontend logs:** `[API] ✖ 401 GET /api/v1/vips` + warning
**User sees:** Toast: "Authentication required. Please log in again."

### 3. Permission Error (403)
**Backend logs:** `[WARN] [POST] /api/v1/users - 403 - Forbidden resource`
**Frontend logs:** `[API] ✖ 403 POST /api/v1/users` + warning
**User sees:** Toast: "You do not have permission to perform this action."

### 4. Validation Error (400)
**Backend logs:** `[WARN] [POST] /api/v1/events - 400 - Validation failed`
**Frontend logs:** `[API] ✖ 400 POST /api/v1/events` + response data
**User sees:** Toast: "Validation failed: email must be a valid email"

### 5. Conflict Error (409)
**Backend logs:** `[WARN] [POST] /api/v1/events - 409 - Driver has conflicting events`
**Frontend logs:** `[API] ✖ 409 POST /api/v1/events` + conflicts array
**User sees:** Toast: "A conflict occurred. Please check for overlapping schedules."

### 6. Server Error (500)
**Backend logs:** `[ERROR] [GET] /api/v1/vips - 500 - Internal server error` + stack trace
**Frontend logs:** `[API] ✖ 500 GET /api/v1/vips` + error message
**User sees:** Toast: "Server error. Please try again later."

## Best Practices

### ✅ DO

```typescript
// Use handleError for simple cases
try {
  await api.post('/vips', data);
  toast.success('Success');
} catch (error) {
  handleError('VIP Creation', error);
}

// Use ErrorHandler methods for complex cases
try {
  await api.updateEvent(id, data);
  toast.success('Event updated');
} catch (error) {
  if (ErrorHandler.isConflict(error)) {
    // Show conflict resolution dialog
    showConflictDialog(ErrorHandler.getConflicts(error));
  } else {
    ErrorHandler.showError(error);
  }
}

// Log errors with context
ErrorHandler.log('Event Update', error, { eventId: id, changes: data });

// Use structured logging in backend
this.logger.log(`Created VIP: ${vip.name} (ID: ${vip.id})`);
this.logger.error(`Failed to create VIP: ${error.message}`, error.stack);
```

### ❌ DON'T

```typescript
// Don't use generic error messages
catch (error) {
  toast.error('An error occurred'); // Too vague!
}

// Don't ignore errors
catch (error) {
  console.log(error); // Use console.error and proper context
}

// Don't manually extract error messages
catch (error: any) {
  const msg = error.response?.data?.message || 'Failed'; // Use ErrorHandler.getMessage()
  toast.error(msg);
}

// Don't log sensitive data
this.logger.log(`User login: ${email} with password ${password}`); // Never log passwords!
```

## Debugging Tips

### Enable Verbose Logging

**Backend:** Set `LOG_LEVEL=debug` in `.env`

**Frontend:** Development mode already has verbose logging enabled

### Check Error Context

**Backend logs include:**
- Timestamp
- HTTP method
- URL path
- Status code
- Request params/query/body
- User email (if authenticated)

**Frontend logs include:**
- Timestamp
- Context (feature area)
- HTTP method
- URL
- Request/response data
- Error type

### Common Issues

**"Network error" but backend is running:**
- Check CORS configuration
- Verify API_URL in `.env`
- Check browser DevTools Network tab

**"Authentication required" after login:**
- Check if token is stored in localStorage
- Verify Auth0 configuration
- Check if user is approved in database

**Validation errors don't show field names:**
- Backend DTO needs proper validation decorators
- Use class-validator's @IsString(), @IsEmail(), etc.

---

**Last Updated:** 2026-01-25
**See also:** [CLAUDE.md](../CLAUDE.md) for general project documentation
