Docs
Obrigatoriedade — quando deve usar
10 — Brand kit (`@framework/brand`)
Princípio
Um lugar para rebrandar: nome, domínios, cores, tipografia, logos, favicons, tokens de tema, SEO default e shell de email vivem em packages/brand. Apps consomem — não duplicam.
packages/brand (editar no fork)
├── config.ts / brand-data.json → identidade + domínios + SEO
├── assets/ → logos, favicons, og-image
├── theme.css → tokens shadcn (HSL)
└── helpers (metadata, email, tailwind preset)
↓
@framework/ui → apps/app, apps/backoffice
imports diretos → apps/website, apps/service
O que o pacote exporta
| Import | Quando usar |
|---|---|
@framework/brand | React: BrandLogo, APP_NAME, getBrandMetadata, getThemeStorageKey, getLogoUrl |
@framework/brand/config | brandConfig tipado (Next.js metadata, URLs derivadas) |
@framework/brand/node | Service (CJS): APP_NAME, wrapEmailContent, resolveEmailBrand — ou apps/service/src/lib/brand.ts |
@framework/brand/theme.css | Tokens CSS — não copiar para apps; já importado por @framework/ui |
@framework/brand/tailwind-preset | presets: [brandPreset] nos tailwind.config.js |
brandPublicPlugin({ surface }) | Vite (app/backoffice): sync de assets + injeção de metadata no index.html |
Design guide (dev)
pnpm dev:brand # http://localhost:6007 — catálogo visual
pnpm build:brand # dist-guide/
Obrigatoriedade — quando deve usar @framework/brand
Use o pacote (nunca hardcode) nestes casos:
| Situação | Obrigatório | Como |
|---|---|---|
| Rebrand / fork (Fase 0) | Sim | Editar packages/brand + pnpm rebrand:sync |
| Nome do produto na UI | Sim | APP_NAME, brandConfig.name ou i18n alimentado pelo rebrand |
| Logo na interface | Sim | BrandLogo ou getLogoUrl() / paths em brandPublicPaths |
| Favicon / OG image | Sim | assets/icons/ + sync (brandPublicPlugin ou sync-public.mjs) |
| Domínios em código | Sim | brandConfig.domains, getAppUrl(), getWebsiteUrl(), etc. |
| Cores da identidade | Sim | Tokens em theme.css / classes Tailwind (bg-primary, bg-accent) — não hex #071952 em componentes |
| Metadata (title, description, OG) | Sim | getBrandMetadata(surface) ou plugin no index.html |
| Tema claro/escuro (storage key) | Sim | getThemeStorageKey('app' | 'backoffice') |
| Tipografia da marca | Sim | typography em config + getGoogleFontsCssUrl() / getNextFontOptions() |
| Emails transacionais (service) | Sim | Shell wrapEmailContent + variáveis {{primaryColor}}, {{appName}} |
Fallback de APP_NAME / URL no service | Sim | APP_NAME, getAppUrl() via src/lib/brand.ts — não 'Framework' ou domínio fixo |
| Tailwind — cores semânticas | Sim | Preset @framework/brand/tailwind-preset |
Gate de revisão (PR/commit mental)
Antes de mergear código que toca identidade, pergunte:
- Existe string com nome do produto, domínio
*.forestbit.ioou hex da paleta fora depackages/brand? - Existe logo/favicon copiado manualmente para
public/sem passar porassets/? - O CSS de tema foi duplicado em
apps/*/src/index.cssem vez de importar@framework/ui/styles.css?
Se sim em qualquer item → corrigir para usar @framework/brand.
Quando não é obrigatório (e o que fica fora)
| Situação | Onde fica | Nota |
|---|---|---|
| Componentes shadcn (variants, layout) | @framework/ui | Consome tokens do brand; não move componentes para brand |
| Logos de integrações (Stripe, Shopify…) | public/ do website | Conteúdo de produto, não marca |
| Ilustrações de blog / campanhas | apps/website/content/ | Marketing por página |
| IDs de analytics | env — website: NEXT_PUBLIC_GTM_ID; app: VITE_GA4_ID, VITE_HOTJAR_ID | Domínios do cross-domain linker vêm de brandConfig.domains · ver 06-tracking-attribution.md |
| Copy longo de marketing / legal | docs/, locales do website | Atualizar no rebrand (spec 001); não precisa import TS em runtime |
| Help docs in-app | apps/app/public/docs/ | Conteúdo de produto |
| Placeholders de Storybook | stories | Fixtures de demo |
Uso por app
apps/app e apps/backoffice (Vite + React)
import { APP_NAME, BrandLogo, getThemeStorageKey } from '@framework/brand'
| Integração | Detalhe |
|---|---|
| CSS | src/index.css → @import '@framework/ui/styles.css' apenas |
| Vite | brandPublicPlugin({ surface: 'app' | 'backoffice' }) |
| Tema | <ThemeProvider storageKey={getThemeStorageKey('app')}> |
| Constantes | Re-export em src/shared/lib/constants.ts é aceitável |
Assets em public/brand/ e public/favicon.* são gerados no dev/build — não editar à mão.
apps/website (Next.js)
import { getBrandMetadata, getNextFontOptions } from '@framework/brand'
import { brandConfig } from '@framework/brand/config'
| Integração | Detalhe |
|---|---|
| Layout | getBrandMetadata('website') em metadata / openGraph |
| CSS | @import '@framework/brand/theme.css' em globals.css |
| URLs | lib/constants.ts: APP_URL via brandConfig.domains.app |
| Sign-up | buildSignUpUrl() / SIGN_UP_URL — não URL fixa no JSX |
| Prebuild | sync-public.mjs no predev / prebuild |
apps/service (NestJS)
import { APP_NAME, getAppUrl, resolveEmailBrand, wrapEmailContent } from '../../lib/brand'
| Integração | Detalhe |
|---|---|
| Nome / URLs | src/lib/brand.ts lê brand-data.json + node.cjs |
| Env | APP_NAME, APP_URL, APP_LOGO_URL no .env — exemplos em .env.example |
| Emails | Templates só com conteúdo; shell via wrapEmailContent |
| Swagger | Exemplos de email/domínio devem seguir brand-data.json após rebrand |
Após editar config.ts, rodar:
pnpm --filter @framework/brand sync-brand-data
@framework/ui
- Importa
@framework/brand/theme.cssemsrc/index.css - Não duplicar tokens
:root/.darkno UI ou nos apps
Anti-padrões (proibidos após centralização)
| ❌ Não fazer | ✅ Fazer |
|---|---|
bg-[#071952] em componentes | bg-primary ou var(--brand-primary) |
name: 'Framework' como fallback de produto | APP_NAME ou brandConfig.name |
https://app.seudominio.com hardcoded | getAppUrl() ou brandConfig.domains |
/images/logos/framework-logo.svg | /brand/logos/logo.svg (sync do brand) |
Copiar index.css completo do UI no app | @import '@framework/ui/styles.css' |
Editar favicon só em apps/app/public/ | Editar packages/brand/assets/icons/ |
Metadata estática no index.html (prod) | brandPublicPlugin ou getBrandMetadata |
Fluxo de rebrand (fork)
Ordem recomendada — detalhe em PLAYBOOK Fase 0:
- Editar
packages/brand/src/config.tsepackages/brand/assets/ pnpm rebrand:sync(env examples + cloud/dokploy)- Copiar
.env.example→.envnos apps; preencher secrets - i18n: editar
src/locales/no Cursor - Validar:
pnpm dev:brand,pnpm dev, metadata e logos nos 4 apps
Não rebrandar app por app copiando assets ou cores.
Checklist detalhado: specs/001-setup-initial/checklists/requirements.md.
Relação com outras docs
| Documento | Relação |
|---|---|
| 01-architecture-stack | Domínios por app — valores vêm do brand |
| 05-deploy-infrastructure | cloud/dokploy/* alinhado via pnpm rebrand:sync |
| 06-tracking-attribution | GA cross-domain: domínios do brand |
| marketing/04-brand-communication | Tom de voz e comunicação (negócio) |
| spec 001 | Checklist de rebrand (referência) |