docs: add rate limiter refactor spec

This commit is contained in:
2026-05-06 23:17:35 +02:00
parent 999a7f73c1
commit d7db3d6d1c

View File

@@ -0,0 +1,68 @@
# Design Spec: Generic Rate Limiter Refactor
Refactor the current global-state rate limiter into a struct-based implementation that supports multiple instances with different configurations, improving testability and flexibility.
## 1. Core Architecture
### Current State
- `pkg/middleware/ratelimit.go` uses global variables (`visitors`, `mu`, `quit`).
- Cleanup logic is started automatically via `init()`.
- Limits are hardcoded (5 attempts per minute).
### Changes
- **Limiter Struct:** Encapsulate state within a `Limiter` struct.
- **Explicit Configuration:** Pass limits and windows via a `Config` struct.
- **Context-aware Cleanup:** Use `context.Context` to manage the cleanup goroutine lifecycle instead of a global `quit` channel.
## 2. Component Design
### `Limiter` Struct
```go
type visitor struct {
attempts int
lastSeen time.Time
}
type Config struct {
MaxAttempts int
Window time.Duration
}
type Limiter struct {
mu sync.Mutex
visitors map[string]*visitor
config Config
}
```
### Initialization
```go
func NewLimiter(cfg Config) *Limiter {
return &Limiter{
visitors: make(map[string]*visitor),
config: cfg,
}
}
```
### Middleware Methods
- `Middleware(next http.Handler) http.Handler`: Generic rate limiting.
- `AuthMiddleware(next http.Handler) http.Handler`: Specific logic for auth (redirects with error params).
## 3. Integration Plan
- Instantiate the `Limiter` in `cmd/server/main.go`.
- Pass the `Limiter` or its middleware to `internal/server/NewRouter`.
- Update `internal/server/routes.go` to use the new instance-based middleware.
## 4. Verification Plan
### Automated Checks
- **Unit Tests:** Create `pkg/middleware/ratelimit_test.go` to verify:
- Multiple IPs are tracked independently.
- Limits are enforced correctly.
- Attempts reset after the window expires.
- `go test ./pkg/middleware/...`: Run the new tests.
### Manual Checks
- Verify that exceeding login attempts still triggers the `rate_limited` redirect.