05-production-architecture.md
markdown
sha256:7d5985ef251de9f0154f9b185a75cf36174bf73e0c34f5eca133e7bd20224bf4
Merge branch 'feat/opengraph-repo-cards' into dev
Human
22 days ago
Section 5 — Production Architecture
Companion to
musehub-production-readiness-checklist.md.
Good news first — the app itself is more hardened than the infra around it
Grepping musehub/ turned up real, already-implemented protections that Section 0's
infrastructure-level inventory didn't surface:
- Health checks with real dependency probes:
/healthz(musehub/main.py:323) checks both DB and object storage, not just "process is up." Used bydeploy.shfor the blue/green health gate. - Rate limiting (
musehub/rate_limits.py): per-routeslowapilimits (wire push 30/min, MCP human/agent/anonymous tiers, asset requests), plus a 300/min global per-IP baseline. - Bot throttling (
musehub/middleware/bot_throttle.py): blocks unauthenticated scanners on write paths while explicitly exempting authenticated (MSign) traffic and safe GET/HEAD reads — a deliberate, well-reasoned design, not a blunt UA blocklist. - Security headers already set in
main.py:X-Frame-Options,X-Content-Type-Options,Content-Security-Policy,Strict-Transport-Security— and again at the nginx layer (deploy/nginx-cf.conf): HSTS withincludeSubDomains,nosniff,X-Frame-Options: SAMEORIGIN,Referrer-Policy. - Deliberate per-route timeouts in nginx — not a single blanket value: 5s for fast health checks, 60s default, 120–300s for heavier routes, 3600s for streaming (MCP/SSE) endpoints. This is intentional, not an oversight.
- No cookies at all — MSign is header-based (Ed25519 signatures), so cookie flag items
(
Secure/HttpOnly/SameSite) are N/A, not gaps.
Real gaps
- Single EC2 instance per environment — no ASG, no multi-AZ. Blue/green happens within one instance (two Docker containers on different ports), not across instances. If the instance itself fails (hardware, AZ outage), there is no automatic failover. This is the single largest intentional SPOF and needs an explicit decision: accept it (documented technical debt, matches the "keep it simple" architecture direction from Section 0) or plan multi-instance/multi-AZ.
- No graceful shutdown / SIGTERM handling found in
musehub/main.py— uvicorn's defaults apply. In-flight requests during a container stop may be dropped rather than drained. Given blue/green already waits for the new slot's/healthzbefore flipping nginx, the new slot is protected, but the old slot's shutdown duringdocker rmisn't verified graceful. - No autoscaling, no documented justification for fixed capacity. Fixed
t3.small(prod) /t3.medium(staging) — inconsistent sizing between environments with no stated reason. Worth either matching sizes or documenting why staging is intentionally larger. - No AWS WAF — and none needed the way the checklist assumes. There's no ALB/CloudFront for AWS WAF to attach to. DDoS/abuse protection is Cloudflare's job here (edge proxy in front of everything), which is a reasonable substitution — but Cloudflare's own WAF/rate-limiting rules are unverified from this environment (no Cloudflare API access). Needs Gabriel to check the Cloudflare dashboard for what's actually configured there.
- No AWS service quota monitoring.
- Background job idempotency (
musehub-runnerCI jobs) not verified in this pass — would need a closer read of the runner's job-claiming logic; flagging as unverified rather than assuming. - Migration/rolling-deploy compatibility: the deploy pipeline does run migrations before the
slot flip (per
docs/infrastructure.md's pipeline steps), which is the right shape, but expand-and-contract discipline for schema changes hasn't been reviewed — deferred to Section 8.
Documented intentional single points of failure (per the checklist's explicit ask)
- One EC2 instance per environment — no instance-level redundancy.
- One self-hosted PostgreSQL instance — no replica, no managed failover (RDS Multi-AZ would solve this; explicitly not in scope per the "keep current architecture" lean from Section 0).
- One AWS account, shared with Stori (Section 2).
- One Cloudflare account/zone — DNS, TLS, and (per Section 6) possibly object storage all depend on Cloudflare being up and correctly configured.
- Deploys depend on one human running a script with a shared credential from a laptop — no redundant deployer today (Section 1/3).
Plan to remove unacceptable ones: not yet decided which of the above are acceptable long-term vs. must-fix-before-launch — this needs Gabriel's input once RPO/RTO/availability targets (Section 0, still open) are defined. A SPOF that's fine for a beta with a handful of users may not be fine at real scale.
File History
1 commit
sha256:be1b2fdf6ab1fc652b3b35a945d0277a36fbf5d96e63692020d36cd7ebe03534
Merge 'docs/security-monitoring-verified' into 'dev' — prop…
Human
2 days ago