C4 Container — service topology & protocols
10 services grouped by domain (Identity · Catalog · Transaction) with REST, gRPC, GraphQL Federation, and Kafka edges.
Source: 03-c4-container.mermaid
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#FF9900','primaryBorderColor':'#232F3E','primaryTextColor':'#232F3E','lineColor':'#232F3E','secondaryColor':'#EAF2FB','tertiaryColor':'#F7F8FA','fontFamily':'Helvetica, Arial, sans-serif'}}}%%
flowchart TB
%% ===== C4-Container style diagram =====
%% Notation: rectangle = Container (deployable unit), cylinder = Data store,
%% stadium = External system, hexagon = Person. Protocol annotations on edges.
%% ---------- People / External ----------
user(["fa:fa-user Customer
browser + mobile"]):::person
stripe{{"Stripe
external PSP"}}:::ext
email{{"SES / SendGrid
transactional email"}}:::ext
%% ---------- Edge ----------
subgraph edge[" Edge Tier "]
direction TB
alb["ALB + AWS WAF
HTTPS · TLS via ACM"]:::edge
kong["kong-gateway
Kong OSS
JWT · rate-limit · CORS · CSRF"]:::svc
end
%% ---------- Frontend ----------
subgraph fe[" Frontend "]
direction TB
client[["client
Next.js 16 (App Router) · TS
SSR + Server Actions"]]:::svc
end
%% ---------- GraphQL Federation ----------
subgraph gql[" GraphQL Federation "]
direction TB
router[["apollo-router
Apollo Router v2.1
supergraph gateway"]]:::svc
end
%% ---------- Identity domain ----------
subgraph identity[" Identity "]
direction TB
auth[["auth-service
NestJS 10 · Node 24
signup · login · JWT"]]:::svc
user_svc[["user-service
NestJS 10 · Node 24
profile · prefs · billing"]]:::svc
auth_db[(auth_db
RDS PostgreSQL)]:::db
user_db[(user_db
RDS PostgreSQL)]:::db
auth --- auth_db
user_svc --- user_db
end
%% ---------- Catalog domain ----------
subgraph catalog[" Catalog "]
direction TB
ticket[["ticket-service
Go 1.23 · Echo v4 · gqlgen
quota · reserve · finalize"]]:::svc
venue[["venue-service
Go 1.23 · Echo v4 · gqlgen
seating plan · seat holds · SSE"]]:::svc
ticket_db[(ticket_db
MongoDB 7)]:::db
venue_db[(venue_db
RDS PostgreSQL)]:::db
venue_redis[(ElastiCache Redis
seat hold hot path)]:::db
ticket --- ticket_db
venue --- venue_db
venue --- venue_redis
end
%% ---------- Transaction domain ----------
subgraph txn[" Transaction "]
direction TB
order[["order-service
Java 21 · Spring Boot 4
saga orchestrator · outbox"]]:::svc
payment[["payment-service
NestJS 10 · Node 24
Stripe intents · webhooks"]]:::svc
expiration[["expiration-service
Go 1.23
Redis ZSET timers"]]:::svc
order_db[(order_db
RDS PostgreSQL
+ outbox)]:::db
payment_db[(payment_db
RDS PostgreSQL)]:::db
redis[(ElastiCache Redis
timers · cache · idempotency)]:::db
order --- order_db
payment --- payment_db
expiration --- redis
end
%% ---------- Messaging ----------
subgraph bus[" Async Messaging "]
direction LR
kafka{{"Amazon MSK · Kafka
CloudEvents v1.0 envelopes"}}:::mq
sr[["Glue Schema Registry
Avro/JSON Schema"]]:::mq
kafka --- sr
end
%% ===== Synchronous edges (HTTP/gRPC) =====
user -- HTTPS --> alb
alb --> kong
kong -- SSR --> client
kong -- "REST /auth/*" --> auth
kong -- "REST /users/*" --> user_svc
kong -- "REST /tickets/*" --> ticket
kong -- "REST /venues/*" --> venue
kong -- "REST /orders/*" --> order
kong -- "REST /payments/*" --> payment
kong -- "Stripe webhook" --> payment
kong -- "POST /graphql" --> router
%% Apollo Federation subgraph edges
router -. "subgraph" .-> auth
router -. "subgraph" .-> user_svc
router -. "subgraph" .-> ticket
router -. "subgraph" .-> venue
router -. "subgraph" .-> order
router -. "subgraph" .-> payment
%% gRPC inside the mesh
order == "gRPC ReserveQuota / Finalize / Release" ==> ticket
order == "gRPC ReserveHeldSeats / AutoAssign / Finalize" ==> venue
ticket == "gRPC GetSeatingPlan" ==> venue
auth -. "JWKS (pub key)" .-> kong
client -- "server-to-server API" --> kong
%% External
payment -- "HTTPS PaymentIntents" --> stripe
payment -- "email receipt" --> email
%% ===== Asynchronous edges (Kafka) =====
order -- "produces
orders.order.{created,cancelled,completed}" --> kafka
kafka -- "consumes" --> ticket
kafka -- "consumes" --> venue
kafka -- "consumes" --> expiration
kafka -- "consumes" --> payment
expiration -- "produces
expiration.order.expiration_complete" --> kafka
kafka -- "consumes" --> order
ticket -- "produces
tickets.ticket.{created,updated}" --> kafka
%% ===== Styles =====
classDef svc fill:#FF9900,stroke:#232F3E,stroke-width:1.5px,color:#232F3E;
classDef db fill:#1A73E8,stroke:#232F3E,stroke-width:1.5px,color:#FFFFFF;
classDef mq fill:#7D3C98,stroke:#232F3E,stroke-width:1.5px,color:#FFFFFF;
classDef edge fill:#232F3E,stroke:#232F3E,stroke-width:1.5px,color:#FFFFFF;
classDef ext fill:#7AA116,stroke:#232F3E,stroke-width:1.5px,color:#FFFFFF;
classDef person fill:#FDF6E3,stroke:#232F3E,stroke-width:1.5px,color:#232F3E;