Voltar aos manuais

Manual de Código LZR — Engenharia

Versão 1.0 — 2026-06-20. Consolida em um lugar só todo o conteúdo de engenharia que antes vivia espalhado (o Engineering Handbook até v2.8, a central de regras, a pasta de padrões e os modelos de projeto).

O que este manual responde: como eu construo certo. Tudo que é "como eu provo que funciona" mora no Manual de Testes. Tudo que é identidade visual (cores, fontes, componentes) mora no Manual de Design.

Regra de ouro deste acervo: cada regra mora em um lugar só. Quando uma regra depende de outra, ela aponta — nunca copia. Detalhes práticos, exemplos e passo a passo ficam no anexo de receitas.

Quanto deste manual é obrigatório depende do porte do projeto — ver Níveis de Exigência. O piso de qualidade e segurança vale para todos; o rigor extra sobe com o nível.


1. Idioma

CamadaIdioma
Banco de dados (colunas, tabelas)Inglês
Servidor (variáveis, funções, modelos, API)Inglês
Tipos enumerados (status, opções)Inglês
Comentários no códigoInglês
Interface visível pro usuário (rótulos, mensagens)Idioma do país (pt-BR no Brasil)

2. Qualidade de código

  • Tipagem estrita, zero any. strict: true sem exceção. Usar unknown + verificação de tipo quando o tipo não é conhecido.
  • JSDoc obrigatório em todo método público de serviço (descrição + parâmetros).
  • Comentários explicativos onde a lógica não é auto-explicativa: decisões de arquitetura (o porquê), trade-offs, contornos de limitação de biblioteca, e regras de negócio. Não comentar o óbvio (imports, CRUD trivial, código que o nome já explica).
  • Convenções de tipagem e import: imports por caminho atalho (@/...); preferir import de tipo (import type { X }); props de componente tipadas com interface (não type).
  • Mensagens de erro/sucesso vêm de um lugar central — nunca texto fixo solto no código.
  • Nunca console em código de produção — usar o registrador de log central (estruturado: JSON com identificador de rastreio e de cliente).
  • Named exports em componentes e módulos (nunca default), exceto onde o framework exige (page.tsx, layout.tsx, route.ts). Saídas de cada feature reunidas num ponto único (barrel export index.ts).
  • Arquivo grande demais é sinalizado para ser quebrado em pedaços.
  • Não inflar dependências: nunca adicionar biblioteca nova sem verificar se já existe equivalente aprovado na stack.

Toda mudança de lógica nasce com teste. Essa é a lei nº 1 do Manual de Testes — aqui só fica o ponteiro.


3. Estrutura e organização do código

Como o projeto é organizado em pastas. Os princípios valem para qualquer tipo de projeto; as estruturas concretas por tipo (web, servidor, site, app de celular, biblioteca) estão no anexo de receitas.

  1. Organize por funcionalidade, não por tipo de arquivo. A estrutura de pastas deve "gritar" o que o sistema faz (as capacidades de negócio), não a tecnologia. Cada funcionalidade é uma pasta autocontida — sua tela/rota, lógica, dados, testes e tipos juntos. Pastas globais por tipo (uma com todos os componentes, outra com toda a lógica) só servem ao que é genuinamente compartilhado.
  2. Cada coisa perto do que serve (co-localização). Teste, estilo e tipo moram ao lado do que servem — nunca numa pasta-espelho distante. Exceção: testes de ponta a ponta, que cruzam funcionalidades, ficam à parte.
  3. Reuso sobe, nunca atravessa. O que duas funcionalidades usam sobe para a camada compartilhada. Uma funcionalidade não importa direto de outra — a comunicação cruzada passa pela camada de composição.
  4. Fronteiras explícitas, e de preferência verificadas por ferramenta. Deixe claro quem pode depender de quem: as dependências apontam para dentro (a tela não toca o banco direto; passa pela regra de negócio). Onde der, a fronteira vira erro de lint, não só convenção.
  5. Mesma estrutura em todo projeto. Quem abre qualquer projeto LZR já sabe onde cada coisa está. A estrutura-raiz é previsível e padronizada por tipo de projeto.
  6. Nomes previsíveis, árvore rasa, consistência. Evitar aninhamento profundo; nomes que o leitor adivinha. A consistência (ex.: padrão de caixa dos nomes de arquivo) importa mais que a escolha específica.
  7. Cuidado com os "índices de barril" (arquivos que reexportam tudo de uma pasta). Dentro do app, evitar — incham o que é carregado e escondem as dependências reais. São bem-vindos na porta pública de uma biblioteca.

A pasta de roteamento dos frameworks modernos (a que vira URL) é só para rotas — o código de verdade mora nos módulos de funcionalidade, e a rota apenas aponta para a tela.


4. Tolerância zero a erro e aviso

Nada sobe com erro ou aviso pendente — mesmo o que não foi introduzido nesta sessão. Em projeto LZR, quem está codando é responsável por todo problema que aparece, independente de quando entrou. Não existe "pré-existente".

Procedimento ao detectar problema:

  1. Parar a tarefa atual.
  2. Corrigir tudo — não só o arquivo tocado.
  3. Confirmar, em todos os aplicativos do projeto, saída limpa em: auditoria de design, validação de tipos, testes, construção da aplicação, e logs do servidor de desenvolvimento — 0 erro e 0 aviso.
  4. Só então retomar a tarefa original.

Única exceção: suprimir um aviso apenas com marcador explícito e justificativa real (ex.: // ds-audit-ignore: estilos de impressão usam cor fixa). Sem justificativa, não suprime.


5. Como o sistema mostra informação (frontend)

  • Busca de dados sempre pelo padrão de cache do projeto (React Query). Proibido useState + useEffect para carregar dados do servidor. Toda consulta tem chave registrada centralmente; toda escrita é otimista, com desfazer automático em erro. useState só para estado de tela (rascunho, edição, filtro local, efêmero).
  • Botão "voltar" usa o histórico do navegador (router.back()), nunca rota fixa. router.push() é só para navegação intencional (ir a um destino escolhido).
  • Toda listagem é paginada — nunca trazer tudo de uma vez.
  • Formulários usam validação na entrada (React Hook Form + Zod).
  • Componentes do lado do servidor por padrão — só marcar como cliente quando há interatividade real.
  • Notificações usam ícones padronizados, nunca emojis.
  • Componentes pesados e modais entram sob demanda (carregamento tardio).

A aparência (cores, fontes, espaçamento, componentes da biblioteca de UI) é governada pelo Manual de Design, não por este. Aqui fica só o comportamento.


6. Como o sistema guarda e protege os dados (backend)

  • Camada de acesso ao banco separada do fornecedor (padrão repositório em 3 camadas: contrato puro → adaptador concreto → composição). Permite trocar de fornecedor sem reescrever a regra de negócio.
  • Autorização mora na camada de serviço, não no adaptador de dados. A proteção por linha no banco (RLS) é a segunda trava (defesa em profundidade).
  • Toda rota do servidor tem autenticação + verificação de permissão. Endpoint sensível valida escopo/permissão antes de retornar dados.
  • Toda operação de escrita (criar/atualizar/apagar) emite evento.
  • Separação de clientes (multi-cliente): cada cliente só enxerga o que é dele. O acesso total (super-admin) é um papel explícito, nunca a ausência de vínculo. Usuário sem empresa e sem papel de super-admin é bloqueado. Proibido o antipadrão "campo nulo libera acesso" — é brecha entre clientes. Outros perfis (auditor, etc.) recebem papéis específicos filtrados por funcionalidade — nunca acesso total ao banco.
  • Versão na porta de entrada da API — toda rota pública expõe a versão no caminho (/v1/, /v2/). A versão antiga é mantida por tempo suficiente para o cliente migrar.
  • Limite de uso por cliente — toda porta de entrada pública tem limite configurável por cliente (por minuto ou por hora). Quando excede, retorna 429 com cabeçalho informando quando pode tentar de novo.
  • Operação multi-passo é tudo-ou-nada — qualquer sequência de escrita que precisa ser atômica roda dentro de uma transação. Se falhar no meio, desfaz tudo. Nunca estado pela metade.
  • Aviso externo (webhook) é tratado sem repetir o efeito — o processamento de notificações de sistemas externos verifica se aquele evento já foi processado antes de agir. O aviso pode chegar mais de uma vez e o efeito deve acontecer exatamente uma vez.
  • Verificação de saúde — toda aplicação expõe um ponto de verificação que responde se o sistema está funcionando (banco acessível, serviços essenciais respondendo).

A exigência de testar a separação de clientes (cenários obrigatórios, incluindo o usuário órfão bloqueado) está no Manual de Testes §8. Aqui fica a regra de segurança; lá, como provar.


7. Banco de dados

RegraPor quê
Toda tabela tem chave única gerada automaticamente e impossível de adivinharPadronização e segurança
Toda tabela tem proteção de acesso por linha (RLS)Separação entre clientes
Acesso entre clientes só por papel explícito (super-admin), nunca por brecha em campo nuloEvita falha de controle de acesso
Apagar é sempre suave (campo ativo/inativo), nunca apaga de verdadeConformidade legal + recuperação
Toda informação carrega carimbo de criação e de última alteraçãoAuditoria e rastreio
Auditoria é única, central e imutável (ninguém edita nem apaga)Conformidade
Dado nunca em dois lugares (sem armazenamento duplicado)Evita inconsistência
Mudança de estrutura por passos registrados e repetíveisReprodutibilidade
Toda coluna de busca frequente tem índiceEvita varredura completa da tabela a cada consulta
Os tipos do banco são gerados automaticamente a partir do esquemaGarante que o código e o banco nunca divergem na tipagem
Toda mudança de estrutura que apaga ou renomeia coluna exige registro do estado anteriorPermite reverter sem perda de dado

8. Segurança

  • Nunca registrar senha, token, CPF/CNPJ, dado de cartão.
  • Segredos e chaves sempre fora do código. Variável sensível vai apenas no arquivo de ambiente local (.env.local), nunca no arquivo de ambiente compartilhado (.env). Separados por ambiente.
  • Cabeçalhos de segurança configurados.
  • Toda entrada externa (API, formulário, variável de ambiente) é validada antes de usar (Zod).
  • Respostas de erro seguem o padrão RFC 9457.
  • Varredura de dependências — toda atualização de dependência é verificada contra a lista de vulnerabilidades conhecidas. Em projeto de nível Crítico, a varredura roda de forma automatizada a cada nova versão de dependência.
  • Conhecer as categorias clássicas de falha — controle de acesso quebrado, falha de criptografia, injeção, design inseguro, configuração errada, componente vulnerável, autenticação falha, integridade de dados quebrada, registro insuficiente e falsificação de requisição são a referência de revisão de segurança.
  • Processo de resposta a brecha descoberta — ao confirmar uma vulnerabilidade: (1) avaliar o impacto; (2) conter (revogar chave, desabilitar funcionalidade, isolar); (3) corrigir e publicar; (4) notificar o responsável do projeto e, quando a lei exige, o cliente afetado.

9. Vigias automáticos (os guardas)

Rodam no projeto, antes de qualquer mudança subir — valem para qualquer ferramenta (qualquer agente de IA ou dev humano). Quem não segue a regra, é barrado. Vêm prontos no modelo de projeto.

Todo vigia fala — nunca só "falhou". Quando um vigia barra, a mensagem aponta quatro coisas: o quê (qual regra foi quebrada), onde (arquivo e linha exatos), qual manual embasa a regra, e como corrigir (com exemplo concreto). Bloqueio que diz apenas "deu erro" é tratado como defeito do próprio vigia.

VigiaO que faz
Auditoria de designBarra cor crua, etiqueta HTML solta, texto fixo solto, cartão sem ícone, "voltar" com rota fixa — fora da pasta de UI compartilhada
Auditoria de testesBarra mudança de lógica sem teste correspondente
Auditoria de estruturaBarra projeto cuja estrutura-raiz esperada (por tipo) não existe
Auditoria de consistência de dadosBarra escrita do mesmo dado em dois lugares
Formatador de códigoPadroniza estilo automaticamente (não bloqueia, corrige)
Validador de mensagem de mudançaBarra mensagem fora do padrão de commit convencional, sem escopo, com tipo inválido, ou com linha de assunto em maiúscula
Roteiro de qualidade no servidorRoda construção + testes + auditorias + validação de tipos + cobertura antes de mesclar; bloqueia se algo falhar

10. Fluxo de trabalho e entrega

Regimes de trabalho — todo trabalho se enquadra em um de dois:

  • Regime A — Incremento (capacidade nova: função, módulo, feature, integração, banco, segurança): 1 ramo = 1 tarefa = 1 pedido de mudança.
  • Regime B — Onda de polimento (lapidação do que já existe: ajustes visuais, textos, correções miúdas): 1 ramo "onda" = 1 tarefa guarda-chuva com checklist = 1 pedido de mudança. Item miúdo da sessão entra no checklist da onda corrente.

Desempate (nesta ordem): (1) mexeu em banco, segurança ou permissão? → Regime A, sempre. (2) Já existe no código? Sim → B; Não → A.

  • Ramo nomeado <tipo>/<número>-<descrição-curta> (ex.: feat/123-novo-fluxo).
  • Mensagens de mudança em commit convencional com escopo obrigatório (ex.: feat(licitacoes): ...). Título com no máximo 100 caracteres. Tipos: feat, fix, docs, refactor, test, chore e, em serviço, security.
  • Tamanho-alvo: até 400 linhas modificadas (maior, com justificativa).
  • Pedido de mudança fecha a tarefa do seu regime (Closes #N) e tem modelo preenchido obrigatoriamente.
  • Ramo encerrado desaparece assim que a mudança é mesclada — o servidor apaga sozinho.
  • Tempo de vida de um ramo: o alvo é 1 a 3 dias desde a abertura até a mesclagem. Ramo com mais de 3 dias sem atividade recebe investigação.
  • Caminho de emergência (correção urgente): ramo sai diretamente do ramo de produção, com o mínimo necessário, e é mesclado de volta nele e no ramo de desenvolvimento. Não passa pelo fluxo normal, mas exige o mesmo padrão de teste.
  • Estágios de publicação: toda mudança percorre os ambientes na ordem teste local → validação (homologação) → produção. Migração de banco vai antes do código em cada ambiente.

11. Governança das regras (a regra das regras)

Toda criação, edição ou remoção de regra DEVE ser refletida imediatamente em todas as fontes. Checklist de propagação (7 passos):

  1. Versionar — incrementar a versão e registrar no changelog com data.
  2. Propagar para o projeto atual (o atalho do projeto). Não modificar outros projetos — a propagação acontece quando se trabalha em cada um.
  3. Propagar para os arquivos globais (instruções globais do agente + conhecimento global).
  4. Propagar para os sites publicados (manual e design publicados, e a página de personalidade de cada produto ativo).
  5. Propagar para os repositórios de modelo (modelo web, modelo de servidor, configuração compartilhada).
  6. Atualizar referências no código.
  7. Garantir enforcement automático (vigia/teste) quando a regra é verificável, decidindo a severidade: erro (bloqueia) ou aviso (avisa mas permite).

12. Comportamento do agente de IA

Sempre: consultar o Manual de Design antes de criar interface; verificar antes de perguntar (ler/buscar/rodar); avisar antes de operação de efeito colateral; acumular mudanças e gravar junto no fim; seguir o ritual completo em "continuar" e "encerrar".

Nunca: implementar antes de o coder aprovar o plano (salvo autonomia explícita); pular a leitura do design alegando "ajuste simples"; repetir/citar/justificar mensagem de vigia para o coder; tocar em outro projeto sem autorização; usar linguagem fora da stack do projeto; abrir mais de um pedido de mudança pela mesma tarefa; ignorar alerta/erro alegando "pré-existente".


13. Operações que pedem cuidado

Avisar o coder e esperar confirmação antes de: construir a aplicação inteira; trocar de ramo; mexer em peça compartilhada entre projetos; aplicar formatador em massa; apagar arquivo/pasta; forçar envio; desfazer várias mudanças de uma vez; mexer em chave/credencial.


14. Configurações compartilhadas e stack

Os modelos de projeto herdam 4 configurações centralizadas (tipos, lint, formatação, padrão de commit). Para mudar uma regra que afeta todos os projetos, alterar no repositório central correspondente — não duplicar localmente. Override pontual só com motivo documentado.

Ambiente de desenvolvimento padronizado — todo projeto LZR define o ambiente de desenvolvimento como código, via arquivo .devcontainer/devcontainer.json. Isso garante que qualquer pessoa que abre o projeto tem exatamente a mesma versão do Node, o mesmo gerenciador de pacotes, as mesmas ferramentas de linha de comando e o mesmo sistema operacional — eliminando o "na minha máquina funciona".


15. Enxergar o sistema no ar

O código funcionar localmente não é suficiente — o sistema precisa ser observável quando está em produção. Quatro camadas:

  • Registro de funcionamento (log estruturado): toda operação relevante emite um evento com identificador de rastreio e de cliente. Nunca registrar senha, token, dado de cartão ou dado pessoal no log. O log é JSON (não texto livre). console.log cru é proibido em produção.
  • Captura de erro: toda exceção não tratada é capturada e enviada para ferramenta de monitoramento, com identificador de rastreio vinculado ao log. O erro capturado tem contexto suficiente para reproduzir a situação (qual operação, qual entrada — sem dado sensível).
  • Conferência automática após publicar: logo após cada publicação em qualquer ambiente, um passo automático verifica que o sistema responde (ponto de verificação de saúde, fluxo crítico de fumaça). Se falhar, o processo de publicação marca a entrega como problemática e notifica.
  • Alerta por limite: monitora métricas operacionais (taxa de erro, latência, custo de serviços externos) e dispara aviso quando cruza um limite definido. O alerta nomeia o que cruzou o limite, o valor atual e o limite esperado, com ponteiro para onde investigar.

Fronteiras deste manual: testes → Manual de Testes. Identidade visual → Manual de Design.