# Rotas e navegação

Num app Fayz você não escreve um roteador. A navegação — os itens de menu e as telas por trás deles — é **derivada** do que o manifesto declara: os plugins ligados na surface e as páginas extras que você definir. Esta página mostra de onde cada rota vem.

## A surface é a raiz

Toda rota nasce dentro de uma surface. Uma surface é uma face do app (`admin`, `storefront`, `member`); ela declara o `scaffold` (o layout do shell), a lista de `plugins` e uma lista opcional de `pages`:

```json
{
  "surfaces": {
    "admin": {
      "scaffold": "admin",
      "plugins": [{ "id": "dashboard" }, { "id": "crm" }],
      "pages": []
    }
  }
}
```

Do bloco acima o runtime monta a navegação inteira. Você liga um plugin e o menu e as telas dele aparecem — sem tocar em nenhum arquivo de rotas.

## De onde vem a rota de um plugin

Cada plugin descreve a própria navegação e as próprias rotas no seu manifesto (o `PluginManifest`). São dois campos:

- **`navigation`** — os itens de menu. Cada entrada tem `section` (`main`, `secondary` ou `settings`), `position` (ordem), `label`, `route` e um `icon` opcional. É isso que pinta a barra lateral.
- **`routes`** — o mapeamento `path → componente`. Cada rota aponta para um componente (direto ou por `componentId` do registry) e pode declarar um `guard` (`authenticated`, `public`, `role`, `share-token`).

Quando você adiciona `{ "id": "crm" }` à surface, o runtime lê o `navigation` e o `routes` do CRM e injeta ambos: o item do menu e a tela em `/crm`. Ligar dois plugins junta as duas navegações na mesma barra lateral, ordenadas por `section` + `position`. É por isso que a ordem dos ids no manifesto não define a ordem visual — quem define é o `position` de cada plugin.

## Páginas próprias, sem plugin

Quando você precisa de uma tela avulsa que não pertence a nenhum plugin, declare-a em `pages`. Cada página é dado puro e aponta para **exatamente uma** fonte de conteúdo:

```json
{
  "pages": [
    { "path": "/sobre", "label": "Sobre", "section": "secondary",
      "blocks": [{ "type": "hero", "props": { "title": "Nossa história" } }] },
    { "path": "/relatorio", "label": "Relatório", "component": "custom:harvest-board" }
  ]
}
```

O schema exige uma de três chaves na página:

- **`blocks`** — uma árvore de blocos resolvida pelo registry de blocos (recompor conteúdo sem código).
- **`entity`** — o id de uma entidade, para gerar um CRUD sobre ela.
- **`component`** — o id de um componente próprio registrado no `src/registry.tsx` (namespace `custom:`).

Os campos `label`, `icon`, `section` e `permission` controlam como a página aparece no menu e quem a enxerga.

## O registry conecta ids a código

Rotas e páginas referenciam código por **id**, nunca por import inline. Um `component: "custom:harvest-board"` no manifesto só resolve porque você registrou esse id no `src/registry.tsx`:

```tsx
// src/registry.tsx
import { registerPage } from '@fayz-ai/core'
import { HarvestBoard } from './pages/HarvestBoard'

registerPage('custom:harvest-board', HarvestBoard)
```

{% callout type="info" %}
`registerPage` (e as suas irmãs `registerComponent` / `registerBlock`) vêm de `@fayz-ai/core` — esse import compila hoje. O `src/lib/fayz-runtime.ts` gerado pelo scaffold ainda é uma **tela-âncora** e não reexporta essas funções; ele vai reexportá-las em breve. Até lá, importe direto de `@fayz-ai/core`.
{% /callout %}

Essa separação — dado no manifesto, código no registry — é o que mantém o app atualizável: a plataforma sabe exatamente quais ids você sobrescreveu e o `fayz doctor` consegue reportar divergências.

{% callout type="tip" %}
Regra prática: **capacidade = ligar um plugin** (o menu cresce sozinho); **tela avulsa = uma entrada em `pages`**; **código próprio = um id `custom:` no `registry.tsx`, referenciado como dado**. Você nunca edita um roteador.
{% /callout %}

---

Próximo: entenda o arquivo inteiro em [Configuração](/pt-BR/docs/apps/configuracao).
