--- source: https://developers.fayz.ai/pt-BR/docs/visao-geral.md --- # O que é o Fayz O Fayz é uma fábrica de SaaS. Em vez de escrever um produto multi-tenant do zero — autenticação, banco, isolamento por cliente, telas de CRUD, cobrança — você **compõe** plugins de capacidade sobre um motor compartilhado. Um salão, um restaurante e uma clínica são o mesmo motor com plugins diferentes ligados. O que muda entre um produto e outro é uma **composição** — config + plugins + tema — não uma base de código nova. A ideia central: um app Fayz não bifurca a SDK. Ele fica sobre uma fronteira de propriedade estrita, então uma melhoria na SDK atravessa todos os apps como **uma** migração, não milhares de PRs. Você personaliza de um rótulo até uma página inteiramente sob medida sem nunca ejetar. ## As quatro peças Guarde estas quatro e o resto encaixa: - **SDK** — os pacotes `@fayz-ai/*`. O motor headless (`@fayz-ai/core`) define o contrato de plugin, o modelo de dados e o runtime; a camada SaaS (`@fayz-ai/saas`) traz multi-tenancy, permissões e o motor de CRUD; a UI (`@fayz-ai/ui`) traz o shell e os componentes. Você instala só o que usa. - **Plugins** — pacotes `@fayz-ai/plugin-*` que declaram capacidades: agenda, CRM, financeiro, menu, cursos, estoque. Cada plugin traz suas rotas, sua navegação, seus widgets e suas migrações de banco. Você liga os que precisa. - **Supabase** — o backend real por trás do app: Postgres com RLS multi-tenant, provisionado a partir dos pacotes que você instalou. Todo app nasce em modo mock (zero configuração) e você troca para Supabase quando estiver pronto. - **Deploy** — o app é um projeto web comum. Hoje você publica como site estático em qualquer host; amanhã, direto pela plataforma Fayz gerenciada. ## O modelo mental Um app Fayz se descreve como **dados**. Você declara a config, liga plugins, e isso vira um manifesto — a fonte única a partir da qual o runtime monta telas, rotas e acesso a dados: ``` config do app │ (nome, tema, locale, backend, quais plugins) ▼ plugins ligados ─────────────┐ agenda · crm · financeiro … │ cada um declara │ rotas + navegação + widgets + migrações ▼ ▼ manifesto ────────────────────────────────► runtime (o app inteiro como dados) │ ├─► telas (shell + páginas dos plugins) ├─► rotas (navegação gerada) └─► dados (providers → mock ou Supabase) ``` A mesma direção vale seja você escrevendo a config em JSON (`app.manifest.json`) ou em código (`defineSaas`): as duas viram o mesmo manifesto. Personalizar um app é, quase sempre, editar esses dados — não escrever telas novas. ## Fayz e Faya Labs **Fayz** é a tecnologia — a SDK, os plugins, a CLI. **Faya Labs** é a comunidade em volta dela: quem constrói produtos reais, compartilha plugins e ajuda quem está começando. Você *usa* o Fayz; você *participa* da Faya Labs. ## Para quem é Para o desenvolvedor que quer construir um produto de verdade — um SaaS que vai para produção com clientes pagantes — e não um protótipo descartável. Se você já sabe montar um app web e quer parar de reescrever o mesmo esqueleto multi-tenant a cada projeto, este é o seu lugar. {% callout type="info" %} O Fayz está pré-1.0. Os pacotes são reais e usados no dia a dia, mas as APIs ainda podem mudar entre versões menores. Fixe versões exatas em produção e leia o changelog antes de atualizar. O contrato completo está em [Conceitos → canais de versão](/pt-BR/docs/conceitos). {% /callout %} ## Por onde seguir {% cards %} {% card title="Quickstart" href="/pt-BR/docs/quickstart" icon="⚡" %} Um app rodando no seu navegador em cinco minutos, sem configurar nada. {% /card %} {% card title="Conceitos" href="/pt-BR/docs/conceitos" icon="📚" %} Manifesto, biblioteca core, tenants, providers, canais e incubator. {% /card %} {% /cards %} --- source: https://developers.fayz.ai/pt-BR/docs/quickstart.md --- # Quickstart Do zero a um app Fayz rodando no seu navegador em cinco minutos. Você instala a CLI, gera um app admin, instala as dependências, sobe o dev server e vê a coisa funcionando — tudo em modo mock, sem configurar nenhuma variável de ambiente. ## Pré-requisitos - **Node ≥ 20** e **npm** (vêm juntos). Confira com `node -v`. - Uma conta **Supabase** — **opcional**, só para o último passo, quando você quiser trocar o mock por dados reais. Para o quickstart em si, você não precisa de nada além do Node. ## 1. Instale a CLI ```bash npm i -g @fayz-ai/cli ``` Confira que funcionou com `fayz --version`. ## 2. Crie o app ```bash fayz create admin minha-app ``` Isso gera um projeto `minha-app/` — um app admin com o plugin de dashboard já ligado, apontado para faixas caret (`^`) de um conjunto coerente de pacotes `@fayz-ai/*` — o canal `stable` — e em modo mock. O comando não instala nada nem sobe servidor: ele só escreve os arquivos e te diz os próximos passos. ## 3. Instale e suba o dev server ```bash cd minha-app npm install npm run dev ``` {% callout type="tip" %} **Checkpoint.** Abra `http://localhost:5173`. O app sobe em **modo mock**: dados de exemplo, autenticação simulada, **zero env**. Você navega pelo shell, abre plugins e vê telas reais sem tocar em Supabase. É o ponto de partida de todo app Fayz — e é aqui que você vai personalizar tema, plugins e conteúdo antes de sequer pensar em backend. {% /callout %} Consumindo os pacotes em código e quer telas populadas? Os providers mock nascem vazios — veja [Mock e dados de exemplo](/pt-BR/docs/apps/mock-e-dados-de-exemplo) para os seams de seed. ## O que você acabou de montar Um app Fayz completo, descrito por `app.manifest.json`: o shell de admin, a navegação, e o plugin de dashboard — tudo renderizado pelo runtime a partir desse manifesto. Personalizar daqui para frente é, na maioria das vezes, editar o manifesto: renomear o app, trocar o tema, ligar mais plugins. Nada de reescrever telas. ## Próximo passo O tutorial pega esse mesmo app e leva do primeiro comando ao deploy — tema, plugins, dados reais e um plugin seu — em sete passos. {% cards %} {% card title="Tutorial · 01 · Criar o app" href="/pt-BR/docs/tutorial/01-criar-o-app" icon="🧭" %} Comece a jornada guiada do zero ao ar. {% /card %} {% card title="Os dois caminhos" href="/pt-BR/docs/dois-caminhos" icon="🍴" %} Confirme que o App Fayz é mesmo o que você quer (vs. Headless). {% /card %} {% card title="Dados reais com Supabase" href="/pt-BR/docs/dados/supabase" icon="🗄️" %} Quando estiver pronto para sair do mock. {% /card %} {% /cards %} --- source: https://developers.fayz.ai/pt-BR/docs/conceitos.md --- # Conceitos São seis conceitos que fazem todo app Fayz encaixar. Domine estes e você lê qualquer projeto Fayz sem se perder: o **plugin e seu manifesto**, a **biblioteca core multi-tenant**, os **providers**, os **dois caminhos** de construção, os **canais de versão** e os **plugins incubator**. Cada um vem com um parágrafo e, quando ajuda, um trecho de código. ## 1. Plugin e manifesto Um plugin é uma capacidade empacotada — agenda, CRM, financeiro. Você o cria chamando a factory dele (`createAgendaPlugin`, `createCrmPlugin`, …), que retorna um **manifesto**: a descrição, em dados, de tudo que aquele plugin contribui para o app. Rotas, navegação, widgets de dashboard, migrações de banco, ferramentas de IA — tudo declarado num objeto, não espalhado pelo código. ```ts import { createAgendaPlugin } from '@fayz-ai/plugin-agenda' const agenda = createAgendaPlugin() // → { id, name, icon, version, navigation, routes, widgets?, // dashboardWidgets?, migrations?, ... } = PluginManifest ``` O app compõe uma lista desses manifestos e o runtime faz o resto: monta a navegação, resolve as rotas, registra os widgets e ordena as migrações. A regra que mantém isso são: um plugin **não emite nada específico do app por padrão** — o que ele contribui para uma superfície compartilhada é opt-in. O app decide o que aparece. ## 2. Biblioteca core multi-tenant Todo app Fayz senta sobre a **biblioteca core** (antes chamada `saas_core`): as tabelas-base que todo negócio precisa — `tenants`, `people`, `tenant_members`, `role_permissions`, `appointments`, `transactions`. Essas tabelas não vivem num schema `core.` separado — moram todas em `public.*`. Por cima delas, o modelo tem só mais duas camadas: ``` public.* tabelas-base compartilhadas (tenants, people, tenant_members, role_permissions, appointments…) plg_* tabelas que um plugin instala e possui (plg_shop_products, plg_courses_*…) suas tabelas o que o seu app/incubator cria por cima ``` Um plugin instala as próprias tabelas com prefixo `plg_` e **reutiliza** as tabelas do core que precisa em vez de copiá-las; se o financeiro precisa saber "quem recebeu", ele referencia `public.people`, não guarda uma cópia. Uma fonte de verdade por entidade. O **tenant** é o cliente do seu SaaS (um salão, uma clínica). **Toda tabela** — do core, de plugin ou sua — carrega `tenant_id`, e o isolamento é garantido por **RLS** (Row-Level Security) do Postgres, chaveada nesse `tenant_id`. O RLS **é** a fronteira, não a separação de schemas: você não filtra por tenant na aplicação — o banco recusa linhas de outro tenant. Você traz o seu próprio Supabase (**BYOS**) e ele recebe exatamente essa forma; é a mesma que a plataforma hospeda em escala. O detalhe completo está em [Dados → Modelo](/pt-BR/docs/dados/modelo) e [RLS e multi-tenant](/pt-BR/docs/dados/rls). ## 3. Providers (mock-first) Um **provider** é a abstração de backend de um plugin: a mesma interface, duas implementações. Todo app nasce com `backend.provider: "mock"` — dados de exemplo, auth simulada, **zero variável de ambiente** — então você desenvolve e demonstra sem tocar em infraestrutura. Quando estiver pronto, você faz o *flip*: troca o provider para `supabase` e o mesmo plugin passa a falar com o Postgres real. ```jsonc // app.manifest.json — de mock para real é uma linha: "backend": { "provider": "mock" } "backend": { "provider": "supabase", "projectRef": "" } ``` No nível do plugin isso aparece como um provider seguro que escolhe Supabase quando há credenciais e cai no mock quando não há — a mesma interface dos dois lados, então nada no resto do plugin muda no flip. Como conectar o Supabase de verdade está em [Dados → Supabase](/pt-BR/docs/dados/supabase). ## 4. Os dois caminhos Existem dois jeitos de construir. No **App Fayz** você ganha um shell de admin completo pronto — navegação gerada, troca de tenant, permissões, CRUD — a partir da sua config. No **Fayz Headless** você consome o core e os bundles de plugin dentro do seu próprio site, sendo dono da casca. Os dois usam os mesmos plugins e o mesmo backend; muda quem monta a interface em volta. Escolher o caminho certo no começo economiza retrabalho — a comparação completa, com quando usar cada um, está em [Os dois caminhos](/pt-BR/docs/dois-caminhos). ## 5. Canais de versão Duas coisas diferentes usam nomes parecidos, então separe-as: - **Canais de release** (`stable`, `latest`, `preview`) são *conjuntos de versões* — grupos coerentes de pacotes `@fayz-ai/*` que você instala juntos. `fayz create` fixa seu app no canal `stable` por padrão. - **Tiers de maturidade** (`stable`, `beta`, `preview`, `internal`) são uma propriedade de *cada pacote* — o quanto você pode se apoiar nele hoje. {% callout type="warn" %} Seja honesto com você mesmo: **nada é tier `stable` ainda**. O Fayz é pré-1.0, e enquanto um pacote está em `0.x`, um bump *menor* (`0.4.0` → `0.5.0`) pode conter mudanças que quebram — e nós usamos essa margem. O core e os plugins que já rodam no dia a dia são tier **`beta`**. Fixe versões exatas em produção e leia o changelog antes de atualizar. {% /callout %} A tabela completa de tiers, com garantias de versionamento e resposta a bugs, está em [Referência → versões e canais](/pt-BR/docs/referencia/versoes). ## 6. Plugins incubator Nem toda capacidade precisa virar um pacote publicado. Um **plugin incubator** é um plugin que mora dentro do seu próprio app (em `src/plugins/`), seguindo o **mesmo contrato** dos plugins oficiais — mesmo manifesto, mesmas rotas, migrações e providers. É onde você põe a lógica específica do seu produto, ou incuba um plugin novo antes de eventualmente graduá-lo para o catálogo. ```bash fayz create plugin meu-plugin ``` Como o contrato é idêntico, um incubator injeta na UI da SDK do mesmo jeito que um plugin oficial — a diferença é só quem é dono do código. Os padrões para escrever um estão em [Plugins próprios → incubator](/pt-BR/docs/plugins-proprios/incubator). ## Próximo passo {% cards %} {% card title="Os dois caminhos" href="/pt-BR/docs/dois-caminhos" icon="🍴" %} Decida entre o App Fayz e o modo Headless antes de escrever a primeira linha. {% /card %} {% card title="Tutorial completo" href="/pt-BR/docs/tutorial" icon="🧭" %} Do primeiro comando ao deploy, em sete passos. {% /card %} {% /cards %} --- source: https://developers.fayz.ai/pt-BR/docs/setup-agentico.md --- # Setup agêntico Você não vai construir sozinho. A forma canônica de construir com a Fayz é **com um agente** — Claude Code, Cursor, Codex, qualquer ferramenta que leia um `AGENTS.md`. Esta página prepara o terreno: as contas e acessos, os MCPs que valem a pena, os trilhos (skills) que guiam cada etapa, e uma sessão de **descoberta de produto** que você faz hoje, antes de escrever a primeira linha. ## A premissa Todo app gerado já nasce com um `AGENTS.md` na raiz apontando para este Dev Center — para o `llms.txt` (o mapa) e para as páginas em Markdown (a referência). Então o agente que abre o seu projeto já sabe onde buscar a estrutura real do SDK em vez de chutar. O primeiro passo não é técnico: é **apontar o seu agente para o knowledge base**. Como fazer isso — dar o `llms.txt` primeiro, puxar páginas `.md` sob demanda, deixar o `AGENTS.md` no contexto — está detalhado em [Conecte seu agente](/pt-BR/docs/ia/conecte-seu-agente). Faça isso uma vez por sessão e o resto desta página funciona. ## Contas e acessos Antes de começar, tenha à mão: | O quê | Para quê | Custo | | --- | --- | --- | | **Node ≥ 20 + npm** | Rodar a CLI (`npx @fayz-ai/cli`) e o app Vite. | Grátis | | **Conta GitHub** | Seu app é o seu repositório; o deploy sobe daqui. | Grátis | | **Conta Supabase** | Seu banco de dados, projeto próprio. O plano grátis serve para começar. | Grátis para começar | | **Token Fayz** (`fayz_`) | Publicar com `fayz deploy`. Em rollout para a rede convidada. | Convite | | **Editor com agente** | Claude Code, Cursor, Codex — qualquer um que leia `AGENTS.md`. | Varia | Você não precisa de tudo no minuto zero: o app roda em modo mock sem Supabase, e você só precisa do token Fayz na hora de publicar. Mas ter as contas prontas evita travar no meio. ## MCPs Um agente fica muito mais forte com **MCPs** (Model Context Protocol) — servidores que dão ao agente ferramentas para agir, não só ler. O que vale a pena agora é o **Supabase MCP oficial**. Com ele, o agente cria tabelas, consulta dados e inspeciona o schema em linguagem natural, direto do seu projeto Supabase. A maioria dos editores com agente lê um bloco de configuração de MCP servers neste formato: ```json { "mcpServers": { "supabase": { "command": "npx", "args": [ "-y", "@supabase/mcp-server-supabase@latest", "--read-only", "--project-ref=" ], "env": { "SUPABASE_ACCESS_TOKEN": "" } } } } ``` O `--read-only` é uma escolha segura para começar (o agente consulta mas não altera). Os flags e o nome exato do pacote evoluem — a fonte da verdade é a doc oficial: [supabase.com/docs/guides/getting-started/mcp](https://supabase.com/docs/guides/getting-started/mcp). **A divisão de trabalho, honesta:** o Supabase MCP é ótimo para o agente **explorar e prototipar** o banco em conversa. As migrações dos plugins Fayz continuam vindo do `fayz db apply`, que monta a ordem correta (spine → drizzle → seed → plugins) a partir dos pacotes instalados — veja [Supabase](/pt-BR/docs/dados/supabase). Um não substitui o outro: o MCP é a mão livre do agente; o `db apply` é o trilho reproduzível dos plugins. Um **MCP dedicado da Fayz** — para o agente consultar catálogo e docs sem colar URLs — está em breve. Por enquanto, o `llms.txt` mais as páginas `.md` fazem esse papel. ## Repos Por padrão você **não clona nada**. O SDK é consumido do npm como `@fayz-ai/*`, e o seu app é o seu próprio repositório — criado pela CLI, versionado por você. Não existe um monorepo para baixar nem um fork para manter. Contribuições ao core acontecem por convite, via [comunidade](/pt-BR/docs/recursos/comunidade). Para construir produtos, você nunca precisa disso. ## Skills — os trilhos A metodologia Fayz vive como **skills**: sequências que o agente executa, cada uma cobrindo uma etapa da jornada. Hoje elas são **prompts copiáveis** que você dá ao agente (o `/fayz-descoberta` completo está logo abaixo); o empacotamento instalável — instalar a skill e chamá-la por nome — está em breve. A referência canônica — as cinco skills oficiais, as skills da comunidade recomendadas (como `ui-ux-pro-max` e `supabase-postgres-best-practices`) e como um agente descobre e aplica skills — vive em [Skills: procedimentos para o seu agente](/pt-BR/docs/ia/skills). Aqui embaixo fica só o prompt pronto para colar da primeira etapa. ## O `/fayz-descoberta` completo O produto começa antes do código. Cole o bloco abaixo no seu agente hoje: ele conduz uma entrevista de descoberta, uma pergunta de cada vez, e no fim escreve um `PRODUCT-BRIEF.md` no seu repositório com a decisão de scaffold, plugins e tema. ```` Você é um parceiro de descoberta de produto da plataforma Fayz. Leia https://developers.fayz.ai/llms.txt para conhecer os tipos de produto e os plugins disponíveis. Depois me entreviste — UMA pergunta de cada vez, esperando minha resposta antes da próxima. Se eu responder vago, repergunte até ficar concreto. As perguntas, nesta ordem: 1. TIPO DE PRODUTO — qual dos tipos do catálogo mais se aproxima? (gestão/admin, agendamento, food, e-commerce, curso online, website) Referência: https://developers.fayz.ai/pt-BR/docs/plugins 2. INDÚSTRIA / VERTICAL — em que ramo? (ex.: clínica de estética, food truck) 3. CLIENTE IDEAL — quem exatamente sofre com isso hoje, e em que contexto? 4. A DOR DE HOJE — o que essa pessoa faz na mão, no Excel, no WhatsApp? 5. O 1 FLUXO ESSENCIAL — UM único caminho que, se funcionar, já entrega valor. Só um. (ex.: "cliente agenda um horário e recebe confirmação") 6. DADOS MÍNIMOS — as 2 ou 3 entidades que esse fluxo precisa. (ex.: cliente, serviço, agendamento) 7. MARCA — cor, personalidade e modo (claro/escuro). Traduza para uma receita de tema: https://developers.fayz.ai/pt-BR/docs/tutorial/03-tema-e-marca 8. NOME — como o produto se chama? Ao terminar, escreva um arquivo PRODUCT-BRIEF.md no repositório com: resumo do produto, cliente e dor, o fluxo essencial, o modelo de dados mínimo, a receita de tema (brand/radius/mode) e o nome. Em seguida, PROPONHA — sem executar ainda — o comando de scaffold (fayz create ), os plugins do catálogo que cobrem o fluxo, e o bloco theme. Espere meu OK. Regra de ouro: escopo pequeno que funciona ganha de escopo grande que não roda. ```` O `PRODUCT-BRIEF.md` vira a memória do projeto: o próximo passo (`/fayz-bootstrap`) lê dele para gerar o app certo, com os plugins certos e o tema certo — sem você repetir o contexto. ## Próximo passo Com o agente conectado, as contas prontas e o brief escrito, você está pronto para construir. Vá para o [Quickstart](/pt-BR/docs/quickstart) para o caminho rápido, ou direto para o [Tutorial 01 · Criar o app](/pt-BR/docs/tutorial/01-criar-o-app) para o passo a passo completo. --- Anterior: [Conceitos](/pt-BR/docs/conceitos) · Próximo: [Os dois caminhos](/pt-BR/docs/dois-caminhos) --- source: https://developers.fayz.ai/pt-BR/docs/dois-caminhos.md --- # Os dois caminhos Tem dois jeitos de construir com a Fayz SDK, e escolher o certo no começo economiza retrabalho. Ou você usa o **App Fayz** — um shell de admin completo montado a partir da sua config — ou vai de **Fayz Headless**, consumindo o core e os bundles de plugin direto no seu próprio projeto. Os dois usam os mesmos plugins e o mesmo backend; muda **quem é dono da casca** em volta dos plugins. Regra de bolso: se o produto **é** o app de gestão (um SaaS multi-tenant, um admin), vá de App Fayz. Se você já tem um site próprio — uma landing page, uma loja com marca forte — e só quer plugar algumas capacidades dentro dele, vá de Headless. ## App Fayz Você declara a config do app — em `app.manifest.json` ou em código com `defineSaas` — liga um conjunto de plugins, e ganha um app pronto: shell de admin, navegação gerada a partir dos plugins, troca de tenant, permissões e telas de CRUD. É o caminho mais rápido para um produto multi-tenant completo, e é o que o `fayz create admin` gera para você. ```ts import { defineSaas } from '@fayz-ai/saas' import { createAgendaPlugin } from '@fayz-ai/plugin-agenda' import { createCrmPlugin } from '@fayz-ai/plugin-crm' export default defineSaas({ name: 'Minha Clínica', plugins: [createAgendaPlugin(), createCrmPlugin()], }) // → shell de admin completo: navegação, tenants, permissões, CRUD ``` Você entra pelo [Quickstart](/pt-BR/docs/quickstart), que gera exatamente esse tipo de app e o sobe em modo mock. Consumindo os pacotes em código, os providers mock nascem vazios — [Mock e dados de exemplo](/pt-BR/docs/apps/mock-e-dados-de-exemplo) mostra como semeá-los. ## Fayz Headless {% badge status="beta" %} Você importa `@fayz-ai/core` e monta as superfícies você mesmo, injetando os bundles de plugin (`{ manifest, Provider }`) e servindo os subpaths deles em `/public`. É o caminho para um site sob medida — marketing, loja, portal — que só quer algumas capacidades do Fayz sem adotar o shell inteiro. O tema herda dos seus próprios tokens, então o plugin se parece com o seu site, não com o admin padrão. {% callout type="warn" %} O caminho Headless é real e está em uso, mas tem **menos documentação** que o App Fayz hoje. Espere se apoiar mais na leitura dos tipos e dos exemplos, e menos em guias passo a passo, enquanto ele amadurece. {% /callout %} ## Comparação | | **App Fayz** | **Fayz Headless** | |---|---|---| | Quem monta o shell | a SDK (pronto) | você, no seu projeto | | Navegação / rotas | geradas do manifesto | você conecta as suas | | Multi-tenant + permissões | incluídos | você integra o que precisar | | Tema | shell e tokens do Fayz | herda dos seus próprios tokens | | Ponto de partida | `fayz create admin` | um site seu já existente | | Melhor para | SaaS / admin de gestão | site com marca própria + algumas capacidades | | Custo de entrada | mínimo — roda em minutos | maior — você é dono da integração | | Documentação hoje | completa | em amadurecimento | O que você ganha no App Fayz — shell, navegação, tenancy — é exatamente o que você abre mão de controlar. O Headless inverte: você controla tudo, e paga isso montando a integração. Nenhum é "melhor"; depende de o produto ser o app de gestão ou um site que consome capacidades. ## Escolha o seu {% cards %} {% card title="Caminho A · App Fayz" href="/pt-BR/docs/quickstart" icon="🏗️" %} Comece pelo Quickstart: um shell de admin completo rodando em minutos. {% /card %} {% card title="Caminho B · Headless" href="/pt-BR/docs/apps/headless" icon="🧱" %} Core + bundles de plugin dentro do seu próprio site. {% /card %} {% /cards %} --- source: https://developers.fayz.ai/pt-BR/docs/tutorial.md --- # Tutorial — do zero ao app no ar Este é o caminho completo do Fayz: você começa com um comando e termina com um app publicado, passando por anatomia, tema, plugins, dados reais e um plugin escrito por você. Cada passo é curto, mostra o comando exato e um checkpoint do que você deve ver antes de seguir. Faça na ordem na primeira vez — leva cerca de 30 minutos. {% callout type="info" %} O que você precisa: Node 20 ou superior e um terminal. Para o passo 05 (dados reais) você também vai querer uma conta gratuita no Supabase. Nada mais. {% /callout %} {% steps %} {% step title="01 · Criar o app" %} Gere o projeto com a CLI, instale e rode em modo mock. [Começar →](/pt-BR/docs/tutorial/01-criar-o-app) {% /step %} {% step title="02 · Explorar a anatomia" %} Entenda o manifesto, a geração de plugins, o registry e o AGENTS.md. [Abrir →](/pt-BR/docs/tutorial/02-explorar-a-anatomia) {% /step %} {% step title="03 · Tema e marca" %} Troque a marca, o raio e o modo de cor no manifesto. [Abrir →](/pt-BR/docs/tutorial/03-tema-e-marca) {% /step %} {% step title="04 · Adicionar um plugin" %} Ligue um plugin do catálogo e veja a navegação crescer. [Abrir →](/pt-BR/docs/tutorial/04-adicionar-um-plugin) {% /step %} {% step title="05 · Dados reais com Supabase" %} Saia do mock: provisione o banco com `fayz db apply`. [Abrir →](/pt-BR/docs/tutorial/05-dados-reais-com-supabase) {% /step %} {% step title="06 · Seu próprio plugin" %} Crie um plugin no incubator seguindo o mesmo contrato dos oficiais. [Abrir →](/pt-BR/docs/tutorial/06-seu-proprio-plugin) {% /step %} {% step title="07 · Publicar" %} Faça o build e coloque o app no ar em um host estático. [Abrir →](/pt-BR/docs/tutorial/07-publicar) {% /step %} {% /steps %} Pronto? [Comece pelo passo 01 →](/pt-BR/docs/tutorial/01-criar-o-app) --- source: https://developers.fayz.ai/pt-BR/docs/tutorial/01-criar-o-app.md --- # 01 · Criar o app Gere o projeto com a CLI, instale as dependências e rode em modo mock. Ao fim deste passo você tem um app Fayz abrindo no navegador — sem configurar nenhuma variável de ambiente. {% steps %} {% step title="Gere o projeto" %} A CLI cria um projeto repo-por-app. A forma é `fayz create `, onde o tipo é `storefront`, `admin` ou `member` e o nome é kebab-case. Rode com `npx` para não instalar nada global: ```bash npx @fayz-ai/cli create admin minha-loja ``` Saída exata: ``` ✓ Created admin app "minha-loja" cd minha-loja npm install npm run dev ``` O comando não tem flags — ele imprime os próximos passos manuais em vez de rodá-los. {% /step %} {% step title="Instale e rode" %} Siga os três passos que a CLI imprimiu: ```bash cd minha-loja npm install npm run dev ``` O app é um projeto Vite. O dev server sobe em `http://localhost:5173`. {% /step %} {% /steps %} {% callout type="tip" %} ✓ Você deve ver: o Vite anunciando `Local: http://localhost:5173/` no terminal e, ao abrir a URL, a tela inicial do app com o nome `minha-loja`. Nenhuma env foi necessária — o backend está em modo `mock`. {% /callout %} Para dados de exemplo ao consumir os pacotes em código (os providers mock nascem vazios), veja [Mock e dados de exemplo](/pt-BR/docs/apps/mock-e-dados-de-exemplo). ## O que foi gerado O comando cria um app pequeno e legível. Cada arquivo tem um papel: | Arquivo | Para que serve | | --- | --- | | `app.manifest.json` | A configuração do app: surfaces, plugins, tema, locale e `backend.provider`. É o arquivo que você mais edita. | | `src/main.tsx` | Ponto de entrada. Monta o app a partir do manifesto. | | `src/plugins.generated.ts` | Mapa dos plugins do manifesto para os factories da plataforma (gerado — não edite à mão). | | `src/registry.tsx` | Seu código custom: blocos, páginas e componentes próprios. | | `src/lib/fayz-runtime.ts` | O runtime do app (ver nota abaixo). | | `vite.config.ts` · `index.html` · `tsconfig.json` | Config padrão de um app Vite + React. | | `.env.example` | Modelo das variáveis do Supabase — você copia para `.env.local` no passo 05. | | `AGENTS.md` | Guia para agentes de IA (ou humanos) trabalharem no app — padrão aberto, não amarrado a nenhum fornecedor. | {% callout type="info" %} Hoje o app local renderiza uma tela-âncora que confirma a fiação do manifesto; o runtime completo (shell, navegação, telas dos plugins) é fornecido pela plataforma Fayz. As edições de manifesto dos próximos passos são a **configuração real** que esse runtime consome — por isso o tutorial é todo feito a partir do `app.manifest.json`. {% /callout %} Deixe o `npm run dev` rodando: os próximos passos editam o manifesto e você recarrega a página para ver o efeito. --- [Próximo: 02 · Explorar a anatomia →](/pt-BR/docs/tutorial/02-explorar-a-anatomia) --- source: https://developers.fayz.ai/pt-BR/docs/tutorial/02-explorar-a-anatomia.md --- # 02 · Explorar a anatomia Antes de mudar qualquer coisa, entenda as quatro peças que fazem o app funcionar: o manifesto, o mapa de plugins gerado, o registry de código custom e o AGENTS.md. Depois deste passo você sabe onde tocar para cada tipo de mudança. ## `app.manifest.json` — o centro de tudo É o arquivo que descreve o app inteiro. Recém-criado, um app admin se parece com isto: ```json { "manifestVersion": 2, "id": "minha-loja", "name": "minha-loja", "backend": { "provider": "mock" }, "locale": { "default": "pt-BR", "supported": ["pt-BR", "en"], "currency": "BRL" }, "theme": { "brand": "violet" }, "surfaces": { "admin": { "scaffold": "admin", "plugins": [{ "id": "dashboard" }], "pages": [] } } } ``` Três blocos importam mais do que os outros: - **`surfaces`** — cada surface é uma face do app (`admin`, `storefront`, `member`). Ela declara um `scaffold` (o layout do shell), a lista de `plugins` e `pages` extras. A navegação é derivada dos plugins: você liga um plugin e as rotas e o menu aparecem — você não escreve rotas à mão. - **`plugins`** — dentro da surface, cada item é só `{ "id": "..." }`. É assim que você adiciona uma capacidade (passo 04). - **`backend`** — `{ "provider": "mock" }` roda com dados de exemplo e zero configuração. No passo 05 você troca para `"supabase"`. ## `src/plugins.generated.ts` — o mapa dos plugins ```ts // Generated by 'fayz create'. Maps manifest plugin ids → platform-bundled plugin factories. export {} ``` Esse arquivo liga os `id`s do manifesto aos factories reais dos plugins. Hoje ele vem vazio porque os plugins do catálogo são resolvidos pelo bundle da plataforma. Trate-o como gerado: você não edita à mão — o manifesto é a fonte da verdade. ## `src/registry.tsx` — o seu código ```tsx // import { registerBlock } from './lib/fayz-runtime' // registerBlock('custom:my-block', MyBlock) export {} ``` É o ponto onde você registra blocos, páginas e componentes próprios (níveis 5–7 da escada de personalização) e depois os referencia no manifesto pelo id `custom:`. Enquanto você só configura, ele fica vazio. ## `AGENTS.md` — o manual para um agente O scaffold inclui um `AGENTS.md` descrevendo a estrutura, a checklist de personalização e o passo a passo do Supabase. A ideia é concreta: você pode abrir este app com um agente de IA e ele já sabe que "personalizar = editar o manifesto, não escrever código novo", onde ficam os arquivos e como conectar um banco real. É documentação para a máquina, versionada junto com o app. Ver também: [Conecte seu agente](/pt-BR/docs/ia/conecte-seu-agente) — como apontar o Claude Code, o Cursor ou o Codex para o `AGENTS.md` e o `llms.txt`. {% callout type="tip" %} ✓ Você deve ver: abrindo o `app.manifest.json`, o bloco `surfaces.admin.plugins` com um único `{ "id": "dashboard" }`. Guarde esse lugar — os próximos passos editam exatamente ele. {% /callout %} --- [← Anterior: 01 · Criar o app](/pt-BR/docs/tutorial/01-criar-o-app) · [Próximo: 03 · Tema e marca →](/pt-BR/docs/tutorial/03-tema-e-marca) --- source: https://developers.fayz.ai/pt-BR/docs/tutorial/03-tema-e-marca.md --- # 03 · Tema e marca Um tema não é uma cor — é um **sistema de decisões encadeadas**. No Fayz você declara três decisões no `app.manifest.json` e o motor de tema do shell deriva a paleta inteira a partir delas. O shell continua o mesmo; só a aparência muda, de forma coerente. ## Passo 1 · Pense no sistema Antes de editar, escolha três coisas — cada uma cascateia por dezenas de tokens: - **Cor da marca** → vira `primary`, o anel de foco, um `accent` derivado e (opcionalmente) a barra lateral colorida. - **Personalidade dos cantos** (o raio) → define botões, cards, inputs e modais de uma vez. - **Estratégia de modo** → claro, escuro ou seguir o sistema operacional. Três decisões, não trinta cores. Esse é o ponto de um Design System. ## Passo 2 · Aplique no manifesto Recém-criado, o app traz `"theme": { "brand": "violet" }`. O bloco aceita três chaves: ```json { "theme": { "brand": "teal", "radius": "lg", "mode": "system" } } ``` Parece pouco — e é de propósito. Cada chave é a raiz de uma cadeia. Veja o que ela desdobra. ### Galeria das 7 marcas Escolher `brand` é escolher uma família inteira. O motor pega o matiz da marca, o aplica em `primary`/`ring` e gira o matiz **−50°** para gerar um `accent` harmônico automaticamente. A tabela abaixo mostra, por marca, o matiz base, o `accent` derivado e onde cada uma brilha: | Marca | Matiz base (HSL) | Vira `primary`/`ring` | `accent` derivado (matiz −50°) | Personalidade · quando usar | | --- | --- | --- | --- | --- | | `blue` | `221 83% 53%` | azul institucional | `171` → ciano-esverdeado | Confiança, corporativo. SaaS B2B, fintech, jurídico. | | `violet` | `262 83% 58%` | violeta premium | `212` → azul | Neutro-premium, criativo, tech. O padrão do scaffold. | | `green` | `142 71% 45%` | verde vivo | `92` → verde-limão | Cuidado e crescimento. Saúde, finanças, sustentabilidade. | | `orange` | `25 95% 53%` | laranja quente | `335` → rosa | Apetite e energia. Food, hospitalidade, varejo. | | `red` | `0 84% 60%` | vermelho forte | `310` → magenta | Urgência e paixão. Esporte, delivery, promoções (cuidado: convive com o `destructive`). | | `pink` | `330 81% 60%` | rosa vibrante | `280` → violeta | Lifestyle e expressão. Beleza, moda, D2C jovem. | | `teal` | `172 66% 50%` | verde-água | `122` → verde | Calma e clareza. Clínicas, wellness, apps de produtividade. | {% callout type="info" %} Os HSL acima são **valores representativos** para você raciocinar sobre a família e o `accent` que sai de cada uma — o runtime da plataforma aplica a variante calibrada de cada nome. A regra de derivação (matiz −50°, mesma saturação e luz) é a mesma; o que muda é o ponto exato de partida. {% /callout %} ### O que cada chave cascateia | Chave | Valor | O que muda de uma vez | | --- | --- | --- | | `brand` | um dos 7 nomes | `primary`, `ring`, `accent` (matiz −50°) e, se você optar, a barra lateral colorida — todos da mesma raiz. | | `radius` | `none` | Cantos retos — leitura **técnica e densa** (tabelas, back-office). | | | `sm` | Arredondamento discreto — **sóbrio**, corporativo. | | | `md` | O meio-termo **equilibrado** — a escolha segura. | | | `lg` | Cantos generosos — **amigável**, tátil no toque. | | | `full` | Pílulas e círculos — **lúdico**, consumer. | | `mode` | `system` | Respeita o SO do usuário — o padrão sensato. | | | `dark` | Sempre escuro — apps noturnos, backstage, salão à noite. | | | `light` | Sempre claro — operação diurna, recepção, balcão. | Repare que `radius` não muda "o botão": muda **botões, cards, inputs e modais** juntos, na mesma proporção. É isso que mantém o app coerente quando você troca uma ponta. ### 3 receitas prontas Copie, cole no `app.manifest.json` e ajuste o `name`. Cada uma é uma combinação testada de marca + raio + modo para um tipo de negócio: **Clínica / saúde** ```json { "theme": { "brand": "green", "radius": "md", "mode": "light" } } ``` Verde comunica cuidado e confiança; `md` equilibra o formal e o acessível; `light` combina com recepção e atendimento diurno. **Food / comanda noturna** ```json { "theme": { "brand": "orange", "radius": "lg", "mode": "dark" } } ``` Laranja é apetite e hospitalidade; `lg` deixa os alvos táteis para o toque rápido; `dark` descansa a vista do salão à noite. **SaaS B2B sóbrio** ```json { "theme": { "brand": "blue", "radius": "sm", "mode": "system" } } ``` Azul institucional passa segurança; `sm` mantém a densidade profissional; `system` respeita o SO do operador ao longo do dia. O `name` no topo do manifesto é o nome exibido — troque-o junto com a cor para a mudança de marca ficar completa: ```json { "name": "Minha Clínica", "theme": { "brand": "green", "radius": "md", "mode": "light" } } ``` ## Passo 3 · Valide Edite o bloco, salve e rode o doctor: ```bash npx @fayz-ai/cli doctor ``` ``` ⚠ plugins referenced by manifest are resolved by the platform bundle, not public npm packages: dashboard 0 error(s), 1 warning(s) ``` {% callout type="tip" %} ✓ Você deve ver: `0 error(s)` no doctor. O aviso sobre plugins resolvidos pelo bundle da plataforma é esperado em modo mock — não é um erro. O doctor confirma que o manifesto está bem-formado e íntegro antes de a plataforma consumi-lo. {% /callout %} ## Por baixo do capô Essas três chaves são a **expressão resumida** de um sistema maior. A partir da sua cor de marca, o motor de tema (`createTheme` / `applyTheme`, em `@fayz-ai/saas`) deriva a cadeia — verificado no código: | Token derivado | De onde sai | | --- | --- | | `primary` | a marca, com `primaryForeground` branco para o contraste sobre o preenchimento. | | `ring` (foco) | a mesma marca — o anel herda a identidade. | | `accent` | o matiz da marca girado **−50°** (mesma saturação e luz), um segundo tom harmônico. | | barra lateral (opcional) | o fundo do rail recebe a marca, texto branco, borda **−12%** de luz, item ativo **−15%**, ícones secundários em `matiz 35% 82%`. | | neutros, superfícies, semânticas, raio, sombras, tipografia | de um **preset base curado** (o admin clássico), no qual a sua marca se encaixa. | O `applyTheme` então escreve cada valor como **variável CSS** no documento (`--primary`, `--ring`, `--accent`, `--sidebar`, `--button-radius`, `--font-family`, `--shadow-sm/md/lg`). Sua marca é **uma entrada** num sistema de tokens já consistente. {% callout type="info" %} A derivação acontece no **runtime da plataforma Fayz**, que consome o bloco `theme` para pintar o shell inteiro. Na pré-visualização local do scaffold — hoje uma tela-âncora — a paleta ainda não é aplicada. Por isso este passo se valida pelo `doctor` (config válida), e o resultado visual completo aparece no runtime da plataforma. {% /callout %} Quer a cadeia inteira — as oito famílias de tokens, o raciocínio de contraste e o fluxo de desenhar o sistema antes de configurar? Está no capítulo [Design System e tema](/pt-BR/docs/apps/temas). Ver também: a [Referência completa de tokens](/pt-BR/docs/referencia/tokens) — a consulta rápida das famílias e das variáveis CSS que o motor escreve. ## Além das 3 chaves {% badge status="experimental" /%} O manifesto expõe três decisões hoje, mas o motor por baixo é bem mais rico. Já existem, atrás do runtime da plataforma: **cor livre em HSL** (não só os 7 nomes), **11 famílias de fonte** (de `inter` e `geist` a `outfit` e `manrope`), **níveis de sombra** (`none` → `subtle` → `medium` → `bold`), a barra lateral em modo `brand` ou `neutral`, e **presets** base inteiros. Expor essas famílias no manifesto — sem inflá-lo — é o próximo passo do contrato de tema; o sentido é evolutivo, não pronto. {% callout type="tip" %} Dica de fluxo: desenhe o sistema como um **artefato** primeiro. Uma sessão de design com IA gera um `tokens.css` com as famílias completas (marca, tints, tipografia, elevação); o bloco `theme` do manifesto vira a **expressão condensada** desse artefato, e você promove tokens para as costuras de [Personalização](/pt-BR/docs/apps/personalizacao) conforme cresce. O manifesto declara o tema — não é onde você o descobre. {% /callout %} --- [← Anterior: 02 · Explorar a anatomia](/pt-BR/docs/tutorial/02-explorar-a-anatomia) · [Próximo: 04 · Adicionar um plugin →](/pt-BR/docs/tutorial/04-adicionar-um-plugin) --- source: https://developers.fayz.ai/pt-BR/docs/tutorial/04-adicionar-um-plugin.md --- # 04 · Adicionar um plugin Adicionar uma capacidade ao app é uma linha de JSON. Você liga um plugin do catálogo no manifesto e a navegação e as telas crescem sozinhas — você não escreve rotas, o core deriva do plugin. ## Ligue o plugin no manifesto Os pacotes de plugin já vêm nas dependências do app gerado — `@fayz-ai/plugin-crm`, `plugin-tasks`, `plugin-agenda`, `plugin-financial`, `plugin-inventory` e outros já estão no `package.json`. Ligar um é adicionar seu `id` à lista `plugins` da surface. Abra o `app.manifest.json` e adicione `crm` (e, de brinde, `tasks`) ao lado do `dashboard`: ```json { "surfaces": { "admin": { "scaffold": "admin", "plugins": [ { "id": "dashboard" }, { "id": "crm" }, { "id": "tasks" } ] } } } ``` Salve. Você **não** precisa mexer no `src/plugins.generated.ts` por enquanto — a pré-visualização local valida a fiação pelo manifesto; as telas completas vêm do runtime que consome essa mesma lista. ## Confirme com o doctor ```bash npx @fayz-ai/cli doctor ``` ``` ⚠ manifest references plugin(s) [dashboard, crm, tasks] — each id must resolve to an installed @fayz-ai/plugin-* factory wired in src/plugins.generated.ts or src/config/app.tsx 0 error(s), 1 warning(s) ``` Repare que a lista do aviso cresceu: `dashboard, crm, tasks`. O doctor está lendo o manifesto e lembrando que cada id precisa corresponder a um pacote `@fayz-ai/plugin-*` instalado — que já veio nas dependências do app gerado. {% callout type="tip" %} ✓ Você deve ver: os três ids — `dashboard, crm, tasks` — no aviso do doctor, com `0 error(s)`. Se você digitar um id que não existe no catálogo, é aqui que o erro aparece. {% /callout %} ## O que acontece na navegação Cada plugin declara sua própria navegação e rotas no manifesto do plugin. Quando você o liga na surface, o runtime da plataforma injeta o item de menu e as telas correspondentes — o CRM adiciona a seção de contatos, o Tasks adiciona o quadro de tarefas. É por isso que você nunca edita um roteador: a navegação é derivada da lista de plugins. {% callout type="info" %} Onde a mudança aparece: as telas e o menu dos plugins são renderizados pelo runtime completo da plataforma Fayz, que consome esta mesma lista. A pré-visualização local de hoje é uma tela-âncora, então o passo se valida pelo `doctor` (a capacidade está corretamente ligada). Para navegar pelo catálogo completo de plugins disponíveis, veja a seção [Plugins](/pt-BR/docs/plugins). {% /callout %} Antes de seguir, deixe só `dashboard` na lista se quiser um app enxuto para o próximo passo — ou mantenha os três; qualquer um funciona com o Supabase. --- [← Anterior: 03 · Tema e marca](/pt-BR/docs/tutorial/03-tema-e-marca) · [Próximo: 05 · Dados reais com Supabase →](/pt-BR/docs/tutorial/05-dados-reais-com-supabase) --- source: https://developers.fayz.ai/pt-BR/docs/tutorial/05-dados-reais-com-supabase.md --- # 05 · Dados reais com Supabase Até aqui o app rodou em modo `mock`, com dados de exemplo em memória. Agora você segue o modelo **BYOS — traga o seu próprio Supabase**: conecta um projeto Supabase seu, provisiona nele a mesma forma de schema que a plataforma usa (a biblioteca `core` + os módulos de plugin + os seus incubator) com `fayz db apply`, e vira a chave para dados reais e persistentes. {% steps %} {% step title="Crie o seu projeto Supabase (BYOS)" %} No [dashboard do Supabase](https://supabase.com/dashboard), crie um projeto novo (o plano gratuito basta). Ele é o **seu** banco — o `fayz db apply` só escreve a forma-alvo nele. Você vai precisar de quatro valores dele: - **Project URL** e **anon key** — em Project Settings → API. Ficam no navegador (públicos). - **Project ref** — em Project Settings → General. É o identificador do projeto. - **Personal access token (PAT)** — em Account → Access Tokens. É um segredo de máquina; nunca vai para o navegador nem para o Git. {% /step %} {% step title="Preencha o .env.local" %} O scaffold traz um `.env.example`. Copie para `.env.local` (que já está no `.gitignore`) e preencha: ```bash cp .env.example .env.local ``` ```bash # Runtime (vão para o navegador — só valores públicos) VITE_SUPABASE_URL=https://SEU-REF.supabase.co VITE_SUPABASE_ANON_KEY=sua-anon-key # Tooling (usados pelo `fayz db apply` — NÃO vão para o navegador) SUPABASE_PROJECT_REF=seu-project-ref SUPABASE_PAT=seu-personal-access-token ``` {% /step %} {% step title="Planeje a migração (dry-run)" %} Antes de tocar no banco, veja o plano. O `--dry-run` não faz nenhuma chamada de rede e não lê o seu PAT — é seguro rodar sempre: ```bash npx @fayz-ai/cli db apply --dry-run ``` Saída real em um app recém-criado: ``` ▸ Migration plan for minha-loja 1. [spine ] @fayz-ai/db — no files Notes: ⚠ installed @fayz-ai/db ships no migrations/ — the spine step is empty (upgrade to @fayz-ai/db >= 0.1.3 once published) ⚠ plugin 'dashboard': @fayz-ai/plugin-dashboard ships no src/migrations — skipped Summary: 1 step(s), 0 sql file(s). (dry-run — nothing was applied) ``` A ordem do plano é sempre a mesma: o **core** primeiro, depois as migrations **versionadas de cada plugin**, e por fim os seus **incubator**. Na saída do CLI atual isso aparece com os rótulos `spine → drizzle → seed → plugins → incubator` (os três primeiros são o core — o rótulo migra para `core` na wave de *industry pools*). Cada passo só entra se o pacote correspondente trouxer arquivos SQL. Com as versões atuais dos pacotes o plano ainda é enxuto; conforme os plugins passam a trazer migrations, novos passos aparecem aqui. {% /step %} {% step title="Aplique de verdade" %} Quando o plano estiver como você quer, aplique. Este é o comando que roda com as **suas** credenciais (o `SUPABASE_PROJECT_REF` e o `SUPABASE_PAT` do `.env.local`) e escreve no banco via Supabase Management API: ```bash npx @fayz-ai/cli db apply ``` Ele pede confirmação antes de aplicar (use `--yes` para pular o prompt em CI). Sem as duas variáveis definidas, ele para com um erro claro — de propósito, para nunca aplicar contra o projeto errado. {% /step %} {% step title="Vire a chave para o Supabase" %} Com o esquema no lugar, troque o backend no `app.manifest.json` de `mock` para `supabase` e informe o ref: ```json { "backend": { "provider": "supabase", "projectRef": "seu-project-ref" } } ``` E valide tudo com o doctor: ```bash npx @fayz-ai/cli doctor ``` {% /step %} {% /steps %} {% callout type="tip" %} ✓ Você deve ver: no dry-run, a linha `Summary: N step(s) ... (dry-run — nothing was applied)`. Depois do `db apply` real, a confirmação de que a migração foi aplicada. E o `doctor` com `0 error(s)` após virar o `provider` para `supabase`. {% /callout %} O modelo de dados tem três camadas — a biblioteca `core` (as tabelas-base compartilhadas), as tabelas `plg_` que cada plugin instala, e as tabelas do seu app — todas isoladas por `tenant_id` com RLS. Você não precisa dominar isso agora; o `fayz db apply` monta a ordem correta no seu próprio Supabase. Para o mapa completo, veja [Modelo de dados](/pt-BR/docs/dados/modelo) e [RLS e multi-tenant](/pt-BR/docs/dados/rls). --- [← Anterior: 04 · Adicionar um plugin](/pt-BR/docs/tutorial/04-adicionar-um-plugin) · [Próximo: 06 · Seu próprio plugin →](/pt-BR/docs/tutorial/06-seu-proprio-plugin) --- source: https://developers.fayz.ai/pt-BR/docs/tutorial/06-seu-proprio-plugin.md --- # 06 · Seu próprio plugin Ligar plugins do catálogo é ótimo, mas em algum momento você quer uma capacidade que só existe no seu produto. O incubator é o caminho: um plugin app-local que segue o **mesmo contrato** dos plugins oficiais. É o passo que transforma você de usuário do SDK em autor. ## Gere o plugin ```bash npx @fayz-ai/cli create plugin fidelidade ``` ``` ✓ Created app-local plugin "src/plugins/fidelidade" Add createFidelidadePlugin() to your app's plugins array (see src/plugins/fidelidade/README.md). Run "fayz doctor" to check boundaries. ``` O que foi criado em `src/plugins/fidelidade/`: | Arquivo | Papel | | --- | --- | | `index.ts` | O `PluginManifest`: id, navegação, rotas e a página. O mesmo contrato de um `@fayz-ai/plugin-*`. | | `data/types.ts` | O contrato de dados (`FidelidadeDataProvider`) que todo backend implementa. | | `data/mock.ts` | Provider mock — o plugin já roda sem banco. | | `data/supabase.ts` | Provider real, passando pelo boundary do Fayz (`getSupabaseClientOptional`), nunca importando o SDK do Supabase direto. | | `schema/index.ts` | Onde as migrations do plugin vivem. | | `README.md` | Como fiar o plugin e a checklist de graduação para oficial. | ## O contrato é o mesmo dos oficiais O `index.ts` exporta uma factory que devolve um `PluginManifest` — id, `navigation`, `routes` e uma página. Ele escolhe o provider automaticamente (Supabase quando há backend, mock caso contrário) via `createSafeDataProvider`: ```ts export function createFidelidadePlugin(options?: FidelidadePluginOptions): PluginManifest { const provider = options?.dataProvider ?? createSafeDataProvider( () => createSupabaseFidelidadeProvider(), () => createMockFidelidadeProvider(), ) // ... return { id: 'fidelidade', name: 'Fidelidade', navigation: [{ section: 'main', label: 'Fidelidade', route: '/fidelidade', icon: 'Puzzle' }], routes: [{ path: '/fidelidade', component: Page }], } } ``` Para ligá-lo, adicione `createFidelidadePlugin()` ao array de plugins da config do app (veja o `README.md` do plugin). E confira os limites com o doctor: ```bash npx @fayz-ai/cli doctor ``` {% callout type="tip" %} ✓ Você deve ver: a pasta `src/plugins/fidelidade/` com os seis arquivos, e o `doctor` com `0 error(s)`. O `data/supabase.ts` já usa `getSupabaseClientOptional` — se você importasse `@supabase/supabase-js` direto, o doctor acusaria a quebra de boundary. {% /callout %} ## Onde vão as migrations As tabelas do seu plugin vivem em `schema/index.ts` e são referenciadas no manifesto via `migrations: [...]`: ```ts migrations: [{ id: 'fidelidade-0001', version: '0.1.0', sql: '' }] ``` Quando você rodar `fayz db apply`, o passo `incubator` (o último da ordem) aplica essas migrations junto com o resto — foi por isso que a ordem `spine → drizzle → seed → plugins → incubator` importa. ## De incubator a oficial Promover um plugin app-local para um pacote `@fayz-ai/plugin-*` oficial é **empacotamento, não reescrita**: o manifesto não muda, você só move a pasta. O `README.md` gerado traz a checklist completa de graduação (contrato validado, teste de capacidade, permissões, i18n, boundary limpo). O mesmo contrato que você seguiu aqui é o que os plugins do catálogo seguem. --- [← Anterior: 05 · Dados reais com Supabase](/pt-BR/docs/tutorial/05-dados-reais-com-supabase) · [Próximo: 07 · Publicar →](/pt-BR/docs/tutorial/07-publicar) --- source: https://developers.fayz.ai/pt-BR/docs/tutorial/07-publicar.md --- # 07 · Publicar Chegou a hora de colocar o app no ar. O fluxo é direto: você gera o **build** (que já é o seu teste de compilação), sobe o código no **GitHub** e roda **`fayz deploy`** — um comando que faz a autenticação, conecta o projeto na plataforma e publica numa URL própria. Ao fim deste passo você tem um link `https://.live.fayz.ai` que qualquer pessoa abre. Os comandos `fayz` abaixo rodam via `npx @fayz-ai/cli ` (sem instalar nada global); os exemplos usam a forma curta `fayz` para ficar legível. {% steps %} {% step title="Build + teste de compilação" %} Gere o build de produção. Ele é o seu **teste de compilação**: se o Vite empacota o app sem erro, o código está íntegro para publicar. ```bash npm run build ``` Saída real: ``` vite v5.4.21 building for production... ✓ 34 modules transformed. dist/index.html 0.40 kB │ gzip: 0.27 kB dist/assets/index-tn0RQdqM.css 0.00 kB │ gzip: 0.02 kB dist/assets/index-BERJrSU-.js 143.00 kB │ gzip: 46.00 kB ✓ built in 274ms ``` O resultado é uma pasta `dist/` pronta para servir. Em seguida, rode o doctor para validar o manifesto uma última vez: ```bash fayz doctor ``` ``` ⚠ plugins referenced by manifest are resolved by the platform bundle, not public npm packages: dashboard 0 error(s), 1 warning(s) ``` {% callout type="tip" %} ✓ Você deve ver: `✓ N modules transformed` e `✓ built in …` no build, e `0 error(s)` no doctor. O aviso sobre plugins resolvidos pelo bundle da plataforma é **esperado** — não é um erro. Se o build falhar, é aqui que você descobre, antes de subir qualquer coisa. {% /callout %} {% /step %} {% step title="Push no GitHub" %} Seu app é o seu repositório. Antes de commitar, adicione a pasta `.fayz/` ao `.gitignore` — ela guarda o vínculo local do deploy (`.fayz/project.json`) e **não deve ir para o repositório**. O scaffold ainda não cobre isso, então faça manualmente: ```bash # na raiz do app, garanta que .fayz/ está ignorado echo ".fayz/" >> .gitignore ``` Agora inicialize o repositório e faça o primeiro commit: ```bash git init git add . git commit -m "feat: meu app Fayz" ``` Crie o repositório remoto — pela CLI do GitHub ou pelo site — e faça o push: ```bash # com a gh CLI gh repo create minha-loja --private --source=. --push # ou, se você criou o repo pelo site: git remote add origin https://github.com//minha-loja.git git push -u origin main ``` {% callout type="tip" %} ✓ Você deve ver: `.fayz/` listado no `.gitignore` **antes** do primeiro `git add`, e o repositório no GitHub com o seu código — sem a pasta `.fayz/`. Confira no site do GitHub que ela não aparece. {% /callout %} {% /step %} {% step title="Autentique com `fayz login`" %} O deploy precisa de um token de acesso. Gere um em **Fayz → Configurações → Tokens de acesso** — ele vem com o prefixo `fayz_`. (O acesso de deploy está em rollout para a rede de desenvolvedores convidados.) ```bash fayz login ``` Cole o token quando pedido. Saída real: ``` ✓ Token salvo em ~/.fayz/credentials.json (permissão 0600). fayz_xxx…xxx O token será validado no primeiro deploy (nenhuma chamada de rede foi feita agora). ``` O login é local: ele só grava o token com permissão `0600` e o valida mais tarde, no primeiro deploy. Comandos úteis: ```bash fayz login --status # mostra o token mascarado, se já houver um fayz logout # remove o credentials.json ``` Em CI ou máquinas efêmeras, use a variável de ambiente `FAYZ_TOKEN` em vez do `fayz login` — a CLI a lê direto. {% callout type="tip" %} ✓ Você deve ver: `✓ Token salvo em ~/.fayz/credentials.json`. O `fayz login --status` deve mostrar o token mascarado. Nenhuma chamada de rede acontece no login — a validação fica para o deploy. {% /callout %} {% /step %} {% step title="Inspecione com `fayz deploy --dry-run`" %} Antes de subir de verdade, rode o dry-run. Ele lista exatamente o que seria enviado e qual seria o destino, **sem nenhuma chamada de rede**: ```bash fayz deploy --dry-run ``` Saída real: ``` ▸ Arquivos a enviar de minha-loja: app.manifest.json (1087 B) index.html (299 B) … Total: 13 arquivo(s), 7099 B. Destino: novo projeto 'minha-loja' (será criado no primeiro deploy) (dry-run — nenhuma chamada de rede foi feita) ``` O nome do projeto é derivado do campo `name` do seu `package.json`. Confira a lista e o destino antes de prosseguir. {% callout type="tip" %} ✓ Você deve ver: a lista de arquivos com tamanhos, o `Total`, o `Destino: novo projeto ''` e a linha `(dry-run — nenhuma chamada de rede foi feita)`. Se o destino ou a contagem de arquivos surpreender, resolva antes do deploy real. {% /callout %} {% /step %} {% step title="Publique com `fayz deploy`" %} Agora suba de verdade: ```bash fayz deploy ``` A CLI confirma o destino antes de agir (use `--yes` para pular a confirmação; em shell não interativo ela recusa rápido em vez de agir sozinha). No **primeiro deploy** ela cria o projeto na plataforma e grava `.fayz/project.json` com `{ projectId, name }`; nos deploys seguintes ela reusa esse arquivo, mandando para o mesmo projeto. O código sobe em lotes, a plataforma builda no servidor (install + Vite) e devolve a **URL final**: ``` 🔗 https://minha-loja.live.fayz.ai ``` {% callout type="info" %} **Acesso em rollout.** O `fayz deploy` está sendo liberado para a rede de desenvolvedores convidados. Se o deploy retornar um erro de autorização, seu token ainda **não** tem acesso de CLI liberado — fale com a gente na [comunidade](/pt-BR/docs/recursos/comunidade). O caminho de [host estático](/pt-BR/docs/deploy/estatico) coloca o mesmo app no ar enquanto isso. {% /callout %} {% callout type="tip" %} ✓ Você deve ver: a URL `https://.live.fayz.ai` no fim do deploy, e um `.fayz/project.json` novo na raiz (ignorado pelo git). Abra a URL — o app deve carregar igual ao `npm run preview`. {% /callout %} {% /step %} {% /steps %} ## Você entregou? Publicar não é só o comando passar — é o app funcionar para quem abre o link. Confira: - **A URL abre** — `https://.live.fayz.ai` carrega sem tela em branco. - **O fluxo principal funciona** — aquele um caminho essencial do seu produto vai do início ao fim. - **Os dados persistem** — o que você cria numa sessão continua lá na próxima (Supabase conectado no [passo 05](/pt-BR/docs/tutorial/05-dados-reais-com-supabase)). **Alternativa: host estático.** Prefere Vercel, Netlify ou Cloudflare Pages? O mesmo `dist/` sobe em qualquer host de arquivos — veja [Deploy estático](/pt-BR/docs/deploy/estatico). ## E agora? Do zero ao ar: você gerou o app, entendeu a anatomia, aplicou a marca, ligou plugins, conectou um banco real, escreveu seu próprio plugin e publicou — tudo a partir do manifesto. Os próximos caminhos: - Explorar o [catálogo de plugins](/pt-BR/docs/plugins) e montar o próximo produto. - Transformar o app numa camada que um agente lê e opera em [IA · Seu app como camada de dados](/pt-BR/docs/ia/seu-app-como-camada-de-dados). - Aprofundar plugins próprios em [Incubator](/pt-BR/docs/plugins-proprios/incubator). --- [← Anterior: 06 · Seu próprio plugin](/pt-BR/docs/tutorial/06-seu-proprio-plugin) · [Voltar ao início do tutorial](/pt-BR/docs/tutorial) --- source: https://developers.fayz.ai/pt-BR/docs/apps/rotas-e-navegacao.md --- # 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). --- source: https://developers.fayz.ai/pt-BR/docs/apps/configuracao.md --- # Configuração O `app.manifest.json` descreve o app inteiro num único arquivo JSON. Ele é a fonte da verdade: surfaces, tema, locale, backend e plugins. Esta página é o mapa de cada bloco de topo — o que ele faz e o que o `fayz doctor` valida. ## A forma do manifesto Um app admin recém-criado se parece com isto (`manifestVersion` sempre `2` nesta geração): ```json { "manifestVersion": 2, "id": "minha-loja", "name": "Minha Loja", "backend": { "provider": "mock" }, "locale": { "default": "pt-BR", "supported": ["pt-BR", "en"], "currency": "BRL" }, "theme": { "brand": "violet" }, "surfaces": { "admin": { "scaffold": "admin", "plugins": [{ "id": "dashboard" }], "pages": [] } } } ``` Os quatro campos obrigatórios são `manifestVersion`, `id`, `name` e `surfaces`. O resto é opcional e tem default sensato. ## Os blocos de topo | Campo | Papel | | --- | --- | | `id` | Identificador em kebab-case (`^[a-z0-9][a-z0-9-]*$`). | | `name` | O nome exibido do app. | | `backend` | De onde vêm os dados. Objeto `{ provider, ... }` — detalhado abaixo. | | `locale` | Idioma, idiomas suportados e moeda. | | `theme` | A marca: `brand`, `radius`, `mode` (veja [Temas](/pt-BR/docs/apps/temas)). | | `permissions` | Declaração de features e ações (deny-by-default no multi-tenant). | | `surfaces` | As faces do app. Pelo menos uma é obrigatória. | ## O bloco `backend` O `provider` decide de onde os dados vêm. Os valores aceitos: | `provider` | Para quê | | --- | --- | | `mock` | Dados de exemplo em memória, zero configuração. É o default do scaffold. Ao consumir os pacotes em código, os providers mock nascem vazios — veja [Mock e dados de exemplo](/pt-BR/docs/apps/mock-e-dados-de-exemplo) para semeá-los. | | `supabase` | Um projeto Supabase real. Acompanha `projectRef`. | | `fayz-api` | A API gerenciada do Fayz. | | `fayz-shop` | O backend de e-commerce do Fayz. | | `custom` | Um adapter próprio, referenciado por `adapterId`. | Trocar de `mock` para `supabase` é o passo do meio do tutorial — veja [Supabase](/pt-BR/docs/dados/supabase): ```json { "backend": { "provider": "supabase", "projectRef": "seu-project-ref" } } ``` ## Surfaces e plugins Dentro de `surfaces`, cada surface declara o `scaffold` (obrigatório), uma lista de `plugins` e uma de `pages`. Ligar uma capacidade é adicionar `{ "id": "..." }` à lista `plugins` — os pacotes já vêm nas dependências do app gerado, então não há nada para instalar nem para editar em `src/plugins.generated.ts`. Cada `pluginRef` aceita `config` (opções do plugin) e `enabled` (para desligar sem remover). Como as rotas e o menu são derivados dessa lista, o detalhe está em [Rotas e navegação](/pt-BR/docs/apps/rotas-e-navegacao). ## Duas formas de configurar O scaffold entrega a forma **manifesto-primeiro**: você edita JSON e a plataforma renderiza. Existe também a forma **código-primeiro**, em que a configuração vive em `src/` (via `defineSaas` / `defineStorefront`). O `fayz doctor` reconhece as duas: um app sem `app.manifest.json` mas com `package.json` é tratado como app código-primeiro — o doctor roda as checagens de boundary e passa. Comece pela forma manifesto; ela cobre a maioria dos casos e é a que a plataforma edita ao vivo. ## Valide sempre Depois de qualquer edição, rode o doctor. Ele confere a estrutura do manifesto, os plugins referenciados e os limites de arquitetura: ```bash npx @fayz-ai/cli doctor ``` Um `id` fora do padrão ou uma surface sem `scaffold` fazem o doctor sair com erro — de propósito, para você pegar o problema antes de subir. Hoje o doctor valida a **estrutura** do manifesto e as fronteiras de arquitetura; a validação dos *valores* de enums (como `backend.provider` ou `theme.brand`) está chegando — um fix de SDK está em PR. --- Próximo: aplique a sua marca em [Temas](/pt-BR/docs/apps/temas). --- source: https://developers.fayz.ai/pt-BR/docs/apps/temas.md --- # Design System e tema Um tema não é uma cor. É um **sistema de decisões encadeadas**: você escolhe uma marca, e dela desce uma paleta derivada, uma semântica por modo (claro/escuro), uma tipografia, uma malha de espaçamento, uma escala de raio, uma elevação e um vocabulário de movimento. Trocar "a cor do app" é, na verdade, mexer numa ponta dessa corrente — e o valor de um Design System é justamente garantir que a corrente inteira continue coerente. No Fayz, o bloco `theme` do manifesto é a **expressão resumida** desse sistema. Você declara pouco; o runtime da plataforma preenche o resto de forma consistente. Antes de escrever esse bloco, vale entender o sistema completo que ele resume. ## As oito famílias de tokens Um Design System maduro organiza suas decisões em famílias. Os valores abaixo vêm do Design System oficial da Fayz — servem de exemplo concreto do nível de riqueza que cada família carrega. | Família | O que decide | Exemplo (Design System da Fayz) | | --- | --- | --- | | **Marca + tints** | a cor-assinatura e suas variações derivadas | `ignite #2FDD4B` → `deep #119A27`, `soft #DFFBE3`, `bg #F2FDF4` | | **Neutros** | a escala de cinza que carrega texto e superfícies | `paper #FAFAF8` → `near-black #0B0F0E` (12 degraus) | | **Secundárias** | acentos pontuais, usados com parcimônia | `yellow #F2DB0F`, `cyan #17C1EA`, `coral #FF6B5C` | | **Semântica por modo** | o mapeamento bg / surface / border / text por tema | claro usa `paper` + texto escuro; escuro inverte para `near-black` + texto branco | | **Tipografia** | famílias e hierarquia por peso | `Outfit` (display), `DM Sans` (corpo), `JetBrains Mono` (código) | | **Espaçamento** | a malha que alinha tudo | grade de **4px** (4, 8, 12, 16, 24, 32…) | | **Radius** | a personalidade dos cantos | `xs 4px` → `sm 8px` → `md 14px` → `lg 22px` → `pill 9999px` | | **Elevação + motion** | sombras, o glow-assinatura e o timing | `shadow-sm` → `shadow-glow` (halo verde); `ease-out cubic-bezier(0.22,1,0.36,1)`, `240ms` | Há ainda uma nona peça, opcional mas característica da marca: o **vidro fosco** (`rgba(255,255,255,0.55)` + `blur 24px`) e a **aurora** — um `radial-gradient` verde que vaza por trás do herói. São receitas, não cores soltas: cada uma combina fundo, borda, desfoque e brilho num único token nomeado. {% callout type="tip" %} Esta própria documentação usa esse sistema: o corpo é **Inter**, o código é **JetBrains Mono**, o botão primário tem o glow verde-ignite e o herói carrega a aurora. Um Design System bem feito se aplica igual num painel administrativo e numa página de docs. {% /callout %} ## De uma cor para um sistema O ponto do Design System aparece quando você segue **uma** decisão até o fim. Pegue a marca `ignite #2FDD4B`: - Como **preenchimento** (um botão, um bloco), o verde vivo `#2FDD4B` funciona com texto quase-preto por cima — o contraste fica alto porque o verde é claro. - Como **texto de link** sobre fundo branco, `#2FDD4B` reprova em contraste. O sistema então usa o `deep #119A27` — a mesma marca, escurecida — para o link ficar legível. - Em **modo escuro**, a lógica inverte: o fundo vira `near-black`, o texto vira branco, e o mesmo verde agora brilha mais forte (a aurora ganha opacidade de `0.55` para `0.65`). - Para **halos de seleção e hover**, entra o `soft #DFFBE3`; para acentos sutis de superfície no claro, o `bg #F2FDF4`. Repare que o raciocínio de **contraste e acessibilidade** é parte do Design System, não um detalhe posterior. Uma decisão de marca virou quatro tokens com papéis distintos, cada um escolhido para permanecer legível no contexto certo. É por isso que declarar dezenas de cores à mão é frágil — e derivá-las de uma raiz é robusto. ## O que o runtime Fayz faz com o seu tema hoje No manifesto você escreve pouco: ```json { "theme": { "brand": "teal", "radius": "lg", "mode": "system" } } ``` - **`brand`** — a cor da marca. Valores prontos: `blue`, `violet`, `green`, `orange`, `red`, `pink`, `teal`. - **`radius`** — o arredondamento: `none`, `sm`, `md`, `lg`, `full`. - **`mode`** — o modo de cor: `light`, `dark` ou `system`. Hoje o `fayz doctor` valida a **estrutura** do manifesto (a presença e a forma do bloco `theme`), mas ainda não os *valores* desses enums — a validação de que `brand`/`radius`/`mode` estão dentro dessas listas está chegando (um fix de SDK está em PR). A partir daí, o motor de tema do shell (`createTheme` / `applyTheme`, em `@fayz-ai/saas`) faz a derivação. Verificado no código, de uma única cor de marca ele produz: - **`primary`** = a marca, com **`primaryForeground` branco** — texto legível sobre o preenchimento colorido. - **`ring`** = a marca — o anel de foco herda a identidade. - **`accent`** = a marca com o **matiz girado ~50°** (mesma saturação e luz), gerando um segundo tom harmônico automaticamente. - Uma **barra lateral colorida** opcional: o motor tinge o fundo do rail com a marca, força texto branco, escurece a borda em ~12% e o item ativo em ~15% de luz, e apaga os ícones secundários (`matiz 35% 82%`) — tudo derivado da mesma raiz para o texto continuar legível sobre a barra saturada. Todo o resto — neutros, superfícies, bordas, semânticas de `success`/`warning`/`destructive`, a escala de raio, as sombras e a tipografia — vem de um **preset base curado** (o padrão é o admin clássico) no qual a sua marca se encaixa. O `applyTheme` então escreve cada valor como uma **variável CSS** no documento (`--primary`, `--ring`, `--accent`, `--sidebar`, `--button-radius`, `--font-family`, `--shadow-sm/md/lg`, e os tokens de vidro como `--surface-backdrop-filter`). Ou seja: a sua marca é **uma entrada** num sistema de tokens maior e já consistente — exatamente o modelo de Design System. {% callout type="info" %} A derivação acontece no **runtime da plataforma Fayz**, que consome o bloco `theme` para pintar o shell inteiro. Na pré-visualização local do scaffold — hoje uma tela-âncora — a paleta ainda não é aplicada. Por isso este passo se valida pelo `doctor` (config válida) e o resultado visual completo aparece no runtime. Nunca conte com a marca renderizada no preview local isolado. {% /callout %} ## Para onde isso caminha {% badge status="experimental" /%} Hoje o manifesto expõe três decisões (marca, raio, modo). A direção é trazer as famílias mais ricas do Design System oficial — escala tipográfica, elevação, vidro fosco e motion — como **costuras de customização**, sem inflar o manifesto. Quando você extrapola o que a config resolve, o caminho já existe: os níveis 5–7 da escada em [Personalização](/pt-BR/docs/apps/personalizacao) deixam você registrar tokens e componentes próprios, referenciados como dado, sem forkar o SDK. ## Fluxo recomendado: o Design System antes do manifesto A ordem que funciona melhor é **de fora para dentro**: 1. **Desenhe o sistema como um artefato primeiro** — um `tokens.css` com as oito famílias, do jeito que o Design System da própria Fayz foi montado numa sessão de design com IA. Ter as cores, os tints, a tipografia e a elevação escritos num só lugar força as decisões de contraste antes de qualquer código. 2. **Resuma no manifesto** — o bloco `theme` vira a expressão condensada desse artefato: a raiz da marca, a personalidade dos cantos e a estratégia de modo. O runtime deriva o resto na direção que o seu artefato já definiu. 3. **Valide com o doctor** — e itere no artefato quando precisar de mais riqueza, promovendo tokens para as costuras de personalização conforme cresce. Assim o manifesto nunca é onde você "descobre" o tema — é onde você o **declara**, depois de já ter pensado no sistema inteiro. Ver também: a [Referência completa de tokens](/pt-BR/docs/referencia/tokens) — a consulta rápida das oito famílias e das variáveis CSS que o runtime escreve. --- Próximo: as costuras para ir além da config em [Personalização](/pt-BR/docs/apps/personalizacao). --- source: https://developers.fayz.ai/pt-BR/docs/apps/personalizacao.md --- # 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). --- source: https://developers.fayz.ai/pt-BR/docs/apps/mock-e-dados-de-exemplo.md --- # Rodando local com dados de exemplo O `backend: { provider: "mock" }` deixa o app rodar sem env — mas "modo mock" não significa "modo populado". Os providers mock **nascem vazios**: você abre a agenda e não há agendamentos, abre o financeiro e não há lançamentos. A promessa de "dados de exemplo" só se cumpre quando você **semeia** o provider na construção. Esta página é o mapa direto dos seams de seed, mais dois detalhes que mordem quem consome os pacotes publicados: o dashboard em mock e o `FAYZ_SDK_SOURCE`. {% callout type="info" %} Isto é sobre o segundo caminho de consumo — código que importa os pacotes `@fayz-ai/*` publicados e monta o app em `src/` (via `defineSaas` / plugin factories), não o app manifesto-primeiro que a plataforma renderiza. Se você está no fluxo do [Quickstart](/pt-BR/docs/quickstart), o mock populado é responsabilidade da plataforma; aqui você faz na mão. {% /callout %} ## Por que o mock nasce vazio Um provider mock é uma implementação em memória do contrato de dados de um plugin. Ele existe para o app **compilar e rodar sem backend** — não para adivinhar que loja você está construindo. Sem seed, a lista está vazia por design. Semear é passar os objetos de domínio na construção do provider; a partir daí o mock os trata como o "banco" existente (cria, edita, filtra em cima deles). Há quatro seams, do mais específico (um plugin) ao mais genérico (uma entidade CRUD). ## Agenda: `createMockAgendaProvider({ seed })` `createMockAgendaProvider` aceita um `MockAgendaSeed` (de `@fayz-ai/plugin-agenda`). Você passa o provider semeado para a factory do plugin via `dataProvider`: ```ts import { createAgendaPlugin, createMockAgendaProvider } from '@fayz-ai/plugin-agenda' import type { MockAgendaSeed } from '@fayz-ai/plugin-agenda' const seed: MockAgendaSeed = { professionals: [ { id: 'p1', name: 'Ana', /* … */ }, ], bookings: [ { id: 'b1', professionalId: 'p1', startsAt: '2026-07-20T14:00:00Z', /* … */ }, ], // schedules? também aceito; qualquer coleção omitida cai no exemplo embutido } export const agenda = createAgendaPlugin({ dataProvider: createMockAgendaProvider({ seed }), }) ``` {% callout type="tip" %} **Atalho:** `createMockAgendaProvider()` **sem seed** já traz um exemplo pronto — uma agenda estilo salão com profissionais e horários embutidos. É o jeito mais rápido de ver a agenda populada; use o `seed` só quando quiser dados do seu próprio cenário (uma clínica, um estúdio). Qualquer coleção que você **omitir** no seed cai de volta nesse exemplo embutido. {% /callout %} ## Financeiro: `createMockFinancialProvider({ seed })` Mesma forma para o financeiro. O `MockFinancialSeed` (de `@fayz-ai/plugin-financial`) pré-popula o ledger — faturas, movimentos, contas, métodos de pagamento: ```ts import { createFinancialPlugin, createMockFinancialProvider } from '@fayz-ai/plugin-financial' import type { MockFinancialSeed } from '@fayz-ai/plugin-financial' const seed: MockFinancialSeed = { invoices: [ /* … */ ], movements: [ /* … */ ], // bankAccounts? cai em duas contas padrão quando ausente; o resto fica vazio se omitido } export const financial = createFinancialPlugin({ dataProvider: createMockFinancialProvider({ seed }), }) ``` Diferente da agenda, o financeiro **não** inventa faturas/movimentos quando o seed é omitido — as coleções ficam vazias (exceto `bankAccounts`, que cai em duas contas padrão). Se quer o módulo populado, passe o seed. ## Uma entidade qualquer: `createMockProvider(entityDef, initialData)` Para CRUD genérico — um plugin próprio, uma entidade sua — `@fayz-ai/core` expõe `createMockProvider`. O segundo argumento é o array inicial: ```ts import { createMockProvider } from '@fayz-ai/core' const provider = createMockProvider(clientEntityDef, [ { id: 'c1', name: 'Cliente Exemplo', email: 'exemplo@teste.com' }, { id: 'c2', name: 'Outro Cliente', email: 'outro@teste.com' }, ]) ``` O primeiro argumento pode ser o `EntityDef` (de onde ele deriva os campos pesquisáveis e a ordenação padrão) ou só um array de chaves pesquisáveis. `initialData` default é `[]` — por isso o vazio. ## Uma página CRUD do SaaS: `createCrudPage(entity, { mockData })` No nível de página, `createCrudPage` (de `@fayz-ai/saas`) aceita `mockData` direto nas opções — útil quando você monta uma tela de listagem sem provider explícito: ```ts import { createCrudPage } from '@fayz-ai/saas' const ClientsPage = createCrudPage(clientEntity, { mockData: [ { id: 'c1', name: 'Cliente Exemplo' }, { id: 'c2', name: 'Outro Cliente' }, ], }) ``` ## O dashboard em mock mostra zeros O `plugin-dashboard` lê o Supabase **direto** para compor seus KPIs — ele não passa pelos providers mock dos outros plugins. Em modo mock, sem Supabase configurado, os cards vêm **zerados**. Semear a agenda ou o financeiro não muda isso: o dashboard não enxerga esses seeds. A saída honesta é **não** contar com o dashboard embutido em modo mock, e sim registrar **widgets custom com `compute`** que derivam dos mesmos seeds. Um widget do tipo KPI aceita um `compute?: () => Promise` — você calcula o número a partir dos seus dados de exemplo: ```ts // um widget que deriva o número dos seeds, em vez de ler o Supabase { id: 'custom:faturas-abertas', compute: async () => ({ value: seed.invoices.filter((i) => i.status === 'open').length }), } ``` Assim o painel reflete o cenário mock em vez de mostrar zeros. Quando você trocar para o backend Supabase real, o dashboard embutido passa a computar de verdade e esses widgets custom viram opcionais. ## `FAYZ_SDK_SOURCE`: fixe os pacotes publicados O helper `fayzVite` (de `@fayz-ai/sdk/vite`) tem um comportamento de conveniência para o monorepo: se um checkout do `fayz-sdk` existir **ao lado** do app (em `../../fayz-sdk`), ele aliassa os imports `@fayz-ai/*` para o **código-fonte local** desse monorepo, não para o `node_modules`. Ótimo para quem desenvolve o SDK; uma armadilha para um app standalone que só quer consumir os pacotes publicados — de repente o app roda contra fonte não publicada que por acaso está no disco. O controle é a env `FAYZ_SDK_SOURCE`. Um app standalone deve fixá-la em `published` nos scripts, garantindo que ele sempre resolva os pacotes de `node_modules`: ```json { "scripts": { "dev": "FAYZ_SDK_SOURCE=published vite", "build": "FAYZ_SDK_SOURCE=published vite build" } } ``` Com `FAYZ_SDK_SOURCE=published`, o `fayzVite` ignora qualquer checkout vizinho e usa exatamente as versões dos seus `dependencies` — que é o que você quer ao testar o app como um dev externo testaria. --- Próximo: o segundo caminho de consumo em [Headless](/pt-BR/docs/apps/headless). --- source: https://developers.fayz.ai/pt-BR/docs/apps/headless.md --- # Headless Até aqui a documentação assumiu o caminho principal: um app gerado que renderiza a partir do manifesto pelo runtime da plataforma. Existe um segundo caminho, para quando você já tem um site sob medida e quer só **algumas** capacidades do Fayz dentro dele — não o shell inteiro. É o modo headless. {% callout type="info" %} Esta página descreve o **conceito e o formato**. O empacotamento headless dos plugins está chegando com os plugins de website (blog, payments, agenda público) — por isso as importações concretas ainda não são mostradas aqui: elas só serão publicadas quando os pacotes exportarem o subpath. {% badge status="experimental" /%} {% /callout %} ## A ideia No caminho principal, o Fayz é dono da página: o shell, o menu e o layout vêm do scaffold, e você liga plugins. No caminho headless, **você** é dono da página — um site bespoke em qualquer framework — e importa de um plugin só o que precisa: os dados e os componentes de uma capacidade, sem o shell. Isso serve para sites de marketing que querem, por exemplo, um blog e um botão de agendamento embutidos no design próprio, sem adotar a navegação do admin. ## O formato: um bundle `{ manifest, Provider }` + subpaths O plano de empacotamento é que cada plugin voltado a website exponha um bundle headless com duas peças: - **`manifest`** — o mesmo `PluginManifest` que descreve a capacidade (o contrato não muda entre os dois caminhos). - **`Provider`** — um provider React que injeta o contexto do plugin (data provider, tenant) na sua árvore, para os seus componentes consumirem via hooks. O componente de cada capacidade é servido por um **subpath** dedicado do pacote (ex.: a peça pública de agendamento, separada da peça de admin). Você monta o `Provider` uma vez na raiz do seu site e usa os componentes headless onde quiser no seu próprio layout. ## Por que o contrato é o mesmo O ponto que faz o headless valer a pena: um plugin não é reescrito para virar headless. O mesmo `PluginManifest` que roda no shell do admin roda dentro do seu site — muda só **quem monta a página**. É a mesma simetria da escada de personalização: o plugin declara a capacidade, e o host (o shell do Fayz ou o seu site) decide como renderizá-la. ## Enquanto isso Se você precisa hoje de um site sob medida com capacidades Fayz, o caminho suportado é o app gerado com um scaffold `storefront` e páginas recompostas via blocos (níveis 3–6 da [escada de personalização](/pt-BR/docs/apps/personalizacao)). O modo headless completo — importar um bundle de plugin dentro de um projeto totalmente seu — chega com os plugins de website. --- Próximo: entenda a biblioteca core que todos esses caminhos compartilham em [Modelo de dados](/pt-BR/docs/dados/modelo). --- source: https://developers.fayz.ai/pt-BR/docs/dados/modelo.md --- # Modelo de dados Para um dev externo, o modelo de dados do Fayz colapsa numa ideia só: **você traz o seu próprio Supabase (BYOS)** e o seu projeto recebe a **mesma forma de schema** que a plataforma usa em escala. Essa forma tem três camadas — a **biblioteca core**, as **tabelas de plugin** (`plg_`) e as **tabelas do seu app** — e uma regra única que faz tudo se encaixar: **`tenant_id` + RLS é a fronteira de isolamento.** Acerte isso e a dúvida clássica — "onde essa tabela mora?" — desaparece. ``` public.* tabelas-base que todo negócio precisa (tenants, people, tenant_members, role_permissions…) plg_* tabelas que um plugin instala e possui (plg_shop_products, plg_courses_*…) suas tabelas o que o seu app/incubator cria por cima (mesmas regras: tenant_id + RLS) ``` {% callout type="info" %} **Arquitetura em transição.** Esta documentação descreve a **forma-alvo** — a biblioteca `core` e as tabelas de plugin com prefixo `plg_` — que está sendo lançada com a wave de *industry pools*. Hoje as tabelas-base não vivem num schema `core.` separado: moram todas em `public.*` (a migração 001 é explícita — *all core entities live directly in the public schema*), e o prefixo `plg_` é uma convenção já adotada por alguns módulos, não uma regra que todos cumprem ainda. O comando e o fluxo já são estes; os rótulos e a nomenclatura migram junto com a wave. {% /callout %} ## A biblioteca core — as tabelas-base A biblioteca **core** (antes chamada `saas_core`) traz o que **todo** negócio precisa. Não é um schema separado com regras próprias — as tabelas moram em `public.*`, prontas e isoladas: | Tabela core | O que guarda | | --- | --- | | `tenants` | os clientes do seu SaaS (um salão, uma clínica) — a raiz do isolamento | | `people` | pessoas do negócio: clientes, contatos, leads | | `tenant_members` | quem trabalha no tenant (profissionais, atendentes) | | `role_permissions` | papéis e permissões dentro do tenant | | `appointments` | agendamentos, reservas, encontros | | `transactions` | movimentos financeiros: entradas e saídas | **Toda tabela carrega `tenant_id` e tem RLS.** É esse par — coluna + policy — que garante que a linha de um tenant seja fisicamente invisível para outro. O isolamento **não** vem de separar schemas; vem do RLS chaveado no `tenant_id`. Esse é o ponto que sustenta o resto do modelo, e o detalhe está em [RLS e multi-tenant](/pt-BR/docs/dados/rls). ## Tabelas de plugin — o prefixo `plg_` é a posse Um plugin instala as **suas próprias tabelas** com o prefixo **`plg_`** (por exemplo `plg_shop_products`, `plg_courses_*`). O prefixo sinaliza posse: se a tabela começa com `plg_`, ela pertence a um plugin, não ao core nem ao seu app. É uma **convenção** — adotada hoje por shop e courses e **recomendada para plugins novos** — não uma regra que todo módulo já cumpre (alguns conectores criam tabelas sem prefixo). Veja as tabelas `plg_` que cada plugin instala — com as colunas-chave — na ficha do plugin no [catálogo](/pt-BR/docs/plugins). Além das tabelas que cria, um plugin **reutiliza** as tabelas do core que precisa, em vez de copiá-las. Se o plugin de agenda precisa saber "quem marcou", ele referencia `public.people`; ele nunca guarda uma cópia da pessoa. Uma fonte de verdade por entidade. Cada plugin embarca as suas migrations, e elas seguem regras que fazem o `db apply` ser reproduzível: - **ordenadas** — a sequência de aplicação é determinística. - **versionadas** — cada migration tem uma versão; o runner sabe o que já rodou. - **fix-forward** — migrations são append-only: nunca edite uma migração já aplicada, escreva a próxima que corrige. Não há `.down.sql`. - **idempotentes** — rodar de novo não quebra nem duplica. ## As tabelas do seu app Quando o seu produto precisa de campos ou tabelas que nem o core nem um plugin trazem, o seu app (ou um [plugin incubator](/pt-BR/docs/plugins-proprios/incubator)) cria as próprias tabelas. É onde a riqueza específica do seu domínio vive. A regra não muda: **precisam carregar `tenant_id` e ter RLS**, exatamente como o core e os plugins. Suas tabelas não são exceção ao isolamento — são iguais a todas as outras. ## A regra de ouro: mesma forma, três tiers A mesma forma de schema — core + `plg_` + suas tabelas, tudo isolado por `tenant_id` + RLS — vale onde quer que o app rode. É isso que faz o seu BYOS ser idêntico ao que a plataforma opera em escala. {% callout type="info" %} **Como a plataforma hospeda em escala (contexto — o seu BYOS é a mesma forma).** A plataforma serve três tiers com o **mesmo shape**: ① um **pool por indústria** — um projeto Supabase compartilhado por muitos tenants da mesma indústria, isolados só por `tenant_id` + RLS; ② **objetos customizados** — tabelas extras no mesmo pool via um mecanismo genérico, sem DDL (ainda sem contrato externo estável); ③ **banco dedicado** — um projeto só seu, com o mesmo shape, onde promover é copiar os dados e trocar a string de conexão. Você não precisa disso para construir: o seu BYOS já nasce na mesma forma, e migrar de tier nunca reescreve o schema. {% /callout %} ## Website e admin: mesmas tabelas, RLS diferente Um erro comum é criar pares de tabela `public_*` (para o site) e `admin_*` (para o painel). **O Fayz nunca faz isso.** O lado do site e o lado do admin leem as **mesmas tabelas** — o que muda é a **policy de RLS** e o **papel** de quem consulta: a equipe do tenant enxerga as linhas do tenant; o cliente final enxerga só as próprias. Uma tabela, duas visões, garantidas pelo banco — não duas tabelas para manter em sincronia. ## Por que isso importa na prática Essa forma única é o que faz o cliente do CRM e a reserva da agenda concordarem sobre o que é "uma pessoa": os dois apontam para a mesma `public.people`. Você não precisa montar nada disso à mão — o `fayz db apply` cria as camadas na ordem certa (core primeiro, depois as migrations versionadas de cada plugin, depois os seus incubator) no seu próprio Supabase. --- Próximo: provisione tudo isso num banco real com BYOS em [Supabase](/pt-BR/docs/dados/supabase). --- source: https://developers.fayz.ai/pt-BR/docs/dados/supabase.md --- # Supabase Dados reais no Fayz seguem o modelo **BYOS — traga o seu próprio Supabase**: você cria o projeto, aponta o app para ele, e o `fayz db apply` provisiona nele a **mesma forma de schema** que a plataforma usa (a [biblioteca core](/pt-BR/docs/dados/modelo) + os módulos versionados de cada plugin + os seus incubator). Sair do modo `mock` para dados reais é, no fim, um comando. Esta página é a referência do fluxo; o passo a passo guiado está no [tutorial 05](/pt-BR/docs/tutorial/05-dados-reais-com-supabase). O caminho tem quatro passos: **crie o projeto → preencha o `.env` → rode `fayz db apply` → vire o provider**. O `db apply` lê os pacotes instalados, monta a ordem de migração (core → módulos de plugin versionados → incubator) e a aplica no **seu** projeto via Management API. {% callout type="info" %} **Arquitetura em transição.** Esta documentação descreve a **forma-alvo** — a biblioteca `core` e as tabelas de plugin com prefixo `plg_` — que está sendo lançada com a wave de *industry pools*. A wave de pacotes publicada hoje ainda embarca a nomenclatura anterior (o CLI, por exemplo, rotula o primeiro passo do plano como `spine`, que vira `core`). O comando e o fluxo já são estes; só os rótulos internos migram junto com a wave. Onde o texto mostra saída real do CLI, ela aparece com o rótulo atual. {% /callout %} ## As quatro credenciais Um projeto Supabase te dá quatro valores, com papéis diferentes: - **Project URL** e **anon key** (Project Settings → API) — vão para o navegador, são públicos. - **Project ref** (Project Settings → General) — o identificador do projeto. - **Personal access token / PAT** (Account → Access Tokens) — segredo de máquina; nunca vai para o navegador nem para o Git. No `.env.local` (git-ignored) eles se separam por prefixo: `VITE_` para o que é público, sem prefixo para o que é ferramenta. ```bash # Runtime (vão para o navegador — só valores públicos) VITE_SUPABASE_URL=https://SEU-REF.supabase.co VITE_SUPABASE_ANON_KEY=sua-anon-key # Tooling (usados pelo `fayz db apply` — NÃO vão para o navegador) SUPABASE_PROJECT_REF=seu-project-ref SUPABASE_PAT=seu-personal-access-token ``` O CLI também aceita os aliases `SUPABASE_REF` e `SUPABASE_ACCESS_TOKEN`, e lê primeiro do ambiente do processo, depois de `/.env.local`, depois de `/.env` (os arquivos nunca sobrescrevem o ambiente). ## Planeje antes de aplicar (dry-run) O `--dry-run` não faz nenhuma chamada de rede e não lê o seu PAT — é seguro rodar sempre: ```bash npx @fayz-ai/cli db apply --dry-run ``` {% callout type="tip" %} O `--dry-run` pressupõe que você já rodou `npm install`: ele lê os pacotes `@fayz-ai/*` do seu `node_modules` para montar o plano. Sem o `@fayz-ai/db` instalado, o comando **erra** em vez de imprimir o plano — instale as dependências antes. {% /callout %} Ele imprime o plano ordenado e para. A ordem é **sempre** a mesma: o **core** primeiro, depois as migrations **versionadas de cada plugin**, e por fim os seus **incubator**. Na saída atual do CLI isso aparece com os rótulos: ``` spine → drizzle → seed → plugins → incubator ``` onde `spine`/`drizzle`/`seed` são os passos do core (o rótulo migra para `core` na wave de *industry pools*), `plugins` são os módulos versionados de cada plugin, e `incubator` são as suas tabelas. Cada passo só entra se o pacote correspondente trouxer arquivos SQL. Com as versões atuais dos pacotes o plano ainda é enxuto — conforme os plugins passam a trazer migrations, novos passos aparecem aqui. Não estranhe um aviso de "core vazio" no dry-run: o `@fayz-ai/db` publicado ainda não embarca migrations nessa geração, e o próprio comando avisa qual versão resolve isso. ## Aplique de verdade Quando o plano estiver como você quer, aplique. Este comando roda com as **suas** credenciais e escreve no banco: ```bash npx @fayz-ai/cli db apply ``` Ele pede confirmação antes de aplicar; use `--yes` para pular o prompt em CI. Sem `SUPABASE_PROJECT_REF` e `SUPABASE_PAT` definidos, ele para com um erro claro — de propósito, para nunca aplicar contra o projeto errado. Flags úteis para aplicar em pedaços: | Flag | Efeito | | --- | --- | | `--dry-run` | Só imprime o plano ordenado; nenhuma chamada de rede. | | `--yes`, `-y` | Pula a confirmação (obrigatório em shells não interativos). | | `--spine-only` | Aplica só o core do `@fayz-ai/db` (a flag mantém o rótulo `spine` na wave atual). | | `--plugins-only` | Aplica só as migrations de plugins + incubator. | | `--only-plugins a,b` | Restringe o passo de plugins aos ids nomeados. | ## Vire a chave Com o esquema no lugar, troque o backend no `app.manifest.json` de `mock` para `supabase` e informe o ref: ```json { "backend": { "provider": "supabase", "projectRef": "seu-project-ref" } } ``` E valide: ```bash npx @fayz-ai/cli doctor ``` O `fayz db apply` cuida da ordem das camadas por você — core, depois os módulos de plugin, depois os seus incubator — no seu próprio Supabase. Você não escreve o SQL do core à mão. Para entender o que está sendo criado, veja [Modelo de dados](/pt-BR/docs/dados/modelo). --- Próximo: como o isolamento entre tenants é garantido em [RLS e multi-tenant](/pt-BR/docs/dados/rls). --- source: https://developers.fayz.ai/pt-BR/docs/dados/rls.md --- # RLS e multi-tenant Todo app Fayz é multi-tenant: vários clientes (tenants) compartilham o mesmo banco. O isolamento entre eles **não** é garantido no código da aplicação, e **não** vem de separar schemas — é garantido **no banco**, com Row Level Security (RLS) do Postgres. O RLS **é** a fronteira de isolamento do modelo: uma linha de um tenant é fisicamente invisível para os outros, mesmo que a aplicação erre. ## A regra única: `tenant_id` + RLS A regra é a mesma em todas as camadas do [modelo de dados](/pt-BR/docs/dados/modelo) — core, tabelas `plg_` de plugin e as tabelas do seu app: toda tabela carrega uma coluna `tenant_id` e tem uma policy de RLS chaveada nela. A forma **canônica** escopa a linha aos tenants a que o usuário logado pertence: ```sql CREATE POLICY tenant_isolation ON USING (tenant_id IN ( /* tenants do usuário logado */ )); ``` O conjunto de tenants do usuário vem de uma função no schema `public`, resolvida a partir do vínculo do usuário com cada tenant. A policy vale para SELECT, INSERT, UPDATE e DELETE. Resultado: uma query nunca enxerga uma linha de um tenant ao qual o usuário não pertence — o Postgres filtra antes de a aplicação ver. {% callout type="info" %} O **conceito** — policy escopada por `tenant_id` ao conjunto de tenants do usuário — é estável. O **nome exato** da função e o texto SQL literal dependem da wave de pacotes instalada e podem mudar de rótulo; trate o SQL acima como a forma, não como uma assinatura fixa. {% /callout %} ## Website e admin: mesmas tabelas, papéis diferentes O isolamento por tenant é só o primeiro eixo. O segundo é **quem, dentro do tenant, vê o quê** — e ele também mora no RLS, sobre as **mesmas tabelas**. O lado do site e o lado do admin não têm tabelas separadas (`public_*`/`admin_*`); têm **policies e papéis diferentes** sobre a mesma tabela: o `staff` enxerga as linhas do tenant, o cliente final enxerga só as próprias. É por isso que o Fayz nunca duplica tabelas por superfície — uma tabela, várias visões, todas garantidas pelo banco. ## Canônico vs. deferido Nem todo plugin escreve a policy inline, e isso é intencional: - **canônico** — a policy escreve a forma canônica (o `tenant_id` escopado ao conjunto de tenants do usuário) direto na migration do plugin. - **deferido** — o plugin habilita RLS (`ENABLE ROW LEVEL SECURITY`) mas **não** cria a policy; a tabela (com coluna `tenant_id`, tipo `BASE TABLE`, sem prefixo `_`) é capturada por um bloco de auto-detecção do app, que emite **exatamente** a policy canônica no momento do apply. Um plugin deferido, portanto, **aterrissa como canônico** num banco real — não é uma divergência, só um deferimento de *onde o texto da policy mora*. As duas formas produzem o mesmo isolamento. Qualquer outra forma (`divergent`, `no-rls`) é tratada como problema a padronizar antes de mergear. ## As tabelas do seu app também isolam As tabelas que o seu app ou incubator cria não são exceção. Uma tabela de clientes ou de agendamentos que você adicione **precisa** carregar `tenant_id` e ter RLS. É fácil esquecer, porque essas tabelas são suas; a regra vale igual para elas — e para as tabelas `plg_` dos plugins. ## Migrations são append-only depois de aplicadas Um detalhe operacional que evita corrupção silenciosa: **uma migration que já rodou contra qualquer banco real é imutável.** Corrija com uma migration *nova*, nunca editando o arquivo — o arquivo divergiria do banco em silêncio. A exceção é antes do primeiro apply: um app greenfield, ou o schema-fonte de um plugin que ainda não rodou, pode ser editado no lugar (é até preferível — um apply novo deve já produzir a forma final). A regra de bolso: *já tocou um banco vivo? → migration nova. Nunca aplicou? → edita no lugar.* {% callout type="tip" %} Você quase nunca escreve essas policies à mão. O `fayz db apply` emite a forma canônica por você, e o padrão de tabelas do modelo (core, `plg_`, suas tabelas) já garante que toda tabela nova entre isolada. O que esta página te dá é o *porquê* — para você reconhecer uma tabela mal isolada quando vir uma. {% /callout %} --- Próximo: como o usuário logado é resolvido em [Auth — visão geral](/pt-BR/docs/auth/visao-geral). --- source: https://developers.fayz.ai/pt-BR/docs/auth/visao-geral.md --- # Auth — visão geral A autenticação no Fayz é abstraída por um contrato: o `AuthAdapter`. O mesmo `useAuth` vale rodando contra o Supabase em produção ou contra um adapter mock nos previews. O backend de auth é um detalhe que você troca — o código que consome auth não muda. ## O contrato: `AuthAdapter` Um adapter implementa as operações de sessão — `getSession`, `signIn`, `signUp`, `signOut`, `signInWithOAuth`, `resetPassword`, `onAuthStateChange` e afins. O `@fayz-ai/auth` traz dois de fábrica: - **`createSupabaseAuthAdapter({ supabaseUrl, supabaseAnonKey })`** — auth real via Supabase Auth. Mapeia usuário e sessão do Supabase para os tipos do Fayz (`AuthUser`, `AuthSession`). - **`createMockAuthAdapter()`** — um usuário simulado persistido em `localStorage`, para desenvolvimento e previews sem backend. Ele já vem "logado" como um usuário demo. Trocar de um para o outro é trocar a factory — nada mais. ## Consumindo: `AuthProvider` + `useAuth` Num app código-primeiro, você monta o `AuthProvider` na raiz, passando o adapter escolhido, e consome o estado com o hook `useAuth`: ```tsx import { AuthProvider, useAuth, createSupabaseAuthAdapter } from '@fayz-ai/auth' const adapter = createSupabaseAuthAdapter({ supabaseUrl: import.meta.env.VITE_SUPABASE_URL, supabaseAnonKey: import.meta.env.VITE_SUPABASE_ANON_KEY, }) function Root() { return ( ) } ``` ```tsx function UserBadge() { const { user, isAuthenticated, signOut } = useAuth() if (!isAuthenticated) return Visitante return } ``` O `useAuth` expõe `user`, `session`, `isLoading`, `isAuthenticated`, `error` e as ações (`signIn`, `signUp`, `signOut`, `signInWithOAuth`, `resetPassword`, …). Chamá-lo fora de um `` lança um erro — de propósito. ## Como isso se aplica no scaffold manifesto-primeiro Aqui está a parte honesta. No app gerado pelo `fayz create` — o caminho manifesto-primeiro — **você não monta o `AuthProvider` à mão**. O runtime da plataforma lê o `backend.provider` do manifesto e conecta o adapter correspondente por você: `mock` usa o adapter simulado; `supabase` usa o adapter real com as credenciais do seu `.env.local`. A auth "acompanha" o backend que você declara — trocar o `provider` no manifesto já troca o adapter de auth. O `AuthProvider` / `useAuth` explícitos que você viu acima são o caminho **código-primeiro**: apps que montam a própria árvore React (via `defineSaas` ou headless) e querem controle direto sobre onde a sessão entra. Os dois caminhos usam o mesmo contrato `AuthAdapter` — muda só quem monta o provider. {% callout type="info" %} Resumo: **manifesto-primeiro** → o adapter de auth segue `backend.provider`, sem código. **Código-primeiro / headless** → você monta o `AuthProvider` com o adapter da sua escolha. Contrato idêntico nos dois. {% /callout %} ## Auth e o multi-tenant A sessão resolvida pela auth é o que alimenta a função `public.user_tenant_ids()` no banco — ou seja, é a auth que decide, na ponta, quais linhas o RLS deixa você ver. Auth e isolamento andam juntos; veja [RLS e multi-tenant](/pt-BR/docs/dados/rls). --- Próximo: crie a sua primeira capacidade em [Incubator](/pt-BR/docs/plugins-proprios/incubator). --- source: https://developers.fayz.ai/pt-BR/docs/plugins-proprios/incubator.md --- # Incubator O incubator é onde os plugins nascem: uma pasta dentro do seu app que segue o **mesmo contrato** dos plugins oficiais. É o caminho para uma capacidade que só existe no seu produto — e é o passo que transforma você de usuário do SDK em autor. ## Gere o plugin ```bash npx @fayz-ai/cli create plugin fidelidade ``` ``` ✓ Created app-local plugin "src/plugins/fidelidade" Add createFidelidadePlugin() to your app's plugins array (see src/plugins/fidelidade/README.md). Run "fayz doctor" to check boundaries. ``` O que nasce em `src/plugins/fidelidade/`: | Arquivo | Papel | | --- | --- | | `index.ts` | O `PluginManifest`: id, navegação, rotas e a página. O mesmo contrato de um `@fayz-ai/plugin-*`. | | `data/types.ts` | O contrato de dados (`FidelidadeDataProvider`) que todo backend implementa. | | `data/mock.ts` | Provider mock — o plugin já roda sem banco. | | `data/supabase.ts` | Provider real, passando pelo boundary do Fayz (`getSupabaseClientOptional`), nunca importando o SDK do Supabase direto. | | `schema/index.ts` | Onde as migrations do plugin vivem. | | `README.md` | Como fiar o plugin e a checklist de graduação. | ## O contrato é o mesmo dos oficiais O `index.ts` exporta uma factory que devolve um `PluginManifest` — id, `navigation`, `routes` e uma página. Ele escolhe o provider automaticamente (Supabase quando há backend, mock caso contrário) via `createSafeDataProvider`: ```ts export function createFidelidadePlugin(options?: FidelidadePluginOptions): PluginManifest { const provider = options?.dataProvider ?? createSafeDataProvider( () => createSupabaseFidelidadeProvider(), () => createMockFidelidadeProvider(), ) // ... return { id: 'fidelidade', name: 'Fidelidade', icon: 'Puzzle', version: '0.1.0', navigation: [{ section: 'main', position: 50, label: 'Fidelidade', route: '/fidelidade', icon: 'Puzzle' }], routes: [{ path: '/fidelidade', component: Page }], } } ``` Para ligá-lo, adicione `createFidelidadePlugin()` ao array de plugins da config do app (o `README.md` gerado mostra onde). Depois confira os limites: ```bash npx @fayz-ai/cli doctor ``` ## O boundary é obrigatório O `data/supabase.ts` gerado **nunca** importa `@supabase/supabase-js` direto — ele obtém o cliente por `getSupabaseClientOptional()`, o boundary do Fayz, e escopa a query por `tenant_id`: ```ts import { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core' // ... const { data, error } = await sb() .from('fidelidade') .select('*') .eq('tenant_id', getActiveTenantId()) ``` Se você trocasse isso por um import direto do SDK do Supabase, o `fayz doctor` acusaria a quebra de boundary. Essa é a regra que mantém o seu plugin promovível — o detalhe está em [Padrões](/pt-BR/docs/plugins-proprios/padroes). ## Onde vão as migrations As tabelas do seu plugin vivem em `schema/index.ts` e são referenciadas no manifesto via `migrations: [...]`: ```ts migrations: [{ id: 'fidelidade-0001', version: '0.1.0', sql: '' }] ``` No `fayz db apply`, o passo `incubator` (o último da ordem) aplica essas migrations junto com o resto — por isso a ordem `spine → drizzle → seed → plugins → incubator` importa. ## De incubator a oficial Promover um plugin app-local para um pacote `@fayz-ai/plugin-*` oficial é **empacotamento, não reescrita**: o manifesto não muda, você move a pasta para um pacote próprio. O `README.md` gerado traz a checklist completa de graduação (contrato validado, teste de capacidade, migrations fiadas, permissões declaradas, i18n completo, boundary limpo). O mesmo contrato que você seguiu aqui é o que os plugins do catálogo seguem — não há nada que um plugin oficial faça que o seu não possa. --- Próximo: cada campo que um plugin pode declarar em [Manifesto do plugin](/pt-BR/docs/plugins-proprios/manifesto). --- source: https://developers.fayz.ai/pt-BR/docs/plugins-proprios/manifesto.md --- # Manifesto do plugin Um plugin se descreve inteiro por um objeto: o `PluginManifest`. Ele declara o que o plugin é — navegação, rotas, widgets, dados, permissões — e o runtime faz o resto. Plugins declaram; o core resolve. Esta página é o tour pelos campos; a referência exaustiva está em [referência do manifesto do plugin](/pt-BR/docs/referencia/plugin-manifest). ## O núcleo obrigatório Quatro campos identificam qualquer plugin, mais os dois seams que dão a ele um lugar na UI: ```ts { id: 'fidelidade', name: 'Fidelidade', icon: 'Puzzle', version: '0.1.0', navigation: [ { section: 'main', position: 50, label: 'Fidelidade', route: '/fidelidade', icon: 'Puzzle' }, ], routes: [{ path: '/fidelidade', component: Page }], } ``` - **`id`** — identificador único do plugin. - **`name`** / **`icon`** / **`version`** — rótulo, ícone e versão. - **`navigation`** — os itens de menu (veja [Rotas e navegação](/pt-BR/docs/apps/rotas-e-navegacao)). - **`routes`** — o mapeamento `path → componente`. Um componente sempre pode ser dado **direto** (`component`) ou por **id de registry** (`componentId`) — exatamente um dos dois. ## Os seams de extensão Além do núcleo, o manifesto tem uma família de campos opcionais — cada um é um "seam" pelo qual o plugin estende a plataforma sem tocar em nenhum outro plugin: | Seam | O que declara | | --- | --- | | `settings` | Abas na tela de configurações do plugin. | | `widgets` | Componentes injetados em zonas nomeadas do shell (`WidgetZone`). | | `dashboardWidgets` | KPIs, gráficos e tabelas que o plugin contribui ao dashboard. | | `events` | Eventos que o plugin emite no bus (`agenda.booking.confirmed`, …). | | `aiTools` | Ferramentas que um agente de IA pode chamar (modo `read` ou `persist`). | | `capabilities` | As capacidades declaradas do plugin (para introspecção). | | `entities` | Entidades de dados que o plugin registra para CRUD. | | `permissions` / `declaredFeatures` | Features e ações para o controle de acesso. | | `connectors` | Conectores para provedores externos (o plugin como addon de outro). | | `migrations` | O SQL das tabelas que o plugin possui (convenção `plg_`), cada uma com `tenant_id` + RLS. | | `diagnostics` | Pré-requisitos de backend que o `fayz doctor` verifica (RPCs, views, tabelas, env). | | `onboarding` | Um fluxo de primeiro uso. | | `locales` | Traduções (`en`, `pt-BR`, …). | Você declara só o que usa. Um plugin mínimo — como o gerado pelo incubator — traz `id`, `name`, `icon`, `version`, `navigation` e `routes`, e nada mais. ## `apiVersion`: o contrato tem versão O campo opcional `apiVersion` fixa a versão do contrato de plugin que o manifesto foi escrito para. O runtime **recusa** um plugin construído para um contrato mais novo do que ele suporta — é o mecanismo que impede um plugin de uma geração futura de rodar meio quebrado numa plataforma antiga. Omitir significa "compatível/legado". ## Por que declarativo O manifesto ser dado (e não código imperativo) é o que dá as três propriedades que sustentam a plataforma: - **Introspecção** — a plataforma sabe exatamente o que um plugin contribui sem executá-lo; é assim que o `fayz doctor` verifica pré-requisitos e o editor monta seletores. - **Simetria** — um plugin app-local e um oficial usam o mesmo tipo, então promover um é empacotar, não reescrever. - **Segurança de upgrade** — os seams são um contrato versionado; a implementação por trás deles pode mudar livremente. --- Próximo: as convenções que mantêm um plugin bem-comportado em [Padrões](/pt-BR/docs/plugins-proprios/padroes). --- source: https://developers.fayz.ai/pt-BR/docs/plugins-proprios/padroes.md --- # Padrões Um plugin que segue o contrato *funciona*. Um plugin que segue os **padrões** compõe: convive com os outros plugins, aceita um backend real sem reescrita e é promovível a oficial. Esta página são as convenções que fazem essa diferença. ## Factory, não instância Um plugin é exportado como uma **factory** — uma função que devolve o `PluginManifest` — não como um objeto pronto. Isso deixa quem monta o app injetar opções (um provider, uma posição de menu, um vertical) sem editar o plugin: ```ts export function createFidelidadePlugin(options?: FidelidadePluginOptions): PluginManifest { // ... } ``` Ligar o plugin é chamar a factory no array de plugins. Configurar é passar opções. Nunca é editar o interior do plugin. ## Provider-first: o dado é um contrato A UI do plugin nunca fala com um banco direto. Ela fala com um **`DataProvider`** — uma interface que todo backend implementa. O plugin define o contrato em `data/types.ts`, entrega um `mock` e um `supabase`, e escolhe entre eles com `createSafeDataProvider`: ```ts const provider = options?.dataProvider ?? createSafeDataProvider( () => createSupabaseFidelidadeProvider(), // usado quando há backend () => createMockFidelidadeProvider(), // fallback sem banco ) ``` O ganho: o plugin roda no dia zero (mock), e trocar para dados reais não toca em nenhuma tela — só troca o provider. É o mesmo padrão que faz um plugin ser testável sem infra (veja [Testar e debugar](/pt-BR/docs/testar-e-debugar)). ## O boundary de provider: fale com o Fayz, não com o provedor A regra que o `fayz doctor` fiscaliza: um app ou plugin **não** importa SDKs de provedor direto (`@supabase/supabase-js`, `mercadopago`, `stripe`, `googleapis`, …). Ele obtém acesso pelo boundary do Fayz — `getSupabaseClientOptional()` / a interface `DataProvider` — ou pelo spine de conectores. ```ts import { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core' // ✔ passa pelo boundary do Fayz, escopa por tenant // import { createClient } from '@supabase/supabase-js' // -> o doctor acusaria isto como quebra de boundary ``` Existe uma exceção deliberada: um plugin app-local **pode** ser dono de um conector + Edge Function para um provedor que o Fayz ainda não suporta — porque a credencial fica no servidor e o app ainda chama o *próprio* boundary, não o provedor do navegador. Essa exceção é declarada com um marcador na linha do import, não casual. ## A superfície suportada Um app só depende de pacotes da superfície pública suportada — `@fayz-ai/sdk`, `core`, `saas`, `ui`, `auth`, `db`, `storefront`, `shop` e os `@fayz-ai/plugin-*`. Importar um subpath interno ou um pacote fora dessa lista faz o doctor avisar (`off-surface-import` / `off-surface-dependency`). A regra existe para o upgrade ficar seguro: o que não está na superfície pode mudar sem aviso. ## Tabelas `plg_` e reúso do core Por convenção, um plugin instala as **suas próprias tabelas** com o prefixo **`plg_`** (é o que shop e courses fazem — `plg_shop_products`, `plg_courses_*`) para deixar a posse óbvia. A convenção é **recomendada, não universal**: nem todo módulo a cumpre — o conector de openbanking, por exemplo, cria `bank_integrations` sem prefixo. O que o plugin **não** cria, ele **reutiliza**: referencia as tabelas da biblioteca [core](/pt-BR/docs/dados/modelo) que precisa em vez de copiá-las. Um plugin jamais redefine uma entidade do core; se precisa saber "quem marcou", referencia `public.people`. Uma fonte de verdade por entidade. As migrations que o plugin embarca seguem regras que fazem o `fayz db apply` ser reproduzível: - **ordenadas** — a sequência de aplicação é determinística. - **versionadas** — cada migration tem versão; o runner sabe o que já rodou. - **fix-forward** — migrations são append-only: nunca edite uma já aplicada, escreva a próxima que corrige. Não há `.down.sql`. - **idempotentes** — rodar de novo não quebra nem duplica. ## Isolamento sempre Toda tabela `plg_` que o plugin possui carrega `tenant_id` e RLS na forma canônica. Isso não é opcional nem "depois" — é a condição para a tabela existir no modelo. O detalhe está em [RLS e multi-tenant](/pt-BR/docs/dados/rls). {% callout type="info" %} A fiscalização é **soft** por design: o `fayz doctor` reporta essas violações como *avisos*, não falha o build. A ideia é visibilidade sem atrapalhar o DX de quem está experimentando. Mas um plugin que quer graduar a oficial precisa estar com o doctor limpo. {% /callout %} --- Próximo: exercite o app e pegue quebras cedo em [Testar e debugar](/pt-BR/docs/testar-e-debugar). --- source: https://developers.fayz.ai/pt-BR/docs/testar-e-debugar.md --- # Testar e debugar Antes de subir, você exercita o app sem infra e valida a estrutura com uma ferramenta. Três coisas fazem isso: o backend `mock`, o adapter de auth simulado e o `fayz doctor`. ## O modo mock roda tudo sem banco Um app recém-criado nasce com `"backend": { "provider": "mock" }`. Isso é dados de exemplo em memória — o app inteiro funciona sem Supabase, sem `.env`, sem rede. Cada plugin (e cada plugin seu, via `createSafeDataProvider`) traz um provider mock, então você desenvolve e demonstra a experiência completa antes de conectar qualquer coisa. Virar a chave para dados reais é trocar o `provider` no manifesto — veja [Supabase](/pt-BR/docs/dados/supabase). ## O auth simulado No mesmo espírito, o `createMockAuthAdapter` do `@fayz-ai/auth` entrega uma sessão logada como um usuário demo, persistida no navegador — sem tela de login, sem provedor. No caminho manifesto-primeiro, o adapter de auth segue o `backend.provider`: em `mock`, a auth é simulada automaticamente. Assim você testa telas que dependem de "estar logado" sem montar auth de verdade. O detalhe está em [Auth — visão geral](/pt-BR/docs/auth/visao-geral). ## `fayz doctor`: a rede de segurança O `doctor` valida o app parado — sem subir nada. Rode-o depois de qualquer mudança: ```bash npx @fayz-ai/cli doctor ``` Ele checa três coisas: - **Estrutura do manifesto e fronteiras arquiteturais** — `manifestVersion`, campos obrigatórios e surface com `scaffold`. Um problema estrutural faz o doctor **sair com erro** (exit 1). Hoje o doctor valida a **forma** do manifesto e as fronteiras, não os *valores* de enums como `theme.brand` ou `backend.provider` — a validação desses valores está chegando (há um fix de SDK em PR). - **Boundaries de arquitetura** — imports de SDK de provedor direto (`provider-import`), imports fora da superfície suportada (`off-surface-import`), dependências fora da superfície. Reportados como **avisos** (soft enforcement — não falham o build). - **Plugins referenciados** — cada id do manifesto precisa resolver para uma factory `@fayz-ai/plugin-*` instalada e ligada no código gerado, mais cobertura de locale. Uma saída típica de um app mock saudável: ``` ⚠ manifest references plugin(s) [dashboard] — each id must resolve to an installed @fayz-ai/plugin-* factory wired in src/plugins.generated.ts or src/config/app.tsx 0 error(s), 1 warning(s) ``` {% callout type="tip" %} Leia o resumo final: `N error(s), M warning(s)`. **Erros** você conserta antes de seguir; **avisos** são visibilidade — o aviso sobre plugins referenciados é esperado em modo mock (o `dashboard` é resolvido pelo bundle da plataforma) e não é um problema. Um app código-primeiro (sem `app.manifest.json`) roda só as checagens de boundary e passa. {% /callout %} ## Planeje migrações sem tocar no banco Para debugar a camada de dados, o `db apply --dry-run` imprime o plano ordenado sem nenhuma chamada de rede e sem ler o seu PAT — seguro de rodar sempre: ```bash npx @fayz-ai/cli db apply --dry-run ``` É a forma de conferir *o que* seria aplicado (e em que ordem: spine → drizzle → seed → plugins → incubator) antes de aplicar de verdade. --- Próximo: coloque o app no ar em [Deploy estático](/pt-BR/docs/deploy/estatico). --- source: https://developers.fayz.ai/pt-BR/docs/deploy/estatico.md --- # Deploy estático O app gerado é um projeto Vite. Publicar é o fluxo estático de sempre: você gera a pasta `dist/` e a serve em qualquer host de arquivos estáticos — sem servidor, sem lock-in. ## Gere o build ```bash npm run build ``` Saída típica: ``` vite v5.4.21 building for production... ✓ 34 modules transformed. dist/index.html 0.40 kB │ gzip: 0.27 kB dist/assets/index-...css 0.00 kB │ gzip: 0.02 kB dist/assets/index-...js 143.00 kB │ gzip: 46.00 kB ✓ built in 274ms ``` O resultado é uma pasta `dist/` com um `index.html` e os assets em `dist/assets/`. Para conferir localmente antes de subir: ```bash npm run preview ``` ## A regra que todo host precisa: rewrite para o `index.html` O app é uma SPA (single-page app): todas as rotas são servidas pelo `index.html` e o roteamento acontece no navegador. Por isso **todo** host precisa de uma regra de rewrite mandando qualquer caminho para o `index.html` — senão um refresh em `/crm` dá 404. **Vercel** — crie um `vercel.json` na raiz: ```json { "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }] } ``` Build command: `npm run build` · Output directory: `dist`. **Netlify** — crie um `public/_redirects`: ``` /* /index.html 200 ``` Build command: `npm run build` · Publish directory: `dist`. **Cloudflare Pages** — mesmo `_redirects` do Netlify: ``` /* /index.html 200 ``` Build command: `npm run build` · Output directory: `dist`. ## As variáveis de ambiente No painel do host, defina as variáveis **públicas** — as mesmas do seu `.env.local`: ``` VITE_SUPABASE_URL=https://SEU-REF.supabase.co VITE_SUPABASE_ANON_KEY=sua-anon-key ``` {% callout type="warn" %} O `SUPABASE_PAT` **não** vai para o host. Ele serve só para o `fayz db apply`, que você roda da sua máquina. No host ficam apenas os valores `VITE_` (públicos, embarcados no navegador). Nunca coloque o PAT numa variável de build de deploy. {% /callout %} Aponte o projeto para o repositório, configure build + output conforme o host acima, defina as variáveis e faça o deploy. O mesmo `dist/` roda idêntico em qualquer um dos três. --- Próximo: o deploy gerenciado que está chegando em [Deploy Fayz](/pt-BR/docs/deploy/fayz). --- source: https://developers.fayz.ai/pt-BR/docs/deploy/fayz.md --- # Deploy Fayz O deploy oficial de apps Fayz: um comando que cuida de build, host, banco e domínio — sem você configurar rewrites nem variáveis à mão. Você conecta o app e a plataforma faz o resto. ```bash fayz login # uma vez, com o seu token de acesso fayz deploy # cria/conecta o projeto, sobe o código e publica ``` A plataforma builda o app num container gerenciado e publica em uma URL própria (`https://.live.fayz.ai`), com suporte a domínio customizado. {% callout type="info" %} **Acesso em rollout.** O `fayz deploy` está sendo liberado para a rede de desenvolvedores convidados. Se o seu token ainda não tem acesso de deploy, fale com a gente na [comunidade](/pt-BR/docs/recursos/comunidade). {% /callout %} ## O que ele faz Fecha a distância entre "o app roda na minha máquina" e "o app está no ar", tirando as etapas manuais do [deploy estático](/pt-BR/docs/deploy/estatico): - **Build + host** — a plataforma builda (install + Vite build) e serve o app; sem `vercel.json` / `_redirects` nem output directory. - **Projeto conectado** — o app fica vinculado a um projeto Fayz (`.fayz/project.json`), com painel de gestão na plataforma. - **Banco** — provisionamento e migração (`fayz db apply`) no mesmo fluxo de trabalho. - **Ambientes e domínio** — URL de produção própria + domínio customizado, com as variáveis geridas pela plataforma. ## Alternativa: host estático O [deploy estático](/pt-BR/docs/deploy/estatico) coloca o mesmo app no ar em qualquer host de arquivos (Vercel, Netlify, Cloudflare Pages) e continua totalmente suportado. Migrar de um para o outro é trocar o fluxo de publicação, não o app. --- Próximo: o passo a passo completo em [07 · Publicar](/pt-BR/docs/tutorial/07-publicar). --- source: https://developers.fayz.ai/pt-BR/docs/plugins.md --- # Catálogo de plugins Um app Fayz é uma composição de plugins. Cada plugin é um pacote `@fayz-ai/*` que declara o que é — navegação, rotas, widgets, dados — e o core resolve tudo em runtime. Mas antes do catálogo cru, a pergunta prática é outra: **que produto você quer construir?** Comece por aí e o conjunto de plugins certo se organiza sozinho. ## O que você quer construir? Cada caminho abaixo é um tipo de produto que o Fayz monta hoje. O card traz a promessa, o comando de scaffold que abre o projeto e os plugins que compõem a base. {% product-types /%} {% callout type="info" %} Os comandos usam `npx` na prática (ex.: `npx fayz create admin minha-empresa`). Curso online e website ainda estão em superfície inicial (preview) — os badges de status em cada card contam a verdade, e o [caminho headless](/pt-BR/docs/apps/headless) detalha os bundles de website (blog, payments) já publicados. {% /callout %} ## Catálogo completo Todos os plugins publicados, agrupados por tipo de produto, direto dos metadados do SDK: status, capability e versão de cada pacote. Um mesmo plugin pode aparecer em mais de um grupo (o `plugin-inventory`, por exemplo, serve gestão, e-commerce e food). Clique em qualquer card para ver a ficha técnica — cada uma traz o modelo de dados, as tools de IA e os conectores do plugin (o contrato que uma IA lê como skill). {% plugin-grid /%} Para os provedores externos que um app pode conectar — pagamentos, agenda, analytics, canais — veja o catálogo de [Integrações](/pt-BR/docs/plugins/integracoes). --- source: https://developers.fayz.ai/pt-BR/docs/plugins/integracoes.md --- # Integrações O Fayz tem um **catálogo de integrações** — provedores externos que um app pode conectar: bancos de dados, gateways de pagamento, agendas, canais de mensagem, analytics e modelos de IA. Esta página lista o catálogo direto da fonte da verdade da plataforma e diz, sem maquiar, **o que já tem conector real no SDK hoje** versus o que é catálogo/roadmap. A régua importa: um item no catálogo **não** significa que existe um conector pronto para plugar. Significa que o provedor está mapeado e o caminho de conexão está desenhado. Os badges de cada card contam a verdade. ## Como ler os status - **Conector no SDK** — existe um `ConnectorDefinition` real, hospedado dentro de um plugin publicado. São dois hoje: **Google Calendar** (no `plugin-agenda`) e **Stripe** (no `plugin-courses`). O card linka a ficha do plugin que o hospeda. - **Catálogo da plataforma** — o provedor está habilitado no catálogo (o control plane existe), mas o conector é resolvido **no app** pela spine de conectores, não empacotado num plugin do SDK. - **Roadmap** — catalogado, ainda não habilitado. Alguns marcados como *chegando* já têm ações declaradas no registro de capacidades do agente. {% callout type="info" %} Nada aqui é inventado: o catálogo vem do seed de conectores da plataforma e as ferramentas de agente vêm do registro de capacidades. Se um provedor aparece como *roadmap*, é porque ainda não tem conector plugável — e a página não finge o contrário. {% /callout %} ## O catálogo {% integrations-grid /%} ## Os dois planos Toda integração real se apoia na **espinha de conectores** de `@fayz-ai/core` (`packages/core/src/integrations`), que separa a conexão em dois planos — o mesmo modelo descrito em [Conectores e canais](/pt-BR/docs/ia/conectores-e-canais): - **Control plane** — a UI de `/settings`: conectar, testar a credencial (`testConnection`), escolher o que sincronizar. Um **ConnectorsHub** compartilhado na shell gerencia os provedores. - **Data plane** — a **Supabase Edge Function** que roda o `sync` de verdade. O trabalho pesado fica no backend, nunca no navegador. O contrato `Connector` / `ConnectorDefinition` costura os dois: declara o modo de autenticação (`oauth`, `api-key`, `mtls`), as capacidades que sabe sincronizar e as funções `testConnection` e `sync`. ## O seam `connectors` do manifesto Um plugin publica conectores pelo campo **`connectors`** do [manifesto do plugin](/pt-BR/docs/referencia/plugin-manifest) — é assim que o plugin vira um addon de um host e passa a oferecer um provedor externo. Os dois conectores que já existem seguem exatamente esse caminho: {% cards %} {% card title="Google Calendar → plugin-agenda" icon="📅" %} OAuth, seletor de calendário e sync de eventos em `src/integrations/google-calendar`. O exemplo canônico de conector nativo de um plugin. {% /card %} {% card title="Stripe → plugin-courses" icon="💳" %} Conector de pagamentos em `src/connectors/stripe.ts`. O mesmo contrato aplicado a um provedor de billing. {% /card %} {% /cards %} Um plugin próprio (ou um plugin de incubator) replica esse `ConnectorDefinition` para falar com qualquer provedor do catálogo. Veja o padrão de conector client-side (ex.: PlugBank/open banking) na página [Incubator](/pt-BR/docs/plugins-proprios/incubator). --- Veja também: [Conectores e canais](/pt-BR/docs/ia/conectores-e-canais) para o fluxo de canais de mensagem (WhatsApp é roadmap), o campo `connectors` no [Manifesto do plugin](/pt-BR/docs/referencia/plugin-manifest) e o [Catálogo de plugins](/pt-BR/docs/plugins). --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-admin.md --- # plugin-admin `@fayz-ai/plugin-admin` · preview · Capability parcial Every SaaS/admin-template app already resolves a shell config — sidebar or topbar layout, rail or tabs for module navigation, a mobile header treatment, whether org/branding settings are shown — from FayzAppConfig (src/config/app.tsx / theme.ts) at build time. Today an operator can't see any of that from the Panel; changing it means hand-editing config files and redeploying. plugin-admin adds an… ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-admin` - **Versão:** 0.1.0 - **Status:** preview - **Capability:** Capability parcial - **Tipo de produto:** Plataforma - **Canal stable:** ainda não publicado - **Migrations:** nenhuma - **Factory:** `createAdminPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `admin.get-shell-settings` | read | Returns the app shell configuration: layout variant, module nav style, mobile header treatment, and whether org/branding settings are shown. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "admin", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-agenda.md --- # plugin-agenda `@fayz-ai/plugin-agenda` · beta · Capability parcial Every service business runs on a calendar. Salons book stylists, clinics book doctors, studios book rooms — the same primitive, rebuilt badly a thousand times. plugin-agenda is that primitive done once: a resource-aware calendar with appointments, blocks, working hours, conflict detection, and drag-and-drop, all driven by config instead of forks. ## Visão geral O calendário como primitiva: agendamentos, bloqueios, horários de trabalho, detecção de conflito e drag-and-drop, tudo dirigido por config. O plugin monta a página `/agenda`. Empacota quatro migrations que sustentam a **reserva pública** e a view-ponte `v_bookings` (renomeação e compatibilidade da view, além de dedupe de telefones). O provider Supabase lê e grava tabelas compartilhadas (`bookings`, `schedules`, `locations`) e a `v_bookings`, com fallback automático para um provider mock (uma agenda de salão de exemplo, semeável pelo app). A config é rica: locais, janelas de reserva, concorrência e seleção de serviços via lookup. Traz um addon oficial de Google Calendar (`createGoogleCalendarPlugin`) e uma ponte financeira (`createFinancialBridge`) que calcula comissão ao concluir um atendimento. Para IA, expõe `listAppointments`, `createAppointment` e `checkAvailability`. Status **beta / capability parcial**. ## Quando usar - Qualquer negócio que gira em torno de uma agenda: salões, clínicas, estúdios. - Precisa de detecção de conflito e visão por recurso ou profissional. - Quer sincronizar com Google Calendar ou gerar comissão a partir do atendimento. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-agenda` - **Versão:** 0.3.0 - **Status:** beta - **Capability:** Capability parcial - **Tipo de produto:** Agendamento - **Canal stable:** `^0.4.0` - **Migrations:** 4 migration(s) - **Factory:** `createAgendaPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `agenda.list-appointments` | read | Lists upcoming appointments for a given date or date range, optionally filtered by professional. | | `agenda.create-appointment` | persist | Creates a new appointment for a client with a specific professional and service. | | `agenda.check-availability` | read | Checks available time slots for a professional on a given date. | ## Integrações Conector(es) hospedado(s): `google-calendar`. Veja Integrações. ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "agenda", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-auth.md --- # plugin-auth `@fayz-ai/plugin-auth` · preview · Superfície visual Reusable auth runtime and UI for Fayz apps. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-auth` - **Versão:** 0.1.3 - **Status:** preview - **Capability:** Superfície visual - **Tipo de produto:** Plataforma - **Canal stable:** `^0.1.3` - **Migrations:** nenhuma ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA Nenhuma ferramenta de IA declarada. ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "auth", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-automations.md --- # plugin-automations `@fayz-ai/plugin-automations` · preview · Superfície visual The best automations don't live in a third-party tool watching webhooks from the outside — they live inside the app, listening to its own events. plugin-automations is the GoHighLevel "Automation" surface for Fayz: when a form is submitted, a call is missed, or a deal is won, fan out into SMS, email, waits, tags, and tasks. Because it's a plugin in the same defineSaas app, it can react to real… ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-automations` - **Versão:** 0.2.3 - **Status:** preview - **Capability:** Superfície visual - **Tipo de produto:** Gestão (Admin/SaaS) - **Canal stable:** `^0.2.3` - **Migrations:** nenhuma - **Factory:** `createAutomationsPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA Nenhuma ferramenta de IA declarada. ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "automations", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-blog.md --- # plugin-blog `@fayz-ai/plugin-blog` · preview · Capability parcial Marketing sites need a blog, and every one ends up rebuilt from scratch. plugin-blog is the reusable version: a headless, SEO-ready blog you compose into a Fayz website as a bundle of { manifest, Provider }. It ships the public read surface — a /blog list and a /blog/:slug article page — plus the data seam behind them, so the host site owns layout and navigation while the plugin owns posts. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-blog` - **Versão:** 0.1.0 - **Status:** preview - **Capability:** Capability parcial - **Tipo de produto:** Website - **Canal stable:** `^0.1.0` - **Migrations:** nenhuma - **Factory:** `createBlogPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA Nenhuma ferramenta de IA declarada. ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "blog", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-conversations.md --- # plugin-conversations `@fayz-ai/plugin-conversations` · preview · Capability parcial Customers reach out everywhere — a WhatsApp here, an Instagram DM there, an email, a text. Replying across five tabs is how businesses drop conversations. plugin-conversations is the GoHighLevel-style unified inbox for the Fayz engine: every channel collapses into one threaded view, so a salon, a restaurant, or an agency answers everyone from a single place. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-conversations` - **Versão:** 0.2.4 - **Status:** preview - **Capability:** Capability parcial - **Tipo de produto:** Gestão (Admin/SaaS) - **Canal stable:** `^0.2.4` - **Migrations:** nenhuma - **Factory:** `createConversationsPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `conversations.list-threads` | read | Lists open conversations across all channels, optionally filtered by channel. | | `conversations.send-message` | persist | Sends a reply in a conversation thread. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "conversations", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-courses.md --- # plugin-courses `@fayz-ai/plugin-courses` · preview · Capability parcial Every vertical eventually wants to sell knowledge. A salon teaches a masterclass, a clinic runs patient education, a gym ships training programs. Bolting an LMS onto each is wasted work. This plugin makes "courses" a capability you snap on: a navigation entry plus admin pages for authoring courses, organizing modules and lessons, and tracking enrollments and progress. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-courses` - **Versão:** 0.2.3 - **Status:** preview - **Capability:** Capability parcial - **Tipo de produto:** Cursos - **Canal stable:** `^0.2.3` - **Migrations:** nenhuma - **Factory:** `createCoursesPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA Nenhuma ferramenta de IA declarada. ## Integrações Conector(es) hospedado(s): `stripe`. Veja Integrações. ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "courses", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-crm.md --- # plugin-crm `@fayz-ai/plugin-crm` · beta · Capability parcial Every business that sells anything needs a way to track who's interested, what's in motion, and what's about to close. Most verticals end up rebuilding the same CRM badly. plugin-crm is the one sales engine — leads, a drag-style pipeline, deals, quotes, and activities — that snaps into a defineSaas app and adapts to the vertical underneath it. ## Visão geral CRM enxuto para negócios de serviço: leads viram negócios, negócios andam por um pipeline visual, e atividades e orçamentos registram o histórico. O plugin monta a página `/sales` (rota e navegação), widgets de dashboard e uma aba de Configurações. Os módulos `quotes`, `activities` e `pipeline` são ligáveis e desligáveis por config. Sobre dados, o CRM segue o padrão de arquétipos do Fayz: **leads são pessoas** (`saas_core.persons`, `kind='lead'`) e **negócios e orçamentos são orders** (`saas_core.orders`, `kind='deal'`/`quote`). O plugin acrescenta tabelas de extensão em `public` — `pipelines`, `pipeline_stages`, `lead_sources`, `crm_tags`, `crm_activities` e `deal_extensions` — em cinco migrations que cobrem base, atividades, views + RLS e o seed de um pipeline padrão. Provider Supabase com fallback mock. Quando um lead é aprovado, o CRM pode promover a pessoa (`persons.kind`) e criar o registro na tabela de extensão configurada (`clientConversion`). Para IA, expõe `countCustomers` e `listLeads`. Status **beta / capability parcial**: pronto para dogfood, ainda evoluindo. ## Quando usar - Acompanhar leads e negócios num funil visual. - Emitir orçamentos e registrar atividades de contato. - Converter um lead aprovado em cliente sem sair do fluxo. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-crm` - **Versão:** 0.3.0 - **Status:** beta - **Capability:** Capability parcial - **Tipo de produto:** Gestão (Admin/SaaS) - **Canal stable:** `^0.3.0` - **Migrations:** 5 migration(s) - **Factory:** `createCrmPlugin()` ## Modelo de dados Tabelas instaladas (convenção `plg_` · `tenant_id` + RLS): - `plg_crm_pipelines` — name, is_default, is_active - `plg_crm_pipeline_stages` — pipeline_id, name, order, color, probability, is_won - `plg_crm_lead_sources` — name, is_active - `plg_crm_tags` — name, color, is_active - `plg_crm_deal_extensions` — order_id, pipeline_id, stage_id, probability, expected_close_date, lead_id - `plg_crm_activity_types` — name, is_active - `plg_crm_activities` — deal_id, lead_id, contact_id, contact_name, activity_type, title ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `crm.count-customers` | read | Returns the number of active customers/clients. | | `crm.list-leads` | read | Lists leads with optional filters. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "crm", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-dashboard.md --- # plugin-dashboard `@fayz-ai/plugin-dashboard` · preview · Superfície visual A SaaS home page is never owned by one team. Bookings wants today's agenda, finance wants revenue, the shop wants top products. The usual outcome is one god-component that imports everything and rots. This plugin kills that. It provides the / home surface and a widget registry: every plugin contributes its own dashboardWidgets, and the dashboard renders, orders, and lays them out into a single… ## Visão geral A tela inicial do app. Não tem dados próprios nem migrations: é uma **superfície visual** que agrega widgets do registro — KPIs, seções customizadas, checklist de onboarding e os widgets que outros plugins (CRM, financeiro, estoque) contribuem para a home. Monta a rota `/` e renderiza o `DashboardCanvas`. É configurável por `metrics`, `sections`, `onboardingSteps`, `customWidgets` e `layout`; dá para desligar o cabeçalho (`showHeader`) ou o menu "Customize" (`customizable`) para uma home B2C limpa, e compartilhar um controle de intervalo de tempo (`range`) entre os widgets. Para IA, expõe `getKpiSummary`. Status **preview / superfície visual** — a API ainda pode mudar. ## Quando usar - Montar a home com KPIs e um checklist de primeiros passos. - Reunir num só lugar os widgets que os outros plugins expõem. - Entregar uma home B2C enxuta, sem o chrome de customização. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-dashboard` - **Versão:** 0.1.6 - **Status:** preview - **Capability:** Superfície visual - **Tipo de produto:** Gestão (Admin/SaaS) - **Canal stable:** `^0.1.6` - **Migrations:** nenhuma - **Factory:** `createDashboardPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `dashboard.kpi-summary` | read | Returns a summary of all KPI metrics for the current dashboard, including trends and comparisons. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "dashboard", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-financial.md --- # plugin-financial `@fayz-ai/plugin-financial` · beta · Capability parcial Most vertical SaaS bolts on finance as an afterthought: a "total" field, a spreadsheet export, and a prayer. plugin-financial makes money a first-class part of the app. It models the full order-to-cash loop — receivables, payables, cash registers, statements, card reconciliation, and commission rules — as composable modules you toggle per business. ## Visão geral Núcleo financeiro: contas a pagar e a receber, caixas, extratos, comissões, cartões e conciliação bancária. Monta a página `/financial`, widgets de dashboard e um widget de extrato por pessoa (zona `person.detail.financial`). Os módulos `payables`, `receivables`, `cashRegisters`, `statements`, `commissions`, `cards` e `reconciliation` (opt-in, exige um conector bancário) são ligáveis por config. Sobre dados, **as faturas são orders** (`saas_core.orders`, `kind='invoice_payable'`/`invoice_receivable'`), enquanto o razão financeiro vive em `financial_movements`. O plugin acrescenta em `public` tabelas como `payment_methods`, `payment_method_types`, `bank_accounts`, `cash_register_sessions`, `chart_of_accounts`, `card_brands` e `cost_centers` — onze migrations cobrindo plano de contas, bandeiras de cartão, order-to-cash, RLS, conciliação e split de pagamento. Provider Supabase com fallback mock. Para IA, expõe `getRevenue`, `createInvoice` e `listPayables`. Status **beta / capability parcial**. ## Quando usar - Controlar fluxo de caixa, contas a pagar e a receber. - Emitir e acompanhar faturas ligadas a contatos. - Conciliar extrato bancário com um conector — módulo opt-in. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-financial` - **Versão:** 0.2.0 - **Status:** beta - **Capability:** Capability parcial - **Tipo de produto:** Gestão (Admin/SaaS) - **Canal stable:** `^0.2.0` - **Migrations:** 11 migration(s) - **Factory:** `createFinancialPlugin()` ## Modelo de dados Tabelas instaladas (convenção `plg_` · `tenant_id` + RLS): - `plg_financial_payment_method_types` — name, transaction_type, is_active, allowed_account_types - `plg_financial_payment_methods` — name, payment_method_type_id, is_active, discount_mode, discount_value, interest_mode - `plg_financial_bank_accounts` — name, account_type, bank_name, account_number, agency_number, current_balance - `plg_financial_cash_register_sessions` — bank_account_id, status, opened_at, opened_by_user_id, opened_by_name, opening_balance - `plg_financial_movements` — invoice_id, direction, movement_kind, amount, paid_amount, status - `plg_financial_chart_of_accounts` — code, name, node_type, parent_id, is_active - `plg_financial_cost_centers` — code, name, is_active - `plg_financial_card_brands` — name, is_active - `sequences` — kind, current_value ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `financial.get-revenue` | read | Returns revenue for the business in a given period. | | `financial.create-invoice` | persist | Creates a new invoice/payable for a contact. | | `financial.list-payables` | read | Lists outstanding payables/bills. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "financial", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-forms.md --- # plugin-forms `@fayz-ai/plugin-forms` · beta · Capability parcial Every real business runs on forms it never wanted to build: anamnesis sheets, evolution notes, consent contracts, intake docs. plugin-forms kills that busywork. Define a template once, attach a filled document to a person, and the data lives in your tenant — not in a PDF nobody can query. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-forms` - **Versão:** 0.2.0 - **Status:** beta - **Capability:** Capability parcial - **Tipo de produto:** Gestão (Admin/SaaS) - **Canal stable:** `^0.2.0` - **Migrations:** 3 migration(s) - **Factory:** `createCustomFormsPlugin()` ## Modelo de dados Tabelas instaladas (convenção `plg_` · `tenant_id` + RLS): - `plg_forms_templates` — name, description, category, version, is_current, parent_id - `plg_forms_documents` — template_id, person_id, title, data, status, signed_at - `plg_forms_document_files` — document_id, field_key, file_url, file_name, file_size, mime_type - `documents` — kind, person_id, title, description, status, file_url ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `custom_forms.list-templates` | read | Lists available form templates for the current tenant. | | `custom_forms.list-documents` | read | Lists filled documents, optionally filtered by person or status. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "forms", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-inventory.md --- # plugin-inventory `@fayz-ai/plugin-inventory` · beta · Capability parcial Inventory is the universal organ — a salon counts product, a restaurant counts ingredients, a clinic counts supplies. plugin-inventory is that organ as a plugin: a product catalog, stock entry/exit/history, optional recipes (bill of materials), and a dashboard that surfaces stock value and what's running low. It's scope: universal, so it snaps into any vertical. ## Visão geral Estoque e catálogo: entradas e saídas, histórico, saldo por local e fichas técnicas (receitas). Monta a página `/inventory` e widgets de dashboard. Os módulos `recipes`, `stockLocations` e `batchTracking` (opt-in) são ligáveis por config; os tipos de produto padrão são insumo, para venda, intermediário e ativo. Sobre dados, **os produtos são o arquétipo** `saas_core.products`; o plugin acrescenta tabelas de extensão em `public` — `stock_locations`, `stock_movements`, `stock_positions`, `recipes`, `recipe_ingredients`, `measurement_units` e `product_categories` — em quatro migrations (renomeação de prefixo, base, receitas, unidades de medida). Provider Supabase com fallback mock. Para IA, expõe `getLowStock` (produtos abaixo do mínimo). Status **beta / capability parcial**. ## Quando usar - Controlar entradas, saídas e saldo de estoque por local. - Modelar receitas ou fichas técnicas que consomem insumos. - Receber alertas de estoque baixo, inclusive via IA. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-inventory` - **Versão:** 0.1.7 - **Status:** beta - **Capability:** Capability parcial - **Tipo de produto:** Gestão (Admin/SaaS), E-commerce, Restaurante / food - **Canal stable:** `^0.1.7` - **Migrations:** 4 migration(s) - **Factory:** `createInventoryPlugin()` ## Modelo de dados Tabelas instaladas (convenção `plg_` · `tenant_id` + RLS): - `plg_inventory_product_categories` — name, parent_id, is_active - `plg_inventory_stock_locations` — name, description, is_active, unit_id - `plg_inventory_stock_movements` — product_id, quantity, movement_type, unit_cost, total_cost, stock_location_id - `plg_inventory_stock_positions` — product_id, quantity, unit_cost, stock_location_id, batch_number, expiration_date - `plg_inventory_recipes` — name, description, product_id, yield_quantity, yield_unit_id, preparation_time_minutes - `plg_inventory_recipe_ingredients` — recipe_id, product_id, quantity, unit_id, display_order, notes - `plg_inventory_measurement_units` — name, abbreviation, is_active ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `inventory.low-stock` | read | Lists products with stock below minimum threshold. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "inventory", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-marketing.md --- # plugin-marketing `@fayz-ai/plugin-marketing` · beta · Capability parcial Marketing analytics are always the same shape — channels, campaigns, a funnel, landing-page CVR — but what counts as a "conversion" changes per business. A salon converts a booking, a store converts an order, an agency converts a lead. plugin-marketing is one plugin that adapts to all of them: pick a domain preset (or pass an explicit conversion model + channels) and the funnel, channel… ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-marketing` - **Versão:** 0.2.1 - **Status:** beta - **Capability:** Capability parcial - **Tipo de produto:** Gestão (Admin/SaaS) - **Canal stable:** `^0.2.1` - **Migrations:** 4 migration(s) - **Factory:** `createMarketingPlugin()` ## Modelo de dados Tabelas instaladas (convenção `plg_` · `tenant_id` + RLS): - `plg_marketing_social_accounts` — name, handle, platform, is_active - `plg_marketing_content_plans` — account_id, name, status, weeks_count, start_date, objective - `plg_marketing_content_posts` — plan_id, week_number, position, title, format, status ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `marketing.channel-performance` | read | Returns acquisition performance per channel (reach, conversions, CVR, spend, CPA). | | `marketing.top-channels` | read | Returns the top acquisition channels ranked by conversions. | | `marketing.campaign-cvr` | read | Lists campaigns with their conversion rate for a date range. | | `marketing.create-campaign` | persist | Creates an acquisition campaign on a channel. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "marketing", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-menu.md --- # plugin-menu `@fayz-ai/plugin-menu` · beta · Capability parcial A menu is the product catalog of a food business — and it changes by the hour. plugin-menu is the management surface for that: items, categories, allergens, and modifiers, with sold-out toggles that take effect instantly. It's the foundation the orders flow reads from, so the two compose into a working restaurant. ## Visão geral Gestão de cardápio: itens, categorias e modificadores, com controle de disponibilidade (disponível / esgotado). Monta a página `/menu`. É um plugin **vertical** (`scope: 'vertical'`), normalmente combinado com o `plugin-orders`. Não empacota migrations. Por padrão roda com um provider mock e, para a plataforma Fayz, usa `createFayzMenuProvider` com tabelas configuráveis (`categoriesTable`, `productsTable`). O módulo `modifiers` vem ligado; `deliveryPricing` é opt-in. O canal `stable` já pina `^0.3.0`. Para IA, expõe `listMenuItems` e `toggleMenuItemAvailability`. Status **beta / capability parcial**. ## Quando usar - Manter um cardápio com categorias e modificadores. - Marcar um item como esgotado em tempo real, inclusive via IA. - Alimentar o plugin-orders com o catálogo de itens. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-menu` - **Versão:** 0.3.0 - **Status:** beta - **Capability:** Capability parcial - **Tipo de produto:** Restaurante / food - **Canal stable:** `^0.3.0` - **Migrations:** nenhuma - **Factory:** `createMenuPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `menu.list-items` | read | Lists menu items, optionally filtered by category or status. | | `menu.toggle-availability` | persist | Marks a menu item as available or sold out. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "menu", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-orders.md --- # plugin-orders `@fayz-ai/plugin-orders` · beta · Capability parcial Orders are the heartbeat of an operations business. plugin-orders gives a restaurant — or any food vertical — a real-time order board: dine-in, takeout, and delivery flowing across a kanban, with history behind it. It's the surface the floor staff actually live in. ## Visão geral Comandas para operação de restaurante: um kanban de pedidos por status, com origens dine-in, takeout e delivery. Monta a página `/orders`. É um plugin **vertical** (`scope: 'vertical'`) e declara dependência do `plugin-menu` para o catálogo de itens. Não empacota migrations. Por padrão roda com um provider mock (em memória) e, para persistir na plataforma Fayz, usa `createFayzOrdersProvider` com nomes de tabela configuráveis (`ordersTable`, `orderItemsTable`). Os lookups de item de menu e de staff são injetados pelo app. O canal `stable` já pina `^0.3.0`. Para IA, expõe `getOrdersSummary`, `getActiveOrders` e `createOrder`. Status **beta / capability parcial**. ## Quando usar - Operação de restaurante que precisa acompanhar comandas em tempo real. - Separar pedidos por dine-in, takeout e delivery num kanban. - Combinar com o plugin-menu (dependência declarada) para os itens. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-orders` - **Versão:** 0.3.0 - **Status:** beta - **Capability:** Capability parcial - **Tipo de produto:** Restaurante / food - **Canal stable:** `^0.3.0` - **Migrations:** nenhuma - **Factory:** `createOrdersPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `orders.today-summary` | read | Returns order count, revenue, and average ticket for today or a given period. | | `orders.active-orders` | read | Lists currently active (non-completed) orders. | | `orders.create-order` | persist | Creates a new restaurant order with items. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "orders", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-payments.md --- # plugin-payments `@fayz-ai/plugin-payments` · preview · Capability parcial Taking money is the one thing every commerce build cannot fake, and in Brazil that means Pix. plugin-payments gives Fayz apps a single PaymentProvider abstraction for Pix charges — create a charge, get a QR / copy-paste code, poll its status — behind the same safe mock/real resolver used across the SDK. Build and demo the whole checkout flow today on the mock; swap in a real gateway later without… ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-payments` - **Versão:** 0.1.1 - **Status:** preview - **Capability:** Capability parcial - **Tipo de produto:** Website - **Canal stable:** `^0.1.1` - **Migrations:** nenhuma ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA Nenhuma ferramenta de IA declarada. ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "payments", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-reports.md --- # plugin-reports `@fayz-ai/plugin-reports` · preview · Capability parcial Every business eventually asks the same thing: "show me the numbers." plugin-reports answers it without a BI bolt-on. You declare reports as data — columns, filters, date ranges, badges, and a data source — and the plugin renders a searchable report hub plus a filterable, exportable viewer. No per-report UI, no copy-pasted tables. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-reports` - **Versão:** 0.2.0 - **Status:** preview - **Capability:** Capability parcial - **Tipo de produto:** Gestão (Admin/SaaS) - **Canal stable:** `^0.2.0` - **Migrations:** nenhuma - **Factory:** `createReportsPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA Nenhuma ferramenta de IA declarada. ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "reports", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-reputation.md --- # plugin-reputation `@fayz-ai/plugin-reputation` · preview · Capability parcial Reputation is the cheapest growth lever a local business has, and the easiest to ignore. Reviews sit scattered across Google and Facebook, replies never happen, and nobody ever asks the happy customer for a rating. plugin-reputation is the GoHighLevel-style reputation surface for the Fayz engine: a single home for your rating, your review feed, and the actions that move it. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-reputation` - **Versão:** 0.2.4 - **Status:** preview - **Capability:** Capability parcial - **Tipo de produto:** Agendamento - **Canal stable:** `^0.2.4` - **Migrations:** nenhuma - **Factory:** `createReputationPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA Nenhuma ferramenta de IA declarada. ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "reputation", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-shop.md --- # plugin-shop `@fayz-ai/plugin-shop` · preview · Capability parcial Every vertical eventually wants to sell something. A salon sells retail product, a restaurant sells gift cards, a clinic sells packages. plugin-shop is the e-commerce admin surface that snaps into that need — a catalog, orders, customers, and discounts — without making you rebuild Shopify from scratch. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-shop` - **Versão:** 0.2.5 - **Status:** preview - **Capability:** Capability parcial - **Tipo de produto:** E-commerce - **Canal stable:** `^0.2.5` - **Migrations:** nenhuma - **Factory:** `createShopPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `shop.list-products` | read | Lists products in the shop catalog. | | `shop.list-orders` | read | Lists recent shop orders. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "shop", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-sites.md --- # plugin-sites `@fayz-ai/plugin-sites` · preview · Superfície visual Most teams duct-tape a page builder onto a separate CRM and pray the leads sync. plugin-sites is the GoHighLevel "Sites" surface, native to your Fayz app: funnels, landing pages, and full websites that capture leads straight into the same tenant your pipeline lives in. No webhooks, no Zapier, no copy-paste. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-sites` - **Versão:** 0.2.3 - **Status:** preview - **Capability:** Superfície visual - **Tipo de produto:** Website - **Canal stable:** `^0.2.3` - **Migrations:** nenhuma - **Factory:** `createSitesPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA Nenhuma ferramenta de IA declarada. ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "sites", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-tables.md --- # plugin-tables `@fayz-ai/plugin-tables` · beta · Capability parcial Restaurants don't run on records — they run on the room. plugin-tables gives the food vertical a real floor plan: zones, tables, and live status (available, occupied, reserved, cleaning), with seat and close flows wired to your own backend. It's the difference between a generic CRM and software a host can actually work a Friday night on. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-tables` - **Versão:** 0.3.0 - **Status:** beta - **Capability:** Capability parcial - **Tipo de produto:** Restaurante / food - **Canal stable:** `^0.3.0` - **Migrations:** nenhuma - **Factory:** `createTablesPlugin()` ## Modelo de dados Sem tabelas próprias — usa a biblioteca core / archetype (mesma regra: `tenant_id` + RLS). ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `tables.availability` | read | Returns which tables are available, occupied, reserved, or being cleaned. | | `tables.seat-guests` | persist | Seats guests at a specific table. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "tables", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/plugins/plugin-tasks.md --- # plugin-tasks `@fayz-ai/plugin-tasks` · beta · Capability parcial Work happens between the records. A salon owner needs to "call the supplier," a clinic admin needs to "follow up on lab results" — small things that never fit neatly into a booking or an invoice. plugin-tasks gives every Fayz app a lightweight, always-available task list: a topbar button that opens a drawer for quick-add, statuses, priorities, due dates, labels, and assignees. ## Visão geral Gestão de tarefas transversal a qualquer app. Diferente da maioria dos plugins, o `plugin-tasks` não adiciona um item no menu: ele monta um botão na barra superior do shell (zona `shell.topbar.end`) que abre uma gaveta de tarefas de qualquer lugar do app, além de uma aba em Configurações. É a **capability completa** deste grupo — entrega dados, UI e ferramenta de IA prontos. Empacota duas migrations (`000_plg_rename` + `001_tasks_base`) com duas tabelas próprias, `tsk_tasks` (subtarefas via `parent_id`, status `todo`/`in_progress`/`done`/`cancelled`, prioridade `low`/`medium`/`high`/`urgent`, prazo e etiquetas) e `tsk_labels`. O provider Supabase cai automaticamente para um provider mock em memória quando o Supabase não está configurado. Para IA, expõe a ferramenta `getTasksSummary` (total, atrasadas, vencendo hoje, por status e prioridade). ## Quando usar - Precisa de um "to-do" leve disponível em todo o app, sem ocupar um item de menu. - Quer subtarefas, prioridades e etiquetas coloridas sem construir do zero. - Quer que o assistente de IA responda "o que está atrasado?" a partir dos dados reais. ## Ficha técnica - **Pacote:** `@fayz-ai/plugin-tasks` - **Versão:** 0.1.7 - **Status:** beta - **Capability:** Capability parcial - **Tipo de produto:** Gestão (Admin/SaaS) - **Canal stable:** `^0.1.7` - **Migrations:** 2 migration(s) - **Factory:** `createTasksPlugin()` ## Modelo de dados Tabelas instaladas (convenção `plg_` · `tenant_id` + RLS): - `plg_tasks_labels` — name, color, is_active - `plg_tasks_tasks` — title, description, status, priority, due_date, assigned_to_id ## Tools de IA | id | modo | descrição | | --- | --- | --- | | `tasks.summary` | read | Returns a summary of pending tasks: total, overdue, due today, by status and priority. | ## Integrações Sem conector hospedado — provedores externos via spine de conectores (`@fayz-ai/core`). ## Integrar Adicione o plugin em `surfaces.admin.plugins` do `app.manifest.json` e rode o doctor: ```json { "surfaces": { "admin": { "plugins": [ { "id": "tasks", "enabled": true } ] } } } ``` ```bash npx fayz doctor ``` --- source: https://developers.fayz.ai/pt-BR/docs/referencia/cli.md --- # CLI A CLI do Fayz scaffolda projetos, valida manifestos e limites de arquitetura, assiste a migração de config-em-código para manifesto, e provisiona o banco Supabase de um app a partir dos pacotes instalados. Você a chama sem instalar nada, via `npx`: ```bash npx @fayz-ai/cli ``` ## Comandos | Comando | O que faz | | --- | --- | | `fayz create storefront ` | Scaffolda um storefront (loja voltada ao cliente). | | `fayz create admin ` | Scaffolda um app admin multi-tenant. | | `fayz create member ` | Scaffolda um portal de membros/alunos. | | `fayz create plugin ` | Scaffolda um plugin app-local (incubator). | | `fayz doctor [dir]` | Valida manifesto + limites de arquitetura. | | `fayz extract [dir]` | Migração assistida de config-em-código → manifesto. | | `fayz db apply [dir]` | Provisiona o Supabase a partir dos pacotes instalados. | | `fayz db pool status` | Mostra o ledger de migração de cada *industry pool* (Runner v2). *(≥ 0.3.0)* | | `fayz db pool apply --app ` | Aplica o plano de um app a **um** pool, sempre ledger-gated. *(≥ 0.3.0)* | | `fayz db pool move-tenant --from

--to

--tenant [--yes]` | Move um tenant entre pools (dry-run sem `--yes`). *(≥ 0.3.0)* | | `fayz db fan-out --app

` | Aplica o plano de um app em todos os pools: canary primeiro, depois o resto. *(≥ 0.3.0)* | | `fayz login [--token \| --status]` | Salva o token da plataforma Fayz para o `deploy`. *(≥ 0.3.0, em rollout)* | | `fayz logout` | Remove a credencial salva. *(≥ 0.3.0, em rollout)* | | `fayz deploy [dir] [--dry-run \| --yes]` | Publica o app na plataforma Fayz. *(≥ 0.3.0, em rollout)* | | `fayz --help` | Mostra a ajuda. | | `fayz --version` | Mostra a versão. | {% callout type="info" %} Os comandos `db pool`, `db fan-out`, `login`, `logout` e `deploy` **requerem CLI ≥ 0.3.0** — não existem na 0.2.0 publicada. `login`/`logout`/`deploy` ainda estão **em rollout** para a rede de desenvolvedores convidados. {% /callout %} O `create` recebe o **kind** e um **nome em kebab-case** (`^[a-z0-9][a-z0-9-]*$`) — sem flags. Ele gera um projeto Vite com `app.manifest.json`, `src/plugins.generated.ts`, `src/registry.tsx`, `AGENTS.md` e o `.env.example`. Veja o [tutorial 01](/pt-BR/docs/tutorial/01-criar-o-app). ## `fayz create plugin` Cria um plugin app-local em `src/plugins//`, seguindo o mesmo contrato dos plugins oficiais (index/data/schema/README). Detalhes em [Incubator](/pt-BR/docs/plugins-proprios/incubator). ## `fayz doctor` Valida o app do diretório atual: estrutura do manifesto, plugins referenciados, cobertura de locale e os limites de arquitetura (imports de provedor + superfície suportada). Problemas **estruturais** do manifesto saem com erro (exit 1); problemas de **boundary** são avisos (soft enforcement). Um app sem `app.manifest.json` mas com `package.json` é tratado como código-primeiro — roda só os boundaries e passa. Veja [Testar e debugar](/pt-BR/docs/testar-e-debugar). ## `fayz db apply` Monta a ordem de migração — o **core** primeiro, depois os módulos versionados de cada plugin, depois os incubator — a partir dos pacotes instalados e a aplica no seu projeto Supabase via Management API. O CLI atual rotula os passos como `spine → drizzle → seed → plugins → incubator` (os três primeiros são o core; o rótulo migra na wave de *industry pools*). ### Flags | Flag | Efeito | | --- | --- | | `--dry-run` | Imprime só o plano ordenado; **nenhuma** chamada de rede. | | `--yes`, `-y` | Pula a confirmação (obrigatório em shells não interativos). | | `--spine-only` | Aplica só o core do `@fayz-ai/db` (a flag mantém o rótulo `spine` na wave atual). | | `--plugins-only` | Aplica só as migrations de plugins + incubator. | | `--only-plugins a,b` | Restringe o passo de plugins aos ids nomeados. | ### Env (obrigatório num apply real; nunca no `--dry-run`) | Variável | Descrição | | --- | --- | | `SUPABASE_PROJECT_REF` | Ref do projeto (alias: `SUPABASE_REF`). Dashboard → Project Settings → General. | | `SUPABASE_PAT` | Personal access token (alias: `SUPABASE_ACCESS_TOKEN`). Dashboard → Account → Access Tokens. | O comando lê primeiro do ambiente do processo, depois de `/.env.local`, depois de `/.env` — e os arquivos nunca sobrescrevem o ambiente. Sem essas variáveis, um apply real para com um erro claro; o `--dry-run` não precisa delas. ```bash # planeje sem tocar no banco npx @fayz-ai/cli db apply --dry-run # aplique (pede confirmação; use --yes em CI) npx @fayz-ai/cli db apply ``` O fluxo completo de conexão está em [Supabase](/pt-BR/docs/dados/supabase). ## `fayz extract` Assiste a migração de um app código-primeiro (config em `src/App.tsx` / `defineSaas`) para o `app.manifest.json`. Rode-o na raiz de um app existente; ele lê o código de config e propõe o manifesto equivalente. ## `fayz db pool` e `fayz db fan-out` (industry pools — Runner v2) {% badge status="beta" %} {% callout type="info" %} Requer **CLI ≥ 0.3.0** — estes comandos não existem na 0.2.0 publicada. {% /callout %} Enquanto o `db apply` provisiona **um** projeto Supabase, o Runner v2 opera sobre uma frota de *industry pools* — os projetos Supabase compartilhados por vertical. Ele lê o registro de pools de `cli/pools.config.json` (use `--pools-file` para apontar outro arquivo) e pega o token de `SUPABASE_PAT` / `SUPABASE_ACCESS_TOKEN` (a ref de cada pool vem do arquivo de pools, não do ambiente). | Comando | O que faz | | --- | --- | | `fayz db pool status` | Imprime o ledger de migração de cada pool: o que já foi aplicado e o que está pendente. | | `fayz db pool apply --app ` | Aplica o plano do app (derivado dos pacotes instalados em ``) a **um** pool nomeado. | | `fayz db pool move-tenant --from

--to

--tenant [--yes]` | Move um tenant de um pool para outro. | | `fayz db fan-out --app

` | Aplica o plano do app **em todos os pools**: o canary primeiro, depois o resto. | ### Applies são sempre ledger-gated Toda aplicação passa pelo ledger de cada pool. Um arquivo já aplicado, sem mudança, é **pulado**. Um arquivo já aplicado cujo **checksum mudou** é um **HARD STOP** — o runner para em vez de reaplicar. A regra é absoluta: **nunca edite uma migração já aplicada; escreva a próxima**. Isso garante que o histórico de cada pool seja reprodutível e auditável. ### Fan-out: canary primeiro O `db fan-out` não aplica em tudo de uma vez. Ele aplica primeiro no pool marcado como canary (`--canary ` para forçar outro), e só depois nos demais — para um erro aparecer num pool antes de tocar a frota inteira. Pools em estado `PROVISIONING` são pulados no fan-out a menos que nomeados explicitamente; um pool marcado `dataCritical` exige `--allow-critical` (junto de `--yes`). ### `move-tenant` é seguro por construção O `move-tenant` é **dry-run por padrão** — sem `--yes` ele só mostra o plano. Com `--yes`, ele: faz backup em JSON **antes** de qualquer escrita, insere os registros no destino (parents-first), **verifica as contagens** (se divergirem, é HARD STOP e a origem fica intacta) e só então apaga na origem (children-first). O pool de destino não pode estar em `PROVISIONING`. ## `fayz login` / `fayz logout` / `fayz deploy` {% badge status="experimental" %} {% callout type="info" %} Requer **CLI ≥ 0.3.0** e está **em rollout** para a rede de desenvolvedores convidados. Se o `deploy` retornar erro de autorização, seu token ainda não tem acesso de CLI liberado — o [host estático](/pt-BR/docs/deploy/estatico) coloca o mesmo app no ar enquanto isso. {% /callout %} Esse trio publica um app direto na plataforma Fayz, sem CI próprio. - **`fayz login [--token | --status]`** — salva o token de acesso da plataforma (prefixo `fayz_`) em `~/.fayz/credentials.json` (modo `0600`, só o dono lê). Sem `--token`, ele lê da env `FAYZ_TOKEN` ou pede interativamente (num shell não interativo sem token, falha rápido com instruções). `--status` mostra a credencial mascarada, sem rede. Não há validação de rede no login — o token é validado no primeiro deploy. - **`fayz logout`** — apaga a credencial salva. - **`fayz deploy [dir] [--dry-run | --yes]`** — coleta os arquivos de **fonte** do app, cria/vincula um projeto na plataforma e dispara o build server-side com host estático. O vínculo do projeto fica em `/.fayz/project.json` (adicione `.fayz/` ao seu `.gitignore`). O app publicado fica em `https://.live.fayz.ai`. `--dry-run` não faz **nenhuma** chamada de rede; um deploy real pede confirmação a menos que `--yes`. **Resolução de token e URL:** o token vem de `FAYZ_TOKEN` (env, prioridade) → `~/.fayz/credentials.json`. A URL da API vem de `FAYZ_API_URL` (default `https://beta.fayz.ai/api`). O passo a passo com screenshots está em [Deploy na Fayz](/pt-BR/docs/deploy/fayz). --- Próximo: os campos que o `doctor` valida em [Manifesto do plugin — referência](/pt-BR/docs/referencia/plugin-manifest). --- source: https://developers.fayz.ai/pt-BR/docs/referencia/plugin-manifest.md --- # Manifesto do plugin — referência A referência completa do `PluginManifest` — cada campo que um plugin pode declarar e o que o runtime faz com ele. Para a introdução conceitual, veja [Manifesto do plugin](/pt-BR/docs/plugins-proprios/manifesto). O tipo canônico vive em `@fayz-ai/core` (`PluginManifest`). Um plugin — oficial ou app-local — é sempre uma factory que devolve este objeto. ## Campos de identidade | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | `string` | sim | Identificador único do plugin. | | `name` | `string` | sim | Nome exibido. | | `icon` | `string` | sim | Nome do ícone. | | `version` | `string` | sim | Versão do plugin (semver). | | `apiVersion` | `number` | não | Versão do contrato de plugin. O runtime recusa um plugin construído para um contrato mais novo do que suporta. Omitir = legado/compatível. | | `description` | `string` | não | Descrição curta. | | `scope` | `PluginScope` | não | `core` · `vertical` · `universal` · `addon` · `tenant`. | | `verticalId` | `VerticalId` | não | `beauty` · `food` · `health` · `services` · `retail` · `education` · (custom). | | `scaffolds` | `ScaffoldType[]` | não | Scaffolds que o plugin suporta. Omitir = universal. | | `defaultEnabled` | `boolean` | não | Se já vem ligado. | | `dependencies` | `string[]` | não | Ids de outros plugins de que depende. | | `tenantId` | `string` | não | Vincula o plugin a um tenant específico (instâncias por tenant). | | `schema` | `string` | não | Schema de banco em que as tabelas do plugin vivem. | ## UI e navegação | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `navigation` | `PluginNavigationEntry[]` | sim | Itens de menu. Cada um: `section` (`main`/`secondary`/`settings`), `position`, `label`, `route`, `icon?`, `badge?`, `permission?`. | | `routes` | `PluginRouteDefinition[]` | sim | Rotas. Cada uma: `path`, `component` **ou** `componentId`, `guard?` (`authenticated`/`role`/`public`/`share-token`), `roles?`, `permission?`, `fullBleed?`. | | `settings` | `PluginSettingsTab[]` | não | Abas na tela de configurações. `id`, `label`, `component`/`componentId`, `order?`, `permission?`. | | `widgets` | `PluginWidgetDefinition[]` | não | Componentes injetados em zonas do shell. `id`, `zone` (`WidgetZone`), `component`/`componentId`, `order?`, `visibility?`. | | `dashboardWidgets` | `DashboardWidgetDef[]` | não | KPIs/gráficos/tabelas contribuídos ao dashboard. `id`, `title`, `kind` (`kpi`/`chart`/`table`/`onboarding`/`custom`), `span?`, `surfaces?`. | | `onboarding` | `PluginOnboarding` | não | Fluxo de primeiro uso. `component`/`componentId`, `title?`, `description?`. | > **Componente por valor ou por id:** em toda parte (rotas, abas, widgets), você fornece **ou** `component` (o componente React direto) **ou** `componentId` (um id resolvido pelo registry) — exatamente um. ## Comportamento e integração | Campo | Tipo | Descrição | | --- | --- | --- | | `events` | `PluginEventDefinition[]` | Eventos que o plugin emite no bus. `name` namespaced (`agenda.booking.confirmed`), `description?`, `payloadSchema?`. | | `capabilities` | `PluginCapability[]` | Capacidades declaradas. `id`, `label`, `kind?` (`page`/`widget`/`data`/`integration`). | | `aiTools` | `PluginAITool[]` | Ferramentas para um agente de IA. `id`, `name`, `description`, `mode` (`read`/`persist`), `parameters?`, `permission?`, `suggestions?`. | | `connectors` | `ConnectorDefinition[]` | Conectores para provedores externos (o plugin como addon de um host). Veja o catálogo de [Integrações](/pt-BR/docs/plugins/integracoes). | | `registries` | `PluginRegistryDef[]` | Entidades registradas com `seedData`/`mockData` e display (`table`/`cards`/`tree`). | ## Dados, permissões e diagnóstico | Campo | Tipo | Descrição | | --- | --- | --- | | `entities` | `string[]` | Entidades de dados que o plugin registra. | | `permissions` | `string[]` | Permissões que o plugin usa. | | `declaredFeatures` | `FeatureDeclaration[]` | Features declaradas para o controle de acesso. | | `migrations` | `PluginMigration[]` | O SQL das tabelas do plugin. Cada uma: `id`, `version`, `sql`, `description?`. | | `diagnostics` | `PluginDiagnostic[]` | Pré-requisitos de backend verificados pelo `fayz doctor`. `requires` (`rpcs`/`views`/`tables`/`migrations`/`env`), `level?` (`error`/`warn`/`info`). | | `locales` | `Record>` | Traduções por idioma. | ## Exemplo mínimo O plugin gerado pelo incubator — o menor manifesto válido e útil: ```ts import type { PluginManifest } from '@fayz-ai/core' export function createFidelidadePlugin(): PluginManifest { const Page = () => /* ... */ null return { id: 'fidelidade', name: 'Fidelidade', icon: 'Puzzle', version: '0.1.0', navigation: [ { section: 'main', position: 50, label: 'Fidelidade', route: '/fidelidade', icon: 'Puzzle' }, ], routes: [{ path: '/fidelidade', component: Page }], } } ``` ## Exemplo com seams O mesmo plugin declarando dados, permissões e um diagnóstico: ```ts return { id: 'fidelidade', name: 'Fidelidade', icon: 'Puzzle', version: '0.1.0', apiVersion: 1, navigation: [{ section: 'main', position: 50, label: 'Fidelidade', route: '/fidelidade', icon: 'Award' }], routes: [{ path: '/fidelidade', component: Page }], permissions: ['fidelidade:read', 'fidelidade:write'], migrations: [{ id: 'fidelidade-0001', version: '0.1.0', sql: 'create table fid_points (...)' }], diagnostics: [ { id: 'fid-tables', requires: { tables: ['fid_points'] }, level: 'warn' }, ], locales: { 'pt-BR': { 'fidelidade.title': 'Fidelidade' }, en: { 'fidelidade.title': 'Loyalty' }, }, } ``` --- Próximo: a ferramenta que valida tudo isso em [CLI](/pt-BR/docs/referencia/cli). --- source: https://developers.fayz.ai/pt-BR/docs/referencia/tokens.md --- # Tokens de tema A **consulta rápida** do sistema de tokens: as famílias que compõem o Design System e as variáveis CSS que o motor de tema escreve a partir do manifesto. É o lado de referência do assunto — o **conceito** está em [Design System e tema](/pt-BR/docs/apps/temas) e o **passo prático** em [03 · Tema e marca](/pt-BR/docs/tutorial/03-tema-e-marca). Leia esta página em duas camadas: - **(a) O Design System oficial da Fayz** — o artefato de referência (`design/fayz-tokens.css`) que define a taxonomia completa das oito famílias. É o vocabulário-alvo. - **(b) O que o runtime aplica hoje** — as 3 chaves do manifesto (`brand`, `radius`, `mode`) e as variáveis CSS que o `theme engine` (`@fayz-ai/saas`) deriva delas. É o subconjunto vivo. ## (a) As oito famílias — Design System oficial Valores canônicos do Design System da Fayz, como taxonomia de referência. ### 1 · Marca + tints | Token | Valor | Papel | | --- | --- | --- | | `ignite` | `#2FDD4B` | Verde-assinatura — o hit da marca. | | `ignite-deep` | `#119A27` | Verde escuro — campos e blocos de marca. | | `ignite-soft` | `#DFFBE3` | Tint claro — halos de seleção e hover. | | `ignite-bg` | `#F2FDF4` | Tint pálido — acentos de superfície no claro. | ### 2 · Escala de neutros | Token | Valor | | Token | Valor | | --- | --- | --- | --- | --- | | `n-0` | `#FFFFFF` | | `n-500` | `#8A8A82` | | `n-50` | `#FAFAF8` | | `n-600` | `#5C5C57` | | `n-100` | `#F4F4F1` | | `n-700` | `#3D3D3A` | | `n-200` | `#EAEAE5` | | `n-800` | `#26262B` | | `n-300` | `#D9D9D2` | | `n-900` | `#131816` | | `n-400` | `#B8B8AF` | | `n-1000` | `#0B0F0E` | ### 3 · Secundárias (usar com parcimônia) | Token | Valor | | --- | --- | | `yellow` | `#F2DB0F` | | `cyan` | `#17C1EA` | | `coral` | `#FF6B5C` | | `magenta` | `#E81073` | ### 4 · Semântica por modo | Papel | Claro | Escuro | | --- | --- | --- | | Fundo | `paper #FAFAF8` | `black #0B0F0E` | | Superfície | `paper-2 #F4F4F1` | `n-900 #131816` | | Borda | `rgba(11,15,14,0.06)` | `rgba(255,255,255,0.08)` | | Texto | `near-black` | `white` | | Texto atenuado | `n-600` | `n-400` | ### 5 · Tipografia | Token | Família | Uso | | --- | --- | --- | | `font-display` | `Outfit` | Títulos e herói. | | `font-logo` | `Sora` | Só o wordmark. | | `font-body` | `DM Sans` | Corpo. | | `font-mono` | `JetBrains Mono` | Código. | ### 6 · Espaçamento Grade de **4px**: `4 · 8 · 12 · 16 · 24 · 32 …` — a malha que alinha tudo. ### 7 · Radius | Token | Valor | | Token | Valor | | --- | --- | --- | --- | --- | | `xs` | `4px` | | `lg` | `22px` | | `sm` | `8px` | | `xl` | `32px` | | `md` | `14px` | | `pill` | `9999px` | ### 8 · Elevação + motion | Token | Valor | | --- | --- | | `shadow-sm` | `0 1px 3px rgba(11,15,14,.06)…` | | `shadow-md` | `0 4px 12px rgba(11,15,14,.06)…` | | `shadow-lg` | `0 12px 32px rgba(11,15,14,.08)…` | | `shadow-glow` | halo verde `0 0 0 4px rgba(47,221,75,.15)…` | | `ease-out` | `cubic-bezier(0.22, 1, 0.36, 1)` | | `dur-base` | `240ms` | **Nona peça — vidro + aurora.** Receitas nomeadas, não cores soltas: o **vidro fosco** (`rgba(255,255,255,0.55)` + `blur 24px` no claro) e a **aurora** (`radial-gradient` verde que vaza atrás do herói). Cada uma combina fundo, borda, desfoque e brilho num único token. ## (b) O que o runtime aplica hoje No manifesto você declara três chaves. Detalhe dos valores e da personalidade de cada uma em [03 · Tema e marca](/pt-BR/docs/tutorial/03-tema-e-marca). | Chave | Valores | Deriva | | --- | --- | --- | | `brand` | `blue` `violet` `green` `orange` `red` `pink` `teal` | `primary`, `ring`, `accent` (matiz −50°) e a barra lateral opcional. | | `radius` | `none` `sm` `md` `lg` `full` | botões, cards, inputs e modais juntos. | | `mode` | `light` `dark` `system` | a estratégia de cor. | A partir daí, o `theme engine` (`createTheme` / `applyTheme`, em `@fayz-ai/saas`) escreve cada valor como **variável CSS** no documento: | Variável CSS | Vem de | | --- | --- | | `--primary` | a marca (`primaryForeground` branco). | | `--ring` | a marca — anel de foco. | | `--accent` | a marca com matiz girado **−50°**. | | `--sidebar`, `--sidebar-*` | rail colorido opcional (borda −12% de luz, item ativo −15%, ícones `matiz 35% 82%`). | | `--button-radius` | (com `--card-radius`, `--input-radius`, `--modal-radius`) da chave `radius`. | | `--font-family` | do preset base curado. | | `--shadow-sm` / `--shadow-md` / `--shadow-lg` | do preset base curado. | Tudo o que não vem da marca — neutros, superfícies, semânticas de `success`/`warning`/`destructive`, tipografia e sombras — sai de um **preset base curado** (o admin clássico) no qual a marca se encaixa. {% callout type="info" %} As oito famílias em (a) são a **taxonomia-alvo**; o manifesto expõe hoje o subconjunto em (b). Cor livre em HSL, as 11 famílias de fonte, os níveis de sombra e presets inteiros já existem no motor, atrás do runtime da plataforma — expô-los no manifesto é a evolução do contrato de tema. Contexto em [Além das 3 chaves](/pt-BR/docs/tutorial/03-tema-e-marca). {% /callout %} --- Próximo: as versões que coordenam esses pacotes em [Versões e canais](/pt-BR/docs/referencia/versoes). --- source: https://developers.fayz.ai/pt-BR/docs/referencia/versoes.md --- # Versões e canais Como as versões dos pacotes @fayz-ai/* são coordenadas por canais e como ler o suporte de cada superfície. {% callout type="warn" %} Em construção — estrutura para validação. {% /callout %} ## Canais | Canal | Para quê | | --- | --- | | `stable` | O conjunto testado e recomendado para produção. | | `latest` | A última versão publicada de cada pacote. | | `preview` | Versões de pré-lançamento, para experimentar o que vem. | Os canais são conjuntos de versões fixados (pin sets) pelo release-channels: o resolver mantém todos os pacotes `@fayz-ai/*` em um conjunto coerente. Para trocar de canal depois, você atualiza os pins do app para o conjunto desejado (`stable`, `latest` ou `preview`). **Como o canal entra no scaffold depende da versão da CLI:** - **CLI 0.2.0** (publicada) — o `fayz create` aceita a flag `--channel stable|latest|preview`; sem a flag, o default é `stable`. Você escolhe o conjunto de versões no momento de criar o app. - **CLI ≥ 0.3.0** — o `create` é flagless: o canal é decidido pelo próprio scaffold (o conjunto embutido na release da CLI), não por uma flag. Para trocar depois, você edita os pins do app. ## Tiers de suporte Cada superfície do SDK declara um nível de suporte (SUPPORT). Use-o para saber com o que contar: superfícies estáveis têm garantia de compatibilidade; superfícies em preview ou experimental podem mudar. --- source: https://developers.fayz.ai/pt-BR/docs/ia/seu-app-como-camada-de-dados.md --- # Seu app como camada de dados para IA Todo app gerado pela Fayz nasce **pronto para agentes**. Não é um recurso que você liga depois: o mesmo manifesto que descreve telas, rotas e dados também descreve, em contrato tipado, **o que uma IA pode ler e fazer** naquele app. Um agente que entende esse contrato consulta a agenda, resume o financeiro ou ajusta o estoque — sem que você escreva um endpoint de IA do zero. Esta página explica o contrato `aiTools`, o que já vem de graça, como a shell de chat se conecta a um LLM e como um plugin próprio entra nessa camada. ## O contrato `aiTools` Todo plugin pode declarar um campo `aiTools` no seu manifesto (`PluginManifest.aiTools?: PluginAITool[]`, em `@fayz-ai/core`). Cada ferramenta é uma **função que um agente pode chamar**, descrita num formato que LLMs entendem nativamente — o mesmo shape de _function calling_ que a OpenAI e a Anthropic usam: ```ts type PluginAITool = { id: string // 'agenda.create-appointment' name: string // 'createAppointment' — o nome que o LLM chama description: string // o que a ferramenta faz, em linguagem natural mode: 'read' | 'persist' // só lê dados, ou grava/muda estado? parameters?: { // JSON Schema: type:'object', properties, required type: 'object' properties: Record required?: string[] } permission?: { feature: string; action: 'read' | 'create' | ... } suggestions?: { label: string }[] // chips de sugestão no chat category?: string } ``` Dois detalhes importam: - **`mode` separa leitura de escrita.** `read` consulta; `persist` cria ou muda estado. A shell usa isso para filtrar e para você poder pedir confirmação antes de qualquer `persist`. - **`permission` prende a ferramenta ao controle de acesso.** A mesma feature/permissão que protege a tela protege a ferramenta. Um agente rodando com o papel de um usuário só enxerga as ferramentas que aquele usuário poderia usar. {% callout type="tip" %} **14 dos 22 plugins já declaram `aiTools`** hoje — agenda, conversations, crm, dashboard, financial, forms, inventory, marketing, menu, orders, shop, tables, tasks e admin. Ligou o plugin, ganhou as ferramentas dele no contrato. {% /callout %} ## Exemplos reais do SDK Estas são ferramentas que existem no código dos plugins hoje — não exemplos inventados: | Plugin | Ferramenta | `mode` | O que faz | | --- | --- | --- | --- | | `agenda` | `listAppointments` | `read` | Lista agendamentos de uma data ou período, com filtro por profissional. | | `agenda` | `createAppointment` | `persist` | Cria um agendamento para um cliente com profissional e serviço. | | `agenda` | `checkAvailability` | `read` | Verifica horários livres de um profissional numa data. | | `menu` | `toggleMenuItemAvailability` | `persist` | Marca um item do cardápio como disponível/esgotado. | | `financial` | `getRevenue` | `read` | Devolve o faturamento de um período. | | `orders` | `createOrder` | `persist` | Abre um novo pedido. | | `inventory` | `getLowStock` | `read` | Lista itens abaixo do ponto de reposição. | | `conversations` | `sendMessage` | `persist` | Envia uma mensagem numa conversa. | | `dashboard` | `getKpiSummary` | `read` | Resume os KPIs do negócio. | ## O que já vem de graça: ferramentas de core + registries Além do que cada plugin declara, a shell da Fayz (`@fayz-ai/saas`) injeta **três ferramentas de core sempre presentes**, definidas em `core-ai-tools.ts`: - `getBusinessSummary` (`read`) — o panorama do negócio. - `getTeamMembers` (`read`) — quem está na equipe. - `navigateTo` (`read`) — leva o usuário a uma tela. E há um multiplicador: **cada registry (entidade) não-readonly do seu app vira uma ferramenta `list` automaticamente**. Registrou `products`, ganhou `listProducts` sem escrever nada — o comentário no código é literal: _"Each registry gets a basic 'list' tool so plugins get AI capabilities for free."_ Suas entidades viram consultáveis por um agente só por existirem. ## A shell de chat — e a fronteira honesta A shell já traz a UI: um **FAB de chat** e um **painel** (`ChatFab`, `ChatPanel`), com chips de sugestão vindos das `aiTools` e filtragem por permissão e vertical via o hook `useAITools`. O usuário vê as ferramentas certas e sugestões prontas. Mas o `useChat` é **traga-seu-endpoint** (_BYO endpoint_). Ele faz `POST` do histórico da conversa para um `apiEndpoint` no formato OpenAI que você configura. Sem endpoint, a resposta é um mock de demonstração. {% callout type="warn" %} **O SDK não executa ferramentas.** `PluginAITool` não tem handler — ele é um **schema**, não uma implementação. Quem recebe o `tool_call` do LLM, roda a ação contra o Supabase (respeitando RLS) e devolve o resultado é o **backend do dono do app**. O SDK entrega o contrato e a UI; o loop de execução é seu. Nunca presuma que a Fayz "roda o agente" por você. {% /callout %} A arquitetura-alvo, honesta sobre o que existe: ``` ┌─────────────┐ histórico (tools ficam no seu backend) ┌──────────────────┐ │ ChatPanel │ ─────────────────────────────────────▶ │ seu apiEndpoint │ │ (shell UI) │ │ (seu backend) │ │ useAITools │ ◀───────────────────── │ + LLM (Claude/…) │ └─────────────┘ resposta / tool_call └────────┬─────────┘ ▲ │ executa a tool │ schemas de aiTools ▼ │ (do manifesto) ┌──────────────────┐ └───────────────────────────────── │ Supabase + RLS │ │ (dados do tenant) │ └──────────────────┘ ``` A shell fornece os **schemas** (o que existe) e a **UI**. Seu endpoint fornece o **LLM** e a **execução**. O RLS garante que o agente só toca os dados do tenant certo. ## Cenários práticos Escritos como **arquitetura-alvo sobre o que já existe** — os schemas estão prontos; falta você plugar o endpoint: - **Assistente que consulta a agenda e marca.** O LLM recebe `listAppointments`, `checkAvailability` e `createAppointment`. "Encaixa a Sarah amanhã de manhã?" → ele chama `checkAvailability`, escolhe o horário e propõe `createAppointment` (que é `persist` — você pede confirmação). - **Resumo financeiro por chat.** `getRevenue` + `getKpiSummary` alimentam "como foi a semana?" com números reais do tenant, não estimativa. - **Agente de estoque.** `getLowStock` acha o que está acabando; um `persist` de reposição (quando você o declarar) fecha o ciclo. ## Um `aiTool` de verdade, em JSON O schema que o seu endpoint entrega ao LLM — adaptado do `createAppointment` real do plugin-agenda: ```json { "name": "createAppointment", "description": "Creates a new appointment for a client with a specific professional and service.", "parameters": { "type": "object", "properties": { "client": { "type": "string", "description": "Client name" }, "professional": { "type": "string", "description": "Professional name" }, "service": { "type": "string", "description": "Service name" }, "date": { "type": "string", "description": "Date (YYYY-MM-DD)" }, "time": { "type": "string", "description": "Time (HH:MM)" } }, "required": ["client", "professional", "service", "date", "time"] } } ``` O `mode: 'persist'` e o `permission` ficam no manifesto (não vão ao LLM) — são o que a shell e o seu backend usam para gate e confirmação. ## Como um plugin próprio entra nessa camada Simples: **declare `aiTools` no manifesto.** O `fayz create plugin` já emite o array (vazio) — é só preencher. Uma ferramenta bem feita: 1. Tem `name` verbo-substantivo claro (`listLeads`, `createOrder`). 2. Declara `mode` honesto — `persist` para tudo que muda estado. 3. Descreve `parameters` com `description` em cada campo (o LLM lê isso). 4. Amarra `permission` à mesma feature da tela. Feito isso, seu plugin aparece no chat, nas sugestões e no contrato que o agente lê. Para os campos completos, veja o [Manifesto do plugin — referência](/pt-BR/docs/referencia/plugin-manifest). Para conectar o agente a este Dev Center, veja [Conecte seu agente](/pt-BR/docs/ia/conecte-seu-agente). --- source: https://developers.fayz.ai/pt-BR/docs/ia/conecte-seu-agente.md --- # Conecte seu agente Este site foi feito para ser lido por humanos **e** por agentes. Se você usa o Claude Code, o Cursor, o Codex ou qualquer agente para construir com a Fayz SDK, aponte a ferramenta para os artefatos abaixo — assim o agente responde com a estrutura real do SDK em vez de chutar. {% callout type="tip" %} Esta página é sobre conectar o agente **ao Dev Center**. Se você quer entender como o seu próprio app vira uma superfície que um agente lê e opera, veja [Seu app como camada de dados](/pt-BR/docs/ia/seu-app-como-camada-de-dados). {% /callout %} ## Todo app gerado já vem com um `AGENTS.md` Quando você roda `fayz create`, o scaffold inclui um **`AGENTS.md`** na raiz do projeto: um guia de agente **neutro de fornecedor** que descreve a estrutura do app, a checklist de personalização e o passo a passo do Supabase. Qualquer agente que respeite a convenção `AGENTS.md` lê esse arquivo e já sabe que "personalizar = editar o manifesto, não escrever código novo", onde ficam os arquivos e como conectar um banco real. O scaffold também gera um `CLAUDE.md` — mas ele é só um **ponteiro** para o `AGENTS.md`, para o Claude Code não duplicar guia. A fonte da verdade é uma só. {% callout type="tip" %} O `AGENTS.md` gerado aponta o agente de volta para este Dev Center — para o `llms.txt` (o mapa) e para o site (a referência humana). Então o agente que abre o seu app já sabe onde buscar o resto. {% /callout %} ## O ponto de entrada: `/llms.txt` Comece pelo [`/llms.txt`](/llms.txt). Ele lista a árvore de navegação inteira do Dev Center em texto puro, com um resumo de cada área — o mapa que um agente lê primeiro para saber o que existe. ```bash curl https://developers.fayz.ai/llms.txt ``` Se o agente precisar de **tudo de uma vez**, existe o [`/llms-full.txt`](/llms-full.txt): o Markdown cru de todas as páginas concatenado em ordem de navegação. É pesado — prefira o `llms.txt` como índice e puxe páginas específicas sob demanda. ## Cada página em Markdown Toda página de documentação tem uma versão em **Markdown cru**, servida no mesmo caminho com sufixo `.md`. No rodapé de cada página existe o link **"Ver esta página em Markdown"** — é exatamente esse arquivo. Aponte o agente para o `.md` da página relevante quando quiser dar contexto específico sem o HTML no meio. Por exemplo, esta página em Markdown está em `/pt-BR/docs/ia/conecte-seu-agente.md`. ## Exemplos de prompt Depois de dar o `llms.txt` ao agente, prompts curtos em português funcionam bem: ``` Leia https://developers.fayz.ai/llms.txt. Depois adicione o plugin crm ao meu app.manifest.json e rode o fayz doctor para validar. ``` ``` Meu npm run dev abre uma tela em branco. Leia a página de troubleshooting do Dev Center em Markdown e me explique se isso é esperado. ``` ``` Conecte este app a um Supabase real seguindo o AGENTS.md: preencha o .env.local e rode o fayz db apply --dry-run antes de aplicar de verdade. ``` ``` Leia /pt-BR/docs/ia/seu-app-como-camada-de-dados.md. Meu plugin próprio tem um registry de pedidos — proponha as aiTools que eu deveria declarar no manifesto, com mode e permission. ``` ## Boas práticas - Dê ao agente o `llms.txt` primeiro, depois páginas específicas sob demanda. - Prefira a versão Markdown de cada página ao HTML renderizado. - Deixe o `AGENTS.md` do app no contexto — ele carrega as convenções específicas do projeto. - Peça para o agente citar o slug da página que usou, para você conferir. - Depois de conectado, aponte-o para os procedimentos prontos em [Skills](/pt-BR/docs/ia/skills) — skills oficiais Fayz e da comunidade. ## MCP: em breve Um **MCP server** dedicado da Fayz — para o agente consultar catálogo e docs sem colar URLs — está **em breve** (em design). Por enquanto, o `llms.txt` mais as páginas `.md` são o caminho oficial. --- Próximo: [Seu app como camada de dados](/pt-BR/docs/ia/seu-app-como-camada-de-dados) · [Conectores e canais](/pt-BR/docs/ia/conectores-e-canais). --- source: https://developers.fayz.ai/pt-BR/docs/ia/skills.md --- # Skills: procedimentos para o seu agente Um app Fayz dá ao seu agente quatro camadas de contexto, e cada uma responde a uma pergunta diferente. O **`AGENTS.md`** é o *contrato* — as regras e convenções do projeto. O **`llms.txt`** (mais as páginas `.md`) é o *conhecimento* — o mapa e a referência do SDK. A **CLI** (`fayz create`, `fayz db`, `fayz deploy`) é a *execução* — as ações reprodutíveis. E as **skills** são os *procedimentos*: sequências prontas que o agente segue passo a passo em vez de improvisar. A direção da Fayz é não reescrever tudo do zero — o ecossistema reaproveita skills que já existem. As **skills oficiais Fayz vêm primeiro** (são o trilho do fluxo da CLI); as **skills da comunidade** entram depois, para cobrir qualidade de UI, banco e testes. {% callout type="tip" %} Uma **skill** é um arquivo `SKILL.md` com frontmatter YAML (`name`, `description`) mais as instruções do procedimento. A convenção é `.claude/skills//SKILL.md` — funciona no Claude Code e, via adaptadores do instalador, também em Cursor, Codex, Copilot, Windsurf, Gemini, Cline e Zed. O diretório aberto é o [skills.sh](https://www.skills.sh/); instalar é `npx skills add /`. {% /callout %} ## Skills oficiais Fayz — o trilho A metodologia Fayz vive como cinco skills, uma por etapa da jornada — descobrir, criar, dar dados, estender, publicar. Elas seguem a mesma ordem do fluxo da CLI e da trilha do [Tutorial](/pt-BR/docs/tutorial). {% callout type="info" %} **Estado honesto:** hoje as skills oficiais são **prompts copiáveis** — você cola o bloco no agente e ele executa o procedimento. O `/fayz-descoberta` completo, pronto para colar, está em [Setup agêntico](/pt-BR/docs/setup-agentico#o-fayz-descoberta-completo). O **empacotamento como skills instaláveis** (instalar por `npx skills add` e chamar por nome) está chegando — ainda não minta para o seu agente que já dá para instalá-las. {% /callout %} | Skill | O que faz | Etapa | Status | | --- | --- | --- | --- | | **/fayz-descoberta** | Entrevista de descoberta de produto, uma pergunta por vez; escreve o `PRODUCT-BRIEF.md`. | Antes do tutorial | Prompt copiável {% badge status="preview" %} | | **fayz-create** | Bootstrap do app: lê o brief → `fayz create` → configura plugins e tema → verifica com `fayz doctor`. | [Tutorial 01](/pt-BR/docs/tutorial/01-criar-o-app)–[04](/pt-BR/docs/tutorial/04-adicionar-um-plugin) | Prompt copiável {% badge status="preview" %} | | **fayz-db** | BYOS (traga o seu Supabase): `fayz db apply --dry-run` → `apply` → seeds. | [Tutorial 05](/pt-BR/docs/tutorial/05-dados-reais-com-supabase) | Prompt copiável {% badge status="preview" %} | | **fayz-plugin** | Autoria de um plugin app-local (incubator) no padrão do SDK. | [Tutorial 06](/pt-BR/docs/tutorial/06-seu-proprio-plugin) | Prompt copiável {% badge status="preview" %} | | **fayz-ship** | build → GitHub → `fayz deploy`. | [Tutorial 07](/pt-BR/docs/tutorial/07-publicar) | Prompt copiável {% badge status="preview" %} | O `PRODUCT-BRIEF.md` que a `/fayz-descoberta` escreve é a memória do projeto: a `fayz-create` lê dele para gerar o app certo, com os plugins e o tema certos, sem você repetir o contexto. ## Skills da comunidade — reaproveite antes de escrever Depois do trilho oficial, o seu agente ganha muito com skills abertas já mantidas por terceiros. Todas estão no [skills.sh](https://www.skills.sh/) e são código aberto no GitHub. Instale só o que a etapa pede. | Skill | Autor | Para quê no contexto Fayz | Instalar | | --- | --- | --- | --- | | **ui-ux-pro-max** | nextlevelbuilder | UI de storefronts e admins: banco local de 84 estilos, 192 paletas e 74 pares tipográficos, com workflows `--design-system` e um `search.py`. **Recomendada** para desenhar o visual antes de mexer no `theme`. | `npx skills add nextlevelbuilder/ui-ux-pro-max-skill` | | **frontend-design** | anthropics | Qualidade geral de front-end e boas práticas de componentes — útil ao editar telas dos plugins. | `npx skills add anthropics/skills` | | **web-design-guidelines** | vercel-labs | Diretrizes de design web (acessibilidade, layout, hierarquia) para revisar páginas de app. | `npx skills add vercel-labs/agent-skills` | | **vercel-react-best-practices** | vercel-labs | Padrões de React/Next para o código de app e plugins incubator. | `npx skills add vercel-labs/agent-skills` | | **supabase-postgres-best-practices** | supabase | Modelagem Postgres, índices e RLS — **recomendada** para o BYOS: casa com [RLS e multi-tenant](/pt-BR/docs/dados/rls) e com o `fayz db apply`. | `npx skills add supabase/agent-skills` | | **supabase** | supabase | Operar o Supabase pelo agente (schema, queries, migrações) — complementa o Supabase MCP do [Setup agêntico](/pt-BR/docs/setup-agentico#mcps). | `npx skills add supabase/agent-skills` | | **browser-use** | browser-use | Testes de browser de ponta a ponta — dirigir o app e conferir um fluxo real depois do `fayz doctor`. | `npx skills add browser-use/browser-use` | | **find-skills** | vercel-labs | Meta-skill: o agente descobre outras skills relevantes no diretório. | `npx skills add vercel-labs/skills` | {% callout type="tip" %} Duas escolhas que valem por padrão: **ui-ux-pro-max** para o visual de storefronts e admins, e **supabase-postgres-best-practices** para quando você conectar o seu próprio banco. As duas encaixam direto nas etapas de tema e de dados do tutorial. {% /callout %} ## Skills internas em desenvolvimento {% badge status="preview" %} Estas skills estão no roadmap da Fayz — ainda **não** disponíveis, listadas aqui para você saber o que vem: - **conceito-financeiro** — modelagem financeira nos módulos (contas, lançamentos, conciliação). - **integrations** — conectar Google Calendar, Stripe e afins pela espinha de conectores; veja [Conectores e canais](/pt-BR/docs/ia/conectores-e-canais). - **module-building** — elevar a qualidade de um plugin ao padrão de marketplace. ## Para agentes: como descobrir e aplicar skills Se você é um agente abrindo um projeto Fayz, siga esta ordem: 1. **Leia o `AGENTS.md` da raiz.** Ele é o contrato do projeto e aponta de volta para este Dev Center (`llms.txt` + páginas `.md`). 2. **Verifique `.claude/skills/`.** Se o projeto já tem skills instaladas, cada `SKILL.md` traz o procedimento e o frontmatter (`name`, `description`) diz quando aplicá-la. Prefira a skill à improvisação. 3. **Puxe o conhecimento sob demanda.** Comece pelo [`/llms.txt`](/llms.txt) como índice e busque a página `.md` específica da etapa (ex.: [dados/rls](/pt-BR/docs/dados/rls) antes de mexer em RLS). 4. **Case skill com etapa.** Descoberta/bootstrap/dados/plugin/ship → skill oficial Fayz correspondente. UI → `ui-ux-pro-max`. Postgres/RLS → `supabase-postgres-best-practices`. Teste de fluxo → `browser-use`. 5. **Cite o slug ou a skill que usou**, para o humano conferir. Para instalar uma skill nova em um projeto, use `npx skills add /` — o instalador grava em `.claude/skills/` e adapta para o agente em uso. --- Próximo: [Conecte seu agente](/pt-BR/docs/ia/conecte-seu-agente) · [Seu app como camada de dados](/pt-BR/docs/ia/seu-app-como-camada-de-dados). --- source: https://developers.fayz.ai/pt-BR/docs/ia/conectores-e-canais.md --- # Conectores e canais Se a [camada de dados](/pt-BR/docs/ia/seu-app-como-camada-de-dados) é sobre o que uma IA pode ler e fazer **dentro** do seu app, esta página é sobre as **pontes para fora**: sincronizar com provedores externos (o Google Calendar, o Stripe) e — o que o fundador mais pergunta — atender por canais de mensagem como o WhatsApp. Parte disso já está em produção. Parte é roadmap, e aqui a gente diz claramente qual é qual. Para a lista completa de provedores do catálogo (com o status de cada um), veja a página de [Integrações](/pt-BR/docs/plugins/integracoes). ## A espinha de conectores Existe um contrato real de conectores em `@fayz-ai/core` (`packages/core/src/integrations`): `Connector` e `ConnectorDefinition`. Um conector declara: - **Um modo de autenticação** — `oauth`, `api-key` ou `mtls`. - **Capacidades** — o que ele sabe sincronizar. - **`testConnection` e `sync`** — testar a credencial e puxar/empurrar dados. Um plugin publica conectores pelo campo `connectors` do manifesto (o plugin vira um addon de um host). A shell traz um **ConnectorsHub** compartilhado nas configurações, onde o usuário conecta e gerencia provedores. O trabalho pesado de sincronização roda em **Supabase Edge Functions** — o plano de dados fica no backend, não no navegador. {% callout type="tip" %} Pense em dois planos: o **control plane** é a UI de `/settings` (conectar, testar, escolher o que sincronizar); o **data plane** é a edge function que faz o sync de verdade. O contrato em `@fayz-ai/core` costura os dois. {% /callout %} ## Dois conectores que já existem Não é teoria — há dois POCs shipados: {% cards %} {% card title="Google Calendar" icon="📅" %} No `plugin-agenda`: OAuth, seletor de calendário e sync de eventos. Vive em `src/integrations/google-calendar`. É o exemplo canônico de conector nativo de um plugin. {% /card %} {% card title="Stripe" icon="💳" %} No `plugin-courses`: conector de pagamentos em `src/connectors/stripe.ts`. Mostra o mesmo contrato aplicado a um provedor de billing. {% /card %} {% /cards %} Os dois seguem o mesmo `ConnectorDefinition` — é o padrão que um plugin próprio replica para falar com qualquer provedor externo. ## Canais de mensagem — e o WhatsApp Aqui entra o que o fundador cobra: **como esses produtos chegam ao WhatsApp**. A resposta honesta tem duas partes — a base que já existe e o marco que ainda vem. ### O que existe: o inbox omni-channel O `plugin-conversations` é um **inbox omni-channel experimental**. O enum de canais já inclui `whatsapp` como rótulo, e o plugin declara as `aiTools` `listConversations` (`read`) e `sendMessage` (`persist`). Ou seja: a **estrutura** de caixa de entrada, threads e ferramentas de IA para ler e responder **já está modelada**. {% badge status="experimental" %} O que **não** existe ainda: o provedor é **mock**. Não há integração real de mensagens. Nenhuma mensagem de WhatsApp entra ou sai hoje. ### O que vem: conectores reais de canal O próprio README do plugin-conversations diz qual é o próximo marco, sem rodeios: > "Real channel connectors — Twilio, WhatsApp Cloud, Meta, IMAP — are the next milestone." {% callout type="warn" %} **WhatsApp é roadmap.** Ainda não existe configuração real de WhatsApp, Twilio ou Meta na SDK. Qualquer tela que sugira o contrário seria falsa. O que existe é o inbox experimental (mock) e o contrato de conectores pronto para receber esses provedores. {% /callout %} ### O fluxo-alvo: atendimento com IA no WhatsApp Quando os conectores de canal chegarem, a base já está desenhada para isto — some as duas metades desta seção: ``` WhatsApp Cloud API ──▶ conector de canal ──▶ plugin-conversations (inbox) │ aiTools (listConversations, sendMessage) │ seu endpoint + LLM │ responde no WhatsApp com contexto real do tenant (agenda, pedidos…) ``` O inbox recebe a mensagem por um conector real; as `aiTools` de conversations (mais as dos outros plugins) dão ao agente o que ler e fazer; seu endpoint roda o LLM; a resposta volta pelo mesmo canal. **Inbox + aiTools = atendimento com IA no WhatsApp** — a arquitetura é essa, e o que falta é o conector de canal, não o resto. ## MCP: em breve Um **MCP server** dedicado da Fayz — para o agente consultar catálogo e docs sem colar URLs — está em fase de design (só docs por enquanto). Até lá, o caminho oficial é o [`llms.txt` e as páginas `.md`](/pt-BR/docs/ia/conecte-seu-agente). --- Veja também: [Seu app como camada de dados](/pt-BR/docs/ia/seu-app-como-camada-de-dados) e o campo `connectors` no [Manifesto do plugin](/pt-BR/docs/referencia/plugin-manifest). --- source: https://developers.fayz.ai/pt-BR/docs/recursos/troubleshooting.md --- # Troubleshooting Os problemas mais comuns ao construir com a Fayz SDK — cada um no formato **problema → causa → solução**. Comece pela tela em branco: é de longe a dúvida número um de quem chega de fora. ## `npm run dev` abre uma tela placeholder / âncora **Problema.** Você gerou o app, rodou `npm install && npm run dev`, abriu o navegador e viu uma tela mínima — um placeholder, uma âncora vazia, nada do shell de admin que a documentação promete. **Causa.** Isso é esperado. O **runtime** que monta o shell a partir do seu `app.manifest.json` é distribuído junto com a plataforma Fayz, não no pacote público `@fayz-ai/sdk` que o scaffold instala hoje. O projeto que você gerou tem o manifesto, os plugins e a config corretos — mas, rodando localmente pela SDK pública, ele ainda não tem o app-runtime que renderiza tudo isso. A tela em branco não é bug: é a fronteira entre o que já é público e o que roda dentro do Fayz. **Solução.** Não há um "conserto" — é uma característica do estágio atual. O que fazer: - Trate o app gerado como **fonte da verdade da config**: o manifesto, os plugins ligados e a árvore de arquivos já são reais e válidos. - Para ver o app renderizado hoje, o caminho é rodá-lo dentro da plataforma Fayz. - Entenda por que essa fronteira existe antes de gastar tempo caçando o "erro". {% callout type="warn" %} Essa é a confusão mais comum de quem experimenta a SDK pública pela primeira vez. Leia [Os dois caminhos](/pt-BR/docs/dois-caminhos) para entender quem é dono do shell, e o [passo 02 do tutorial](/pt-BR/docs/tutorial/02-explorar-a-anatomia) para ver o que cada arquivo do scaffold faz. A tela em branco fica óbvia depois desses dois. {% /callout %} ## Tela em branco / `useAuth must be used inside ` **Problema.** Você monta um app em código consumindo os pacotes publicados, sobe o dev server e a tela fica **em branco**. No console: `useAuth must be used inside ` — mesmo com o `AuthProvider` claramente envolvendo a árvore. **Causa.** É um conflito de versões que gera **duas cópias do contexto React de auth**. Concretamente, na linha `0.6.x`: `@fayz-ai/saas@0.6.0` depende de `plugin-auth ^0.1.0`; o npm resolve isso para `0.1.3`, que por sua vez exige `auth/core ^0.7.1`. O resultado é uma **segunda** cópia de `@fayz-ai/auth` na árvore de `node_modules`. O `AuthProvider` de uma cópia e o `useAuth` da outra referenciam objetos de contexto React **diferentes** — então, para o `useAuth`, não há provider acima dele, e ele lança. A tela em branco é essa exceção derrubando o render. **Solução.** Force uma única linha de versão para todo o eixo de auth com um bloco `overrides` no `package.json` do app, travado na mesma linha do `saas` que você usa: ```json { "overrides": { "@fayz-ai/plugin-auth": "0.1.3", "@fayz-ai/auth": "0.7.1", "@fayz-ai/core": "0.6.0", "@fayz-ai/ui": "0.6.0" } } ``` Depois apague `node_modules` e o lockfile e reinstale (`rm -rf node_modules package-lock.json && npm install`) para o `overrides` de fato colapsar as duas cópias em uma. Ajuste os números para casar com as versões do seu `@fayz-ai/saas` — o ponto é que `plugin-auth`, `auth`, `core` e `ui` fiquem todos numa linha coerente, sem uma segunda cópia do contexto. ## `fayz doctor` avisa sobre plugins referenciados no manifesto **Problema.** Você roda `fayz doctor` e vê um aviso como: ``` ⚠ manifest references plugin(s) [agenda, crm] — each id must resolve to an installed @fayz-ai/plugin-* factory wired in src/plugins.generated.ts or src/config/app.tsx 0 error(s), 1 warning(s) ``` **Causa.** É um **aviso, não um erro** — repare no `0 error(s)`. Cada `id` de plugin no manifesto precisa resolver para uma factory `@fayz-ai/plugin-*` de fato **instalada** (via npm) e **conectada** no `src/plugins.generated.ts` ou no `src/config/app.tsx`. Um plugin, no modelo real, é um pacote npm instalado + ligado no array de plugins — não algo que o runtime injeta sozinho. O `doctor` lista os ids que ainda não estão amarrados para você saber o que falta instalar ou ligar. **Solução.** Instale o pacote de cada plugin referenciado (`npm i @fayz-ai/plugin-agenda`, …) e confirme que ele está ligado no `src/plugins.generated.ts` ou no `src/config/app.tsx`. É um aviso, não um erro — a contagem `0 error(s)` significa que o build não quebra e o CI não cai; mas cada id listado só vira um plugin carregado depois de instalado e wired. ## `fayz doctor` reprova um tema custom num app código-primeiro **Problema.** Você tem um app **código-primeiro** — o tema real vive no code-config (um `SaasTheme` com HSL custom, perfeitamente válido) e o `app.manifest.json` é vestigial. Ainda assim o `fayz doctor` reprova o manifesto porque `theme.brand` não é um dos sete nomes de marca conhecidos. **Causa.** O `doctor` hoje valida o manifesto de forma **estrita**, sem saber que, num app código-primeiro, o manifesto é só um resquício e a fonte da verdade do tema é o code-config. O `theme.brand` do manifesto aceita apenas os sete nomes de marca embutidos; um HSL custom válido no seu `SaasTheme` não satisfaz essa checagem porque ela nem olha para o code-config. **Solução.** Mantenha, no manifesto vestigial, um **`theme.brand` mínimo e válido** — qualquer um dos sete nomes de marca — só para passar no doctor, enquanto o tema real continua no code-config, que é quem de fato pinta o app: ```json { "theme": { "brand": "violet" } } ``` O `brand` nomeado aqui não afeta o app renderizado (o code-config vence); ele só mantém o manifesto válido. É um workaround honesto, não um bug seu. A validação vai ficar **path-aware** — reconhecendo apps código-primeiro e deixando o code-config ser a fonte da verdade do tema — num fix de SDK; até lá, o `brand` nomeado no manifesto é a ponte. ## `fayz db apply` reclama de variáveis de ambiente faltando **Problema.** ``` ✗ Missing required Supabase credentials: SUPABASE_PROJECT_REF (or SUPABASE_REF), SUPABASE_PAT (or SUPABASE_ACCESS_TOKEN). ``` **Causa.** O `fayz db apply` fala com a API de gestão do Supabase e **nunca** assume credenciais padrão. Ele precisa de duas coisas: qual projeto (`SUPABASE_PROJECT_REF`, ou o alias `SUPABASE_REF`) e com qual token (`SUPABASE_PAT`, ou o alias `SUPABASE_ACCESS_TOKEN`). **Solução.** Coloque as duas no seu shell ou em `/.env.local` (que é git-ignored): ```bash SUPABASE_PROJECT_REF=seu-project-ref SUPABASE_PAT=sbp_... ``` Onde achar cada uma: - **Access token (PAT):** dashboard do Supabase → Account → Access Tokens → Generate new token. - **Project ref:** dashboard do Supabase → Project Settings → General (é também o subdomínio na URL do projeto). ## O dry-run diz "ships no migrations" **Problema.** No `fayz db apply --dry-run` aparece uma nota: ``` installed @fayz-ai/db ships no migrations/ — the spine step is empty (upgrade to @fayz-ai/db >= 0.1.3 once published) ``` **Causa.** A "espinha" de migrations (o schema base compartilhado) é distribuída dentro do pacote `@fayz-ai/db`. A versão publicada hoje (0.1.2) ainda não embarca esses arquivos `.sql` — por isso o passo da espinha sai vazio no plano. O SQL da espinha entra a partir da 0.1.3. **Solução.** É esperado enquanto a 0.1.3 não sai. O `--dry-run` continua mostrando o plano corretamente (incluindo suas migrations próprias); só o passo `spine` fica vazio. Quando a 0.1.3+ for publicada, um `npm install @fayz-ai/db@latest` preenche esse passo automaticamente. Veja o [Changelog](/pt-BR/docs/recursos/changelog). ## `db apply` se recusa a rodar em shell não interativo **Problema.** ``` ✗ Refusing to apply migrations without confirmation in a non-interactive shell. Re-run with --yes to proceed. ``` **Causa.** Aplicar migrations é uma operação destrutiva contra um banco real, então o comando pede uma confirmação `y`. Em um shell sem TTY (CI, pipe, agente de IA), não há como digitar essa confirmação — e o comando **se recusa** em vez de travar esperando por um stdin que nunca vem. **Solução.** Passe `--yes` (ou `-y`) para pular o prompt de forma explícita: ```bash fayz db apply --yes ``` {% callout type="warn" %} `--yes` aplica migrations sem pedir confirmação. Use em automação consciente, não como hábito no seu terminal local. {% /callout %} Ver também: [Conecte seu agente](/pt-BR/docs/ia/conecte-seu-agente) — como um agente roda os comandos `fayz` com o `AGENTS.md` no contexto. ## `fayz create` rejeita o nome do app **Problema.** ``` ✗ Provide a kebab-case app name, e.g. fayz create admin my-app ``` **Causa.** O nome do app precisa ser **kebab-case**: só letras minúsculas, números e hífens, começando por letra ou número. Nomes com maiúsculas, espaços, `_` ou caracteres especiais (`Minha Loja`, `minha_loja`, `MinhaLoja`) são recusados. **Solução.** Use um slug válido: ```bash fayz create admin minha-loja ``` ## Porta 5173 já está em uso **Problema.** Ao rodar `npm run dev` o Vite falha ou abre em outra porta porque a `5173` já está ocupada. **Causa.** O scaffold usa Vite, cujo servidor de desenvolvimento sobe na porta `5173` por padrão. Outro processo (uma instância anterior que não morreu, outro app Vite) já está segurando a porta. **Solução.** Escolha uma: - Libere a porta matando o processo antigo: ```bash lsof -ti:5173 | xargs kill ``` - Ou rode em outra porta: ```bash npm run dev -- --port 5174 ``` --- source: https://developers.fayz.ai/pt-BR/docs/recursos/ia.md --- # Para agentes de IA Esta seção virou uma área própria do Dev Center: **IA**. - [Conecte seu agente](/pt-BR/docs/ia/conecte-seu-agente) — `llms.txt`, `.md` por página, `AGENTS.md` do scaffold e prompts de exemplo. - [Skills](/pt-BR/docs/ia/skills) — os procedimentos prontos: skills oficiais Fayz primeiro, depois as da comunidade (`ui-ux-pro-max`, `supabase-postgres-best-practices`). - [Seu app como camada de dados](/pt-BR/docs/ia/seu-app-como-camada-de-dados) — o contrato `aiTools`, ferramentas de core e a shell de chat. - [Conectores e canais](/pt-BR/docs/ia/conectores-e-canais) — a espinha de conectores, Google Calendar/Stripe e o roadmap de WhatsApp. --- source: https://developers.fayz.ai/pt-BR/docs/recursos/changelog.md --- # Changelog O histórico de mudanças do SDK e dos plugins: o que entrou em cada release, o que quebrou compatibilidade e o que foi removido. ## Formato de uma entrada Cada entrada tem três coisas: - **Versão + data** — o número da release e quando ela saiu (ou, se ainda em preparação, o alvo). - **Mudanças por pacote** — agrupadas por pacote (`@fayz-ai/cli`, `@fayz-ai/db`, plugins…), porque cada pacote versiona por conta própria. - **Notas de compatibilidade** — quando algo muda de comportamento ou exige um passo de migração. Enquanto o SDK está pré-1.0, versões `0.x` podem trazer mudanças de comportamento em releases menores — leia as notas antes de subir de versão. Veja [Versionamento](/pt-BR/docs/referencia/versoes) para a política completa. --- ## CLI 0.3.0 — fluxo de banco de dados {% badge status="beta" %} **Em preparação** — descrito aqui para você acompanhar; ainda não publicado. Esta leva foca em levar um app do mock a um Supabase real por um caminho previsível e auditável. **`@fayz-ai/cli`** - Novo comando **`fayz db apply`**: monta um plano de migração ordenado e o aplica via API de gestão do Supabase. - `--dry-run` mostra o plano inteiro **sem rede** — bom para revisar antes de tocar o banco. - Contrato de ambiente explícito: exige `SUPABASE_PROJECT_REF` e `SUPABASE_PAT` (alias `SUPABASE_ACCESS_TOKEN`), nunca assume padrão. - Confirmação obrigatória: pede `y` num TTY e **se recusa** em shell não interativo a menos que `--yes` seja passado. - Scaffold do `fayz create` mais completo: agora gera **`.env.example`** (com as chaves de runtime e de tooling comentadas) e **`AGENTS.md`** (guia de agente neutro de fornecedor, com `CLAUDE.md` apontando para ele). **`@fayz-ai/db`** - Passa a embarcar o **SQL da espinha** (schema base compartilhado) dentro de `migrations/`, que o `fayz db apply` consome como o primeiro passo do plano. - Até a 0.1.2, o passo da espinha sai vazio e o dry-run avisa `installed @fayz-ai/db ships no migrations/`. A partir da **0.1.3** esse passo é preenchido. **Compatibilidade.** Apps existentes seguem rodando em `backend.provider: "mock"` sem mudança. O caminho de banco real é opt-in: só quem preenche o `.env.local` e roda `fayz db apply` é afetado. {% callout type="warn" %} As versões e o escopo acima descrevem trabalho **em preparação** e podem mudar até a publicação. Quando a release sair, esta entrada é atualizada com a data real. {% /callout %} --- source: https://developers.fayz.ai/pt-BR/docs/recursos/comunidade.md --- # Comunidade A **Faya Labs** é a comunidade em volta do Fayz: onde você tira dúvidas, reporta problemas e acompanha o que está sendo construído. O Fayz é o produto; a Faya Labs é quem o mantém e as pessoas que constroem com ele. ## Onde conseguir ajuda - **Suporte / dúvidas.** Comece pela documentação — o [Troubleshooting](/pt-BR/docs/recursos/troubleshooting) e o [FAQ](/pt-BR/docs/recursos/faq) cobrem a maioria dos tropeços iniciais. O canal de suporte da comunidade será anunciado aqui em breve. - **Reportar bugs.** Achou algo quebrado ou um comportamento que a doc não explica? O canal oficial para abrir issues (o tracker de bugs) será anunciado aqui nesta página assim que estiver no ar. Enquanto isso, já vá montando o relato: o que você esperava, o que aconteceu e como reproduzir (comando, versão do pacote, saída do `fayz doctor`). Quanto mais concreto, mais rápido o retorno. - **Ideias e feedback.** Falta uma capacidade, um plugin, um trecho de doc? Mande — a lista de prioridades da SDK é moldada por quem está construindo de verdade. {% callout type="tip" %} Ao reportar um problema, inclua a saída de `fayz doctor` e a versão do pacote (`npm ls @fayz-ai/cli`). Isso encurta metade das idas e vindas. {% /callout %} ## Como o feedback vira SDK O Fayz é construído de dentro para fora: a Faya Labs usa a própria SDK para tocar apps reais. Um atrito que aparece num app de cliente vira um item de backlog, e o item vira uma melhoria no core, num plugin ou na documentação. Quando algo relevante entra numa release, ele aparece no [Changelog](/pt-BR/docs/recursos/changelog). Em outras palavras: o que você reporta não some numa caixa de sugestões — ele compete pela mesma fila que os problemas que a própria equipe encontra. --- source: https://developers.fayz.ai/pt-BR/docs/recursos/faq.md --- # FAQ As perguntas que aparecem com mais frequência de quem está começando com a Fayz SDK. ## É grátis? Qual a licença? Os pacotes públicos da SDK são distribuídos sob licença **MIT** — livres para usar, inclusive comercialmente. A plataforma Fayz hospedada é um produto à parte; a SDK em si você pode instalar e rodar sem custo. ## Posso usar a SDK sem a plataforma Fayz? Em parte, e vale ser honesto sobre o limite. Você pode instalar o `@fayz-ai/cli`, gerar apps, editar o manifesto, ligar plugins e planejar migrations — tudo isso é público. **Mas** o app-runtime que renderiza o shell de admin a partir do manifesto é distribuído junto com a plataforma, então localmente pela SDK pública você ainda vê uma tela placeholder em vez do app montado. Veja [Troubleshooting](/pt-BR/docs/recursos/troubleshooting) e [Os dois caminhos](/pt-BR/docs/dois-caminhos) para entender exatamente onde fica essa fronteira hoje. ## Como funciona o versionamento antes da 1.0? Cada pacote versiona por conta própria em `0.x`. Enquanto estamos pré-1.0, uma release menor **pode** trazer mudança de comportamento — não trate `0.x` como estritamente semver. Leia as notas do [Changelog](/pt-BR/docs/recursos/changelog) antes de subir de versão, e fixe versões em produção. A política completa está em [Versionamento](/pt-BR/docs/referencia/versoes). ## Posso criar meu próprio plugin? Sim. O caminho recomendado é o **incubator**: um plugin que mora no `src/plugins/` do seu app, seguindo o mesmo contrato dos plugins do catálogo, com dono do próprio banco e injetando UI nas superfícies da SDK. Ele pode amadurecer localmente e, se fizer sentido, graduar para o marketplace. Veja [Plugins próprios](/pt-BR/docs/plugins-proprios/incubator). ## Como contribuo com o core? Por enquanto o desenvolvimento do core é conduzido pela Faya Labs. Se você quer propor uma mudança, corrigir algo ou construir junto, **fale com a gente** pela [Comunidade](/pt-BR/docs/recursos/comunidade) — descreva o caso e a gente encaminha. Não há um fluxo público de pull request aberto hoje. ## Qual a relação entre Fayz e Faya Labs? **Fayz** é o produto — a SDK, os plugins, a plataforma. **Faya Labs** é quem constrói e mantém o Fayz, e a comunidade em volta dele. Quando você lê "a Faya Labs decidiu X", é sobre a direção do produto Fayz. ## Preciso de Supabase para começar? Não. Todo app gerado nasce com `backend.provider: "mock"`, que roda com dados de exemplo e **zero configuração** — é o modo mock-first. Você só conecta um Supabase real quando quiser dados persistentes; aí preenche o `.env.local` e roda `fayz db apply`. Comece no mock, migre quando precisar. O passo a passo está em [Dados reais com Supabase](/pt-BR/docs/tutorial/05-dados-reais-com-supabase). ## O que dá para publicar como site estático? O front-end gerado é uma app Vite, então o build é um bundle estático publicável em qualquer host de arquivos. O que exige backend (dados reais via Supabase, tooling de migração) continua precisando das credenciais correspondentes. Veja [Deploy estático](/pt-BR/docs/deploy/estatico).