Opening the shared document…
Diagram playground
Write a diagram as text and it renders here as you type. Canvas editing for six of ten notations. Nothing leaves your browser. Syntax reference ·
1
archlab 1.0
2
schema "https://arch-lab.dev/schema/v1/diagram.schema.json"
3
title "Atlas Shop"
4
description "Global event-sourced order shop. Commands append immutable events to a regional event store, Kafka carries the stream, projections build eventually-consistent read models, and MirrorMaker 2 mirrors events between regions. The diagrams show one regional stamp (EU); the US region runs the identical topology."
5
owner "orders-platform"
6
tags #commerce #event-sourcing #kafka #multi-region
7
created 2026-07-28T00:00:00Z
8
updated 2026-07-28T00:00:00Z
9
tagcolor regional "#8b5cf6"
10
tagcolor region-us "#f59e0b"
11
tagcolor write-side "#e0524d"
12
tagcolor read-side "#10b981"
13
tagcolor async "#eab308"
14
generator "arch-lab" "0.1.0"
15
16
@component d-cmp-order-command "Order Command Service — Components" owner=order-command-service
17
desc "The write side: commands in, events out. No component updates state in place — the aggregate decides, the handler appends, the relay publishes. Boundary nodes come from the container view; the payment saga is omitted at this zoom."
18
view 1 0 0
19
command-handler:component "Command Handler" [Go / pgx] (576,256 208x96)
20
desc "Decodes and authenticates commands, folds the order's event history into state, invokes the aggregate, and appends the new events with optimistic concurrency — a racing writer makes the append fail, and the handler retries against fresh history. Returns the outcome synchronously."
21
ext-eventstore-cmp:database ^d-cnt-atlas/event-store (576,560 208x88)
22
ext-kafka-cmd:queue ^d-cnt-atlas/kafka (1064,856 208x88)
23
ext-storefront-cmp:external ^d-cnt-atlas/storefront (584,32 192x80)
24
order-aggregate:component "Order Aggregate" [Go] >d-code-order-aggregate (1064,256 208x96)
25
desc "Pure decision logic, rehydrated by folding the event stream. decide() enforces invariants — no paying a cancelled order — and emits new events. No I/O."
26
outbox-relay:component "Outbox Relay" [Go] (1064,556 208x96)
27
desc "Tails the committed journal and publishes each event to Kafka at-least-once, in stream order, key = order id. The journal is its own outbox: appending the event and queueing it are one transaction."
28
29
command-handler -> order-aggregate : "Rehydrates state, calls decide(state, command)" id=e-handler-aggregate
30
command-handler <-> ext-eventstore-cmp : "Appends at expected version — unique (stream_id, version) rejects racing writers" [SQL/TCP] ~e-commands-eventstore id=e-handler-eventstore
31
outbox-relay ..> ext-eventstore-cmp : "Tails the journal (poll + LISTEN/NOTIFY)" [SQL/TCP] ~e-commands-eventstore id=e-outbox-eventstore
32
outbox-relay ..> ext-kafka-cmd : "Publishes to orders.events.v1, key = order id, at-least-once" [Kafka protocol] #async ~e-commands-kafka id=e-outbox-kafka
33
ext-storefront-cmp -> command-handler : "PlaceOrder, CancelOrder" [HTTP/JSON] ~e-storefront-commands id=e-sf-handler
34
35
@container d-cnt-atlas "Atlas Shop — Containers (one regional stamp)" owner=atlas-shop
36
desc "The EU region of the active-active deployment; the US stamp is identical. An order is written only in the region that accepted it (its home region); every region serves reads for all orders via mirrored events. Commands and queries are synchronous (solid); events cross Kafka asynchronously (dashed)."
37
view 1 0 0
38
frame read-side "Read side" in=regional-stamp
39
frame regional-stamp "Regional stamp (us-east-1)"
40
frame write-side "Write side" in=regional-stamp
41
event-store:database "Event Store" @postgresql~ [PostgreSQL 16] #regional #write-side in=write-side (440,800 208x96)
42
desc "Append-only order_events journal, one stream per order, unique (stream_id, version). An order's stream lives only in its home region, so there are no cross-region write conflicts by construction."
43
ext-payment:external ^d-ctx-root/payment-gateway (32,496 176x80)
44
ext-shopper:person ^d-ctx-root/shopper (880,32 160x88)
45
kafka:queue "Event Backbone" @queue! [Apache Kafka 3.7] #regional in=regional-stamp (840,800 240x96)
46
desc "Regional Kafka cluster carrying orders.events.v1 (key = order id, so each order's events stay ordered) plus the mirrored us.orders.events.v1. Retention is long enough to rebuild any projection from scratch."
47
order-command-service:container "Order Command Service" @golang~ [Go 1.23] #regional #write-side >d-cmp-order-command in=write-side (440,488 208x96)
48
desc "The write side. Validates each command against the order's event history and appends new events — never updating state in place; the event stream is the system of record. Its payment saga consumes OrderPlaced, calls the gateway, and feeds the result back in as a command."
49
order-projection-service:container "Order Projection Service" @golang~ [Go 1.23] #read-side #regional in=read-side (1272,488 208x96)
50
desc "The read side. Consumes the local and mirrored event topics into denormalised views and serves order queries. Eventually consistent — milliseconds behind the write side, seconds for cross-region orders. Upserts are versioned and idempotent, so at-least-once delivery never double-applies."
51
read-store:database "Order Read Store" @mongodb~ [MongoDB 7] #read-side #regional in=read-side (1272,800 208x96)
52
desc "Denormalised order views: summary, history, tracking. Disposable — any view can be dropped and rebuilt by replaying the event topics."
53
storefront:container "Storefront" @nextjs~ [Next.js 15] #regional in=regional-stamp (864,240 192x96)
54
desc "Server-rendered shop UI; routes commands to the write side and queries to the read side. After checkout it renders the command response, not the projection — the shopper never observes read-model lag on their own order."
55
us-region:external "US Region (peer stamp)" [Identical deployment, us-east-1] #region-us (840,1096 240x96)
56
desc "The identical topology in us-east-1. Each region owns writes for orders placed there and mirrors its events to the other. Mirroring is async: a region loss can lose the last seconds of unreplicated events (RPO > 0)."
57
58
order-command-service <-> event-store : "Appends events; reads streams to rehydrate" [SQL/TCP] id=e-commands-eventstore
59
order-command-service ..> kafka : "Publishes committed events via outbox, key = order id" [Kafka protocol] #async id=e-commands-kafka
60
order-command-service -> ext-payment : "Authorises and captures payments" [HTTPS/JSON] ~e-atlas-payment id=e-commands-payment
61
kafka <..> us-region : "Mirrors event topics both ways — async, per-partition order preserved" [MirrorMaker 2] #async id=e-kafka-us
62
order-projection-service ..> kafka : "Consumes orders.events.v1 + us.orders.events.v1" [Kafka protocol] #async id=e-projections-kafka
63
order-projection-service <-> read-store : "Projects events into views; serves queries" [MongoDB wire protocol] id=e-projections-readstore
64
ext-shopper -> storefront : "GeoDNS serves each shopper from the nearest healthy region" [HTTPS] ~e-shopper-atlas id=e-shopper-storefront
65
storefront -> order-command-service : "Order commands: PlaceOrder, CancelOrder" [HTTP/JSON] id=e-storefront-commands
66
storefront -> order-projection-service : "Order queries: summary, history, tracking" [HTTP/JSON] id=e-storefront-queries
67
68
path command "The write path"
69
beat "A shopper's command reaches the region nearest them."
70
ext-shopper -> storefront -> order-command-service
71
beat "The command authorises the payment and appends its events."
72
order-command-service -> ext-payment
73
order-command-service -> event-store
74
beat "Committed events are published, and mirrored to the peer region."
75
order-command-service -> kafka -> us-region
76
77
path query "The read path"
78
beat "A query never touches the command side."
79
ext-shopper -> storefront -> order-projection-service
80
beat "The projection service consumes both regions' events."
81
order-projection-service -> kafka
82
beat "And serves its views from the read store."
83
order-projection-service -> read-store
84
85
@code d-code-order-aggregate "Order Aggregate — Code" owner=order-aggregate
86
desc "Event sourcing in one loop: state is a left fold of events, decide() proposes new events from the current state, and nothing mutates in place."
87
view 1 0 0
88
apply-fn:code "apply()" [Go func] (936,320 192x88)
89
desc "(OrderState, OrderEvent) → OrderState. The fold step: replaying history is events.reduce(apply, empty)."
90
decide-fn:code "decide()" [Go func] (200,320 192x88)
91
desc "(OrderState, Command) → []OrderEvent. Pure: enforces invariants and either emits events or rejects the command. No clock, no I/O."
92
order-event:code "OrderEvent" [Go sum type] (568,608 192x88)
93
desc "OrderPlaced, PaymentCaptured, PaymentFailed, OrderShipped, OrderCancelled — immutable facts named in the past tense, versioned for schema evolution."
94
order-state:code "OrderState" [Go struct] (568,32 192x88)
95
desc "In-memory snapshot of one order, produced only by apply(). Never persisted — rebuilt from the stream on every command."
96
97
apply-fn -> order-state : "Returns the next state" id=e-apply-state
98
decide-fn -> order-event : "Emits new events" id=e-decide-event
99
order-event -> apply-fn : "Folded one at a time" id=e-event-apply
100
order-state -> decide-fn : "Current state in" id=e-state-decide
101
102
@context d-ctx-root "Atlas Shop — System Context"
103
desc "Who shops here and the one third party the platform cannot work without. Shoppers everywhere use one shop; geography appears one level down."
104
view 1 0 0
105
atlas-shop:system "Atlas Shop" [Go / Next.js / Kafka] >d-cnt-atlas (400,352 320x128)
106
desc "Online order shop deployed as identical stamps in eu-central-1 and us-east-1. Orders are event-sourced: every state change is an immutable event, and all read views derive from the event stream."
107
payment-gateway:external "Payment Gateway" [REST API] (448,712 224x96)
108
desc "Third party that authorises and captures card payments."
109
shopper:person "Shopper" (472,48 176x96)
110
desc "Customer browsing, ordering, and tracking deliveries — served by whichever region is closest."
111
112
atlas-shop -> payment-gateway : "Authorises and captures payments" [HTTPS/JSON] id=e-atlas-payment
113
shopper -> atlas-shop : "Browses, orders and tracks deliveries" [HTTPS] id=e-shopper-atlas
Tab indents · Esc then Tab leaves the editor · syntax reference
Read-only
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Atlas Shop
Global event-sourced order shop. Commands append immutable events to a regional event store, Kafka carries the stream, projections build eventually-consistent read models, and MirrorMaker 2 mirrors events between regions. The diagrams show one regional stamp (EU); the US region runs the identical topology.