Go Components

Three deliberate Go components — chosen because the workload fits the language, not for variety.


Table of Contents

  1. Why Go in a Java + Python Platform?
  2. Component 1 — anchita-cli
    1. What It Is
    2. Commands
    3. Tech Stack
    4. Configuration
    5. Distribution
  3. Component 2 — Notification Service (WebSocket Hub)
    1. What It Is
    2. Why Go, Not Spring Boot
    3. Architecture
    4. Tech Stack
    5. EKS Deployment
  4. Component 3 — API Gateway (Anchita Digital Banking Portal)
    1. What It Is
    2. Why Go, Not Spring Boot
    3. Architecture
    4. Code Shape
    5. Tech Stack
    6. EKS Deployment
  5. Go Components — Summary
  6. Learning Path for Go in This Project

Why Go in a Java + Python Platform?

Anchita is a deliberately polyglot architecture. The principle is simple: use the right tool for the workload. Java and Python cover the heavy lifting — durable workflows, complex domain logic, AI/ML toolchain. Go fills two specific gaps where its characteristics are a genuine fit:

Characteristic Java Python Go
Single static binary ✗ (needs JVM) ✗ (needs runtime)
Startup time 8–15 seconds 2–5 seconds < 500ms
Goroutine concurrency (10k+ idle connections) Complex (WebFlux) Complex (asyncio) Natural
CLI tooling ecosystem Adequate Adequate Best-in-class
Cross-platform native binary ✓ (GOOS cross-compile)
High-throughput reverse proxy / gateway Heavy (Spring MVC overhead) Not idiomatic Natural (standard library)

Each Go component in Anchita occupies a role where one or more of these characteristics is the deciding factor — not because Go is fashionable, but because the alternative would require meaningfully more resources or complexity to achieve the same result.


Component 1 — anchita-cli

What It Is

A Go command-line tool distributed to platform engineers, DevOps teams, and on-call operators. It wraps the Anchita REST API in a developer-friendly shell interface — no browser, no Temporal UI, no database access required for common operational tasks.

Commands

# ── Case management ──────────────────────────────────────────────
anchita cases list
anchita cases list --segment=ENTERPRISE --status=COMPLIANCE
anchita cases list --assigned-to=me --sla=AT_RISK
anchita cases show CASE-2026-042
anchita cases search --company="Acme Corp"

# ── Workflow operations ──────────────────────────────────────────
anchita workflow status CASE-2026-042
anchita workflow signal CASE-2026-042 \
    --signal=submitErrorRecovery \
    --action=RETRY
anchita workflow history CASE-2026-042 --tail=20

# ── Worker health ────────────────────────────────────────────────
anchita workers status
anchita workers queues
anchita workers queues --task-queue=product-provisioning --verbose

# ── Admin ────────────────────────────────────────────────────────
anchita admin product-catalog list
anchita admin product-catalog show WIRE_DOMESTIC
anchita admin segments

Tech Stack

anchita-cli (Go)
├── github.com/spf13/cobra      — command structure + subcommands
├── github.com/spf13/viper      — config file (~/.anchita/config.yaml) + env vars
├── github.com/olekukonko/tablewriter — formatted table output
└── net/http                    — REST API client (stdlib, no external dep)

Configuration

# ~/.anchita/config.yaml
api:
  base_url: https://api.anchita.example
  timeout: 30s
auth:
  token: ${ANCHITA_API_TOKEN}
output:
  format: table   # table | json | yaml

Distribution

Built and released via GitHub Actions as a multi-platform binary:

# .github/workflows/release-cli.yml (future)
- GOOS=darwin  GOARCH=arm64  → anchita-darwin-arm64
- GOOS=darwin  GOARCH=amd64  → anchita-darwin-amd64
- GOOS=linux   GOARCH=amd64  → anchita-linux-amd64
- GOOS=windows GOARCH=amd64  → anchita-windows-amd64.exe

Installable via brew install bits2qubits/anchita/anchita-cli or direct download from the GitHub releases page. No runtime dependency — single file, runs immediately.


Component 2 — Notification Service (WebSocket Hub)

What It Is

The real-time push service that delivers case state changes to the React operator workspace. When a Temporal workflow advances a phase, a human task is completed, or an AI suggestion arrives, the operator sees it in their browser within 1–2 seconds — without polling.

Why Go, Not Spring Boot

The workload profile is: many idle connections, small infrequent writes. This is the goroutine model’s natural habitat.

Metric Spring Boot (Thread-per-connection) Go (Goroutine-per-connection)
10,000 connections ~10,000 threads · ~10GB RAM ~10,000 goroutines · ~80MB RAM
1,000 connections ~1,000 threads · ~1GB RAM ~1,000 goroutines · ~8MB RAM
Stack size ~1MB per thread (JVM default) ~2–8KB per goroutine (grows on demand)
Programming model Reactive/WebFlux (complex) Simple blocking reads in a goroutine
Binary size on EKS 80MB JAR + JVM layer ~12MB static binary

At peak usage (operations team + all active cases), a banking operations floor might have 200–400 concurrent browser sessions. Go handles this trivially. But the architecture should not assume low numbers — a future enterprise rollout across multiple banks could push 5,000+ concurrent connections. Go scales linearly with zero architectural changes.

Architecture

Aurora PostgreSQL
  NOTIFY case_updated → Go notification-service (listener goroutine)
    → fan-out to all WebSocket connections subscribed to that case_id
      → React workspace receives update → Playbook stage refreshes
// Simplified connection hub
type Hub struct {
    connections map[string][]*websocket.Conn  // case_id → connections
    notify      chan CaseUpdate
    mu          sync.RWMutex
}

func (h *Hub) Run() {
    for update := range h.notify {
        h.mu.RLock()
        for _, conn := range h.connections[update.CaseID] {
            go conn.WriteJSON(update)  // non-blocking per client
        }
        h.mu.RUnlock()
    }
}

Tech Stack

notification-service (Go)
├── github.com/gorilla/websocket  — WebSocket implementation
├── github.com/lib/pq             — PostgreSQL LISTEN/NOTIFY listener
└── net/http                      — HTTP upgrade endpoint (stdlib)

EKS Deployment

# namespace: platform
notification-service:
  replicas: 2          # sticky sessions via ingress for WebSocket
  resources:
    requests:
      memory: "32Mi"   # dramatically lower than Java equivalent
      cpu: "50m"
    limits:
      memory: "128Mi"
      cpu: "200m"

The Go binary’s low memory footprint means the notification service costs a fraction of a comparable Spring Boot pod — relevant when running many replicas for high availability.


Component 3 — API Gateway (Anchita Digital Banking Portal)

What It Is

A lightweight reverse proxy and middleware chain that sits in front of all customer-facing traffic to the Anchita Digital Banking Portal. Treasury clients — the companies that Anchita onboards — access their accounts, initiate payments, and download reports through this gateway.

This is distinct from the existing Spring Boot API Gateway (Layer 2), which serves the internal operator workspace and banker mobile app. The two gateways serve different audiences with different traffic profiles:

Gateway Audience Traffic Profile Technology
Spring Boot GraphQL BFF Internal operators, banker mobile Moderate, complex queries, domain logic Spring Boot
Go API Gateway External treasury clients (portal) High concurrency, stateless I/O proxy Go

Why Go, Not Spring Boot

The portal gateway’s job is to receive a request, validate a JWT, check a rate limit, and forward the request to a backend service. It contains no business logic — only cross-cutting concerns. That workload profile is exactly where Spring Boot’s strengths (dependency injection, ORM, rich domain modelling) become overhead rather than value.

Metric Spring Boot Gateway Go Gateway
Memory per replica 256–512MB (JVM baseline) 20–40MB
Startup time 8–12 seconds < 100ms
5,000 concurrent clients Requires WebFlux + tuning Handled by goroutines natively
Binary size on EKS 80MB JAR + JVM ~15MB static binary

Production API gateways are overwhelmingly built in Go or C for exactly these reasons — Traefik, Caddy, and Kong (Go); Envoy (C++). Stripe’s infrastructure layer is heavily Go. This is the established industry pattern for the gateway role.

Architecture

Anchita Digital Banking Portal (React — browser)
            ↓  HTTPS
┌───────────────────────────────────────────────┐
│              Go API Gateway                    │
│                                               │
│  ┌─────────────────────────────────────────┐  │
│  │           Middleware Chain               │  │
│  │  1. RequestID     — trace ID per req    │  │
│  │  2. AuditLogger   — every req logged    │  │
│  │  3. JWTValidator  — Bearer token check  │  │
│  │  4. RateLimiter   — per-client (Redis)  │  │
│  │  5. PortalTierGate — STANDARD/ENTERPRISE│  │
│  └─────────────────────────────────────────┘  │
│                    ↓ routes to                 │
│  /api/accounts/*  →  Core Banking Ledger       │
│  /api/payments/*  →  Payment Service           │
│  /api/reports/*   →  BAI2 Report Generator     │
│  /api/rates/*     →  FRED API adapter          │
│  /ws/*            →  Notification Service      │
└───────────────────────────────────────────────┘

Portal tier gate: The PortalTierGate middleware reads the portalTier claim from the validated JWT (STANDARD or ENTERPRISE) and rejects requests to Enterprise-only endpoints from Standard-tier clients at the gateway — before the request reaches any backend service. No backend service needs to implement tier checking; it is enforced once, at the edge.

Code Shape

func main() {
    r := chi.NewRouter()

    // Cross-cutting middleware — every request
    r.Use(middleware.RequestID)
    r.Use(AuditLogger(db))          // writes to audit_events
    r.Use(JWTValidator(jwksURL))    // validates + injects claims
    r.Use(RateLimiter(redisClient)) // per client_id, per minute
    r.Use(PortalTierGate)           // STANDARD vs ENTERPRISE endpoints

    // Route groups with backend proxy targets
    r.Handle("/api/accounts/*",  reverseProxy(cfg.CoreBankingURL))
    r.Handle("/api/payments/*",  reverseProxy(cfg.PaymentServiceURL))
    r.Handle("/api/reports/*",   reverseProxy(cfg.ReportingServiceURL))
    r.Handle("/api/rates/*",     reverseProxy(cfg.FREDAdapterURL))
    r.Handle("/ws/*",            websocketProxy(cfg.NotificationServiceURL))
}

Each middleware is a standard func(http.Handler) http.Handler — composable, independently testable, zero framework coupling.

Tech Stack

anchita-portal-gateway (Go)
├── github.com/go-chi/chi/v5         — router + middleware composition
├── github.com/golang-jwt/jwt/v5     — JWT validation (RS256, JWKS endpoint)
├── golang.org/x/time/rate           — token bucket rate limiter (stdlib extension)
├── github.com/redis/go-redis/v9     — distributed rate limit state
├── github.com/sony/gobreaker        — circuit breaker for backend calls
└── net/http/httputil                 — ReverseProxy (stdlib — no external dep)

EKS Deployment

# namespace: platform
anchita-portal-gateway:
  replicas: 3            # stateless — scale horizontally
  resources:
    requests:
      memory: "32Mi"
      cpu: "100m"
    limits:
      memory: "128Mi"    # handles thousands of concurrent connections
      cpu: "500m"

Contrast with a Spring Boot equivalent at the same traffic level: ~512MB memory request, ~1000m CPU, 3–5 replicas minimum due to JVM warmup. The Go gateway achieves the same throughput at roughly one-eighth the memory cost.


Go Components — Summary

Component Role Key Go Feature Used
anchita-cli Operations CLI for platform engineers Single static binary, cobra command tree
Notification Service WebSocket hub — real-time case state push Goroutines, channels, LISTEN/NOTIFY
API Gateway Customer-facing reverse proxy + middleware net/http, goroutine-per-request, minimal memory

All three are statically compiled, independently deployable, and carry no JVM or Python runtime dependency. Each occupies a role where Go’s characteristics — binary size, startup time, goroutine concurrency, or standard-library depth — are the deciding factor.


Learning Path for Go in This Project

For someone new to Go, these three components form a natural progression — each one introducing the next layer of the language:

  1. Start with anchita-cli — pure Go, no concurrency. Learn cobra, viper, HTTP client, JSON parsing, table output. Immediate visible results. This is 2–3 weeks of focused Go learning that makes you productive in the language.

  2. Move to the Notification Service — introduces goroutines, channels, sync.RWMutex. The fan-out pattern (one incoming event → many WebSocket writes) is idiomatic Go and transfers directly to every concurrent Go program you’ll ever write.

  3. Build the API Gateway — brings it together. Middleware composition, HTTP reverse proxy, JWT parsing, Redis-backed rate limiting, circuit breakers. This is where Go’s standard library depth becomes visible — net/http alone covers most of what Spring needs a dozen dependencies for.

Good resources:

  • The Go Programming Language (Donovan & Kernighan) — language fundamentals
  • tour.golang.org — syntax and standard library
  • Concurrency in Go (Cox-Buday) — goroutine model for the notification service
  • pkg.go.dev/net/http — standard library HTTP for the gateway

↑ Back to top

Anchita Platform — Fictional Reference Architecture for Cloud-Native Institutional Banking