


Trabalhar em um Monorepo Frontend em TypeScript sem Furar os Limites entre Pacotes
Para quando uma IA altera um frontend modular em TypeScript. Cobre limites entre pacotes e um núcleo sem framework, mudar o estado só pela ação dona dele, onde ficam arquivos e testes, as checagens antes do commit, a ordem de release e as camadas de UI.
Para usar estas regras de IA
## Cruze os Limites entre Pacotes Só pelos Exports Públicos
- Em um workspace com múltiplos pacotes, dê a cada pacote uma única responsabilidade e cruze limites apenas através dos exports públicos do pacote; nunca importe estruturas internas de outro pacote a partir do código da aplicação, pois importações internas acoplam quem chama à estrutura privada e quebram quando ela muda. Reforce os limites com lint automatizado e verificações de arquitetura em vez de depender só de revisão, e onde não existir um local correto, crie um deliberadamente e atualize as convenções documentadas.
- Mantenha o núcleo compartilhado agnóstico de framework e livre do DOM do navegador: coloque os bindings de framework de UI e a projeção DOM/CSS em camadas dedicadas, e carregue dependências pesadas de runtime, como módulos WASM ou SDKs grandes, a partir de um único módulo central que entrega uma instância injetada a quem chama, em vez de importá-las de forma improvisada em cada ponto de uso.
- Não crie arquivos-shim de reexportação cujo único propósito seja repassar a API de outro pacote; importe o pacote proprietário diretamente nos pontos de uso. Um barrel de compatibilidade pode reexportar um proprietário apenas para preservar uma API pública já estabelecida.
- Prefira exports de subcaminho estreitos e específicos a um único barrel genérico quando importações menores deixarem mais clara a intenção da dependência.
## Mude o Estado Compartilhado Só pela Ação que É Dona Dele
- Monte subsistemas grandes a partir de um contexto compartilhado somado a módulos de ação específicos de domínio (viewport, seleção, histórico, estrutura e assim por diante), em vez de um único arquivo que só cresce. Antes de adicionar comportamento, examine a pasta existente e os padrões próximos e coloque a mudança no módulo de domínio correspondente mais próximo; não empilhe lógica sem relação no arquivo que por acaso já está aberto.
- Encaminhe toda mutação de estado através do setter ou da ação proprietária, para que os efeitos colaterais — eventos, agrupamento de undo, atualizações derivadas — disparem de forma consistente. Nunca atribua valores diretamente a campos de estado compartilhado, ou esses efeitos deixam de rodar silenciosamente, e não mantenha estado mutável em nível de módulo dentro de componentes; guarde o estado compartilhado na store.
- Exponha mudanças por meio de um sistema de eventos tipado e faça os assinantes reagirem a eventos em vez de fazer polling. Mantenha os módulos de domínio compartilhando estado através do objeto de contexto, e não importando código de aplicação ou de framework.
- Wrappers de aplicação podem adicionar estado reativo, persistência e I/O de plataforma ao redor do núcleo, mas o núcleo permanece agnóstico de framework; proteja qualquer API do navegador em código compartilhado com uma verificação explícita em tempo de execução antes do uso.
## Proíba any e Asserções Non-Null em TypeScript
- Proíba `any`: use tipos precisos, generics e declaration merging. Proíba asserções non-null: use guards, optional chaining e nullish coalescing. As duas medidas mantêm o verificador de tipos capaz de capturar erros reais em vez de mascará-los.
- Prefira union types precisos a primitivos genéricos — uma pequena union de string literals em vez de `number | string | null` — e não defina um tipo inline quando já existir um tipo compartilhado nomeado; importe-o e reutilize-o.
- Nomeie constantes repetidas ou usadas entre várias features em um módulo de constantes compartilhado, em vez de duplicar literais pela base de código.
- Nunca use uma fonte de aleatoriedade não criptográfica para identificadores ou qualquer coisa relevante para segurança; use um RNG criptográfico em todos os lugares. Faça cópia profunda de objetos aninhados com um structured clone, nunca com um spread raso, ao mutar dados aninhados.
## Organize Pastas por Domínio e Ponha Cada Tipo de Teste em Seu Lugar
- Organize por namespace de domínio em vez de cerimônia estrutural profunda, e mantenha serviços de aplicação, views de rota ou layout, e UI em suas próprias áreas de nível superior.
- Use uma subpasta para um domínio com múltiplos arquivos, em vez de arquivos irmãos compartilhando um prefixo repetido. Quando um domínio ganhar seu segundo arquivo, crie a pasta imediatamente em vez de prefixar os nomes — prefira `selection/hit-test` a `selection-hit-test`.
- Mantenha nomes de arquivo de entrypoint convencionais como `index`, `types` e `context` em minúsculas, e siga a convenção de capitalização do ecossistema para arquivos de componente. Não posicione código ou testes de forma improvisada; se não existir um local adequado, crie um deliberadamente e documente-o.
- Mantenha o posicionamento de testes rígido e baseado em localização: coloque cada tipo de teste em seu diretório estabelecido (end-to-end, integração, unitário, helpers compartilhados, por pacote). Comportamento visível ao usuário pertence aos testes end-to-end; asserções de estado interno e de dados pertencem aos testes unitários. Nunca faça commit de arquivos de teste temporários ou de profiling.
## Use uma Biblioteca Existente em Vez de Escrever o Mesmo Código à Mão
- Não reimplemente na mão o que uma dependência já faz. Verifique primeiro as dependências existentes; se nenhuma servir, adote uma biblioteca de qualidade em vez de embutir uma implementação própria — por exemplo, use uma biblioteca de diff para diffs unificados e uma biblioteca de cores para cálculos de cor, não um loop escrito à mão.
- Antes de construir UI, controles ou composables personalizados, leia a documentação oficial da dependência em vez de adivinhar a partir do uso local, preferindo pontos de entrada de documentação legíveis por máquina quando oferecidos. Se a documentação oficial contradisser os padrões locais, siga as APIs oficiais atuais e atualize os wrappers locais deliberadamente.
- Coloque programas e helpers de manutenção em uma área dedicada de ferramentas organizada por domínio, cada um com testes focados, em vez de scripts improvisados na raiz. Reserve uma área de scripts apenas para pequenos shims de entrypoint de compatibilidade que importam da área de ferramentas, mantendo a lógica de implementação fora dos shims.
- Inclua testes das ferramentas mais cobertura de lint e formatação nas verificações padrão, para que a área de ferramentas seja mantida no mesmo nível de exigência do código de produto.
## Passe Todas as Checagens de Qualidade Antes do Commit e Use Conventional Commits
- Execute o gate de qualidade completo antes de fazer commit e novamente antes de abrir a mudança para revisão: lint consciente de tipos e typecheck com zero erros, o formatador com ordenação de imports, detecção de copiar-e-colar e duplicação com zero clones, e as suítes unitárias e end-to-end relevantes.
- Faça autorrevisão antes de submeter: se a duplicação aumentar, extraia helpers compartilhados ou reutilize tipos existentes; remova definições de tipo inline que duplicam tipos nomeados e qualquer lógica copiada e colada; mantenha os arquivos abaixo de poucas centenas de linhas e divida por domínio quando crescerem.
- Escreva mensagens de commit no formato Conventional Commits (`feat`, `fix`, `refactor`, `perf`, `docs`, `test`, `build`, `ci`, `chore`): uma primeira linha curta, no imperativo, com escopo opcional e tipo em minúsculas, e a justificativa no corpo, com cada linha do corpo começando com uma palavra maiúscula.
- Preserve a capitalização de nomes de produto e siglas nos assuntos e corpos das mensagens, em vez de achatar siglas para prosa em minúsculas, e use o escopo mais estreito e honesto possível — ou omita o escopo quando a mudança abranger áreas sem relação entre si.
## Faça Releases numa Ordem Fixa e Mantenha o Changelog Atualizado
- Siga um procedimento de release fixo e ordenado: incremente a versão em todos os arquivos que a carregam, mova as entradas do changelog de uma seção "Unreleased" para um novo cabeçalho de versão datado, faça o commit com uma mensagem de release e, então, crie e envie (push) a tag. Confirme que quaisquer segredos de assinatura ou de release existem antes de criar a tag.
- Trate o workflow de build e release como a única fonte de verdade para empacotamento e publicação, e mantenha qualquer lista duplicada de pacotes sincronizada com ele. Condicione os deploys de produção a tags de release ou a disparo manual explícito, nunca a pushes comuns na branch padrão, para que o lançamento continue sendo intencional.
- Mantenha a documentação atualizada: atualize a seção "Unreleased" do changelog e a documentação voltada ao usuário sempre que o comportamento mudar, e atualize a referência para contribuidores ou agentes quando a arquitetura ou as convenções mudarem.
- Mantenha a documentação publicada livre de planos especulativos ou de implementação interna — coloque planos temporários em uma área de rascunho ignorada e destile a direção duradoura em documentos canônicos — e não crie cópias localizadas de placeholder; direcione a navegação localizada para a página canônica até que exista uma tradução real.
## Não Deixe Componentes Base de UI Compartilhados Importarem Código do App
- Separe uma camada de primitivos de UI compartilhada e reutilizável das camadas de feature e de shell. Primitivos compartilhados e controles estilizados de baixo nível não devem importar serviços de aplicação, stores ou painéis de feature; os componentes de feature são donos de seus controles específicos de feature.
- Resolva o estilo por meio de variantes de tema estáticas e tipadas, definidas em um único lugar e mescladas por instância, em vez de espalhar ramificações condicionais de classes utilitárias ou props de classe avulsas por slot. Vincule o estado visual por meio de atributos de dados semânticos e resolva as variantes tipadas no script.
- Para localizadores de teste, prefira role, label e texto voltados ao usuário; exponha atributos semânticos com escopo definido para identidade, e reserve test ids dedicados para limites de integração raros, em vez de fabricar ids globalmente únicos dentro de componentes compartilhados.
- Não passe setters ou ações imperativas através de slots, a menos que um componente seja explicitamente um primitivo renderless; prefira model bindings, eventos emitidos e props normais. Use uma biblioteca de ícones em vez de SVG inline bruto ou símbolos Unicode, e mantenha os labels semânticos renderizando os atalhos de teclado a partir de metadados de comando, em vez de embutir o texto do atalho diretamente nos labels.
