22 KiB
Multi-Application Architecture & Naming Conventions
Audience: DevOps Engineers, Infrastructure Team, Developers Status: Architecture Reference Document Last Updated: November 2025
Overview
This document defines the multi-application architecture for Maple Open Technologies production infrastructure. The infrastructure is designed to support multiple independent applications (MaplePress, MapleFile, mapleopentech) sharing common infrastructure (Cassandra, Redis, Meilisearch) while maintaining clear boundaries and isolation.
Architecture Principles
1. Shared Infrastructure, Isolated Applications
┌─────────────────────────────────────────────────────────────────┐
│ SHARED INFRASTRUCTURE │
│ (Used by ALL apps: MaplePress, MapleFile, mapleopentech) │
├─────────────────────────────────────────────────────────────────┤
│ Infrastructure Workers (1-5): │
│ - Manager Node (worker-1): Redis │
│ - Cassandra Cluster (workers 2,3,4) │
│ - Meilisearch (worker 5) │
│ │
│ Networks: │
│ - mapleopentech-private-prod (databases, cache, search) │
│ - mapleopentech-public-prod (reverse proxies + backends) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ APPLICATION: MAPLEPRESS │
├─────────────────────────────────────────────────────────────────┤
│ Worker 6 - MaplePress Backend + Proxy: │
│ Stack: maplepress │
│ │
│ Service: maplepress_backend │
│ Hostname: maplepress-backend │
│ Port: 8000 │
│ Networks: mapleopentech-private-prod + mapleopentech-public-prod │
│ Connects to: Cassandra, Redis, Meilisearch, Spaces │
│ │
│ Service: maplepress_backend-caddy │
│ Hostname: caddy │
│ Domain: getmaplepress.ca (API) │
│ Proxies to: maplepress-backend:8000 │
│ │
│ Worker 7 - MaplePress Frontend: │
│ Stack: maplepress-frontend │
│ Service: maplepress-frontend_caddy │
│ Hostname: frontend-caddy │
│ Domain: getmaplepress.com (Web UI) │
│ Serves: /var/www/maplepress-frontend/ │
│ Calls: https://getmaplepress.ca (backend API) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ APPLICATION: MAPLEFILE (Future) │
├─────────────────────────────────────────────────────────────────┤
│ Worker 8 - MapleFile Backend + Proxy: │
│ Stack: maplefile │
│ │
│ Service: maplefile_backend │
│ Hostname: maplefile-backend │
│ Port: 8000 │
│ Networks: mapleopentech-private-prod + mapleopentech-public-prod │
│ Connects to: Cassandra, Redis, Meilisearch, Spaces │
│ │
│ Service: maplefile_backend-caddy │
│ Hostname: maplefile-backend-caddy │
│ Domain: maplefile.ca (API) │
│ Proxies to: maplefile-backend:8000 │
│ │
│ Worker 9 - MapleFile Frontend: │
│ Stack: maplefile-frontend │
│ Service: maplefile-frontend_caddy │
│ Hostname: maplefile-frontend-caddy │
│ Domain: maplefile.com (Web UI) │
│ Serves: /var/www/maplefile-frontend/ │
│ Calls: https://maplefile.ca (backend API) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ APPLICATION: mapleopentech (Future) │
├─────────────────────────────────────────────────────────────────┤
│ Worker 10 - mapleopentech Backend + Proxy: │
│ Stack: mapleopentech │
│ │
│ Service: mapleopentech_backend │
│ Hostname: mapleopentech-backend │
│ Port: 8000 │
│ Networks: mapleopentech-private-prod + mapleopentech-public-prod │
│ Connects to: Cassandra, Redis, Meilisearch, Spaces │
│ │
│ Service: mapleopentech_backend-caddy │
│ Hostname: mapleopentech-backend-caddy │
│ Domain: api.mapleopentech.io (API) │
│ Proxies to: mapleopentech-backend:8000 │
│ │
│ Worker 11 - mapleopentech Frontend: │
│ Stack: mapleopentech-frontend │
│ Service: mapleopentech-frontend_caddy │
│ Hostname: mapleopentech-frontend-caddy │
│ Domain: mapleopentech.io (Web UI) │
│ Serves: /var/www/mapleopentech-frontend/ │
│ Calls: https://api.mapleopentech.io (backend API) │
└─────────────────────────────────────────────────────────────────┘
Naming Conventions
Pattern: Option C - Hybrid Stacks
Strategy:
- Backend + Backend Caddy in one stack (deployed together)
- Frontend Caddy in separate stack (independent deployment)
Why this pattern?
- Backend and its reverse proxy are tightly coupled → deploy together
- Frontend is independent → deploy separately
- Avoids redundant naming like
maplepress-backend_backend - Clean service names:
maplepress_backend,maplepress_backend-caddy,maplepress-frontend_caddy
Stack Names
| Application | Stack Name | Services in Stack | Purpose |
|---|---|---|---|
| MaplePress | maplepress |
backend, backend-caddy |
Backend API + reverse proxy |
| MaplePress | maplepress-frontend |
caddy |
Frontend static files |
| MapleFile | maplefile |
backend, backend-caddy |
Backend API + reverse proxy |
| MapleFile | maplefile-frontend |
caddy |
Frontend static files |
| mapleopentech | mapleopentech |
backend, backend-caddy |
Backend API + reverse proxy |
| mapleopentech | mapleopentech-frontend |
caddy |
Frontend static files |
Service Names (Docker Auto-Generated)
Docker Swarm automatically creates service names from: {stack-name}_{service-name}
| Stack Name | Service in YAML | Full Service Name | Purpose |
|---|---|---|---|
maplepress |
backend |
maplepress_backend |
Go backend API |
maplepress |
backend-caddy |
maplepress_backend-caddy |
Backend reverse proxy |
maplepress-frontend |
caddy |
maplepress-frontend_caddy |
Frontend static file server |
maplefile |
backend |
maplefile_backend |
Go backend API |
maplefile |
backend-caddy |
maplefile_backend-caddy |
Backend reverse proxy |
maplefile-frontend |
caddy |
maplefile-frontend_caddy |
Frontend static file server |
View services:
docker service ls
# Output:
# maplepress_backend 1/1
# maplepress_backend-caddy 1/1
# maplepress-frontend_caddy 1/1
# maplefile_backend 1/1
# maplefile_backend-caddy 1/1
# maplefile-frontend_caddy 1/1
Hostnames (DNS Resolution Within Networks)
Hostnames are defined in the stack YAML (hostname: ...) and used for container-to-container communication.
| Application | Component | Hostname | Used By |
|---|---|---|---|
| MaplePress | Backend | maplepress-backend |
Caddy proxy, other services |
| MaplePress | Backend Caddy | caddy |
Internal reference (rarely used) |
| MaplePress | Frontend Caddy | frontend-caddy |
Internal reference (rarely used) |
| MapleFile | Backend | maplefile-backend |
Caddy proxy, other services |
| MapleFile | Backend Caddy | caddy |
Internal reference (rarely used) |
| MapleFile | Frontend Caddy | frontend-caddy |
Internal reference (rarely used) |
Example - Caddyfile for MaplePress backend:
getmaplepress.ca www.getmaplepress.ca {
reverse_proxy maplepress-backend:8000 # Uses hostname, not service name
}
Example - Caddyfile for MapleFile backend:
maplefile.ca www.maplefile.ca {
reverse_proxy maplefile-backend:8000
}
Docker Configs (Auto-Generated with Stack Prefix)
| Stack Name | Config in YAML | Full Config Name |
|---|---|---|
maplepress |
caddyfile |
maplepress_caddyfile |
maplepress-frontend |
caddyfile |
maplepress-frontend_caddyfile |
maplefile |
caddyfile |
maplefile_caddyfile |
maplefile-frontend |
caddyfile |
maplefile-frontend_caddyfile |
View configs:
docker config ls
# Output:
# maplepress_caddyfile
# maplepress-frontend_caddyfile
# maplefile_caddyfile
# maplefile-frontend_caddyfile
File Paths
| Application | Component | Path |
|---|---|---|
| MaplePress | Frontend | /var/www/maplepress-frontend/ |
| MaplePress | Backend | /var/www/monorepo/cloud/mapleopentech-backend/ |
| MapleFile | Frontend | /var/www/maplefile-frontend/ |
| MapleFile | Backend | /var/www/monorepo/cloud/mapleopentech-backend/ |
Resource Allocation
Workers 1-5: Shared Infrastructure (ALL Apps)
| Worker | Role | Services | Shared By |
|---|---|---|---|
| 1 | Manager + Redis | Swarm manager, Redis cache | All apps |
| 2 | Cassandra Node 1 | cassandra-1 | All apps |
| 3 | Cassandra Node 2 | cassandra-2 | All apps |
| 4 | Cassandra Node 3 | cassandra-3 | All apps |
| 5 | Meilisearch | meilisearch (full-text search) | All apps |
Workers 6-7: MaplePress Application
| Worker | Role | Services |
|---|---|---|
| 6 | MaplePress Backend + Proxy | maplepress_backend, maplepress_backend-caddy |
| 7 | MaplePress Frontend | maplepress-frontend_caddy |
Workers 8-9: MapleFile Application (Future)
| Worker | Role | Services |
|---|---|---|
| 8 | MapleFile Backend + Proxy | maplefile_backend, maplefile_backend-caddy |
| 9 | MapleFile Frontend | maplefile-frontend_caddy |
Workers 10-11: mapleopentech Application (Future)
| Worker | Role | Services |
|---|---|---|
| 10 | mapleopentech Backend + Proxy | mapleopentech_backend, mapleopentech_backend-caddy |
| 11 | mapleopentech Frontend | mapleopentech-frontend_caddy |
Network Topology
mapleopentech-private-prod (Shared by ALL Apps)
Purpose: Private backend services - databases, cache, search
Services:
- Cassandra cluster (3 nodes)
- Redis
- Meilisearch
- All backend services (maplepress-backend, maplefile-backend, mapleopentech-backend)
Security: No ingress ports, no internet access, internal-only
mapleopentech-public-prod (Per-App Reverse Proxies + Backends)
Purpose: Internet-facing services - reverse proxies and backends
Services:
- All backend services (join both networks)
- All Caddy reverse proxies (backend + frontend)
Security: Ports 80/443 exposed on workers running Caddy
Deployment Commands
MaplePress
# Backend + Backend Caddy (deployed together in one stack)
docker stack deploy -c maplepress-stack.yml maplepress
# Frontend (deployed separately)
docker stack deploy -c maplepress-frontend-stack.yml maplepress-frontend
MapleFile (Future)
# Backend + Backend Caddy (deployed together in one stack)
docker stack deploy -c maplefile-stack.yml maplefile
# Frontend (deployed separately)
docker stack deploy -c maplefile-frontend-stack.yml maplefile-frontend
mapleopentech (Future)
# Backend + Backend Caddy (deployed together in one stack)
docker stack deploy -c mapleopentech-stack.yml mapleopentech
# Frontend (deployed separately)
docker stack deploy -c mapleopentech-frontend-stack.yml mapleopentech-frontend
Verification Commands
List All Stacks
docker stack ls
# Expected output:
# NAME SERVICES
# cassandra 3
# maplepress 2 (backend + backend-caddy)
# maplepress-frontend 1 (frontend caddy)
# maplefile 2 (future)
# maplefile-frontend 1 (future)
# meilisearch 1
# redis 1
List All Services
docker service ls | sort
# Expected output (partial):
# cassandra_cassandra-1 1/1
# cassandra_cassandra-2 1/1
# cassandra_cassandra-3 1/1
# maplepress_backend 1/1
# maplepress_backend-caddy 1/1
# maplepress-frontend_caddy 1/1
# meilisearch_meilisearch 1/1
# redis_redis 1/1
List All Configs
docker config ls
# Expected output:
# maplepress_caddyfile
# maplepress-frontend_caddyfile
Adding a New Application
To add a new application (e.g., "MaplePortal"):
1. Update .env.template
# Add new section
# ==============================================================================
# MAPLEPORTAL APPLICATION
# ==============================================================================
# Backend Configuration
MAPLEPORTAL_BACKEND_DOMAIN=api.mapleportal.io
MAPLEPORTAL_SPACES_BUCKET=mapleportal-prod
MAPLEPORTAL_JWT_SECRET=CHANGEME
MAPLEPORTAL_IP_ENCRYPTION_KEY=CHANGEME
# Frontend Configuration
MAPLEPORTAL_FRONTEND_DOMAIN=mapleportal.io
MAPLEPORTAL_FRONTEND_API_URL=https://api.mapleportal.io
2. Create New Workers
# Worker 12 - Backend + Backend Caddy
# Worker 13 - Frontend Caddy
3. Follow Naming Convention
- Stack names:
mapleportal(backend + backend-caddy),mapleportal-frontend - Service names:
mapleportal_backend,mapleportal_backend-caddy,mapleportal-frontend_caddy - Hostnames:
mapleportal-backend,mapleportal-backend-caddy,mapleportal-frontend-caddy - Domains:
api.mapleportal.io(backend),mapleportal.io(frontend) - Paths:
/var/www/mapleportal-frontend/
4. Deploy Services
# Backend + backend-caddy in one stack
docker stack deploy -c mapleportal-stack.yml mapleportal
# Frontend in separate stack
docker stack deploy -c mapleportal-frontend-stack.yml mapleportal-frontend
Benefits of This Architecture
1. Clear Separation
- Each app has dedicated workers and services
- No naming conflicts between apps
- Easy to identify which services belong to which app
2. Shared Infrastructure Efficiency
- Single Cassandra cluster serves all apps
- Single Redis instance (or sharded by app)
- Single Meilisearch instance with app-prefixed indexes
- Cost savings: 5 workers for infrastructure vs 15+ if each app had its own
3. Independent Scaling
- Scale MaplePress without affecting MapleFile
- Deploy new apps without touching existing ones
- Remove apps without impacting infrastructure
4. Operational Clarity
# View only MaplePress services
docker service ls | grep maplepress
# View only MapleFile services
docker service ls | grep maplefile
# Restart MaplePress backend
docker service update --force maplepress_backend
# Remove MapleFile entirely (if needed)
docker stack rm maplefile
docker stack rm maplefile-frontend
5. Developer Friendly
- Developers instantly know which app they're working with
- No ambiguous "backend" or "frontend" names
- Service discovery is intuitive:
maplepress-backend:8000
Migration Checklist (For Existing Deployments)
If you deployed with old naming (caddy, maplepress, frontend-caddy), migrate like this:
Step 1: Update Configuration Files Locally
cd ~/monorepo/cloud/infrastructure/production
# Update all YAML files to use new naming
# - maplepress → maplepress-backend
# - caddy → maplepress-backend-caddy
# - frontend-caddy → maplepress-frontend-caddy
# Update Caddyfiles to use new hostnames
# - backend:8000 → maplepress-backend:8000
Step 2: Remove Old Stacks
# On manager node
docker stack rm maplepress
docker stack rm caddy
docker stack rm frontend-caddy
# Wait for cleanup
sleep 10
# Remove old configs
docker config rm caddy_caddyfile
docker config rm frontend-caddy_caddyfile
Step 3: Deploy New Stacks
# Deploy with new names (Option C naming)
docker stack deploy -c maplepress-stack.yml maplepress
docker stack deploy -c maplepress-frontend-stack.yml maplepress-frontend
Step 4: Verify
docker service ls
# Should show:
# maplepress_backend
# maplepress_backend-caddy
# maplepress-frontend_caddy
docker config ls
# Should show:
# maplepress_caddyfile
# maplepress-frontend_caddyfile
Last Updated: November 2025 Maintained By: Infrastructure Team Status: Production Standard - Follow for All New Applications