@unbox-plus/cli 0.20.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +46 -0
- package/README.md +175 -0
- package/bin/cli.js +439 -0
- package/package.json +43 -0
- package/src/colors.js +100 -0
- package/src/presets.js +241 -0
- package/src/theme.js +253 -0
- package/template/.claude/agents/assets-marca.md +40 -0
- package/template/.claude/agents/avaliador-visual.md +48 -0
- package/template/.claude/agents/branding-briefing.md +401 -0
- package/template/.claude/agents/conteudo-secao.md +46 -0
- package/template/.claude/agents/paginas-legais.md +44 -0
- package/template/.claude/settings.json +3 -0
- package/template/.claude/skills/frontend-design/ATTRIBUTION.md +3 -0
- package/template/.claude/skills/frontend-design/LICENSE.txt +177 -0
- package/template/.claude/skills/frontend-design/SKILL.md +55 -0
- package/template/.claude/skills/web-design-guidelines/ATTRIBUTION.md +3 -0
- package/template/.claude/skills/web-design-guidelines/SKILL.md +50 -0
- package/template/.claude/skills/web-design-guidelines/guidelines-snapshot.md +180 -0
- package/template/.env.example +158 -0
- package/template/.mcp.json.example +14 -0
- package/template/.nvmrc +1 -0
- package/template/CLAUDE.md +333 -0
- package/template/COVERAGE.md +80 -0
- package/template/DEPLOY.md +179 -0
- package/template/QA.md +108 -0
- package/template/README.md +152 -0
- package/template/agents/CONSTRUCAO.md +207 -0
- package/template/agents/MANAGER.md +192 -0
- package/template/agents/PADROES.md +255 -0
- package/template/agents/definitions/00-scaffold.md +56 -0
- package/template/agents/definitions/01-layout.md +47 -0
- package/template/agents/definitions/02-homepage.md +70 -0
- package/template/agents/definitions/03-catalog.md +86 -0
- package/template/agents/definitions/04-pdp.md +97 -0
- package/template/agents/definitions/05-cart.md +116 -0
- package/template/agents/definitions/06-checkout.md +146 -0
- package/template/agents/definitions/07-auth.md +130 -0
- package/template/agents/definitions/08-customer.md +55 -0
- package/template/agents/definitions/09-promotions.md +62 -0
- package/template/agents/definitions/10-feedback.md +128 -0
- package/template/agents/definitions/11-seo-infra.md +159 -0
- package/template/agents/definitions/12-deploy.md +173 -0
- package/template/agents/definitions/13-cro.md +275 -0
- package/template/agents/definitions/14-seo.md +388 -0
- package/template/agents/definitions/15-branding.md +26 -0
- package/template/agents/definitions/16-qa-visual.md +138 -0
- package/template/agents/definitions/17-aeo.md +257 -0
- package/template/app/(loja)/busca/page.tsx +72 -0
- package/template/app/(loja)/carrinho/oferta/page.tsx +57 -0
- package/template/app/(loja)/carrinho/page.tsx +160 -0
- package/template/app/(loja)/categoria/[tagSlug]/layout.tsx +31 -0
- package/template/app/(loja)/categoria/[tagSlug]/loading.tsx +17 -0
- package/template/app/(loja)/categoria/[tagSlug]/page.tsx +49 -0
- package/template/app/(loja)/checkout/page.tsx +80 -0
- package/template/app/(loja)/checkout/pix/[ref]/page.tsx +133 -0
- package/template/app/(loja)/conta/assinaturas/[referenceId]/page.tsx +112 -0
- package/template/app/(loja)/conta/assinaturas/page.tsx +51 -0
- package/template/app/(loja)/conta/enderecos/page.tsx +20 -0
- package/template/app/(loja)/conta/entrar/page.tsx +119 -0
- package/template/app/(loja)/conta/page.tsx +45 -0
- package/template/app/(loja)/conta/pedidos/[referenceId]/page.tsx +49 -0
- package/template/app/(loja)/conta/pedidos/page.tsx +104 -0
- package/template/app/(loja)/conta/preferencias/page.tsx +24 -0
- package/template/app/(loja)/devolucoes/page.tsx +36 -0
- package/template/app/(loja)/layout.tsx +22 -0
- package/template/app/(loja)/oferta/page.tsx +57 -0
- package/template/app/(loja)/page.tsx +86 -0
- package/template/app/(loja)/pedido/[referenceId]/page.tsx +78 -0
- package/template/app/(loja)/privacidade/page.tsx +113 -0
- package/template/app/(loja)/produto/[productSlug]/layout.tsx +23 -0
- package/template/app/(loja)/produto/[productSlug]/loading.tsx +20 -0
- package/template/app/(loja)/produto/[productSlug]/page.tsx +372 -0
- package/template/app/(loja)/produtos/loading.tsx +16 -0
- package/template/app/(loja)/produtos/page.tsx +33 -0
- package/template/app/(loja)/termos/page.tsx +104 -0
- package/template/app/acesso/page.tsx +129 -0
- package/template/app/api/account/addresses/route.ts +39 -0
- package/template/app/api/account/exists/route.ts +21 -0
- package/template/app/api/account/me/route.ts +25 -0
- package/template/app/api/account/otp/route.ts +26 -0
- package/template/app/api/account/preferences/route.ts +19 -0
- package/template/app/api/account/signin/route.ts +27 -0
- package/template/app/api/account/signout/route.ts +9 -0
- package/template/app/api/acesso/route.ts +171 -0
- package/template/app/api/capi/route.ts +34 -0
- package/template/app/api/cart/coupon/route.ts +49 -0
- package/template/app/api/cart/items/route.ts +45 -0
- package/template/app/api/cart/link/route.ts +69 -0
- package/template/app/api/cart/route.ts +113 -0
- package/template/app/api/cart/share/route.ts +21 -0
- package/template/app/api/cep/[code]/route.ts +18 -0
- package/template/app/api/checkout/address/route.ts +24 -0
- package/template/app/api/checkout/email/route.ts +41 -0
- package/template/app/api/checkout/installments/route.ts +16 -0
- package/template/app/api/checkout/route.ts +110 -0
- package/template/app/api/checkout/shipping/route.ts +65 -0
- package/template/app/api/checkout-destination/route.ts +31 -0
- package/template/app/api/order/[ref]/route.ts +17 -0
- package/template/app/api/payment-link/route.ts +28 -0
- package/template/app/api/revalidate/route.ts +52 -0
- package/template/app/api/shipping/quote/route.ts +29 -0
- package/template/app/api/subscriptions/[id]/route.ts +52 -0
- package/template/app/api/track/route.ts +28 -0
- package/template/app/api/unbox/catalogo/route.ts +136 -0
- package/template/app/api/unbox/paginas/route.ts +167 -0
- package/template/app/api/unbox/vitrine/route.ts +84 -0
- package/template/app/api/webhooks/unbox/route.ts +97 -0
- package/template/app/apple-icon.svg +5 -0
- package/template/app/error.tsx +15 -0
- package/template/app/globals.css +457 -0
- package/template/app/icon.svg +4 -0
- package/template/app/layout.tsx +90 -0
- package/template/app/llms.txt/route.ts +43 -0
- package/template/app/manifest.ts +21 -0
- package/template/app/not-found.tsx +18 -0
- package/template/app/opengraph-image.tsx +35 -0
- package/template/app/robots.ts +31 -0
- package/template/app/sitemap.ts +42 -0
- package/template/bootstrap.sh +87 -0
- package/template/components/account/account-shell.tsx +47 -0
- package/template/components/account/address-book.tsx +147 -0
- package/template/components/account/preferences-form.tsx +77 -0
- package/template/components/account/reorder-button.tsx +47 -0
- package/template/components/account/signout-button.tsx +20 -0
- package/template/components/account/subscription-actions.tsx +204 -0
- package/template/components/account-nav.tsx +41 -0
- package/template/components/address-fields.tsx +102 -0
- package/template/components/analytics/data-layer-ready.tsx +16 -0
- package/template/components/analytics/purchase-tracker.tsx +32 -0
- package/template/components/brand-search.tsx +34 -0
- package/template/components/cart/cart-provider.tsx +340 -0
- package/template/components/cart/mini-cart.tsx +228 -0
- package/template/components/cart-button.tsx +35 -0
- package/template/components/catalog/catalog-client.tsx +523 -0
- package/template/components/catalog/grid-skeleton.tsx +19 -0
- package/template/components/catalog/pager.tsx +66 -0
- package/template/components/catalog/product-grid-card.tsx +52 -0
- package/template/components/catalog/product-grid.tsx +27 -0
- package/template/components/checkout/checkout-client.tsx +1333 -0
- package/template/components/chrome/announce-bar.tsx +57 -0
- package/template/components/chrome/chrome-recipe.ts +13 -0
- package/template/components/chrome/footers/captura-botao.tsx +28 -0
- package/template/components/chrome/footers/colunas.tsx +110 -0
- package/template/components/chrome/footers/conversao.tsx +90 -0
- package/template/components/chrome/footers/editorial.tsx +98 -0
- package/template/components/chrome/footers/minimal.tsx +55 -0
- package/template/components/chrome/header-bar-mobile.tsx +64 -0
- package/template/components/chrome/headers/centralizado.tsx +71 -0
- package/template/components/chrome/headers/classico.tsx +64 -0
- package/template/components/chrome/headers/compacto.tsx +66 -0
- package/template/components/chrome/headers/equilibrado.tsx +73 -0
- package/template/components/chrome/headers/imersivo.tsx +62 -0
- package/template/components/chrome/registry.ts +70 -0
- package/template/components/chrome/solid-on-scroll.tsx +39 -0
- package/template/components/empty-state.tsx +22 -0
- package/template/components/home/combo-card-compact.tsx +67 -0
- package/template/components/home/combos-home.tsx +64 -0
- package/template/components/home/combos-section.tsx +177 -0
- package/template/components/home/home-recipe.ts +41 -0
- package/template/components/home/sections/attributes-marquee.tsx +178 -0
- package/template/components/home/sections/benefits.tsx +80 -0
- package/template/components/home/sections/bloco-html.tsx +47 -0
- package/template/components/home/sections/catalogo.ts +165 -0
- package/template/components/home/sections/category-pills.tsx +32 -0
- package/template/components/home/sections/combos-carousel.tsx +141 -0
- package/template/components/home/sections/comparison.tsx +73 -0
- package/template/components/home/sections/founder-story.tsx +40 -0
- package/template/components/home/sections/hero.tsx +187 -0
- package/template/components/home/sections/kits.tsx +11 -0
- package/template/components/home/sections/media-cards.tsx +70 -0
- package/template/components/home/sections/newsletter.tsx +62 -0
- package/template/components/home/sections/product-showcase.tsx +175 -0
- package/template/components/home/sections/purchase-hero.tsx +187 -0
- package/template/components/home/sections/quote-banner.tsx +50 -0
- package/template/components/home/sections/registry.ts +186 -0
- package/template/components/home/sections/reviews-carousel.tsx +66 -0
- package/template/components/home/sections/reviews.tsx +68 -0
- package/template/components/home/sections/ritual.tsx +96 -0
- package/template/components/home/sections/savings.tsx +47 -0
- package/template/components/home/sections/social-row.tsx +65 -0
- package/template/components/home/sections/spec-table.tsx +117 -0
- package/template/components/home/sections/stars.tsx +12 -0
- package/template/components/home/sections/stats-grid.tsx +54 -0
- package/template/components/home/sections/trust-bar.tsx +56 -0
- package/template/components/home/sections/trust-strip.tsx +40 -0
- package/template/components/home/sections/video-wall.tsx +59 -0
- package/template/components/landing/landing-recipe.ts +20 -0
- package/template/components/landing/oferta-sections.tsx +40 -0
- package/template/components/landing/product-picker.tsx +257 -0
- package/template/components/mobile-nav.tsx +71 -0
- package/template/components/order-status.tsx +163 -0
- package/template/components/powered-by-unbox.tsx +27 -0
- package/template/components/product/pdp/buy-box.tsx +604 -0
- package/template/components/product/pdp/catalog-grid.tsx +113 -0
- package/template/components/product/pdp/faq-modelo.ts +86 -0
- package/template/components/product/pdp/gallery.tsx +87 -0
- package/template/components/product/pdp/interactive.tsx +200 -0
- package/template/components/product/pdp/newsletter.tsx +64 -0
- package/template/components/product/pdp/payment-chips.tsx +22 -0
- package/template/components/product/pdp/pdp-view.tsx +227 -0
- package/template/components/product/pdp/recommendations.tsx +144 -0
- package/template/components/product/pdp/sections.tsx +173 -0
- package/template/components/quantity-stepper.tsx +36 -0
- package/template/components/search-box.tsx +37 -0
- package/template/components/site-footer.tsx +59 -0
- package/template/components/site-header.tsx +64 -0
- package/template/components/ui/accordion.tsx +72 -0
- package/template/components/ui/alert-dialog.tsx +187 -0
- package/template/components/ui/alert.tsx +76 -0
- package/template/components/ui/aspect-ratio.tsx +22 -0
- package/template/components/ui/avatar.tsx +109 -0
- package/template/components/ui/badge.tsx +52 -0
- package/template/components/ui/breadcrumb.tsx +125 -0
- package/template/components/ui/button.tsx +58 -0
- package/template/components/ui/card.tsx +103 -0
- package/template/components/ui/carousel.tsx +242 -0
- package/template/components/ui/command.tsx +196 -0
- package/template/components/ui/dialog.tsx +160 -0
- package/template/components/ui/dropdown-menu.tsx +268 -0
- package/template/components/ui/foto.tsx +54 -0
- package/template/components/ui/input-group.tsx +158 -0
- package/template/components/ui/input-otp.tsx +87 -0
- package/template/components/ui/input.tsx +20 -0
- package/template/components/ui/label.tsx +20 -0
- package/template/components/ui/navigation-menu.tsx +168 -0
- package/template/components/ui/pagination.tsx +132 -0
- package/template/components/ui/popover.tsx +90 -0
- package/template/components/ui/progress.tsx +83 -0
- package/template/components/ui/radio-group.tsx +38 -0
- package/template/components/ui/scroll-area.tsx +55 -0
- package/template/components/ui/select.tsx +201 -0
- package/template/components/ui/separator.tsx +25 -0
- package/template/components/ui/sheet.tsx +138 -0
- package/template/components/ui/skeleton.tsx +13 -0
- package/template/components/ui/sonner.tsx +44 -0
- package/template/components/ui/switch.tsx +32 -0
- package/template/components/ui/table.tsx +116 -0
- package/template/components/ui/tabs.tsx +82 -0
- package/template/components/ui/textarea.tsx +18 -0
- package/template/components/ui/toggle-group.tsx +89 -0
- package/template/components/ui/toggle.tsx +45 -0
- package/template/components/ui/tooltip.tsx +66 -0
- package/template/components.json +25 -0
- package/template/eslint.config.mjs +36 -0
- package/template/gitignore +21 -0
- package/template/lib/analytics.ts +369 -0
- package/template/lib/api.ts +60 -0
- package/template/lib/capi.ts +87 -0
- package/template/lib/cart-link.ts +51 -0
- package/template/lib/cart-normalize.ts +142 -0
- package/template/lib/cart-recovery.ts +23 -0
- package/template/lib/cart-response.ts +48 -0
- package/template/lib/catalog-map.ts +54 -0
- package/template/lib/catalog.ts +3 -0
- package/template/lib/checkout-lock.ts +21 -0
- package/template/lib/checkout-nav.ts +22 -0
- package/template/lib/config.ts +51 -0
- package/template/lib/crm.ts +40 -0
- package/template/lib/customer-session.ts +21 -0
- package/template/lib/dataloader.ts +23 -0
- package/template/lib/editable/config.ts +11 -0
- package/template/lib/editable/document.ts +1762 -0
- package/template/lib/editable/index.ts +3 -0
- package/template/lib/editable/primitives.tsx +821 -0
- package/template/lib/editable/provider.tsx +861 -0
- package/template/lib/editable/rastreio-navegacao.tsx +65 -0
- package/template/lib/editable/rastreio.tsx +168 -0
- package/template/lib/editable/server.ts +189 -0
- package/template/lib/editable/tokens.ts +22 -0
- package/template/lib/editable/verify.ts +24 -0
- package/template/lib/enrichment/combos.ts +184 -0
- package/template/lib/enrichment/index.ts +188 -0
- package/template/lib/enrichment/products.json +1 -0
- package/template/lib/env-check.ts +47 -0
- package/template/lib/format.ts +130 -0
- package/template/lib/icons.ts +67 -0
- package/template/lib/json-ld.ts +9 -0
- package/template/lib/llms-txt.ts +75 -0
- package/template/lib/mockup.ts +24 -0
- package/template/lib/newsletter.ts +12 -0
- package/template/lib/orders.ts +160 -0
- package/template/lib/queries.ts +66 -0
- package/template/lib/ratelimit.ts +47 -0
- package/template/lib/rotas-editaveis.ts +192 -0
- package/template/lib/sanitize.ts +36 -0
- package/template/lib/schemas.ts +78 -0
- package/template/lib/session.ts +98 -0
- package/template/lib/store-config.ts +67 -0
- package/template/lib/unbox/client.ts +829 -0
- package/template/lib/unbox/customer.ts +224 -0
- package/template/lib/unbox/errors.ts +97 -0
- package/template/lib/unbox/index.ts +10 -0
- package/template/lib/unbox/store.ts +113 -0
- package/template/lib/unbox/types.ts +195 -0
- package/template/lib/unbox/webhooks.ts +66 -0
- package/template/lib/utils.ts +6 -0
- package/template/lib/vitrine.ts +242 -0
- package/template/lib/webhook-store.ts +22 -0
- package/template/middleware.ts +178 -0
- package/template/next.config.ts +63 -0
- package/template/package.json +62 -0
- package/template/postcss.config.mjs +5 -0
- package/template/public/brand/coll/default.png +0 -0
- package/template/public/brand/hero-desktop.svg +12 -0
- package/template/public/brand/hero-mobile.svg +12 -0
- package/template/public/brand/heros/boutique-desktop.svg +11 -0
- package/template/public/brand/heros/boutique-mobile.svg +11 -0
- package/template/public/brand/heros/editorial-desktop.svg +11 -0
- package/template/public/brand/heros/editorial-mobile.svg +11 -0
- package/template/public/brand/heros/essencial-desktop.svg +12 -0
- package/template/public/brand/heros/essencial-mobile.svg +12 -0
- package/template/public/brand/heros/promocional-desktop.svg +12 -0
- package/template/public/brand/heros/promocional-mobile.svg +12 -0
- package/template/public/brand/logo-chrome.svg +6 -0
- package/template/public/brand/logo-white.svg +6 -0
- package/template/public/brand/logo.svg +7 -0
- package/template/public/brand/pay-amex.webp +0 -0
- package/template/public/brand/pay-elo.webp +0 -0
- package/template/public/brand/pay-mastercard.webp +0 -0
- package/template/public/brand/pay-pix.webp +0 -0
- package/template/public/brand/pay-visa.webp +0 -0
- package/template/public/brand/ph/avatar-a.svg +5 -0
- package/template/public/brand/ph/avatar-b.svg +5 -0
- package/template/public/brand/ph/avatar-c.svg +5 -0
- package/template/public/brand/ph/avatar-d.svg +5 -0
- package/template/public/brand/ph/photo-a.svg +7 -0
- package/template/public/brand/ph/photo-b.svg +6 -0
- package/template/public/brand/ph/photo-c.svg +6 -0
- package/template/public/brand/ph/poster-a.svg +6 -0
- package/template/public/brand/ph/poster-b.svg +6 -0
- package/template/public/brand/ph/poster-c.svg +6 -0
- package/template/public/unbox/powered-by-fundo-preto.png +0 -0
- package/template/public/unbox/powered-by-transparente.png +0 -0
- package/template/public/unbox/powered-by.png +0 -0
- package/template/scripts/abandoned-cart.ts +82 -0
- package/template/scripts/check-editable.mjs +467 -0
- package/template/scripts/check-honestidade.mjs +111 -0
- package/template/scripts/check-placeholder.mjs +200 -0
- package/template/scripts/check-recipe.mjs +76 -0
- package/template/scripts/check-unbox-brand.mjs +298 -0
- package/template/scripts/contraste.js +177 -0
- package/template/scripts/dump-catalog.ts +95 -0
- package/template/scripts/load-env.ts +13 -0
- package/template/scripts/medir-sistema.mjs +56 -0
- package/template/scripts/place-order-pix.ts +61 -0
- package/template/scripts/qa-screenshots.mjs +150 -0
- package/template/scripts/sistema.py +231 -0
- package/template/scripts/subscribe-webhook.ts +36 -0
- package/template/scripts/test-live.ts +186 -0
- package/template/scripts/vocabulario.py +264 -0
- package/template/tsconfig.json +27 -0
- package/tools/LEIA-ME.md +39 -0
- package/tools/check-template-neutro.mjs +111 -0
- package/tools/notion-doc.mjs +191 -0
- package/tools/tokenize-neutrals.mjs +0 -0
- package/tools/tokenize-radius.mjs +52 -0
- package/tools/workflow-storefront.legado.js +1207 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# Agente 14 — Unbox AI SEO Agent
|
|
2
|
+
|
|
3
|
+
## Objetivo
|
|
4
|
+
|
|
5
|
+
Otimização avançada de SEO para o storefront headless. Complementa o agente 11 (infraestrutura básica) com schemas ricos, OG images dinâmicas, breadcrumbs, otimização de títulos e Core Web Vitals.
|
|
6
|
+
|
|
7
|
+
**Pré-requisito:** agente 11 concluído — `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation), `sitemap.ts` e `robots.ts` já existem.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Apresentação ao usuário
|
|
12
|
+
|
|
13
|
+
Ao iniciar este agente, exiba o menu abaixo e pergunte quais módulos ativar:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
17
|
+
Unbox AI SEO Agent — Módulos disponíveis
|
|
18
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
19
|
+
|
|
20
|
+
[1] Schemas JSON-LD Avançados
|
|
21
|
+
Organization, WebSite+SearchAction, BreadcrumbList,
|
|
22
|
+
AggregateRating e Review no Product schema
|
|
23
|
+
⚙️ Sem dependências
|
|
24
|
+
|
|
25
|
+
[2] OG Images Dinâmicas
|
|
26
|
+
Imagem Open Graph gerada por produto e categoria
|
|
27
|
+
via Next.js ImageResponse (rota opengraph-image.tsx)
|
|
28
|
+
⚙️ Sem dependências (usa dados já disponíveis no RSC)
|
|
29
|
+
|
|
30
|
+
[3] Breadcrumbs
|
|
31
|
+
Componente visual + BreadcrumbList JSON-LD integrado
|
|
32
|
+
Inserido no PDP e páginas de categoria
|
|
33
|
+
⚙️ Sem dependências
|
|
34
|
+
|
|
35
|
+
[4] Templates de Título e Description
|
|
36
|
+
Templates configuráveis por tipo de página com variáveis
|
|
37
|
+
dinâmicas: {productName}, {categoryName}, {siteName}, {price}
|
|
38
|
+
⚙️ Sem dependências
|
|
39
|
+
|
|
40
|
+
[5] Canonical e Paginação de Catálogo
|
|
41
|
+
Canonical limpo em URLs com query params de filtro/ordem
|
|
42
|
+
rel prev/next (ou canonical único) para paginação
|
|
43
|
+
⚙️ Sem dependências
|
|
44
|
+
|
|
45
|
+
[6] Core Web Vitals
|
|
46
|
+
fetchpriority="high" no LCP image, preconnect hints,
|
|
47
|
+
font-display: swap, lazy loading estratégico
|
|
48
|
+
⚙️ Sem dependências
|
|
49
|
+
|
|
50
|
+
[7] Search Console Setup
|
|
51
|
+
Meta tag de verificação, guia de submissão do sitemap,
|
|
52
|
+
teste de rich results para Product schema
|
|
53
|
+
⚙️ Requer: acesso ao Google Search Console
|
|
54
|
+
|
|
55
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
56
|
+
Opções: "all", números separados por vírgula (ex: 1,3,6), ou "none"
|
|
57
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Aguarde a resposta antes de qualquer implementação.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Módulos — especificação técnica
|
|
65
|
+
|
|
66
|
+
### [1] Schemas JSON-LD Avançados
|
|
67
|
+
|
|
68
|
+
**Arquivo:** `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation) (estender o existente)
|
|
69
|
+
|
|
70
|
+
#### Organization + WebSite (global)
|
|
71
|
+
|
|
72
|
+
**A foundation JÁ emite os dois** em `app/(loja)/page.tsx` (Organization + WebSite/SearchAction).
|
|
73
|
+
ESTENDA esse bloco (sameAs, logo, contactPoint); não crie outro no `app/layout.tsx`: schema
|
|
74
|
+
duplicado é penalizado. O exemplo abaixo mostra o formato completo pra comparar.
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
// Formato de referência: a foundation já tem este bloco em app/(loja)/page.tsx
|
|
78
|
+
const orgSchema = {
|
|
79
|
+
"@context": "https://schema.org",
|
|
80
|
+
"@type": "Organization",
|
|
81
|
+
name: process.env.NEXT_PUBLIC_SITE_NAME,
|
|
82
|
+
url: process.env.NEXT_PUBLIC_SITE_URL,
|
|
83
|
+
logo: `${process.env.NEXT_PUBLIC_SITE_URL}/brand/logo.svg`,
|
|
84
|
+
// TODO: adicionar sameAs com redes sociais da loja
|
|
85
|
+
sameAs: [],
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const websiteSchema = {
|
|
89
|
+
"@context": "https://schema.org",
|
|
90
|
+
"@type": "WebSite",
|
|
91
|
+
name: process.env.NEXT_PUBLIC_SITE_NAME,
|
|
92
|
+
url: process.env.NEXT_PUBLIC_SITE_URL,
|
|
93
|
+
potentialAction: {
|
|
94
|
+
"@type": "SearchAction",
|
|
95
|
+
target: {
|
|
96
|
+
"@type": "EntryPoint",
|
|
97
|
+
urlTemplate: `${process.env.NEXT_PUBLIC_SITE_URL}/busca?q={search_term_string}`,
|
|
98
|
+
},
|
|
99
|
+
"query-input": "required name=search_term_string",
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
SearchAction habilita o **Sitelinks Searchbox** do Google — caixa de busca direta nos resultados.
|
|
105
|
+
|
|
106
|
+
#### AggregateRating no Product JSON-LD
|
|
107
|
+
|
|
108
|
+
Estender o objeto `jsonLd` em `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation):
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
// Adicionar ao objeto de retorno quando reviews existirem
|
|
112
|
+
aggregateRating: reviews?.length ? {
|
|
113
|
+
"@type": "AggregateRating",
|
|
114
|
+
ratingValue: avgRating, // média calculada localmente
|
|
115
|
+
reviewCount: reviews.length,
|
|
116
|
+
bestRating: 5,
|
|
117
|
+
worstRating: 1,
|
|
118
|
+
} : undefined,
|
|
119
|
+
review: reviews?.slice(0, 5).map(r => ({
|
|
120
|
+
"@type": "Review",
|
|
121
|
+
author: { "@type": "Person", name: r.author },
|
|
122
|
+
reviewRating: { "@type": "Rating", ratingValue: r.stars },
|
|
123
|
+
reviewBody: r.comment,
|
|
124
|
+
})),
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Fonte dos reviews:** `lib/enrichment/products.json` (campo `reviews[]`) ou array vazio como fallback.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### [2] OG Images Dinâmicas
|
|
132
|
+
|
|
133
|
+
**Arquivos:**
|
|
134
|
+
- `app/(loja)/produto/[productSlug]/opengraph-image.tsx` — OG image por produto
|
|
135
|
+
- `app/(loja)/categoria/[tagSlug]/opengraph-image.tsx` — OG image por categoria
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
// app/(loja)/produto/[productSlug]/opengraph-image.tsx
|
|
139
|
+
import { ImageResponse } from "next/og"
|
|
140
|
+
|
|
141
|
+
export const runtime = "edge"
|
|
142
|
+
export const size = { width: 1200, height: 630 }
|
|
143
|
+
export const contentType = "image/png"
|
|
144
|
+
|
|
145
|
+
export default async function Image({ params }: { params: { productSlug: string } }) {
|
|
146
|
+
const product = await withStoreClient((c) => c.getProductBySlug(params.productSlug)) // lib/unbox/store.ts
|
|
147
|
+
|
|
148
|
+
return new ImageResponse(
|
|
149
|
+
<div style={{ display: "flex", width: "100%", height: "100%", background: "#18181B" }}>
|
|
150
|
+
{/* Imagem do produto à direita */}
|
|
151
|
+
{product.imageUrls?.[0] && (
|
|
152
|
+
<img src={product.imageUrls[0]} style={{ width: 400, height: 630, objectFit: "cover" }} />
|
|
153
|
+
)}
|
|
154
|
+
{/* Texto à esquerda */}
|
|
155
|
+
<div style={{ flex: 1, padding: "60px 48px", display: "flex", flexDirection: "column", justifyContent: "center" }}>
|
|
156
|
+
<div style={{ color: "#D97706", fontSize: 18, marginBottom: 16 }}>
|
|
157
|
+
{process.env.NEXT_PUBLIC_SITE_NAME}
|
|
158
|
+
</div>
|
|
159
|
+
<div style={{ color: "white", fontSize: 48, fontWeight: 800, lineHeight: 1.1 }}>
|
|
160
|
+
{product.title}
|
|
161
|
+
</div>
|
|
162
|
+
{product.pricing?.[0]?.price && (
|
|
163
|
+
<div style={{ color: "#D97706", fontSize: 36, marginTop: 24 }}>
|
|
164
|
+
R$ {product.pricing[0].price.toFixed(2).replace(".", ",")}
|
|
165
|
+
</div>
|
|
166
|
+
)}
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Runtime:** não force `runtime = "edge"`: `withStoreClient` usa Node (cookies/`server-only`) e `ImageResponse` roda no Node normalmente. `app/opengraph-image.tsx` da foundation é o exemplo.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
### [3] Breadcrumbs
|
|
178
|
+
|
|
179
|
+
**Arquivo:** `components/ui/breadcrumbs.tsx`
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
interface Crumb { label: string; href?: string }
|
|
183
|
+
|
|
184
|
+
export function Breadcrumbs({ items }: { items: Crumb[] }) {
|
|
185
|
+
const jsonLd = {
|
|
186
|
+
"@context": "https://schema.org",
|
|
187
|
+
"@type": "BreadcrumbList",
|
|
188
|
+
itemListElement: items.map((crumb, i) => ({
|
|
189
|
+
"@type": "ListItem",
|
|
190
|
+
position: i + 1,
|
|
191
|
+
name: crumb.label,
|
|
192
|
+
...(crumb.href ? { item: `${process.env.NEXT_PUBLIC_SITE_URL}${crumb.href}` } : {}),
|
|
193
|
+
})),
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<>
|
|
198
|
+
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
|
|
199
|
+
<nav aria-label="Breadcrumb">
|
|
200
|
+
<ol className="flex flex-wrap items-center gap-1 text-sm text-muted-foreground">
|
|
201
|
+
{items.map((crumb, i) => (
|
|
202
|
+
<li key={i} className="flex items-center gap-1">
|
|
203
|
+
{i > 0 && <span aria-hidden>/</span>}
|
|
204
|
+
{crumb.href && i < items.length - 1
|
|
205
|
+
? <a href={crumb.href} className="hover:text-foreground transition-colors">{crumb.label}</a>
|
|
206
|
+
: <span className="text-foreground font-medium">{crumb.label}</span>
|
|
207
|
+
}
|
|
208
|
+
</li>
|
|
209
|
+
))}
|
|
210
|
+
</ol>
|
|
211
|
+
</nav>
|
|
212
|
+
</>
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Inserir no PDP:**
|
|
218
|
+
```tsx
|
|
219
|
+
<Breadcrumbs items={[
|
|
220
|
+
{ label: "Home", href: "/" },
|
|
221
|
+
{ label: category.name, href: `/categoria/${category.slug}` },
|
|
222
|
+
{ label: product.title },
|
|
223
|
+
]} />
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
### [4] Templates de Título e Description
|
|
229
|
+
|
|
230
|
+
**Arquivo:** `lib/seo-templates.ts`
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
// Configurar aqui — usar variáveis entre chaves
|
|
234
|
+
export const SEO_TEMPLATES = {
|
|
235
|
+
product: {
|
|
236
|
+
title: "{productName} | {siteName}",
|
|
237
|
+
description: "Compre {productName} por R${price}. {shortDescription}",
|
|
238
|
+
},
|
|
239
|
+
category: {
|
|
240
|
+
title: "{categoryName} — {siteName}",
|
|
241
|
+
description: "Confira nossa seleção de {categoryName} em {siteName}.",
|
|
242
|
+
},
|
|
243
|
+
home: {
|
|
244
|
+
title: "{siteName} — Loja Oficial",
|
|
245
|
+
description: "Compre em {siteName}: {shortDescription}",
|
|
246
|
+
},
|
|
247
|
+
search: {
|
|
248
|
+
title: 'Resultados para "{query}" | {siteName}',
|
|
249
|
+
description: 'Encontre "{query}" em {siteName}. Filtros por categoria, preço e disponibilidade.',
|
|
250
|
+
},
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ⚠️ Nenhuma promessa comercial no template. Frete grátis só entra interpolado de
|
|
254
|
+
// FREE_SHIPPING_THRESHOLD (lib/store-config.ts) quando não for null; prazo de entrega só se o
|
|
255
|
+
// lojista tiver SLA documentado no DESIGN-<MARCA>.md. O unbox:honestidade derruba
|
|
256
|
+
// "frete grátis acima de R$N" e "entrega rápida" escritos à mão.
|
|
257
|
+
export function fillTemplate(template: string, vars: Record<string, string>): string {
|
|
258
|
+
return Object.entries(vars).reduce(
|
|
259
|
+
(str, [k, v]) => str.replaceAll(`{${k}}`, v),
|
|
260
|
+
template,
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Substituir chamadas hardcoded em `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation) por `fillTemplate(SEO_TEMPLATES.product.title, { ... })`.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
### [5] Canonical e Paginação de Catálogo
|
|
270
|
+
|
|
271
|
+
**Problema:** `/categoria/camisetas?sort=price&page=2` → Google vê URL diferente de `/categoria/camisetas`.
|
|
272
|
+
|
|
273
|
+
**Solução em `buildCategoryMetadata`:**
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
export function buildCategoryMetadata(
|
|
277
|
+
tag: { name: string; displayTitle?: string; description?: string; slug: string },
|
|
278
|
+
page?: number,
|
|
279
|
+
): Metadata {
|
|
280
|
+
const base = `${URL}/categoria/${tag.slug}`
|
|
281
|
+
const canonical = page && page > 1 ? `${base}?page=${page}` : base
|
|
282
|
+
|
|
283
|
+
return {
|
|
284
|
+
title: fillTemplate(SEO_TEMPLATES.category.title, { categoryName: tag.displayTitle ?? tag.name, siteName: SITE }),
|
|
285
|
+
description: tag.description,
|
|
286
|
+
alternates: {
|
|
287
|
+
canonical,
|
|
288
|
+
// rel prev/next para paginação — sinaliza série ao Google
|
|
289
|
+
...(page && page > 1 ? { prev: page === 2 ? base : `${base}?page=${page - 1}` } : {}),
|
|
290
|
+
},
|
|
291
|
+
// Parâmetros de filtro e ordem não devem gerar URLs canônicas distintas
|
|
292
|
+
robots: { index: true, follow: true },
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**robots.txt** — bloquear parâmetros de ordenação/filtro que não mudam conteúdo:
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
disallow: [
|
|
301
|
+
"/conta/", "/checkout", "/pedido/", "/api/", "/busca?",
|
|
302
|
+
"/categoria/*?sort=", // ordenação não cria página nova
|
|
303
|
+
"/categoria/*?filter=", // filtros internos, se houver
|
|
304
|
+
]
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
### [6] Core Web Vitals
|
|
310
|
+
|
|
311
|
+
#### LCP Image — fetchpriority
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
// No hero / primeira imagem do PDP
|
|
315
|
+
// next/image com priority={true} gera automaticamente fetchpriority="high" + preload link
|
|
316
|
+
<Image
|
|
317
|
+
src={product.imageUrls[0]}
|
|
318
|
+
priority={true} // ← crucial para LCP
|
|
319
|
+
sizes="(max-width: 768px) 100vw, 50vw"
|
|
320
|
+
fill
|
|
321
|
+
alt={product.title}
|
|
322
|
+
/>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Garantir que `priority={true}` está em:
|
|
326
|
+
- Hero da home (`components/home/sections/hero.tsx`)
|
|
327
|
+
- Primeira imagem da galeria do PDP (`components/product/pdp/gallery.tsx`)
|
|
328
|
+
- Primeira imagem do catálogo (acima da dobra apenas — produto 1 e 2)
|
|
329
|
+
|
|
330
|
+
#### Preconnect hints em `app/layout.tsx`
|
|
331
|
+
|
|
332
|
+
```tsx
|
|
333
|
+
// No <head> via metadata ou diretamente no layout:
|
|
334
|
+
<link rel="preconnect" href="https://cdn.unbox.com.br" /> // CDN de imagens Unbox
|
|
335
|
+
<link rel="dns-prefetch" href="https://cdn.unbox.com.br" />
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
#### Font display
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
// No next/font (já configurado no layout.tsx) — garantir:
|
|
342
|
+
const plusJakarta = Plus_Jakarta_Sans({
|
|
343
|
+
display: "swap", // evita FOIT — texto invisível durante carregamento
|
|
344
|
+
// ...
|
|
345
|
+
})
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
### [7] Search Console Setup
|
|
351
|
+
|
|
352
|
+
Este módulo não gera código — é um guia de ações manuais:
|
|
353
|
+
|
|
354
|
+
```
|
|
355
|
+
Checklist pós-deploy:
|
|
356
|
+
|
|
357
|
+
□ 1. Acessar https://search.google.com/search-console
|
|
358
|
+
□ 2. Adicionar propriedade (URL prefix) com a URL de produção
|
|
359
|
+
□ 3. Verificar via meta tag:
|
|
360
|
+
→ Copiar conteúdo do atributo "content" fornecido pelo GSC
|
|
361
|
+
→ Adicionar em app/layout.tsx:
|
|
362
|
+
export const metadata = { verification: { google: "CODIGO_AQUI" } }
|
|
363
|
+
□ 4. Fazer deploy e confirmar verificação no GSC
|
|
364
|
+
□ 5. Submeter sitemap: Sitemaps → https://seudominio.com.br/sitemap.xml
|
|
365
|
+
□ 6. Aguardar 3-5 dias e verificar em Enhancements → Shopping (Product rich results)
|
|
366
|
+
□ 7. Testar JSON-LD em: https://search.google.com/test/rich-results
|
|
367
|
+
→ Testar URL de produto → confirmar Product + breadcrumb valid
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Fluxo do agente
|
|
373
|
+
|
|
374
|
+
1. **Apresentar menu** e aguardar escolha.
|
|
375
|
+
2. **Verificar pré-requisito:** confirmar que `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation) existe (agente 11 concluído).
|
|
376
|
+
3. **Implementar** em ordem numérica — cada módulo é independente.
|
|
377
|
+
4. **Para módulos que estendem `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation):** ler o arquivo atual antes de editar.
|
|
378
|
+
5. **Ao final:** listar o que foi implementado e qualquer TODO que exige ação manual (ex: sameAs de redes sociais, código do Search Console).
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Regras
|
|
383
|
+
|
|
384
|
+
- **Nunca duplicar** o que o agente 11 já fez — ler `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation) antes de editar.
|
|
385
|
+
- `<script type="application/ld+json">` deve usar `JSON.stringify()` — nunca template string com interpolação direta (risco de XSS se dados contiverem `</script>`).
|
|
386
|
+
- OG images no Edge Runtime — não usar `import "server-only"` nem APIs Node.js nativas.
|
|
387
|
+
- `priority={true}` apenas na primeira imagem visível — não em todas; múltiplos preloads prejudicam LCP.
|
|
388
|
+
- Templates de título: nunca ultrapassar ~60 caracteres no título e ~155 na description para evitar truncamento no Google.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Agente 15 — Branding & Identidade
|
|
2
|
+
|
|
3
|
+
**Este arquivo é um ponteiro de propósito. Não há definição aqui.**
|
|
4
|
+
|
|
5
|
+
A definição viva do agente 15 é `.claude/agents/branding-briefing.md`, e o
|
|
6
|
+
`.claude/settings.json` a carrega como **system prompt** assim que você abre o Claude Code na
|
|
7
|
+
raiz deste projeto.
|
|
8
|
+
|
|
9
|
+
Ou seja: **se você está numa sessão de briefing, esse texto já está inteiro no seu contexto.**
|
|
10
|
+
Abrir a definição pra "consultar o que o agente deve fazer" relê ~8k tokens do que você já tem.
|
|
11
|
+
|
|
12
|
+
Até a v0.14.3 este arquivo era uma cópia integral daquele prompt — 32 KB duplicados que o
|
|
13
|
+
MANAGER apontava como "a definição", convidando exatamente essa releitura. Virou ponteiro na
|
|
14
|
+
v0.15.0.
|
|
15
|
+
|
|
16
|
+
## Se você quer mesmo ler a definição
|
|
17
|
+
|
|
18
|
+
Casos legítimos: você está numa sessão que **não** é a de briefing (por exemplo, rodando o
|
|
19
|
+
agente 16 de QA e querendo saber o que o 15 prometeu), ou está editando o prompt.
|
|
20
|
+
|
|
21
|
+
.claude/agents/branding-briefing.md
|
|
22
|
+
|
|
23
|
+
## Se você quer saber onde as coisas ficam no projeto
|
|
24
|
+
|
|
25
|
+
Não é aqui. É o `CLAUDE.md` da raiz — o mapa "quero mudar X, mexo em Y". É bem mais barato que
|
|
26
|
+
abrir componentes até achar.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Agente 16 — QA Visual (gate de "pronto")
|
|
2
|
+
|
|
3
|
+
## Escopo
|
|
4
|
+
Transformar o critério de pronto de "o agente achou que terminou" em "**todo frame foi
|
|
5
|
+
visto e avaliado**". Roda depois do briefing/build do agente 15 e depois de CADA rodada de
|
|
6
|
+
feedback (`marca/FEEDBACK-NN.md`). Nada vai pro cliente sem passar aqui.
|
|
7
|
+
|
|
8
|
+
## Dependências
|
|
9
|
+
- `marca/DESIGN-<MARCA>.md` existente (contrato de design do agente 15) — se não existir,
|
|
10
|
+
volte ao 15 e gere antes; avaliar sem contrato é opinião, não QA.
|
|
11
|
+
- Skill `web-design-guidelines` (em `.claude/skills/`) — **invocação obrigatória** na etapa 4.
|
|
12
|
+
|
|
13
|
+
## A regra de ordem: barato reprova antes de caro
|
|
14
|
+
|
|
15
|
+
Screenshot é a etapa mais cara do ciclo, e um defeito pego na etapa 1 invalida todas as
|
|
16
|
+
imagens da etapa 3. Então os gates de texto rodam **primeiro**, sempre, sem exceção. Nunca
|
|
17
|
+
capture tela pra descobrir algo que um comando de dois segundos já diria.
|
|
18
|
+
|
|
19
|
+
## Protocolo
|
|
20
|
+
|
|
21
|
+
### 1. Gates de texto — antes de qualquer imagem
|
|
22
|
+
```bash
|
|
23
|
+
npm run typecheck # o mais barato: erro de tipo derruba o build depois
|
|
24
|
+
npm run unbox:honestidade # promessa comercial sem lastro (detalhe na etapa 2)
|
|
25
|
+
npm run unbox:receita # variedade da receita — mede, não bloqueia
|
|
26
|
+
npm run build # dispara o prebuild de marca (selo + GTM)
|
|
27
|
+
```
|
|
28
|
+
**Não avance com nenhum deles vermelho.** Corrija e rode de novo. Só depois:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm run start # next start, porta 3000
|
|
32
|
+
```
|
|
33
|
+
> ⚠️ Build e dev compartilham `.next`: rodar `npm run build` enquanto o `next dev` serve
|
|
34
|
+
> corrompe os dois. Derrube o dev antes. E painel de preview em aba oculta NÃO rasteriza
|
|
35
|
+
> (screenshot vem em branco): use Chrome headless.
|
|
36
|
+
>
|
|
37
|
+
> ⚠️ Porta de preview: no localhost ela fica DESLIGADA por padrão (só liga em host de
|
|
38
|
+
> preview — *.vercel.app/*.myunbox.com.br), então o QA local não esbarra na tela /acesso.
|
|
39
|
+
> Se os screenshots vierem todos com a "Prévia privada", alguém setou `PREVIEW_FORCE=1`
|
|
40
|
+
> no `.env.local` — remova pra rodar o QA.
|
|
41
|
+
|
|
42
|
+
### 2. Gate de honestidade — contra fabricação SILENCIOSA
|
|
43
|
+
O `unbox:honestidade` da etapa 1 lista prova social/afirmação sem lastro que alguém tenha
|
|
44
|
+
ADICIONADO (vendas fixas, avaliações inventadas, nota estruturada pro Google, selos sem dado,
|
|
45
|
+
prazos não confirmados). A foundation não traz nenhum: num scaffold novo ele sai verde. **Exit
|
|
46
|
+
1 = algo entrou sem dado real e ninguém decidiu.**
|
|
47
|
+
|
|
48
|
+
A regra: **você nunca inventa dado por conta própria, e nada fabricado vai pro ar por
|
|
49
|
+
omissão — mas a loja é do lojista.** Apresente a lista a ele em linguagem simples ("isso
|
|
50
|
+
aqui é número de exemplo, não é real — troco por dado real, tiro, ou você quer manter?").
|
|
51
|
+
O que ele mandar manter é decisão DELE: registre a substring em
|
|
52
|
+
`marca/honestidade-permitido.txt` e anote quem decidiu no `DESIGN-<MARCA>.md`. O que ele
|
|
53
|
+
não decidir: dado real ou estado honesto (convite a avaliar, trust strip verdadeiro).
|
|
54
|
+
|
|
55
|
+
### 3. Screenshots — com orçamento, não à exaustão
|
|
56
|
+
Cobrir "nenhuma região sem frame" numa home de 16 seções em dois viewports passa de 70
|
|
57
|
+
imagens por rodada, e a maioria mostra o que a anterior já mostrou. O que pega defeito é
|
|
58
|
+
**dobra, transição entre seções e os extremos**, não o meio de um bloco.
|
|
59
|
+
|
|
60
|
+
Orçamento por rodada completa — **~20 frames**, desktop 1440 e mobile 390:
|
|
61
|
+
|
|
62
|
+
| Tela | Desktop | Mobile | O que capturar | Quem captura |
|
|
63
|
+
|---|---:|---:|---|---|
|
|
64
|
+
| Home | 4 | 4 | dobra, primeira transição de seção, meio, rodapé | `unbox:qa` |
|
|
65
|
+
| PDP (produto principal) | 2 | 2 | dobra com galeria/preço, bloco de conteúdo enriquecido | `unbox:qa` com `QA_PDP=/produto/<slug>` |
|
|
66
|
+
| PDP (2º produto) | 1 | 1 | só a dobra — confere que não quebra com outro dado | manual (browser) |
|
|
67
|
+
| Catálogo | 1 | 1 | grade (o script captura sem filtro; filtro aplicado é manual) | `unbox:qa` |
|
|
68
|
+
| Carrinho | 1 | 1 | o script captura VAZIO; com item dentro é manual | `unbox:qa` + manual |
|
|
69
|
+
| Checkout | 1 | 1 | primeira tela | `unbox:qa` |
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm run unbox:placeholder # antes de publicar: placeholder no HTML servido
|
|
73
|
+
npm run unbox:qa # home, catálogo, carrinho, checkout (14 frames)
|
|
74
|
+
QA_PDP=/produto/<slug> npm run unbox:qa # + PDP do produto principal (18 frames)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
O que o script não cobre (2º produto, catálogo filtrado, carrinho com item) você captura no
|
|
78
|
+
browser, só na dobra, e só se a rodada for a final.
|
|
79
|
+
|
|
80
|
+
**Nunca capture com `chrome --headless --window-size=390,844`.** No macOS o Chrome trava a
|
|
81
|
+
largura mínima da janela: o PNG sai com 390 de largura — e é por isso que o erro passa
|
|
82
|
+
despercebido — mas a página renderizou a **500**. Medido, nos dois modos headless:
|
|
83
|
+
|
|
84
|
+
--window-size=390,844 → window.innerWidth = 500
|
|
85
|
+
|
|
86
|
+
O "mobile" do QA era o layout de 500px reduzido, e metade da revisão visual de toda loja
|
|
87
|
+
aprovava uma tela que nenhum usuário vê. O `unbox:qa` usa emulação de dispositivo do CDP
|
|
88
|
+
(`Emulation.setDeviceMetricsOverride`), que independe do tamanho da janela, e **confere a
|
|
89
|
+
cada captura que `window.innerWidth` bateu com o pedido** — se divergir, ele avisa e sai
|
|
90
|
+
com erro em vez de entregar frame inválido em silêncio. Sem dependência nova.
|
|
91
|
+
|
|
92
|
+
Precisa de outra rota ou de mais frames numa página? O plano fica no topo de
|
|
93
|
+
`scripts/qa-screenshots.mjs`. Rotas com dado de sessão (PDP de um produto real, carrinho
|
|
94
|
+
com item dentro) pedem captura manual — use o mesmo script como base, nunca `--window-size`.
|
|
95
|
+
|
|
96
|
+
Estoure o orçamento de propósito quando houver motivo declarado: seção nova que ninguém viu
|
|
97
|
+
ainda, defeito que você não consegue localizar, ou pedido explícito do cliente. Orçamento é
|
|
98
|
+
piso de disciplina, não teto burro.
|
|
99
|
+
|
|
100
|
+
### 4. Avalie cada frame contra o contrato — cinco olhares, em paralelo
|
|
101
|
+
São cinco leituras independentes do mesmo material, e nenhuma delas escreve nada. Rodar em
|
|
102
|
+
série, dentro de uma conversa só, é o desperdício mais barato de eliminar do protocolo.
|
|
103
|
+
|
|
104
|
+
Invoque o subagente `avaliador-visual` (em `.claude/agents/`) **uma vez por olhar**, na mesma
|
|
105
|
+
mensagem, para que rodem juntos:
|
|
106
|
+
|
|
107
|
+
| Olhar | Procura |
|
|
108
|
+
|---|---|
|
|
109
|
+
| composição | a dobra conta a história do conceito central? hierarquia, blocos órfãos, ritmo |
|
|
110
|
+
| contraste | texto sobre imagem, tokens `--store-*` respeitados, foco visível |
|
|
111
|
+
| responsivo | nada cortado/estourado no 390, nada "flutuando" no 1440, imagem acima da resolução registrada no inventário (ex.: foto de 432px em full-bleed) |
|
|
112
|
+
| copy | tom de voz e proibições do contrato no texto renderizado (travessão, palavras vetadas) |
|
|
113
|
+
| honestidade | afirmação sem lastro que não está em `marca/honestidade-permitido.txt` |
|
|
114
|
+
|
|
115
|
+
O agente é somente-leitura de propósito: ele devolve achados, **você** corrige. Só quem vê os
|
|
116
|
+
cinco retornos juntos consegue evitar correções que se atropelam.
|
|
117
|
+
|
|
118
|
+
Antes de corrigir, junte os cinco retornos e **descarte o que se repete**: o mesmo defeito
|
|
119
|
+
costuma aparecer em dois olhares com palavras diferentes.
|
|
120
|
+
|
|
121
|
+
A skill `web-design-guidelines` continua de invocação obrigatória — invoque-a você, ao revisar
|
|
122
|
+
os achados, não dentro de cada avaliador (cinco cópias da mesma skill não melhoram nada).
|
|
123
|
+
|
|
124
|
+
### 5. Corrija e reveja — só o que mudou
|
|
125
|
+
Liste os defeitos das etapas 2 e 4 e corrija. Na volta:
|
|
126
|
+
|
|
127
|
+
- **os gates de texto da etapa 1 rodam inteiros de novo** — são baratos e pegam regressão;
|
|
128
|
+
- **as capturas, não.** Recapture as telas que a correção tocou, mais a home (que quase tudo
|
|
129
|
+
afeta). Uma correção de CSS de PDP não pede recaptura de carrinho e checkout.
|
|
130
|
+
|
|
131
|
+
A passada final é a exceção: quando você acredita que acabou, faça **uma** rodada completa do
|
|
132
|
+
orçamento inteiro, do build novo. É essa que autoriza o "tá pronto" e é ela que fica em `qa/`.
|
|
133
|
+
|
|
134
|
+
## Saída esperada
|
|
135
|
+
- `qa/` com os screenshots da passada final completa (desktop + mobile, todas as telas);
|
|
136
|
+
- `npm run typecheck`, `build` e `unbox:honestidade` saindo com ✓;
|
|
137
|
+
- lista do que foi corrigido registrada em `marca/BRIEFING.md` (ou no FEEDBACK-NN da rodada);
|
|
138
|
+
- só então: "tá pronto" pro cliente.
|