> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Maintenance

> Maintenance mode middleware for scheduled downtime.

## Overview

The `maintenance` middleware enables maintenance mode for your application, returning a 503 Service Unavailable response with optional whitelist support for IPs and paths.

## Installation

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/maintenance"
```

## Quick Start

```go theme={null}
app := mizu.New()

// Enable maintenance mode
app.Use(maintenance.New(true))
```

## Configuration

| Option           | Type           | Default                          | Description                   |
| ---------------- | -------------- | -------------------------------- | ----------------------------- |
| `Enabled`        | `bool`         | `false`                          | Enable maintenance mode       |
| `Message`        | `string`       | `"Service is under maintenance"` | Response message              |
| `RetryAfter`     | `int`          | `3600`                           | Retry-After header in seconds |
| `StatusCode`     | `int`          | `503`                            | HTTP status code              |
| `Handler`        | `mizu.Handler` | -                                | Custom maintenance handler    |
| `Whitelist`      | `[]string`     | -                                | Allowed IP addresses          |
| `WhitelistPaths` | `[]string`     | -                                | Paths that bypass maintenance |
| `Check`          | `func() bool`  | -                                | Dynamic maintenance check     |

## Examples

### Basic Maintenance Mode

```go theme={null}
// Enabled from start
app.Use(maintenance.New(true))
// All requests return 503
```

### Custom Message

```go theme={null}
app.Use(maintenance.WithOptions(maintenance.Options{
    Enabled: true,
    Message: "We're upgrading our systems. Back soon!",
}))
```

### Custom Handler

```go theme={null}
app.Use(maintenance.WithOptions(maintenance.Options{
    Enabled: true,
    Handler: func(c *mizu.Ctx) error {
        return c.HTML(503, `
            <html>
                <head><title>Maintenance</title></head>
                <body>
                    <h1>Under Maintenance</h1>
                    <p>We'll be back shortly.</p>
                </body>
            </html>
        `)
    },
}))
```

### Whitelist IPs

```go theme={null}
app.Use(maintenance.WithOptions(maintenance.Options{
    Enabled: true,
    Whitelist: []string{
        "192.168.1.100",    // Admin workstation
        "10.0.0.0/8",       // Internal network
    },
}))
```

### Whitelist Paths

```go theme={null}
app.Use(maintenance.WithOptions(maintenance.Options{
    Enabled: true,
    WhitelistPaths: []string{
        "/health",          // Health checks
        "/status",          // Status endpoint
        "/api/webhooks",    // Critical webhooks
    },
}))
```

### Dynamic Control

```go theme={null}
mode := maintenance.NewMode(maintenance.Options{
    Message: "Maintenance in progress",
})

app.Use(mode.Middleware())

// Enable/disable dynamically
app.Post("/admin/maintenance/enable", func(c *mizu.Ctx) error {
    mode.Enable()
    return c.Text(200, "Maintenance enabled")
})

app.Post("/admin/maintenance/disable", func(c *mizu.Ctx) error {
    mode.Disable()
    return c.Text(200, "Maintenance disabled")
})

app.Get("/admin/maintenance/status", func(c *mizu.Ctx) error {
    return c.JSON(200, map[string]bool{
        "enabled": mode.IsEnabled(),
    })
})
```

### Toggle Maintenance

```go theme={null}
mode := maintenance.NewMode(maintenance.Options{})

app.Post("/admin/maintenance/toggle", func(c *mizu.Ctx) error {
    mode.Toggle()
    return c.JSON(200, map[string]bool{
        "enabled": mode.IsEnabled(),
    })
})
```

### Scheduled Maintenance

```go theme={null}
// Maintenance window: Dec 15, 2024 2:00 AM - 4:00 AM UTC
start := time.Date(2024, 12, 15, 2, 0, 0, 0, time.UTC)
end := time.Date(2024, 12, 15, 4, 0, 0, 0, time.UTC)

app.Use(maintenance.ScheduledMaintenance(start, end))
```

### Check Function

```go theme={null}
app.Use(maintenance.WithOptions(maintenance.Options{
    Check: func() bool {
        // Check external flag (e.g., from database or config)
        return config.IsMaintenanceMode()
    },
}))
```

### Environment-Based

```go theme={null}
app.Use(maintenance.WithOptions(maintenance.Options{
    Check: func() bool {
        return os.Getenv("MAINTENANCE_MODE") == "true"
    },
    WhitelistPaths: []string{"/health"},
}))
```

### With Retry-After

```go theme={null}
app.Use(maintenance.WithOptions(maintenance.Options{
    Enabled:    true,
    RetryAfter: 1800, // 30 minutes
}))
// Response includes: Retry-After: 1800
```

### JSON Response

```go theme={null}
app.Use(maintenance.WithOptions(maintenance.Options{
    Enabled: true,
    Handler: func(c *mizu.Ctx) error {
        c.Writer().Header().Set("Retry-After", "3600")
        return c.JSON(503, map[string]any{
            "status":     "maintenance",
            "message":    "Service is under maintenance",
            "retry_after": 3600,
        })
    },
}))
```

## API Reference

```go theme={null}
func New(enabled bool) mizu.Middleware
func WithOptions(opts Options) mizu.Middleware
func ScheduledMaintenance(start, end time.Time) mizu.Middleware
func NewMode(opts Options) *Mode

// Mode methods
func (m *Mode) Enable()
func (m *Mode) Disable()
func (m *Mode) Toggle()
func (m *Mode) IsEnabled() bool
func (m *Mode) Middleware() mizu.Middleware
```

## Response Headers

```
HTTP/1.1 503 Service Unavailable
Retry-After: 3600
Content-Type: text/plain

Service is under maintenance
```

## Technical Details

### Implementation Architecture

The maintenance middleware is implemented with a layered approach for flexibility and performance:

1. **Static Configuration** - Uses `Options` struct to configure enabled state, messages, status codes, and retry headers
2. **Dynamic Mode Control** - `Mode` type provides thread-safe atomic operations for runtime enable/disable toggling
3. **Bypass Mechanisms** - Implements two bypass layers:
   * IP-based whitelisting via `Whitelist` option (checks X-Forwarded-For, X-Real-IP, and RemoteAddr)
   * Path-based whitelisting via `WhitelistPaths` option (exact path matching)
4. **Custom Check Function** - Supports dynamic maintenance state via `Check` function, which takes precedence over static `Enabled` flag
5. **Scheduled Maintenance** - Uses time-based checks to automatically enable/disable maintenance during specific windows

### Key Components

* **Options**: Configuration struct with fields for enabled state, messages, status codes, handlers, and whitelists
* **Mode**: Thread-safe maintenance mode controller using `atomic.Int32` for concurrent read/write operations
* **WithOptions**: Core middleware factory that processes configuration and returns the middleware function
* **ScheduledMaintenance**: Helper function that creates time-windowed maintenance middleware
* **getClientIP**: Helper function to extract client IP from various headers (X-Forwarded-For, X-Real-IP, RemoteAddr)
* **itoa**: Custom integer-to-string conversion for Retry-After header (avoids fmt package overhead)

### Execution Flow

1. Check if maintenance is enabled (via `Check` function or `Enabled` flag)
2. If disabled, pass request to next handler
3. If enabled, check IP whitelist (bypass if matched)
4. Check path whitelist (bypass if matched)
5. Execute custom handler if provided, or return default 503 response with Retry-After header

### Thread Safety

The `Mode` type uses `atomic` operations for thread-safe state management:

* `Enable()` and `Disable()` use `atomic.StoreInt32`
* `IsEnabled()` uses `atomic.LoadInt32`
* `Toggle()` uses `atomic.CompareAndSwapInt32` for lock-free toggling

## Best Practices

* Whitelist health check endpoints for monitoring
* Use scheduled maintenance for planned downtime
* Whitelist admin IPs for debugging
* Set appropriate Retry-After values
* Provide helpful maintenance messages
* Use dynamic control for emergency maintenance

## Testing

The maintenance middleware includes comprehensive test coverage for all scenarios:

| Test Case                                               | Description                             | Expected Behavior                                                                                                      |
| ------------------------------------------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `TestNew`                                               | Basic maintenance mode enabled          | Returns 503 with default message "Service is under maintenance"                                                        |
| `TestNew_Disabled`                                      | Maintenance mode disabled               | Returns 200 and passes through to handler                                                                              |
| `TestWithOptions_CustomMessage`                         | Custom maintenance message              | Returns 503 with custom message "We'll be back soon!"                                                                  |
| `TestWithOptions_RetryAfter`                            | Custom retry-after value                | Sets Retry-After header to 7200 seconds                                                                                |
| `TestWithOptions_Whitelist` (whitelisted IP)            | IP in whitelist accesses endpoint       | Returns 200 and bypasses maintenance mode                                                                              |
| `TestWithOptions_Whitelist` (non-whitelisted IP)        | IP not in whitelist accesses endpoint   | Returns 503 in maintenance mode                                                                                        |
| `TestWithOptions_WhitelistPaths` (whitelisted path)     | Access to /health whitelisted path      | Returns 200 and bypasses maintenance mode                                                                              |
| `TestWithOptions_WhitelistPaths` (non-whitelisted path) | Access to /api non-whitelisted path     | Returns 503 in maintenance mode                                                                                        |
| `TestWithOptions_CustomHandler`                         | Custom handler for maintenance response | Returns JSON response with custom handler                                                                              |
| `TestMode`                                              | Mode creation, enable, disable, toggle  | Correctly changes state: disabled by default, enabled after Enable(), disabled after Disable(), enabled after Toggle() |
| `TestMode_Middleware` (disabled)                        | Middleware with Mode disabled           | Returns 200 and passes through                                                                                         |
| `TestMode_Middleware` (enabled)                         | Middleware with Mode enabled            | Returns 503 in maintenance mode                                                                                        |
| `TestScheduledMaintenance`                              | Scheduled maintenance in the past       | Returns 200 as maintenance period has ended                                                                            |

## Related Middlewares

* [version](/middlewares/version) - API versioning
* [ratelimit](/middlewares/ratelimit) - Rate limiting
