Last Updated: 2026-05-14 Status: Active Service:
apps/gateway
Detailed reference for every middleware in apps/gateway/src/middleware/. They are always applied in this order:
Rate Limit → CORS → Auth (JWT or API Key) → PBAC Access → Subscription Guard → Proxy1. Rate Limit Middleware
File: src/middleware/rate-limit.middleware.ts
Applied at: app.use("/*", rateLimitMiddleware) — every single request, first in the stack.
1.1 Algorithm
Fixed window: 100 requests per 60-second window, keyed by client IP.
The window start time is locked on the first request and does not slide forward. This blocks the drip-feeding attack where a client sends exactly 99 req/min indefinitely by straddling window boundaries.
1.2 Full Decision Flowchart
1.3 Key Design Notes
| Detail | Reason |
|---|---|
waitUntil for KV writes |
Writes happen after response is sent — zero added latency |
KV TTL always WINDOW_SECONDS (60) |
KV rejects TTLs below 60 s; the actual window boundary is enforced by resetAt inside the JSON value |
Stale-window check (now >= resetAt) |
Race: KV TTL cleanup is eventual. A stale entry may still exist when the next request arrives; this check forces a fresh window |
"unknown" bucket |
All requests without a traceable IP share one counter — acceptable since they're rare in production |
1.4 Configuration
| Constant | Value | File:Line |
|---|---|---|
RATE_LIMIT |
100 |
rate-limit.middleware.ts:6 |
WINDOW_SECONDS |
60 |
rate-limit.middleware.ts:7 |
2. Auth Middleware (JWT)
File: src/middleware/auth.middleware.ts Used by: manager (protected paths), media (upload/files), blog admin, content, brain, contacts, newsletter admin, comms, chatbot.
2.1 Full Decision Flowchart
2.2 Why RS256 (Asymmetric)
The manager service signs tokens with a private key it never exposes. The gateway and all downstream services hold only the public key (JWT_PUBLIC_KEY) to verify. This means:
- No service besides manager can mint valid tokens.
- Verification is a pure CPU operation — no DB or network call.
- Leaking a downstream service does not compromise token issuance.
3. API Key Middleware
File: src/middleware/api-key.middleware.ts
Used by: blog.proxy.ts /public/*, newsletter.proxy.ts /public/subscribe.
Factory function — apiKeyMiddleware("blog") returns a MiddlewareHandler scoped to service code "blog". The service code gates PBAC permission checks.
3.1 Full Decision Flowchart — Extraction + Cache
3.2 Full Decision Flowchart — Validation + Context
3.3 Cache TTL Trade-off
| Tier | TTL | Consequence of revocation |
|---|---|---|
| L1 memory | 5 min | Revoked key usable on same isolate for up to 5 min |
| L2 KV | 5 min | Revoked key usable across all instances for up to 5 min |
| L3 DB | — | Source of truth; always reflects current state |
To force immediate revocation, manually delete the KV entry:
wrangler kv key delete "ak:<sha256-hash>" --binding=RATE_LIMIT_KV4. Access Middleware (PBAC)
File: src/middleware/access.middleware.ts Used by: blog admin, content, brain, contacts, newsletter admin, comms, chatbot. NOT used by: manager (always accessible for billing) and media (platform-wide service).
4.1 Full Decision Flowchart
4.2 Service Code Matrix
| Route file | Hardcoded ServiceCode | Skip reason if absent |
|---|---|---|
blog.proxy admin |
"blog" |
— |
content.proxy |
"content" |
— |
brain.proxy |
"brain" |
— |
contacts.proxy |
"contacts" |
— |
newsletter.proxy admin |
"newsletter" |
— |
comms.proxy |
"comms" |
— |
chatbot.proxy |
"chatbot" |
— |
manager.proxy |
not applied | Must stay reachable for billing UI |
media.proxy |
not applied | Platform-wide service, no per-plan gating |
5. Subscription Guard
File: src/middleware/subscription.middleware.ts Used by: all paid-feature routes (blog admin, media upload/files, content, brain, contacts, newsletter admin, comms, chatbot). NOT used by: manager proxy — tenants must always reach the billing UI to reactivate.
5.1 Full Decision Flowchart
5.2 Billing State Reference
5.3 Error Code Reference
| HTTP | code |
Client action |
|---|---|---|
402 |
NO_SUBSCRIPTION |
Contact support — onboarding bug |
402 |
TRIAL_EXPIRED |
Add a payment method in /manager/billing |
402 |
SUBSCRIPTION_CANCELED |
Reactivate in /manager/billing |
402 |
PAYMENT_FAILED |
Update payment method in /manager/billing |
6. Middleware Execution Order Per Route
| Route pattern | Rate limit | CORS policy | Auth | PBAC | Sub guard |
|---|---|---|---|---|---|
GET /blog/public/* |
✅ | origin: * |
🔑 API key — "blog" |
"blog" |
— |
* /blog/admin/* |
✅ | Whitelist | JWT | "blog" |
✅ |
* /manager/* public paths |
✅ | Whitelist | — | — | — |
* /manager/* protected |
✅ | Whitelist | JWT | — | — |
* /media/upload/* |
✅ | Whitelist | JWT | — | ✅ |
* /media/files/* |
✅ | Whitelist | JWT | — | ✅ |
* /content/* |
✅ | Whitelist | JWT | "content" |
✅ |
* /brain/* |
✅ | Whitelist | JWT | "brain" |
✅ |
* /contacts-intel/* |
✅ | Whitelist | JWT | "contacts" |
✅ |
POST /newsletter/public/subscribe |
✅ | origin: * |
🔑 API key — "newsletter" |
"newsletter" |
— |
POST /newsletter/public/unsubscribe |
✅ | origin: * |
— HMAC inside service | — | — |
POST /newsletter/public/confirm |
✅ | origin: * |
— HMAC inside service | — | — |
* /newsletter/* admin |
✅ | Whitelist | JWT | "newsletter" |
✅ |
* /comms/* |
✅ | Whitelist | JWT | "comms" |
✅ |
* /chatbot/* |
✅ | Whitelist | JWT | "chatbot" |
✅ |