formato: markdown origem: https://docs.cfourdev.com.br/llms-full.txt documentos: 47 conteudo-sha256: a06656c29fc81ac7af27db8e0e18d567e2ab81563c4a264d52a4f3c05c1e6b79 # cfourdev — a documentacao inteira A documentacao do cfourdev: arquitetura C4 escrita em YAML, versionada com o codigo, validada e publicada por linha de comando, e lida como diagrama no navegador. Este arquivo e a documentacao publica reunida. Cada documento entra como um bloco marcado com ``, e o mesmo `` e o caminho da pagina em https://docs.cfourdev.com.br. Um link `doc:` aponta para o bloco deste mesmo arquivo. ## Indice - `doc:inicio` — Comecando: O que é o cfourdev - `doc:comecando/c4` — Comecando: O modelo C4, em quatro níveis - `doc:comecando/como-funciona` — Comecando: Como o cfourdev funciona - `doc:comecando/instalacao` — Comecando: Instalação - `doc:comecando/primeiro-diagrama` — Comecando: Primeiro diagrama - `doc:modelando/anatomia` — Modelando: A anatomia de uma modelagem - `doc:modelando/elementos` — Modelando: Elementos: as caixas - `doc:modelando/relacoes` — Modelando: Relações: as setas - `doc:modelando/contexto` — Modelando: Diagrama de contexto - `doc:modelando/containers` — Modelando: Diagrama de containers - `doc:modelando/componentes` — Modelando: Diagrama de componentes - `doc:modelando/codigo` — Modelando: O nível de código - `doc:modelando/diagramas` — Modelando: Como um diagrama escolhe o que mostra - `doc:modelando/grupos` — Modelando: Grupos dentro de um diagrama - `doc:modelando/etiquetas-e-metadados` — Modelando: Etiquetas e metadados - `doc:modelando/notas` — Modelando: Notas - `doc:modelando/fluxos` — Modelando: Fluxos: uma sequência - `doc:modelando/projetos` — Modelando: Projetos - `doc:modelando/aparencia` — Modelando: Aparência da modelagem - `doc:modelando/modelagens` — Modelando: Várias modelagens, e federação - `doc:cli` — Linha de comando: Visão geral do cfour - `doc:cli/escrever` — Linha de comando: Escrever no modelo - `doc:cli/consultar` — Linha de comando: Consultar o modelo - `doc:cli/validar` — Linha de comando: Validar - `doc:cli/ver` — Linha de comando: Ver os diagramas na sua máquina - `doc:cli/automatizar` — Linha de comando: Usar em scripts e automação - `doc:publicar` — Publicar: Como a publicação funciona - `doc:publicar/ci` — Publicar: Publicar a partir do CI - `doc:publicar/viewer` — Publicar: Ler os diagramas publicados - `doc:plataforma/organizacoes` — Plataforma: Organizações - `doc:plataforma/pessoas` — Plataforma: Pessoas, convites e papéis - `doc:plataforma/dominios` — Plataforma: Domínios de e-mail verificados - `doc:plataforma/repositorios` — Plataforma: Repositórios e visibilidade - `doc:plataforma/chaves` — Plataforma: Chaves de publicação - `doc:agentes` — Agentes e IA: O servidor MCP - `doc:agentes/ferramentas` — Agentes e IA: As ferramentas do MCP - `doc:agentes/plugin` — Agentes e IA: O plugin do Claude Code - `doc:agentes/cli-ou-mcp` — Agentes e IA: Linha de comando ou MCP? - `doc:agentes/llms` — Agentes e IA: llms.txt - `doc:referencia/yaml` — Referencia: Campos do YAML - `doc:referencia/seletores` — Referencia: Seletores - `doc:referencia/cli` — Referencia: Comandos do cfour - `doc:referencia/configuracao` — Referencia: Configuração da aparência - `doc:referencia/variaveis` — Referencia: Variáveis de ambiente - `doc:referencia/limites` — Referencia: Limites - `doc:referencia/mcp` — Referencia: Ferramentas do MCP - `doc:ajuda/problemas` — Ajuda: Quando algo dá errado # O que é o cfourdev O cfourdev descreve a arquitetura de um sistema em arquivos YAML versionados junto com o código, valida esse modelo e o publica como diagramas navegáveis. O cfourdev descreve a arquitetura de um sistema em **arquivos YAML**, guardados no mesmo repositório Git do código. Uma ferramenta de linha de comando valida esses arquivos e os publica; um leitor no navegador transforma o resultado em diagramas navegáveis, nos quatro níveis do [modelo C4](doc:comecando/c4). Você escreve o **modelo**. Os diagramas são consequência dele. ## O problema que ele resolve Diagramas de arquitetura desenhados à mão envelhecem em silêncio. Eles ficam numa ferramenta separada do código, ninguém revisa um retângulo num *pull request*, e a única forma de saber que um desenho está errado é alguém reparar. Quando o mesmo sistema aparece em três desenhos — contexto, containers, componentes —, o problema piora: acrescentar um serviço obriga a editar os três, e o primeiro que alguém esquecer passa a mentir. O cfourdev inverte isso: - **o modelo é texto**, então ele entra no *pull request*, tem histórico, tem autor e tem revisão, como qualquer outra mudança; - **um diagrama não guarda a lista de quem ele mostra** — ele guarda um critério. "Todos os containers deste sistema" continua correto depois que o container novo é criado, sem ninguém editar o desenho; - **uma seta é escrita uma vez**, no nível mais fino que você conhece. Os diagramas mais gerais derivam a versão deles sozinhos; - **o modelo é validado**. Uma referência para uma caixa que não existe é um erro na hora do `cfour check`, e não uma surpresa no navegador. ## O que você vai fazer - [Entender o C4 primeiro](doc:comecando/c4): Os quatro níveis, em cinco minutos, sem YAML nenhum. - [Ver as peças e como se encaixam](doc:comecando/como-funciona): Arquivos, linha de comando, publicação e leitura — o ciclo inteiro. - [Instalar](doc:comecando/instalacao): Um pacote npm, e nada mais. - [Ter um diagrama na tela](doc:comecando/primeiro-diagrama): Do zero ao primeiro desenho, escrevendo cada linha. ## O que ele não é - **Não é uma ferramenta de desenho.** Você não posiciona caixas para criar conteúdo: o conteúdo vem do modelo. O leitor no navegador permite arrastar caixas para arrumar um desenho, e essa arrumação é salva à parte. - **Não é um catálogo de serviços nem um inventário automático.** Nada é descoberto sozinho a partir do seu código ou da sua nuvem — o modelo é escrito por quem conhece o sistema. - **Não é um formato proprietário fechado.** O que você escreve é YAML comum, legível e editável em qualquer editor, e a ferramenta que o valida é a mesma que você roda na sua máquina. **Este texto descreve o produto que existe** Toda página desta documentação descreve comportamento que a ferramenta tem hoje. Quando algo ainda não existe, ou existe com um limite, está dito na página. # O modelo C4, em quatro níveis O suficiente do modelo C4 para usar o cfourdev corretamente — pessoas, sistemas, containers, componentes, relações e fronteiras. O C4 é uma forma de desenhar arquitetura de software criada por Simon Brown. A ideia central é a de um mapa com **níveis de zoom**: em vez de um desenho único que tenta caber tudo, você tem quatro desenhos, cada um respondendo a uma pergunta diferente, para um público diferente. Esta página ensina só o que é preciso para usar o cfourdev. Se você quiser a fonte original, ela está em [c4model.com](https://c4model.com). ## Os quatro níveis | Nível | Pergunta que ele responde | Quem costuma ler | |---|---|---| | **Contexto** | Que sistema é este, quem o usa e com que outros sistemas ele conversa? | qualquer pessoa, inclusive quem não é técnica | | **Container** | De que partes executáveis este sistema é feito? | quem desenvolve e quem opera | | **Componente** | Que peças existem dentro de uma dessas partes? | quem desenvolve aquela parte | | **Código** | Como uma peça está estruturada por dentro? | quem vai mexer naquele arquivo | A palavra **container** aqui não significa Docker. No C4, um container é qualquer coisa que executa ou guarda dados separadamente: uma aplicação web, uma API, um banco de dados, uma fila, um processo agendado, um aplicativo de celular. ## As peças de um diagrama **Pessoa** — um ser humano que usa o sistema, ou um papel: cliente, atendente, administrador. **Sistema** — um todo que entrega valor. Alguns são seus e você vai detalhar por dentro; outros são de terceiros ou de outra equipe, e você só precisa saber que eles existem e que você conversa com eles. **Container** — uma parte executável ou de armazenamento de um sistema seu. **Componente** — um agrupamento de código com uma responsabilidade clara dentro de um container. **Relação** — uma seta entre duas dessas peças, com um rótulo curto dizendo o que trafega: "consulta o saldo", "publica o pedido", "envia o e-mail". A seta descreve intenção, não protocolo. **Fronteira** — a moldura que diz "tudo aqui dentro pertence a esta caixa". Num diagrama de containers, a fronteira é o sistema que você abriu. ## Como o cfourdev representa isso Esta é a parte que muda a forma de escrever, e vale ler com atenção: **Você não escolhe o nível de uma caixa. Ele é derivado.** No cfourdev, toda caixa pode declarar um `parent` — a caixa que a contém. Essa única relação de contenção constrói uma árvore, e a profundidade na árvore *é* o nível C4: ```text sem parent → nível context (um sistema, ou uma pessoa) filho de uma raiz → nível container filho de um container → nível component filho de um component → nível code ``` Não existe um quinto nível, e não existe um campo para "eu quero que esta caixa seja um componente". Para descer um nível, dê um `parent` à caixa nova. **Um diagrama não é um nível: é um recorte.** O nível de um diagrama vem do que ele mostra. Você pode escrever um diagrama que mistura níveis se isso ajudar quem lê — o modelo não impede. **A aparência é separada do nível.** O campo `shape` de uma caixa escolhe o desenho: cilindro para banco de dados, silhueta de pessoa para um ator, moldura tracejada para um sistema de fora. Um cilindro no nível de container e um cilindro no nível de componente continuam sendo cilindros; o nível decide a cor, a forma decide o desenho. **"Dynamic" e "Deployment" não existem como níveis aqui.** O C4 original tem duas visões complementares além das quatro. O cfourdev implementa a primeira com outro nome e outra forma — os [fluxos](doc:modelando/fluxos), que contam um caso de uso como uma sequência de mensagens sobre as caixas que já existem. Não há visão de implantação. ## Um exemplo, em palavras Um sistema de reserva de salas: - **contexto:** o *Colaborador* usa a *Reserva de Salas*, que cria eventos na *Agenda Corporativa* (um sistema de terceiro); - **container:** dentro da *Reserva de Salas* existem um *Painel* no navegador, uma *API*, uma *Base de Reservas*, uma *Fila* e um *Sincronizador*; - **componente:** dentro da *API* existem um *Serviço de Reserva*, um *Repositório de Reservas* e um *Publicador*. É exatamente esse modelo que as páginas de [Modelando](doc:modelando/anatomia) constroem, um passo de cada vez. # Como o cfourdev funciona As peças do cfourdev e o ciclo de trabalho — arquivos YAML no Git, a ferramenta de linha de comando, a publicação e a leitura no navegador. O cfourdev tem quatro peças. Vale conhecer as quatro antes de escrever a primeira linha, porque cada página desta documentação assume que você sabe qual delas está fazendo o quê. ## As quatro peças **Os arquivos YAML.** São a fonte da verdade. Ficam num diretório do seu repositório Git e descrevem caixas, setas, diagramas, fluxos e notas. Você os edita com o editor que quiser. **O `cfour`.** Uma ferramenta de linha de comando, instalada pelo npm. Ela valida o modelo, responde perguntas sobre ele, escreve nele por comando, abre um leitor na sua máquina e publica o resultado. **A plataforma.** Um serviço hospedado que guarda o que foi publicado, controla quem pode ler e escrever, e responde a agentes de IA através de um servidor MCP. **O leitor.** A página no navegador que desenha os diagramas — a mesma tanto para o que está na sua máquina quanto para o que foi publicado. ## O ciclo ```text você escreve │ ▼ YAML no Git ──────────────┐ │ │ │ cfour check │ revisão no pull request, │ valida │ como qualquer outro código ▼ │ cfour serve ◄─────────────┘ desenha na sua máquina │ │ cfour push ▼ plataforma │ ├──► leitor no navegador (pessoas) └──► servidor MCP (agentes de IA) ``` Nada nesse ciclo é obrigatório além do primeiro passo. Você pode usar só os arquivos e o `cfour serve`, sem nunca criar uma conta. ## O que cada peça decide | | | |---|---| | **os arquivos** | o que existe: caixas, setas, o que cada diagrama mostra, os casos de uso | | **o `cfour`** | se o modelo está válido, e quando ele vai para a plataforma | | **a plataforma** | quem pode ler, quem pode publicar, e por quanto tempo cada publicação vive | | **o leitor** | como o desenho aparece — e guarda, em arquivos do seu repositório, a arrumação manual das caixas | ## Três coisas que costumam surpreender **Um diagrama não lista os seus membros.** Ele guarda um critério — "os filhos desta caixa", "tudo com a etiqueta `nucleo`" — e a resposta é calculada a cada leitura. É por isso que um container novo entra sozinho no diagrama de containers do sistema dele. **Uma seta é declarada uma vez só.** Se você escreve que o *Repositório de Reservas* lê do *Banco*, o diagrama de containers mostra a *API* lendo do *Banco*, porque o repositório está dentro da API. Você não escreve a mesma integração em dois níveis. **A posição das caixas não é o modelo.** Arrastar uma caixa no leitor grava a posição num arquivo separado, dentro de `.layout/`. Apagar esses arquivos não perde informação nenhuma de arquitetura — só a arrumação. ## O que fica em cada lugar ```text seu-repositorio/ ├── cfour.yaml ← o registro: quais modelagens existem aqui ├── arquitetura/ ← uma modelagem │ ├── modelagem.yaml ← identidade dela │ └── model/ │ ├── workspace.yaml ← aparência (opcional) │ └── reservas/ ← um projeto │ ├── project.yaml │ ├── elements.yaml ← caixas e setas │ ├── contexto.yaml ← um diagrama │ └── .layout/ ← arrumação, escrita pelo leitor └── src/ ← o seu código ``` Os nomes `arquitetura`, `reservas` e `elements.yaml` são escolha sua. O que é fixo está explicado em [A anatomia de uma modelagem](doc:modelando/anatomia). # Instalação Como instalar a ferramenta de linha de comando cfour, quais são os requisitos e como atualizá-la. A única coisa a instalar é a ferramenta de linha de comando. Ela é publicada no npm como **[`cfour-cli`](https://www.npmjs.com/package/cfour-cli)**, e o comando que ela instala chama-se `cfour`. ## Requisitos - **Node.js 20 ou mais novo**, com o `npm` que vem junto. - **Git**, se você quiser que a publicação carimbe automaticamente a *branch* e o commit. Sem Git a ferramenta funciona igual; você só informa a referência à mão. Não há nada para instalar no servidor, nem banco de dados, nem Docker. ## Instalar ```sh npm install -g cfour-cli ``` Confira: ```sh cfour version ``` Se preferir não instalar nada globalmente, rode sob demanda: ```sh npx cfour-cli@latest version ``` ## Atualizar ```sh npm install -g cfour-cli@latest ``` Vale atualizar quando você for publicar: a plataforma e a ferramenta conversam por uma interface versionada, e uma versão muito antiga pode ser recusada na publicação. A mensagem, quando isso acontece, diz o que fazer. ## Autocompletar no terminal A ferramenta emite o script de autocompletar do seu shell: ```sh cfour completion bash # ou: zsh, fish ``` Para instalar, redirecione a saída para onde o seu shell lê os *completions*. No bash, por exemplo: ```sh cfour completion bash > ~/.local/share/bash-completion/completions/cfour ``` ## Onde a ferramenta guarda coisas | | | |---|---| | chaves de publicação | `$XDG_CONFIG_HOME/cfour/credentials` (ou `~/.config/cfour/credentials`), com permissão `0600` | | tudo o mais | dentro do seu repositório, em arquivos que você versiona | Nenhum arquivo `.env` é lido automaticamente. As variáveis de ambiente que a ferramenta reconhece estão em [Variáveis de ambiente](doc:referencia/variaveis). ## Próximo passo Com o `cfour` instalado, [escreva o primeiro diagrama](doc:comecando/primeiro-diagrama). # Primeiro diagrama Do repositório vazio ao primeiro diagrama na tela, escrevendo cada arquivo — e entendendo o que cada linha faz. Ao fim desta página você terá um modelo válido e um diagrama desenhado na sua máquina. Leva menos de dez minutos, não exige conta nenhuma e não envia nada para lugar nenhum. Pré-requisito: a ferramenta instalada — veja [Instalação](doc:comecando/instalacao). 1. ### Criar a estrutura inicial Dentro do repositório onde a arquitetura vai morar: ```sh cfour init ``` Ele escreve cinco arquivos e diz o que fazer em seguida: ```text criado cfour.yaml criado arquitetura/modelagem.yaml criado arquitetura/model/ola/project.yaml criado arquitetura/model/ola/elements.yaml criado arquitetura/model/ola/contexto.yaml ``` Esse é um modelo mínimo que já desenha alguma coisa: uma pessoa, um sistema, uma seta e um diagrama. O nome da modelagem é `arquitetura` por padrão; use `cfour init --id --nome ""` para escolher outro. 2. ### Ver o que ele escreveu O arquivo `arquitetura/model/ola/elements.yaml` tem duas caixas e uma seta: ```yaml title="arquitetura/model/ola/elements.yaml" elements: - id: visitante name: Visitante shape: actor - id: site name: Site shape: system description: O que o visitante abre. relations: - from: visitante to: site kind: sync label: Acessa ``` Repare no que **não** está escrito: ninguém disse que `site` é um sistema. Ele é raiz — não tem `parent` —, e no C4 uma raiz é um sistema. O nível vem da árvore de contenção, nunca de um campo. E o diagrama, em `contexto.yaml`: ```yaml title="arquitetura/model/ola/contexto.yaml" kind: diagram id: contexto title: arquitetura — Contexto level: context include: - level: context ``` `include` recebe um **critério**, e não uma lista de identificadores. `level: context` casa com toda caixa que é raiz — então acrescentar um segundo sistema no arquivo ao lado o traz para este desenho sem ninguém editar aqui. 3. ### Validar ```sh cfour check ``` ```text arquitetura (arquitetura) 2 elementos · 1 relações · 1 diagramas · 0 fluxos 0 erro(s), 0 aviso(s) ``` Esse é o comando que você vai rodar o tempo todo, e é o que você coloca no seu CI. Ele sai com código 1 quando há erro. 4. ### Ver na tela ```sh cfour serve ``` ```text cfour serve · http://127.0.0.1:5199 1 modelagem(ns) · arrastar salva em .layout/ da modelagem aberta Ctrl+C para parar ``` Abra o endereço. Você verá o diagrama de contexto: o *Visitante* e o *Site*, com a seta entre eles. O servidor escuta apenas em `127.0.0.1`, ou seja, só a sua máquina o alcança. 5. ### Acrescentar uma caixa e descer um nível Abra `elements.yaml` e acrescente um container dentro do site — basta dar a ele um `parent`: ```yaml title="arquitetura/model/ola/elements.yaml" ins={5-10} elements: - id: visitante name: Visitante shape: actor - id: site name: Site shape: system description: O que o visitante abre. - id: site-web name: Aplicação Web shape: browser parent: site technology: React ``` Agora `site-web` está um nível abaixo de `site`, ou seja, é um **container**. 6. ### Escrever o diagrama que mostra esse nível Crie `arquitetura/model/ola/containers.yaml`: ```yaml title="arquitetura/model/ola/containers.yaml" kind: diagram id: containers title: Site — Containers level: container scope: site relations: auto ``` `scope: site` faz duas coisas: abre a caixa `site` por dentro e, como não há `include`, mostra os **filhos diretos** dela. É assim que se desce um nível. Valide e recarregue o navegador: ```sh cfour check && cfour serve ``` **Se você criar filhos e não criar o diagrama** O leitor nunca inventa uma visão: uma caixa só é navegável por dentro através de um diagrama que alguém escreveu para ela. Por isso o `cfour check` avisa quando uma caixa tem filhos e nenhum diagrama com `scope` apontando para ela — aquele conteúdo existe no modelo e ninguém consegue vê-lo. ## Para onde ir agora - Para construir um modelo de verdade, passo a passo, comece em [A anatomia de uma modelagem](doc:modelando/anatomia) e siga a seção *Modelando* na ordem. - Para publicar e compartilhar por link, vá para [Como a publicação funciona](doc:publicar). - Para escrever pelo terminal em vez de editar YAML à mão, veja [Escrever no modelo](doc:cli/escrever). # A anatomia de uma modelagem Onde cada arquivo mora, o que é fixo e o que é escolha sua, e como o cfourdev encontra e interpreta a sua modelagem. Antes de escrever caixas e setas, vale saber onde as coisas moram. São poucas regras, e quase tudo é escolha sua. ## Os três níveis de organização **Modelagem** — uma realidade inteira, com propósito, vocabulário e público próprios. Um repositório pode ter uma só (o caso comum) ou várias. **Projeto** — uma pasta diretamente sob `model/`. É o dono dos identificadores dentro dela: o mesmo `api` pode existir em dois projetos sem colidir. **Documento** — qualquer arquivo `.yaml` dentro de um projeto. O conteúdo dele diz o que ele é; o nome do arquivo e a pasta são livres. ## A estrutura no disco - cfour.yaml o registro — **o único caminho que a ferramenta procura** - arquitetura/ uma modelagem (o nome é escolha sua) - modelagem.yaml identidade: id, nome, status - model/ - workspace.yaml aparência (opcional) - reservas/ **uma pasta aqui é um projeto** - project.yaml - elements.yaml - contexto.yaml - .layout/ arrumação das caixas, escrita pelo leitor - src/ o seu código Não existe índice nem lista mestra. Acrescentar uma caixa é criar ou editar um arquivo, e mais nada. ## O que é fixo, e o que não é | Fixo | Livre | |---|---| | o nome `cfour.yaml`, e o fato de ele ficar na raiz do repositório | o nome da pasta da modelagem | | o nome `modelagem.yaml`, dentro da pasta da modelagem | os nomes dos projetos | | a pasta `model/` dentro da modelagem | o arranjo de pastas dentro de um projeto | | o nome `workspace.yaml`, dentro de `model/` | os nomes dos arquivos `.yaml` | | que uma pasta diretamente sob `model/` é um projeto | quantos documentos há em cada arquivo | Três nomes de pasta têm significado especial: - **`.layout/`** guarda a posição das caixas. É escrita pelo leitor e nunca é lida como modelo. - **`shared`**, como nome de projeto, é onde ficam as caixas que todos os projetos usam — veja [Projetos](doc:modelando/projetos). - Qualquer pasta começando com `.` e a pasta `node_modules` são ignoradas. ## Como a ferramenta encontra a sua modelagem Todo comando do `cfour` sobe a árvore de diretórios a partir de onde você está até achar um `cfour.yaml`. Achou, tudo o mais é derivado dele: do `path` de cada modelagem registrada sai o `model/` que será carregado. Quando há mais de uma modelagem registrada, a escolha segue esta ordem: ```text title="quem decide qual modelagem abrir, do mais forte para o mais fraco" --modelagem na linha de comando C4_MODELAGEM no ambiente o campo "active" do cfour.yaml a única que existe ``` Se nada decidir e houver mais de uma, o comando recusa e lista os identificadores disponíveis. Escolher em silêncio seria pior. **Uma pasta avulsa, sem registro** `C4_ROOT` aponta direto para uma pasta `model/` e vence tudo, inclusive um `cfour.yaml` que exista ao lado. É a saída para validar uma árvore que ninguém registrou — `cfour check --root ` faz o mesmo por comando. ## As duas formas de um arquivo do modelo Um `.yaml` do modelo diz o que carrega de duas maneiras, e as duas podem conviver no mesmo arquivo, separadas por `---`: **Singular** — `kind:` no topo, e os campos do objeto logo abaixo: ```yaml title="model/reservas/project.yaml" kind: project id: reservas name: Reservas de Salas ``` **Coleção** — sem `kind`, com uma ou mais das listas `elements:`, `relations:`, `diagrams:`, `flows:` e `notes:`: ```yaml title="model/reservas/elements.yaml" elements: - id: colaborador name: Colaborador shape: actor relations: - from: colaborador to: reservas kind: sync label: Procura e reserva ``` Os valores válidos de `kind:` na forma singular são `project`, `element`, `relation`, `diagram`, `flow`, `note` e `folder`. Um `kind` que a ferramenta não conhece faz o documento ser ignorado, com aviso. **folder.yaml** Um arquivo chamado `folder.yaml` não descreve conteúdo: ele dá nome e ordem à pasta onde está, na árvore de navegação do leitor. Ele aceita `name` e `order`. ## O identificador de cada coisa Um identificador local usa letras, números, ponto, hífen ou sublinhado, e começa com letra ou número. A barra é reservada: ela separa o projeto do identificador. Dentro do modelo carregado, tudo tem identificador **qualificado**: `reservas/api` é a caixa `api` do projeto `reservas`. Você quase nunca escreve a forma qualificada — dentro do próprio projeto basta `api` — mas é ela que aparece nas mensagens de erro e nas respostas de consulta. ## Próximo passo [Elementos: as caixas](doc:modelando/elementos) começa a construir um modelo de verdade, que cresce até o fim desta seção. # Elementos: as caixas Como declarar uma caixa, o que cada campo faz, e por que o nível C4 é derivado da árvore de contenção em vez de escolhido. Uma caixa — um **elemento** — é uma pessoa, um sistema, um container, um componente ou uma classe. Tudo isso é a mesma estrutura no arquivo; o que diferencia é onde a caixa está na árvore e qual desenho ela pede. A partir desta página vamos construir um modelo de **reserva de salas de reunião**, que cresce até o fim da seção *Modelando*. ## A primeira caixa ```yaml title="model/reservas/elements.yaml" elements: - id: reservas name: Reserva de Salas shape: system description: Procura salas livres, confirma reservas e avisa quem participa. ``` Quatro campos, e só o `id` é obrigatório. Sem `parent`, essa caixa é raiz da árvore — portanto está no nível `context`, portanto é um **sistema**. ## Os campos de um elemento | Campo | Obrigatório | O que faz | |---|---|---| | `id` | sim | o identificador dentro do projeto. Letras, números, `.`, `-`, `_` | | `name` | não | o nome exibido. Sem ele, o próprio `id` aparece na caixa | | `shape` | não | o desenho. Padrão: `system` | | `parent` | não | a caixa que contém esta. **É o que decide o nível C4** | | `description` | não | uma frase sobre o que ela faz, exibida na caixa | | `technology` | não | a tecnologia, exibida na caixa em letra menor | | `tags` | não | etiquetas livres, para filtrar e agrupar | | `meta` | não | pares chave/valor livres | | `level` | não | força o nível. Discordar da árvore gera aviso, e **a árvore vence** | | `bind` | não | declara que esta caixa é o espelho de um elemento de outra modelagem | ## O nível é derivado, não escolhido Esta é a regra que mais muda a forma de escrever. O nível C4 vem da **profundidade na árvore de contenção**, que o campo `parent` constrói: ```text sem parent → context (um sistema, ou uma pessoa) filho de uma raiz → container filho de um container → component filho de um componente → code ``` Não existe um quinto nível: uma caixa mais funda que `code` continua sendo `code`. E não existe um campo "eu quero que esta seja um componente" — para descer um nível, dê um `parent` à caixa. **O campo `level` existe, e quase nunca deve ser usado** Ele serve para o caso raro em que você quer nomear o nível explicitamente. Se o valor discordar da árvore, o `cfour check` avisa e o valor derivado prevalece. Na prática: use `parent`, não `level`. ## As formas disponíveis `shape` escolhe o desenho e a cor. Estas são as formas que vêm de fábrica: | `shape` | Desenho | Uso típico | |---|---|---| | `system` | caixa | um sistema seu | | `external` | caixa de borda tracejada, cinza | um sistema de terceiro ou de outra equipe | | `actor` | silhueta de pessoa | uma pessoa, ou um papel | | `bot` | silhueta de robô | um agente automatizado tratado como ator | | `container` | caixa | uma parte executável genérica | | `api` | caixa | um serviço com interface de programação | | `browser` | janela de navegador | uma aplicação que roda no navegador | | `database` | cilindro | um banco de dados | | `queue` | fila | uma fila de mensagens | | `topic` | tópico | um tópico de eventos | | `component` | caixa menor | um componente dentro de um container | | `class` | caixa menor | uma classe, no nível de código | Uma forma desconhecida não some do desenho: ela vira uma caixa neutra, e o `cfour check` avisa. Você pode criar formas próprias — veja [Aparência da modelagem](doc:modelando/aparencia). **Forma e nível são coisas separadas** `shape: database` num container e `shape: database` num componente desenham o mesmo cilindro; o que muda é a cor, que vem do nível. Escolher `shape: component` para uma caixa que é filha de um sistema não a torna um componente — ela continua sendo um container, desenhado com a silhueta errada. ## Descendo um nível Para pôr containers dentro do sistema, basta dar a eles um `parent`: ```yaml title="model/reservas/containers.yaml" {5,12} elements: - id: painel name: Painel de Reservas shape: browser parent: reservas technology: React description: Onde a pessoa procura uma sala livre e confirma a reserva. - id: api name: API de Reservas shape: api parent: reservas technology: Node.js description: Onde moram as regras — conflito de horario, limite e confirmacao. ``` Nada mais precisa mudar. As duas caixas agora são containers de `reservas`, e qualquer diagrama que abra `reservas` por dentro passa a mostrá-las. ## O estado atual do modelo Este é o arquivo completo depois de acrescentar a pessoa e o sistema de fora: ```yaml title="model/reservas/elements.yaml" elements: - id: colaborador name: Colaborador shape: actor description: Quem precisa de uma sala para a proxima reuniao. - id: reservas name: Reserva de Salas shape: system description: Procura salas livres, confirma reservas e avisa quem participa. - id: agenda-corporativa name: Agenda Corporativa shape: external technology: Google Workspace description: Onde a empresa inteira ja mantem os compromissos das pessoas. relations: - from: colaborador to: reservas kind: sync label: Procura e reserva - from: reservas to: agenda-corporativa kind: sync label: Cria o evento na agenda ``` Repare em `agenda-corporativa`: ela é `external` porque é um sistema de outra gente. Você não vai detalhar o que existe dentro dela, e o desenho tracejado diz isso a quem lê. ## Próximo passo As caixas existem, mas ainda não conversam. [Relações: as setas](doc:modelando/relacoes). # Relações: as setas Como declarar uma seta entre duas caixas, quais tipos existem, como uma referência é resolvida, e por que você escreve a integração uma vez só. Uma **relação** é uma seta de uma caixa para outra, com um rótulo curto dizendo o que trafega. Ela descreve intenção — "reserva itens", "publica o pedido" —, e não protocolo. ## A forma mais simples ```yaml title="model/reservas/elements.yaml" relations: - from: colaborador to: reservas kind: sync label: Procura e reserva ``` ## Os campos de uma relação | Campo | Obrigatório | O que faz | |---|---|---| | `from` | sim | a caixa de origem | | `to` | sim | a caixa de destino | | `kind` | não | o tipo da seta, que decide traço, ponta e cor. Padrão: `sync` | | `label` | não | poucas palavras sobre o que trafega. É o título do cartão que aparece ao passar o mouse | | `description` | não | a forma longa, revelada ao passar o mouse | | `bidirectional` | não | `true` põe ponta também na origem | | `route` | não | `straight`, `orthogonal` ou `bezier`, sobrepondo o padrão do diagrama | | `tags` | não | etiquetas livres | | `meta` | não | pares chave/valor livres | | `id` | não | um identificador próprio, para o caso raro de algo externo precisar nomear aquela seta | Sem `id`, o identificador é derivado como `~~`. Duas setas iguais entre as mesmas caixas recebem um sufixo `#2`, `#3` e assim por diante. ## Os tipos de seta | `kind` | Aparência | Uso típico | |---|---|---| | `sync` | linha cheia, ponta fechada | uma chamada em que se espera resposta | | `async` | tracejado longo, ponta aberta | uma mensagem em que não se espera resposta | | `event` | pontilhado roxo, ponta aberta | a publicação de um evento | | `batch` | tracejado bem espaçado | uma carga periódica | | `dep` | tracejado fino cinza | uma dependência sem tráfego, como uma biblioteca | | `peer` | pontas nos dois lados | uma conversa nos dois sentidos | Um tipo desconhecido não some do desenho: vira uma linha cheia com ponta fechada, e o `cfour check` avisa. Você pode criar tipos próprios em [Aparência da modelagem](doc:modelando/aparencia). ## Onde escrever uma relação **Numa lista `relations:`, em qualquer arquivo do projeto.** É a forma que os exemplos usam. Um arquivo só de relações também vale. **Dentro do documento do próprio elemento.** Num documento singular de elemento (`kind: element`), uma lista `relations:` aninhada tem o `from` **implícito** — ele é a caixa que declara: ```yaml title="model/reservas/api.yaml" kind: element id: api name: API de Reservas shape: api parent: reservas relations: - to: banco kind: sync label: Le e grava ``` Escrever `from:` ali seria ignorado. A escolha entre as duas formas é de organização: setas junto da caixa que as origina ficam fáceis de achar; um arquivo de relações separado é melhor quando a seta atravessa projetos e nenhum dos dois lados deveria ser o dono dela. ## Como uma referência é resolvida Todo campo que cita outra caixa — `from`, `to`, `parent`, `scope`, `subject`, `target`, os seletores de um diagrama, os participantes de um fluxo — segue a mesma regra: | Como está escrito | Como resolve | |---|---| | **com barra**, `reservas/api` | absoluta: projeto e identificador | | **sem barra**, `api` | tenta o projeto que declara; se não achar, tenta `shared/` | Uma referência sem barra **não é global**: `api` escrito dentro do projeto `portaria` procura `portaria/api` e depois `shared/api`, e falha se nenhum dos dois existir. Para atravessar projeto, qualifique. Uma referência que não resolve é **erro**, não aviso: o `cfour check` reprova e diz o arquivo e o campo. ## A seta é escrita uma vez, no nível mais fino Esta é a segunda regra que muda a forma de trabalhar. Quando você desce um nível e descobre qual componente de fato conversa com o banco, a seta **desce com ele** — e você apaga a versão mais geral. Antes, no nível de container: ```yaml relations: - from: api to: banco kind: sync label: Le e grava ``` Depois, quando os componentes da API existem: ```yaml relations: - from: repositorio-de-reservas to: banco kind: sync label: Le e grava ``` O diagrama de containers **continua mostrando a mesma seta**: como o repositório está dentro da API, o desenho projeta cada ponta na caixa mais próxima que ele está mostrando. Você não mantém a integração escrita em dois lugares. **Como confirmar isso** `cfour diagram show containers --resolved` lista as caixas e as setas que o desenho de fato produz, e diz por que cada uma entrou. ## Erros comuns **Escrever a mesma integração em dois níveis.** O resultado são duas setas paralelas no diagrama mais geral. Declare no nível mais fino que você conhece. **Uma seta de uma caixa para ela mesma.** É ignorada, com aviso. Uma ação interna não é uma relação — se ela importa, ela é um passo de um [fluxo](doc:modelando/fluxos). **Uma seta entre uma caixa e um filho dela.** É aceita, mas quase sempre é ruído: a contenção já diz que um está dentro do outro. **Confiar num identificador sem barra para alcançar outro projeto.** Ele só procura o projeto local e o `shared`. ## Próximo passo Com caixas e setas, dá para desenhar. [Diagrama de contexto](doc:modelando/contexto). # Diagrama de contexto O primeiro dos quatro diagramas do C4 — o que o sistema é, quem o usa e com que sistemas ele conversa — escrito no cfourdev. O diagrama de contexto responde a uma pergunta: **que sistema é este, quem o usa e com que outros sistemas ele conversa?** Ele é o único desenho que uma pessoa não técnica precisa entender, e por isso não mostra nada de dentro. ## O que ele contém - o seu sistema, em destaque; - as pessoas e os papéis que o usam; - os sistemas de terceiros ou de outras equipes com que ele conversa; - as setas entre tudo isso, com rótulos em linguagem de negócio. E nada mais. Sem containers, sem bancos de dados, sem tecnologia. ## O modelo até aqui ```yaml title="model/reservas/elements.yaml" elements: - id: colaborador name: Colaborador shape: actor description: Quem precisa de uma sala para a proxima reuniao. - id: reservas name: Reserva de Salas shape: system description: Procura salas livres, confirma reservas e avisa quem participa. - id: agenda-corporativa name: Agenda Corporativa shape: external technology: Google Workspace description: Onde a empresa inteira ja mantem os compromissos das pessoas. relations: - from: colaborador to: reservas kind: sync label: Procura e reserva - from: reservas to: agenda-corporativa kind: sync label: Cria o evento na agenda ``` Três caixas, todas raízes — nenhuma tem `parent` —, portanto todas no nível `context`. Duas setas. ## O diagrama ```yaml title="model/reservas/contexto.yaml" kind: diagram id: contexto title: Reserva de Salas — Contexto level: context order: 10 include: - level: context relations: auto subject: reservas ``` Campo por campo: | | | |---|---| | `kind: diagram` | diz que este documento é um diagrama | | `id` | o identificador dele dentro do projeto. Sem ele, o nome do arquivo vale como identificador | | `title` | o título exibido no desenho e na barra lateral | | `level` | o nível em que o seletor de níveis do leitor abre este desenho | | `order` | a posição na barra lateral. Padrão: 500 | | `include` | **o critério** de quem entra | | `relations: auto` | desenha toda seta cujas duas pontas estão no desenho | | `subject` | a caixa em foco, desenhada com destaque | ## `include: level: context` — um critério, não uma lista Esta é a linha que faz o desenho não envelhecer: ```yaml include: - level: context ``` Ela não diz *quais* caixas mostrar; diz *que tipo* de caixa mostrar. Acrescentar um segundo sistema no arquivo ao lado o traz para este desenho sem ninguém editar aqui. Nem todo diagrama de contexto quer isso. Num modelo grande, "toda raiz" pode ser gente demais, e aí você nomeia os membros um a um: ```yaml include: - ref: reservas - ref: colaborador - ref: agenda-corporativa ``` A escolha é sua, e as duas formas convivem na mesma lista. A regra prática: use um critério quando o conjunto é o que você quer de fato; use referências quando o diagrama é uma seleção editorial. ## `subject`: o que está em foco `subject: reservas` desenha aquela caixa com destaque. O foco é uma propriedade **da visão**, e nunca da caixa: o mesmo sistema pode estar em foco num diagrama e ser um coadjuvante em outro. Por isso o campo mora no diagrama. `subject` também aceita uma lista, quando o desenho tem mais de um protagonista. ## `relations: auto`, e as alternativas | Valor | Efeito | |---|---| | `auto` | desenha toda seta cujas duas pontas estão no desenho | | `none` | não desenha seta nenhuma | | uma lista de identificadores | desenha só aquelas setas | | `{ exclude: [ids] }` | desenha todas menos aquelas | Sem o campo, o comportamento é o mesmo de `auto`. A lista explícita é rara e frágil — os identificadores derivados mudam se você trocar o tipo de uma seta —, mas existe para o desenho que precisa esconder uma integração específica. **Um diagrama vazio é um aviso** Se nenhum seletor casar com nada, o desenho fica em branco. O `cfour check` avisa, com o nome do diagrama, em vez de deixar você descobrir isso no navegador. ## Próximo passo [Diagrama de containers](doc:modelando/containers) abre o sistema por dentro. # Diagrama de containers O segundo nível do C4 — as partes executáveis de um sistema — e como um diagrama com escopo mostra os filhos de uma caixa sem listar nenhum. O diagrama de containers abre **um** sistema e mostra de que partes executáveis ele é feito: aplicações, serviços, bancos, filas, processos agendados. No C4, *container* não significa Docker. É qualquer coisa que executa ou guarda dados separadamente. ## O que muda no modelo Cada container é uma caixa nova com `parent` apontando para o sistema. É o `parent` que a põe no nível `container`. ```yaml title="model/reservas/containers.yaml" elements: - id: painel name: Painel de Reservas shape: browser parent: reservas technology: React description: Onde a pessoa procura uma sala livre e confirma a reserva. - id: api name: API de Reservas shape: api parent: reservas technology: Node.js description: Onde moram as regras — conflito de horario, limite e confirmacao. - id: banco name: Base de Reservas shape: database parent: reservas technology: PostgreSQL description: Salas, reservas e participantes. - id: fila-de-sincronizacao name: Fila de Sincronizacao shape: queue parent: reservas technology: Amazon SQS description: Uma mensagem por reserva confirmada. - id: sincronizador name: Sincronizador de Agenda shape: container parent: reservas technology: Node.js description: Le a fila e cria o evento correspondente na agenda corporativa. relations: - from: colaborador to: painel kind: sync label: Procura e reserva - from: painel to: api kind: sync label: Chama - from: api to: banco kind: sync label: Le e grava - from: api to: fila-de-sincronizacao kind: async label: Enfileira a reserva confirmada - from: fila-de-sincronizacao to: sincronizador kind: async label: Entrega a reserva - from: sincronizador to: agenda-corporativa kind: sync label: Cria o evento ``` ## As setas desceram junto Repare no que **saiu** do arquivo do contexto: as duas relações que estavam lá — `colaborador → reservas` e `reservas → agenda-corporativa` — foram reescritas aqui como `colaborador → painel` e `sincronizador → agenda-corporativa`. Isso não deixa o diagrama de contexto incompleto. Ele continua desenhando as mesmas duas setas, porque cada ponta é projetada na caixa mais próxima que aquele desenho está mostrando — e no contexto, tanto o painel quanto o sincronizador estão dentro de `reservas`. **Confira você mesmo** ```sh cfour diagram show contexto --resolved ``` ```text reservas/colaborador -> reservas/reservas sync "Procura e reserva" reservas/reservas -> reservas/agenda-corporativa sync "Cria o evento" ``` É por isso que uma integração é escrita uma vez só, no nível mais fino que você conhece. ## O diagrama ```yaml title="model/reservas/containers-diagrama.yaml" kind: diagram id: containers title: Reserva de Salas — Containers level: container scope: reservas order: 20 neighbors: 1 relations: auto ``` Duas linhas fazem o trabalho: **`scope: reservas`** — abre aquela caixa por dentro. Ela vira a fronteira do desenho: uma moldura com o nome dela, e tudo que estiver dentro pertence a ela. No leitor, descer para dentro de `reservas` abre este diagrama. **A ausência de `include`** — quando há `scope` e não há `include`, o padrão é mostrar os **filhos diretos** do escopo. É isso que faz um container novo entrar sozinho: você cria o arquivo com `parent: reservas` e ele aparece aqui, sem editar este documento. **`neighbors: 1`** — puxa quem está a um salto de distância como contexto mudo, fora da fronteira. Aqui isso traz o *Colaborador* e a *Agenda Corporativa*, para o desenho não parecer que o sistema conversa com o nada. ## O que aparece de fato ```text 7 caixa(s), 6 seta(s) reservas/painel dentro children:reservas/reservas reservas/api dentro children:reservas/reservas reservas/banco dentro children:reservas/reservas reservas/fila-de-sincronizacao dentro children:reservas/reservas reservas/sincronizador dentro children:reservas/reservas reservas/colaborador contexto neighbors: 1 reservas/agenda-corporativa contexto neighbors: 1 ``` *Dentro* significa dentro da fronteira; *contexto* significa trazido pelo anel de vizinhos, e desenhado esmaecido. ## Tecnologia é um campo, não um rótulo solto `technology: PostgreSQL` aparece na caixa em letra menor. Use para o que ajuda quem lê a se orientar — a linguagem, o banco, o serviço gerenciado — e não para a versão exata, que envelhece antes do desenho. ## Próximo passo [Diagrama de componentes](doc:modelando/componentes) abre **um** container por dentro. # Diagrama de componentes O terceiro nível do C4 — as peças dentro de um container — e como a seta que estava no nível de cima desce para o componente que de fato a faz. O diagrama de componentes abre **um** container e mostra as peças dentro dele. É o nível que mais rende quando o container é grande e a equipe é nova nele, e o que mais envelhece quando o time refatora com frequência. Não é obrigatório descer até aqui em todo container — desça onde a pergunta existe. ## Os componentes Cada componente é uma caixa com `parent` apontando para o container: ```yaml title="model/reservas/componentes.yaml" elements: - id: servico-de-reserva name: Servico de Reserva shape: component parent: api technology: TypeScript description: Confere conflito de horario e confirma a reserva. - id: repositorio-de-reservas name: Repositorio de Reservas shape: component parent: api technology: TypeScript description: Le e grava reservas. - id: publicador name: Publicador shape: component parent: api technology: TypeScript description: Poe a reserva confirmada na fila de sincronizacao. relations: - from: servico-de-reserva to: repositorio-de-reservas kind: sync label: Consulta e grava - from: repositorio-de-reservas to: banco kind: sync label: Le e grava - from: servico-de-reserva to: publicador kind: sync label: Pede a publicacao - from: publicador to: fila-de-sincronizacao kind: async label: Enfileira a reserva confirmada ``` ## O que saiu do arquivo de containers Duas relações desapareceram de `containers.yaml`: ```yaml del={2-5,7-10} relations: - from: api to: banco kind: sync label: Le e grava - from: api to: fila-de-sincronizacao kind: async label: Enfileira a reserva confirmada ``` Elas foram reescritas no nível de componente, apontando para quem de fato faz o trabalho: `repositorio-de-reservas → banco` e `publicador → fila-de-sincronizacao`. O diagrama de containers **não perdeu nada**: as duas setas continuam lá, projetadas na API, porque os dois componentes estão dentro dela. **Se você deixar as duas versões** O diagrama de containers passa a mostrar duas setas paralelas da API para o banco — a declarada e a derivada. Quando descer um nível, apague a versão de cima. Uma relação **não** desceu: `painel → api`. Isso é deliberado — o painel fala com a API como um todo, e não com um componente específico dela. Escreva a seta na granularidade que você realmente conhece. ## O diagrama ```yaml title="model/reservas/componentes-diagrama.yaml" kind: diagram id: componentes title: API de Reservas — Componentes level: component scope: api order: 30 neighbors: 1 relations: auto ``` Mesma estrutura do nível anterior, com o escopo um degrau mais fundo: `scope: api` abre a API por dentro, e a ausência de `include` mostra os filhos diretos dela. ## Quando parar Não existe obrigação de descer. Um bom critério: - **desça** quando alguém novo na equipe precisaria de um mapa para achar onde mexer; - **desça** quando o container tem mais de um motivo para mudar, e você quer que isso fique visível; - **não desça** quando os componentes seriam um espelho dos diretórios do código, que já estão lá e já são navegáveis; - **não desça** quando você não consegue se comprometer a atualizar. Um modelo que para no nível de container e está correto vale muito mais do que um que desce até o código e mente. ## Próximo passo [O nível de código](doc:modelando/codigo) — o quarto e último. # O nível de código O quarto nível do C4 no cfourdev — o que ele é aqui, quando vale a pena, e por que quase sempre não vale. O quarto nível do C4 mostra como um componente está estruturado por dentro: classes, interfaces, funções. No cfourdev ele não é um recurso separado. É a mesma coisa de sempre, um degrau mais fundo na árvore: ```text sem parent → context filho de uma raiz → container filho de um container → component filho de um componente → code ← aqui ``` Uma caixa filha de um componente está no nível `code`. Nada mais muda: os mesmos campos, as mesmas relações, o mesmo tipo de diagrama. ## O que existe de específico **A forma `class`.** Um desenho compacto, com a cor mais clara da escala. É a única forma pensada para este nível, e nada impede usar outra. **Nada além disso.** Não há campo para método, para atributo, para visibilidade, para herança, nem para *generics*. O cfourdev não é uma ferramenta de UML — o vocabulário é o do C4, e no C4 este nível é opcional e informal. ## Um exemplo ```yaml title="model/reservas/classes.yaml" elements: - id: reserva name: Reserva shape: class parent: servico-de-reserva description: Sala, horario, quem pediu e o estado da confirmacao. - id: janela-de-horario name: JanelaDeHorario shape: class parent: servico-de-reserva description: Um intervalo, e a regra de sobreposicao entre dois deles. relations: - from: reserva to: janela-de-horario kind: dep label: Usa ``` E o diagrama: ```yaml title="model/reservas/codigo.yaml" kind: diagram id: codigo title: Servico de Reserva — Codigo level: code scope: servico-de-reserva relations: auto ``` ## Quando isso vale a pena Raramente, e é honesto dizer. O código é a única descrição de si mesmo que nunca desatualiza, e ele está a um clique de distância de quem lê. Um diagrama de classes escrito à mão compete com isso e perde na semana seguinte. Os casos em que ele ganha: - **um desenho que sobrevive à implementação** — o modelo de domínio que a equipe combinou antes de escrever qualquer coisa, e ao qual ela volta; - **uma peça central e estável** — o núcleo de regras que muda uma vez por ano e que todo mundo precisa entender; - **uma explicação para quem não vai ler o código** — arquitetos de outra equipe, uma auditoria, um pedido de aprovação. Se o seu caso não é um desses, pare no nível de componente. ## Próximo passo Os quatro níveis estão cobertos. As próximas páginas são sobre **como um diagrama escolhe o que mostrar** — [os seletores](doc:modelando/diagramas). # Como um diagrama escolhe o que mostra Escopo, seletores, filtro, exclusão, anel de vizinhos e agrupamento automático — a ordem em que um diagrama é resolvido, e o que cada campo faz. Um diagrama **não guarda a lista dos seus membros**. Ele guarda uma pergunta, e a resposta é calculada a cada leitura. É a diferença que mais custa quando se ignora, e a que faz um desenho não envelhecer. Esta página explica cada peça dessa pergunta e a ordem em que elas se aplicam. ## A ordem da resolução ```text 1. include quem entra (ou os filhos de `scope`, se não houver include) 2. where filtra o que entrou 3. exclude tira quem o seletor pegar 4. neighbors puxa quem encosta, como contexto mudo, fora da fronteira 5. relações projeta cada ponta na caixa mais próxima que o desenho mostra 6. grupos as bandas, sobre quem está DENTRO da fronteira 7. subject marca quem está em foco ``` A ordem importa: `where` filtra só o que `include` trouxe, e `exclude` age depois do filtro. Nenhum dos três alcança o que `neighbors` puxa depois. ## `scope`: a caixa que o diagrama detalha ```yaml scope: reservas ``` Faz três coisas: - desenha a **fronteira**, uma moldura com o nome daquela caixa; - define o padrão de `include` como **os filhos diretos** do escopo; - torna o diagrama o destino de quem descer para dentro daquela caixa no leitor. O escopo é a moldura, e **não um membro**: ele não aparece como caixa dentro do próprio desenho. ## Os seletores Um seletor nomeia um conjunto sem listá-lo. Estes são todos: | Seletor | O que traz | |---|---| | `ref: ` | exatamente aquela caixa | | `children: ` | os filhos **diretos** dela | | `descendants: ` | todos os descendentes, em qualquer profundidade | | `descendants: ` + `depth: ` | os descendentes até `n` níveis abaixo | | `tag: ` | quem tem aquela etiqueta. Aceita uma lista, que combina com **ou** | | `meta: { : }` | quem tem aquele metadado. O valor aceita uma lista | | `level: ` | `context`, `container`, `component` ou `code`. Aceita lista | | `shape: ` | quem tem aquela forma. Aceita lista | | `project: ` | tudo de um projeto | Uma string solta é atalho para `ref`: ```yaml include: - reservas # o mesmo que { ref: reservas } - ref: colaborador - tag: nucleo - level: [container, component] ``` Vários seletores na mesma lista **somam** — a união de todos. **Um seletor que não acha nada** Um `ref` para uma caixa inexistente é **erro**, e o `cfour check` reprova. Já um `tag:` que não casa com ninguém é legítimo — o conjunto simplesmente é vazio. Quando o diagrama inteiro fica vazio, você recebe um aviso com o nome dele. ## `where`: um filtro sobre o que entrou ```yaml include: - descendants: reservas where: level: container ``` `where` aceita os mesmos seletores **menos** `ref`, `children` e `descendants` — ou seja, `tag`, `meta`, `level`, `shape` e `project`. A razão é que os três de fora produzem conjuntos, e não respondem "sim ou não" sobre uma caixa. ## `exclude`: tirar quem o seletor pegar ```yaml scope: reservas exclude: - ref: sincronizador - tag: legado ``` Aceita todos os seletores, com a mesma sintaxe de `include`. ## `neighbors`: quem encosta, sem entrar ```yaml neighbors: 1 ``` Traz para o desenho quem tem uma seta com a outra ponta já dentro. Essas caixas aparecem **esmaecidas e fora da fronteira** — são contexto, não membros. Dois detalhes que evitam surpresa: - **um vizinho de outra árvore aparece como o sistema dele**, e não como o componente que por acaso faz a integração. É assim que o C4 desenha quem está de fora; - **num diagrama sem `scope`**, todo vizinho colapsa para a raiz dele, porque uma visão de raízes não deve receber uma caixa de nível 3. `neighbors: 2` repete o processo sobre o resultado. Valores acima de 2 costumam trazer o modelo inteiro. ## `relations`: quais setas desenhar | Valor | Efeito | |---|---| | ausente, ou `auto` | toda seta cujas duas pontas estão no desenho | | `none` | nenhuma | | `[id, id, ...]` | só aquelas | | `{ exclude: [id, ...] }` | todas menos aquelas | Os identificadores são derivados (`~~`), então uma lista explícita quebra em silêncio se você trocar o tipo de uma seta. O `cfour check` avisa quando um identificador citado não existe. Para descobrir os identificadores: `cfour relation list --json`. ## `groupBy`: uma banda por valor, sem escrever nenhuma ```yaml groupBy: meta.dominio ``` Cria automaticamente um grupo para cada valor distinto encontrado. Os valores aceitos são: | `groupBy` | Agrupa por | |---|---| | `meta.` | o valor daquele metadado | | `level` | o nível C4 | | `shape` | a forma | | `project` | o projeto | Quem não tem valor para aquela dimensão fica solto, fora de qualquer banda. **Não existe `groupBy: tag:`.** Um grupo é uma partição: cada caixa cai em exatamente uma, porque o retângulo é o contorno dos membros dele. Etiquetas acumulam — uma caixa pode ter três —, então agrupar por etiqueta não tem como cumprir a promessa. Escrever isso é um erro com mensagem explícita. Etiqueta serve para **filtrar**, que é onde a relação de muitos para muitos se resolve. Para grupos escritos à mão, com nome e aninhamento, veja [Grupos dentro de um diagrama](doc:modelando/grupos). ## `subject`: quem está em foco ```yaml subject: reservas # ou subject: [reservas, api] ``` Desenha aquelas caixas com destaque. O foco é propriedade **da visão**: a mesma caixa pode ser protagonista num diagrama e coadjuvante em outro, e por isso o campo mora no diagrama e não no elemento. `subject` não cai de volta para `scope`: num diagrama com escopo, o escopo é a moldura e não está no desenho. ## Os campos restantes | Campo | O que faz | |---|---| | `title` | o título exibido. Sem ele, vale o identificador | | `level` | o nível em que o seletor de níveis do leitor abre este desenho. Sem ele, é derivado do que o desenho mostra | | `order` | a posição na barra lateral. Padrão: 500 | | `tags`, `meta` | etiquetas e metadados do próprio diagrama, para filtrar a lista de diagramas | | `notes` | uma lista de notas confinadas a este desenho — veja [Notas](doc:modelando/notas) | A pasta onde o arquivo está define a trilha dele na barra lateral. Um primeiro segmento chamado `diagrams` é descartado, porque ele diz "isto é um diagrama", que a árvore já mostra. ## Descobrir o que um diagrama de fato mostra ```sh cfour diagram show containers --resolved ``` Ele lista as caixas, quem as trouxe, as setas, e as bandas. É a forma de responder "por que essa caixa está aqui" sem abrir o navegador. ## Próximo passo [Grupos dentro de um diagrama](doc:modelando/grupos). # Grupos dentro de um diagrama Como agrupar caixas num diagrama — bandas escritas à mão, com nome, aninhamento e orientação — e por que um grupo pertence ao diagrama e não ao modelo. Um **grupo** é um retângulo com nome, dentro de um diagrama, que reúne algumas das caixas daquele desenho: "Experiência", "Domínio", "Dados". Ele pertence ao **diagrama**, e não ao modelo. A mesma caixa pode estar num grupo chamado "Dados" num desenho e em nenhum grupo noutro — porque agrupar é uma decisão de leitura, e leituras diferentes agrupam diferente. ## Um exemplo ```yaml title="model/reservas/containers-diagrama.yaml" kind: diagram id: containers title: Reserva de Salas — Containers level: container scope: reservas order: 20 neighbors: 1 relations: auto groups: - id: experiencia name: Experiencia orientation: row match: tag: experiencia - id: plataforma name: Plataforma include: - ref: api - ref: sincronizador groups: - id: dados name: Dados match: shape: [database, queue] ``` O que isso desenha: uma banda *Experiência* com o painel; uma banda *Plataforma* com a API e o sincronizador; e, dentro dela, uma banda *Dados* com o banco e a fila. ## Os campos de um grupo | Campo | Obrigatório | O que faz | |---|---|---| | `id` | sim | o identificador dentro daquele diagrama | | `name` | não | o rótulo exibido. Sem ele, o próprio `id` | | `orientation` | não | `row` faz a banda ler como uma linha; sem isso, as caixas empilham | | `include` | não | uma lista de seletores — os mesmos de um diagrama | | `match` | não | atalho para um `include` de uma cláusula só | | `groups` | não | grupos aninhados | `include` e `match` fazem a mesma coisa; `match` existe para o caso comum de um critério único, e aceita `tag`, `meta`, `level`, `shape` e `project`. ## Aninhamento, e quem reivindica primeiro Grupos aninham, e a regra é: **a banda mais interna reivindica primeiro, e os ancestrais herdam**. Uma caixa que casa com *Dados* fica em *Dados*, e por consequência dentro de *Plataforma*. Isso é o que permite escrever a banda de fora por seletor largo e a de dentro por seletor estreito, sem tirar uma da outra à mão. ## Só quem está dentro da fronteira Uma caixa trazida por `neighbors` — contexto mudo, fora da moldura — **não entra em grupo nenhum**. Se entrasse, o retângulo da banda a desenharia dentro de uma fronteira que a exclui, e os dois retângulos se contradiriam. ## Quando usar `groupBy` em vez disto `groupBy: meta.dominio` cria uma banda por valor distinto, sem você escrever nenhuma. Use quando: - o agrupamento **é** um dado que já está no modelo (o domínio, o time, o nível); - você quer que uma caixa nova entre na banda certa sozinha. Use grupos escritos à mão quando o agrupamento é editorial — quando o nome da banda é uma explicação, e não um valor. Os dois não convivem: quando há `groups`, o `groupBy` é ignorado. **Por que um grupo não pode ser feito por etiqueta** Um grupo é uma partição — cada caixa cai em exatamente uma banda, porque o retângulo é o contorno dos membros dele, e duas bandas sobrepostas não são desenháveis. Uma caixa pode ter três etiquetas, então `groupBy` por etiqueta não teria como escolher. Isso é recusado com uma mensagem explícita. Um `match: {tag: ...}` escrito à mão continua valendo, porque aí é você quem garante que os conjuntos não se sobrepõem. ## Próximo passo [Etiquetas e metadados](doc:modelando/etiquetas-e-metadados) — os dois eixos livres do formato. # Etiquetas e metadados Os dois eixos livres do formato — quando usar etiqueta, quando usar metadado, onde eles podem ser escritos e o que a plataforma faz com eles. O cfourdev conhece C4 e nada mais. Time, domínio, produto, criticidade, jornada, código de rastreabilidade — nada disso tem campo próprio, e é deliberado: seriam campos de um domínio específico dentro de um formato que precisa servir a todos. O que existe são **dois eixos livres**, e a diferença entre eles é uma só. ## A diferença, em uma frase | | | |---|---| | **etiqueta** (`tags`) | uma marca **sem valor**. Uma caixa pode ter várias | | **metadado** (`meta`) | um par **chave e valor**. Uma chave tem um valor só por caixa | Daí decorre tudo o mais: - **agrupar** exige valor único, então só metadado agrupa; - **filtrar** funciona com os dois; - **colorir** o desenho por uma dimensão exige valor único, então só metadado colore. ## Como escrever ```yaml - id: api name: API de Reservas shape: api parent: reservas tags: [nucleo, pci] meta: dominio: reservas time: squad-espacos criticidade: alta ``` Os valores de `meta` podem ser texto, número ou booleano. Uma estrutura mais complexa é convertida em texto. ## Onde eles podem ser escritos | | `tags` | `meta` | |---|---|---| | elemento | sim | sim | | relação | sim | sim | | diagrama | sim | sim | | fluxo | sim | sim | | projeto | sim | sim | | nota | não | sim | ## O que a plataforma faz com eles **Toda etiqueta e toda chave de metadado viram filtro automaticamente.** Não há nada a configurar: escrever `time: squad-espacos` numa caixa faz aparecer um filtro "time" no leitor, com os valores encontrados e a contagem de cada um. **Um metadado cujo valor é uma URL vira um link na caixa**, e não um filtro. Nenhum campo novo, nenhuma configuração: ```yaml meta: runbook: https://exemplo.interno/runbooks/api-de-reservas ``` O leitor mostra isso como um link chamado `runbook`. Ele não vira filtro porque um filtro cujos valores são todos únicos não filtra nada — só enterra os filtros reais. **A configuração da modelagem pode dar um rótulo melhor a uma chave**, e liberar uma chave para colorir o desenho. Isso é opcional; veja [Aparência da modelagem](doc:modelando/aparencia). ## Convenções que ajudam **Prefixe etiquetas quando houver mais de um eixo.** `camada/experiencia`, `camada/dominio`, `conformidade/pci`. O motor nunca interpreta o conteúdo de uma etiqueta, mas quem lê a lista agradece. **Use metadado quando você quiser agrupar ou colorir por aquilo.** Se a pergunta é "mostre-me isto separado por domínio", é metadado. **Use etiqueta quando uma caixa pode ter várias marcas ao mesmo tempo.** Uma API pode ser ao mesmo tempo `nucleo` e `pci`. **Mantenha o vocabulário curto.** Uma chave de metadado usada em três caixas de oitenta é ruído no filtro. **Etiqueta não agrupa** `groupBy: tag:` não existe, e escrever isso é erro. A razão está em [Grupos](doc:modelando/grupos): uma banda é uma partição, e etiquetas acumulam. ## O estado atual do modelo ```yaml title="model/reservas/containers.yaml" elements: - id: painel name: Painel de Reservas shape: browser parent: reservas technology: React description: Onde a pessoa procura uma sala livre e confirma a reserva. tags: [experiencia] meta: dominio: reservas time: squad-espacos - id: api name: API de Reservas shape: api parent: reservas technology: Node.js description: Onde moram as regras — conflito de horario, limite e confirmacao. tags: [nucleo] meta: dominio: reservas time: squad-espacos criticidade: alta runbook: https://exemplo.interno/runbooks/api-de-reservas - id: banco name: Base de Reservas shape: database parent: reservas technology: PostgreSQL description: Salas, reservas e participantes. tags: [dados] meta: dominio: reservas time: squad-espacos - id: fila-de-sincronizacao name: Fila de Sincronizacao shape: queue parent: reservas technology: Amazon SQS description: Uma mensagem por reserva confirmada. tags: [dados] meta: dominio: integracao time: squad-espacos - id: sincronizador name: Sincronizador de Agenda shape: container parent: reservas technology: Node.js description: Le a fila e cria o evento correspondente na agenda corporativa. tags: [integracao] meta: dominio: integracao time: squad-integracoes relations: - from: colaborador to: painel kind: sync label: Procura e reserva - from: painel to: api kind: sync label: Chama meta: protocolo: REST - from: fila-de-sincronizacao to: sincronizador kind: async label: Entrega a reserva - from: sincronizador to: agenda-corporativa kind: sync label: Cria o evento meta: protocolo: REST ``` ## Descobrir o vocabulário de uma modelagem ```sh cfour find squad-espacos cfour element list --tag nucleo ``` E, no leitor, o painel de filtros lista toda etiqueta e toda chave de metadado encontradas, com a contagem de cada valor. ## Próximo passo [Notas](doc:modelando/notas) — riscos, decisões e recados presos ao modelo. # Notas Como registrar riscos, decisões, dúvidas e avisos junto do elemento a que eles pertencem — e por que risco e decisão são notas, e não entidades próprias. Uma **nota** é um recado preso a uma caixa, ou solto num diagrama. É onde vivem o risco conhecido, a decisão tomada, a dúvida em aberto e o aviso de operação. Não existe entidade "risco" nem entidade "decisão" no formato. **Um risco é uma nota com `kind: risk`**, e o vocabulário de tipos é aberto — quem modela declara os que fizerem sentido. ## Escrever uma nota ```yaml title="model/reservas/notas.yaml" notes: - target: api kind: risk text: Ponto unico de falha para confirmar uma reserva. meta: levantadoPor: arquitetura - target: sincronizador kind: decisao text: A sincronizacao e assincrona de proposito — a reserva vale mesmo se a agenda estiver fora do ar. # Sem `target`: um adesivo solto, so no diagrama de containers. - scope: containers kind: info text: Desenho congelado para a revisao de arquitetura de 2026-Q1. ``` ## Os campos | Campo | Obrigatório | O que faz | |---|---|---| | `text` | sim | o texto da nota | | `target` | não | a caixa a que ela se prende | | `scope` | não | o diagrama a que ela se restringe | | `kind` | não | o tipo. Padrão: `info` | | `meta` | não | pares chave/valor livres | **`target` e `scope` decidem onde a nota aparece:** | `target` | `scope` | Onde aparece | |---|---|---| | uma caixa | ausente | naquela caixa, em **todo** diagrama que a mostra | | uma caixa | um diagrama | naquela caixa, **só** naquele diagrama | | ausente | um diagrama | como um adesivo solto naquele diagrama | | ausente | ausente | em lugar nenhum — o `cfour check` avisa e a nota é descartada | ## Os tipos que vêm de fábrica | `kind` | Rótulo | Marca | |---|---|---| | `risk` | Risco | R, vermelho | | `blocker` | Bloqueio | !, vermelho forte | | `warning` | Atenção | !, laranja | | `question` | Dúvida | ?, roxo | | `info` | Informação | i, azul | | `tip` | Nota | estrela, verde | Um tipo desconhecido não some: ele vira um distintivo neutro carregando a chave crua, e o `cfour check` avisa. Criar um tipo novo é uma entrada em `workspace.yaml` — veja [Aparência da modelagem](doc:modelando/aparencia). ## Onde escrever **Num arquivo só de notas**, como no exemplo acima. É a forma mais legível quando as notas são revisadas juntas. **Dentro do documento do elemento.** Num documento singular (`kind: element`), uma lista `notes:` aninhada tem o `target` implícito: ```yaml title="model/reservas/api.yaml" kind: element id: api name: API de Reservas parent: reservas notes: - kind: risk text: Ponto unico de falha para confirmar uma reserva. ``` **Dentro do documento do diagrama.** Ali o `scope` é implícito — a nota fica confinada àquele desenho: ```yaml title="model/reservas/containers-diagrama.yaml" kind: diagram id: containers scope: reservas notes: - kind: info text: Desenho congelado para a revisao de arquitetura de 2026-Q1. ``` ## Por que a nota se prende ao elemento, e não ao desenho Uma nota presa a uma caixa **acompanha aquela caixa em todo diagrama onde ela apareça**. Isso é o oposto de escrever um comentário num desenho: o risco da API é do sistema, e não da folha de papel em que alguém o anotou primeiro. Use `scope` quando o recado é mesmo sobre aquele desenho — "aqui omitimos o legado de propósito" — e não sobre a caixa. **Encontrar as notas depois** ```sh cfour note list cfour note list --target api cfour find "ponto unico" ``` Um agente conectado ao [servidor MCP](doc:agentes) faz a mesma pergunta com a ferramenta `cfour_notes`, filtrando por tipo. ## Próximo passo [Fluxos](doc:modelando/fluxos) — contar o que acontece, e em que ordem. # Fluxos: uma sequência Como contar um caso de uso como uma sequência de mensagens sobre as caixas que já existem, com caminhos alternativos e desfechos. Um **fluxo** conta um caso de uso como uma sequência de mensagens, no estilo de um diagrama de sequência. Ele é a resposta do cfourdev à visão *dynamic* do C4. Um fluxo **não inventa caixa nenhuma**: ele percorre as que já existem. E cada passo deveria corresponder a uma seta que o modelo já declara — quando não corresponde, o desenho marca o passo, porque o fluxo acabou de encontrar um buraco na estrutura. ## O fluxo completo ```yaml title="model/reservas/fluxo-reservar.yaml" kind: flow id: reservar title: Reservar uma sala scope: reservas level: container order: 10 main: name: Sala livre outcome: success participants: - colaborador - painel - api steps: - from: colaborador to: painel label: Escolhe sala e horario - to: api label: Pede a reserva # Da API para o componente que faz o trabalho: nao ha seta declarada entre os # dois, e nem precisa haver — um deles esta DENTRO do outro. - to: servico-de-reserva label: Confirma a reserva - id: conflito to: repositorio-de-reservas label: Procura conflito no horario reply: Nenhum conflito - from: servico-de-reserva to: publicador label: Pede a publicacao - to: fila-de-sincronizacao kind: async label: Enfileira a reserva confirmada - from: api to: painel label: Reserva confirmada - to: colaborador label: Mostra a confirmacao paths: - id: ocupada name: Sala ocupada outcome: failure from: conflito steps: - to: servico-de-reserva label: Ja existe reserva nesse horario - from: api to: painel label: Recusa com o motivo - to: colaborador label: Sugere outro horario ``` ## Os campos de um fluxo | Campo | Obrigatório | O que faz | |---|---|---| | `id` | não | o identificador. Sem ele, o nome do arquivo | | `title` | não | o título exibido | | `scope` | não | onde o caso de uso acontece. Dá a trilha e o lugar na árvore — **não** escolhe os participantes | | `level` | não | o nível em que o fluxo abre. Sem ele, o nível mais fino que os passos citam | | `order` | não | a posição na barra lateral | | `main` | não | `name` e `outcome` do caminho principal | | `participants` | não | fixa quem são as colunas e a ordem delas | | `steps` | sim | as mensagens do caminho principal | | `paths` | não | os caminhos alternativos | | `tags`, `meta` | não | etiquetas e metadados | **`scope` de um fluxo não é `scope` de um diagrama** Num diagrama, o escopo escolhe os membros. Num fluxo, quem escolhe são os passos — o escopo só diz onde a história mora, para a barra lateral. ## Os passos ```yaml steps: - from: colaborador to: painel label: Escolhe sala e horario - to: api label: Pede a reserva ``` | Campo | Obrigatório | O que faz | |---|---|---| | `to` | sim | quem recebe | | `from` | não | quem envia. **Omitido, herda o `to` do passo anterior** | | `label` | não | o texto ao lado da linha. Sem ele, o rótulo da seta declarada | | `kind` | não | o tipo da seta. Sem ele, o da seta declarada | | `reply` | não | uma resposta curta, tracejada, na própria linha | | `description` | não | o texto longo, revelado ao passar o mouse | | `id` | não | um identificador local, necessário só para ser ponto de desvio | O `from` implícito é o que torna a maioria dos fluxos curta: quase toda sequência é uma corrente, e escrever `from` em todo passo seria repetir o passo anterior. No **primeiro** passo não há o que herdar, e omiti-lo é erro. ## Os três casos em que um passo não precisa de seta declarada Um passo cuja conversa não existe no modelo recebe um aviso e é desenhado marcado. Três situações são exceção, e não geram aviso nenhum: **Contenção.** Um passo da API para um componente dentro dela é sustentado pelo modelo tanto quanto uma seta seria — a contenção *é* a relação entre os dois. Pedir uma seta ali seria pedir para escrever algo que o vocabulário do C4 não tem. **Chamada interna.** Um passo de uma caixa para ela mesma é uma ação interna, e não uma integração. **A resposta.** Um passo no sentido contrário ao de uma seta declarada é sustentado por ela — a resposta volta pelo mesmo caminho da pergunta. O rótulo não é herdado, porque o rótulo declarado descreve a chamada, e não a resposta. ## `reply`: uma resposta curta na mesma linha ```yaml - id: conflito to: repositorio-de-reservas label: Procura conflito no horario reply: Nenhum conflito ``` Desenha uma linha tracejada de volta, logo abaixo. É para a resposta que não merece um passo próprio. Uma resposta que muda o rumo da história merece um passo. ## Caminhos alternativos ```yaml paths: - id: ocupada name: Sala ocupada outcome: failure from: conflito steps: - to: servico-de-reserva label: Ja existe reserva nesse horario ``` | Campo | Obrigatório | O que faz | |---|---|---| | `id` | sim | o identificador do caminho dentro do fluxo | | `name` | não | o nome no seletor. Sem ele, o próprio `id` | | `outcome` | não | como ele termina. Padrão: `alternate` | | `from` | não | o `id` do passo de onde ele desvia, **inclusive** | | `steps` | sim | os passos deste caminho | `from: conflito` significa: os passos do caminho principal até `conflito`, incluindo-o, são reproduzidos esmaecidos como contexto, e daí em diante vale o que está escrito aqui. Você escreve **só o que difere**. Um caminho sem `from` começa do zero. O primeiro passo de um caminho que desvia herda o `to` do passo de desvio, do mesmo jeito que dentro de uma sequência. ## Os desfechos | `outcome` | Rótulo | Cor | |---|---|---| | `success` | Sucesso | verde | | `failure` | Falha | vermelho | | `alternate` | Alternativo | âmbar | A cor fica no seletor que escolhe o caminho, e nunca nas mensagens — um final infeliz é uma leitura do fluxo, e não uma propriedade de uma seta. O vocabulário é aberto: `flowOutcomes` em `workspace.yaml` aceita os seus. ## `participants`: a ordem das colunas ```yaml participants: - colaborador - painel - api ``` Fixa quem são as primeiras colunas e em que ordem. Quem não está na lista entra na ordem em que aparece pela primeira vez. Listar a espinha do caso de uso costuma bastar. Um participante que não aparece em passo nenhum recebe aviso. ## O fluxo lido em outro nível Um fluxo escrito no nível mais fino que o modelo tem pode ser lido mais acima: o seletor de nível do leitor sobe as pontas de cada mensagem. Quando as duas pontas caem na mesma caixa, aquela mensagem **desaparece** — ela aconteceu dentro de uma caixa só. É por isso que vale escrever o fluxo fino: a leitura grosseira é derivada, e a fina não seria. ## Um fluxo não tem arrumação manual Diagramas guardam a posição das caixas em `.layout/`. Fluxos não guardam nada: toda coordenada vem da ordem das colunas e da ordem das mensagens. A única decisão de apresentação é a ordem de `participants`, e ela é escrita. ## Próximo passo [Projetos](doc:modelando/projetos) — como dividir um modelo grande. # Projetos Como dividir uma modelagem grande em projetos, como referências atravessam a fronteira entre eles, e para que serve o projeto shared. Um **projeto** é uma pasta diretamente sob `model/`. Ele faz uma coisa só: ser o dono dos identificadores dentro dele. O mesmo `api` pode existir em `reservas/` e em `portaria/` sem colidir. É por isso que dividir um modelo grande não obriga a renomear nada. ## A estrutura - model/ - workspace.yaml - shared/ caixas que todos usam - project.yaml - elements.yaml - reservas/ - project.yaml - elements.yaml - contexto.yaml - portaria/ - project.yaml - elements.yaml - contexto.yaml ## Declarar um projeto Um `project.yaml` não é obrigatório: uma pasta com documentos dentro já é um projeto, com o nome da própria pasta. O arquivo existe para dar a ele um nome legível, uma ordem e etiquetas. ```yaml title="model/reservas/project.yaml" kind: project id: reservas name: Reservas de Salas order: 10 ``` | Campo | O que faz | |---|---| | `id` | deve bater com o nome da pasta. Se discordar, **a pasta vence** e você recebe um aviso | | `name` | o nome exibido na barra lateral | | `order` | a posição entre os projetos. Padrão: 500 | | `tags`, `meta` | etiquetas e metadados do projeto | ## Atravessar a fronteira Uma referência **sem barra** procura no projeto que a declara e depois em `shared`. Para alcançar outro projeto, qualifique com barra: ```yaml title="model/portaria/elements.yaml" elements: - id: portaria name: Controle de Portaria shape: system description: Libera a catraca de quem tem reuniao marcada no predio. relations: # Uma seta que atravessa projetos: os dois lados sao ids qualificados. - from: portaria to: reservas/reservas kind: sync label: Confere a reserva do dia ``` Uma seta pode atravessar projetos livremente. O que decide em qual arquivo escrevê-la é organização, não permissão: quando nenhum dos dois lados deveria ser o dono da integração, um arquivo de relações próprio resolve. ## O projeto `shared` `shared` é o único nome de projeto com significado especial: ele é o segundo lugar consultado quando uma referência não tem barra. ```yaml title="model/shared/elements.yaml" elements: - id: colaborador name: Colaborador shape: actor description: Quem trabalha na empresa. - id: agenda-corporativa name: Agenda Corporativa shape: external technology: Google Workspace ``` Com isso, qualquer projeto escreve `colaborador` e alcança essa caixa, sem qualificar. O que costuma morar ali: as pessoas e os papéis, os sistemas de terceiros, e as plataformas internas que todo mundo consome. **O que não deve morar em `shared`** Uma caixa que só um projeto usa. Pôr tudo em `shared` desfaz a única coisa que os projetos fazem — separar espaços de identificadores — e transforma a pasta num depósito. ## Quando criar o segundo projeto Crie um projeto novo quando: - o modelo tem **dois ou mais sistemas** com vidas próprias, cada um com o seu conjunto de containers; - equipes diferentes editam partes diferentes, e você quer que os arquivos delas não se cruzem; - os identificadores começaram a ficar longos para evitar colisão (`reservas-api`, `portaria-api`). Não crie um projeto para separar níveis, nem para separar tipos de arquivo. A árvore de contenção já separa níveis, e o arranjo de pastas dentro de um projeto é livre. ## Quando o caso é outra **modelagem**, e não outro projeto Um projeto novo é a resposta certa enquanto tudo é a mesma realidade: o mesmo vocabulário, o mesmo público, a mesma configuração de aparência. Quando não é — quando são duas equipes com glossários diferentes, ou dois produtos que se leem separadamente — a resposta é uma [segunda modelagem](doc:modelando/modelagens), que é uma unidade maior e se publica sozinha. ## Próximo passo [Aparência da modelagem](doc:modelando/aparencia). # Aparência da modelagem O arquivo workspace.yaml — título, formas próprias, tipos de seta, tipos de nota, desfechos, paleta e rótulos de metadado. Tudo o que diz respeito à **aparência** de uma modelagem mora num arquivo só: `model/workspace.yaml`. Ele é opcional — sem ele, o leitor desenha um diagrama C4 completo e convencional. O que estiver ali é somado **chave a chave** sobre os padrões do motor. Você sobrepõe o que quiser e herda o resto, então o arquivo pode ser tão curto quanto um título. ## O menor arquivo útil ```yaml title="model/workspace.yaml" version: 2 title: Reserva de Salas ``` `title` é o nome que aparece no alto da barra lateral. ## Rotular e colorir por metadado ```yaml title="model/workspace.yaml" metadata: dominio: label: Dominio color: true time: label: Time criticidade: label: Criticidade color: true ``` Este bloco faz duas coisas, e só duas: - **`label`** dá um nome legível ao filtro daquela chave; - **`color: true`** libera a chave na opção "colorir por" do leitor. **Não é preciso declarar uma chave para ela virar filtro.** Toda chave de metadado escrita no modelo já vira filtro sozinha, com a chave crua como rótulo. Este bloco só melhora o rótulo e libera a coloração. ## Tipos de seta ```yaml title="model/workspace.yaml" relationKinds: webhook: label: Webhook markerEnd: arrow-open dash: "4 3" color: "#0f766e" ``` Escrever isso faz `kind: webhook` passar a valer, sem nenhuma mudança de código. | Campo | O que faz | |---|---| | `label` | o nome legível, exibido na legenda | | `dash` | o tracejado, no formato `stroke-dasharray` do SVG. Ausente: linha cheia | | `color` | a cor da linha, em hexadecimal | | `width` | a espessura | | `markerStart`, `markerEnd` | a ponta de cada lado: `none`, `arrow-open`, `arrow-closed`, `arrow-half`, `circle`, `diamond` | | `animated` | anima a linha | Sobrepor um tipo que já existe é escrever a mesma chave — `sync:` com outra cor troca a cor de toda seta síncrona da modelagem. ## Formas ```yaml title="model/workspace.yaml" shapes: lambda: primitive: box stereotype: Function palette: container ``` | Campo | O que faz | |---|---| | `primitive` | o desenho base: `box`, `person`, `robot`, `browser`, `cylinder`, `queue`, `topic`, `component`, `class` | | `stereotype` | o texto entre guilemetes na caixa. É apresentação, e não carrega semântica | | `palette` | qual entrada da paleta a forma usa | | `outline` | `solid` ou `dashed` | | `size` | `standard`, `narrow`, `compact` ou `wide` | ## A paleta ```yaml title="model/workspace.yaml" palette: container: fill: "#438dd5" stroke: "#2f6ba3" text: "#ffffff" ``` A cor é uma **vaga**, e não um estereótipo: trocar a entrada `container` recolore todas as formas que apontam para ela, sem você saber quais são. As vagas de fábrica são `person`, `system`, `container`, `component`, `code`, `external` e `neutral`. ## Tipos de nota ```yaml title="model/workspace.yaml" noteKinds: decisao: label: Decisao color: "#0f766e" char: D ``` Escrever isso faz `kind: decisao` passar a valer. `char` é um caractere único desenhado no distintivo; `icon` é uma marca desenhada, por nome, e vence `char` quando os dois existem. ## Desfechos de fluxo ```yaml title="model/workspace.yaml" flowOutcomes: degradado: label: Degradado color: "#a16207" ``` Faz `outcome: degradado` passar a valer num caminho de fluxo. ## Alterar tudo isso por comando Você não precisa editar o arquivo à mão: ```sh cfour config show # a configuração efetiva cfour config title "Reserva de Salas" cfour config set noteKinds decisao --label Decisao --color "#0f766e" --char D cfour config set relationKinds webhook --label Webhook --dash "4 3" cfour config rm noteKinds decisao ``` `cfour config show` mostra os padrões do motor **com** o seu `workspace.yaml` por cima — ou seja, os valores que de fato valem naquela modelagem. ## A referência completa Todos os campos, com tipo e padrão, estão em [Configuração da aparência](doc:referencia/configuracao). ## Próximo passo [Várias modelagens, e federação](doc:modelando/modelagens). # Várias modelagens, e federação O registro cfour.yaml, quando criar a segunda modelagem, e como uma seta atravessa a fronteira entre duas delas por espelho. Uma **modelagem** é uma realidade inteira: propósito, público, glossário e convenções próprios. Um repositório pode ter uma só — o caso comum — ou várias. ## O registro `cfour.yaml`, na raiz do repositório, é o único caminho que a ferramenta procura subindo a árvore de diretórios. Tudo o mais é derivado dele. ```yaml title="cfour.yaml" version: 1 id: d8525e0d active: reservas modelagens: - id: reservas name: Reserva de Salas path: ./reservas - id: portaria name: Controle de Portaria path: ./portaria ``` | Campo | O que faz | |---|---| | `version` | a versão do formato do registro | | `id` | o identificador **deste registro**, e não de uma modelagem. Serve para uma máquina com várias chaves de publicação saber qual é a deste repositório. É opaco de propósito | | `active` | qual modelagem abre quando ninguém diz qual | | `modelagens` | a lista, cada uma com `id`, `name` e `path` | | `federacoes` | leituras conjuntas nomeadas — mais abaixo | O `path` aceita caminho relativo e `~`, então **uma modelagem pode morar fora deste repositório**. ## A identidade de uma modelagem ```yaml title="portaria/modelagem.yaml" version: 1 id: portaria name: Controle de Portaria status: active federacao: predio ``` | Campo | O que faz | |---|---| | `id` | tem de bater com o do registro | | `name` | o nome legível | | `description` | para que ela existe | | `status` | `active`, `reference` ou `archived`. **É o único campo daqui que muda o comportamento de um comando**: só `active` é publicado | | `federacao` | a leitura conjunta de que ela participa | ## Quando criar a segunda modelagem A pergunta certa não é de tamanho, é de **realidade**. Crie um [projeto](doc:modelando/projetos) novo quando: - é o mesmo vocabulário e o mesmo público; - as duas partes se leem juntas, no mesmo desenho; - a configuração de aparência é a mesma. Crie uma **modelagem** nova quando: - os glossários são diferentes, e a mesma palavra significa duas coisas; - os públicos são diferentes, e ninguém lê as duas ao mesmo tempo por padrão; - as duas devem ser **publicadas separadamente**, com controle de acesso próprio; - uma delas mora em outro repositório. ## A seta que atravessa duas modelagens **Não existe referência direta entre modelagens**, e nunca vai existir: cada uma é compilada e validada sozinha, então um identificador da outra seria uma referência solta exatamente no único momento em que daria para conferi-la. O que atravessa é um **espelho**: uma caixa local comum — quase sempre `shape: external` — que declara de quem ela é o reflexo. ```yaml title="portaria/model/portaria/elements.yaml" elements: - id: portaria name: Controle de Portaria shape: system description: Libera a catraca de quem tem reuniao marcada no predio. # O ESPELHO. Lido sozinho, e uma caixa externa comum. Lido junto da modelagem # `reservas`, ele se dissolve no elemento real de la — e a seta abaixo passa a # chegar naquele sistema, que o leitor pode entao abrir por dentro. - id: reserva-de-salas name: Reserva de Salas shape: external description: Sistema de outra equipe. Modelado por ela, nao por nos. bind: modelagem: reservas ref: reservas/reservas relations: - from: portaria to: reserva-de-salas kind: sync label: Confere a reserva do dia ``` Lida sozinha, a modelagem `portaria` desenha uma caixa externa tracejada, como qualquer sistema de fora. Lida **junto** com `reservas`, o espelho se dissolve no elemento real de lá — e a seta que apontava para a caixa local passa a chegar naquele sistema, que o leitor pode então abrir por dentro. O mesmo arquivo serve as duas leituras, sem ninguém escrever a integração duas vezes. ### Os campos de `bind` | Campo | Obrigatório | O que é | |---|---|---| | `modelagem` | sim | o identificador da modelagem que declara o elemento real | | `ref` | sim | o identificador **qualificado** (`/`) daquele elemento | `ref` tem de ser qualificado. Um identificador solto resolveria contra o projeto que o declara — e esse projeto é um fato desta árvore, não da outra. **Um espelho não tem interior** Uma caixa com `bind` não deve ter filhos. Numa leitura conjunta ela se dissolve no elemento real, e os filhos ficariam sem pai. O `cfour check` avisa quando isso acontece. ### O que é validado, e quando A forma de `bind` é validada sempre. **A existência do alvo, não**: a modelagem apontada, por definição, não está na árvore que está sendo carregada. Quem confere as duas pontas é: ```sh cfour check --all ``` Ele carrega todas as modelagens do registro e confere os espelhos — como **aviso**, e não erro, porque a outra modelagem tem outro dono e pode ter mudado sem avisar esta. ## Declarar uma leitura conjunta Uma federação é um apelido para o que o leitor também poderia marcar à mão. Ela é declarada nos **dois** lados: ```yaml title="cfour.yaml" federacoes: - id: predio name: Reservas + Portaria modelagens: [reservas, portaria] curador: reservas ``` ```yaml title="portaria/modelagem.yaml" federacao: predio ``` | Campo | O que faz | |---|---| | `id` | o identificador da leitura conjunta | | `name` | o rótulo exibido | | `modelagens` | os membros | | `curador` | de quem vale a configuração de aparência quando os membros discordam. Sem ele, vale a do primeiro | Os dois lados precisam concordar. Sem o par, a leitura conjunta aparece na plataforma e não na sua máquina, ou o contrário. Por comando: ```sh cfour federacao add predio --modelagem reservas --modelagem portaria --curador reservas cfour federacao list # diz se os dois lados concordam cfour federacao rm predio ``` A razão de a federação ser declarada em `modelagem.yaml`, e não só no registro, é que um registro conhece apenas o próprio repositório — e uma leitura conjunta pode atravessar repositórios. Do lado da plataforma, é esse campo que faz duas modelagens publicadas separadamente serem lidas juntas. ## Trabalhar com várias ```sh cfour modelagem list # as registradas cfour modelagem use portaria # troca a que abre por padrão cfour check --modelagem portaria # sem trocar a padrão cfour check --all # todas, e confere os espelhos ``` `C4_MODELAGEM` no ambiente faz o mesmo que `--modelagem`, para a sessão inteira. ## Próximo passo O modelo está completo. A seção [Linha de comando](doc:cli) mostra como trabalhar nele sem editar YAML à mão, e [Publicar](doc:publicar) leva o resultado para o ar. # Visão geral do cfour O que a ferramenta de linha de comando faz, as convenções comuns a todos os comandos, e onde encontrar cada família. `cfour` é a ferramenta de linha de comando do cfourdev. Ela é publicada no npm como **[`cfour-cli`](https://www.npmjs.com/package/cfour-cli)** — veja [Instalação](doc:comecando/instalacao). Ela faz cinco coisas: | | | |---|---| | **valida** | `cfour check` diz se o modelo carrega, e o que está errado | | **escreve** | `element`, `relation`, `diagram`, `flow`, `note`, `group`, `step`, `path`, `project`, `config` | | **consulta** | `find`, `refs`, e os `list` e `show` de cada família | | **desenha** | `cfour serve` abre o leitor na sua máquina | | **publica** | `login`, `push`, `status`, `keys` | ## O que ela nunca faz **Não reserializa o seu YAML.** Todo comando que escreve acha o ponto exato e emenda o texto. Comentários, alinhamento, aspas e fim de linha ficam como estavam — porque num repositório em que o YAML é a fonte legível da verdade, formatação não é detalhe, é o produto. **Não grava um resultado que não carrega.** A validação roda depois da gravação, e qualquer erro **novo** desfaz tudo. **Não remove algo de que alguém depende.** Um `rm` que quebraria referências recusa e lista quem aponta para lá. `--cascade` passa por cima, e `--yes` dispensa a confirmação. ## As convenções comuns Estas valem em **todo** comando que escreve: | Opção | O que faz | |---|---| | `--dry-run` | mostra o *patch* que seria aplicado, e não escreve nada | | `--json` | saída em JSON: o que mudou, ou o erro com código estável | | `--no-input` | nunca pergunta, mesmo num terminal. Recusa dizendo qual campo falta | | `--modelagem ` | em qual modelagem mexer, quando há mais de uma | | `--file ` | força o arquivo de destino, dentro do projeto | E estas valem na edição de qualquer coisa que já existe: | Opção | O que faz | |---|---| | `-- ` | define aquele campo | | `--clear ` | apaga aquele campo. Repetível | | `--tag` / `--tag-rm` | acrescenta ou tira **uma** etiqueta, sem reescrever o conjunto | | `--meta` / `--meta-rm` | o mesmo, para metadados | A última linha é o que dispensa ler o valor atual antes de mudar uma parte dele — e uma leitura desatualizada apagaria trabalho de outra pessoa. ## Escolher a modelagem Quando há mais de uma modelagem registrada, a ordem de decisão é: ```text --modelagem na linha de comando C4_MODELAGEM no ambiente active: no cfour.yaml a única que existe ``` Sem nada disso, e com mais de uma, o comando recusa e lista os identificadores. ## A ajuda embutida ```sh cfour help # a árvore inteira cfour help element add # um comando só cfour help formato # as regras do formato, sem precisar de rede cfour help --output json # a árvore inteira em JSON, para um agente ``` `cfour help formato` é a resposta curta para "como isso funciona mesmo?": ele imprime a anatomia dos arquivos, a derivação de níveis, a resolução de referências, a diferença entre selecionar e listar, e as garantias de escrita. ## As páginas desta seção - [Escrever no modelo](doc:cli/escrever) — criar, alterar, mover e remover - [Consultar o modelo](doc:cli/consultar) — achar coisas e entender o que existe - [Validar](doc:cli/validar) — `cfour check`, e o que ele reprova - [Ver os diagramas na sua máquina](doc:cli/ver) — `cfour serve` - [Usar em scripts e automação](doc:cli/automatizar) — JSON, códigos de saída, CI A lista completa de comandos, com toda opção, está em [Comandos do cfour](doc:referencia/cli). # Escrever no modelo Criar, alterar, mover e remover caixas, setas, diagramas, grupos, fluxos, notas e projetos pela linha de comando — com as garantias que a ferramenta dá ao escrever. Você pode editar o YAML à mão a qualquer momento; ele continua sendo a fonte da verdade. Os comandos existem porque escrever por comando é mais rápido, não esquece um campo obrigatório e recusa uma alteração que quebraria o modelo. ## As quatro garantias **O *diff* é pequeno.** Nada é reserializado: a ferramenta acha o ponto e emenda o texto. Comentários, alinhamento, aspas e fim de linha ficam como estavam. **Nada é escrito se o resultado não carregar.** A validação roda depois da gravação, e qualquer erro **novo** desfaz tudo. **Remover recusa quando alguém depende.** E lista quem. **`--dry-run` mostra o *patch* sem gravar**, em qualquer comando que escreve: ```sh cfour element add api --name "API de Reservas" --parent reservas --shape api --dry-run ``` ```text reservas/reservas ainda nao tem filhos; fica na pasta dele: --- /dev/null +++ reservas/containers.yaml @@ -0,0 +1,5 @@ +elements: + - id: api + name: API de Reservas + shape: api + parent: reservas --dry-run: nada foi escrito. ``` Repare que ele também **diz onde vai escrever** e por quê. Para forçar outro arquivo, use `--file`. ## Caixas ```sh cfour element add api --name "API de Reservas" --parent reservas --shape api \ --technology "Node.js" --description "Regras de reserva." \ --tag nucleo --meta dominio=reservas cfour element list --level container cfour element show api cfour element set api --technology "Node.js 22" --tag pci --meta-rm dominio cfour element mv api api-de-reservas # renomeia, e conserta quem apontava cfour element rm api ``` **Não existe `--level`.** Quem decide o nível é `--parent`, e mover uma caixa na árvore (`element set --parent `) é o que muda o nível dela. `element mv` renomeia e **conserta todas as referências** — pais, setas, escopos, seletores, participantes de fluxo, alvos de nota. `element rm` recusa quando alguém aponta para a caixa. `--cascade` passa por cima; `--yes` dispensa a confirmação. ## Setas ```sh cfour relation add painel api --kind sync --label "Chama" --meta protocolo=REST cfour relation list --from painel cfour relation show painel api cfour relation set painel api --label "Chama a API" cfour relation mv painel api async # troca o tipo cfour relation rm painel api ``` Quando há mais de uma seta entre as mesmas caixas, `--kind` desempata. `--inline` escreve a seta **dentro do documento da origem**, com o `from` implícito. ## Diagramas ```sh cfour diagram add containers --title "Reserva de Salas — Containers" \ --scope reservas --level container --neighbors 1 --relations auto cfour diagram list cfour diagram show containers cfour diagram show containers --resolved # o que ele MOSTRA, e por quê cfour diagram set containers --include tag:nucleo --exclude-rm ref:legado cfour diagram mv containers containers-v2 # renomeia, e move o layout junto cfour diagram rm containers ``` Na linha de comando, um critério se escreve `:`. Não há ambiguidade com um identificador porque identificador não aceita dois-pontos: ```sh --include level:context --include tag:nucleo --include children:reservas --include descendants:reservas:2 --include shape:queue --include project:shared --include meta:dominio=reservas --where level:container ``` ## Grupos ```sh cfour group add containers dados --name Dados --match-shape database --match-shape queue cfour group add containers experiencia --name "Experiencia" --orientation row --include painel cfour group add containers replicas --parent dados --match-tag replica cfour group list containers cfour group set containers dados --name "Persistencia" cfour group rm containers dados --cascade ``` Vários `--match-*` do **mesmo tipo** combinam com **ou**; de tipos diferentes, com **e**. Não há negação. ## Fluxos, passos e caminhos ```sh cfour flow add reservar colaborador painel --title "Reservar uma sala" \ --scope reservas --label "Escolhe sala e horario" cfour flow step reservar api --label "Pede a reserva" cfour step add reservar servico-de-reserva --label "Confirma a reserva" cfour step set reservar --n 3 --label "Confirma" cfour step mv reservar --n 4 --after 2 cfour step rm reservar --n 4 cfour path add reservar ocupada servico-de-reserva --name "Sala ocupada" \ --outcome failure --from conflito --label "Ja existe reserva nesse horario" cfour path list reservar cfour flow show reservar ``` `cfour flow step` é apelido de `cfour step add`. Um passo é endereçado pelo número que `cfour flow show` mostra (`--n`) ou pelo identificador dele (`--id`), quando tem um. `--path ` mexe num caminho alternativo em vez do principal. ## Notas ```sh cfour note add api "Ponto unico de falha para confirmar uma reserva." --kind risk cfour note add banco "Vale separar a replica?" --kind question --scope containers cfour note add containers "Congelado para a revisao de 2026-Q1" cfour note list --target api cfour note set api --text "..." --match "Ponto unico" cfour note rm api --match "Ponto unico" ``` O primeiro argumento é o alvo: uma caixa, ou um diagrama. Quando o mesmo identificador nomeia as duas coisas, `--target` e `--scope` desfazem a ambiguidade. `--match ` escolhe entre várias notas do mesmo alvo. ## Projetos ```sh cfour project add portaria --name "Controle de Portaria" --order 20 cfour project list cfour project set portaria --name "Portaria" cfour project rm portaria --cascade # apaga a pasta, mesmo com conteúdo ``` ## Configuração da aparência ```sh cfour config show cfour config title "Reserva de Salas" cfour config set noteKinds decisao --label Decisao --color "#0f766e" --char D cfour config set shapes lambda --primitive box --stereotype Function --palette container cfour config rm noteKinds decisao ``` `cfour config show` lista os valores que de fato valem naquela modelagem — os padrões do motor com o `workspace.yaml` por cima. É a resposta para "quais formas eu posso usar aqui?". ## O registro e as modelagens ```sh cfour modelagem list cfour modelagem add portaria --path ./portaria --name "Portaria" --ativa cfour modelagem set portaria --status reference --federacao predio cfour modelagem use portaria cfour modelagem show portaria cfour modelagem rm portaria # tira do registro; nunca apaga arquivo ``` ## A referência completa Cada comando, com todo argumento e toda opção: [Comandos do cfour](doc:referencia/cli). # Consultar o modelo Como achar o que existe no modelo, entender o contexto de uma caixa e descobrir o que quebra se algo sair. Um modelo com algumas centenas de caixas deixa de caber na cabeça. Estes comandos respondem sem abrir o navegador — e todos aceitam `--json`. ## `cfour find` — procurar por qualquer coisa ```sh cfour find loja-api ``` ```text element loja/loja-api id API da Loja relation loja/loja-api~sync~estoque/estoque-api id Reserva relation loja/loja-web~sync~loja/loja-api id Chama relation shared/erp-corporativo~batch~loja/loja-api id Carga de preços ``` Ele procura em identificador, nome, descrição, tecnologia, etiqueta, metadado e texto de nota. A terceira coluna diz **onde** o termo casou. `--tipo` restringe: `element`, `relation`, `note`, `diagram`, `flow` ou `project`. ```sh cfour find squad-espacos --tipo element ``` ## `cfour element show` — tudo sobre uma caixa ```sh cfour element show loja-api ``` ```text loja/loja-api nome API da Loja nivel container forma api parent loja/loja tecnologia .NET 8 descricao Regras de pedido — monta o carrinho, aplica preço e fecha a compra. tags core, pci meta.domain vendas meta.owner squad-checkout arquivo loja/elements/containers.yaml filhos loja/pedido-repository, loja/preco-client, ... 14 referencia(s): ... ``` Além dos campos escritos, ele mostra o que só o motor sabe: o nível derivado, os filhos, o arquivo de origem e tudo o que aponta para aquela caixa. ## `cfour refs` — o que quebra se isto sair ```sh cfour refs loja-api ``` ```text 14 referencia(s) a loja/loja-api: loja/pedido-repository tem loja/loja-api como parent loja/elements/checkout/componentes.yaml loja/loja-web -> loja/loja-api loja/relations/integracoes.yaml o diagrama "API da Loja — Componentes" detalha loja/loja-api loja/diagrams/componentes.yaml loja/loja-api é participante do fluxo "Fechar pedido" loja/flows/checkout.yaml ... ``` É a mesma pergunta que o `element rm` faz para decidir se recusa a remoção — com o arquivo de cada referência, para você ir direto ao ponto. ## Listar cada família ```sh cfour element list --level container --tag nucleo --projeto reservas cfour relation list --from painel --kind sync cfour diagram list --projeto reservas cfour flow list cfour note list --target api --scope containers cfour project list cfour group list containers cfour path list reservar ``` ## `--resolved`: o que um diagrama de fato mostra ```sh cfour diagram show containers --resolved ``` ```text reservas/containers (Reserva de Salas — Containers) nivel container fronteira Reserva de Salas 7 caixa(s), 6 seta(s) reservas/painel dentro children:reservas/reservas reservas/colaborador contexto neighbors: 1 ... reservas/api -> reservas/banco sync "Le e grava" ``` A terceira coluna diz **qual seletor trouxe cada caixa**. É a forma de responder "por que essa caixa está aqui" — e "por que essa não está". ## `cfour flow show` — a sequência inteira ```sh cfour flow show reservar ``` ```text passos: 1. reservas/colaborador -> reservas/painel Escolhe sala e horario 2. reservas/painel -> reservas/api Pede a reserva 3. reservas/api -> reservas/servico-de-reserva Confirma a reserva 4. reservas/servico-de-reserva -> reservas/repositorio-de-reservas ... [conflito] desvio "Sala ocupada" (failure) a partir de [conflito]: 3 passo(s) ``` O número à esquerda é o que `--n` endereça nos comandos de passo; o `[conflito]` é o identificador do passo, quando ele tem um. ## `cfour config show` — o vocabulário desta modelagem ```sh cfour config show ``` Lista formas, tipos de seta, tipos de nota, desfechos e paleta que valem **ali** — os padrões do motor com o `workspace.yaml` por cima. É a resposta para "quais valores eu posso escrever em `shape:`?". ## Consultar outra modelagem Todos aceitam `--modelagem `: ```sh cfour find api --modelagem portaria ``` # Validar O comando cfour check — o que ele reprova, o que ele apenas avisa, e como usá-lo no CI. ```sh cfour check ``` ```text Reserva de Salas (reservas) 11 elementos · 8 relações · 3 diagramas · 1 fluxos 0 erro(s), 0 aviso(s) ``` Ele carrega a modelagem inteira e relata tudo o que encontrou. **Sai com código 1 quando há erro**, e 0 quando há apenas avisos. ## Erro e aviso A diferença é uma só: **erro** significa que o modelo está errado; **aviso** significa que ele está incompleto ou provavelmente não é o que você quis. Um modelo com erro **não é publicado** — `cfour push` recusa. Um modelo com aviso publica normalmente. ### O que é erro | | | |---|---| | YAML inválido | o arquivo não é lido | | elemento sem `id`, ou com identificador inválido | | | dois elementos com o mesmo identificador no mesmo projeto | | | `parent`, `from`, `to`, `scope`, `subject`, `target` ou um seletor `ref` apontando para caixa inexistente | | | um ciclo de contenção | os membros são tratados como raiz | | um elemento que é pai de si mesmo | | | relação sem `from` ou sem `to` | | | nota sem texto, ou apontando para diagrama inexistente | | | diagrama ou fluxo duplicado, ou com identificador inválido | | | um fluxo cujo identificador já é de um diagrama | os dois dividem o mesmo espaço de nomes | | passo de fluxo sem `to`, ou sem `from` e sem passo anterior | | | caminho de fluxo desviando de um passo inexistente | | | `relations:` com uma forma que o formato não conhece | | | `groupBy: tag:` | não existe — veja [Grupos](doc:modelando/grupos) | | `bind` malformado, ou com `ref` não qualificado | | ### O que é aviso | | | |---|---| | forma, tipo de seta, tipo de nota ou desfecho desconhecido | desenha neutro | | `level:` declarado que discorda da árvore | a árvore vence | | **uma caixa com filhos e nenhum diagrama que a detalhe** | aquele conteúdo é inalcançável no leitor | | **um diagrama que não desenha nenhuma caixa** | nenhum seletor casou | | um passo de fluxo usando uma seta não declarada | o fluxo encontrou um buraco na estrutura | | um participante de fluxo que não aparece em passo nenhum | | | `relations:` citando um identificador de seta que não existe | | | uma nota sem `target` e sem `scope` | não aparece em lugar nenhum | | um elemento com `bind` que tem filhos | um espelho não tem interior | | um documento fora de um projeto | ignorado | | um `kind:` desconhecido | documento ignorado | Os dois avisos em negrito são os que mais evitam surpresa no navegador: eles existem porque o leitor nunca inventa uma visão, e porque um desenho vazio carrega sem reclamar. ## As opções ```sh cfour check --modelagem portaria # outra modelagem cfour check --all # todas as do registro, e confere os espelhos cfour check --root ./caminho/model # uma árvore avulsa, ignorando o registro cfour check --json # saída estruturada cfour check --inventory # + o inventário do modelo (implica --json) ``` `--all` é o único modo em que as duas pontas de um `bind` se encontram: ele carrega todas as modelagens juntas e confere se o alvo de cada espelho existe — como **aviso**, porque a outra modelagem tem outro dono. ## No CI ```yaml title=".github/workflows/arquitetura.yml" name: arquitetura on: [push, pull_request] jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm install -g cfour-cli - run: cfour check --all ``` Como o comando sai com código 1 em erro, isso já reprova o *pull request* que quebrar o modelo. Para publicar no mesmo fluxo, veja [Publicar a partir do CI](doc:publicar/ci). ## Quando algo dá errado Cada mensagem diz o arquivo e o campo. As causas mais comuns, com o que fazer em cada uma, estão em [Quando algo dá errado](doc:ajuda/problemas). # Ver os diagramas na sua máquina O comando cfour serve — o leitor rodando localmente sobre os arquivos do disco, e o que a arrumação manual das caixas grava. ```sh cfour serve ``` ```text cfour serve · http://127.0.0.1:5173 1 modelagem(ns) · arrastar salva em .layout/ da modelagem aberta Ctrl+C para parar ``` É o mesmo leitor da plataforma, servido da sua máquina, lendo os arquivos direto do disco. Salvar um `.yaml` e recarregar a página mostra o resultado. Nada é enviado para lugar nenhum, e nenhuma conta é necessária. ## As opções | Opção | O que faz | |---|---| | `--port ` | a porta. Padrão: `5173` | | `--host ` | escuta fora do laço local. Padrão: `127.0.0.1` | | `--modelagem ` | qual modelagem abre primeiro | ## Ele escuta só na sua máquina Por padrão o servidor se vincula a `127.0.0.1`, ou seja, ninguém na rede o alcança. Além disso ele confere dois cabeçalhos em toda requisição de dados: - **`Host`**, contra reassociação de DNS — uma página hostil que faça um nome dela resolver para `127.0.0.1` seria recusada, porque o `Host` enviado não é um dos permitidos; - **`Origin`**, contra requisição forjada de outro site. Qualquer um dos dois fora do esperado responde **403**. `--host 0.0.0.0` é uma decisão explícita de expor: use apenas numa rede em que você confia. O endereço que você passa em `--host` passa a ser aceito na conferência acima — senão a flag pediria uma coisa e o servidor recusaria exatamente ela. ## Arrastar caixas, e o que isso grava O leitor deixa você arrastar caixas, dobrar arestas, recolher grupos e trocar o estilo das linhas. Isso é gravado em arquivos JSON dentro de `.layout/`, no projeto correspondente: ```text model/reservas/.layout/containers.json ``` Duas coisas importantes: **A arrumação não é o modelo.** Apagar `.layout/` inteiro não perde informação de arquitetura nenhuma — só a arrumação. O desenho volta a ser calculado automaticamente. **A arrumação vale a pena versionar.** Ela é a metade comunicativa do trabalho: é o que faz o desenho ficar legível em vez de apenas correto. E é ela que viaja junto quando você publica, para quem lê no navegador ver o mesmo arranjo. Um fluxo **não tem** arquivo de arrumação: toda coordenada de uma sequência vem da ordem das colunas e da ordem das mensagens. ## O endereço de um diagrama A visão fica no *hash* da URL: ```text http://127.0.0.1:5173/#/// http://127.0.0.1:5173/#/reservas/reservas/containers ``` Um fluxo aceita dois parâmetros a mais: `?p=` escolhe o caminho alternativo e `?n=` o nível de leitura. É a mesma forma de endereço da plataforma — então um link que você copiou do `cfour serve` abre o mesmo desenho no site depois de publicar. ## Se ele reclamar que não achou o leitor ```text o viewer não foi encontrado em ... ``` Isso acontece quando a ferramenta está sendo executada a partir do repositório de desenvolvimento sem o leitor construído. Instalada pelo npm, ela traz o leitor dentro do pacote. ## O que dá para fazer no leitor Está em [Ler os diagramas publicados](doc:publicar/viewer) — a interface é a mesma, tirando o que depende de conta. # Usar em scripts e automação Saída em JSON, códigos de saída, o modo sem terminal e as variáveis de ambiente — o que a ferramenta garante para quem a chama de um script. A ferramenta foi feita para ser chamada por outra coisa além de uma pessoa: um *script*, um *job* de CI, um agente de IA. ## Códigos de saída | Código | Significado | |---|---| | `0` | deu certo. Avisos não mudam isso | | `1` | erro — modelo inválido, falta de credencial, recusa da plataforma | | `2` | uso errado do comando | ## `--json` Todo comando de consulta e todo comando que escreve aceitam `--json`. Nos comandos de escrita, a saída diz **o que mudou** — ou traz o erro com um código estável, que é o que permite um *script* reagir ao motivo em vez de ao texto da mensagem. ```sh cfour element list --json | jq -r '.[].id' cfour check --json cfour diagram show containers --resolved --json cfour keys --json cfour status --json ``` ## `--no-input` Sem terminal, a ferramenta nunca pergunta. Com terminal, ela pode perguntar — e `--no-input` desliga isso explicitamente: ```sh cfour push --no-input ``` **Todo campo tem uma opção**, então nada é impossível de fazer sem responder a uma pergunta. Quando falta algo, a recusa diz qual campo é. ## `--dry-run` Em qualquer comando que escreve, mostra o *patch* e não grava. Em `cfour push`, diz o destino e não envia nada. Vale como verificação num *pull request*: rodar o comando com `--dry-run` e comparar a saída é uma forma barata de revisar uma automação antes de soltá-la. ## O inventário do modelo ```sh cfour check --inventory ``` Devolve JSON com o resultado da validação **e** um inventário: as contagens por tipo, os projetos, os níveis, o vocabulário encontrado. É o que um agente lê para saber o tamanho e a forma do que está prestes a editar, sem carregar o modelo inteiro no contexto. ## A árvore de comandos, em JSON ```sh cfour help --output json ``` Devolve a árvore inteira: cada comando, com argumentos, opções, se cada opção é repetível, e exemplos. É a mesma declaração que despacha os comandos — então ela não pode divergir do que a ferramenta faz. É a forma correta de um agente descobrir a superfície da ferramenta em vez de adivinhar as opções. ## As regras do formato, sem rede ```sh cfour help formato cfour help formato --output json ``` Imprime a anatomia dos arquivos, a derivação dos níveis, a resolução de referências, a diferença entre selecionar e listar, as duas formas de um documento e as garantias de escrita. ## Variáveis de ambiente | Variável | Para quê | |---|---| | `CFOUR_KEY` | a chave de publicação. **Vence** o arquivo de credenciais | | `CFOUR_ENDPOINT` | outra instalação da plataforma | | `CFOUR_CONFIG_HOME` | onde gravar a chave | | `C4_MODELAGEM` | qual modelagem abrir | | `C4_ROOT` | uma árvore avulsa; vence tudo | Nenhum arquivo `.env` é lido automaticamente — não há *dotenv*, de propósito, para a precedência de `CFOUR_KEY` sobre o arquivo de credenciais não ser surpreendente. Para carregar um: ```sh set -a; . .env; set +a ``` A referência completa está em [Variáveis de ambiente](doc:referencia/variaveis). ## Autocompletar ```sh cfour completion bash # ou zsh, fish ``` ## Publicar de um *job* de CI Veja [Publicar a partir do CI](doc:publicar/ci) — é o caso de automação mais comum, e tem uma página própria. # Como a publicação funciona Do cfour push ao link que outra pessoa abre — o que é publicado, o que é uma ref, o que expira e o que a plataforma recusa. Publicar é enviar o resultado da compilação da sua modelagem para a plataforma, para que outras pessoas leiam os diagramas por um link, sem clonar nada e sem instalar nada. Publicar é **opcional**. O `cfour serve` funciona sem conta nenhuma. ## O que acontece num `cfour push` ```text 1. a ferramenta compila cada modelagem `status: active` 2. valida — qualquer ERRO interrompe tudo, e nada é enviado 3. resolve a chave de publicação, e diz o destino 4. pede à plataforma autorização para enviar 5. envia os arquivos compilados 6. avisa a plataforma de que terminou ``` O passo 2 é o que evita meio repositório publicado: **tudo** é compilado e validado antes de qualquer byte subir. Um site descrevendo um estado que nunca existiu seria pior que um push que falha. ## O que é publicado Cada modelagem vira um arquivo comprimido contendo: - o modelo inteiro — caixas, setas, diagramas, fluxos, notas, projetos; - a configuração de aparência já resolvida; - **a arrumação das caixas** que está em `.layout/`; - de onde ele veio: organização, repositório, *ref* e o *commit*. O caminho absoluto dos arquivos da sua máquina **não** viaja: cada item carrega o caminho relativo à raiz da modelagem. ## Antes do primeiro push 1. Crie uma conta em [app.cfourdev.com.br](https://app.cfourdev.com.br). 2. Você já tem uma organização pessoal. Para trabalho em equipe, crie uma organização de empresa — veja [Organizações](doc:plataforma/organizacoes). 3. Crie um **repositório** dentro dela. Ele é o destino do push, e o nome dele entra na URL pública. 4. Gere uma **chave de publicação** para aquele repositório — veja [Chaves de publicação](doc:plataforma/chaves). ```sh cfour login --key c4_xxxxxxxx_yyyyyyyyyyyy ``` Isso grava a chave em `$XDG_CONFIG_HOME/cfour/credentials` (modo `0600`) **e** liga este repositório a ela. A ligação importa porque uma máquina pode guardar várias chaves, cada uma publicando num repositório diferente: ```sh cfour keys # as chaves guardadas, e qual vale aqui cfour use outra # troca a deste repositório ``` ## Publicar ```sh cfour push --dry-run # diz o destino e não envia nada cfour push ``` ```text Reserva de Salas (reservas) · 11 elementos · 3 layouts · 8.4 KB publicado em o-a1b2c3d4e5f6/arquitetura · ref main ``` O que é publicado: **todas** as modelagens do registro cujo `status` é `active`. As demais são puladas, com o motivo dito na saída. `--all` inclui as puladas por status. Uma modelagem cujo `path` aponta para fora do repositório **nunca** é publicada, com ou sem `--all`. ## A *ref* Uma *ref* é o nome sob o qual a publicação vive. Por padrão é a *branch* do Git em que você está; `--ref ` escolhe outra. | | | |---|---| | a *ref* **padrão** do repositório | é o que um link sem parâmetro abre. **Publicar nela exige papel de admin** | | qualquer outra *ref* | é um **preview**, que qualquer membro publica, e que **expira sozinho em 30 dias** | A regra é a mesma que a equipe já tem no Git: qualquer um abre uma *branch*, e o que vai para a principal passa por quem responde pelo repositório. Um repositório aceita **10 refs vivas**. Como o preview expira sozinho, esse número só aperta se você publicar mais de dez em trinta dias. ## Ler o que foi publicado ```text https://app.cfourdev.com.br/// https://app.cfourdev.com.br///#/// ``` Um preview é lido acrescentando a *ref* como parâmetro de busca. Veja [Ler os diagramas publicados](doc:publicar/viewer). ```sh cfour status # o que está publicado neste repositório, ref por ref ``` ## O que a plataforma recusa, e por quê | Recusa | Razão | |---|---| | o modelo tem erro | nada é enviado; a saída lista cada erro com o arquivo | | a chave venceu | toda chave vence em 30, 90 ou 365 dias. O push avisa 14 dias antes | | publicar na *ref* padrão sem ser admin | a mensagem diz para publicar noutra *ref*, ou pedir a um admin | | a *ref* foi publicada por outra pessoa | um admin passa; outro membro publica em outra *ref* | | o repositório é privado e você não é admin | tornar um repositório privado revoga a escrita de quem não é admin | | a modelagem passou de 2 MB comprimidos | é o teto por modelagem | | o repositório passaria de 10 MB publicados | remova uma *ref* antiga | | o repositório já tem 10 refs vivas | espere um preview expirar, ou remova uma | | mais de 25 modelagens num push | é o teto por push | Os números estão todos em [Limites](doc:referencia/limites). ## Quem pode publicar é resolvido a cada push O papel de quem é dono da chave é consultado **no momento do push**, e não congelado quando a chave foi criada. Rebaixar ou remover alguém tira o alcance da chave dela no mesmo instante, sem ninguém precisar lembrar de revogá-la. ## Próximo passo - [Publicar a partir do CI](doc:publicar/ci) - [Ler os diagramas publicados](doc:publicar/viewer) - [Chaves de publicação](doc:plataforma/chaves) # Publicar a partir do CI Validar em todo pull request e publicar quando a branch principal muda — com exemplos para GitHub Actions e GitLab CI. O caso mais comum: **validar em todo *pull request*** e **publicar quando a *branch* principal muda**. Assim o modelo nunca fica atrás do código, e ninguém precisa lembrar de publicar. ## O que o CI precisa Uma variável de ambiente, e mais nada: | | | |---|---| | `CFOUR_KEY` | a chave de publicação, guardada como segredo do seu CI | `CFOUR_KEY` **vence** o arquivo de credenciais, e é por isso que ela é a forma certa em CI — não há ninguém para rodar `cfour login`. Sem terminal, a ferramenta nunca pergunta: todo campo tem uma opção, e a recusa diz qual falta. ## GitHub Actions ```yaml title=".github/workflows/arquitetura.yml" name: arquitetura on: push: branches: [main] pull_request: jobs: arquitetura: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm install -g cfour-cli # Vale em todo push e em todo pull request. Sai com código 1 em erro. - run: cfour check --all # Só na branch principal. - if: github.ref == 'refs/heads/main' run: cfour push --no-input env: CFOUR_KEY: ${{ secrets.CFOUR_KEY }} ``` ## GitLab CI ```yaml title=".gitlab-ci.yml" arquitetura: image: node:20 script: - npm install -g cfour-cli - cfour check --all - if [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then cfour push --no-input; fi variables: CFOUR_KEY: $CFOUR_KEY ``` ## Publicar um preview em todo *pull request* Um preview é qualquer *ref* que não seja a padrão do repositório. Ele expira sozinho em 30 dias, e **qualquer membro** pode publicá-lo — não é preciso ser admin. ```yaml - if: github.event_name == 'pull_request' run: cfour push --ref "pr-${{ github.event.number }}" --no-input env: CFOUR_KEY: ${{ secrets.CFOUR_KEY }} ``` O link para ler aquele preview é o endereço do repositório com a *ref* como parâmetro de busca: ```text https://app.cfourdev.com.br///?ref=pr-42 ``` Um repositório aceita 10 refs vivas ao mesmo tempo. Como o preview expira sozinho em 30 dias, isso só aperta num fluxo com mais de dez *pull requests* abertos por mês publicando diagramas — e aí vale publicar preview só quando o modelo mudou. ## Detalhes que evitam surpresa **A *ref* vem do Git.** Sem `--ref`, a ferramenta lê a *branch* atual. Um *checkout* em `HEAD` destacado — comum em CI — não tem *branch*, e a ferramenta recusa em vez de publicar sob um nome que não leva a lugar nenhum. Passe `--ref` explicitamente quando isso acontecer. **O *commit* também é carimbado.** Sem `--sha`, ele vem do Git. **Ensaie antes.** `cfour push --dry-run` compila, valida, diz o destino e não envia nada. Vale como passo de verificação num *pull request*. **A chave vence.** Toda chave expira em 30, 90 ou 365 dias, escolhidos na criação. O `cfour push` imprime um aviso nos **14 dias** anteriores ao vencimento, no log da execução — que é onde alguém já olha quando um *job* falha. Esse é o único canal: a plataforma não envia e-mail. **Guarde a chave como segredo.** Ela não deve ser versionada. O arquivo local que o `cfour login` escreve é para a sua máquina, não para o CI. ## Validar sem publicar Se você quer só a validação, `cfour check --all` basta — e nem precisa de chave. Esse é um bom primeiro passo: colocar o modelo sob CI antes de decidir publicar. # Ler os diagramas publicados Como abrir, navegar, filtrar, buscar e compartilhar um modelo publicado — e o que muda entre a leitura local e a hospedada. O leitor é a mesma página nos dois mundos: o que o `cfour serve` abre na sua máquina e o que a plataforma serve são o mesmo programa, lendo os mesmos dados. ## O endereço ```text https://app.cfourdev.com.br/// ``` Isso abre a *ref* padrão do repositório. Um preview é escolhido por parâmetro de busca: ```text https://app.cfourdev.com.br///?ref=pr-42 ``` E um desenho específico fica no *hash*: ```text #/// #/reservas/reservas/containers ``` Copiar a URL da barra de endereços e colar no chat é o suficiente para mandar alguém exatamente ao desenho que você está vendo. Num fluxo, `?p=` carrega o caminho alternativo e `?n=` o nível de leitura. ## A navegação **A árvore, à esquerda.** Os projetos, os diagramas e os fluxos, na ordem que `order` definiu e agrupados pelas pastas em que os arquivos estão. **Descer para dentro de uma caixa.** Uma caixa que tem um diagrama detalhando-a abre por ali. Quando há mais de um diagrama candidato, o leitor pergunta qual. **A trilha, no topo.** Mostra onde você está e volta um nível. **O seletor de nível.** Num fluxo, ele sobe ou desce a leitura da sequência: as mensagens entre duas caixas que, no nível escolhido, viraram a mesma caixa, desaparecem. ## Filtrar e buscar **A busca** encontra por identificador, nome, descrição, tecnologia, etiqueta, metadado e texto de nota. **Os filtros** são construídos a partir do modelo: toda etiqueta e toda chave de metadado viram um filtro, com os valores encontrados e a contagem de cada um. Não há nada a configurar — [escrever um metadado já cria o filtro](doc:modelando/etiquetas-e-metadados). **Colorir por** repinta o desenho segundo uma chave de metadado, quando aquela chave foi liberada para isso em [`workspace.yaml`](doc:modelando/aparencia). ## O que aparece numa caixa Ao selecionar uma caixa, o painel de detalhes mostra o que ela declara, o que o motor derivou (o nível, o pai, os filhos), as relações que entram e saem, as notas presas a ela, e os **links** — todo metadado cujo valor é uma URL. ## Arrumar o desenho Arrastar caixas, dobrar arestas, recolher grupos e trocar o estilo das linhas funciona nos dois mundos. A diferença é onde a arrumação é gravada: | | | |---|---| | `cfour serve` | em arquivos JSON dentro de `.layout/`, no seu repositório | | plataforma | na sua conta, como uma preferência sua sobre aquele repositório | Ou seja: no leitor hospedado, mexer no desenho **não** altera o que os outros veem. O arranjo que todo mundo vê é o que foi publicado a partir de `.layout/`. ## Exportar O leitor exporta o desenho como imagem, para colar numa apresentação ou num documento. ## Ler duas modelagens juntas Quando duas modelagens declaram a mesma [federação](doc:modelando/modelagens), o leitor oferece abri-las ao mesmo tempo. Nessa leitura, um **espelho** — a caixa externa com `bind` — se dissolve no elemento real da outra modelagem, e você pode descer para dentro dele. ## Quem consegue abrir Depende da visibilidade do repositório: | | | |---|---| | `org` | qualquer membro da organização, com qualquer papel | | `private` | apenas quem é admin ou dono | Não existe leitura anônima: todo acesso passa por login. Veja [Repositórios e visibilidade](doc:plataforma/repositorios). # Organizações Conta pessoal e organização de empresa, como criar uma, o identificador sorteado, os limites e o que acontece ao desativar. Uma **organização** é o dono de tudo na plataforma: repositórios, pessoas, chaves de publicação e domínios verificados. Todo endereço público começa com o identificador dela. ## Os dois tipos **Conta pessoal.** Criada sozinha na primeira vez que você entra. Você é a única pessoa dela, e ela existe para você publicar sem precisar de mais nada. **Organização de empresa.** Criada por você, com outras pessoas dentro, papéis e domínios verificados. As duas funcionam igual em tudo o que diz respeito a repositórios, chaves e publicação. As diferenças estão em [Pessoas, convites e papéis](doc:plataforma/pessoas). ## Criar uma organização de empresa Em **Conta → Nova organização**, você informa **um nome** — e nada mais. Duas condições: - **o seu e-mail precisa estar confirmado.** Sem isso, "eu sou da empresa tal" é uma afirmação, e não um fato; - **cada conta pode ser dona de no máximo 5 organizações ativas.** ## O identificador é sorteado, e ninguém o escolhe O identificador de uma organização é **gerado**: `o-` seguido de doze caracteres. ```text o-a1b2c3d4e5f6 ``` Você escolhe o **nome** — que é um rótulo e pode ser reescrito a qualquer momento —, mas não o identificador. A razão é direta. O identificador é o primeiro segmento de toda URL pública, e escolhê-lo num espaço de nomes compartilhado seria uma corrida: quem registrasse o nome de uma empresa primeiro publicaria para sempre num endereço que se apresenta como sendo dela. Não existe caminho para apagar uma organização e liberar o identificador, então a corrida não teria como ser desfeita. Sortear remove a corrida em vez de arbitrá-la. Isso também garante, por construção, que um identificador de organização nunca colida com um caminho que o site atende — nenhuma rota do produto começa com `o-`. ## O endereço público ```text https://app.cfourdev.com.br/// https://app.cfourdev.com.br/o-a1b2c3d4e5f6/arquitetura/ ``` ## Desativar uma organização Uma organização não é apagada; ela é **desativada**. A diferença importa nos dois sentidos. **O que a desativação desfaz:** - ninguém entra, ninguém publica; - o domínio verificado para de admitir gente; - um convite pendente deixa de valer; - ela some das listas — inclusive para quem é membro; - ela **libera a vaga** no limite de 5 organizações ativas. **O que a desativação não desfaz:** - o armazenamento continua ocupado, dentro dos [limites do repositório](doc:referencia/limites); - nada é apagado. **Reativar** devolve tudo. Só quem é dono reativa, e o limite de 5 organizações ativas é conferido de novo nesse momento — reativar produz uma organização ativa tanto quanto criar. Duas recusas que parecem arbitrárias e não são: - **uma conta pessoal não se desativa.** Ela é recriada na navegação seguinte, e a operação se desfaria sozinha; - **quem não é dono não vê a organização desativada em lugar nenhum** — nem para saber que ela existe. ## Os limites | | | |---|---| | organizações ativas por conta | 5 | | repositórios por organização | 50 | A lista completa está em [Limites](doc:referencia/limites). ## Próximo passo - [Pessoas, convites e papéis](doc:plataforma/pessoas) - [Repositórios e visibilidade](doc:plataforma/repositorios) # Pessoas, convites e papéis Os três papéis de uma organização, o que cada um pode fazer, como convidar e remover pessoas, e o que acontece com quem já é membro. ## Os três papéis | Papel | O que pode fazer | |---|---| | **reader** | ler os repositórios de visibilidade `org`; criar chaves de publicação para eles; publicar em *refs* de preview | | **admin** | tudo do reader, mais: criar e configurar repositórios, ler repositórios privados, publicar na *ref* padrão, ver e revogar as chaves de todo mundo, convidar e remover **readers** | | **owner** | tudo do admin, mais: mexer em papéis de admin e de dono, gerenciar domínios verificados, desativar e reativar a organização | A regra que separa admin de owner é uma só: **qualquer coisa que envolva um admin ou um dono, em qualquer direção, é só do dono.** Sem isso, um admin se promoveria a dono, ou removeria o dono, e o papel deixaria de significar algo. "Reader" não é só leitura: um reader **publica preview**. Isso é deliberado — qualquer pessoa da equipe deve poder abrir uma *branch* e mostrar o desenho dela. O que fica com o admin é a *ref* padrão, que é o que um link sem parâmetro abre. ## Convidar alguém Em **Conta → a organização → Membros**, informe o e-mail e o papel. | | | |---|---| | quem convida | um **admin** convida readers; um **dono** convida qualquer papel | | validade | **14 dias**. Uma oferta que ninguém aceitou deixa de ser uma oferta | | notificação | **a plataforma não envia e-mail.** Avise a pessoa por outro canal | | ao aceitar | é preciso ter o e-mail confirmado | O convite é endereçado a um e-mail, e é conferido contra o endereço confirmado de quem aceita — um convite dirigido a outra pessoa simplesmente não é encontrado. **Aceitar um convite nunca rebaixa um papel.** Se a pessoa já é membro com um papel maior, o convite não a diminui; se o papel do convite é maior, ele promove. ## Remover alguém Um admin remove readers; um dono remove qualquer um. Remover **não** apaga o que a pessoa publicou. E a plataforma **lembra** que ela foi removida: sem isso, numa organização com domínio verificado, a pessoa seria readmitida automaticamente na navegação seguinte — a remoção pareceria uma revogação e não seria. Para readmitir alguém que foi removido, convide de novo. Um convite é um ato deliberado de quem pode; o domínio não decide isso sozinho. **A última pessoa dona não pode ser removida nem rebaixada.** Domínios, papéis e convites são todos exclusivos do dono, então uma organização sem dono seria uma que ninguém consegue mais administrar — e não há suporte aqui para consertar isso. Promova outra pessoa antes. ## Entrar sem convite Uma organização pode verificar um domínio de e-mail. A partir daí, quem entra com um endereço daquele domínio **vira membro sozinho**, com papel `reader`. Isso está em [Domínios de e-mail verificados](doc:plataforma/dominios). ## Como saber por onde alguém entrou Cada filiação registra o caminho: `owner` (criou a organização), `invite` (aceitou um convite) ou `domain` (entrou pelo domínio verificado). É o que responde à pergunta "por que essa pessoa tem acesso". ## Sair de uma organização Você mesmo pode sair. A mesma proteção vale: a última pessoa dona não sai sem promover outra antes. # Domínios de e-mail verificados Como fazer com que todo mundo com um e-mail do seu domínio entre na organização sem convite — o registro DNS, a verificação e o que acontece ao remover. Um **domínio verificado** faz com que quem entra na plataforma com um e-mail daquele domínio vire membro da sua organização **automaticamente**, sem convite. É o mecanismo para uma empresa não precisar convidar pessoa por pessoa. Isto **não** é um domínio próprio para hospedar os diagramas. A plataforma não oferece endereço personalizado: todo modelo publicado é lido em `app.cfourdev.com.br///`. ## Quem pode Apenas quem é **dono** da organização. Quem decide quem mais pode entrar é o mesmo papel que decide papéis. ## O fluxo, em três passos ### 1. Declarar o domínio Em **Conta → a organização → Domínios**, informe o domínio, por exemplo `suaempresa.com.br`. A plataforma devolve um **token** de verificação e o registro DNS a publicar. ### 2. Publicar o registro TXT No provedor de DNS do seu domínio, crie: ```text nome: _cfour-verify.suaempresa.com.br tipo: TXT valor: cfour-verify= ``` O nome é sempre `_cfour-verify.` seguido do domínio declarado. O valor é sempre `cfour-verify=` seguido do token. ### 3. Verificar Volte à tela e peça a verificação. A plataforma resolve o TXT ao vivo, na hora — não é uma declaração num formulário, é uma checagem contra algo que só quem opera o domínio controla. Se o registro ainda não propagou, a resposta diz exatamente qual nome foi consultado e qual valor era esperado. Espere a propagação e tente de novo. ## O que acontece depois Quem entrar com um e-mail `@suaempresa.com.br` e tiver **o endereço confirmado** vira membro com papel **`reader`**. Três coisas que não acontecem, e vale saber: - **quem foi removido não volta.** A remoção é lembrada; a pessoa só entra de novo se for convidada; - **numa organização desativada, o domínio não admite ninguém**; - **um endereço não confirmado não entra.** Sem a confirmação, o domínio no e-mail é uma afirmação. ## Remover um domínio Remover impede que **mais alguém** entre por ali. Ele **não remove** quem já entrou: aquelas filiações são fatos próprios, com papel próprio, e revogar o acesso de todo mundo que um dia chegou por esse caminho seria uma ação bem maior do que "não usamos mais este domínio". Para tirar alguém, remova a pessoa — veja [Pessoas, convites e papéis](doc:plataforma/pessoas). ## Quando não usar Se o seu domínio de e-mail é compartilhado com gente de fora da empresa, ou se nem todo mundo da empresa deve ver a arquitetura, use convites. O domínio verificado é uma porta aberta para todos os endereços daquele domínio. # Repositórios e visibilidade O que é um repositório na plataforma, como criá-lo, a ref padrão, a visibilidade e o que acontece ao remover uma ref. Um **repositório** na plataforma é o destino de um `cfour push`. Ele corresponde, na prática, a um repositório Git seu — mas nada é lido do Git: quem envia é a ferramenta de linha de comando. O identificador dele entra na URL pública: ```text https://app.cfourdev.com.br/// ``` ## Criar Em **Conta → a organização → Repositórios**, informe o identificador. Ele usa letras minúsculas, números e hífen. **Quem cria é um admin.** E **o identificador não pode ser renomeado depois** — ele é o primeiro segmento de todo link compartilhado e o prefixo de todo objeto guardado. O **nome** exibido é livre e pode ser trocado a qualquer momento. Criar o repositório é um ato separado de gerar a chave, e o repositório tem de existir antes: uma chave é emitida **para um repositório**. Isso evita que um erro de digitação produza um repositório permanente que ninguém quis. ## A *ref* padrão Toda leitura sem parâmetro abre a *ref* padrão — normalmente `main`. | | | |---|---| | publicar na *ref* padrão | exige **admin** | | publicar em qualquer outra | qualquer membro; é um **preview**, e expira em 30 dias | Um admin pode trocar qual *ref* é a padrão. ## Visibilidade | | Quem lê | |---|---| | `org` | qualquer membro da organização, com qualquer papel | | `private` | apenas admin e dono | Não existe leitura anônima nem link público: todo acesso passa por login. **Tornar um repositório privado revoga também a escrita** de quem não é admin. Um repositório em que alguém perde a leitura e mantém a escrita seria a ordem inversa do que qualquer um espera — e a decisão é resolvida a cada push, contra o estado de agora. ## Remover uma *ref* Um admin remove uma *ref* publicada. Isso apaga os arquivos daquela publicação e libera o espaço contado no limite do repositório. Um preview expira sozinho em 30 dias; a *ref* padrão não expira. ## Remover o repositório Um admin remove o repositório inteiro, com tudo o que foi publicado nele. O identificador **não** volta a ficar disponível para reuso imediato de forma implícita — trate a remoção como definitiva. ## Os limites | | | |---|---| | repositórios por organização | 50 | | refs vivas por repositório | 10 | | tamanho de uma modelagem | 2 MB comprimidos | | total publicado por repositório | 10 MB | | modelagens por push | 25 | Veja [Limites](doc:referencia/limites). ## Ver o que está publicado Pela tela do repositório, ou pela linha de comando: ```sh cfour status cfour status --json ``` # Chaves de publicação Como criar, guardar, usar, rotacionar e revogar uma chave de publicação — e o que ela alcança. Uma **chave de publicação** é a credencial que a ferramenta de linha de comando usa para publicar. Ela não é uma senha de pessoa: ela pertence a **um repositório** e a quem a criou. ## A forma ```text c4__ ``` O identificador é público; o segredo é a metade que importa. A plataforma guarda apenas o *hash* do segredo — **o valor completo aparece uma única vez**, na tela que a cria. ## Criar Em **Conta → a organização → o repositório → Chaves de publicação**. | | | |---|---| | quem pode | **qualquer membro**, para um repositório de visibilidade `org` | | repositório privado | apenas admin e dono | | prazo | escolhido na criação: **30, 90 ou 365 dias**. Padrão: 90 | | quantas | até **10 chaves ativas por pessoa, por repositório** | Qualquer membro poder criar uma chave não é o mesmo que qualquer membro poder publicar qualquer coisa: [quem pode publicar em qual *ref*](doc:publicar) é decidido no momento do push. Se só o admin pudesse criar chaves, ele seria também o único capaz de distribuir o meio de publicar — e um colega querendo mostrar um rascunho teria de pedir emprestada uma credencial. Chave emprestada é chave que ninguém consegue revogar sem quebrar todo mundo. ## Guardar na sua máquina ```sh cfour login --key c4_xxxxxxxx_yyyyyyyyyyyy ``` ```text chave guardada como perfil "..." em ~/.config/cfour/credentials (modo 0600) publica em o-a1b2c3d4e5f6/arquitetura este repositorio passa a usar "..." ``` Duas coisas acontecem: a chave é gravada em `$XDG_CONFIG_HOME/cfour/credentials` (ou `~/.config/cfour/credentials`), com permissão `0600` dentro de uma pasta `0700`; e **este repositório passa a usar aquela chave**. ## Várias chaves na mesma máquina Uma máquina pode guardar chaves de vários repositórios. Cada uma carrega a organização e o repositório dela. ```sh cfour keys # as guardadas, e qual vale aqui cfour use outro-perfil # troca a deste repositório cfour use outro --default # troca o padrão da máquina cfour logout perfil # esquece uma cfour logout --all # esquece todas ``` Quem escolhe qual chave vale neste repositório é o campo `id:` do `cfour.yaml` — um identificador opaco do **registro**, e não de uma modelagem. Ele existe só para isso. A ordem de decisão: ```text --profile na linha de comando CFOUR_KEY no ambiente — vence o arquivo o vínculo deste repositório a chave default da máquina a única que existe ``` ## Em CI Exporte `CFOUR_KEY` como segredo do seu CI. Ela vence o arquivo de credenciais, e é a forma certa onde não há ninguém para rodar `cfour login`. Veja [Publicar a partir do CI](doc:publicar/ci). Não versione o arquivo de credenciais. ## Vencimento **Toda chave vence.** O prazo é escolhido na criação, entre 30, 90 e 365 dias. O `cfour push` imprime um aviso nos **14 dias** anteriores ao vencimento, no log da execução. Esse é o único canal — a plataforma não envia e-mail nenhum. É o lugar certo: em CI não há ninguém para ler um e-mail, e o log é onde a pessoa olha quando um *job* falha. Rotacionar é criar a nova, trocar o segredo no CI, confirmar um push, e revogar a antiga. ## Revogar | | | |---|---| | a sua própria chave | você mesmo, a qualquer momento | | a chave de outra pessoa | admin ou dono | Revogar a própria chave não é privilégio: é o que se faz no minuto em que se desconfia de um vazamento, e precisar achar um admin antes é como uma chave vazada passa a noite viva. A chave é marcada como revogada, e não apagada — é o que mantém respondível a pergunta "quem publicou isto, e com o quê". ## O que uma chave alcança **Um repositório, e não a organização.** Uma chave que vaze consegue sobrescrever os diagramas de um repositório, e não os de todos. **O papel de quem a criou, resolvido agora.** Rebaixar ou remover alguém tira o alcance da chave dela no mesmo instante. Se a pessoa deixou de ser membro, a chave para de funcionar. **Não sobrescreve o trabalho alheio.** Se outra pessoa publicou naquela *ref*, a sua chave é recusada com a mensagem dizendo para publicar em outra *ref* ou pedir a um admin. Um admin passa, porque é ele quem responde pelo repositório. ## Boas práticas - uma chave por lugar de uso: a sua máquina, o CI, e nada mais; - prazo curto para chave de máquina pessoal; 365 dias só quando a rotação está automatizada; - guardar em cofre de segredos, nunca no repositório; - revogar ao trocar de máquina. # O servidor MCP O que o servidor MCP do cfourdev acrescenta, como conectar um agente de IA, o que ele consegue ler, e quais são os limites. O cfourdev expõe a arquitetura **publicada** a agentes de IA através de um servidor MCP (*Model Context Protocol*) em: ```text https://api.cfourdev.com.br/mcp ``` ## O que ele acrescenta Um agente que ajuda a escrever código costuma ter acesso ao repositório em que está. O que ele não tem é o mapa: quais sistemas existem na organização, quem fala com quem, onde estão os riscos registrados, e o que quebra se um serviço sair. O servidor MCP responde a isso. Com ele, perguntas assim passam a ter resposta: - "o que depende da API de reservas?" - "quais riscos estão registrados no domínio de pagamentos?" - "que sistemas conversam com a agenda corporativa?" - "me mostre o fluxo de reserva, com os caminhos de falha" É **somente leitura**. Nada nele altera modelo nenhum — quem escreve é a [linha de comando](doc:cli/escrever). ## O que ele lê Ele lê o que foi **publicado** com `cfour push`, no escopo das organizações de que você é membro, respeitando a visibilidade de cada repositório. Um repositório privado não aparece para quem é `reader`, nem numa tela nem numa busca — é a mesma regra, num lugar só. Ele **não** lê os arquivos da sua máquina, e não enxerga uma modelagem que nunca foi publicada. ## Conectar O servidor fala HTTP e autentica por OAuth 2.1 com PKCE. A descoberta é padrão: um cliente sem credencial recebe 401 com o endereço do metadado do recurso, e a partir dali encontra o servidor de autorização sozinho. Falta uma peça, e é preciso saber disso: **não há registro dinâmico de cliente**. O `client_id` tem de chegar ao agente por configuração. ```text client_id 5849jmr7iticd3fc2ikcfrtec8 porta de retorno 33418 ``` O `client_id` é **público por desenho** — um cliente OAuth público não tem segredo — e por isso pode ir para um arquivo versionado. ### Claude Code ```sh claude mcp add --transport http --client-id 5849jmr7iticd3fc2ikcfrtec8 \ --callback-port 33418 cfourdev https://api.cfourdev.com.br/mcp ``` Isso grava a configuração no `.mcp.json` do projeto: ```json title=".mcp.json" { "mcpServers": { "cfourdev": { "type": "http", "url": "https://api.cfourdev.com.br/mcp", "oauth": { "clientId": "5849jmr7iticd3fc2ikcfrtec8", "callbackPort": 33418 } } } } ``` Na primeira chamada, o agente abre a tela de login no navegador. A sessão vale uma hora e é renovada sozinha. ### Outros clientes Qualquer cliente MCP com transporte HTTP e OAuth serve, desde que aceite um `client_id` por configuração e permita fixar a porta do laço local de retorno. **A porta de retorno importa.** A lista de endereços de retorno aceitos é mantida à mão, e o servidor de autorização casa a URL **exata** — esquema, host, porta e caminho. Hoje ela aceita `http://localhost:33418/callback` e `http://127.0.0.1:33418/callback`, além das variantes com `/oauth/callback`, e os endereços de retorno do Claude na web. Um cliente que abra o laço local numa porta aleatória não conecta. ## Duas coisas para saber antes de perguntar **Comece pelo catálogo.** `cfour_catalog` diz o que existe e o que você pode ler: as organizações, os repositórios e as modelagens publicadas em cada um, com o estado de indexação de cada uma. **Descubra o vocabulário antes de filtrar.** `cfour_facets` lista as etiquetas, as chaves e valores de metadado, e os tipos de nota que existem numa modelagem. Quem modela escolhe as palavras, e elas não são as mesmas em duas modelagens — filtrar por `risco` numa modelagem que usa `risk` devolve zero, e zero parece uma resposta. ## Toda resposta diz de quando ela é Cada resposta carrega a procedência: o repositório, a modelagem, a *ref*, quando o modelo foi compilado e quando a cópia consultada foi escrita. Isso existe porque a consulta não lê o arquivo publicado diretamente — ela lê uma cópia preparada na publicação, para responder rápido sem abrir megabytes por pergunta. Nenhuma resposta pode se apresentar mais fresca do que é, e uma modelagem que ainda não foi indexada é dita como tal em vez de aparecer como "nenhum resultado". ## Os limites | | | |---|---| | resultados por chamada | 20 por padrão, 100 no máximo | | tamanho de uma chamada | 32 KB | | ritmo | 4 requisições por segundo, com rajada de 8 | | tamanho indexável de uma modelagem | 1 MB comprimido, e 5.000 itens | | leitura por consulta | 10.000 itens. Acima disso a consulta **exige** um recorte por `repo` ou `modelagem` | Uma modelagem acima do teto de indexação **publica normalmente** — ela só não é respondida pelo MCP, e o catálogo diz isso. ## O que não existe - **escrita.** Nenhuma ferramenta altera modelo; - **registro dinâmico de cliente.** O `client_id` vai por configuração; - **fluxo de eventos.** O servidor atende `POST`. Um `GET /mcp` **autenticado** responde 405 dizendo isso; sem credencial ele responde 401 antes disso, porque quem recusa é a borda e não a aplicação; - **acesso a modelagem não publicada.** ## Próximo passo - [As ferramentas do MCP](doc:agentes/ferramentas) — as dez, com exemplos - [Linha de comando ou MCP?](doc:agentes/cli-ou-mcp) — quando usar cada uma - [O plugin do Claude Code](doc:agentes/plugin) — para **escrever** o modelo conversando # As ferramentas do MCP As dez ferramentas que o servidor MCP do cfourdev expõe, o que cada uma responde, e a ordem em que vale a pena chamá-las. São dez ferramentas, todas de leitura. A referência com os parâmetros exatos está em [Ferramentas do MCP](doc:referencia/mcp); esta página explica **para que serve cada uma**. ## As três de recorte, que toda ferramenta aceita | Parâmetro | O que faz | |---|---| | `org` | a organização. Obrigatório se você é membro de mais de uma | | `repo` | restringe a um repositório | | `modelagem` | restringe a uma modelagem | Sem recorte, a pergunta vale para tudo o que você pode ler. ## Por onde começar **`cfour_catalog`** — o que existe e o que você pode ler: as organizações, os repositórios visíveis e as modelagens publicadas em cada um, com o estado de indexação de cada uma. É a primeira chamada de qualquer sessão. Sem ela, um agente não sabe nem quais organizações nomear no parâmetro `org`. **`cfour_facets`** — o vocabulário de uma modelagem: as etiquetas com contagem, as chaves e valores de metadado, os tipos de nota, os níveis, as formas, os tipos de relação e os projetos. Chame **antes** de filtrar por um valor que você não viu. Quem modela escolhe as palavras. ## Achar e entender **`cfour_search`** — procura por texto livre, por critério, ou pelos dois. O texto casa, sem acento e sem caixa, em identificador, nome, descrição, tecnologia, etiqueta, metadado, **texto de nota**, rótulo de passo de fluxo e nome de projeto. O critério usa a mesma sintaxe do formato, e vários separados por espaço combinam com **e**: ```text tag:nucleo level:container meta:dominio=reservas descendants:reservas:2 shape:database project:shared ``` **`cfour_get`** — tudo o que se sabe sobre uma caixa, pelo identificador: os campos dela **mais** o contexto que só o motor monta — nível, pai, a trilha de ancestrais, filhos, as relações que entram e saem com o nome da outra ponta, as notas agrupadas por tipo, os diagramas que a mostram, os fluxos que passam por ela, e os links. **`cfour_tree`** — a árvore de contenção: o mapa que se lê primeiro. Cada caixa com o nível C4 dela e a forma. ## Entender dependências **`cfour_references`** — quem aponta para uma caixa, e por qual vínculo: filho, relação, escopo ou seletor de diagrama, assunto, participante ou passo de fluxo, nota. É a resposta a "o que deixa de fazer sentido se isto sumir" — a mesma pergunta que a linha de comando faz para recusar uma remoção. **`cfour_neighbors`** — com quem uma caixa conversa: o que é alcançável por relações, até três saltos, com o rótulo de cada seta. Aceita direção (`entram`, `saem`, `ambas`). `references` responde "quem depende disto"; `neighbors` responde "com quem isto fala". São perguntas diferentes. ## Riscos e decisões **`cfour_notes`** — as notas, filtradas por tipo. **Risco e decisão são notas**, e não entidades próprias: um risco é uma nota com `kind: risk`, e o vocabulário de tipos é aberto, declarado por quem modela. A resposta sempre inclui **os tipos que de fato existem** naquela modelagem — é o que impede um agente de concluir que não há riscos porque chutou a palavra errada. ## Ver um desenho **`cfour_diagram`** — a especificação de um diagrama **mais o que ele de fato mostra**. Isso importa porque um diagrama seleciona e não lista: `include: {tag: nucleo}` é uma regra, e a especificação sozinha não diz quais caixas aparecem. A resposta traz a resolução — membros, setas (cada uma com as relações que representa) e grupos. **`cfour_flow`** — um caso de uso contado como sequência: participantes, passos e caminhos alternativos com o desfecho de cada um. Repare em `declared: false` num passo: significa que o fluxo descreve uma conversa para a qual **não existe relação declarada** no modelo. Isso é o fluxo auditando a estrutura, e costuma ser a coisa mais interessante da resposta. ## Uma ordem que funciona ```text 1. cfour_catalog o que existe 2. cfour_facets o vocabulário desta modelagem 3. cfour_tree o mapa 4. cfour_search achar a caixa de que se fala 5. cfour_get tudo sobre ela 6. cfour_references o que depende dela ``` ## Procedência Toda resposta carrega de onde ela veio e de quando: repositório, modelagem, *ref*, quando o modelo foi compilado e quando a cópia consultada foi escrita. Modelagens que existem e não estão indexadas são listadas à parte, em vez de sumirem em silêncio. ## Limites das respostas `limite` vale **20 por padrão e 100 no máximo**. O recurso escasso do outro lado é a janela de contexto do agente, e não o servidor. Quando um recorte tem mais de **10.000 itens indexados**, a consulta exige um recorte por `repo` ou `modelagem` em vez de ler tudo, e a mensagem diz isso. # O plugin do Claude Code Como modelar a arquitetura conversando — o plugin cfour para o Claude Code, o que ele faz, como instalar e o que ele grava no repositório. Existe um plugin oficial para o [Claude Code](https://claude.com/claude-code) que conduz a modelagem por conversa: você descreve o sistema em português, e ele traduz isso em comandos do `cfour`, que escrevem no YAML. Ele mora em [github.com/evandrobreis/cfourdev-claude](https://github.com/evandrobreis/cfourdev-claude). ## O que muda com ele Sem o plugin, você aprende o formato e escreve — à mão ou por comando. Com o plugin, o trabalho começa por uma conversa: ele pergunta o que o sistema faz, quem o usa, com o que ele integra; propõe como aquilo vira caixas e setas; e executa os comandos, mostrando o que mudou. O que ele faz, em linhas gerais: - **prepara o repositório** — confere se a ferramenta está instalada, se existe um `cfour.yaml`, se o modelo atual está válido, e explica o que falta; - **entende o software antes de desenhar** — por rodadas curtas de perguntas e pela leitura das fontes que já existem no repositório; - **traduz pedido em comando** — cria e altera elementos, relações, notas, diagramas, fluxos e projetos, valida com `cfour check`, abre o leitor e publica; - **descobre a ferramenta em vez de adivinhar** — ele lê a árvore de comandos do próprio `cfour` instalado, então não inventa opção que não existe; - **retoma o trabalho** — carrega o que ficou decidido numa sessão anterior, aponta divergências entre o que ele lembra e o que está no disco, e registra o que virou fato ao encerrar. O que ele **não** faz: decidir arquitetura por inferência. Ele pergunta. ## Instalar Dentro do Claude Code: ```text /plugin marketplace add evandrobreis/cfourdev-claude /plugin install cfour@cfourdev ``` Para que todo mundo que clonar um repositório receba o plugin sem digitar nada, declare isso no `.claude/settings.json` do repositório: ```json title=".claude/settings.json" { "extraKnownMarketplaces": { "cfourdev": { "source": { "source": "github", "repo": "evandrobreis/cfourdev-claude" } } }, "enabledPlugins": { "cfour@cfourdev": true } } ``` Os comandos que o plugin acrescenta aparecem na ajuda do próprio Claude Code depois da instalação — é de lá que vem a lista atual, e não daqui: o plugin tem ciclo de vida próprio. ## Pré-requisitos - o Claude Code instalado; - a ferramenta `cfour` instalada — [Instalação](doc:comecando/instalacao). O plugin não a substitui: ele a **usa**; - um repositório onde a modelagem vai morar. ## O que ele grava no seu repositório Além do modelo — que é o mesmo YAML de sempre — o plugin mantém uma **memória** da modelagem em: ```text .claude/cfour/history// ``` É onde ficam o contexto do software apurado nas conversas, as decisões tomadas e o estado da última sessão. Isso é dado, e não código: vale versionar, porque é o que faz a próxima sessão continuar de onde a anterior parou — inclusive para outra pessoa da equipe. A memória é indexada pelo **identificador** da modelagem, e não pela pasta dela. Uma consequência: mover a modelagem para outro repositório move o modelo, e a memória tem de ser levada junto deliberadamente. ## Plugin, linha de comando e MCP São três coisas diferentes, e as três convivem: | | | |---|---| | **o plugin** | escreve o modelo **conversando**, na sua máquina | | **o `cfour`** | escreve o modelo por **comando**, na sua máquina, e publica | | **o [servidor MCP](doc:agentes)** | **lê** o modelo publicado, de qualquer lugar | O plugin é uma camada sobre a linha de comando: tudo o que ele faz, você também consegue fazer digitando. O MCP é outra coisa — ele responde perguntas sobre o que já está publicado, e não escreve nada. # Linha de comando ou MCP? As duas interfaces do cfourdev para automação, o que cada uma faz e não faz, e como decidir qual usar. O cfourdev tem duas interfaces programáveis, e elas não competem: uma **escreve**, a outra **lê o que foi publicado**. ## A diferença, em uma frase | | | |---|---| | **`cfour`** | trabalha no modelo que está **no disco**, e escreve nele | | **servidor MCP** | consulta o modelo que está **publicado**, e nunca escreve | ## Lado a lado | Necessidade | `cfour` | MCP | |---|---|---| | criar ou alterar caixas, setas, diagramas, fluxos, notas | **sim** | não | | validar o modelo | **sim** (`cfour check`) | não | | publicar | **sim** (`cfour push`) | não | | desenhar na sua máquina | **sim** (`cfour serve`) | não | | gerenciar organização, chaves, membros | não — isso é pela tela da plataforma | não | | buscar no modelo | sim, no do disco | **sim**, no publicado, em toda a organização | | ver o que um diagrama de fato mostra | sim (`--resolved`) | **sim** (`cfour_diagram`) | | descobrir dependências de uma caixa | sim (`cfour refs`) | **sim** (`cfour_references`) | | ler riscos e decisões | sim (`cfour note list`) | **sim** (`cfour_notes`) | | atravessar vários repositórios de uma vez | não | **sim** | | rodar em CI | **sim** | não faz sentido | | ser usado por um agente sem acesso ao seu disco | não | **sim** | ## Como decidir **Você está no repositório e quer mudar o modelo** → `cfour`. Um agente com acesso ao terminal também usa a linha de comando, e é assim que ele escreve: com `--json` e `--dry-run`, que existem exatamente para isso. **Você quer que um agente entenda a arquitetura da empresa** → MCP. Ele vê tudo o que foi publicado nas organizações de que a pessoa é membro, atravessando repositórios, sem precisar de um clone. **Você está no CI** → `cfour`. `check` reprova o *pull request*; `push` publica. **Você está numa conversa, e quer que o modelo mude** → o [plugin do Claude Code](doc:agentes/plugin), que traduz o pedido em comandos da linha de comando. ## Por que a escrita não está no MCP Escrever exige o disco. O motor de escrita acha o ponto exato dentro do seu arquivo e emenda o texto, preservando comentário, alinhamento e fim de linha — e o resultado é um *diff* que alguém revisa num *pull request*. Um servidor remoto que escrevesse no modelo escreveria no que foi **publicado**, que é o resultado da compilação. O caminho de volta até o seu arquivo não existe, e o *diff* — que é a razão de o modelo estar no Git — não aconteceria. ## Como um agente descobre a linha de comando Sem adivinhar as opções: ```sh cfour help --output json # a árvore inteira: comandos, argumentos, opções, exemplos cfour help formato # as regras do formato cfour check --inventory # o que existe no modelo, em JSON ``` E, para escrever com segurança: ```sh cfour element add ... --dry-run --json # mostra o patch, não grava cfour element add ... --json --no-input # grava, e devolve o que mudou ou o erro ``` # llms.txt Os dois arquivos que um agente busca sozinho para aprender o formato do cfourdev, o que eles contêm e como consumi-los. Esta documentação também é publicada em dois arquivos de texto, na raiz do site, seguindo o padrão [llmstxt.org](https://llmstxt.org): | | | |---|---| | [`/llms.txt`](https://docs.cfourdev.com.br/llms.txt) | o índice: o que este site é, e o que há nele | | [`/llms-full.txt`](https://docs.cfourdev.com.br/llms-full.txt) | a documentação inteira num arquivo só | ## Para que servem Um agente de IA que precisa **escrever** YAML do cfourdev tem duas possibilidades: navegar por dezenas de páginas HTML, ou buscar um endereço e ler o contrato inteiro de uma vez. O `llms.txt` existe porque é um endereço que se procura **sem perguntar**: o padrão diz que ele fica na raiz do site, então nenhum agente precisa que alguém conte onde ele está. O `llms-full.txt` é o conteúdo. São dois arquivos e não um porque o consumidor é diferente: o índice tem alguns quilobytes e responde "o que é este site"; o completo é a documentação inteira, e só vale a pena buscar depois de saber disso. ## O que tem dentro O `llms-full.txt` é Markdown puro, montado a partir das **mesmas páginas** deste site — não é uma segunda descrição escrita à parte. Uma cópia à mão seria a descrição que envelhece calada. Cada documento entra como um bloco marcado, e o cabeçalho do arquivo diz a versão do formato, quantos documentos ele traz e o *hash* do conteúdo. O **`conteudo-sha256`** existe para um consumidor saber que a documentação mudou sem baixar tudo de novo. Por isso o cabeçalho **não tem data**: um carimbo de tempo faria toda reconstrução parecer uma mudança. ## Como consumir ```sh curl https://docs.cfourdev.com.br/llms.txt curl https://docs.cfourdev.com.br/llms-full.txt ``` Eles são servidos como `text/plain`, com cache curto. ## O que **não** está neles O modelo da sua arquitetura. Estes arquivos são a documentação do **formato e da ferramenta** — a metade "como se escreve isto". A outra metade — "o que está escrito no nosso modelo" — é o [servidor MCP](doc:agentes), que responde sobre o que a sua organização publicou. Um agente bem equipado usa os dois: o `llms-full.txt` para saber escrever, e o MCP para saber o que já existe. # Campos do YAML Todo campo de todo documento do formato, com tipo, obrigatoriedade, valor padrão e o que acontece quando ele falta. Referência para consulta rápida. Para aprender o formato, comece em [A anatomia de uma modelagem](doc:modelando/anatomia). ## Os documentos Um arquivo `.yaml` do modelo declara o que carrega de duas formas, que podem conviver no mesmo arquivo separadas por `---`: - **singular** — `kind: ` no topo, e os campos logo abaixo; - **coleção** — sem `kind`, com as listas `elements:`, `relations:`, `diagrams:`, `flows:`, `notes:`. Valores de `kind`: `project`, `element`, `relation`, `diagram`, `flow`, `note`, `folder`. Um `kind` desconhecido faz o documento ser ignorado, com aviso. ## `cfour.yaml` — o registro | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `version` | número | não | — | a versão do formato do registro | | `id` | texto | não | — | o identificador **deste registro**. Serve para escolher a chave de publicação deste repositório | | `active` | texto | não | — | qual modelagem abre quando ninguém diz qual | | `modelagens` | lista | sim | — | as modelagens registradas | | `modelagens[].id` | texto | sim | — | o identificador | | `modelagens[].name` | texto | não | o `id` | o nome legível; perde para o `name` do `modelagem.yaml` | | `modelagens[].path` | texto | sim | — | a pasta da modelagem. Aceita relativo e `~` | | `federacoes` | lista | não | — | leituras conjuntas nomeadas | | `federacoes[].id` | texto | sim | — | o identificador | | `federacoes[].name` | texto | não | o `id` | o rótulo | | `federacoes[].modelagens` | lista de texto | sim | — | os membros | | `federacoes[].curador` | texto | não | o primeiro membro | de quem vale a configuração | Um `id` de modelagem repetido é erro. Uma federação citando modelagem não registrada é aviso. ## `modelagem.yaml` — a identidade | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `version` | número | não | — | | | `id` | texto | não | — | tem de bater com o do registro; discordar é aviso | | `name` | texto | não | o do registro | o nome legível | | `description` | texto | não | — | para que ela existe | | `status` | texto | não | `active` | `active`, `reference` ou `archived`. **Só `active` é publicado** | | `federacao` | texto | não | — | a leitura conjunta de que ela participa | ## `project.yaml` — um projeto | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `id` | texto | não | o nome da pasta | discordar da pasta é aviso, e **a pasta vence** | | `name` | texto | não | o `id` | o nome exibido | | `order` | número | não | 500 | a posição entre os projetos | | `tags` | lista de texto | não | `[]` | | | `meta` | mapa | não | `{}` | | ## `folder.yaml` — o nome de uma pasta | Campo | Tipo | Obrigatório | O que faz | |---|---|---|---| | `name` | texto | não | o nome da pasta na árvore de navegação | | `order` | número | não | a posição dela | ## Elemento | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `id` | texto | **sim** | — | `[A-Za-z0-9][A-Za-z0-9._-]*`. A barra é reservada | | `name` | texto | não | o `id` | | | `shape` | texto | não | `system` | chave em `shapes`. Desconhecida: caixa neutra + aviso | | `parent` | referência | não | — | **decide o nível C4** | | `description` | texto | não | — | | | `technology` | texto | não | — | | | `level` | texto | não | derivado | `context`, `container`, `component`, `code`. Discordar da árvore é aviso, e a árvore vence | | `tags` | lista de texto | não | `[]` | | | `meta` | mapa | não | `{}` | valores de texto, número ou booleano | | `bind` | mapa | não | — | espelho de um elemento de outra modelagem | | `bind.modelagem` | texto | **sim**, dentro de `bind` | — | | | `bind.ref` | texto | **sim**, dentro de `bind` | — | tem de ser **qualificado** | | `relations` | lista | não | — | só em documento singular; `from` implícito | | `notes` | lista | não | — | só em documento singular; `target` implícito | ## Relação | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `from` | referência | **sim** | — | implícito num documento singular de elemento | | `to` | referência | **sim** | — | | | `kind` | texto | não | `sync` | chave em `relationKinds`. Desconhecida: linha cheia + aviso | | `label` | texto | não | — | | | `description` | texto | não | — | | | `bidirectional` | booleano | não | — | `true` põe ponta também na origem | | `route` | texto | não | o padrão do diagrama | `straight`, `orthogonal`, `bezier` | | `tags` | lista de texto | não | `[]` | | | `meta` | mapa | não | `{}` | | | `id` | texto | não | `~~` | duplicatas recebem `#2`, `#3`... | Uma relação de uma caixa para ela mesma é ignorada, com aviso. ## Diagrama | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `id` | texto | não | o nome do arquivo | | | `title` | texto | não | o `id` | | | `level` | texto | não | derivado | em que nível o leitor o abre | | `scope` | referência | não | — | a caixa detalhada; vira a fronteira | | `order` | número | não | 500 | | | `include` | lista de seletores | não | `[{children: scope}]` quando há `scope` | quem entra | | `exclude` | lista de seletores | não | — | quem sai | | `where` | seletor de predicado | não | — | filtra o que `include` trouxe | | `neighbors` | número | não | 0 | saltos de contexto mudo | | `relations` | vários | não | `auto` | `auto`, `none`, lista de ids, `{exclude: [ids]}` | | `groups` | lista | não | — | grupos escritos à mão | | `groupBy` | texto | não | — | `meta.`, `level`, `shape`, `project` | | `subject` | referência ou lista | não | — | quem está em foco | | `tags` | lista de texto | não | `[]` | | | `meta` | mapa | não | `{}` | | | `notes` | lista | não | — | notas confinadas a este diagrama | `groupBy: tag:` **não existe**, e escrevê-lo é erro. ### Grupo | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `id` | texto | **sim** | — | único dentro do diagrama | | `name` | texto | não | o `id` | | | `orientation` | texto | não | empilha | `row` ou `column` | | `include` | lista de seletores | não | — | | | `match` | seletor de predicado | não | — | atalho para um `include` de uma cláusula | | `groups` | lista | não | — | grupos aninhados | ## Nota | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `text` | texto | **sim** | — | | | `target` | referência | não | — | a caixa. Implícito em documento singular de elemento | | `scope` | referência de diagrama | não | — | o diagrama. Implícito em documento de diagrama | | `kind` | texto | não | `info` | chave em `noteKinds`. Desconhecida: neutro + aviso | | `meta` | mapa | não | `{}` | | Sem `target` e sem `scope`, a nota é descartada com aviso. ## Fluxo | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `id` | texto | não | o nome do arquivo | divide o espaço de nomes com diagramas | | `title` | texto | não | o `id` | | | `scope` | referência | não | — | onde o caso de uso mora. **Não** escolhe participantes | | `level` | texto | não | o mais fino que os passos citam | | | `order` | número | não | 500 | | | `main.name` | texto | não | `Principal` | o nome do caminho principal | | `main.outcome` | texto | não | `success` | chave em `flowOutcomes` | | `participants` | lista de referências | não | ordem de aparição | fixa as primeiras colunas | | `steps` | lista | **sim** | — | os passos do caminho principal | | `paths` | lista | não | — | os caminhos alternativos | | `tags` | lista de texto | não | `[]` | | | `meta` | mapa | não | `{}` | | ### Passo | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `to` | referência | **sim** | — | | | `from` | referência | não | o `to` do passo anterior | no primeiro passo, omitir é erro | | `kind` | texto | não | o da seta declarada, ou `sync` | | | `label` | texto | não | o rótulo da seta declarada | | | `description` | texto | não | — | | | `reply` | texto | não | — | resposta curta, tracejada | | `id` | texto | não | — | necessário só para ser ponto de desvio | ### Caminho alternativo | Campo | Tipo | Obrigatório | Padrão | O que faz | |---|---|---|---|---| | `id` | texto | **sim** | — | | | `name` | texto | não | o `id` | | | `outcome` | texto | não | `alternate` | chave em `flowOutcomes` | | `from` | id de passo | não | — | de onde ele desvia, **inclusive** | | `steps` | lista | **sim** | — | | ## Referências | Como está escrito | Como resolve | |---|---| | com barra, `reservas/api` | absoluta: projeto e identificador | | sem barra, `api` | o projeto que declara; depois `shared/` | Todo campo que cita uma caixa segue essa regra: `parent`, `from`, `to`, `scope`, `subject`, `target`, os seletores e os participantes de fluxo. ## `.layout/` — a arrumação Escrita pelo leitor, nunca lida como modelo. Um arquivo JSON por diagrama, em `/.layout/.json`, com as posições das caixas e das notas soltas, o estado dos grupos, as arestas ajustadas e o estilo de linha. Fluxos não têm arquivo de arrumação. ## `workspace.yaml` Está em [Configuração da aparência](doc:referencia/configuracao). # Seletores Todos os seletores do formato, onde cada um pode ser usado, e a sintaxe deles no YAML e na linha de comando. Um **seletor** nomeia um conjunto de caixas sem listá-las. É o que faz um diagrama não envelhecer. ## A tabela | Seletor | Traz | Vale em `where` e `match`? | |---|---|---| | `ref: ` | exatamente aquela caixa | não | | `children: ` | os filhos diretos | não | | `descendants: ` | todos os descendentes | não | | `descendants: ` + `depth: ` | os descendentes até `n` níveis | não | | `tag: ` | quem tem a etiqueta | **sim** | | `meta: { : }` | quem tem o metadado | **sim** | | `level: ` | `context`, `container`, `component`, `code` | **sim** | | `shape: ` | quem tem a forma | **sim** | | `project: ` | tudo de um projeto | **sim** | Os três primeiros produzem conjuntos a partir de uma caixa nomeada, e por isso não servem como predicado: eles não respondem "sim ou não" sobre uma caixa. `tag`, `level` e `shape` aceitam uma lista, que combina com **ou**. Em `meta`, o valor de cada chave também aceita uma lista. ## Onde eles aparecem | Lugar | Quais | |---|---| | `include` de um diagrama | todos | | `exclude` de um diagrama | todos | | `where` de um diagrama | só os predicados | | `include` de um grupo | todos | | `match` de um grupo | só os predicados | ## No YAML ```yaml include: - reservas # atalho para { ref: reservas } - ref: colaborador - children: reservas - descendants: reservas depth: 2 - tag: nucleo - tag: [nucleo, pci] # nucleo OU pci - meta: dominio: reservas - meta: dominio: [reservas, integracao] - level: container - level: [container, component] - shape: [database, queue] - project: shared ``` Vários seletores na mesma lista **somam** — a união de todos. ## Na linha de comando Um critério se escreve `:`. Não há ambiguidade com um identificador, porque identificador não aceita dois-pontos. ```sh --include level:context --include tag:nucleo --include children:reservas --include descendants:reservas:2 --include shape:queue --include project:shared --include meta:dominio=reservas --where level:container ``` Um valor sem `:` é lido como uma referência: ```sh --include reservas # o mesmo que ref:reservas ``` ## Na busca do MCP A ferramenta `cfour_search` aceita a mesma sintaxe no parâmetro `seletor`, e vários critérios separados por espaço combinam com **e**: ```text tag:nucleo level:container meta:dominio=reservas shape:database descendants:reservas:2 ``` ## A ordem em que eles se aplicam ```text 1. include (ou os filhos de `scope`, quando não há include) 2. where filtra o que entrou 3. exclude tira 4. neighbors puxa contexto mudo, fora da fronteira ``` `where` só filtra o que `include` trouxe; `exclude` age depois do filtro; e nenhum dos três alcança o que `neighbors` puxa. ## Depurar ```sh cfour diagram show --resolved ``` A terceira coluna da saída diz **qual seletor trouxe cada caixa**. # Comandos do cfour Todo comando da ferramenta de linha de comando, com argumentos, opções e exemplos. Esta página é **gerada** a partir da própria declaração de comandos da ferramenta. Ela não pode divergir do que o `cfour` faz. O mesmo conteúdo está disponível offline: ```sh cfour help # a árvore inteira cfour help element add # um comando só cfour help --output json # em JSON, para um agente ``` **As convenções que valem em vários comandos** `--dry-run`, `--json`, `--no-input`, `--modelagem` e `--file` aparecem em quase todo comando que escreve, e fazem sempre a mesma coisa. O que cada uma significa está em [Visão geral do cfour](doc:cli). ## `cfour init [id]` cria a menor modelagem que desenha algo | argumento | obrigatorio | o que e | |---|---|---| | `id` | nao | id da modelagem (padrao: arquitetura) | | opcao | repetivel | o que faz | |---|---|---| | `--id ` | nao | id da modelagem | | `--nome ` | nao | nome legivel da modelagem | | `--force` | nao | escreve mesmo onde ja ha um registro governando | ## `cfour check` valida uma modelagem | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | qual modelagem validar | | `--all` | nao | valida todas as modelagens do registro, e confere os espelhos | | `--root ` | nao | valida uma arvore avulsa, ignorando o registro | | `--json` | nao | saida em JSON | | `--inventory` | nao | inclui o inventario do modelo (implica --json) | ## `cfour serve` viewer local; arrastar salva em .layout/ | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | qual modelagem abre primeiro | | `--port ` | nao | porta (padrao: 5173) | | `--host ` | nao | escuta fora do loopback (padrao: 127.0.0.1) | ## `cfour login [key]` guarda uma chave e vincula a este repo | argumento | obrigatorio | o que e | |---|---|---| | `key` | nao | a chave, se preferir sem --key | | opcao | repetivel | o que faz | |---|---|---| | `--key ` | nao | a chave: c4__ | | `--profile ` | nao | guarda sob outro nome que nao o destino | ## `cfour logout [perfil]` esquece uma chave, ou todas | argumento | obrigatorio | o que e | |---|---|---| | `perfil` | nao | qual perfil esquecer | | opcao | repetivel | o que faz | |---|---|---| | `--profile ` | nao | qual perfil esquecer | | `--all` | nao | esquece todas | ## `cfour keys` as chaves guardadas, e qual vale aqui | opcao | repetivel | o que faz | |---|---|---| | `--json` | nao | saida em JSON | ## `cfour use [perfil]` troca a chave deste repo, ou o default | argumento | obrigatorio | o que e | |---|---|---| | `perfil` | nao | o perfil a usar | | opcao | repetivel | o que faz | |---|---|---| | `--default` | nao | torna este o perfil default da maquina | ## `cfour push` publica as modelagens status: active | opcao | repetivel | o que faz | |---|---|---| | `--ref ` | nao | a ref a carimbar (padrao: a do git) | | `--all` | nao | inclui as que nao estao com status: active | | `--dry-run` | nao | ensaia: diz o destino e nao envia nada | | `--sha ` | nao | carimba outro commit | | `--profile ` | nao | usa outra chave | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour push --dry-run cfour push --ref main cfour push --all --profile acme ``` ## `cfour status` o que esta publicado | opcao | repetivel | o que faz | |---|---|---| | `--json` | nao | saida em JSON | | `--profile ` | nao | usa outra chave | ## `cfour element` as caixas: cria, consulta, altera, remove Tambem: `el` ### `cfour element add ` cria uma caixa e a coloca na arvore de contencao | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | id local, ou / | | opcao | repetivel | o que faz | |---|---|---| | `--name ` | nao | o nome legivel (padrao: o proprio id) | | `--shape ` | nao | a forma da caixa; `cfour config show` lista as que valem aqui | | `--parent ` | nao | a caixa que contem esta; e o que decide o nivel C4 | | `--technology ` | nao | a tecnologia, como aparece na caixa | | `--description ` | nao | uma frase sobre o que ela faz | | `--tag ` | sim | uma etiqueta; repetivel | | `--meta ` | sim | um metadado; repetivel | | `--bind ` | nao | espelho de um elemento de outra modelagem | | `--projeto ` | nao | em qual projeto, quando o id nao diz | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour element add loja --shape system --name "Loja Online" cfour element add loja-api --parent loja --shape api --technology ".NET 8" cfour element add pedido-service --parent loja-api --shape component --tag core cfour element add cache --parent loja --dry-run ``` ### `cfour element list` lista as caixas, com filtros Tambem: `ls` | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--projeto ` | nao | so as de um projeto | | `--level ` | nao | context, container, component ou code | | `--shape ` | nao | so as de uma forma | | `--tag ` | nao | so as que tem esta etiqueta | | `--json` | nao | saida em JSON | ### `cfour element show ` tudo sobre uma caixa, e quem aponta para ela Tambem: `get` | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--json` | nao | saida em JSON | ### `cfour element set ` altera campos de uma caixa que ja existe | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--name ` | nao | o nome legivel | | `--shape ` | nao | a forma | | `--parent ` | nao | move na arvore de contencao; e o que muda o nivel C4 | | `--technology ` | nao | a tecnologia | | `--description ` | nao | uma frase sobre o que ela faz | | `--bind ` | nao | espelho de um elemento de outra modelagem | | `--tag ` | sim | acrescenta uma etiqueta; repetivel | | `--tag-rm ` | sim | tira uma etiqueta; repetivel | | `--meta ` | sim | define um metadado; repetivel | | `--meta-rm ` | sim | tira um metadado; repetivel | | `--clear ` | sim | apaga um campo; repetivel | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour element set loja-api --technology ".NET 9" cfour element set loja/loja-web --name "Vitrine" cfour element set pedido-service --parent loja-api # reclassifica o nivel C4 cfour element set loja-api --tag pci --tag-rm legado cfour element set loja-api --meta owner=squad-checkout --meta-rm layer cfour element set loja-api --clear technology ``` ### `cfour element rm ` remove uma caixa, se ninguem depender dela Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--cascade` | nao | nao recusa por causa de quem aponta para ela | | `--yes` | nao | segue sem confirmar; so faz sentido junto de --cascade | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour element rm loja/loja-legacy --dry-run cfour element rm loja/loja-legacy ``` ### `cfour element mv ` renomeia uma caixa, e conserta quem apontava para ela Tambem: `rename` | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | `novo-id` | sim | o id novo, local | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour element mv loja-api api-de-pedidos --dry-run cfour element mv loja/loja-legacy carrinho-antigo ``` ## `cfour relation` as setas entre as caixas Tambem: `rel` ### `cfour relation add ` liga duas caixas | argumento | obrigatorio | o que e | |---|---|---| | `origem` | sim | de onde a seta sai | | `destino` | sim | onde a seta chega | | opcao | repetivel | o que faz | |---|---|---| | `--kind ` | nao | o tipo da seta (padrao: sync); `cfour config show` lista os que valem aqui | | `--label ` | nao | o que trafega, em poucas palavras | | `--description ` | nao | a forma longa, que aparece ao passar o mouse | | `--tag ` | sim | uma etiqueta; repetivel | | `--meta ` | sim | um metadado; repetivel | | `--route ` | nao | straight, orthogonal ou bezier; sem isto vale o padrao do diagrama | | `--bidirectional` | nao | poe ponta tambem na origem | | `--inline` | nao | escreve dentro do documento da origem, com o from implicito | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour relation add loja-web loja-api --kind sync --label Chama cfour relation add pedido-service loja-db --inline cfour relation add loja-api estoque/estoque-api --kind async --dry-run ``` ### `cfour relation list` lista as setas, com filtros Tambem: `ls` | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--from ` | nao | so as que saem daqui | | `--to ` | nao | so as que chegam aqui | | `--kind ` | nao | so as deste tipo | | `--json` | nao | saida em JSON | ### `cfour relation show ` tudo sobre uma seta Tambem: `get` | argumento | obrigatorio | o que e | |---|---|---| | `origem` | sim | de onde a seta sai | | `destino` | sim | onde a seta chega | | opcao | repetivel | o que faz | |---|---|---| | `--kind ` | nao | quando ha mais de uma seta entre as duas caixas | | `--modelagem ` | nao | em qual modelagem olhar | | `--json` | nao | saida em JSON | ### `cfour relation set ` altera uma seta que ja existe | argumento | obrigatorio | o que e | |---|---|---| | `origem` | sim | de onde a seta sai | | `destino` | sim | onde a seta chega | | opcao | repetivel | o que faz | |---|---|---| | `--kind ` | nao | quando ha mais de uma seta entre as duas caixas | | `--label ` | nao | o que trafega, em poucas palavras | | `--description ` | nao | a forma longa, que aparece ao passar o mouse | | `--route ` | nao | straight, orthogonal ou bezier | | `--bidirectional` | nao | poe ponta tambem na origem | | `--tag ` | sim | acrescenta uma etiqueta; repetivel | | `--tag-rm ` | sim | tira uma etiqueta; repetivel | | `--meta ` | sim | define um metadado; repetivel | | `--meta-rm ` | sim | tira um metadado; repetivel | | `--clear ` | sim | apaga um campo; repetivel | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour relation set loja-web loja-api --label "Chama a API" cfour relation set loja-web loja-api --bidirectional --tag critico cfour relation set loja-api loja-db --kind sync --clear description ``` ### `cfour relation mv ` troca o tipo de uma seta | argumento | obrigatorio | o que e | |---|---|---| | `origem` | sim | de onde a seta sai | | `destino` | sim | onde a seta chega | | `novo-kind` | sim | o tipo novo | | opcao | repetivel | o que faz | |---|---|---| | `--kind ` | nao | o tipo ATUAL, quando ha mais de uma seta entre as duas caixas | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour relation mv loja-api estoque/estoque-api async cfour relation mv loja-web loja-api event --kind sync --dry-run ``` ### `cfour relation rm ` desfaz uma seta Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `origem` | sim | de onde a seta sai | | `destino` | sim | onde a seta chega | | opcao | repetivel | o que faz | |---|---|---| | `--kind ` | nao | quando ha mais de uma seta entre as duas caixas | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour relation rm loja-web loja-api cfour relation rm loja-web loja-db --kind async --dry-run ``` ## `cfour note` os recados: presos numa caixa, ou soltos num diagrama ### `cfour note add ` escreve um recado | argumento | obrigatorio | o que e | |---|---|---| | `alvo` | sim | a caixa OU o diagrama que recebe a nota | | `texto` | sim | o que a nota diz | | opcao | repetivel | o que faz | |---|---|---| | `--kind ` | nao | o tipo da nota (padrao: info); `cfour config show` lista os que valem aqui | | `--target ` | nao | a caixa, quando o mesmo id nomeia uma caixa e um diagrama | | `--scope ` | nao | o diagrama, para restringir uma nota de caixa a um desenho so | | `--meta ` | sim | um metadado; repetivel | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour note add loja-api "Ponto unico de falha" --kind risk cfour note add loja-db "Vale separar a replica?" --kind question --scope containers cfour note add containers "Congelado para a revisao de 2026-Q1" ``` ### `cfour note list` lista as notas Tambem: `ls` | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--target ` | nao | so as de uma caixa | | `--scope ` | nao | so as de um diagrama | | `--json` | nao | saida em JSON | ### `cfour note set ` altera um recado que ja existe | argumento | obrigatorio | o que e | |---|---|---| | `alvo` | sim | a caixa ou o diagrama que tem a nota | | opcao | repetivel | o que faz | |---|---|---| | `--text ` | nao | o texto novo | | `--kind ` | nao | o tipo novo | | `--scope ` | nao | restringe a nota a um diagrama | | `--meta ` | sim | define um metadado; repetivel | | `--meta-rm ` | sim | tira um metadado; repetivel | | `--clear ` | sim | apaga um campo; repetivel | | `--match ` | nao | quando o alvo tem mais de uma nota | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour note set loja-api --text "Ponto unico de falha do fechamento" cfour note set loja-db --match replica --kind decision cfour note set containers --clear scope ``` ### `cfour note rm ` tira um recado Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `alvo` | sim | a caixa ou o diagrama que tem a nota | | opcao | repetivel | o que faz | |---|---|---| | `--match ` | nao | quando o alvo tem mais de uma nota | | `--kind ` | nao | so as deste tipo | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour note rm loja-legacy cfour note rm loja-db --match "replica" cfour note rm contexto --kind info ``` ## `cfour diagram` as visoes: o que cada desenho mostra Tambem: `dia` ### `cfour diagram add ` cria uma visao | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | id local, ou / | | opcao | repetivel | o que faz | |---|---|---| | `--title ` | nao | o titulo que aparece no desenho | | `--scope ` | nao | a caixa que este diagrama detalha; da a fronteira e o nome | | `--level ` | nao | context, container, component ou code | | `--order ` | nao | a posicao na lateral | | `--include ` | sim | uma caixa ou um criterio; repetivel | | `--exclude ` | sim | tira quem o seletor pega; repetivel | | `--where ` | sim | filtra o que os seletores trouxeram; repetivel | | `--neighbors ` | nao | puxa quem esta a N saltos como contexto mudo | | `--relations ` | nao | auto ou none | | `--group-by ` | nao | meta. ou level: uma banda por valor | | `--subject ` | nao | a caixa em foco | | `--tag ` | sim | uma etiqueta; repetivel | | `--meta ` | sim | um metadado; repetivel | | `--projeto ` | nao | em qual projeto, quando o id nao diz | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour diagram add containers --scope loja --level container --relations auto cfour diagram add contexto --level context --include level:context cfour diagram add integracoes --include tag:externo --include children:loja cfour diagram add componentes --scope loja-api --group-by meta.domain ``` ### `cfour diagram list` lista as visoes Tambem: `ls` | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--projeto ` | nao | so as de um projeto | | `--json` | nao | saida em JSON | ### `cfour diagram show ` tudo sobre uma visao Tambem: `get` | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--resolved` | nao | o que o desenho MOSTRA: caixas, setas, e por que cada uma entrou | | `--modelagem ` | nao | em qual modelagem olhar | | `--json` | nao | saida em JSON | ```sh cfour diagram show contexto cfour diagram show contexto --resolved cfour diagram show loja/containers --resolved --json ``` ### `cfour diagram set ` altera um diagrama que ja existe | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--title ` | nao | o titulo exibido | | `--scope ` | nao | a caixa que o diagrama abre por dentro | | `--level ` | nao | context, container, component ou code | | `--order ` | nao | ordem na arvore (padrao: 500) | | `--include ` | sim | acrescenta um seletor ao recorte; repetivel | | `--include-rm ` | sim | tira um seletor do recorte; repetivel | | `--exclude ` | sim | acrescenta um seletor a exclusao; repetivel | | `--exclude-rm ` | sim | tira um seletor da exclusao; repetivel | | `--where ` | sim | substitui o filtro do diagrama; repetivel | | `--neighbors ` | nao | quantos saltos de vizinhos trazer | | `--relations ` | nao | auto ou none | | `--group-by ` | nao | bandas automaticas: meta., level, shape ou project | | `--subject ` | nao | destaca uma caixa | | `--subject-rm ` | sim | tira o destaque de uma caixa; repetivel | | `--tag ` | sim | acrescenta uma etiqueta; repetivel | | `--tag-rm ` | sim | tira uma etiqueta; repetivel | | `--meta ` | sim | define um metadado; repetivel | | `--meta-rm ` | sim | tira um metadado; repetivel | | `--clear ` | sim | apaga um campo; repetivel | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour diagram set containers --title "Loja Online — Containers" cfour diagram set contexto --include estoque/estoque --neighbors 1 cfour diagram set contexto --include level:context --include-rm loja cfour diagram set componentes --group-by meta.domain cfour diagram set contexto --clear subject ``` ### `cfour diagram mv ` renomeia um diagrama, e move o layout junto Tambem: `rename` | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | `novo-id` | sim | o id novo, dentro do mesmo projeto | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour diagram mv containers visao-de-containers --dry-run cfour diagram mv loja/contexto panorama ``` ### `cfour diagram rm ` apaga uma visao, e o arquivo dela Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour diagram rm loja/rascunho --dry-run cfour diagram rm rascunho ``` ## `cfour group` as bandas: agrupa caixas dentro de UM diagrama ### `cfour group add ` cria uma banda no diagrama | argumento | obrigatorio | o que e | |---|---|---| | `diagrama` | sim | id local ou / | | `id` | sim | o id da banda, unico no diagrama | | opcao | repetivel | o que faz | |---|---|---| | `--name ` | nao | o rotulo da banda (padrao: o proprio id) | | `--orientation ` | nao | row para a banda ler como uma linha; sem isto, empilha | | `--parent ` | nao | aninha esta banda dentro de outra | | `--include ` | sim | poe quem o seletor pega nesta banda; repetivel | | `--include-rm ` | sim | tira um seletor desta banda; repetivel | | `--match-tag ` | sim | entra quem tem esta etiqueta; repetivel | | `--match-meta ` | sim | entra quem tem este metadado; repetivel | | `--match-level ` | sim | entra quem e deste nivel; repetivel | | `--match-shape ` | sim | entra quem tem esta forma; repetivel | | `--match-project ` | sim | entra quem e deste projeto; repetivel | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour group add containers dados --name Dados --match-shape database cfour group add containers experiencia --name "Experiência" --orientation row --include loja-web cfour group add containers replicas --parent dados --match-tag replica ``` ### `cfour group list ` as bandas de um diagrama, com o aninhamento Tambem: `ls` | argumento | obrigatorio | o que e | |---|---|---| | `diagrama` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--json` | nao | saida em JSON | ### `cfour group set ` altera uma banda que ja existe | argumento | obrigatorio | o que e | |---|---|---| | `diagrama` | sim | id local ou / | | `id` | sim | o id da banda | | opcao | repetivel | o que faz | |---|---|---| | `--name ` | nao | o rotulo da banda | | `--orientation ` | nao | row ou column | | `--clear ` | sim | apaga um campo; repetivel | | `--include ` | sim | poe quem o seletor pega nesta banda; repetivel | | `--include-rm ` | sim | tira um seletor desta banda; repetivel | | `--match-tag ` | sim | entra quem tem esta etiqueta; repetivel | | `--match-meta ` | sim | entra quem tem este metadado; repetivel | | `--match-level ` | sim | entra quem e deste nivel; repetivel | | `--match-shape ` | sim | entra quem tem esta forma; repetivel | | `--match-project ` | sim | entra quem e deste projeto; repetivel | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour group set containers dados --name "Persistência" cfour group set containers experiencia --include-rm loja-web cfour group set containers dados --clear match ``` ### `cfour group rm ` tira uma banda do diagrama Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `diagrama` | sim | id local ou / | | `id` | sim | o id da banda | | opcao | repetivel | o que faz | |---|---|---| | `--cascade` | nao | leva junto as bandas aninhadas nela | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour group rm containers dados cfour group rm containers dominio --cascade ``` ## `cfour step` os passos de um fluxo, na ordem em que acontecem ### `cfour step add ` acrescenta um passo | argumento | obrigatorio | o que e | |---|---|---| | `fluxo` | sim | id local ou / | | `destino` | sim | quem recebe a mensagem | | opcao | repetivel | o que faz | |---|---|---| | `--from ` | nao | quem envia; sem isto, herda o destino do passo anterior | | `--label ` | nao | o que aparece ao lado da linha | | `--kind ` | nao | o tipo da seta; sem isto, o da seta declarada | | `--reply ` | nao | uma resposta curta, tracejada, na linha seguinte | | `--after ` | nao | entra logo depois deste passo; sem isto, no fim | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour step add checkout loja-api --label "Fecha pedido" cfour step add checkout estoque/estoque-api --from loja-api --label "Reserva" cfour step add checkout pagamento-client --after cobra ``` ### `cfour step set ` altera um passo | argumento | obrigatorio | o que e | |---|---|---| | `fluxo` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--from ` | nao | quem envia | | `--to ` | nao | quem recebe | | `--label ` | nao | o que aparece ao lado da linha | | `--kind ` | nao | o tipo da seta | | `--reply ` | nao | a resposta curta | | `--description ` | nao | o texto que aparece ao passar o mouse | | `--clear ` | sim | apaga um campo; repetivel | | `--n ` | nao | qual passo, pelo numero que `cfour flow show` mostra | | `--id ` | nao | qual passo, pelo id — quando ele tem um | | `--path ` | nao | num caminho alternativo; sem isto, no principal | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour step set checkout --n 2 --label "Fecha o pedido" cfour step set checkout --n 4 --id cobra # nomeia o passo 4 cfour step set checkout --id cobra --reply "Autorizado" ``` ### `cfour step mv ` reordena um passo | argumento | obrigatorio | o que e | |---|---|---| | `fluxo` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--after ` | nao | passa a vir logo depois deste | | `--first` | nao | passa a ser o primeiro | | `--n ` | nao | qual passo, pelo numero que `cfour flow show` mostra | | `--id ` | nao | qual passo, pelo id — quando ele tem um | | `--path ` | nao | num caminho alternativo; sem isto, no principal | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour step mv checkout --n 4 --after 2 cfour step mv checkout --id reserva --first ``` ### `cfour step rm ` tira um passo Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `fluxo` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--n ` | nao | qual passo, pelo numero que `cfour flow show` mostra | | `--id ` | nao | qual passo, pelo id — quando ele tem um | | `--path ` | nao | num caminho alternativo; sem isto, no principal | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour step rm checkout --n 3 cfour step rm checkout --path recusado --n 1 ``` ## `cfour path` os desvios de um fluxo, com desfecho proprio ### `cfour path add ` acrescenta um caminho alternativo, com o primeiro passo dele | argumento | obrigatorio | o que e | |---|---|---| | `fluxo` | sim | id local ou / | | `id` | sim | o id do caminho, unico no fluxo | | `destino` | sim | quem recebe a primeira mensagem do desvio | | opcao | repetivel | o que faz | |---|---|---| | `--name ` | nao | o nome no seletor (padrao: o proprio id) | | `--outcome ` | nao | success, failure ou alternate; `cfour config show` lista | | `--from ` | nao | o id do passo de onde ele desvia, inclusive | | `--label ` | nao | o rotulo do primeiro passo | | `--kind ` | nao | o tipo da seta do primeiro passo | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour path add checkout recusado pagamento-client --name "Pagamento recusado" \ cfour path add checkout sem-estoque loja-web --outcome alternate ``` ### `cfour path list ` os caminhos de um fluxo, com o principal Tambem: `ls` | argumento | obrigatorio | o que e | |---|---|---| | `fluxo` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--json` | nao | saida em JSON | ### `cfour path set ` altera um caminho alternativo | argumento | obrigatorio | o que e | |---|---|---| | `fluxo` | sim | id local ou / | | `id` | sim | o id do caminho | | opcao | repetivel | o que faz | |---|---|---| | `--name ` | nao | o nome no seletor | | `--outcome ` | nao | success, failure ou alternate | | `--from ` | nao | o id do passo de onde ele desvia | | `--clear ` | sim | apaga um campo; repetivel | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour path set checkout recusado --name "Recusa do emissor" cfour path set checkout recusado --clear from ``` ### `cfour path rm ` tira um caminho alternativo Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `fluxo` | sim | id local ou / | | `id` | sim | o id do caminho | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour path rm checkout recusado ``` ## `cfour federacao` as leituras conjuntas de duas ou mais modelagens ### `cfour federacao add ` declara uma leitura conjunta | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | o apelido da leitura | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | sim | um membro; repita para os demais | | `--name ` | nao | o rotulo exibido | | `--curador ` | nao | de quem vale a configuracao quando os membros discordam | | `--dry-run` | nao | mostra o que mudaria e nao escreve nada | ```sh cfour federacao add plataforma --modelagem loja --modelagem logistica cfour federacao add par --modelagem a --modelagem b --curador a --dry-run ``` ### `cfour federacao list` as leituras conjuntas, e se os dois lados concordam Tambem: `ls` | opcao | repetivel | o que faz | |---|---|---| | `--json` | nao | saida em JSON | ### `cfour federacao rm ` desfaz uma leitura conjunta, nos dois lados Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | o apelido da leitura | | opcao | repetivel | o que faz | |---|---|---| | `--dry-run` | nao | mostra o que mudaria e nao escreve nada | ```sh cfour federacao rm par --dry-run cfour federacao rm plataforma ``` ## `cfour flow` os casos de uso, contados como sequencia ### `cfour flow add ` cria um fluxo, ja com o primeiro passo | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | id local, ou / | | `origem` | sim | quem inicia o primeiro passo | | `destino` | sim | quem recebe o primeiro passo | | opcao | repetivel | o que faz | |---|---|---| | `--title ` | nao | o titulo do caso de uso | | `--scope ` | nao | onde ele acontece; da a trilha e o lugar na arvore | | `--level ` | nao | o nivel em que ele abre | | `--order ` | nao | a posicao na lateral | | `--main ` | nao | o nome do caminho feliz (padrao: Caminho feliz) | | `--outcome ` | nao | o desfecho (padrao: success); `cfour config show` lista os que valem aqui | | `--participant ` | sim | fixa a ordem das lifelines; repetivel | | `--label ` | nao | o rotulo do primeiro passo | | `--kind ` | nao | o tipo do primeiro passo | | `--tag ` | sim | uma etiqueta; repetivel | | `--projeto ` | nao | em qual projeto, quando o id nao diz | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour flow add checkout cliente loja-web --title "Fechar pedido" --scope loja cfour flow add reserva loja-api estoque-api --label "Reserva itens" ``` ### `cfour flow step ` acrescenta um passo a sequencia | argumento | obrigatorio | o que e | |---|---|---| | `fluxo` | sim | id local ou / | | `destino` | sim | quem recebe a mensagem | | opcao | repetivel | o que faz | |---|---|---| | `--from ` | nao | quem envia; omitido, herda o destino do passo anterior | | `--label ` | nao | o que a mensagem diz | | `--kind ` | nao | o tipo da seta | | `--reply ` | nao | a resposta, tracejada na propria linha | | `--after ` | nao | entra depois deste passo; sem isto, entra no fim | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour flow step checkout loja-api --label "Fecha pedido" cfour flow step checkout loja-db --from pedido-service --label Persiste cfour flow step checkout gateway --after cobra --label Autoriza ``` ### `cfour flow set ` altera um fluxo que ja existe | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--title ` | nao | o titulo exibido | | `--scope ` | nao | onde o caso de uso acontece | | `--level ` | nao | em qual altura o fluxo abre | | `--order ` | nao | ordem na arvore (padrao: 500) | | `--main ` | nao | o nome do caminho principal | | `--outcome ` | nao | o desfecho do caminho principal | | `--participant ` | sim | acrescenta uma coluna; repetivel | | `--participant-rm ` | sim | tira uma coluna; repetivel | | `--tag ` | sim | acrescenta uma etiqueta; repetivel | | `--tag-rm ` | sim | tira uma etiqueta; repetivel | | `--meta ` | sim | define um metadado; repetivel | | `--meta-rm ` | sim | tira um metadado; repetivel | | `--clear ` | sim | apaga um campo; repetivel | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour flow set checkout --title "Fechar pedido" cfour flow set checkout --main "Pedido aprovado" --outcome success cfour flow set checkout --participant shared/cliente --participant loja-web ``` ### `cfour flow mv ` renomeia um fluxo Tambem: `rename` | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | `novo-id` | sim | o id novo, dentro do mesmo projeto | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour flow mv checkout fechar-pedido --dry-run ``` ### `cfour flow rm ` remove um fluxo inteiro Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour flow rm conciliacao --dry-run cfour flow rm loja/checkout ``` ### `cfour flow list` lista os fluxos, com passos e desfechos Tambem: `ls` | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--projeto ` | nao | so os de um projeto | | `--json` | nao | saida em JSON | ### `cfour flow show ` a sequencia inteira, passo a passo Tambem: `get` | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--json` | nao | saida em JSON | ## `cfour project` as pastas sob model/ que agrupam tudo Tambem: `proj` ### `cfour project add ` cria um projeto | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | o id, que e tambem o nome da pasta | | opcao | repetivel | o que faz | |---|---|---| | `--name ` | nao | o nome legivel | | `--order ` | nao | a posicao na lateral | | `--tag ` | sim | uma etiqueta; repetivel | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour project add loja --name "Loja Online" --order 10 ``` ### `cfour project set ` altera o nome, a ordem e as etiquetas de um projeto | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | o id do projeto, que e o nome da pasta | | opcao | repetivel | o que faz | |---|---|---| | `--name ` | nao | o nome exibido na arvore | | `--order ` | nao | ordem entre os projetos (padrao: 500) | | `--tag ` | sim | acrescenta uma etiqueta; repetivel | | `--tag-rm ` | sim | tira uma etiqueta; repetivel | | `--meta ` | sim | define um metadado; repetivel | | `--meta-rm ` | sim | tira um metadado; repetivel | | `--clear ` | sim | apaga um campo; repetivel | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour project set loja --name "Loja Online" --order 10 cfour project set loja --meta owner=tribo-vendas ``` ### `cfour project rm ` remove um projeto, e a pasta dele Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | o id do projeto | | opcao | repetivel | o que faz | |---|---|---| | `--cascade` | nao | apaga a pasta mesmo com conteudo dentro | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour project rm rascunho --dry-run cfour project rm rascunho --cascade ``` ### `cfour project list` lista os projetos, com o que ha em cada um Tambem: `ls` | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--json` | nao | saida em JSON | ## `cfour find ` procura em id, nome, descricao, tag, meta e texto de nota | argumento | obrigatorio | o que e | |---|---|---| | `termo` | sim | o que procurar; casa em qualquer parte, sem acento e sem caixa | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--tipo ` | nao | element, relation, note, diagram, flow ou project | | `--json` | nao | saida em JSON | ```sh cfour find checkout cfour find PostgreSQL --tipo element cfour find "ponto unico de falha" --tipo note cfour find "pedido" --json ``` ## `cfour refs ` onde uma caixa e usada | argumento | obrigatorio | o que e | |---|---|---| | `ref` | sim | id local ou / | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--json` | nao | saida em JSON | ```sh cfour refs loja-api ``` ## `cfour config` formas, tipos de seta, de nota e de desfecho ### `cfour config rm ` tira uma chave de um registro do workspace.yaml Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `registro` | sim | shapes, relationKinds, noteKinds, flowOutcomes, metadata ou palette | | `chave` | sim | a chave a remover | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour config rm noteKinds decision cfour config rm shapes lambda --dry-run ``` ### `cfour config title ` o titulo desta modelagem, no alto da barra lateral | argumento | obrigatorio | o que e | |---|---|---| | `texto` | sim | o titulo | | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour config title "Arquitetura da Loja" ``` ### `cfour config show` a configuracao efetiva: os defaults com o workspace.yaml por cima | opcao | repetivel | o que faz | |---|---|---| | `--modelagem ` | nao | em qual modelagem olhar | | `--json` | nao | saida em JSON | ### `cfour config set ` acrescenta ou altera uma chave de um registro aberto | argumento | obrigatorio | o que e | |---|---|---| | `registro` | sim | shapes, relationKinds, noteKinds, flowOutcomes, metadata ou palette | | `chave` | sim | o nome novo, que o YAML passa a aceitar | | opcao | repetivel | o que faz | |---|---|---| | `--label ` | nao | o rotulo legivel | | `--color ` | nao | a cor, em hex | | `--dash ` | nao | o tracejado de uma seta (stroke-dasharray) | | `--char ` | nao | o caractere do cracha de uma nota | | `--stereotype ` | nao | o que aparece entre guilemetes na caixa | | `--palette ` | nao | qual entrada da paleta a forma usa | | `--primitive ` | nao | o desenho base da forma | | `--modelagem ` | nao | em qual modelagem mexer | | `--dry-run` | nao | mostra o patch e nao escreve nada | | `--file ` | nao | força o arquivo de destino, dentro do projeto | | `--json` | nao | saida em JSON: o que mudou, ou o erro com codigo estavel | | `--no-input` | nao | nunca pergunta, mesmo num terminal | ```sh cfour config set relationKinds webhook --label Webhook --dash "4 2" cfour config set noteKinds decisao --label Decisao --char D cfour config set shapes lambda --primitive container --stereotype Function ``` ## `cfour modelagem` as realidades registradas no cfour.yaml Tambem: `modelagens` ### `cfour modelagem list` lista as modelagens do registro Tambem: `ls` | opcao | repetivel | o que faz | |---|---|---| | `--json` | nao | saida em JSON | ### `cfour modelagem add ` registra uma modelagem que ja existe no disco | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | o id, unico no registro | | opcao | repetivel | o que faz | |---|---|---| | `--path ` | nao | a pasta da modelagem, que tem um model/ dentro | | `--name ` | nao | o nome legivel | | `--ativa` | nao | passa a ser a que abre quando ninguem diz qual | | `--dry-run` | nao | mostra o que mudaria e nao escreve nada | ```sh cfour modelagem add logistica --path ./logistica --name "Logistica" cfour modelagem add legado --path ~/Git/legado-arquitetura ``` ### `cfour modelagem set ` altera uma modelagem: nome, caminho, descricao e status | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | o id no registro | | opcao | repetivel | o que faz | |---|---|---| | `--name ` | nao | o nome legivel | | `--path ` | nao | a pasta da modelagem | | `--description ` | nao | a prosa que diz para que ela existe | | `--status ` | nao | active, reference ou archived | | `--federacao ` | nao | a leitura conjunta de que ela participa | | `--clear ` | sim | apaga description ou federacao; repetivel | | `--dry-run` | nao | mostra o que mudaria e nao escreve nada | ```sh cfour modelagem set exemplos --status reference cfour modelagem set exemplos --name "Exemplos" --description "So para ensinar" cfour modelagem set legado --path ./arquivo/legado --dry-run ``` ### `cfour modelagem use ` troca a modelagem que abre quando ninguem diz qual | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | o id no registro | | opcao | repetivel | o que faz | |---|---|---| | `--dry-run` | nao | mostra o que mudaria e nao escreve nada | ```sh cfour modelagem use logistica ``` ### `cfour modelagem show ` tudo sobre uma modelagem, dos dois arquivos de uma vez Tambem: `get` | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | o id no registro | | opcao | repetivel | o que faz | |---|---|---| | `--json` | nao | saida em JSON | ### `cfour modelagem rm ` tira uma modelagem do registro; nunca apaga arquivo Tambem: `remove` | argumento | obrigatorio | o que e | |---|---|---| | `id` | sim | o id no registro | | opcao | repetivel | o que faz | |---|---|---| | `--dry-run` | nao | mostra o que mudaria e nao escreve nada | ```sh cfour modelagem rm legado ``` ## `cfour completion ` o script de autocompletar deste shell | argumento | obrigatorio | o que e | |---|---|---| | `shell` | sim | bash, zsh ou fish | ## `cfour version` a versao deste CLI ## `cfour help [comando]` a ajuda de um comando so | argumento | obrigatorio | o que e | |---|---|---| | `comando` | nao | de qual comando | | opcao | repetivel | o que faz | |---|---|---| | `--output ` | nao | text (padrao) ou json: a arvore inteira, para um agente | # Configuração da aparência Todos os campos de model/workspace.yaml, com os valores que vêm de fábrica. `model/workspace.yaml` é opcional. O que estiver nele é somado **chave a chave** sobre os padrões do motor. Para o guia, veja [Aparência da modelagem](doc:modelando/aparencia). ```sh cfour config show # a configuração efetiva desta modelagem ``` ## Os blocos | Campo | Tipo | O que faz | |---|---|---| | `version` | número | a versão do formato | | `title` | texto | o título no alto da barra lateral. Padrão: `C4` | | `relationKinds` | mapa | os tipos de seta | | `shapes` | mapa | as formas de caixa | | `palette` | mapa | as cores, por vaga | | `noteKinds` | mapa | os tipos de nota | | `flowOutcomes` | mapa | os desfechos de caminho de fluxo | | `metadata` | mapa | rótulo e coloração por chave de metadado | Todos os mapas são **abertos**: acrescentar uma chave faz aquele valor passar a valer, sem mudança de código. ## `relationKinds` | Campo | Tipo | O que faz | |---|---|---| | `label` | texto | o nome legível, exibido na legenda | | `dash` | texto | `stroke-dasharray` do SVG. Ausente: linha cheia | | `color` | texto | a cor da linha | | `width` | número | a espessura | | `markerStart` | texto | a ponta na origem | | `markerEnd` | texto | a ponta no destino | | `animated` | booleano | anima a linha | Pontas: `none`, `arrow-open`, `arrow-closed`, `arrow-half`, `circle`, `diamond`. ### De fábrica | Chave | Rótulo | Traço | Ponta final | |---|---|---|---| | `sync` | Síncrono | cheio | fechada | | `async` | Assíncrono | `6 4` | aberta | | `event` | Evento | `2 5`, roxo | aberta | | `batch` | Batch | `10 6` | fechada | | `dep` | Dependência | `3 3`, cinza | aberta | | `peer` | Bidirecional | cheio | aberta nos dois lados | Um tipo desconhecido renderiza como linha cheia com ponta fechada, e gera aviso. ## `shapes` | Campo | Tipo | O que faz | |---|---|---| | `primitive` | texto | o desenho base | | `stereotype` | texto | o texto entre guilemetes. Só apresentação | | `palette` | texto | a vaga de cor | | `outline` | texto | `solid` ou `dashed` | | `size` | texto | `standard`, `narrow`, `compact`, `wide` | Primitivas: `box`, `person`, `robot`, `browser`, `cylinder`, `queue`, `topic`, `component`, `class`. ### De fábrica | Chave | Primitiva | Estereótipo | Vaga | |---|---|---|---| | `system` | box | System | system | | `external` | box, tracejada | System_Ext | external | | `actor` | person | Person | person | | `bot` | robot | Person | person | | `container` | box | Container | container | | `api` | box | Container | container | | `browser` | browser | Container | container | | `database` | cylinder | ContainerDb | container | | `queue` | queue | ContainerQueue | container | | `topic` | topic | ContainerTopic | container | | `component` | component | Component | component | | `class` | class | Class | code | Uma forma desconhecida renderiza como caixa neutra, e gera aviso. ## `palette` Cada entrada tem `fill`, `stroke` e `text`, em hexadecimal. Vagas de fábrica: `person`, `system`, `container`, `component`, `code`, `external`, `neutral` — a escada azul convencional do C4. A cor é uma **vaga**, e não um estereótipo: trocar `container` recolore todas as formas que apontam para ela. ## `noteKinds` | Campo | Tipo | O que faz | |---|---|---| | `label` | texto | o nome legível | | `color` | texto | a cor do distintivo | | `char` | texto | um caractere único no distintivo | | `icon` | texto | uma marca desenhada, por nome. **Vence `char`** | ### De fábrica | Chave | Rótulo | Marca | |---|---|---| | `risk` | Risco | `R` | | `blocker` | Bloqueio | `!` | | `warning` | Atenção | `!` | | `question` | Dúvida | `?` | | `info` | Informação | `i` | | `tip` | Nota | estrela | ## `flowOutcomes` | Campo | Tipo | O que faz | |---|---|---| | `label` | texto | o nome legível | | `color` | texto | a cor do seletor de caminho | De fábrica: `success` (verde), `failure` (vermelho), `alternate` (âmbar). A cor fica no seletor que escolhe o caminho, e nunca nas mensagens. ## `metadata` | Campo | Tipo | O que faz | |---|---|---| | `label` | texto | o nome legível do filtro daquela chave | | `color` | booleano | libera a chave na opção "colorir por" | Vazio de fábrica, de propósito: os eixos que uma modelagem quer são dela. **Uma chave não precisa estar aqui para virar filtro.** Toda chave de metadado escrita no modelo já vira filtro sozinha, com a chave crua como rótulo. Este bloco só melhora o rótulo e libera a coloração. # Variáveis de ambiente As variáveis que você pode configurar ao usar o cfourdev, por contexto, com obrigatoriedade, padrão e finalidade. **Nenhum arquivo `.env` é lido automaticamente.** Não há *dotenv*, de propósito: a precedência de `CFOUR_KEY` sobre o arquivo de credenciais é explícita, e um carregamento automático a tornaria surpreendente. Para usar um arquivo: ```sh set -a; . .env; set +a ``` Em CI, exporte direto no ambiente do *job*. ## Publicar | Variável | Obrigatória | Padrão | Finalidade | |---|---|---|---| | `CFOUR_KEY` | não | — | a chave de publicação. **Vence o arquivo de credenciais** — é a forma certa em CI, onde não há ninguém para rodar `cfour login`. Ausente nos dois lugares, `push` e `status` saem com código 1 e pedem login | | `CFOUR_ENDPOINT` | não | `https://api.cfourdev.com.br` | outra instalação da plataforma. `http:` é **recusado**: a chave viaja em cabeçalho de autorização | | `CFOUR_CONFIG_HOME` | não | `$XDG_CONFIG_HOME`, ou `~/.config` | onde gravar a chave. O arquivo é escrito com modo `0600` dentro de uma pasta `0700` | ## Escolher a modelagem Valem para `cfour check`, `cfour serve` e todos os comandos de modelo. | Variável | Obrigatória | Padrão | Finalidade | |---|---|---|---| | `C4_MODELAGEM` | não | a marcada como `active` no `cfour.yaml` | abre outra modelagem do registro sem editar o registro. **Perde** para `--modelagem ` | | `C4_ROOT` | não | — | uma árvore avulsa, que não está em registro nenhum. **Vence tudo**, inclusive um `cfour.yaml` ao lado. Aponta para a pasta `model/`, e não para a raiz da modelagem | ## A ordem de precedência **Qual modelagem abrir:** ```text C4_ROOT vence tudo — nem consulta o registro --modelagem na linha de comando C4_MODELAGEM no ambiente active: no cfour.yaml a única registrada ``` **Qual chave usar:** ```text --profile na linha de comando CFOUR_KEY no ambiente — vence o arquivo o vínculo deste repositório (o `id:` do cfour.yaml) a chave default da máquina a única guardada ``` ## O que **não** é configurável por variável A plataforma hospedada não expõe configuração por variável de ambiente para quem a usa: organização, repositório e papéis são configurados pela tela, e a chave de publicação carrega a organização e o repositório dentro dela. As variáveis da API e da infraestrutura da plataforma são internas ao serviço, e não fazem parte da superfície de quem usa o produto. # Limites Todos os limites e cotas do cfourdev que alcançam quem usa o produto, com o valor e o que acontece ao ultrapassar. Não há planos: os limites abaixo são os mesmos para todo mundo. ## Organização | Limite | Valor | Ao ultrapassar | |---|---|---| | organizações ativas por conta | **5** | criar recusa. Desativar uma libera a vaga; reativar a ocupa de novo | | repositórios por organização | **50** | criar recusa | | validade de um convite | **14 dias** | o convite deixa de valer | ## Repositório | Limite | Valor | Ao ultrapassar | |---|---|---| | *refs* vivas | **10** | publicar numa *ref* nova recusa. Um preview expira sozinho em 30 dias | | total publicado | **10 MB** comprimidos | o push recusa, pedindo para remover uma *ref* antiga | | tamanho de uma modelagem | **2 MB** comprimidos | o push recusa aquela modelagem | | modelagens num único push | **25** | o push recusa | | chaves ativas por pessoa | **10** | criar recusa até revogar uma | | validade de uma chave | **30, 90 ou 365 dias** | escolhida na criação. Padrão: 90. Aviso 14 dias antes | | expiração de um preview | **30 dias** | some sozinho. A *ref* padrão não expira | | arrumação de um diagrama | **100 KB** | salvar recusa | ## Leitura conjunta | Limite | Valor | |---|---| | modelagens numa federação | **50** | ## Servidor MCP | Limite | Valor | Ao ultrapassar | |---|---|---| | resultados por chamada | **20** por padrão, **100** no máximo | a resposta é truncada, e diz que foi | | tamanho de uma chamada | **32 KB** | a requisição é recusada | | ritmo | **4 req/s**, rajada de **8** | a borda recusa | | tamanho indexável de uma modelagem | **1 MB** comprimido | a modelagem **publica normalmente**; ela só não é respondida pelo MCP, e o catálogo diz isso | | itens indexáveis de uma modelagem | **5.000** | idem | | itens lidos por consulta | **10.000** | a consulta **exige** um recorte por `repo` ou `modelagem`, e a mensagem diz isso | ## O que não tem limite escrito - **quantas pessoas** uma organização tem; - **quantos diagramas, elementos, relações ou fluxos** um modelo tem — o que limita é o tamanho publicado, acima; - **quantas leituras** um modelo publicado recebe. ## Onde eles aparecem Toda recusa carrega o número e o que fazer. Por exemplo: ```text este repositório já tem 10 refs publicadas (máximo 10). Um preview expira sozinho em 30 dias; a ref default não expira. ``` Se você bateu num limite e a mensagem não deixou claro o caminho, [Quando algo dá errado](doc:ajuda/problemas) tem a lista por sintoma. # Ferramentas do MCP As dez ferramentas do servidor MCP do cfourdev, com os parâmetros de cada uma e o que a resposta traz. Endereço: `https://api.cfourdev.com.br/mcp`. Para conectar, veja [O servidor MCP](doc:agentes); para o que cada uma serve, [As ferramentas do MCP](doc:agentes/ferramentas). Todas são de **leitura**. Nenhuma altera modelo. ## Os parâmetros de recorte Aceitos por **todas** as ferramentas: | Parâmetro | Tipo | Obrigatório | O que faz | |---|---|---|---| | `org` | texto | só se você é membro de mais de uma organização | a organização | | `repo` | texto | não | restringe a um repositório | | `modelagem` | texto | não | restringe a uma modelagem | ## `cfour_catalog` O que existe e o que você pode ler: as organizações de que você é membro, os repositórios visíveis e as modelagens publicadas em cada um, com o estado de indexação de cada uma. Sem parâmetros além do recorte. ## `cfour_facets` O vocabulário de uma modelagem: etiquetas com contagem, chaves e valores de metadado, **os tipos de nota que existem**, níveis, formas, tipos de relação e projetos. Sem parâmetros além do recorte. ## `cfour_search` | Parâmetro | Tipo | Obrigatório | O que faz | |---|---|---|---| | `texto` | texto | um dos dois | texto livre. Casa sem acento e sem caixa em identificador, nome, descrição, tecnologia, etiqueta, metadado, **texto de nota**, rótulo de passo de fluxo e nome de projeto | | `seletor` | texto | um dos dois | critérios na sintaxe do formato. Vários separados por espaço combinam com **e** | | `tipo` | lista de texto | não | restringe os tipos de habitante | | `limite` | número | não | padrão 20, máximo 100 | É obrigatório informar `texto`, `seletor`, ou os dois. Sintaxe do `seletor`: `tag:`, `level:`, `shape:`, `project:`, `meta:=`, `children:`, `descendants:[:]`. ## `cfour_get` | Parâmetro | Tipo | Obrigatório | O que faz | |---|---|---|---| | `id` | texto | **sim** | o identificador, qualificado ou não | A resposta traz os campos da caixa **mais** o que o motor deriva: nível, pai, a trilha de ancestrais, filhos, relações que entram e saem com o nome da outra ponta, notas agrupadas por tipo, diagramas que a mostram, fluxos que passam por ela, e os links (todo metadado cujo valor é uma URL). ## `cfour_references` | Parâmetro | Tipo | Obrigatório | |---|---|---| | `id` | texto | **sim** | Quem aponta para a caixa, e por qual vínculo: filho, relação, escopo ou seletor de diagrama, assunto, participante ou passo de fluxo, nota. Vem com um resumo por tipo de vínculo. ## `cfour_neighbors` | Parâmetro | Tipo | Obrigatório | O que faz | |---|---|---|---| | `id` | texto | **sim** | a caixa de partida | | `direcao` | `entram` \| `saem` \| `ambas` | não | padrão: `ambas` | | `profundidade` | número | não | de 1 a 3. Padrão: 1 | ## `cfour_tree` | Parâmetro | Tipo | Obrigatório | O que faz | |---|---|---|---| | `raiz` | texto | não | a partir desta caixa. Ausente: as raízes | | `profundidade` | número | não | padrão 3, máximo 6 | Cada caixa vem com o nível C4 dela — derivado da profundidade, e não declarado — e a forma. ## `cfour_notes` | Parâmetro | Tipo | Obrigatório | O que faz | |---|---|---|---| | `kind` | lista de texto | não | os tipos que interessam | | `alvo` | texto | não | só as notas presas nesta caixa | | `limite` | número | não | padrão 20, máximo 100 | A resposta sempre inclui **`kindsExistentes`** — os tipos que de fato existem naquela modelagem — e a contagem por tipo. É o que impede concluir que não há riscos por ter chutado a palavra errada. ## `cfour_diagram` | Parâmetro | Tipo | Obrigatório | |---|---|---| | `id` | texto | **sim** | A especificação do diagrama **e** a resolução dele: membros, setas — cada uma com as relações que representa — e grupos. Um diagrama seleciona e não lista, então a especificação sozinha não diz quais caixas aparecem. ## `cfour_flow` | Parâmetro | Tipo | Obrigatório | O que faz | |---|---|---|---| | `id` | texto | **sim** | o fluxo | | `caminho` | texto | não | o identificador de um caminho alternativo | Participantes, passos e caminhos alternativos com o desfecho de cada um. Um passo com **`declared: false`** descreve uma conversa para a qual não existe relação declarada no modelo. ## O que toda resposta carrega | Campo | O que é | |---|---| | `procedencia.org` | a organização consultada | | `procedencia.modelagens[]` | repositório, modelagem, *ref*, quando o modelo foi compilado e quando a cópia consultada foi escrita | | `procedencia.naoIndexadas` | as modelagens que existem e não estão indexadas | | `total` e `truncado` | nas ferramentas que listam | ## Erros | Situação | O que acontece | |---|---| | identificador que não existe no que você pode ler | erro dizendo isso | | identificador que existe em mais de uma modelagem | erro pedindo para dizer qual, listando as candidatas | | falta um campo obrigatório | erro nomeando o campo | | corpo acima de 32 KB | recusado antes de ser interpretado | | `GET /mcp` autenticado | 405 — o servidor atende `POST` | | qualquer chamada sem credencial | **401 da borda**, com `WWW-Authenticate` apontando para o metadado do recurso. A função nem é invocada | # Quando algo dá errado Os problemas mais comuns do cfourdev, por sintoma — a causa provável e como resolver. Cada caso abaixo traz **sintoma**, **causa provável** e **como resolver**. ## Encontrar a modelagem ### "registry: há N modelagens e nenhuma marcada como active" **Causa.** Existe mais de uma modelagem registrada e nada diz qual abrir. **Resolver.** Escolha uma, de um destes jeitos: ```sh cfour check --modelagem reservas # só desta vez cfour modelagem use reservas # grava `active:` no cfour.yaml export C4_MODELAGEM=reservas # para a sessão ``` ### "modelagem desconhecida: ..." **Causa.** O identificador não está no `cfour.yaml`. **Resolver.** `cfour modelagem list` mostra os registrados. ### Um comando não acha nada, e você está no repositório certo **Causa.** Não há `cfour.yaml` acima do diretório atual — a ferramenta sobe a árvore até achar um, e para aí. **Resolver.** `cfour init` na raiz do repositório, ou aponte uma árvore avulsa com `cfour check --root ./caminho/model`. ## O modelo não valida ### "referência inexistente ..." **Causa.** Um `parent`, `from`, `to`, `scope`, `subject`, `target` ou um seletor `ref` aponta para uma caixa que não existe — quase sempre um erro de digitação, ou uma referência sem barra tentando alcançar outro projeto. **Resolver.** Lembre da regra: **sem barra procura o projeto que declara e depois `shared/`**. Para atravessar projeto, qualifique: `reservas/api`. ```sh cfour find api # confere como a caixa se chama de verdade ``` ### "elemento duplicado: ..." **Causa.** Dois documentos declaram o mesmo identificador no mesmo projeto. A mensagem diz em qual arquivo o primeiro foi declarado. **Resolver.** Renomeie um dos dois, ou mova-o para outro projeto. ### "id inválido ..." **Causa.** O identificador tem um caractere que o formato não aceita. São permitidos letras, números, ponto, hífen e sublinhado, começando com letra ou número. **A barra é reservada** — ela separa projeto de identificador. ### "ciclo de contenção: ..." **Causa.** Um `parent` fecha um laço: A é filho de B, que é filho de A. **Resolver.** Quebre o laço. Enquanto ele existir, os membros são tratados como raiz — ou seja, aparecem como sistemas. ### "YAML inválido: ..." **Causa.** Indentação, dois-pontos dentro de um valor sem aspas, ou tabulação. **Resolver.** Cerque com aspas todo valor que contenha `:` ou comece com um caractere especial. Nunca use tabulação em YAML. ## O desenho não é o esperado ### O diagrama aparece vazio **Sintoma.** O `cfour check` avisa: "o diagrama X não desenha nenhuma caixa". **Causa.** Nenhum seletor casou. Um `tag:` escrito errado, um `scope` para uma caixa sem filhos, ou um `where` que filtrou tudo. **Resolver.** ```sh cfour diagram show --resolved ``` Ele diz o que entrou e por quê — e, quando nada entrou, mostra os seletores que você escreveu para você compará-los com o modelo. ### Uma caixa que deveria aparecer não aparece **Causa mais comum.** O `scope` mostra apenas os **filhos diretos**. Um neto não entra. **Resolver.** Use `include: [{descendants: }]`, com `depth` se quiser limitar. **Segunda causa.** Um `exclude` ou um `where` a tirou. ### Duas setas paralelas entre as mesmas caixas **Causa.** A mesma integração foi declarada em dois níveis: `api → banco` e `repositorio → banco`. O diagrama de containers desenha a declarada **e** a derivada. **Resolver.** Apague a versão mais geral. Uma seta é escrita uma vez, no nível mais fino que você conhece — veja [Relações](doc:modelando/relacoes). ### "X tem N caixas dentro e nenhum diagrama" **Causa.** Você criou filhos e não criou o diagrama que os mostra. O leitor nunca inventa uma visão, então aquele conteúdo existe no modelo e ninguém consegue vê-lo. **Resolver.** Escreva o diagrama: ```sh cfour diagram add containers --scope --level container --relations auto ``` ### "groupBy: tag:... não existe mais" **Causa.** Agrupar exige valor único, e uma caixa pode ter várias etiquetas. **Resolver.** Agrupe por metadado (`groupBy: meta.`), ou escreva os grupos à mão com `match: {tag: ...}`. Veja [Grupos](doc:modelando/grupos). ### Um passo do fluxo aparece marcado **Sintoma.** O aviso diz "usa uma seta não declarada". **Causa.** O fluxo descreve uma conversa que o modelo não declara. **Isso pode ser a resposta certa**: o fluxo acabou de encontrar um buraco na estrutura. **Resolver.** Ou declare a relação, ou aceite a marca. Três casos nunca avisam: contenção, chamada de uma caixa para ela mesma, e a resposta a uma seta declarada. ## Autenticação e publicação ### "nenhuma chave guardada" **Resolver.** ```sh cfour login --key c4_xxxxxxxx_yyyyyyyyyyyy # na sua máquina export CFOUR_KEY=c4_... # em CI ``` ### O push foi para o repositório errado **Causa.** Uma máquina com várias chaves usou a chave padrão, e não a deste repositório. **Resolver.** ```sh cfour keys # qual vale aqui, e por quê cfour use # liga este repositório a outra chave ``` O vínculo usa o campo `id:` do `cfour.yaml`. Se o seu registro não tem esse campo, o `cfour login` o acrescenta. ### "publicar em 'main' exige admin nesta organização" **Causa.** A *ref* padrão é do admin. **Resolver.** Publique em outra *ref* — o preview vale para qualquer membro — ou peça a um admin. ```sh cfour push --ref minha-branch ``` ### "'main' foi publicada por outra pessoa" **Causa.** Outra pessoa publicou naquela *ref*, e a plataforma recusa sobrescrever o trabalho dela. **Resolver.** Publique em outra *ref*, ou peça a um admin — um admin passa. ### "esta chave de publicação vence em N dia(s)" **Causa.** Toda chave vence. O aviso aparece nos 14 dias anteriores. **Resolver.** Gere outra na tela do repositório, troque o segredo onde ela é usada, e revogue a antiga. ### "a chave pertence a quem não é mais membro desta organização" **Causa.** Quem criou a chave foi removido. **Resolver.** Gere uma chave nova, com uma pessoa que seja membro. ### "este repositório é privado: publicar nele exige admin" **Causa.** O repositório virou privado, e isso revoga também a escrita de quem não é admin. ### "não foi possível determinar a ref" **Causa.** *HEAD* destacado — comum em CI — ou fora de um repositório Git. **Resolver.** `cfour push --ref `. ### "nenhuma modelagem para publicar" **Causa.** Nenhuma está com `status: active`, ou todas moram fora do repositório. **Resolver.** A saída diz o motivo de cada uma pulada. `--all` inclui as puladas por status; uma modelagem fora do repositório **nunca** é publicada. ### "bundle grande demais" ou "passaria de 10 MB publicados" **Resolver.** Remova uma *ref* antiga pela tela do repositório. Um preview expira sozinho em 30 dias. Veja [Limites](doc:referencia/limites). ## O leitor local ### "host não autorizado" ou "origem não autorizada" (403) **Causa.** O `cfour serve` confere `Host` e `Origin` em toda requisição de dados, contra reassociação de DNS e requisição forjada. **Resolver.** Abra pelo endereço que ele imprimiu. Para expor na rede, use `--host ` — o endereço passado passa a ser aceito. ### "o viewer não foi encontrado em ..." **Causa.** A ferramenta está sendo executada a partir do repositório de desenvolvimento, sem o leitor construído. **Resolver.** Instale pelo npm (`npm i -g cfour-cli`); o pacote traz o leitor dentro. ### O desenho não mudou depois de salvar o YAML **Resolver.** Recarregue a página. Se persistir, rode `cfour check`: um erro de carregamento mantém a versão anterior. ## Servidor MCP ### O cliente diz que não suporta registro dinâmico de cliente **Causa.** É verdade: o servidor **não** faz registro dinâmico, e o `client_id` tem de chegar por configuração. **Resolver.** Passe o `client_id` e a porta de retorno explicitamente — veja [O servidor MCP](doc:agentes). ### O login falha com erro de endereço de retorno **Causa.** O servidor de autorização casa a URL de retorno **exata**: esquema, host, porta **e caminho**. Um cliente que abra o laço local numa porta aleatória não conecta. **Resolver.** Fixe a porta em `33418`. ### A busca não acha nada, e você sabe que existe **Causa provável.** O vocabulário. Filtrar por `risco` numa modelagem que usa `risk` devolve zero, e zero parece uma resposta. **Resolver.** Chame `cfour_facets` antes de filtrar. Ela lista as etiquetas, as chaves de metadado e os tipos de nota que existem ali. **Segunda causa.** A modelagem não está indexada — porque passou do teto de indexação, ou porque a publicação foi agora. `cfour_catalog` diz o estado de cada uma, e toda resposta carrega a procedência. ### "este recorte tem mais de 10.000 itens indexados" **Resolver.** Informe `repo` ou `modelagem` na chamada. ## Nada acima resolveu ```sh cfour check --json # o relatório inteiro, estruturado cfour check --inventory # + o inventário do modelo cfour help formato # as regras do formato, offline ```