> For the complete documentation index, see [llms.txt](https://docs.ipcheck.ing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ipcheck.ing/developer/pt-br/development/coding-conventions.md).

# Convenções de Código

Regras somente em JavaScript, estilo de funções, padrões de comentários e convenções de logging do backend.

Estas são as regras desta base de código. Elas não são preferências de estilo para discutir em cada pull request — são o que os revisores verificam e o que mantém um projeto com dois runtimes e um conjunto crescente de linguagens legível.

## Idioma

{% hint style="warning" %}
**Somente JavaScript. Nada de TypeScript.**
{% endhint %}

Os novos arquivos são `.js` ou `.vue`. Sem `lang="ts"` em um `<script setup>` bloco, sem `.ts` módulos, sem migração incremental para TypeScript. Um PR que introduzir TypeScript será solicitado a removê-lo.

Comentários de código, mensagens de commit e documentação do repositório são escritos em **inglês**. Os pacotes de locale obviamente carregam seu próprio idioma.

## Funções

Funções novas e reescritas usam **`const` sintaxe de arrow**:

{% code title="o estilo da casa" %}

```js
const isValidMAC = (address) => {
    const normalized = address.replace(/[:-]/g, '');
    return normalized.length === 12 && /^[0-9A-Fa-f]+$/.test(normalized);
};

const loadSecurityChecklist = async () => { /* … */ };
```

{% endcode %}

Duas ressalvas:

* **Métodos de objeto mantêm a sintaxe abreviada.** `{ status(code) { … } }` permanece como está.
* **Consts de arrow não sofrem hoisting.** Declare-as antes do código que as chama.

Isso se aplica ao código que você escreve ou reescreve. Não **faça** conversões em massa `de funções` existentes — um diff cheio de ruído de estilo não relacionado é mais difícil de revisar do que o recurso que ele esconde.

## Comentários

Três regras, em ordem de importância:

1. **Todo novo arquivo começa com um comentário de cabeçalho que declara seu propósito.** Para um handler de API, isso significa sua rota e o que ele faz. É assim que o restante da base de código pode ser navegado sem abrir cada arquivo — a documentação em nível de diretório termina deliberadamente em "leia os comentários de cabeçalho".
2. **Templates grandes e funções grandes carregam comentários de bloco por região significativa.** Um template de 400 linhas `.vue` deve informar onde termina a área de entrada e onde começa a área de resultado.
3. **Comentários descrevem o código como ele é agora.** Sem narrativa de changelog: nada de "antes fazíamos X", nada de "isso corrige o bug em que…". O histórico do Git cobre o passado. Um comentário que explica *por que* uma escolha não óbvia foi feita é valioso; um comentário que narra a edição que o produziu é ruído.

Um comentário deve ser mais curto que o código que ele explica.

## Convenções de frontend

Arquitetura completa em [Frontend](/developer/pt-br/architecture/frontend.md). As regras que você precisa ao escrever código:

* **Composition API, `<script setup>`, em todo lugar.** Sem Options API.
* **Alias de caminho `@` → `frontend/`.** Importe como `@/utils/valid-ip.js`, nunca com um monte de `../`.
* **shadcn-vue primeiro.** Verifique `frontend/components/ui/` para um primitivo existente, depois o catálogo shadcn-vue em busca de um para copiar. Tailwind feito na mão é o último recurso.
* **Somente tokens de design semânticos.** `bg-info`, `bg-action`, `text-muted-foreground`, e similares — os tokens definem o tema por si mesmos. Nunca escreva `dark:` utilitários de pares duplos.
* **`console.*` é aceitável no frontend.** É proibido apenas no backend (veja abaixo).

### Comunicação entre componentes

Três mecanismos, cada um com uma função:

* **Eventos** (`utils/app-events.js`) transmitem fatos — "o teste de velocidade terminou" — para qualquer número de assinantes, sem valor de retorno.
* **Comandos** (`utils/app-commands.js`) são gatilhos imperativos com resultados — "executar o teste WebRTC" — de propriedade de exatamente um componente, disparados pelo nome, resolvidos quando o trabalho termina.
* **Refs de template** são apenas para a interface da UI — focar um input, medir um elemento. Nunca use um para fazer outro componente executar trabalho.

Ambos os barramentos são cobertos em [Frontend](/developer/pt-br/architecture/frontend.md).

### Onde um helper vai

Essa decisão aparece em quase toda mudança, então tem uma resposta fixa:

<table><thead><tr><th width="200">Diretório</th><th>O que pertence ali</th></tr></thead><tbody><tr><td><code>frontend/composables/</code></td><td>Lógica que precisa da reatividade ou do ciclo de vida do Vue. Nomeada <code>use-xxx.js</code>, exportando <code>useXxx()</code>.</td></tr><tr><td><code>frontend/utils/</code></td><td>Helpers e IO agnósticos de framework. Nunca <code>use-</code> com prefixo.</td></tr><tr><td><code>frontend/lib/</code></td><td>apenas a camada de suporte do shadcn — atualmente só <code>cn()</code>. Não adicione nada a ele.</td></tr><tr><td><code>frontend/data/</code></td><td>Configuração estática e registros: ferramentas, seções, conquistas, changelog.</td></tr></tbody></table>

Um refinamento: **uma função pura que vive ao lado de um composable é exportada do arquivo desse composable**, não promovida a seu próprio módulo em `utils/`. `ipFieldTone()` saindo de `composables/use-status-tone.js` é o padrão a copiar.

## Código compartilhado vive em `common/`

Tudo o que ambos os lados precisam vai para `common/` — a única fonte da verdade — e o frontend acessa isso por meio de uma **ponte fina de reexportação** em `utils/`, então os imports do frontend mantêm sua `@/utils/...` forma:

{% code title="frontend/utils/valid-ip.js" %}

```js
// A única fonte da verdade é common/valid-ip.js (compartilhado com o backend).
// Este arquivo existe como uma ponte fina de reexportação para que o código do front-end possa continuar escrevendo
// `import { isValidIP } from '@/utils/valid-ip.js'` sem se importar com onde
// a implementação vive.
export { isValidIP, isIPv6, isValidDomain, isUsablePublicIP } from '../../common/valid-ip.js';
```

{% endcode %}

`frontend/utils/fetch-with-timeout.js`, `bgp-prefix.js` e `ip-math.js` seguem o mesmo padrão (o último como um simples `export *`, já que todo o módulo é seguro para o navegador). Ao adicionar uma ponte, adicione uma spec que importe **ambos** os caminhos e verifique se concordam — `tests/valid-ip.test.js` faz exatamente isso, e `tests/ip-math.test.js` verifica cada export do módulo em um único loop — o que impede uma ponte de crescer silenciosamente e virar uma segunda implementação.

{% hint style="info" %}
**`isValidIP` e `isUsablePublicIP` respondem perguntas diferentes.** `isValidIP` pergunta se uma string é um endereço bem formado, e continua sendo a chamada certa sempre que um endereço estiver sendo apenas lido ou exibido — parseando a saída dos hops do MTR, filtrando campos de relatório, mascarando um IP para telemetria, decidindo se deve mostrar um botão de copiar.

`isUsablePublicIP` pergunta se um endereço vale a pena ser enviado a uma busca externa: ela incorpora a validade e, em seguida, rejeita espaço reservado (RFC 1918, loopback, CGNAT, link-local, documentação, multicast e seus equivalentes IPv6). Recorra a ela apenas onde o valor está prestes a se tornar uma consulta a um registro, uma fonte de geolocalização ou uma frota de sondas — nenhuma das quais pode dizer qualquer coisa sobre um endereço privado. Em todo o resto, `isValidIP` continua sendo o que você quer.

nenhum dos dois te dá um número. Quando você precisa *calcular* com um endereço — mascará-lo, compará-lo, testar a contenção CIDR, dividir ou agregar blocos — isso é `common/ip-math.js` (`parseIp` → `{ family, value: bigint }`, `parseCidr`, `cidrContains`, e similares). Seus parsers são deliberadamente mais estritos do que `isValidIP`: um octeto com zero à esquerda como `01.2.3.4` é rejeitado em vez de ser lido como octal, e os helpers retornam `null` em vez de lançar erro.
{% endhint %}

## Convenções de backend

O panorama completo em [Backend](/developer/pt-br/architecture/backend.md). As regras que pegam:

### Forma do handler

Um arquivo por rota em `api/`, com uma única exportação padrão:

```js
export default async (req, res) => {
    // leia req.query / req.body, chame o upstream, escreva uma resposta
};
```

A forma do erro é concisa e consistente: `400` em caso de entrada inválida, `res.status(500).json({ error: error.message })` em caso de falha do upstream. O frontend não exibe isso literalmente.

### Nunca um `fetch()`

Toda chamada HTTP de saída de `api/` passa por `fetchUpstream` de `common/fetch-with-timeout.js`. Ela aplica um timeout de 8 segundos e um `User-Agent`. Um provedor upstream travado deve estourar timeout, não manter a conexão aberta.

### Guardas, não verificações inline

O controle de acesso e a validação de parâmetros vivem em middleware (`common/guards.js`), anexado em `backend-server.js`. Os handlers nunca os repetem:

* `requireReferer` — global em `/api/*`
* `requirePublicIP()` / `requireValidDomain()` / `requireValidPrefix()` / `requireValidASN()` / `requireValidProviderId()` / `requireValidRecordType()` / `requireValidReportId()` — por rota

Uma nova forma de parâmetro significa um novo guard em `common/guards.js`, não uma verificação codificada à mão no topo de um handler.

### Logging

{% hint style="danger" %}
**`console.*` é proibido em arquivos de backend.** Sempre o logger pino compartilhado de `common/logger.js`.
{% endhint %}

Pino é orientado ao contexto — o objeto vem primeiro, a mensagem curta depois:

{% code title="o estilo da casa" %}

```js
import logger from '../common/logger.js';

logger.error({ err: e, mac: macAddress }, 'mac-checker handler failed');
logger.warn({ err: e, query }, 'whois: RDAP IP lookup failed, trying WHOIS');
```

{% endcode %}

Mais duas regras:

* **Handlers nunca registram linhas de "received request".** é trabalho do logger, montado em `pino-http`apenas quando `/api` somente quando `LOG_HTTP=true`.
* **Linhas apenas de inicialização começam com um emoji** — 🚀 ouvindo, 📦 pronto, 📥 baixando, 🛡️ segurança, 🐢 limitação, 🗓️ agendamento, ⚠️ recuperável, ❌ falha. Os logs por requisição permanecem simples.

A configuração é `LOG_LEVEL` (padrão `info`), `LOG_FORMAT=json` para transportadores de logs, e `LOG_HTTP=true`. Não há `NODE_ENV` em nenhum lugar neste projeto — veja [Logging](/developer/pt-br/configuration/logging.md).

### Cache de borda

Toda `/api/*` resposta tem como padrão `Cache-Control: no-store`. Rotas públicas que mudam lentamente optam por isso via o `cacheable(maxAgeSeconds)` middleware em `backend-server.js`. Escreva TTLs como expressões multiplicadas (`24 * 60 * 60`), não segundos crus. Os handlers em si nunca mexem em `Cache-Control`, e endpoints por usuário ou autenticados nunca são envolvidos.

## O que acompanha sua mudança

Duas coisas não são opcionais, e ambas são verificadas:

* **cobertura de i18n.** Tudo o que expõe texto cai em **cada `locale` completo** na mesma mudança — os locales `common/locale-registry.js` marca `locale`; esse arquivo é a lista atual — incluindo a `frontend/data/changelog.json` entrada. Locales marcados `beta` estão isentos; eles voltam para o inglês. Veja [i18n](/developer/pt-br/development/i18n.md).
* **Testes.** Qualquer lógica não visual que possa ser exercitada sem uma chamada de rede vem com uma spec em `tests/`, na mesma mudança. Atualize as specs afetadas quando o comportamento mudar — não deixe para depois. Veja [Testes](/developer/pt-br/development/testing.md).

Depois rode `pnpm check`. Ele precisa estar verde antes de você passar a mudança adiante.

## Em seguida

* [Adicionando uma nova ferramenta](/developer/pt-br/development/adding-a-new-tool.md) — tudo acima, aplicado de ponta a ponta.
* [Como Contribuir](/developer/pt-br/contributing/how-to-contribute.md) — branches, commits e expectativas para PRs.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ipcheck.ing/developer/pt-br/development/coding-conventions.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
