Full System Architecture
▸ END-TO-END TRAFFIC & CONTROL FLOW
graph TB
%% ── External ──────────────────────────────────────────────
Browser["🌐 Browser / CLI\nTenant User"]:::ext
Admin["🔑 Platform Admin\nAPI Key / OIDC"]:::ext
%% ── Edge layer ────────────────────────────────────────────
subgraph EDGE[" ⚡ EDGE LAYER "]
Traefik["⬡ Traefik v3\nL7 Reverse Proxy\n+ TLS Termination\n+ Rate Limiting"]:::traefik
end
%% ── Control plane ─────────────────────────────────────────
subgraph CP[" 🧠 CONTROL PLANE (Go + Fiber v2) "]
direction TB
FiberAPI["▶ Fiber HTTP Server\nMiddleware Stack\nrecovery · cors · limiter\nidempotency · zap"]:::fiber
subgraph HANDLERS["API Handlers /api/v1"]
H_Tenant["Tenant\nHandler"]:::handler
H_App["App\nHandler"]:::handler
H_Cluster["Cluster\nHandler"]:::handler
H_Events["Events\nHandler"]:::handler
end
subgraph CORE["Core Services"]
OAMTranslator["📐 OAM Translator\nApplication → Nomad Job\nComponent → TaskGroup\nTrait → Constraint/Tag"]:::core
Store["💾 State Store\nTenants · Apps · Events\n(memory | etcd | pg)"]:::core
Metrics["📊 Prometheus\nMetrics Registry\nHTTP · Deploy · Nomad"]:::core
end
FiberAPI --> H_Tenant & H_App & H_Cluster & H_Events
H_App --> OAMTranslator
H_Tenant & H_App --> Store
FiberAPI --> Metrics
end
%% ── HashiCorp stack ───────────────────────────────────────
subgraph HASHI[" 🔶 HASHICORP STACK "]
direction LR
subgraph NomadMgr["Nomad Cluster Manager"]
Strategy["Scheduling Strategy\nprimary · round-robin\nleast-loaded"]:::nomad
end
subgraph ConsulMgr["Consul Tenant Manager"]
ConsulNS["Namespace\nIsolation"]:::consul
ConsulACL["ACL Policies\n+ Tokens"]:::consul
ConsulIntentions["Service Mesh\nIntentions"]:::consul
end
subgraph TraefikWriter["Traefik Config Writer"]
DynYAML["YAML Config\nWriter (atomic\nrename)"]:::traefik2
end
Vault["🔐 Vault\nSecret Engine\nPKI · KV · Dynamic"]:::vault
end
%% ── Multicloud Nomad clusters ─────────────────────────────
subgraph CLOUDS[" ☁ MULTICLOUD NOMAD CLUSTERS "]
direction LR
subgraph AWS["▲ AWS"]
NomadAWS["Nomad Cluster\nus-east-1"]:::aws
ConsulAWS["Consul\nDatacenter"]:::consul
end
subgraph GCP["◆ GCP"]
NomadGCP["Nomad Cluster\neurope-west1"]:::gcp
ConsulGCP["Consul\nDatacenter"]:::consul
end
subgraph AZURE["■ Azure"]
NomadAzure["Nomad Cluster\neastasia"]:::azure
ConsulAzure["Consul\nDatacenter"]:::consul
end
end
%% ── Workloads ─────────────────────────────────────────────
subgraph WORKLOADS[" 📦 TENANT WORKLOADS "]
direction LR
WL1["WebService\n(service job)"]:::wl
WL2["Worker\n(service job)"]:::wl
WL3["CronTask\n(periodic batch)"]:::wl
WL4["Daemon\n(system job)"]:::wl
end
%% ── UI ────────────────────────────────────────────────────
UI["⬕ Svelte UI\n+ Tailwind CSS\nSPA Dashboard"]:::ui
%% ── Edges ─────────────────────────────────────────────────
Browser -->|"HTTPS"| Traefik
Admin -->|"X-API-Key\nor OIDC JWT"| Traefik
UI -->|"REST /api/v1"| Traefik
Traefik -->|"Consul catalog\nservice discovery"| ConsulMgr
Traefik -->|"File provider\nwatches dir"| DynYAML
Traefik -->|"Route to tenant\nworkload"| WORKLOADS
FiberAPI -->|"auth middleware\nrequest routing"| HANDLERS
H_Tenant -->|"provision/deprovision"| ConsulMgr
H_Tenant -->|"write routing rules"| TraefikWriter
H_App -->|"submit / deregister\nnomad jobs"| NomadMgr
H_Cluster -->|"query nodes,\njobs, allocs"| NomadMgr
OAMTranslator -->|"nomadapi.Job"| NomadMgr
NomadMgr -->|"strategy: primary\nround-robin\nleast-loaded"| Strategy
Strategy -->|"Jobs().Register()"| NomadAWS & NomadGCP & NomadAzure
ConsulMgr --> ConsulNS & ConsulACL & ConsulIntentions
ConsulNS & ConsulACL -->|"namespace ACLs"| ConsulAWS & ConsulGCP & ConsulAzure
NomadAWS & NomadGCP & NomadAzure -->|"run allocs"| WORKLOADS
WORKLOADS -->|"register services"| ConsulAWS & ConsulGCP & ConsulAzure
WORKLOADS -->|"fetch secrets"| Vault
classDef ext fill:#0d1520,stroke:#1e3a5a,color:#7ab8f5
classDef traefik fill:#0a1e28,stroke:#26b5d8,color:#26b5d8
classDef traefik2 fill:#0a1e28,stroke:#26b5d866,color:#26b5d8
classDef fiber fill:#0a200e,stroke:#00de64,color:#00de64
classDef handler fill:#071a0b,stroke:#1a4025,color:#6ed89a
classDef core fill:#071a0b,stroke:#2a5535,color:#8fc4a0
classDef nomad fill:#0d1a06,stroke:#5da832,color:#7dd14d
classDef consul fill:#1a0f06,stroke:#e76d3b,color:#e76d3b
classDef vault fill:#1a1006,stroke:#c8a84b,color:#c8a84b
classDef aws fill:#1a0e00,stroke:#ff9900,color:#ff9900
classDef gcp fill:#060e1a,stroke:#4285f4,color:#4285f4
classDef azure fill:#00091a,stroke:#0078d4,color:#0078d4
classDef wl fill:#0d1a12,stroke:#2a4a30,color:#6ea880
classDef ui fill:#140a1a,stroke:#8b5cf6,color:#a78bfa
OAM → Nomad Translation Pipeline
▸ OPEN APPLICATION MODEL RESOURCE FLOW
flowchart LR
subgraph INPUT[" OAM Input (JSON/YAML) "]
direction TB
APP["Application\napiVersion: core.oam.dev/v1beta1\nkind: Application"]:::oam
COMP["ApplicationComponent\n• name, type (webservice|worker…)\n• properties (image, ports, env)\n• targetClusters"]:::oam
TRAITS["Traits\n• scaler → replicas, min/max\n• ingress → host, pathPrefix, TLS\n• vault-secret → path, env map\n• affinity → cloud, region, nodeClass\n• volume → type, source, mountPath"]:::oam
APP --> COMP --> TRAITS
end
subgraph TRANS[" Translator (Go) "]
direction TB
T1["componentKindToNomadType()\nwebservice/worker → service\ntask/cron-task → batch\ndaemon → system"]:::trans
T2["buildTaskGroup()\ncount from ScalerTrait\nRestartPolicy, UpdateStrategy\nMigrateStrategy"]:::trans
T3["buildTraefikTags()\nHost() / PathPrefix() rules\ncertresolver tags\nsticky cookie, healthcheck"]:::trans
T4["buildConstraints()\n${meta.cloud}\n${meta.cloud_region}\n${node.class}"]:::trans
T5["buildVaultTemplate()\nconsul-template syntax\nenvvars = true"]:::trans
T6["buildScalingPolicy()\nNomad Autoscaler\ntarget-value strategy"]:::trans
T1 --> T2
T2 --> T3 & T4 & T5 & T6
end
subgraph OUTPUT[" Nomad Job Spec "]
direction TB
JOB["nomadapi.Job\n• ID, Namespace, Type\n• Datacenters, Meta\n• Periodic (cron)\n• Vault policy"]:::nomad2
TG["TaskGroup\n• Count (replicas)\n• RestartPolicy\n• UpdateStrategy\n• Spread stanza\n• Constraints"]:::nomad2
SVC["Service\n• Provider: consul\n• Traefik tags\n• Connect sidecar\n• Health checks"]:::nomad2
TASK["Task (Docker)\n• image, ports\n• Env map\n• Resources\n• Templates (Vault)\n• VolumeMounts"]:::nomad2
SCALE["ScalingPolicy\n• min/max\n• nomad-apm source\n• target-value\n• cooldown: 2m"]:::nomad2
JOB --> TG --> SVC & TASK & SCALE
end
INPUT -->|"Translator.Translate()\napp, tenantID"| TRANS
TRANS -->|"*nomadapi.Job\nper component"| OUTPUT
OUTPUT -->|"Jobs().Register()"| NOMAD[("Nomad\nCluster")]:::cluster
classDef oam fill:#0e0a1a,stroke:#a78bfa,color:#c4aafa
classDef trans fill:#071a0b,stroke:#2a5535,color:#7aad88
classDef nomad2 fill:#0d1a06,stroke:#5da832,color:#7dd14d
classDef cluster fill:#0d1a06,stroke:#5da832,color:#7dd14d
Multi-Tenant Isolation Model
▸ TENANT PROVISIONING & ISOLATION BOUNDARIES
sequenceDiagram
actor Admin
participant Fiber as Fiber API
participant Store as State Store
participant Consul as Consul Manager
participant Nomad as Nomad Manager
participant Traefik as Traefik Writer
participant Vault as Vault
Admin->>+Fiber: POST /api/v1/tenants\n{name, domain, quotas}
Fiber->>Store: CreateTenant() → UUID
Store-->>Fiber: *Tenant{id, name, ...}
Fiber->>+Consul: ProvisionTenant(tenantID)
Consul->>Consul: ensureNamespace("tenant-{id}")
Consul->>Consul: ensurePolicy(ns) → ACL HCL rules
Consul->>Consul: ensureToken(policyID) → SecretID
Consul->>Consul: ensureIntentions()\nAllow intra-ns\nDeny cross-ns
Consul-->>-Fiber: TenantResources{namespace, token}
loop Each Nomad cluster
Fiber->>Nomad: EnsureNamespace("tenant-{id}")
Nomad-->>Fiber: OK (idempotent)
end
Fiber->>Traefik: WriteTenantConfig(tenantID, domain)
Note over Traefik: Writes tenant-{id}.yml atomically\n• Rate limit middleware\n• Tenant header injection\n• Security headers chain\n• Domain catch-all router
Fiber->>Store: AddEvent("tenant.create")
Fiber-->>-Admin: 201 Created {tenant}
Note over Admin,Vault: Later: App Deploy
Admin->>+Fiber: POST /tenants/{id}/apps\nOAM Application JSON
Fiber->>Fiber: OAMTranslator.Translate(app, tenantID)
Note over Fiber: Per component:\n→ Nomad Job\n→ Traefik tags in Consul service\n→ Vault template blocks
loop Each component
Fiber->>+Nomad: SubmitJob(cluster, *nomadapi.Job)
Nomad->>Nomad: Pick cluster\n(strategy: primary | round-robin | least-loaded)
Nomad-->>-Fiber: EvalID
end
Fiber->>Store: SaveApp(tenantID, app)
Fiber-->>-Admin: 202 Accepted {app, submitted[]}
Live Request Routing (Traefik + Consul)
▸ L7 TRAFFIC PATH FOR TENANT WORKLOADS
flowchart TD
REQ["HTTPS Request\nHost: api.tenant-a.acme.com"]:::req
subgraph TRAEFIK["Traefik v3"]
EP["EntryPoint: websecure\n:443"]:::t
TLS["TLS Termination\nLet's Encrypt ACME\nor internal Vault PKI"]:::t
DISCOVERY["Consul Catalog\nProvider\n• polls every 15s\n• reads Traefik tags\n• builds route table"]:::t
subgraph MW["Middleware Chain (per tenant)"]
RL["Rate Limiter\n100 req/min avg\nburst 50"]:::mw
TH["Tenant Headers\nX-Tenant-ID\nX-Tenant-Namespace\nX-Forwarded-By"]:::mw
SEC["Security Headers\nHSTS · X-Frame\nContent-Type\nReferrer-Policy"]:::mw
CB["Circuit Breaker\nNetworkError > 30%\nor 5xx > 25%"]:::mw
end
ROUTER["Router Match\nHost(api.tenant-a.acme.com)\npriority: auto"]:::t
LB["Load Balancer\nRound Robin\nsticky cookie\nhealthcheck: /healthz 10s"]:::t
end
subgraph CONSUL["Consul Service Mesh"]
CAT["Catalog\nservice: api-api-http\ntags: [traefik.enable=true, …]"]:::consul
ENVOY1["Envoy Sidecar\nmTLS upstream"]:::consul
end
subgraph NOMAD["Nomad Allocations (namespace: tenant-abc)"]
ALLOC1["Alloc 1\nDocker: api:v2.1\nport: 8080"]:::alloc
ALLOC2["Alloc 2\nDocker: api:v2.1\nport: 8080"]:::alloc
ALLOC3["Alloc 3\nDocker: api:v2.1\nport: 8080"]:::alloc
end
REQ --> EP --> TLS --> DISCOVERY
DISCOVERY <-->|"register/watch"| CAT
TLS --> ROUTER --> MW
RL --> TH --> SEC --> CB --> LB
LB -->|"upstream: consul\ncatalog service"| ENVOY1
ENVOY1 -->|"mTLS"| ALLOC1 & ALLOC2 & ALLOC3
CAT -.->|"Traefik tag\nparsing"| ROUTER
classDef req fill:#0d1520,stroke:#1e3a5a,color:#7ab8f5
classDef t fill:#0a1e28,stroke:#26b5d8,color:#26b5d8
classDef mw fill:#081620,stroke:#26b5d855,color:#7acde8
classDef consul fill:#1a0f06,stroke:#e76d3b,color:#e76d3b
classDef alloc fill:#0d1a06,stroke:#5da832,color:#7dd14d
Component Reference
Control Plane
Fiber HTTP Server
Go + Fiber v2. Handles all REST API traffic. Middleware: recovery, CORS, zap logging, rate limiter, idempotency keys, Prometheus instrumentation.
cmd/server/main.go
internal/api/handler.go
Fiber v2
validator
Workload Schema
OAM Translator
Converts OAM Application resources into Nomad API Job structs. Decodes typed traits (scaler, ingress, vault-secret, affinity, volume) via generic JSON round-trip.
internal/oam/translator.go
internal/oam/types.go
OAM v0.3
nomadapi
Orchestration
Nomad Manager
Manages N Nomad cluster clients. Scheduling strategies: primary, round-robin, least-loaded. Concurrent job listing via goroutines. Namespace provisioning.
internal/nomad/client.go
multi-cluster
autoscale
Service Mesh
Consul Manager
Provisions per-tenant Consul namespaces, ACL policies, ACL tokens, and Connect service mesh intentions. Allow intra-tenant, deny cross-tenant by default.
internal/consul/tenant.go
namespace
intentions
Ingress / Proxy
Traefik Writer
Atomically writes YAML dynamic config files into Traefik's watched directory. Per-tenant middleware chains, rate limiting, security headers, TLS cert resolvers.
internal/traefik/config.go
atomic write
file provider
Secrets
Vault Integration
Dynamic secret injection via Nomad template blocks using consul-template syntax. Per-tenant Vault policies. PKI for internal mTLS. Change mode: restart or signal.
internal/oam/translator.go\nbuildVaultTemplate()
dynamic
PKI
State
Store Layer
In-memory store with RWMutex for thread safety. Tenants, apps, events. Pluggable backend — swap for etcd or PostgreSQL without changing handler code.
internal/store/store.go
memory
etcd-ready
Observability
Metrics & Logging
Prometheus metrics: HTTP request count/duration, deployment rate/latency, Nomad submit errors, tenant/app gauges. Zap structured logging. pprof in debug mode.
internal/metrics/metrics.go
internal/middleware/middleware.go
prometheus
zap
Deploy Flow
Tenant POSTs OAM Application JSON →
Fiber validates + parses → OAM Translator converts each
ApplicationComponent into a nomadapi.Job →
Nomad Manager picks cluster per scheduling strategy →
Jobs().Register() called per component →
Consul service tags auto-configure Traefik routing.
Scheduling Strategies
primary — all jobs to designated primary cluster.
round-robin — atomic counter cycles across clusters.
least-loaded — polls allocation count per cluster, picks minimum.
Override per-component via targetClusters: [aws-us-east].
Tenant Isolation
Each tenant maps to a Nomad namespace (quota enforcement),
a Consul namespace (service mesh ACL), a Vault
namespace (secret isolation), and a Traefik middleware
chain (rate limit + header injection + security hardening).