Architecture Overview¶
System Diagram¶
┌──────────────────────────┐
│ CloudFront (api cache) │
│ per-env distribution │
└────────────┬─────────────┘
│
┌────────────▼─────────────┐
│ Application Load │
│ Balancer (host-based) │
│ api.{env}.appmecca.net │
└────────────┬─────────────┘
│
┌────────────▼─────────────┐
│ appmecca-api container │
│ uvicorn + FastAPI :8080 │
│ replicas: 3, host pool │
└────────────┬─────────────┘
│
┌─────────────────┼──────────────────┐
│ │ │
┌─────────▼──────┐ ┌──────▼───────┐ ┌───────▼─────────┐
│ PostgreSQL │ │ Redis │ │ AWS Services │
│ (AppMecca DB │ │ (ElastiCache) │ │ (CodeBuild, │
│ + _logs DB) │ │ Celery broker │ │ CloudWatch, │
└────────────────┘ │ + cache │ │ CloudFront) │
└──────▲────────┘ └─────────────────┘
│
┌─────────────┴──────────────┐
│ worker + beat containers │
│ (same image, celery) │
└────────────────────────────┘
Clients:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ appmecca │ │ mecca │ │Dashboard │ │ Agent │
│ (admin) │ │ (tenant) │ │(SvelteKit│ │ (EC2) │
│ CLI │ │ CLI │ │ SSR) │ │ writes │
└────┬─────┘ └────┬─────┘ └────┬─────┘ │ to PG │
│ │ │ │ directly │
└─────────────┴─────────────┘ └──────────┘
│
All go through
CloudFront → ALB → container
Services¶
The API repository declares four services in its own appmecca.yaml, all built from one image:
| Service | Command | Port | Replicas | Memory |
|---|---|---|---|---|
api |
uvicorn appmecca_api.main:app |
8080 | 3 | 512m |
worker |
celery … worker -Q default,maintenance,database,cron |
— | 3 | 512m |
beat |
celery … beat |
— | 1 | 128m |
canary |
python -m appmecca_api.canary |
8090 | 1 | 64m |
The canary service is the platform conformance probe — a stateless container in the API's own Docker bridge that the run_canary_conformance Beat task POSTs a network-conformance battery to. It is platform-positioned; not a tenant-isolation proof: its negative check targets an app the isolation policy forbids to the API's bridge, which is itself privileged (apm-467).
Request Flow¶
- Client sends an HTTPS request carrying
Authorization: Bearer am_k1_…(API key) orBearer ses_…(session token). - CloudFront serves the response from the edge if the route's cache tier permits it, otherwise forwards to the ALB.
- ALB matches the reserved
api.{env}.{domain}host header and forwards to the API target group. - uvicorn → FastAPI processes the request:
resolve_identitymiddleware resolves the credential into aResolvedIdentity(API key or session), andresolve_groupderives the caller'sGroupScope- The route calls the service layer, which calls repositories
- Repositories run SQL against PostgreSQL through the shared asyncpg pool
- Queue-writing routes
INSERTinto thedeploy_queuetable - Some routes call AWS APIs directly (CodeBuild, CloudWatch Logs, CloudFront)
- The JSON response is returned, with a
Cache-Controlheader stamped byCacheHeadersMiddleware.
Connection Pooling¶
The container is long-lived, so each uvicorn worker process holds an asyncpg pool created lazily on first use in db/connection.py and closed on shutdown by the FastAPI lifespan hook. Pool bounds come from APPMECCA_API_DB_MIN_POOL_SIZE / _DB_MAX_POOL_SIZE (defaults 1 and 10) and apply per worker, not per container.
There is no RDS Proxy in this path — the container connects to the RDS endpoint directly.
The database password is never fetched by the API. The agent resolves the RDS master password from Secrets Manager and bakes it into APPMECCA_API_DATABASE_URL before launching the container; _resolve_database_url refuses a passwordless URL rather than falling back to its own Secrets Manager call. Containers are jailed; the agent injects every sensitive value.
Network Placement¶
The API container runs on the Docker host pool in the VPC's private subnets — the same subnets as RDS and ElastiCache — so it reaches both over private networking. The ALB in the public subnets provides the public HTTPS endpoint.
The Deploy Queue¶
The API writes to the deploy_queue PostgreSQL table whenever a client asks for work the agent must perform — build triggers, deploys, undeploys, database operations, execs, drive queries, and the agent-mediated RPCs. db/repositories/queue.py owns every one of those writes.
The agent polls that table every 5 seconds and claims rows with an atomic UPDATE … WHERE status = 'queued' AND claimed_by IS NULL RETURNING *. For latency-sensitive round-trips the API also registers a LISTEN/NOTIFY waiter (db/notify.py) so it wakes within milliseconds of the agent's terminal-status write instead of polling.
Rows carry a generated lane column (control or deploy) derived from action_type, so fast control-plane RPCs are claimed independently of the deployment admission gates.
Agent Direct Writes¶
The deployment agent (running on EC2 in the same VPC) writes build results, deployment status, container stats, and heartbeats directly to PostgreSQL — no API round-trip needed. It has direct network access to RDS from the private subnet, and its only credential is APPMECCA_DATABASE_URL.
Edge Caching¶
middleware/cache_headers.py stamps Cache-Control per route from the tier catalogue at src/appmecca_api/data/api_cache_behaviours.yaml. Only tiers explicitly marked shared: true emit public; every per-caller tier emits private, and write methods plus always-live endpoints (logs, exec output, deploy-queue polling) emit no-store.
Authorization is part of the CloudFront cache key, and the distribution runs at MinTTL=0 so the origin's headers are honoured.