> 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/architecture/project-structure.md).

# Estrutura do Projeto

Como o repositório está organizado: um repositório, dois processos, três camadas.

MyIP é um único repositório que inclui **dois processos Node** e contém **três camadas de código**. Nada mais. Depois que você entende isso, cada arquivo na árvore tem um lugar óbvio.

## Dois processos

| Processo          | Arquivo              | Porta padrão              | Função                                                                                                               |
| ----------------- | -------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Servidor estático | `frontend-server.js` | `18966` (`FRONTEND_PORT`) | Serve a SPA compilada a partir de `dist/`, faz proxy de `/api` para o backend e trata o fallback do histórico da SPA |
| Servidor da API   | `backend-server.js`  | `11966` (`BACKEND_PORT`)  | O app Express 5 — cada `/api/*` rota, guardas, limitação de taxa, conjuntos de dados offline                         |

`pnpm start` executa ambos com `concurrently`. Em produção, eles geralmente são gerenciados pelo pm2 (`ecosystem.config.cjs` define `myip-frontend` e `myip-backend`) ou pela imagem Docker, que executa `npm start` dentro de um contêiner e expõe apenas `18966`.

```mermaid
flowchart LR
    B["Navegador"]
    F["frontend-server.js :18966<br/>servidor estático dist/ + fallback da SPA"]
    A["backend-server.js :11966<br/>API Express 5"]
    U["Provedores upstream<br/>ipinfo.io, ip-api.com, RIPEstat, OONI"]
    D["Conjuntos de dados locais<br/>MaxMind mmdb, CAIDA as2org / as-rel"]

    B -->|"GET / , /tools/whois , /assets/*"| F
    B -->|"GET /api/*"| F
    F -->|"http-proxy-middleware"| A
    A -->|"fetchUpstream, 8s timeout"| U
    A --> D
```

{% hint style="info" %}
Só a porta do frontend precisa estar acessível da internet. O backend escuta em `11966` para o proxy; mantenha-o no mesmo host ou em uma rede privada. Veja [Proxy reverso e domínios](/developer/pt-br/getting-started/reverse-proxy-and-domains.md).
{% endhint %}

## Três camadas de código

| Diretório   | Executa onde         | Conteúdo                                                                                                                                     |
| ----------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `frontend/` | Navegador            | A SPA Vue 3 — componentes, roteador, store Pinia, locais, registro de ferramentas                                                            |
| `api/`      | Node                 | Um módulo handler do Express por rota, nada mais                                                                                             |
| `common/`   | Node **e** navegador | Código compartilhado por ambas as partes: validadores, o wrapper de fetch, guardas, logger, serviços MaxMind / CAIDA, o esquema do relatório |

`common/` é a única camada que cruza a fronteira. Módulos de que o navegador também precisa (`valid-ip.js`, `fetch-with-timeout.js`, `report-schema.js`, `dns-record-types.js`, `ip-math.js`) permanecem livres de `fs` e `process` acesso, e são reexportados por meio de pontes finas em `frontend/utils/` para que o código da app continue importando `@/utils/...`. Questões exclusivas do Node que quebrariam essa regra ficam em seu próprio arquivo — por exemplo, o User-Agent upstream é montado em `common/upstream-ua.js` (que lê `package.json` do disco) e injetado em `common/fetch-with-timeout.js` na inicialização.

## Árvore anotada

```
.
├── backend-server.js       App Express: tabela de rotas, ordem dos middlewares, cacheable()
├── frontend-server.js      Servidor estático + proxy /api + fallback do histórico da SPA
├── sentry-instrument.js    Bootstrap do Sentry no backend, carregado via `node --import`
├── ecosystem.config.cjs    Definições de processo do pm2 (leva a flag --import)
├── index.html              Entrada do Vite / casca da SPA
├── vite.config.js          Configuração de build: aliases, chunks manuais, proxy de desenvolvimento
├── Dockerfile              Build em duas etapas (veja abaixo)
│
├── frontend/               SPA Vue 3  → veja Frontend
│   ├── App.vue             Casca fina: provedores globais + <router-view>
│   ├── main.js             Bootstrap + inicialização dinâmica controlada por variável de ambiente
│   ├── store.js            Store principal do Pinia
│   ├── router/             Tabela de rotas
│   ├── data/               Registros estáticos: ferramentas, seções, conquistas, bancos de dados de IP, padrões de conectividade e listas de importação curadas, tabelas de persona
│   │   └── banners/        Dados de banner de seção no momento do deploy — ignorados pelo git (veja Section Banners)
│   ├── components/         Home / StandaloneTool / seções / advanced-tools / relatório / widgets / ui
│   ├── composables/        Lógica `useXxx` compatível com Vue
│   ├── utils/              Ajudantes agnósticos de framework (barramento de eventos, barramento de comandos, getips/, persona/, ip-calc.js, …)
│   └── locales/            Um pacote por locale registrado + subpacotes sob demanda
│
├── api/                    Um handler por rota  → veja Backend
│
├── common/                 Código compartilhado
│   ├── guards.js           Middleware de validação de parâmetros
│   ├── dns-record-types.js Os tipos de registros DNS para os quais o resolvedor responde
│   ├── fetch-with-timeout.js  fetchWithTimeout (5s) / fetchUpstream (8s)
│   ├── ip-math.js          Aritmética de IP / CIDR com BigInt (Calculadora de IP + contenção RDAP)
│   ├── logger.js           singleton do pino
│   ├── ip-timezone.js      Coordenadas → zona IANA + middleware withTimeZone()
│   ├── locale-registry.js  Os idiomas da UI e todos os mapeamentos derivados deles
│   ├── locale-pack.js      Ajudantes de estrutura do pacote de localidade + remoção em tempo de build
│   ├── maxmind-service.js  Leitores GeoLite2 locais + consulta
│   ├── maxmind-updater.js  Download agendado do GeoLite2
│   ├── caida-updater.js    Download agendado de as2org / as-rel
│   ├── as-org-db.js        Consulta CAIDA AS → organização
│   ├── as-rel-db.js        Relacionamentos CAIDA AS (grafo p2c + p2p)
│   ├── service-status-*.js Lista de provedores, poller, transformação de resposta
│   ├── maxmind-db/         GeoLite2-City.mmdb · GeoLite2-ASN.mmdb
│   ├── as-org-db/          as-org2info.txt
│   └── as-rel-db/          as-rel2.txt
│
├── tests/                  Especificações do executador de testes do Node (`node --test`)
└── dist/                   Saída do build (gerada, não comitada)
```

## Como uma requisição flui

**Carregamento da página.** O navegador solicita `frontend-server.js` uma URL.

1. `/api/*` é capturada primeiro pelo middleware de proxy e encaminhada para `http://localhost:11966/api`.
2. Caso contrário `express.static` tenta servir um arquivo real de `dist/`, aplicando um `Cache-Control` cabeçalho por classe de ativo — `dist/assets/**` e `dist/fonts/**` recebem um ano mais `immutable` (o Vite gera content hashes neles), imagens de nível superior 7 dias, `index.html` e `manifest.webmanifest` zero nos navegadores, mas 24h na borda, e o restante uma hora.
3. Se nenhum arquivo corresponder, o fallback do histórico da SPA retorna `index.html` para que o vue-router possa resolver uma rota cliente como `/tools/whois`. O fallback é deliberadamente restrito: `GET` somente, `Accept: text/html` somente, e nunca para um caminho cujo último segmento contenha um ponto — um `/assets/x.js` deve retornar 404, não receber um corpo HTML.

**Chamada da API.** Dentro do backend, a requisição passa pela cadeia de middlewares em `backend-server.js` — opcional `pino-http`, limitador de taxa, slow-down, parser de corpo JSON, o `no-store` padrão no-store, a guarda global de referer, depois os guards de parâmetros por rota e o handler. O handler faz no máximo uma chamada upstream, por meio de `fetchUpstream`. Detalhes em [Backend](/developer/pt-br/architecture/backend.md).

{% hint style="warning" %}
`backend-server.js` também monta `express.static('./dist')`. Isso é uma conveniência para configurações que expõem o backend diretamente; o caminho normal ainda é navegador → servidor frontend → proxy.
{% endhint %}

## Pipeline de build

`pnpm build` executa o Vite, que emite `dist/`:

* `@` resolve para `frontend/`.
* `manualChunks` divide dependências pesadas em quatro chunks — `vendor` (vue / vue-router / vue-i18n), `chart` (chart.js), `speedtest` (@cloudflare/speedtest) e `browser-detect` (thumbmarkjs / ua-parser-js) — e extrai os ajudantes de fonte de IP e autenticação para `utils-getips` / `utils-auth`.
* As fontes vão para `dist/fonts/`, todo o resto com content hash em `dist/assets/`.
* Os sourcemaps são gerados apenas quando `SENTRY_AUTH_TOKEN` está definido, como `ocultos` sourcemaps, e são excluídos de `dist/` após o upload — veja [Monitoramento de Erros](/developer/pt-br/configuration/error-monitoring.md).

O Docker constrói em duas etapas. A etapa de build instala com `pnpm install --frozen-lockfile` e executa `pnpm run build`; a etapa de produção copia apenas `node_modules`, `package.json`, `dist/`, os dois arquivos de servidor, `sentry-instrument.js`, `api/` e `common/`. Sem toolchain, sem etapa de instalação em tempo de execução. Veja [Implantar com Docker](/developer/pt-br/getting-started/deploy-with-docker.md).

## Modo de desenvolvimento

`pnpm dev` inicia o Vite e o backend juntos. O Vite serve a SPA em `FRONTEND_PORT` ele mesmo (sem `dist/`, sem `frontend-server.js`) e faz proxy `/api` para `BACKEND_PORT` — então a forma da URL é idêntica à produção. O backend roda com `nodemon` com `--import ./sentry-instrument.js`, o que é uma operação sem efeito sem um DSN do backend. Os detalhes de configuração estão em [Ambiente de desenvolvimento](/developer/pt-br/development/dev-environment.md).

## Onde fazer uma alteração

| Você quer…                                                     | Vá para                                                                                                                                        |
| -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Adicionar uma ferramenta à UI                                  | `frontend/data/tools.js` — veja [Adicionando uma nova ferramenta](/developer/pt-br/development/adding-a-new-tool.md)                           |
| Adicionar uma rota de API                                      | Um novo arquivo em `api/`, conectado em `backend-server.js`                                                                                    |
| Adicionar um validador compartilhado                           | `common/`, além de uma ponte em `frontend/utils/` se o navegador precisar dele                                                                 |
| Alterar o texto                                                | `frontend/locales/` — veja [i18n](/developer/pt-br/development/i18n.md)                                                                        |
| Mostrar um banner promocional ou de patrocinador sob uma seção | Um arquivo de dados em `frontend/data/banners/` em tempo de build — veja [Banners de seção](/developer/pt-br/configuration/section-banners.md) |
| Adicionar um teste                                             | `tests/` — veja [Testes](/developer/pt-br/development/testing.md)                                                                              |


---

# 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/architecture/project-structure.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.
