Mermaid code
flowchart LR
subgraph Clients
Web[Web app]
Mobile[Mobile app]
end
GW[API gateway]
subgraph Services
Users[User service]
Orders[Order service]
Inventory[Inventory service]
end
UsersDB[(Users DB)]
OrdersDB[(Orders DB)]
InvDB[(Inventory DB)]
Bus{{Message broker}}
Web --> GW
Mobile --> GW
GW --> Users
GW --> Orders
GW --> Inventory
Users --> UsersDB
Orders --> OrdersDB
Inventory --> InvDB
Orders -- order.created --> Bus
Bus --> Inventory Paste this into any tool that renders Mermaid, or into the editor to change the theme and export PNG or SVG. Syntax reference: Flowchart guide.
What this diagram shows
Read it left to right. The Clients subgraph holds the web and mobile apps, both of which call a single API gateway. The gateway routes to three services, and each service owns exactly one database, drawn with the [( )] cylinder shape. The Orders service publishes an order.created event to the Message broker (hexagon), which the Inventory service consumes, so stock is reserved without a direct call between the two.
A flowchart beats a sequence diagram here because the point is topology, not timing. Subgraphs group the tiers, and the LR direction keeps request flow reading like a sentence.
How to adapt it
- Rename the three services and databases to match your domain, keeping one
[( )]cylinder per service so ownership stays obvious. - Add a fourth tier such as
subgraph Externalfor payment or email providers and connect it with dotted arrows (-.->) to mark third-party calls. - Change
flowchart LRtoflowchart TDif the diagram will sit in a narrow document column. - Replace the hexagon
{{Message broker}}with a named topic per event if you publish more than two or three event types.
FAQ
How do I show synchronous versus asynchronous calls?
Use solid arrows (-->) for synchronous HTTP or gRPC calls and dotted arrows (-.->) for events that go through the broker. Add the event name as an edge label so readers see what is published.
Can I put the databases inside the Services subgraph?
Yes, but the diagram gets taller and the per-service ownership is harder to spot. Keeping databases in a row outside the subgraph lets each service line up with its store.
Why is the gateway outside any subgraph?
It is the single entry point, so leaving it ungrouped makes the boundary between clients and services visible. If you have several gateways (public, partner, internal), group them in their own subgraph.