# Error Handling Guide

This guide covers ThrillWiki's comprehensive error handling system for both the Django backend and Nuxt frontend.

## Overview

The error system captures errors from all sources (frontend, backend, API) and displays them in the admin dashboard at `/admin/errors`.

---

## Quick Start

### Backend (Python)

```python
from apps.core.utils import capture_errors, error_context, capture_and_log

# Option 1: Decorator on functions/views
@capture_errors(severity='high')
def create_park(request, data):
    return ParkService.create(data)  # Errors auto-captured

# Option 2: Context manager for code blocks
with error_context('Processing payment', severity='critical'):
    process_payment()

# Option 3: Manual capture
try:
    risky_operation()
except Exception as e:
    error_id = capture_and_log(e, 'Risky operation failed')
    return Response({'error': f'Failed (ref: {error_id})'})
```

### Frontend (TypeScript)

```typescript
// Option 1: useErrorBoundary composable
const { wrap, error, isError, retry } = useErrorBoundary({
  componentName: 'RideDetail'
})
const ride = await wrap(() => api.get('/rides/1'), 'Loading ride')

// Option 2: tryCatch utility (Go-style)
const [data, err] = await tryCatch(fetchRide(id), 'Fetching ride')
if (err) return // Error already reported

// Option 3: useReportError (manual)
const { reportError } = useReportError()
try {
  await riskyOperation()
} catch (e) {
  reportError(e, { action: 'Risky operation' })
}
```

---

## Backend Utilities

### `@capture_errors` Decorator

Automatically captures exceptions from decorated functions.

```python
from apps.core.utils import capture_errors

@capture_errors(
    source='api',        # 'frontend', 'backend', or 'api'
    severity='high',     # 'critical', 'high', 'medium', 'low'
    reraise=True,        # Re-raise after capturing (default True)
    log_errors=True      # Also log to Python logger (default True)
)
def my_view(request):
    # If this raises, error is automatically captured
    return do_something()
```

**Use for**: API views, service methods, any function where you want automatic tracking.

### `error_context` Context Manager

Captures errors from a code block with rich context.

```python
from apps.core.utils import error_context

with error_context(
    'Creating ride submission',
    source='backend',
    severity='high',
    request=request,           # Optional: for user/IP context
    entity_type='Ride',        # Optional: what entity
    entity_id=123,             # Optional: which entity
    reraise=True               # Default True
):
    submission = SubmissionService.create(data)
```

**Use for**: Specific operations where you want detailed context about what was happening.

### `capture_and_log` Function

One-liner for manual error capture that returns the error ID.

```python
from apps.core.utils import capture_and_log

try:
    result = risky_operation()
except Exception as e:
    error_id = capture_and_log(
        e,
        'Risky operation',
        severity='high',
        request=request,
        entity_type='Park',
        entity_id=42
    )
    return Response({'error': f'Failed (ref: {error_id})'}, status=500)
```

**Use for**: When you need the error ID to show to users for support reference.

---

## Frontend Utilities

### `useErrorBoundary` Composable

Component-level error boundary with retry support.

```typescript
const {
  error,        // Ref<Error | null> - current error
  isError,      // ComputedRef<boolean> - whether error exists
  lastErrorId,  // Ref<string | null> - for support reference
  clear,        // () => void - clear error state
  retry,        // () => Promise<void> - retry last operation
  wrap,         // Wrap async function
  wrapSync      // Wrap sync function
} = useErrorBoundary({
  componentName: 'MyComponent',
  entityType: 'Ride',
  defaultSeverity: 'medium',
  showToast: true,
  onError: (err, id) => console.log('Error:', err)
})

// In template
// <div v-if="isError" class="error">
//   {{ error?.message }}
//   <button @click="retry">Try Again</button>
// </div>
```

### `tryCatch` Utility

Go-style error handling for one-liners.

```typescript
import { tryCatch, tryCatchSync } from '~/utils/tryCatch'

// Async
const [ride, error] = await tryCatch(api.get('/rides/1'), 'Loading ride')
if (error) {
  console.log('Failed:', error.message)
  return
}
console.log('Got ride:', ride)

// Sync
const [data, err] = tryCatchSync(() => JSON.parse(input), 'Parsing JSON')

// With options
const [data, err] = await tryCatch(fetchData(), 'Fetching', {
  severity: 'critical',
  silent: true,  // No toast notification
  entityType: 'Ride',
  entityId: 123
})
```

### `useReportError` Composable

Full-featured error reporting with maximum context.

```typescript
const { reportError, reportErrorSilent, withErrorReporting } = useReportError()

// Report with toast
await reportError(error, {
  action: 'Saving ride',
  componentName: 'EditRideModal',
  entityType: 'Ride',
  entityId: 42,
  severity: 'high',
  metadata: { custom: 'data' }
})

// Report without toast
await reportErrorSilent(error, { action: 'Background task' })

// Wrap a function
const safeFetch = withErrorReporting(fetchRide, {
  componentName: 'RideDetail',
  entityType: 'Ride'
})
```

### Global Error Plugin

The `errorPlugin.client.ts` automatically catches:
- Vue component errors
- Unhandled promise rejections
- Global JavaScript errors

These are reported silently to the dashboard without user intervention.

---

## Viewing Errors

1. Navigate to `/admin/errors` (requires admin role)
2. Filter by severity, source, date range, or resolution status
3. Click on an error to see full details including:
   - Stack trace
   - Browser environment
   - User context
   - Request details
4. Mark errors as resolved with notes
5. Export errors to CSV

---

## Best Practices

1. **Use decorators for views**: All API viewsets should have `@capture_errors`

2. **Use context managers for critical operations**: Payments, data migrations, bulk operations

3. **Use `tryCatch` for async code**: Clean, Go-style error handling

4. **Set appropriate severity**:
   - `critical`: Database errors, payment failures, data loss
   - `high`: Unexpected runtime errors, 5xx responses
   - `medium`: Validation errors, user input issues
   - `low`: Warnings, graceful degradation

5. **Include entity context**: Always provide `entity_type` and `entity_id` when operating on specific records

6. **Don't swallow errors**: Use `reraise=True` (default) unless you have a recovery strategy

---

## Integration Patterns

### API ViewSet with Decorator

```python
from rest_framework import viewsets
from apps.core.utils import capture_errors

class RideViewSet(viewsets.ModelViewSet):
    @capture_errors(source='api')
    def create(self, request, *args, **kwargs):
        return super().create(request, *args, **kwargs)
```

### Vue Component with Error Boundary

```vue
<script setup lang="ts">
const { wrap, isError, error, retry } = useErrorBoundary({
  componentName: 'RideCard'
})

const ride = ref(null)

onMounted(async () => {
  ride.value = await wrap(() => api.get(`/rides/${props.id}`), 'Loading ride')
})
</script>

<template>
  <div v-if="isError" class="error-state">
    <p>{{ error?.message }}</p>
    <UButton @click="retry">Retry</UButton>
  </div>
  <div v-else-if="ride">
    <!-- Normal content -->
  </div>
</template>
```

---

## Troubleshooting

**Errors not appearing in dashboard?**
- Check the backend server logs for capture failures
- Verify `MIDDLEWARE` includes `ErrorCaptureMiddleware`
- Ensure the `ApplicationError` model is migrated

**Frontend errors not reporting?**
- Check browser console for API call failures
- Verify `.env` has correct `NUXT_PUBLIC_API_BASE` (port 8000)
- Check network tab for `/api/v1/errors/report/` requests
