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 e Temas. Recompor (nível 3) é montar uma página como árvore de blocos — pura data:
{
"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ê:
// 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):
// 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)
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.
{
"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.
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.
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.
Próximo: o segundo caminho de consumo em Headless.