DEV Community

Doby Baxter
Doby Baxter

Posted on

Making Architecture Diagrams Tell the Truth: Trust Boundaries, Data Flow, and the Things We Leave Out

Most architecture diagrams are optimistic. They show the happy path: a client talks to a service, the service talks to a database, arrows point in tidy directions. What they usually leave out is where the risk actually lives — which components hold sensitive data, where trust changes hands, which team is accountable for what, and where data quietly gets copied to a third place nobody remembers to secure.

That omission isn't cosmetic. As a system grows, the parts that get left off the diagram tend to be exactly the parts that cause incidents: the logging pipeline shipping PII to an analytics vendor, the cache holding session tokens, the "internal" service that's actually reachable from the internet. A diagram that hides those things doesn't just fail to help — it actively misleads the people making decisions from it.

This piece lays out a small set of principles for drawing system diagrams that make responsibility, data movement, and trust boundaries explicit, and then walks the same example system through three stages of growth so you can see how the risk surface expands as the architecture does.

What a component label should answer

Every box in a diagram represents a responsibility. If the label is vague, the accountability is vague too. A well-defined component should let a reader answer three questions without asking you:

  • What does it do? One function, stated plainly. "Auth service," not "backend."
  • What data does it control? Especially whether that data is sensitive.
  • Who owns it? Which team, or which external provider, is responsible when it breaks or leaks.

"User Service" is a weak label. "User Service (Auth + PII, owned by Team A)" is a strong one — it tells you the function, the data sensitivity, and the owner in a single line. The extra words are where the accountability lives.

Make data flow directional and typed

Arrows are claims about communication, and the claim should be specific. Two conventions carry most of the weight:

  • Solid arrows for synchronous calls — the caller waits for a response.
  • Dashed arrows for asynchronous or background flows — events, log shipping, replication.

Every arrow needs a direction, and ideally a label describing what moves along it. "Read/Write (PII)" tells a reviewer something that a bare arrow doesn't: that this path carries sensitive data and therefore deserves stricter controls. Undocumented data movement is where hidden risk accumulates, because you can't protect a flow you haven't drawn.

Draw the trust boundaries

A trust boundary is any line where the level of trust in the input changes — the edge between the public internet and your internal network, between your services and a third-party API, between an untrusted user-facing layer and a privileged internal one. These boundaries are the most security-relevant lines on the whole diagram, because they mark where authentication, authorization, and validation must happen.

If your diagram doesn't show trust boundaries, it's not showing where enforcement is required. Draw them as explicit enclosures, and make it obvious which components sit inside which zone.

Make persistence and duplication visible

Storage is an architectural decision, not a background detail. Databases, caches, replicated stores, and log sinks all hold data, and every one of them is a place that data can leak from or be retained longer than intended. Label them, mark which ones hold sensitive data, and — critically — show where data is duplicated. A record that exists in the primary database, the cache, the analytics warehouse, and the log aggregator now has four places to secure and four retention policies to reason about. If the diagram only shows one, the other three are invisible risk.

Three stages of the same system

The clearest way to see these principles pay off is to watch a system grow. Here's the same application at three levels of scale. Notice that each step buys capability and spends it on complexity — more communication paths, more data stores, more owners, more audit surface.

Stage 1: the contained monolith

flowchart TD
    Client([Client])
    App[Application Server<br/>Auth + API + Business Logic<br/>Owner: Team A]
    DB[(Primary Database<br/>User Data: PII)]
    Logs[(Internal Logs<br/>Audit Trail)]

    Client -->|HTTPS, token auth| App
    App -->|Read/Write, strict access| DB
    App -.->|Events, PII redacted| Logs
Enter fullscreen mode Exit fullscreen mode

One deployment unit, one primary data store, one owner. Enforcement is concentrated in a single place, data replication is minimal, and auditing is simple because there's only one path in and one team accountable. This is the model with the smallest risk surface — everything sensitive sits behind one trust boundary that one team controls. It scales poorly, but it's honest and easy to reason about.

Stage 2: horizontally scaled with shared services

flowchart TD
    Client([Client])
    LB[Load Balancer<br/>Public Entry]
    App1[App Instance 1<br/>Auth + API]
    App2[App Instance 2<br/>Auth + API]
    Cache[(Cache Layer<br/>Session / Hot Data)]
    DB[(Primary Database<br/>User Data: PII)]
    Logs[(Centralized Logging<br/>Audit + Monitoring)]

    Client -->|HTTPS| LB
    LB --> App1
    LB --> App2
    App1 -->|Read/Write| DB
    App2 -->|Read/Write| DB
    App1 -->|Cached data| Cache
    App2 -->|Cached data| Cache
    App1 -.->|Events| Logs
    App2 -.->|Events| Logs
Enter fullscreen mode Exit fullscreen mode

Now there are multiple runtime instances behind a load balancer, plus dedicated caching and logging. Scalability improves — but notice what else changed. Session data now lives in a cache as well as the database, so PII-adjacent data has two homes. Shared state introduces consistency questions. Responsibility starts to fragment across more moving parts. The trust boundary still holds, but there's more inside it to keep track of.

Stage 3: distributed microservices

flowchart TD
    Client([Client])
    GW[API Gateway<br/>Auth + Routing + Rate Limiting]
    SvcA[Service A<br/>User Management<br/>Owner: Team A]
    SvcB[Service B<br/>Orders<br/>Owner: Team B]
    SvcC[Service C<br/>Payments<br/>Owner: Team C]
    MQ[[Message Queue<br/>Async Events]]
    UserDB[(User DB<br/>PII)]
    OrdersDB[(Orders DB<br/>Transactional)]
    PayDB[(Payments DB<br/>Financial)]
    Ext[External Payment Processor<br/>Third Party]
    Logs[(Centralized Logging)]

    Client -->|HTTPS| GW
    GW --> SvcA
    GW --> SvcB
    SvcA --> UserDB
    SvcB --> OrdersDB
    SvcB -.->|Publish event| MQ
    MQ -.->|Consume event| SvcC
    SvcC --> PayDB
    SvcC -->|External API call| Ext
    SvcA -.-> Logs
    SvcB -.-> Logs
    SvcC -.-> Logs
Enter fullscreen mode Exit fullscreen mode

Service isolation and independent data ownership are real benefits — each team owns its service and its database. But the ethical and security surface has expanded proportionally. Data is now duplicated across services. There's asynchronous movement through a message queue that's easy to under-secure. Payments data crosses a trust boundary to an external processor. Ownership is spread across three teams, which means an audit now requires coordinating three sets of answers. Every one of those is a real property of the system — and every one of them is only manageable if it's actually drawn.

The blind spots to check for

Whatever your architecture, these are the things most commonly missing from the diagram — and disproportionately likely to be where incidents originate:

  • Logging and observability pipelines (they carry more sensitive data than people expect)
  • Third-party analytics and their data flows
  • Data replication and backup copies
  • Implicit trust relationships — the "internal" call that isn't authenticated because "it's internal"
  • External APIs that handle sensitive information

If a component is missing from your diagram, it's not being reasoned about. And the components teams most often forget to draw are frequently the highest-risk ones.

Closing

System design isn't only about scalability and performance. It's about responsibility, visibility, and sustainability over time. As a system scales, complexity rises; as complexity rises, accountability diffuses and the data surface area grows. A diagram that makes those dynamics visible — explicit trust boundaries, typed and directional data flow, labeled persistence, named ownership — turns architecture into something you can actually govern, not just something you can deploy. Clarity in the diagram is the first line of defense for everything downstream of it.

Top comments (0)