Brume is a single Rust binary that fronts three stores: Postgres for durable configuration, a dedicated Redis for rate-limit counters, and an in-process cache for hot lookups. This page describes how a check flows through that stack and what we never store.
A rate-limit check touches four layers:
limit only, the project's daily check ceiling is checked against Redis before the rule evaluation, so a client cannot run unlimited denials.The verdict and X-RateLimit-* headers come back in the same response.
| Store | Holds | Touched per check? |
|---|---|---|
| Postgres | Projects, API keys (hashed), rules, overrides, quotas, blocklists, webhooks, audit log | No — read through caches |
| Rate-limit Redis | Counters, windows, daily budgets, quota state | Yes — one atomic Lua script |
| In-process cache | Auth lookups, rule lookups, blocked identifiers | Yes — O(1) |
Keeping Postgres out of the hot path is deliberate: configuration changes are rare, checks are frequent, and the two should never contend.
If the rate-limit Redis is unreachable, the evaluation fails open: the gateway returns success: true with degraded: true and the X-Brume-RateLimit-Degraded header. Availability wins over correctness, and the degradation is visible rather than silent. The SDK offers the same tradeoff for timeouts and network errors via timeout.fallback and onError.
One binary, one config, one bill. The gateway runs behind a reverse proxy with TLS termination; upgrades are zero-downtime systemd restarts. See Deployment for the operational model and Runbook: Redis Failover for the failure path.