# Personalização

A promessa é "nada engessado": um app Fayz vai de pura config a totalmente sob medida **sem nunca forkar o SDK**. A personalização é uma rampa de sete níveis, cada um estritamente aditivo — quem está no nível 6 continua recebendo upgrades do SDK em tudo que não tocou.

## A escada

| Nível | O que muda | Onde | Código? |
| --- | --- | --- | --- |
| 1 · Config | labels, moeda, flags, config de plugin | `app.manifest.json` | não |
| 2 · Tema | marca + tokens | `theme` no manifesto | não |
| 3 · Recompor | reordenar/adicionar/remover blocos, novas páginas | `surfaces.*.pages[].blocks` | não |
| 4 · Slots | injetar widgets em zonas nomeadas | refs de widget no manifesto | às vezes |
| 5 · Override | substituir um componente/bloco do SDK por id | `src/registry.tsx` | sim |
| 6 · Páginas/blocos custom | React sob medida, roteado pelo manifesto | `src/registry.tsx` + componentes | sim |
| 7 · Plugin próprio | entidades/migrations/nav/blocos próprios | um pacote de plugin | sim |

Os níveis 1–4 são **editáveis pela plataforma** — a UI / o agente de IA do Fayz edita o manifesto ao vivo, sem código e sem deploy. Os níveis 5–7 são código do seu repositório, mas **confinados ao `src/registry.tsx` + os seus próprios componentes** — nunca cópias de páginas do SDK.

## Níveis 1–4: só dados

Config e tema você já viu em [Configuração](/pt-BR/docs/apps/configuracao) e [Temas](/pt-BR/docs/apps/temas). **Recompor** (nível 3) é montar uma página como árvore de blocos — pura data:

```json
{
  "pages": [
    { "path": "/", "blocks": [
      { "type": "hero", "props": { "variant": "banner" } },
      { "type": "products", "props": { "title": "Destaques", "limit": 4 } }
    ]}
  ]
}
```

**Slots** (nível 4) injetam widgets em zonas nomeadas do shell (`shell.topbar.end`, `shell.sidebar.footer`, `page.after`, `shell.floating`, …). Você referencia um widget registrado; para um widget seu, registre-o (nível 5/6) e cite pelo id.

## Nível 5: override por id

Todo componente ou bloco do SDK tem um **id de registry**. Re-registre esse id no `src/registry.tsx` e a sua versão vence (last-registration-wins). Ela recebe os **mesmos props tipados** do original — então o SDK evolui os internos por trás do contrato de props sem quebrar você:

```tsx
// src/registry.tsx
import { registerComponent, registerBlock } from '@fayz-ai/core'
import { BrandedDetailHeader } from './components/BrandedDetailHeader'
import { FancyHero } from './components/FancyHero'

registerComponent('crud.detail-header', BrandedDetailHeader) // troca um componente do SDK
registerBlock('hero', FancyHero)                             // troca o bloco hero embutido
```

## Nível 6: páginas e blocos `custom:`

React totalmente seu, no namespace `custom:` (a plataforma nunca gera ids `custom:` — eles só vêm do seu repositório). Registre e referencie por id no manifesto. O seu componente roda com o contexto completo do SDK (data provider, tenant, permissões, i18n):

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

registerBlock('custom:wine-story', WineStory)
registerPage('custom:harvest-board', HarvestBoard)
```

{% callout type="info" %}
As funções `register*` (`registerComponent`, `registerBlock`, `registerPage`) vêm de `@fayz-ai/core` — o import acima compila hoje. O `src/lib/fayz-runtime.ts` que o scaffold gera é, por ora, uma **tela-âncora** (só um `renderApp` placeholder) e ainda **não** reexporta essas funções; o scaffold vai reexportá-las em breve. Até lá, importe direto de `@fayz-ai/core`.
{% /callout %}

```json
{
  "pages": [
    { "path": "/safra", "component": "custom:harvest-board" },
    { "path": "/", "blocks": [{ "type": "custom:wine-story", "props": { "ano": 2019 } }] }
  ]
}
```

## Nível 7: plugin próprio

Quando a personalização é uma capacidade reutilizável (entidades, migrations, navegação, blocos), o teto é um plugin — o **mesmo contrato `PluginManifest`** dos plugins oficiais. Não há nada que um plugin do SDK faça que o seu não possa. Esse é o assunto de [Plugins próprios](/pt-BR/docs/plugins-proprios/incubator).

## Por que os upgrades continuam seguros

- Overrides são chaveados por id e recebem os props tipados do original → os internos do SDK mudam sem quebrar você.
- Código próprio fica confinado ao `src/registry.tsx` + seus componentes + seus plugins; você nunca copia uma página do SDK, então um upgrade toca tudo que você **não** customizou e deixa os seus overrides intactos.

{% callout type="tip" %}
Não existe "eject" por design. Se você sente que precisa forkar uma página do SDK, isso é uma lacuna do SDK para reportar — não um fluxo suportado.
{% /callout %}

---

Próximo: o segundo caminho de consumo em [Headless](/pt-BR/docs/apps/headless).
