wizz-method 1.4.0 → 1.4.1

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.
Files changed (63) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/README.md +1 -1
  3. package/evals/routing/dataset.json +290 -0
  4. package/evals/routing/run-routing-eval.mjs +89 -0
  5. package/package.json +11 -3
  6. package/skills-registry.yaml +65 -28
  7. package/src/modules/wizz/agents/wizz-ads/SKILL.md +1 -1
  8. package/src/modules/wizz/agents/wizz-copy/SKILL.md +1 -1
  9. package/src/modules/wizz/agents/wizz-designer/SKILL.md +6 -8
  10. package/src/modules/wizz/agents/wizz-growth/SKILL.md +1 -1
  11. package/src/modules/wizz/agents/wizz-maestro/SKILL.md +6 -5
  12. package/src/modules/wizz/agents/wizz-memoria/SKILL.md +1 -1
  13. package/src/modules/wizz/agents/wizz-qa/SKILL.md +1 -1
  14. package/src/modules/wizz/agents/wizz-seo/SKILL.md +1 -1
  15. package/src/modules/wizz/agents/wizz-social/SKILL.md +1 -1
  16. package/src/skills-lib/auth-and-secrets/SKILL.md +29 -11
  17. package/src/skills-lib/desktop-security/SKILL.md +35 -4
  18. package/src/skills-lib/premium-landing-ui-researcher/SKILL.md +52 -2083
  19. package/src/skills-lib/premium-landing-ui-researcher/references/audit-protocol.md +124 -0
  20. package/src/skills-lib/premium-landing-ui-researcher/references/component-sources.md +336 -0
  21. package/src/skills-lib/premium-landing-ui-researcher/references/core-goal.md +62 -0
  22. package/src/skills-lib/premium-landing-ui-researcher/references/dashboard-and-portfolio-modes.md +92 -0
  23. package/src/skills-lib/premium-landing-ui-researcher/references/handoffs.md +55 -0
  24. package/src/skills-lib/premium-landing-ui-researcher/references/landing-page-strategy.md +227 -0
  25. package/src/skills-lib/premium-landing-ui-researcher/references/mandatory-process.md +36 -0
  26. package/src/skills-lib/premium-landing-ui-researcher/references/output-format-and-quality.md +129 -0
  27. package/src/skills-lib/premium-landing-ui-researcher/references/prompt-templates.md +206 -0
  28. package/src/skills-lib/premium-landing-ui-researcher/references/site-levels.md +515 -0
  29. package/src/skills-lib/premium-landing-ui-researcher/references/source-first-protocol.md +144 -0
  30. package/src/skills-lib/premium-landing-ui-researcher/references/source-links.md +39 -0
  31. package/src/skills-lib/premium-landing-ui-researcher/references/stack-and-visual-direction.md +118 -0
  32. package/src/skills-lib/taste-skill/SKILL.md +33 -1177
  33. package/src/skills-lib/taste-skill/references/anti-slop-tells.md +110 -0
  34. package/src/skills-lib/taste-skill/references/architecture-conventions.md +39 -0
  35. package/src/skills-lib/taste-skill/references/block-library.md +61 -0
  36. package/src/skills-lib/taste-skill/references/brief-and-dials.md +89 -0
  37. package/src/skills-lib/taste-skill/references/dark-mode.md +23 -0
  38. package/src/skills-lib/taste-skill/references/design-directives.md +191 -0
  39. package/src/skills-lib/taste-skill/references/design-systems.md +267 -0
  40. package/src/skills-lib/taste-skill/references/motion-patterns.md +167 -0
  41. package/src/skills-lib/taste-skill/references/pattern-vocabulary.md +78 -0
  42. package/src/skills-lib/taste-skill/references/performance-a11y.md +33 -0
  43. package/src/skills-lib/taste-skill/references/preflight-checklist.md +73 -0
  44. package/src/skills-lib/taste-skill/references/redesign-protocol.md +52 -0
  45. package/src/skills-lib/web-security/SKILL.md +27 -2
  46. package/src/skills-lib/wizz-router/SKILL.md +21 -246
  47. package/src/skills-lib/wizz-router/references/auditoria-360.md +21 -0
  48. package/src/skills-lib/wizz-router/references/routing-table-flat.md +95 -0
  49. package/src/squads/advisory-board/agents/ray-dalio.md +0 -20
  50. package/tools/hooks/README.md +17 -0
  51. package/tools/hooks/security-defensive-context.js +70 -0
  52. package/tools/hooks/session-rules.js +38 -0
  53. package/tools/hooks/wizz-router-enforce.js +188 -0
  54. package/tools/installer/modules/skills-lib.js +70 -1
  55. package/tools/sync-global.mjs +84 -0
  56. package/.claude/settings.local.json +0 -8
  57. package/src/core-skills/wizz-party-mode/scripts/__pycache__/resolve_party.cpython-314.pyc +0 -0
  58. package/src/skills-lib/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
  59. package/src/skills-lib/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
  60. package/src/skills-lib/ui-ux-pro-max/scripts/__pycache__/search.cpython-314.pyc +0 -0
  61. package/src/skills-lib/ui-ux-pro-max/scripts/graphify-out/cache/0964cef300f753b5cee0cc49777ca97035c85d45c212099405d9ee4da36e523f.json +0 -1
  62. package/src/skills-lib/ui-ux-pro-max/scripts/graphify-out/cache/21a40f6810c3a6f17acc3580f106171daf78c7b41bbd066bc80448a821ea0adf.json +0 -1
  63. package/src/skills-lib/ui-ux-pro-max/scripts/graphify-out/cache/69ea15a020ac81b8459e37ef63654398a50c1035fc01c43d8069df217389f7f3.json +0 -1
@@ -25,14 +25,12 @@ Você é o Designer do Wizz. Cria interfaces e landing pages de alto nível, mos
25
25
 
26
26
  ## Como trabalho (ponte para skills globais)
27
27
 
28
- > **Fonte única (registry) — leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`designer`) vive no `skills-registry.yaml` (resolva em `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml`). Ache o bloco `areas.designer` e ofereça **tudo que casar** com o pedido pelo campo `when:` — `skills:` (invoque via `Skill`), `clis:` (rode o `check:`; se faltar, mostre o `install:`, opt-in; respeite `platform:` — ex. `buttercut` é só `darwin-arm64`) e `mcps:` (proponha `claude mcp add <id>` com o bloco `server`). Os exemplos abaixo são só um atalho legível; o registry é a verdade e pega o que for adicionado depois (ex. tools de vídeo: hyperframes, claude-video, buttercut, voicebox).
29
-
30
- Para cada tarefa, **invoque a skill global certa via a ferramenta `Skill`** e traga o resultado em linguagem fácil:
31
- - Landing page / hero / conversão / 3D → `premium-landing-ui-researcher`
32
- - Design system, paleta, tipografia, componente, review de UI → `ui-ux-pro-max`
33
- - Motion, animação, vídeo, WebGL, Three.js → `motion-3d-director`
34
- - Olhar crítico anti-slop, qualidade de gosto visual → `taste-skill`
35
- - Escolher componentes que combinam com o projeto → `ui-component-curator`
28
+ > **Fonte única (registry) — leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`designer`) vive no `skills-registry.yaml`. Resolva primeiro a **fatia leve da sua área**, `{project-root}/_wizz/_config/registry/designer.yaml` ( vem como o bloco `areas.designer` completo — skills/mcps/clis/references); se faltar (install antigo), caia pro monólito na ordem `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml` e ache o bloco `areas.designer` dentro. Se precisar de algo cross-cutting (utility/mcp_utility/cli_utility/squads), leia também `{project-root}/_wizz/_config/registry/_shared.yaml`. Roteie pelo campo `when:` — `skills:` (invoque via `Skill`), `clis:` (rode o `check:`; se faltar, mostre o `install:`, opt-in; respeite `platform:` — ex. `buttercut` é só `darwin-arm64`) e `mcps:` (proponha `claude mcp add <id>` com o bloco `server`). **Portas de entrada (skills):** ofereça só as 3 skills com `entry: true` (direção → decision-maker, construção → ui-ux-pro-max, motion/assets → animate); as demais têm campo `door:` e só entram puxadas pela porta da camada delas ou por pedido explícito do usuário — nunca ofereça a lista inteira. Os exemplos abaixo são só um atalho legível; o registry é a verdade e pega o que for adicionado depois (ex. tools de vídeo: hyperframes, claude-video, buttercut, voicebox).
29
+
30
+ Para cada tarefa, **entre pela porta certa via a ferramenta `Skill`** e traga o resultado em linguagem fácil:
31
+ - Decidir ANTES de construir (brief, direção visual, caminho de motion/3D) → `decision-maker` (puxa taste-skill, motion-3d-director)
32
+ - Criar/melhorar UI (landing, design system, componente, polish) → `ui-ux-pro-max` (puxa premium-landing-ui-researcher, ui-component-curator, impeccable, taste-redesign, huashu-design, react-components)
33
+ - Executar animação e gerar mídia → `animate` (puxa design-motion-principles, remotion-best-practices, canvas-design, algorithmic-art)
36
34
 
37
35
  Sempre **mostre o visual/plano antes do código**. Construção de código é com o **wizz-dev**.
38
36
 
@@ -20,7 +20,7 @@ Você é o Growth do Wizz. Traz ideias acionáveis de marketing e conversão, pl
20
20
 
21
21
  ## Como trabalho (ponte global)
22
22
 
23
- > **Fonte única (registry) — leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`growth`) vive no `skills-registry.yaml` (resolva em `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml`). Ache o bloco `areas.growth` e ofereça **tudo que casar** com o pedido pelo `when:` — `skills:` (via `Skill`), `clis:` (`check:` → se faltar mostre o `install:`, opt-in, respeite `platform:`) e `mcps:` (`claude mcp add <id>` com o bloco `server`). Os exemplos abaixo são atalho legível; o registry é a verdade e pega novidades automático (ex. MCP `scrapling`).
23
+ > **Fonte única (registry) — leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`growth`) vive no `skills-registry.yaml`. Resolva primeiro a **fatia leve da sua área**, `{project-root}/_wizz/_config/registry/growth.yaml` ( vem como o bloco `areas.growth` completo); se faltar (install antigo), caia pro monólito na ordem `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml` e ache o bloco `areas.growth` dentro. Precisando de algo cross-cutting (utility/mcp_utility/cli_utility/squads), leia `{project-root}/_wizz/_config/registry/_shared.yaml`. Ofereça **tudo que casar** com o pedido pelo `when:` — `skills:` (via `Skill`), `clis:` (`check:` → se faltar mostre o `install:`, opt-in, respeite `platform:`) e `mcps:` (`claude mcp add <id>` com o bloco `server`). Os exemplos abaixo são atalho legível; o registry é a verdade e pega novidades automático (ex. MCP `scrapling`).
24
24
  - Ideias e estratégia de marketing → `marketing-ideas`
25
25
  - Otimizar conversão de página / funil → `page-cro`
26
26
  - Lançamento de produto/feature, go-to-market → `launch-strategy`
@@ -54,15 +54,16 @@ Execute cada item de `{agent.activation_steps_append}`.
54
54
 
55
55
  ### Passo 8 — Carregar o registry e rotear
56
56
 
57
- Carregue o `skills-registry.yaml` (fonte única, a mesma que o installer lê). Resolva o caminho na ordem:
57
+ O `skills-registry.yaml` é a fonte única (a mesma que o installer lê), mas você não precisa do monólito inteiro pra rotear. Carregue em camadas:
58
58
 
59
- 1. `{project-root}/_wizz/_config/skills-registry.yaml`
60
- 2. `{project-root}/_wizz/skills-registry.yaml`
61
- 3. `{project-root}/skills-registry.yaml`
59
+ 1. **Índice leve primeiro:** `{project-root}/_wizz/_config/registry/index.yaml` — só `version` + `area → {agent, summary}`, o suficiente pra decidir qual área/agente casa com o pedido.
60
+ 2. **Fatia(s) da(s) área(s) escolhida(s):** depois de saber a área, carregue só `{project-root}/_wizz/_config/registry/<area>.yaml` (ex. `designer.yaml`, `copy.yaml`) — vem como o bloco `areas.<area>` completo (skills/mcps/clis/references). Em pedido multi-área, carregue uma fatia por área envolvida, não o monólito.
61
+ 3. **Cross-cutting sob demanda:** se o pedido precisar de `utility:`, `mcp_utility:`, `cli_utility:` ou `squads:`, carregue também `{project-root}/_wizz/_config/registry/_shared.yaml`.
62
+ 4. **Fallback (install antigo sem fatias, ou fatia faltando):** caia pro monólito na ordem `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml` e ache o bloco lá dentro.
62
63
 
63
64
  Se o usuário já disse a intenção, **classifique e despache direto** (veja Roteamento). Senão, faça 1 pergunta curta para descobrir a área e então despache.
64
65
 
65
- > Fallback: se nenhum caminho existir, não invente a tabela. Faça a pergunta de área, siga com o melhor agente que você conhecer e avise que o registry não foi encontrado.
66
+ > Fallback final: se nenhum caminho existir (nem fatia, nem monólito), não invente a tabela. Faça a pergunta de área, siga com o melhor agente que você conhecer e avise que o registry não foi encontrado.
66
67
 
67
68
  ## Roteamento (você é o Gerente)
68
69
 
@@ -20,7 +20,7 @@ Você é a Memória do Wizz. Guarda e recupera o contexto do usuário entre sess
20
20
 
21
21
  ## Como trabalho (ponte global)
22
22
 
23
- > **Fonte única (registry) — leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`memoria`) vive no `skills-registry.yaml` (resolva em `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml`). Ache o bloco `areas.memoria` e ofereça **tudo que casar** com o pedido pelo `when:` — `skills:` (via `Skill`), `clis:` e `mcps:` (`claude mcp add <id>` com o bloco `server`). Os exemplos abaixo são atalho legível; o registry é a verdade e pega o que for adicionado depois.
23
+ > **Fonte única (registry) — leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`memoria`) vive no `skills-registry.yaml`. Resolva primeiro a **fatia leve da sua área**, `{project-root}/_wizz/_config/registry/memoria.yaml` ( vem como o bloco `areas.memoria` completo); se faltar (install antigo), caia pro monólito na ordem `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml` e ache o bloco `areas.memoria` dentro. Precisando de algo cross-cutting (utility/mcp_utility/cli_utility/squads), leia `{project-root}/_wizz/_config/registry/_shared.yaml`. Ofereça **tudo que casar** com o pedido pelo `when:` — `skills:` (via `Skill`), `clis:` e `mcps:` (`claude mcp add <id>` com o bloco `server`). Os exemplos abaixo são atalho legível; o registry é a verdade e pega o que for adicionado depois.
24
24
  - Ver estado atual do projeto → `cerebro` (`/ver`)
25
25
  - Salvar a sessão → `cerebro` (`/salvar`)
26
26
  - Registrar uma decisão de arquitetura/produto → `cerebro` (`/decisao`)
@@ -20,7 +20,7 @@ Você é o QA do Wizz. Entra **depois do wizz-dev**: pega o código pronto e ver
20
20
 
21
21
  ## Como trabalho (ponte global)
22
22
 
23
- > **Fonte única (registry) — leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`qa`) vive no `skills-registry.yaml` (resolva em `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml`). Ache o bloco `areas.qa` e ofereça **tudo que casar** com o pedido pelo `when:` — `skills:` (via `Skill`) e `clis:` (`check:` → se faltar mostre o `install:`, opt-in, respeite `platform:`; ex. `agent-browser` p/ verificação de browser — nunca Playwright). Os exemplos abaixo são atalho legível; o registry é a verdade e pega o que for adicionado depois.
23
+ > **Fonte única (registry) — leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`qa`) vive no `skills-registry.yaml`. Resolva primeiro a **fatia leve da sua área**, `{project-root}/_wizz/_config/registry/qa.yaml` ( vem como o bloco `areas.qa` completo); se faltar (install antigo), caia pro monólito na ordem `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml` e ache o bloco `areas.qa` dentro. Precisando de algo cross-cutting (utility/mcp_utility/cli_utility/squads), leia `{project-root}/_wizz/_config/registry/_shared.yaml`. Ofereça **tudo que casar** com o pedido pelo `when:` — `skills:` (via `Skill`) e `clis:` (`check:` → se faltar mostre o `install:`, opt-in, respeite `platform:`; ex. `agent-browser` p/ verificação de browser — nunca Playwright). Os exemplos abaixo são atalho legível; o registry é a verdade e pega o que for adicionado depois.
24
24
  - Rodar a suíte de testes e reportar o que passou/falhou → executo os testes do projeto e resumo.
25
25
  - Gerar testes E2E e rodar fluxos críticos → `e2e-runner` (ou `wizz-qa-generate-e2e-tests`).
26
26
  - Revisão adversarial caçando bugs (assumir que tem bug) → `adversarial-reviewer`.
@@ -20,7 +20,7 @@ Você é o SEO do Wizz. Audita, prioriza e otimiza para Google e para buscas de
20
20
 
21
21
  ## Como trabalho (ponte global)
22
22
 
23
- > **Fonte única (registry) — leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`seo`) vive no `skills-registry.yaml` (resolva em `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml`). Ache o bloco `areas.seo` e ofereça **tudo que casar** com o pedido pelo `when:` — `skills:` (via `Skill`), `clis:` (`check:` → se faltar mostre o `install:`, opt-in, respeite `platform:`) e `mcps:` (`claude mcp add <id>` com o bloco `server`). Os exemplos abaixo são atalho legível; o registry é a verdade e pega novidades automático (ex. `distribb`).
23
+ > **Fonte única (registry) — leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`seo`) vive no `skills-registry.yaml`. Resolva primeiro a **fatia leve da sua área**, `{project-root}/_wizz/_config/registry/seo.yaml` ( vem como o bloco `areas.seo` completo); se faltar (install antigo), caia pro monólito na ordem `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml` e ache o bloco `areas.seo` dentro. Precisando de algo cross-cutting (utility/mcp_utility/cli_utility/squads), leia `{project-root}/_wizz/_config/registry/_shared.yaml`. Ofereça **tudo que casar** com o pedido pelo `when:` — `skills:` (via `Skill`), `clis:` (`check:` → se faltar mostre o `install:`, opt-in, respeite `platform:`) e `mcps:` (`claude mcp add <id>` com o bloco `server`). Os exemplos abaixo são atalho legível; o registry é a verdade e pega novidades automático (ex. `distribb`).
24
24
  - Auditoria, por que não ranqueia, problemas técnicos → `seo-audit`
25
25
  - Aparecer em ChatGPT/Perplexity/AI Overviews → `ai-seo`
26
26
  - Dados estruturados / rich results → `schema-markup`
@@ -43,7 +43,7 @@ Opcionais (quando o tema pedir): **Novidade** (recém lançado? define Fórmula
43
43
 
44
44
  ## Como trabalho (ponte global)
45
45
 
46
- > **Fonte única (registry) · leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`social`) vive no `skills-registry.yaml` (resolva em `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml`). Ache o bloco `areas.social` e ofereça **tudo que casar** com o pedido pelo `when:`. `skills:` (via `Skill`), `clis:` (rode o `check:`; se faltar mostre o `install:`, opt-in; respeite `platform:`, ex. `buttercut` é só `darwin-arm64`) e `mcps:`. Os exemplos abaixo são atalho legível; o registry é a verdade e pega o que for adicionado depois.
46
+ > **Fonte única (registry) · leia SEMPRE antes dos exemplos abaixo:** a lista real da sua área (`social`) vive no `skills-registry.yaml`. Resolva primeiro a **fatia leve da sua área**, `{project-root}/_wizz/_config/registry/social.yaml` ( vem como o bloco `areas.social` completo); se faltar (install antigo), caia pro monólito na ordem `{project-root}/_wizz/_config/skills-registry.yaml` → `{project-root}/_wizz/skills-registry.yaml` → `{project-root}/skills-registry.yaml` e ache o bloco `areas.social` dentro. Ofereça **tudo que casar** com o pedido pelo `when:`. `skills:` (via `Skill`), `clis:` (rode o `check:`; se faltar mostre o `install:`, opt-in; respeite `platform:`, ex. `buttercut` é só `darwin-arm64`) e `mcps:`. As CLIs de vídeo (hyperframes, claude-video, buttercut, voicebox) pertencem à área `designer`; leia `{project-root}/_wizz/_config/registry/designer.yaml` (ou `_shared.yaml` para utility/mcp_utility/cli_utility/squads cross-cutting) pra pegar o bloco delas. Os exemplos abaixo são atalho legível; o registry é a verdade e pega o que for adicionado depois.
47
47
 
48
48
  Roteiro e conteúdo (você mesmo, com o blueprint + skills):
49
49
  - Roteiro viral de Reel/Short, qualquer formato (hook, corpo, CTA) → aplique o blueprint (Seções 1-11; Seção 12 para o formato 3D-personagem).
@@ -13,18 +13,18 @@ description: >
13
13
 
14
14
  ### Senhas
15
15
  - Hash com bcrypt (custo >= 12), Argon2id ou scrypt. Nunca MD5/SHA1 para senhas
16
- - Minimum 8 caracteres, sem restrição de caracteres especiais
16
+ - Mínimo de 8 caracteres, sem restrição de caracteres especiais
17
17
  - Implemente bloqueio após N tentativas (lockout ou CAPTCHA)
18
- - Oferece 2FA: TOTP (Google Authenticator) é o padrão mínimo
18
+ - Ofereça 2FA: TOTP (Google Authenticator) é o padrão mínimo
19
19
 
20
20
  ### JWT
21
- - Assine sempre com RS256 (assimétrico) em produção, nunca HS256 com secret fraco
21
+ - Na verificação, aceite o algoritmo esperado: rejeite `alg: none` e não deixe o token escolher o algoritmo (ataque de confusão de algoritmo)
22
+ - Prefira RS256 (assimétrico) quando mais de um serviço verifica o token. HS256 só com secret forte: 32+ bytes aleatórios, nunca uma palavra
22
23
  - exp curto para access token (15 min a 1h)
23
24
  - Refresh token com rotação: ao usar, invalide o anterior e emita novo
24
25
  - Nunca coloque dados sensíveis no payload (é base64, não criptografia)
25
- - Blacklist de tokens invalidados: Redis com TTL igual ao exp do token
26
26
  - **Token no header `Authorization: Bearer`, NUNCA na URL/query string** (a URL vaza em logs de servidor, histórico do browser, header `Referer` e analytics)
27
- - **Logout de verdade revoga o token**: coloque na blacklist (Redis, TTL = exp) e invalide o refresh token. Sem isso o access token continua válido depois do logout até expirar sozinho
27
+ - **Logout de verdade revoga o token**: coloque na blacklist (Redis, TTL = exp do token) e invalide o refresh token. Sem isso o access token continua válido depois do logout até expirar sozinho
28
28
 
29
29
  ### Enumeração de usuário
30
30
  Evita que um atacante descubra quais e-mails existem na base (login, signup, reset de senha).
@@ -40,9 +40,10 @@ Evita que um atacante descubra quais e-mails existem na base (login, signup, res
40
40
 
41
41
  ### Stack Supabase + Clerk
42
42
  - Auth gerenciada pelo Clerk: nunca reimplementar flows de auth manualmente
43
- - Clerk webhook (`svix`) verificado por assinatura antes de processar não confiar no body sem verificar
43
+ - Toda rota protegida, Server Action e route handler chama `auth()` do Clerk no servidor. Nunca confiar em estado de sessão vindo do cliente
44
+ - Clerk webhook (`svix`) verificado por assinatura antes de processar: não confiar no body sem verificar
44
45
  - Supabase RLS: toda tabela de domínio deve ter RLS ativo; queries devem filtrar por `workspace_id`/`user_id`
45
- - `SUPABASE_SERVICE_ROLE_KEY` só usada em server-side (API routes, never client), nunca exposta no frontend
46
+ - `SUPABASE_SERVICE_ROLE_KEY` bypassa RLS: só em server-side (API routes, jobs), nunca exposta no frontend
46
47
  - `NEXT_PUBLIC_*` = seguro expor no cliente; tudo sem `NEXT_PUBLIC_` = server-only
47
48
 
48
49
  ## Secrets e credenciais
@@ -56,19 +57,36 @@ Evita que um atacante descubra quais e-mails existem na base (login, signup, res
56
57
  ### Onde guardar secrets
57
58
  - Produção: variáveis de ambiente da plataforma (Vercel: `vercel env add`)
58
59
  - CI/CD: variáveis de ambiente criptografadas da plataforma (GitHub Actions Secrets, etc.)
59
- - Dev local: arquivo `.env.local` nunca commitado verificar com `git check-ignore -v .env.local`
60
+ - Dev local: arquivo `.env.local` nunca commitado. Verificar com `git check-ignore -v .env.local`
61
+
62
+ ### API keys emitidas pelo próprio app
63
+ Se o app gera API keys para os usuários:
64
+ - Guarde só o hash (SHA-256) da key no banco, nunca a key em texto plano
65
+ - Mostre a key completa uma única vez, na criação
66
+ - Use prefixo identificável (ex: `wz_live_`) para facilitar detecção em scan de repositório
67
+ - Permita revogar e listar keys por usuário
60
68
 
61
69
  ### Cripto de credenciais de usuário (AES-256-GCM)
62
70
  Se o app armazena credenciais de terceiros do usuário (ex: SMTP, WhatsApp API):
63
71
  ```ts
64
- // src/lib/crypto.ts ler chave do env, nunca hardcodar
65
- const key = process.env.CREDENTIAL_ENCRYPTION_KEY
72
+ // src/lib/crypto.ts: chave vem do env, nunca hardcodada
73
+ import { createCipheriv, randomBytes } from "crypto"
74
+
75
+ const key = process.env.CREDENTIAL_ENCRYPTION_KEY // base64, 32 bytes
66
76
  if (!key) throw new Error("CREDENTIAL_ENCRYPTION_KEY não configurada")
67
- // AES-256-GCM: chave base64 de 32 bytes
77
+
78
+ export function encrypt(plain: string) {
79
+ const iv = randomBytes(12) // IV aleatório por registro, nunca reutilizar
80
+ const cipher = createCipheriv("aes-256-gcm", Buffer.from(key, "base64"), iv)
81
+ const enc = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()])
82
+ return { iv: iv.toString("base64"), data: enc.toString("base64"), tag: cipher.getAuthTag().toString("base64") }
83
+ }
84
+ // no decrypt: setAuthTag antes de final(), senão a integridade não é verificada
68
85
  ```
69
86
 
70
87
  ### Rotação de credenciais
71
88
  - Rotacione secrets de terceiros a cada 90 dias ou após qualquer saída de membro do time
89
+ - Secret commitado por acidente: considere comprometido e rotacione na hora. Reescrever o histórico do git não basta
72
90
  - API keys de produção: uma por serviço/ambiente, nunca compartilhadas
73
91
  - Database passwords: use IAM auth quando disponível no cloud provider
74
92
 
@@ -15,11 +15,32 @@ description: >
15
15
  - contextIsolation: true (obrigatório)
16
16
  - sandbox: true quando possível
17
17
  - webSecurity: false nunca em produção
18
+ - Nunca carregue conteúdo remoto numa janela com acesso a APIs privilegiadas; conteúdo remoto = sandbox + sem preload sensível
19
+ - Mantenha o Electron atualizado (patches de Chromium/Node chegam por release do Electron)
20
+
21
+ ### Navegação e janelas
22
+ - Bloqueie navegação para fora do app: handler em `will-navigate` que cancela URLs fora da allowlist
23
+ - `setWindowOpenHandler`: negue por padrão (`{ action: "deny" }`), abra externo só o que for aprovado
24
+ - `shell.openExternal` só com URL validada (esquema `https:` e host esperado), nunca com input cru do renderer
18
25
 
19
26
  ### IPC (comunicação renderer <> main)
20
- - Valide e sanitize todos os dados vindos do renderer
21
- - Exponha apenas as funções necessárias via contextBridge
27
+ - Valide e sanitize todos os dados vindos do renderer (o renderer é território hostil: trate como input de usuário)
28
+ - Exponha apenas as funções necessárias via contextBridge, cada uma com assinatura fixa
22
29
  - Nunca exponha ipcRenderer diretamente ao renderer
30
+ - Em `ipcMain.handle`, valide tipo e tamanho dos argumentos; se houver múltiplas janelas, cheque `event.senderFrame.url` contra o esperado
31
+
32
+ ```ts
33
+ // preload.ts: superfície mínima, sem repassar ipcRenderer
34
+ contextBridge.exposeInMainWorld("api", {
35
+ saveNote: (text: string) => ipcRenderer.invoke("notes:save", text),
36
+ })
37
+
38
+ // main.ts: valida antes de agir
39
+ ipcMain.handle("notes:save", (event, text) => {
40
+ if (typeof text !== "string" || text.length > 10_000) throw new Error("input inválido")
41
+ // ...
42
+ })
43
+ ```
23
44
 
24
45
  ### Atualizações automáticas
25
46
  - Assine o pacote de atualização com certificado de código (code signing)
@@ -29,8 +50,9 @@ description: >
29
50
  ## Armazenamento local
30
51
 
31
52
  ### O que armazenar localmente
32
- - Tokens de sessão: keychain do OS (electron-keytar), nunca localStorage
33
- - Dados do usuário: criptografados com chave derivada da senha do OS
53
+ - Tokens de sessão: `safeStorage` do Electron (usa Keychain no macOS, DPAPI no Windows, libsecret no Linux), nunca localStorage
54
+ - `safeStorage.encryptString(token)` antes de gravar em disco; `keytar` está arquivado, não use em projeto novo
55
+ - Dados sensíveis do usuário: criptografados via `safeStorage` ou AES-256-GCM com chave guardada no keychain do OS
34
56
 
35
57
  ### O que nunca armazenar localmente
36
58
  - Senhas em texto plano
@@ -41,3 +63,12 @@ description: >
41
63
  - Code signing obrigatório (Windows: Authenticode, macOS: Apple Developer ID)
42
64
  - Notarização no macOS para distribuição fora da App Store
43
65
  - Auto-update com verificação de integridade antes de executar
66
+
67
+ ## Checklist rápido (antes de empacotar)
68
+ - [ ] `contextIsolation: true`, `nodeIntegration: false`, `sandbox: true` onde possível?
69
+ - [ ] Nenhuma janela privilegiada carrega URL remota?
70
+ - [ ] `will-navigate` e `setWindowOpenHandler` restringem navegação?
71
+ - [ ] Todo handler de `ipcMain` valida os argumentos?
72
+ - [ ] Tokens em `safeStorage`/keychain, nada sensível em localStorage?
73
+ - [ ] Build assinado (e notarizado no macOS)? Auto-update valida assinatura?
74
+ - [ ] Versão do Electron atual (sem CVE aberta)?