Current Architecture: Per-Group Deployment Model
The current NGX Ramblers architecture deploys a single Docker image to multiple independent Fly.io apps. Each app connects to its own MongoDB database and S3 bucket, providing complete data isolation.
Architecture Diagram
flowchart TD
IMG@{ icon: "logos:docker-icon", label: "Single Docker Image", pos: "b", h: 48 }
IMG --> APP1@{ icon: "logos:fly-icon", label: "Group A (512MB)", pos: "b", h: 48 }
IMG --> APP2@{ icon: "logos:fly-icon", label: "Group B (512MB)", pos: "b", h: 48 }
IMG --> APP3@{ icon: "logos:fly-icon", label: "Group C (512MB)", pos: "b", h: 48 }
IMG --> APPN["... x 13 apps"]
APP1 --> DB1@{ icon: "ngx:mongodb", label: "Group A DB", pos: "b", h: 48 }
APP2 --> DB2@{ icon: "ngx:mongodb", label: "Group B DB", pos: "b", h: 48 }
APP3 --> DB3@{ icon: "ngx:mongodb", label: "Group C DB", pos: "b", h: 48 }
APP1 --> S31@{ icon: "ngx:aws", label: "Group A bucket", pos: "b", h: 48 }
APP2 --> S32@{ icon: "ngx:aws", label: "Group B bucket", pos: "b", h: 48 }
APP3 --> S33@{ icon: "ngx:aws", label: "Group C bucket", pos: "b", h: 48 }
Key Characteristics
- 13 separate Fly.io apps, each with 512MB–1GB memory
- One MongoDB database per group (complete data isolation)
- One S3 bucket per group (separate image/file storage)
- One AUTH_SECRET per group (independent JWT signing)
- One Cloudflare subdomain per group (e.g.
group-a.ngx-ramblers.org.uk) - Groups also have custom domains (e.g.
group-a-ramblers.org.uk) - The Angular frontend is identical across all sites — all site-specific behaviour comes from runtime config loaded from the database
What Already Works
| Capability | Status |
|---|---|
| Single codebase | One repo, one team |
| Single build artifact | One Docker image for all sites |
| Automated group provisioning | CLI tool creates new groups end-to-end |
| Per-group custom domains | Each group has its own domain and branding |
| Complete data isolation | Physically separate databases — no cross-group leakage possible |
Strengths of This Model
- Data isolation is inherent — no risk of cross-group data leakage because databases are physically separate
- Blast radius is limited — a bug or outage on one group's app doesn't affect others
- Resource isolation — one group's heavy traffic doesn't starve others
- Simple application code — no tenant context needed in queries, middleware, or auth