System Topology
Network topology, service discovery, and port allocation for MQUAD microservices
Network Architecture
All services run on a shared Docker bridge network called mquad-network. Traefik acts as the ingress gateway, routing external requests to the appropriate service based on path prefixes.
Diagram source
graph TB
subgraph "External"
Browser[Browser]
ODKCollect[ODK Collect]
end
subgraph "Edge Layer"
Traefik[Traefik v3.0<br/>:80 / :443 / :8090]
end
subgraph "mquad-network Bridge"
subgraph "Core"
Backend[backend<br/>:8000]
end
subgraph "Domain"
Survey[survey-service<br/>:8001]
Data[data-service<br/>:8002]
Workspace[workspace-service<br/>:8006]
end
subgraph "Analytics"
Sync[sync-service<br/>:8003]
Analytics[analytics-service<br/>:8004]
end
subgraph "Integration"
Webhook[webhook-service<br/>:8007]
Form[form-service<br/>:8010]
ODK[odk-bridge<br/>:8009]
Media[media-service<br/>:8011]
end
subgraph "Support"
Notification[notification-service<br/>:8012]
Audit[audit-service<br/>:8013]
FeatureFlags[feature-flags-service<br/>:8014]
end
subgraph "Documentation"
Scalar[scalar-service<br/>:8030]
end
subgraph "Infrastructure"
Postgres[(PostgreSQL :5432)]
Redis[(Redis :6379)]
MinIO[(MinIO :9000)]
end
subgraph "Monitoring"
Prometheus[Prometheus :9090]
Grafana[Grafana :3001]
Loki[Loki :3100]
Jaeger[Jaeger :16686]
end
end
Browser --> Traefik
ODKCollect --> ODK
Traefik --> Backend
Traefik --> Scalar
Traefik --> Survey
Traefik --> Data
Traefik --> Sync
Traefik --> Analytics
Traefik --> Workspace
Traefik --> Webhook
Traefik --> ODK
Traefik --> Form
Traefik --> Media
Traefik --> Notification
Traefik --> Audit
Traefik --> FeatureFlags
Backend --> Postgres
Backend --> Redis
Survey --> Postgres
Survey --> Redis
Data --> Postgres
Data --> Redis
Media --> MinIOPort Allocation
| Port | Service | Protocol | Exposed |
|---|---|---|---|
| 8000 | backend | HTTP | via Traefik |
| 8001 | survey-service | HTTP | via Traefik |
| 8002 | data-service | HTTP | via Traefik |
| 8003 | sync-service | HTTP | via Traefik |
| 8004 | analytics-service | HTTP | via Traefik |
| 8006 | workspace-service | HTTP | via Traefik |
| 8007 | webhook-service | HTTP | via Traefik |
| 8009 | odk-bridge | HTTP | via Traefik |
| 8010 | form-service | HTTP | via Traefik |
| 8011 | media-service | HTTP | via Traefik |
| 8012 | notification-service | HTTP | via Traefik |
| 8013 | audit-service | HTTP | via Traefik |
| 8014 | feature-flags-service | HTTP | via Traefik |
| 8030 | scalar-service | HTTP | :8030 |
| 5433 | PostgreSQL (host) | TCP | :5433 |
| 6372 | Redis (host) | TCP | :6372 |
Traefik Routing
Traefik routes requests based on path prefix rules defined in api-gateway/traefik/dynamic.yaml:
http:
routers:
backend:
rule: "PathPrefix(`/api/v1`)"
service: backend
survey-service:
rule: "PathPrefix(`/api/v1/surveys`)"
service: survey-service
scalar:
rule: "PathPrefix(`/`)"
service: scalar-serviceService Discovery
Services use static DNS-based discovery via Docker Compose service names. Each service resolves others by container name (e.g., http://survey-service:8001). The scalar-service performs active discovery by polling health endpoints:
SERVICE_DEFINITIONS = {
"survey-service": {
"url": "http://survey-service:8001",
"port": 8001,
"health_url": "http://survey-service:8001/api/v1/health",
}
}