Pular para o conteúdo principal

ADR-016 — Extração de ui-web/ui-native, Storybook independente e docs-site viva (reverse-engineered)

  • Status: Inferred / documentado retroativamente — não é um ADR redigido antes da implementação.
  • Data do registro: 2026-08-30 (a implementação ocorreu em 2026-08-29/30, na branch feat/component-atomicity-storybook, mergeada em master no commit 115ffe2 antes deste documento existir).
  • Decisores: Owner, via pedidos diretos em chat, fora do fluxo SDD formal (sem CR/IS/EP aprovado como ponto de partida).
  • Relacionado: SPEC-ARCH-BOUNDARIES-001 v2.1, SPEC-ARCH-QUALITY-001 v2.1, CR-COMPONENT-ATOMICITY-001, CR-VERCEL-DEPLOYS-001, CR-API-ERROR-CATALOG-001, CR-SDD-DASHBOARD-001.

Nota de proveniência

Este documento foi produzido pela skill raizfc-reverse-engineer-branch para reconstruir, em linguagem de produto/arquitetura, o que a branch feat/component-atomicity-storybook entregou. A branch não partiu de um CR/IS/EP aprovado — foi trabalho direto por pedido do owner em chat. As três CRs relacionadas (CR-COMPONENT-ATOMICITY-001, CR-VERCEL-DEPLOYS-001, CR-API-ERROR-CATALOG-001) foram escritas depois da implementação, a pedido do próprio owner, e cobrem apenas o trabalho futuro (expansão de cobertura de componentes, configuração de deploy Vercel, catálogo de erros por endpoint) — nenhuma delas descreve o que já foi entregue. Este ADR existe para fechar essa lacuna: registrar o que já está em produção, sem inventar aprovação formal que não existiu.

Cenário / objetivo observado

Sequência de pedidos diretos do owner nesta sessão, sem CR prévio:

  1. Uma ferramenta de "documentação viva" a partir de specs + código → escolhido Docusaurus sobre docs/.
  2. Identidade visual RaizFC na doc (logo, cores, tipografia de assets/new_brand/ e docs/03_ux/design_tokens.md, sem reinventar tokens).
  3. Referência de código: TypeDoc para packages/contracts e OpenAPI enriquecido a partir dos DTOs reais.
  4. Visibilidade de componentes de front "tipo Storybook" — tentativa inicial embutida na doc (iframe/MDX), revertida explicitamente pelo owner ("achei que ia ficar dentro da doc como um plugin", depois "pode deixar o storybook como um projeto separado, com um link na doc pra ele, via variável de ambiente").
  5. Promoção do Storybook a app deployável de verdade, separado ("vou deployar em aplicação separada") — o que forçou extrair os componentes de apps/web/apps/mobile para pacotes compartilhados, já que Storybook não pode importar código de dentro de outro app sem violar package_boundaries.md.
  6. Link para a doc oficial no dashboard SDD (tools/sdd-dashboard).

Contexto técnico

  • packages/ui já continha ~30 componentes headless (sem React, ver IS-MVP-17.1/17.2), mas só Button e StatusChip tinham adapter visual real, duplicado dentro de apps/web/src/shared/ui-kit e apps/mobile/src/shared/ui-kit.
  • Não existia pacote de design-system compartilhado entre React DOM e React Native — cada app tinha sua própria cópia do ThemeProvider/ThemeContext.
  • package_boundaries.md (SPEC-ARCH-BOUNDARIES-001) já proibia um app importar arquivo de outro app diretamente, o que tornava impossível o Storybook simplesmente importar apps/web/src/shared/ui-kit sem violar a spec.

Arquivos relevantes

  • packages/ui-web/ e packages/ui-native/ (novos pacotes) — Button, StatusChip, ThemeProvider/ThemeContext extraídos de apps/web e apps/mobile, com persistência própria por plataforma (localStorage no web, expo-secure-store no native).
  • apps/storybook/ (novo app) — Storybook 10 + @storybook/react-vite, consome packages/ui-web via alias de source (não via dist/, para evitar duas instâncias de React.Context).
  • tools/docs-site/ (novo projeto, fora do workspace pnpm, mesmo padrão de tools/sdd-dashboard) — Docusaurus sobre docs/, TypeDoc em /code/contracts, Redocusaurus em /code/api, três links de navbar (Storybook, app em produção, SDD Board) resolvidos por variável de ambiente (STORYBOOK_URL, APP_URL, SDD_BOARD_URL, default localhost).
  • services/api/scripts/generate-openapi.ts (novo) — enriquece o Swagger gerado pelo NestJS com schemas reais de request/response, via parsing de AST TypeScript + ts-json-schema-generator sobre os tipos de @raizfc/contracts (que são type aliases sem presença em runtime, então o @nestjs/swagger sozinho não os alcança).
  • services/api/src/bootstrap.ts — monta Swagger UI em /docs, só fora de produção.
  • tools/sdd-dashboard/app.py — botão/link para a doc oficial (DOCS_URL), na sidebar e na aba Docs.
  • docs/06_architecture/package_boundaries.md e docs/06_architecture/testing_quality_architecture.md — bump 2.0 → 2.1, já formalizam ui-web/ui-native/storybook como tiers do monorepo.
  • scripts/check-workspace-boundaries.mjs — corrigido um bug pré-existente (checagem de DEEP_INTERNAL_IMPORT só reconhecia subpath exports de @raizfc/config, hardcoded) para generalizar e permitir os subpaths novos de ui-web (theme-tokens.css, ui-kit.css).

Comportamento observado

  • A referência de API (tools/docs-site/code/api) hoje mostra schemas reais de request/response para as 225 operações do services/api, mas todo endpoint usa a mesma resposta de erro genérica (default) — não há mapeamento de erro de domínio por rota. É exatamente o gap que CR-API-ERROR-CATALOG-001 propõe fechar.
  • O Storybook publicado cobre 2 de ~30 componentes de packages/ui (Button, StatusChip) — cerca de 3% de cobertura real do design system. É o gap central de CR-COMPONENT-ATOMICITY-001.
  • Web e mobile não compartilham a mesma instância de Storybook ainda — só existe apps/storybook consumindo packages/ui-web (React DOM). Não há integração react-native-web nem @storybook/react-native, apesar do pedido explícito do owner ("web e mobile vão estar no mesmo storybook").
  • As URLs reais de deploy (STORYBOOK_URL, SDD_BOARD_URL, APP_URL) nunca foram configuradas em nenhum ambiente Vercel real — o navbar do docs-site ainda cai nos defaults localhost em qualquer deploy publicado até agora.

Dependências e risco

  • Dois bugs de build só apareceram em produção, depois do merge (branch já estava em master): o build do tools/docs-site na Vercel quebrou porque packages/contracts/dist (gitignored, nunca comitado) nunca era buildado antes de openapi:generate rodar; o build do apps/storybook quebrou pelo mesmo motivo, faltando packages/ui/dist. Ambos corrigidos depois do merge, direto em master, sem passar por PR (commits 4c5c692 e 476c84a). Isso indica que a branch não foi validada contra um checkout limpo equivalente ao da Vercel antes do merge — o CI do monorepo não cobre esses dois builds.
  • package_boundaries.md e testing_quality_architecture.md são specs Approved e foram alteradas (bump de versão) sem passar por Impact Analysis → IS → EP formal antes da implementação — a mudança estrutural já é canônica nas specs, mas o processo que normalmente precede uma mudança de spec Approved não foi seguido aqui.
  • CR-COMPONENT-ATOMICITY-001, CR-VERCEL-DEPLOYS-001 e CR-API-ERROR-CATALOG-001 tiveram human_approval.status: approved (escopo geral) nesta mesma sessão em 2026-08-30, mas ready_gate continua pending nas três — decisões sensíveis reais (fonte de verdade do mapeamento de erros, mecanismo de unificação web/mobile no Storybook, vercel.json vs. documentação de dashboard, acesso público vs. protegido para docs-site/storybook) seguem em aberto e não foram resolvidas pela aprovação de escopo.

Impacto de arquitetura

  • ui-web/ui-native passam a ser um tier formal entre packages/ui (headless) e os apps (web/mobile/storybook), documentado em package_boundaries.md v2.1: nenhum app pode importar componente de outro app diretamente, todos passam pelo adapter compartilhado.
  • apps/storybook é tratado como consumidor read-only de ui/ui-web — sem componente próprio, sem import direto de web/mobile.
  • O boundary-checker (scripts/check-workspace-boundaries.mjs) teve uma correção de escopo mais amplo que o necessário só para este branch: o bug do DEEP_INTERNAL_IMPORT afetava qualquer pacote com subpath exports, não só ui-web — a correção generaliza a checagem para todo o monorepo, não é local a esta mudança.

Itens não resolvidos ou assumidos (inferidos, não formalizados)

  • Não há decisão registrada sobre se este trabalho deveria ter passado por Impact Analysis → IS → EP antes de tocar em specs Approved — não passou, e isso não foi corrigido retroativamente por este ADR (correção de processo, não de código).
  • Não há decisão registrada sobre se os dois bugs de deploy pós-merge deveriam ter bloqueado o merge do PR #88 — não bloquearam; o CI local do monorepo passou porque não simula um checkout limpo sem os dist/ gitignored dos pacotes workspace.
  • Cobertura completa do Storybook, unificação web/mobile numa única instância, e configuração real dos três deploys Vercel ficam para CR-COMPONENT-ATOMICITY-001 e CR-VERCEL-DEPLOYS-001 — ambas aprovadas em escopo, ready_gate pending.

Recomendação

  • Não é necessário reabrir este trabalho como EP formal retroativo — as specs afetadas já foram bumped e o comportamento já está em produção; o valor de formalizar agora seria auditoria/rastreabilidade, não desbloquear algo.
  • Priorizar resolver os pending_decisions de CR-COMPONENT-ATOMICITY-001 e CR-VERCEL-DEPLOYS-001 antes de expandir mais escopo em cima deles.
  • Considerar adicionar ao CI do monorepo uma validação de build "checkout limpo" para tools/docs-site e apps/storybook (os dois dist/ gitignored que já causaram quebra em produção), para não depender de descobrir esse tipo de gap só no deploy real.