docs: document nginx routing rules to prevent SPA fallback hiding API 404s

TASK-006: Document the nginx routing configuration that ensures API requests
returning 404 from FastAPI are not intercepted by the SPA wildcard fallback
rule. This prevents development bugs from being masked by 200 responses
containing HTML instead of 404 errors.

Added section 9.2 in Architekture.md covering:
- nginx location block priority (longest-prefix matching)
- Routing configuration for /api/, /assets/, and /
- Detailed routing behavior diagrams
- Critical implementation notes to prevent regressions

The current nginx.conf is already correct:
- /api/ location has no try_files and proxies directly to backend
- /assets/ location uses try_files with =404
- / catch-all uses SPA fallback to index.html

This ensures:
✓ API typos like /api/jailss return 404, not SPA HTML
✓ Frontend routes serve SPA HTML for client-side routing
✓ Static assets properly return 404 when missing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-26 12:10:21 +02:00
parent f55c317f87
commit 9725714aa2

View File

@@ -768,7 +768,67 @@ APScheduler 4.x (async mode) manages recurring background tasks.
---
## 9.2 Deployment Constraints
## 9.2 nginx Routing Rules
The reverse proxy (nginx) must route requests correctly to prevent frontend SPA fallback rules from hiding backend 404 errors. The following location blocks ensure proper behavior:
### Location Block Priority
nginx uses **longest-prefix matching** to determine which location block handles a request:
1. Exact matches (`location =`) — highest priority
2. Regular expression matches (`location ~`) — second priority
3. Prefix matches (`location /prefix`) — matched in order of specificity (longest first)
4. Catch-all (`location /`) — lowest priority
### Routing Configuration
| Location Block | Rule | Purpose |
|---|---|---|
| `location /api/` | `proxy_pass http://backend:8000;`**no `try_files`** | Proxy all API requests to FastAPI backend. Any unmatched API route (typos, invalid paths) returns 404 from the backend. |
| `location /assets/` | `try_files $uri =404;` | Serve static assets with long-term caching. Return 404 if file doesn't exist. |
| `location /` | `try_files $uri $uri/ /index.html;` | SPA fallback: serve `index.html` for all unmatched routes (client-side routing). |
### Routing Behavior
```
Request → /api/some-endpoint
nginx matches location /api/ (longest prefix)
proxy_pass → backend:8000
Backend returns 404 if endpoint doesn't exist (✓ correct)
Client sees 404, not SPA HTML
Request → /some-page
nginx matches location / (catch-all)
try_files looks for file, then directory, then /index.html
Serves /index.html (React Router handles client-side routing)
Client sees 200 with HTML (✓ correct for SPA)
Request → /api/typos
nginx matches location /api/ (longest prefix, NOT catch-all)
proxy_pass → backend:8000
FastAPI returns 404 (✓ correct, not caught by SPA fallback)
```
### Critical Implementation Notes
- **Never add `try_files` to the `/api/` location block** — this would hide backend 404s.
- **The `/api/` location must come before the `/` catch-all** in the config (this is automatically respected via longest-prefix matching).
- **No inherited `try_files` rules** — the `/api/` location has no global `try_files` that could affect it.
- **Backend 404 responses pass through nginx unchanged** — nginx does not rewrite 404 responses from the backend.
---
## 9.3 Deployment Constraints
### Single-Worker Requirement