Architecture -- System Topology and Design
9-Container Topology
Container Roles
| Container | Image | Internal Port | What It Does |
|---|---|---|---|
registry | images.example.com/registry:stable | 8000 | FastAPI backend + Vue frontend. All API endpoints (auth, agents, transfers, staking, governance, discovery). Runs 4 uvicorn workers; background tasks and reactors are leader-elected (one instance each across all workers). |
teg-layer | images.example.com/teg-layer:stable | 8080 | Token Exchange Gateway. Manages AVT balances, executes transfers, handles staking positions. Internal only -- accessed via the registry as a proxy. |
db | postgres:16-alpine | 5432 | Registry PostgreSQL. Stores agents, developers, governance proposals, event emission policies, federation state. |
teg-db | postgres:16-alpine | 5432 | TEG PostgreSQL. Stores balances, transaction history, staking positions, fee records. |
pgbouncer | edoburu/pgbouncer:latest | 6432 | Connection pooler for registry DB. Transaction-mode pooling: 200 max clients, 20 pool size. Reduces connection overhead with 4 workers. |
redis | redis:7-alpine | 6379 | Shared state across workers. Leader election for singleton background tasks, rate limiting counters, WebSocket pub/sub, session state. 128 MB LRU eviction. |
spire-agent | ghcr.io/spiffe/spire-agent:1.10.4 | -- | SPIFFE/SPIRE agent. Attests to the mainframe SPIRE server via x509 Proof of Possession. Provides cryptographic identity (SVIDs) to the cert-writer. |
cert-writer | images.example.com/cert-writer:stable | -- | Fetches X.509 SVID certificates from the SPIRE agent socket and writes them to a shared volume. Auto-refreshes every 5 minutes. |
nginx-federation | nginx:1.25-alpine | 8443 | mTLS sidecar. Presents SVID client certificates to peers and the EventStore. Reloads certificates every 5 minutes to match cert-writer rotation. |
Image registry: images are pulled from
images.example.comby default. Point the pull at your own mirror or private registry with theIMAGE_REGISTRYenvironment / compose variable.
Startup Dependency Chain
Services start in this order, enforced by Docker Compose healthchecks:
Phase 1 (no dependencies): spire-agent, db, teg-db, redis
Phase 2 (after databases): pgbouncer (waits for db)
teg-layer (waits for teg-db)
cert-writer (waits for spire-agent)
Phase 3 (after infrastructure): registry (waits for db, pgbouncer, teg-layer, redis, spire-agent)
Phase 4 (after registry): nginx-federation (waits for cert-writer, registry)Typical full-stack boot time: 30-60 seconds on modest hardware.
Network Architecture
Internal Bridge Network
All 9 containers share a single Docker bridge network (operator-net). Inter-container traffic uses Docker DNS (e.g., registry resolves to the registry container).
No container port is exposed to the host except:
- <registry-port> -- Registry API (user-facing)
- <federation-port> -- nginx federation sidecar (federation peer sync, EventStore communication)
External Connectivity
| Destination | Port | Protocol | Purpose |
|---|---|---|---|
events.example.com | 443 | HTTPS + mTLS | EventStore event submission (EVENTSTORE_MTLS_REQUIRED=true) |
spire.example.com | 8444 | gRPC + mTLS | SPIRE agent x509pop attestation |
images.example.com | 443 | HTTPS | Docker image registry (pull only) |
| Federation peers | 443 | HTTPS + mTLS | Bilateral agent card sync (via hub relay) |
Two Deployment Modes
Federated is the supported mode -- and effectively the only one to pick today. Standalone (below) is legacy, superseded by running your own sovereign frame (Chapter 11).
Federated (Recommended) -- 9 Containers
Your Registry --[mTLS]--> events.example.com (shared EventStore)
Your Registry --[mTLS]--> spire.example.com (SPIRE identity, x509pop attestation)
Your Registry <-[mTLS]-> Registry A hub (bilateral agent card sync)- Events written to the mainframe's immutable event ledger (
EVENTSTORE_MTLS_REQUIRED=true) - Bilateral federation: your registry syncs FROM Registry A (pull) AND pushes TO Registry A (push). Both directions use mTLS.
- Agent cards discoverable across the entire network
- Cross-registry AVT transfers enabled (2-phase commit, 0.5% fee to receiver)
- Minting disabled -- AVT enters via cross-registry transfers or genesis grants
- Supply invariant enforced per frame:
tokens_issued - tokens_destroyed + transit_net == tokens_circulating - Agent location propagation: each agent card carries
origin_registry_locationmetadata for geographic discovery
Standalone -- legacy (superseded by sovereign frames)
Your Registry --> its own local EventStoreStandalone predates sovereign frames and has not been built or exercised in months -- treat it as legacy. If full self-sovereignty is the goal, run your own frame (Section 11): a frame is the modern, maintained version of "standalone, but real" -- its own SPIRE trust domain, its own EventStore, its own economy, and the ability to peer with and exchange value with other frames. Standalone is kept here for history, not recommended for a fresh deployment.
- Own minting authority -- the TEG can issue its own currency.
- No federation, no peer discovery, no cross-registry transfers -- fully self-contained / air-gapped.
- A current build would be roughly 11 containers with a local EventStore (
event-store+es-db+redpanda), or 9 without one -- treat those numbers as approximate until it is re-tested.
To switch modes, change in .env.operator:
# Federated (default) -- authentication via SPIRE mTLS (no license key needed)
MINTING_AUTHORITY=disabled
EVENTSTORE_MTLS_REQUIRED=true
EVENT_STORE_ENABLED=true
# Standalone (legacy -- superseded by frames; not recently tested)
MINTING_AUTHORITY=teg-layer
EVENTSTORE_MTLS_REQUIRED=false
EVENT_STORE_ENABLED=false # or point to your local EventStoreData Flow
User Action Flow
Event Flow (Federated)
WebSocket Event Stream
The registry exposes a WebSocket endpoint for real-time event notifications:
ws://<your-registry-url>/ws/eventsThe nginx-federation sidecar proxies this as wss:// for external consumers. Events broadcast via Redis Pub/Sub across all 4 workers. Useful for dashboards and live monitoring.
What Operators CAN Customize
| Parameter | Range | Default |
|---|---|---|
| Intra-registry fee rate | 0.5% -- 5.0% | 0.5% |
| Genesis grant amount | 0 -- 100,000 AVT | 1,000 AVT |
| Genesis grant enabled | true/false | true |
| Beta invite required | true/false | false |
| Staking parameters | Within federation bounds | Defaults from onboarding |
| Email provider | Any SMTP | Must configure |
| Rate limiting tiers | Configurable per tier | 60/min public, 300/min authenticated |
| Governance quorum / thresholds | Configurable | Registry-specific (set via governance config) |
What Operators CANNOT Change (Federated Mode)
| Constraint | Reason |
|---|---|
| Minting authority | Disabled. Prevents rogue supply inflation. |
| Supply invariant | tokens_issued - tokens_destroyed + transit_net == tokens_circulating enforced per frame. |
| Minimum fee floor | 0.5% -- prevents race-to-zero fee competition. |
| Maximum fee ceiling | 5.0% -- prevents exploitative fee extraction. |
| Maximum base staking APY | 15% base rate (r_max) -- lock premiums are additive on top. |
| Event immutability | Events cannot be deleted or modified after submission. |
| SPIRE identity | Issued by mainframe. Revocable for quarantine. |
| Cross-registry fee | 0.5% to receiver's TEG treasury (fixed). |
Background Tasks (Auto-Started)
The registry runs its background tasks plus the reactor framework, coordinated via Redis leader election so that only one worker instance runs each task even with 4 uvicorn workers:
| Task | Interval | Purpose |
|---|---|---|
| Federation Sync | 5 min | Push/pull agent cards to/from peers |
| Supply Auditor | periodic | Verify supply invariant in EventStore |
| Staking Rewards | daily | Distribute staking rewards |
| EigenTrust Worker | periodic | Compute agent reputation scores |
| Velocity Snapshot | periodic | Track transaction velocity for fee scaling |
| Settlement Reconciliation | periodic | Reconcile pending settlements |
| Saga Timeout | periodic | Clean up stale 2PC transactions |
| Peer Health Check | 1 hour | Verify federation peer availability |
| A2A Payment Expiry | 60 sec | Expire stale payment tokens |
| WebSocket Metrics | periodic | Broadcast live metrics via WebSocket |
| Auto Tally | configurable | Tally expired governance proposals automatically |
| Collusion Worker | periodic | Detect collusion patterns in transaction graphs |
| Compliance Poller | 6 hours | Poll federated registries for policy compliance |
| Auditor Worker | periodic | Algorithmic audit of financial invariants |
| Webhook Retry | periodic | Retry failed webhook deliveries |
All tasks are automatic. No operator intervention required.
Stack Health (Operator Mode)
The /health endpoint returns an extended response when called from an authenticated operator context, including database connectivity, Redis health, SPIRE agent status, and background task leader state. Use this for automated monitoring:
curl http://localhost:<registry-port>/healthMonitor federation sync status via GET /api/v1/federation/sync-status (see the Federation guide, Section 03).