---
name: c4-diagram
description: Use whenever the user wants to draw, sketch, model, or document a C4 architecture diagram (system context, container, component, system landscape, dynamic, deployment), produce Structurizr DSL (.dsl), model microservices and queues at the right C4 level of abstraction, or visualize software architecture in the C4 tradition (Simon Brown). Output is Structurizr DSL ready to render with the user's preferred Structurizr tooling (online editor, local install, IDE plugin). Default focus is system context and container levels; component, dynamic, and deployment views only on explicit request or when complexity demands. Links ADRs via the !adrs directive when the project has them. Composes with sequence-diagram skill (sequence diagrams are not C4 abstractions) and the design-doc skill (which has a C4 section that delegates here). Do NOT use for sequence diagrams, ER diagrams, flowcharts, class/UML diagrams, or non-architectural visualizations.
license: CC-BY-4.0
metadata:
  author: Cassio Botaro
  version: 1.2.0
---

# C4 Diagram (Structurizr DSL)

Produz diagramas de arquitetura no [C4 model](https://c4model.com/) do Simon Brown usando [Structurizr DSL](https://docs.structurizr.com/dsl/) como saída. Foco em **system context** e **container** views; outros níveis (component, dynamic, deployment) só sob pedido explícito.

> **A saída é texto DSL, não imagem.** A renderização fica com o usuário, na ferramenta Structurizr de preferência (editor online, instalação local, plugin de IDE). Não há script de render porque Structurizr requer JVM e a complexidade não compensa.

## Workflow

### Step 1: Discovery

Antes de escrever DSL, alinhe **cinco coisas** com o usuário (não invente nenhuma delas):

1. **Nível alvo**:
   - **System context** (default): zoom externo. Audiência ampla, técnica e não-técnica.
   - **Container**: zoom no sistema, mostra apps/serviços/data stores + tecnologia. Audiência técnica.
   - **Component / dynamic / deployment**: só quando o usuário pediu explicitamente OU a complexidade justifica.
2. **Software system em foco**: qual é o sistema que vai estar no centro? O que está dentro do escopo do diagrama, o que é externo?
3. **Pessoas**: quem usa o sistema? Use **roles/personas** ("Operador", "Cliente B2B"), nunca nomes próprios.
4. **Sistemas externos**: com o que o sistema em foco se comunica? (Outros sistemas internos, SaaS, APIs externas.)
5. **Containers** (se for nível container): quais aplicações, serviços, data stores compõem o sistema? **Tecnologias?**

**Microservices?** — Se um time único é dono de tudo, modele como **grupo de containers** dentro de um software system. Se múltiplos times com fronteiras claras, **cada serviço é um software system próprio** (Conway's Law).

**Monolito modular?** — Se o sistema é **um único deployável** (uma container em deploy) com módulos internos de fronteira clara (bounded contexts, packages com ownership separado, módulos de domínio), há **três representações C4 válidas** — nenhuma é "a certa". A escolha depende do que você quer comunicar mais. Veja a subseção *"Monolito modular"* em **Modeling guidance** para o trade-off antes de escolher.

**Queues/topics?** — Modele como **containers** (são data stores). Ou, alternativa válida, omita e use *"publishes events to {Topic} via Pub/Sub"* na descrição da relação.

**ADRs existentes?** — Se o projeto já tem ADRs (típico se usaram a skill `adr` deste repo), aponte com `!adrs ./decisions`.

#### Quando perguntar — não invente

A skill **explicitamente pergunta** quando algo não está claro:

- Se o usuário não disse o **role** da pessoa (ex: disse "o cliente" — é cliente final ou cliente B2B?), pergunte.
- Se o usuário descreveu uma relação como *"A usa B"*, pergunte o que isso significa concretamente — *publica eventos? consulta? assina via webhook?*
- Se o usuário não disse a **tecnologia** de um container ou de uma relação container-a-container, pergunte ou marque como `{{a definir}}`.

Não invente status codes, headers, hosts, ou tecnologias que o usuário não compartilhou. Diagrama com tecnologia inventada é diagrama errado, não diagrama incompleto.

### Step 2: Compose

Produza o `.dsl` na ordem `workspace { model { ... } views { ... } }`. Use a linguagem do usuário (PT/EN/ES) nos **nomes e descrições**; as **keywords DSL** são em inglês (são da linguagem).

Para começar do esqueleto, use o subset comum em **DSL fundamentals** abaixo. Para construções fora do comum (deployment, dynamic, archetypes complexos, scripts), carregue `references/syntax.md`. Para um workspace completo com archetypes, queues, ADRs e styles, carregue `references/example.md`.

### Step 3: Validate and self-review (não pule)

**(a) Validação mecânica.** Rode contra o `.dsl` produzido:

```bash
python3 scripts/validate.py < workspace.dsl
```

Pega: workspace/model/views block faltando, brace imbalance, `}` fora de linha própria. Avisa: nenhuma view declarada, label de relação genérico ("Uses", "Calls"), view sem `include`. Não é um parser completo — Structurizr é o source of truth final, mas o validator pega 80% dos bugs de copy-paste.

**(b) Self-review semantic.** Carregue `references/checklist.md`. Pontos que o validator NÃO pega:

- Toda **container tem tecnologia** declarada?
- Toda **relação container-a-container** declara tecnologia/protocolo?
- Microservice modelado como **grupo de containers** (se aplicável)?
- Queue/topic modelado como **container** (se aplicável)?
- Pessoas são **roles**, não nomes próprios?

### Step 4: Deliver

Entregue o DSL em **bloco fenced** (` ```dsl ` ou ` ```text `):

```
Aqui está o workspace:

​`​`​`dsl
<workspace>
​`​`​`

Para renderizar, salve como `workspace.dsl` e abra com sua ferramenta Structurizr de preferência (editor online em https://structurizr.com/dsl, instalação local via Docker, plugin de IDE, ou exportador para outras notações).
```

Adapte o lead-in à linguagem do usuário. Não prescreva uma ferramenta específica de render — o usuário decide.

---

## C4 levels — o que está dentro de cada um

### System Context (default)

**Audiência**: todo mundo, técnico e não-técnico.

**O que tem**: o software system em foco no centro; pessoas (atores/roles) que interagem; sistemas externos diretamente conectados.

**O que NÃO tem**: containers internos, protocolos, schemas, frameworks.

**Quando pular**: nunca — sempre vale ter um system context para qualquer software system documentado.

### Container

**Audiência**: pessoas técnicas (devs, arquitetos, ops, suporte).

**O que tem**: containers do sistema (apps, serviços, data stores, queues), tecnologia explícita em cada um, comunicação entre containers com protocolo declarado, pessoas e sistemas externos diretamente conectados aos containers.

**O que NÃO tem**: componentes internos dos containers, deploy topology (clusters, load balancers), código.

**Cuidado clássico**: *container* aqui **não é Docker container**. É uma unidade executável ou de armazenamento (web app, mobile app, microservice, banco de dados, bucket S3). Pode até rodar dentro de um Docker container, mas a abstração é outra.

### Component / Dynamic / Deployment (sob pedido)

- **Component**: zoom em um container, mostra os componentes (módulos lógicos). Útil quando o container é grande e o usuário pediu detalhamento. Decai rápido em projetos ativos — Simon Brown sugere gerar via análise estática quando possível, não manter manualmente.
- **Dynamic**: ordem temporal entre elementos C4. Raramente o caminho mais legível pra sequência — **prefira a skill `sequence-diagram`** deste repo pra interações temporais.
- **Deployment**: como o sistema é implantado (regions, clusters, nodes). Útil em projetos com topologia complexa. Skill cobre se pedido.

Para os três, carregue `references/syntax.md` quando precisar.

---

## DSL fundamentals (subset comum)

```dsl
workspace "Optional Name" "Optional description" {

    !identifiers hierarchical
    !adrs ./decisions

    model {
        u = person "Role description"
        ext = softwareSystem "External System" "..." "External"

        ss = softwareSystem "Our System" {
            api = container "API" "Handles requests" "Spring Boot"
            db = container "Database" "Stores orders" "PostgreSQL" "Database"
        }

        u -> ss.api "Places orders via" "HTTPS/JSON"
        ss.api -> ss.db "Reads from and writes to" "JDBC/SQL"
        ss -> ext "Notifies of new orders" "HTTPS/JSON"
    }

    views {
        systemContext ss "SystemContext" {
            include *
            autoLayout lr
        }

        container ss "Containers" {
            include *
            autoLayout
        }

        styles {
            element "Person" { shape Person background #08427b color #ffffff }
            element "Software System" { background #1168bd color #ffffff }
            element "External" { background #999999 color #ffffff }
            element "Container" { background #438dd5 color #ffffff }
            element "Database" { shape Cylinder }
        }

        themes default
    }
}
```

Regras de sintaxe que mais mordem:

- `{` na **mesma linha** do keyword; `}` em **linha própria**.
- **Forward references não suportadas** — declare antes de usar.
- Aspas opcionais quando o valor não tem whitespace.

Para o resto (archetypes, deployment, dynamic, includes, scripts), carregue `references/syntax.md`.

---

## Modeling guidance (do C4 model)

### Microservices

> *"A microservice is modelled as group of one or more containers, rather than a container itself."*

Se um único time possui o serviço inteiro, modele cada microservice como um conjunto de containers (API + DB schema, tipicamente) dentro do **software system do produto**. Use `group` no DSL pra clarear o agrupamento visual.

Se múltiplos times possuem serviços diferentes, **cada microservice vira um software system próprio** com seu próprio system context. É Conway's Law: o diagrama reflete a estrutura organizacional.

### Monolito modular

Sistema com **um único artefato de deploy** mas **módulos internos com fronteiras claras** (bounded contexts, packages com ownership separado). Existem três representações C4 válidas, cada uma comunicando algo diferente:

| Opção | O que mostra | Trade-off |
| --- | --- | --- |
| **A — Um container, módulos como `component`** | Container view tem 1 caixa; component view (zoom 3) revela os módulos. | Honesto sobre deploy. Fronteiras dos módulos só aparecem no nível abaixo, exigindo um segundo diagrama. |
| **B — N containers (um por módulo)** dentro do mesmo software system, com nota explícita "deployed as a single artifact" | Container view mostra os módulos lado a lado já no nível 2. | Risco de mentir sobre deploy se a nota não for lida; leitor pode confundir com microsserviços. |
| **C — Um container com `group` separando módulos** | Container view tem 1 caixa; relações entre módulos ficam visíveis em groups dentro dela. | Híbrido. Suporte do renderer pode variar (groups dentro de container nem sempre são bem desenhados). |

**Como escolher:**

- O leitor primário precisa entender **deploy/operação**? Opção A (deploy fiel; módulos só descem de nível pra quem precisa).
- O leitor primário precisa entender **fronteiras de domínio / ownership** rapidamente? Opção B (com a nota visível) — mas o custo de explicar "por que estão separados se deploya junto" é seu.
- O leitor precisa dos dois ao mesmo tempo? C, se o renderer cooperar.

Não trate como decisão arquitetural — é decisão de **comunicação**. Documente a escolha no header do `.dsl` ou em ADR se a equipe oscilar.

**Em DSL, em forma compacta:**

```dsl
// Opção A — 1 container + components
softwareSystem "App" {
    monolith = container "Monolith" "Single deployable" "Spring Boot" {
        catalog = component "Catalog" "Products and categories" "Spring/Java"
        cart = component "Cart" "Active carts" "Spring/Java"
        cart -> catalog "Reads product info from"
    }
}

// Opção B — N containers num único deployável (com nota)
softwareSystem "App" "All containers below deploy as a single Spring Boot artifact." {
    catalog = container "Catalog Module" "Products and categories" "Spring/Java"
    cart = container "Cart Module" "Active carts" "Spring/Java"
    cart -> catalog "Reads product info from"
}

// Opção C — 1 container + groups internos (suporte varia por renderer)
softwareSystem "App" {
    monolith = container "Monolith" "Single deployable" "Spring Boot" {
        group "Catalog Bounded Context" {
            catalog = component "Catalog" "..." "Spring/Java"
        }
        group "Cart Bounded Context" {
            cart = component "Cart" "..." "Spring/Java"
        }
        cart -> catalog "Reads product info from"
    }
}
```

**Sinal de que a representação está errada:** o leitor pergunta *"então isso é microsserviço?"* depois de ver o diagrama. Sintoma de Opção B sem a nota — ou de Opção A sem component view, deixando os módulos invisíveis quando o ouvinte queria saber deles.

### Queues e topics

> *"A message queue is essentially a data store."*

Duas representações válidas, ambas em uso comum:

1. **Explícito**: queue/topic é um container próprio. Setas entram (publishers) e saem (subscribers). Mostra acoplamento ponto-a-ponto explicitamente.
2. **Implícito**: omita o container, use *"publishes order events via Order Topic"* na descrição da seta entre publisher e subscriber. Mais limpo, perde a noção de que existe um broker.

Não há "melhor" — escolha uma e seja consistente no workspace.

### Pessoas (atores)

Use **role** ou **persona**, não nomes próprios. *"Cliente B2B"*, *"Analista de risco"*, *"SRE de plantão"*. Pessoas sobreviven a turnover, nomes próprios não.

### Tecnologia

**Toda container tem tecnologia declarada** (`"Spring Boot"`, `"Cloud Run"`, `"PostgreSQL"`, `"S3 bucket"`). **Toda relação container-a-container declara protocolo** (`"HTTPS/JSON"`, `"gRPC"`, `"JDBC"`, `"Pub/Sub"`). Sem isso, o diagrama vira bonito mas inútil pra implementador.

### Labels de relação

Verbos concretos. **Nunca `"Uses"` ou `"Calls"` soltos.** Exemplos bons:

- `"publishes order events to"`
- `"reads cart contents from"`
- `"queries customer profile from"`
- `"redirects authentication requests to"`

Exemplos ruins: `"Uses"`, `"Talks to"`, `"Connects"`.

---

## Implied relationships

Default ligado. Quando você escreve `u -> ss.api "Uses"`, o DSL cria automaticamente `u -> ss "Uses"` (a relação no nível de software system). Isso mantém o **system context view limpo** sem você ter que duplicar relações em cada nível.

Desligue (`!impliedRelationships false`) só se quiser controle manual — caso raro.

## Archetypes

Ubiquitous language sobre tipos C4. Útil quando o workspace tem repetição (múltiplos `serverlessApp` com `technology "Cloud Run"` e `tag "Application"`). Exemplo:

```dsl
archetypes {
    serverlessApp = container {
        technology "Cloud Run"
        tag "Application"
    }
    documentStore = container {
        technology "Firestore"
        tag "Database"
    }
    https = -> {
        technology "HTTPS/JSON"
    }
}

model {
    api = serverlessApp "Admin API"
    db = documentStore "Deliveries Store"
    api https db "Reads delivery history from"
}
```

Não force pra workspace pequeno — vira overhead. Vale quando há ≥ 3 elementos do mesmo tipo.

---

## Linking ADRs (`!adrs`)

```dsl
workspace {
    !adrs ./decisions       // diretório com ADRs em formato adr-tools
    model { ... }
}
```

Default: usa `AdrToolsDecisionImporter` — **mesmo formato que a skill `adr` deste repo gera** (`NNNN-kebab-slug.md`). Então `!adrs ./decisions` vai puxar todos os ADRs gerados pela skill irmã sem ajuste.

Outros formatos suportados (segundo arg):

```dsl
!adrs ./decisions adrtools     // explicit (default)
!adrs ./decisions madr         // formato MADR
!adrs ./decisions log4brains
```

`!adrs` pode aparecer **no nível de workspace, software system, ou container** — escolha o escopo apropriado.

---

## Composability

- **`design-doc` skill** (mesmo repo): a seção *"O Design"* do design-doc tem subseção C4 com convenção de embed (imagem + link pro fonte). O **fonte é o `.dsl` produzido aqui**. Workflow típico: gerar `.dsl` aqui → renderizar no Structurizr → exportar PNG → embed no design-doc com link de volta pro `.dsl`.
- **`adr` skill** (mesmo repo): `!adrs` puxa exatamente os ADRs que a skill `adr` gera (formato compatível). Não precisa converter nada.
- **`sequence-diagram` skill** (mesmo repo): **sequência não é C4**. C4 tem dynamic view, mas pra interação temporal (chamadas API, ordem de eventos), `sequence-diagram` produz output mais legível e compartilhável (URL clicável). **Não use dynamic view só pra ter algo no C4** — delegue.

---

## Anti-padrões

- **`"Uses"` solto.** Sempre verbo + substantivo concreto.
- **Tecnologia omitida** em container ou em relação container-a-container.
- **Acrônimo sem explicação** (não-universal — DLQ, CSE, etc.).
- **Container = Docker container.** Container em C4 é abstração arquitetural; Docker é deploy.
- **Microservice como UM container.** Microservice é grupo de containers (API + DB + cache + etc.). *Diferente* de monolito modular onde 1 container é correto via Opção A.
- **Opção B do monolito modular sem nota explícita.** Múltiplos containers num único deployável sem deixar visível "deployed as single artifact" induz o leitor a pensar que é microsserviços.
- **Mistura de níveis no mesmo diagrama** (containers + components misturados).
- **Cor sem legenda.** Style com cor distinta exige tag explicada (visualmente, via legenda do renderer ou nota).
- **Dynamic view pra coisa que é sequência.** Use `sequence-diagram` skill.
- **Forward reference no DSL.** Linhas processadas em ordem; declare antes de usar.

---

## When to load references

| Quando | Carregue | Por quê |
| --- | --- | --- |
| Construções fora do subset comum | `references/syntax.md` | DSL completo (component, deployment, dynamic, archetypes complexos, scripts) |
| Usuário pediu "me mostra um exemplo" | `references/example.md` | Webhooks Service workspace completo (archetypes, queues, ADRs, styles) |
| **Sempre antes do Step 4** | `references/checklist.md` | Self-review |

Os três são opcionais durante a composição; o checklist **não** é opcional antes de entregar.
