# Error Handling Guide

## Overview

This guide describes the error handling system implemented in the v2_adminpanel application. The system provides:

- Centralized error handling with custom exception hierarchy
- Input validation framework
- Structured logging
- Monitoring and alerting
- Consistent error responses

## Architecture

### 1. Custom Exception Hierarchy

```
BaseApplicationException
├── ValidationException
│   ├── InputValidationError
│   ├── BusinessRuleViolation
│   └── DataIntegrityError
├── AuthenticationException
│   ├── InvalidCredentialsError
│   ├── SessionExpiredError
│   └── InsufficientPermissionsError
├── DatabaseException
│   ├── ConnectionError
│   ├── QueryError
│   └── TransactionError
├── ExternalServiceException
│   ├── APIError
│   └── TimeoutError
└── ResourceException
    ├── ResourceNotFoundError
    ├── ResourceConflictError
    └── ResourceLimitExceeded
```

### 2. Core Components

- **core/exceptions.py**: Custom exception classes
- **core/error_handlers.py**: Global error handlers and decorators
- **core/validators.py**: Input validation framework
- **core/logging_config.py**: Structured logging setup
- **core/monitoring.py**: Error metrics and alerting
- **middleware/error_middleware.py**: Request-level error handling

## Usage Examples

### 1. Raising Custom Exceptions

```python
from core.exceptions import (
    InputValidationError, 
    ResourceNotFoundError,
    BusinessRuleViolation
)

# Validation error
if not email_is_valid:
    raise InputValidationError(
        field='email',
        message='Invalid email format',
        value=email_value,
        expected_type='email'
    )

# Resource not found
user = db.get_user(user_id)
if not user:
    raise ResourceNotFoundError(
        resource_type='User',
        resource_id=user_id
    )

# Business rule violation
if active_licenses >= license_limit:
    raise BusinessRuleViolation(
        rule='license_limit',
        message='License limit exceeded',
        context={
            'current': active_licenses,
            'limit': license_limit
        }
    )
```

### 2. Using Error Decorators

```python
from core.error_handlers import handle_errors, validate_request
from core.validators import validate

@handle_errors(
    catch=(psycopg2.Error,),
    message='Database operation failed',
    user_message='Datenbankfehler aufgetreten',
    redirect_to='admin.dashboard'
)
def update_customer(customer_id):
    # Database operations
    pass

@validate_request(
    required_fields={
        'email': str,
        'age': int,
        'active': bool
    }
)
def create_user():
    # Request data is validated
    pass

@validate({
    'email': {
        'type': 'email',
        'required': True
    },
    'password': {
        'type': 'password',
        'required': True
    },
    'age': {
        'type': 'integer',
        'required': True,
        'min_value': 18,
        'max_value': 120
    }
})
def register_user():
    # Access validated data
    data = request.validated_data
    # Use data safely
```

### 3. Input Validation

```python
from core.validators import Validators

# Email validation
email = Validators.email(user_input, field_name='email')

# Phone validation
phone = Validators.phone(user_input, field_name='phone')

# License key validation
license_key = Validators.license_key(user_input)

# Integer with constraints
age = Validators.integer(
    user_input,
    field_name='age',
    min_value=0,
    max_value=150
)

# String with constraints
username = Validators.string(
    user_input,
    field_name='username',
    min_length=3,
    max_length=50,
    safe_only=True
)

# Password validation
password = Validators.password(user_input)

# Custom enum validation
status = Validators.enum(
    user_input,
    field_name='status',
    allowed_values=['active', 'inactive', 'pending']
)
```

### 4. Error Context Manager

```python
from core.error_handlers import ErrorContext

with ErrorContext(
    operation='create_license',
    resource_type='License',
    resource_id=license_key
):
    # Operations that might fail
    db.insert_license(license_data)
    # Errors are automatically logged with context
```

### 5. Logging

```python
from core.logging_config import get_logger, log_error, log_security_event

logger = get_logger(__name__)

# Standard logging
logger.info('User created', extra={
    'user_id': user.id,
    'email': user.email
})

# Error logging
try:
    risky_operation()
except Exception as e:
    log_error(
        logger,
        'Risky operation failed',
        error=e,
        user_id=user.id,
        operation='risky_operation'
    )

# Security event logging
log_security_event(
    'INVALID_LOGIN_ATTEMPT',
    'Multiple failed login attempts',
    username=username,
    ip_address=request.remote_addr,
    attempt_count=5
)
```

## Error Response Format

### JSON Responses (API)

```json
{
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "Invalid input provided",
        "timestamp": "2024-01-15T10:30:00Z",
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "details": {
            "field": "email",
            "value": "invalid-email",
            "expected_type": "email"
        }
    }
}
```

### HTML Responses

- User-friendly error messages
- Error code and request ID for support
- Helpful suggestions for resolution
- Navigation options (back, dashboard, retry)

## Monitoring and Alerts

### Metrics Exposed

- `app_errors_total`: Total error count by code, status, endpoint
- `app_error_rate`: Errors per minute by error code
- `app_validation_errors_total`: Validation errors by field
- `app_auth_failures_total`: Authentication failures
- `app_database_errors_total`: Database errors
- `app_request_duration_seconds`: Request duration histogram

### Alert Thresholds

- Error rate > 10/min: Critical alert
- Auth failure rate > 5/min: Security alert
- DB error rate > 3/min: Infrastructure alert
- Response time 95th percentile > 2s: Performance alert

### Accessing Metrics

- Prometheus metrics: `/metrics`
- Active alerts: `/api/alerts`

## Best Practices

### 1. Always Use Specific Exceptions

```python
# Bad
raise Exception("User not found")

# Good
raise ResourceNotFoundError('User', user_id)
```

### 2. Provide Context

```python
# Bad
raise ValidationException("Invalid data")

# Good
raise InputValidationError(
    field='email',
    message='Email domain not allowed',
    value=email,
    expected_type='corporate_email'
)
```

### 3. Handle Database Errors

```python
# Bad
result = db.execute(query)

# Good
try:
    result = db.execute(query)
except psycopg2.IntegrityError as e:
    if e.pgcode == '23505':
        raise DataIntegrityError(
            entity='User',
            constraint='unique_email',
            message='Email already exists'
        )
    raise
```

### 4. Validate Early

```python
# Bad
def process_order(data):
    # Process without validation
    total = data['quantity'] * data['price']

# Good
@validate({
    'quantity': {'type': 'integer', 'min_value': 1},
    'price': {'type': 'float', 'min_value': 0}
})
def process_order():
    data = request.validated_data
    total = data['quantity'] * data['price']
```

### 5. Log Security Events

```python
# Failed login attempts
log_security_event(
    'LOGIN_FAILURE',
    f'Failed login for user {username}',
    username=username,
    ip_address=request.remote_addr
)

# Suspicious activity
log_security_event(
    'SUSPICIOUS_ACTIVITY',
    'Rapid API requests detected',
    ip_address=request.remote_addr,
    request_count=count,
    time_window=60
)
```

## Migration Guide

### Converting Existing Error Handling

1. **Replace generic exceptions**:
```python
# Old
except Exception as e:
    flash(f"Error: {str(e)}", "error")
    return redirect(url_for('admin.dashboard'))

# New
except DatabaseException as e:
    # Already handled by global handler
    raise
```

2. **Update validation**:
```python
# Old
email = request.form.get('email')
if not email or '@' not in email:
    flash("Invalid email", "error")
    return redirect(request.url)

# New
from core.validators import Validators
try:
    email = Validators.email(request.form.get('email'))
except InputValidationError as e:
    # Handled automatically
    raise
```

3. **Use decorators**:
```python
# Old
@app.route('/api/user', methods=['POST'])
def create_user():
    try:
        # validation code
        # database operations
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# New
@app.route('/api/user', methods=['POST'])
@validate({
    'email': {'type': 'email', 'required': True},
    'name': {'type': 'string', 'required': True, 'min_length': 2}
})
def create_user():
    data = request.validated_data
    # Use validated data directly
```

## Testing

Run the test suite:

```bash
pytest v2_adminpanel/tests/test_error_handling.py -v
```

Test coverage includes:
- Exception creation and properties
- Error handler responses (JSON/HTML)
- Validation functions
- Decorators
- Monitoring and metrics
- Alert generation

## Troubleshooting

### Common Issues

1. **Import errors**: Ensure you import from `core` package
2. **Validation not working**: Check decorator order (validate must be closest to function)
3. **Logs not appearing**: Verify LOG_LEVEL environment variable
4. **Metrics missing**: Ensure prometheus_client is installed

### Debug Mode

In development, set:
```python
app.config['DEBUG'] = True
```

This will:
- Include detailed error information
- Show stack traces
- Log to console with readable format