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; its source is available below
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 --> MinIO

Port Allocation

PortServiceProtocolExposed
8000backendHTTPvia Traefik
8001survey-serviceHTTPvia Traefik
8002data-serviceHTTPvia Traefik
8003sync-serviceHTTPvia Traefik
8004analytics-serviceHTTPvia Traefik
8006workspace-serviceHTTPvia Traefik
8007webhook-serviceHTTPvia Traefik
8009odk-bridgeHTTPvia Traefik
8010form-serviceHTTPvia Traefik
8011media-serviceHTTPvia Traefik
8012notification-serviceHTTPvia Traefik
8013audit-serviceHTTPvia Traefik
8014feature-flags-serviceHTTPvia Traefik
8030scalar-serviceHTTP:8030
5433PostgreSQL (host)TCP:5433
6372Redis (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-service

Service 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",
    }
}