Pular para conteúdo

Constituição da Documentação e Engenharia

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-10-02

Preâmbulo

Esta constituição define o piso da documentação, da engenharia e da plataforma da X-Adm: o que se documenta, para quem, qual o mínimo, e as regras que todo repo da casa segue. Cada regra tem um dono; aqui ficam os princípios e os pisos, uma a três frases por regra, com link para o dono do detalhe.

Fonte O que contém
Constituição (esta página) princípios e pisos; nunca mecânica, nunca estado de entrega
Normas derivadas (Engenharia, Infraestrutura, Plataforma) a regra que se executa e se verifica, com âncora estável
Decisão (ADR) do central o porquê de uma escolha, como retrato imutável
Skills e templates o como: ordem, comandos, perguntas; a regra entra por link
Toolchain (validadores e guardas) a cobrança; cada guarda cita a regra que implementa
Manifesto a única lista de artefatos do kit, com perfis e stacks por entrada
CHANGELOG do módulo e backlog a mudança de cada versão e o trabalho em andamento

Precedência: constituição > ADR do central > norma derivada > template > doc do app. ADR que muda uma regra desta página a altera no mesmo PR; conflito achado é bug do nível inferior.

A norma tem versão própria, separada da versão do kit e da do site: ver Versões.

Princípios

Documentação perto do código

A doc mora no docs/ do repositório do próprio projeto e muda no mesmo PR que muda o comportamento. Doc longe do código morre.

Documentar interfaces, decisões e uso

O código diz o quê; a doc serve para por quê (decisões), como integrar (contratos) e como usar (quem não escreveu). O que se infere do código não vai para a doc: vira mentira no primeiro refactor.

Docs as code

Markdown versionado no Git é a fonte da verdade. Documento gerado (o site, o .docx/PDF de saída) nunca é editado à mão nem commitado; as exceções são o pré-projeto, que pode ir em .docx, e o badge de cobertura, que o e2e local grava no repo porque a CI não o reproduz (CI e testes). Asset de tooling (o xadm.css, o .docx de referência de estilo, o logo) é insumo do gerador e se versiona como template — receita em Exportar para .docx.

Decisão é registro; referência é viva

Decisão e etapa de projeto são retratos datados: não se reescrevem, superam-se por outro registro. Manual, runbook e referência têm responsavel: e refletem a realidade — referência desatualizada é bug. Fato incidental errado num registro se corrige no lugar, com > **Correção AAAA-MM-DD:** …; premissa errada que sustentava a decisão pede decisão nova. Nota datada só em registro; referência viva corrige sem nota.

Enxuto por padrão

Doc de projeto curto; decisão de cerca de uma página. Seção vazia não existe.

Migração oportunista

Doc que não segue o padrão migra quando é tocada; projeto novo nasce no padrão. Adiar trabalho que o padrão recomenda é decisão declarada no fechamento, nunca silêncio (REGRA Nº 3); antes da primeira publicação, renomear custa zero e se faz na hora.

Consulta e compreensão

A doc serve quem busca um fato (slug estável, cada ## responde uma pergunta, vocabulário controlado) e quem quer entender o sistema lendo de cima a baixo — o livro. Folha endereçável sozinha não ensina o todo.

Português do Brasil

Toda a documentação é escrita em português do Brasil.

Duas fontes da verdade: o código e docs/

Tudo o mais é transitório ou roteador.

  • Andaime (spec, plano, prompt) vive em .ia/NNN-*.md, fora de docs/; ao concluir, o durável vai para docs/.
  • Segredo nunca entra no Git, nem no andaime.
  • Um dono por fato: dentro de docs/, as outras páginas linkam ou embutem (--8<--), nunca copiam.
  • Fato de outro repo chega por link ou por importação no build; publicá-lo é obrigação do repo onde ele é verdade — Publicar docs.

Níveis de documentação

Nível Conteúdo Audiência Onde vive Formato
1. Pré-projeto estudo de caso e regras de negócio: go / no-go diretoria docs/pre-projeto/ .docx ou Markdown + Mermaid
2. Projeto o desenho, antes de programar, e o livro do estado atual quem implementa e quem mantém docs/projeto/ Markdown + Mermaid + frontmatter
3. Decisões o que foi decidido, e por quê quem implementa e quem mantém docs/decisoes/ Markdown + frontmatter
4. Dev como o código se organiza e como rodar; referência gerada dev de manutenção docs/dev/; Javadoc/dartdoc em docs/dev/api/; OpenAPI em docs/public/api/ Markdown + frontmatter; referência gerada no CI de docs, opt-in por app
5. Operação runbooks: deploy, recuperação, operação destrutiva, config de operador dev e ops da X-Adm docs/operacao/ Markdown + frontmatter
6. Manual passo a passo com prints usuário final e suporte docs/public/manual/ Markdown, imagens em docs/public/img/

Operação é operar (pressupõe acesso a repo e infra); manual é usar (sem jargão, sem nome de tabela).

  • Pré-projeto: problema em uma frase, regras de negócio, clientes impactados, esforço em faixa (S/M/L/XL), riscos, alternativas e recomendação — de 3 a 6 páginas.
  • Etapa de projeto: tecnicamente completa para o seu escopo — um dev que nunca viu o código implementa o que a etapa introduz a partir dela e das etapas que ela referencia. O que outra etapa já desenhou se linka; só se reescreve o que esta etapa altera. Molde e seções em Templates.
  • Decisão: Contexto · Decisão · Consequências · Alternativas realmente deliberadas. Nasce rascunho e vira aprovado na revisão do PR; decisão já em vigor quando registrada nasce aprovado.
  • Dev: obrigatório em repo com código — docs/dev/guia-do-codigo.md (como o código se organiza) e docs/dev/como-rodar.md (como rodar), linkados do README. A referência de API é gerada pelo CI de docs, nunca pelo build do app, e é opt-in: o app que não liga a geração não linka dev/api/ — link para referência que o pipeline não gera é 404.
  • Runbook: O que é · Quando usar · Pré-requisitos · Passos · Verificação · Reversão; operação destrutiva abre com aviso. Um dev que nunca operou o app executa só seguindo o documento. As regras de reversão, verificação e contrato externo, e o molde de implantação, estão em Templates.
  • Config de operador e diagnóstico de algo que roda sozinho vivem num operacao/<nome>.md curto, linkado da decisão — não num runbook que repete o desenho.
  • Manual: screenshot é regenerável, com tooling em scripts/screenshots/ e PNG em docs/public/img/ — receita em Screenshots do manual.

Livro, Resumo e nav

A Documentação Completa é um esqueleto autorado em docs/projeto/index.md que mostra o sistema como ele é hoje, numa ordem de raciocínio que termina nos contratos públicos:

  1. Capa: figura de topologia e fluxos principais, com legenda e, para cada fluxo, como acompanhar se ele rodou ou falhou.
  2. Contexto e problema, com o que está fora do escopo.
  3. Dados de entrada e suas regras.
  4. Modelo de dados — embute projeto/modelagem.md.
  5. Mapeamento entrada ↔ dados — pode embutir projeto/mapeamento.md.
  6. Fluxos e processamento, com a arquitetura interna.
  7. Conceitos transversais e configuração do projeto.
  8. Contratos públicos e API.
  9. Apêndice: histórico de etapas e decisões, injetado pelo build.

O livro não reescreve o que tem fonte (modelo, OpenAPI, histórico): embute. O humano escreve o fio narrativo e o porquê; o agente redige o que consegue ancorar nas fontes e marca o resto para o humano. Os marcadores e o molde estão em Templates. O deploy não entra no livro: é procedimento, e mora em operacao/.

Resumo Executivo é a home do app: o problema e como se resolve em um ou dois parágrafos sem jargão, terminando no livro. O marcador <!-- etapas --> injeta o que já foi entregue e o que está planejado, a partir do entregue: de cada etapa.

Ordem do nav (obrigatória): Resumo → Mudanças → Pré-projeto → Projeto → Operação → Dev → Público → Etapas → Decisões → Glossário. Desvio que o domínio do app justifique é decisão declarada. Projeto é a especificação (o livro); Etapas é a execução ao longo do tempo.

Repo e frontmatter

meu-repo/
├── README.md                  # o que é o repo, com links para docs/dev/
├── Dockerfile                 # app deployável como imagem (buildada pelo pipeline.yml)
├── .dockerignore
├── docs/                      # privado por padrão
│   ├── app.json               # identidade, perfil, versões da norma e do kit
│   ├── index.md               # Resumo Executivo
│   ├── pre-projeto/
│   ├── projeto/               # index.md = livro; modelagem.md; etapas NN-titulo.md
│   ├── decisoes/              # NNNN-titulo.md
│   ├── dev/                   # guia-do-codigo.md, como-rodar.md; api/ gerado
│   ├── operacao/
│   ├── public/                # público: index, manual/, img/, api/
│   └── anexos/                # apoio interno, com README; privado/ fica fora do build
├── scripts/                   # tooling de dev e ops; scripts/sql/ para SQL que não é dado
└── .github/workflows/pipeline.yml

App deployável leva Dockerfile e .dockerignore desde o primeiro commit de código, derivados dos templates, junto do .gitattributes da stack — é neles que vive o health check obrigatório. Repo que não deploya imagem (lib, CLI distribuído como artefato) não os tem.

Perfis de repo

Todo repo no loop desta constituição tem docs/app.json com o campo perfil:

  • app (padrão, quando o campo falta): server Micronaut, Flutter web, CLI on-prem, serviço auxiliar. Carrega o kit completo.
  • config: stack de serviço self-hosted (as stacks PowerSync) — app.json mínimo, regras de IA, hook, skills, VERSION + CHANGELOG e o pipeline-config.yml. Não publica site.
  • lib: o xadm-commons — app.json mínimo com toolchain, hook, skills e checkstyle; o pipeline, a /xadm-release e o índice de CHANGELOGs são customização local declarada (Bibliotecas da casa).

O que cada perfil e stack recebe está no manifesto (regras de bump e uso em Versionamento), não em prosa: a /xadm-docs filtra pelo dado. Cada página de engenharia abre com "Aplica-se a: …".

Frontmatter

Todo .md publicado leva frontmatter, exceto os fragmentos embutidos por --8<-- e as páginas-índice que o validador lista. Esta seção é a dona dos campos:

---
titulo: "..."
tipo: projeto | decisao | dev | operacao | manual | livro
status: rascunho | em-revisao | aprovado | obsoleto
responsavel: "Nome <email>"
modulo: combustiveis | transporte | fiscal | financeiro | estoque | compras | vendas | integracao | comum
cliente: "..."          # só em app de cliente
atualizado: AAAA-MM-DD
decidido_em: AAAA-MM-DD # decisão aprovada: quando foi tomada
entregue: true | false  # etapa: a feature foi entregue (independe do status do doc)
entrega: "..."          # etapa: frase de negócio para o Resumo Executivo
superado-por: "NNNN"    # decisão obsoleta
supersede: "NNNN"       # decisão que substitui outra
tags: [...]
---
  • responsavel: é obrigatório e responde pelo conteúdo; doc sem ele não chega a aprovado.
  • decidido_em: é obrigatório em decisão aprovado; entregue: é obrigatório em toda etapa (diversos.md e o livro são isentos).
  • Id de decisão vai entre aspas: sem elas o YAML lê o zero à esquerda como octal.
  • tipo: livro é o projeto/index.md, sem modulo:; modulo é enum fechado (módulo novo = PR no central) e app de cliente sem módulo de negócio usa integracao.

Convenções de doc

  • Abrangência: app da X-Adm (produto, todos os clientes do módulo usam) ou app de cliente (sob medida, com cliente: no frontmatter).
  • Nomes de arquivo: etapa projeto/NN-titulo-curto.md (duas casas, sem ano); etapa avulsa em projeto/diversos.md; decisão NNNN-titulo-curto.md, sequencial por repo.
  • Slug estável: o nome do arquivo é o ID público da página; renomear exige redirect.
  • Caminho × papel: caminho concreto, em code span, só quando é interface (endpoint, tabela compartilhada, env, caminho-contrato); mecânica interna se descreve pelo papel. URL do Forgejo só em página de privado/, e link relativo para fora de docs/ é proibido.
  • Público e privado: docs/ é privado por padrão; o público de cada app é o que está em docs/public/, e página pública não linka para fora dela. privado/ é sempre excluído do build e é onde fica dado real de cliente.
  • Massa de dados: planilha, dump e banco são proibidos em docs/ fora de privado/ (o .docx de pré-projeto é a exceção). SQL que não é dado vive em scripts/sql/; a página que precisa mostrá-lo transclui, sem literal de cliente. Detalhe em Publicar docs.
  • Modelo de dados: projeto com banco ou contrato de dados mantém projeto/modelagem.md, o modelo consolidado do estado atual, e toda etapa que evolui o modelo o atualiza no mesmo PR.
  • Fragmento embutido (modelagem.md, mapeamento.md, arquivo-fato) não tem frontmatter e se escreve no nível do embed: os títulos começam em ###.
  • Diagramas: Mermaid inline, fluxograma em TB; o CI de docs linta cada bloco. Figura de capa pode ser SVG autoral com o Mermaid-base junto. Receita em Templates.
  • Glossário: cada repo define em docs/glossario.md o vocabulário do seu domínio e linka termo de outro glossário por URL absoluta.

Engenharia

Como construir mora na área de Engenharia: gate de CI e níveis de teste em CI, gates e testes, versão em runtime e health check em Versionamento, receita por stack nas páginas de cada stack. Aqui ficam os princípios.

  • Libs da casa na corrente. App elegível declara a última versão publicada de cada módulo do xadm-commons que consome (fonte: maven-metadata.xml do registro); atrás da corrente é pendência; abaixo do piso a /xadm-release recusa. Adotar uma versão é migrar no mesmo PR, pelas seções ### Migração do CHANGELOG do módulo — Bibliotecas da casa.
  • Server Micronaut: native por padrão; jar declarado com motivo. O motivo é bloqueio de native registrado em ADR do app, ou host de runtime sem a arquitetura do binário. O app é native se e só se build.targets contém native — 0033.
  • Reflexão sob AOT se auto-gera. Recurso alcançado só por reflexão (views JTE, appender) tem o registro gerado pelo build, nunca listado à mão: lista à mão esquece o item novo e o native serve 404.
  • Comentário de linha ou de bloco é uma linha, só para o porquê que o código não mostra; Javadoc e dartdoc de API seguem o padrão da linguagem e documentam o contrato. A história vai para o commit, o CHANGELOG ou a decisão; armadilha de linguagem ou framework vai para as Armadilhas da página da stack — Stack da casa.
  • UI server-render usa o layout padrão X-Adm (o kit de UI do manifesto, na paleta do xadm.css), inclusive tela de admin. O custom-theme.css é identidade da casa e não se edita por app; o app.css é dos componentes do app — Java/Micronaut.

Plataforma

Central de Apps

O central-backend (central-backend.xadm.biz) é o backend da Central de Apps e da autenticação; o central-ui (central.xadm.biz) é o dashboard. Detalhe em Central de Apps.

  • Setup em build-time. O app declara no app.json o que usa; a /xadm-setup provisiona pelo central-backend e grava de volta o resultado client-grade, que o build embarca. Nada de buscar config no boot.
  • Broker de setup é M2M, autenticado por token de serviço cuja força casa com a exposição do endpoint. A regra de geração do token vive fora de banda, nunca na skill nem em doc publicada.
  • Uma identidade por app: o app_id (kebab, no mesmo namespace dos grants) é o mesmo valor do slug e do projeto de erro; o validador barra a divergência e renomear é migração em duas fases — 0038.
  • Papel: o app declara, o central concede. O app publica o catálogo de papéis (roles-catalog.json) e o central-backend o ingere; o grant é por (cliente, app, subject, role) — 0029.
  • Auth social usa um projeto de identidade só: o token identifica o projeto, não o app, e a autorização por app vem sempre do grant — 0030.
  • Observabilidade é baseline: todo app com release tem rastreamento de erros no GlitchTip.
  • Fronteira de dados: autenticação e autorização no banco do central-backend; domínio e estado de flags no banco do app. cliente_id (chave) ≠ cliente (rótulo); a plataforma escopa pela chave declarada e nunca a deriva do rótulo.
  • Segredo nunca vai em docs/, no app.json (público) nem no bundle.

Plataforma de Integração

Detalhe, taxonomia e transporte em Plataforma de Integração.

  • O ponto de integração é o banco por cliente. A Plataforma de Integração é a cópia fiel do X-Adm nesse banco; o que vem de fora entra por apps específicos, donos das próprias tabelas.
  • Organiza-se por tipo de fluxo de dados, não por cliente: o genérico é único e estável; o que diverge se isola por peça, com deploy independente.
  • Owner-writes: cada tabela do banco tem um dono, que roda o Flyway e escreve; os demais leem. A tabela-espelho modela a entidade do X-Adm, e campo de origem externa entra prefixado, só como rastreabilidade.
  • Transporte padronizado por direção, entrega garantida por fronteira: PowerSync entre o banco e os clientes, REST entre a Plataforma e os apps específicos, e cada travessia com o seu mecanismo de entrega — Entrega garantida.
  • O fio inteiro se prova local: fluxo de integração tem suíte e2e-local, com os apps de verdade e fake só nas bordas.

Entrega

Detalhe em Deploy, Operação no Coolify e Smoke de produção.

  • Build fora do host de produção. A imagem é buildada pelo pipeline.yml, num runner fora do host que serve produção; o Coolify só puxa. Recurso deployável declara limite e reserva de memória.
  • Config de build-time vive onde o CI alcança: ARG com default no git, docs/app.json ou secret do repo; env de runtime fica no recurso. Endereço que o app.json já declara é derivado dele no build, nunca copiado à mão.
  • A tag vX.Y.Z é o release: o pipeline.yml builda os alvos do trailer Deploy: (fallback build.targets) e chama o control-plane. Push em master sem tag só publica o dev/ da doc.
  • O deploy é disparado pelo control-plane: o CI faz POST /api/ci/deploy no central-backend, com token de serviço, e o central dispara o recurso no Coolify. Auto-deploy do Coolify fica desligado; os recursos que o Coolify builda do git estão listados em Deploy.
  • Deploy só com gate verde e release válida. O pipeline não tem caminho que deploye com o gate pulado ou vermelho; emergência é consertar o teste, ou reverter à mão no Coolify apontando a tag imutável.
  • O mapa app → recurso casa pelo slug do artefato que o recurso consome (a imagem; no compose, o repo git), nunca por uuid nem por nome — 0026.
  • Deploy só encerra com smoke verde. Todo app deployável declara smoke.routes no app.json: o /health e uma rota de cada classe de credencial que ele serve. Depois do deploy o CI confere a identidade do que está no ar, as rotas declaradas e a ausência de exceção nova no GlitchTip.
  • A tag imutável <imagem>:<sha>-<target> é a saída de emergência: o registry retém as dez últimas por imagem e alvo, e nunca poda a que está no ar.
  • URL que outro sistema consome aponta o domínio estável do serviço, nunca o de um flavor de build ou de uma instância.
  • Repo de config usa o pipeline-config.yml: gate de config e deploy pelo control-plane com target=compose.

Governança

  • Por documento: o responsavel: responde pelo conteúdo, e o hook do MkDocs mostra status, responsável e data no topo de cada página.
  • No PR: mudou contrato, schema ou fluxo público, a doc correspondente muda no mesmo PR; revisão de doc é parte do code review.

Definição de pronto

Mudou código, o mesmo PR traz:

  1. Teste proporcional ao risco, exercitando a plataforma e o runtime reais; em componente compartilhado o risco se multiplica pelos adotantes — regras em CI, gates e testes.
  2. Doc do estado atual: README, runbook, contrato, livro e screenshot que mentiriam depois da mudança são corrigidos no mesmo PR.
  3. Compatibilidade com o rollback: DDL destrutivo segue expand/contract — a release N não remove o que a N-1 usa —, com o marcador -- destrutivo-ok: no .sql.

Pular qualquer item é decisão declarada no fechamento, nunca silêncio.

Todo repo tem CI que cobra o piso: a doc (Publicar docs), o código (job gate do pipeline.yml, com o contrato de release na tag — CI, gates e testes) e a config (pipeline-config.yml — PowerSync). O do central cobra também a redação da norma, o manifesto e os testes de cada gate.

Versões

  • Três números, três coisas: a norma (o versao: desta página) sobe quando a norma muda — esta página ou qualquer norma derivada, porque é por esse número que a frota detecta a mudança; o kit (arquivo KIT) sobe quando template, script ou skill muda; o site (VERSION) é a release do portal. Regra mais restritiva sem bump da norma é regra que ninguém vê chegar.
  • Versão-base: o docs/app.json de cada repo registra constituicao (a norma que segue) e kit (o kit que sincronizou). É o único lugar do número; o CLAUDE.md aponta para o campo.
  • Kit defasado se re-deriva; norma defasada se re-audita, com aprovação do usuário. Manifesto, regras de bump, aviso de defasagem e validador fresco em Versionamento.

Regras de redação

  • Uma regra, um lugar; os outros linkam com âncora.
  • Presente, sem histórico: a norma não cita episódio, data, número de spec ou de item de backlog, nem versão de release; o porquê vai para a ADR, a mudança para o CHANGELOG.
  • Supersede, não empilha: mudou a norma, o parágrafo se reescreve no mesmo PR.
  • Até três frases por item desta página (regra, porquê, link); mais que isso é receita e vai para a norma derivada. O orçamento desta página é de 500 linhas.
  • Exceção nominal (um app, um recurso em dívida) não mora aqui: fica na norma derivada, com dono.
  • Vocabulário: obrigatório, proibido, opcional. "Padrão" só existe com o mecanismo de exceção definido.
  • Seção se cita pelo nome, com link para a âncora, nunca por número.
  • ADR aprovada só recebe correção de fato incidental, visível; decisão nova é ADR nova com supersede:.

O checa-redacao.py cobra estas regras no núcleo, nas normas derivadas, nas páginas satélite (documentação, transversais, glossário e início) e nos templates do kit.

Regras de IA

Todo repo abre o CLAUDE.md com o bloco canônico de templates/claude-regras.md:

  • REGRA Nº 1 — não decidir sozinho: ambiguidade ou mais de um caminho → opções com uma recomendação e confirmação antes de implementar.
  • REGRA Nº 2 — não commitar nem pushar sozinho: a exceção é a /xadm-release; fora dela o agente entrega a mensagem de commit pronta, sem atribuição de IA.
  • REGRA Nº 3 — deferir é explícito: adiar o que o padrão recomenda se declara no fechamento.

O CLAUDE.md (roteador, com teto de linhas), o .claude/settings.json e o fluxo de trabalho com IA (/x-desenhar → … → /x-documentar) estão em IA e Claude Code e Ferramentas.

Feedback

Quem aplica o padrão e encontra lacuna, ambiguidade ou conflito não contorna localmente: escreve o problema para ser tratado numa sessão do repo central. O texto diz de onde vem (repo, versões da norma e do kit), o que se fazia, o que foi medido e o que é suposição, e aponta a fonte em vez de parafrasear.

Todo fechamento de trabalho traz, junto da mensagem de commit, a linha de feedback, afirmativa: Feedback: nada a reportar ou Feedback: candidato — <o quê>. Sem ela, o passo foi pulado.

No central, o feedback passa por revisão adversarial contra a norma vigente: entra o que corrige, generaliza ou substitui uma regra, reescrita no lugar, e cada aceite mostra o que saiu ou foi fundido; mudança que só acrescenta leva a justificativa escrita no backlog. O que só acrescenta o caso de um repo é remendo e é recusado. Cada ponto volta ao repo como Resposta do central: aceito | já coberto | recusado | pendência — <onde ou por quê>.