chore: import maquina-comercial-pessoal history via subtree

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

git-subtree-dir: maquina-comercial-pessoal
git-subtree-mainline: f5af038e19
git-subtree-split: a9ef4d776d
This commit is contained in:
Gustavo
2026-09-28 15:50:17 -03:00
co-authored by Claude Sonnet 5
150 changed files with 33449 additions and 0 deletions
@@ -0,0 +1,212 @@
# Redesign visual: paleta SaaS dark (app inteiro) Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Trocar a identidade visual inteira do app (login + 4 abas + modais) de uma paleta clara/laranja para uma paleta escura única estilo SaaS (Linear/Vercel), com o card de campanha ganhando um tratamento "Dispatch Board" (borda de status colorida + números tabulares monoespaçados), e o toast passando a indicar sucesso/erro por cor.
**Architecture:** `public/css/app.css` é quase inteiramente orientado por variáveis CSS (`:root`); a troca de paleta é uma substituição do bloco de tokens + remoção do bloco `@media (prefers-color-scheme: dark)` (o app deixa de ter modo claro). Três gradientes hardcoded (parceiros do laranja atual) viram um novo token `--accent-light`. Tratamento "Dispatch Board" é CSS adicional em `.campaign-card` e nos números de estatística. Toast colorido é uma pequena mudança em `public/js/api.js` (inferência pelo prefixo "Erro" na própria mensagem) + 2 classes CSS novas — sem tocar nos ~40 call-sites de `toast(...)` espalhados pelos arquivos JS.
**Tech Stack:** HTML/CSS/JS vanilla (sem framework de build), Node `--test`, Playwright.
## Global Constraints
- Este repositório NÃO tem HEAD/commits e commits não são permitidos neste projeto — nenhuma etapa deste plano inclui `git commit`. Ignore os passos de commit do template padrão de planos.
- Não há testes automatizados de aparência visual. A verificação "passou" de cada tarefa é: (a) suíte existente 100% verde, (b) checagem visual ao vivo no navegador via Claude Browser.
- Servidor de dev roda em `http://127.0.0.1:3910` via `node scripts/servidor.mjs`, já ativo nesta sessão — arquivos estáticos (`public/**`) são servidos direto do disco, um `navigate` com `force: true` já pega mudanças de CSS/JS sem precisar reiniciar o processo Node. Só reiniciar o processo Node se mudar algo em `src/**`.
- Design aprovado está em `docs/superpowers/specs/2026-07-30-dark-saas-redesign-design.md` — os valores exatos de cor vêm de lá, não reinvente.
---
### Task 1: Trocar os tokens de cor em `app.css` para a paleta SaaS dark única
**Files:**
- Modify: `public/css/app.css:1-47` (bloco `:root` e `@media (prefers-color-scheme: dark)`)
- Modify: `public/css/app.css:80` (`.brand-monogram`)
- Modify: `public/css/app.css:189` (`.btn-primary`)
- Modify: `public/css/app.css:520` (`.progress-fill`)
- Modify: `public/css/app.css:587` (`.rank-fill, .funil-fill`)
**Interfaces:**
- Produces: todo o resto do CSS (que já usa `var(--x)` em quase tudo) herda a nova paleta automaticamente. Nenhuma outra tarefa precisa saber os valores exatos — só que os tokens `--page`, `--surface`, `--ink`, `--accent`, `--good`, `--warning`, `--critical`, `--radius*`, `--shadow*` continuam existindo com os mesmos nomes.
- [ ] **Step 1: Substituir o bloco `:root` (linhas 2-26) por estes valores**
```css
:root {
--page: #0b0c10;
--page-2: #0d0e13;
--surface: #16171d;
--surface-2: #1d1f27;
--ink: #f4f4f6;
--ink-2: #a4a6b0;
--muted: #6c6e79;
--grid: #2a2c35;
--border: rgba(255, 255, 255, 0.08);
--accent: #6a63f6;
--accent-light: #9d97ff;
--accent-2: #4f8cff;
--accent-ink: #ffffff;
--bar: #6a63f6;
--good: #22c55e;
--good-text: #4ade80;
--warning: #f5a524;
--critical: #fb5b7c;
--critical-bg: rgba(251, 91, 124, 0.12);
--radius-sm: 8px;
--radius: 12px;
--radius-lg: 16px;
--shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
--shadow-soft: 0 8px 24px rgba(0, 0, 0, 0.3);
}
```
- [ ] **Step 2: Apagar inteiramente o bloco `@media (prefers-color-scheme: dark) { ... }` que vem logo depois (linhas 28-47 do arquivo original)**
O app passa a ter uma única aparência, sempre escura — não há mais um segundo bloco de tokens para modo claro/escuro.
- [ ] **Step 3: Trocar as 3 cores hardcoded que combinavam com o laranja antigo pelo novo `--accent-light`**
Em `.brand-monogram`:
```css
.brand-monogram { background: linear-gradient(135deg, var(--accent), var(--accent-light)); color: #fff; font-weight: 900; letter-spacing: -0.06em; box-shadow: var(--shadow-soft); }
```
Em `.btn-primary`:
```css
.btn-primary { background: linear-gradient(135deg, var(--accent), var(--accent-light)); border-color: transparent; color: var(--accent-ink); }
```
Em `.progress-fill`:
```css
.progress-fill { height: 100%; width: 3%; background: linear-gradient(90deg, var(--accent), var(--accent-light)); border-radius: 999px; transition: width 0.4s; }
```
Em `.rank-fill, .funil-fill`:
```css
.rank-fill, .funil-fill { height: 100%; min-width: 3px; border-radius: 999px; background: linear-gradient(90deg, var(--bar), var(--accent-light)); }
```
- [ ] **Step 4: Rodar a suíte de testes existente para confirmar que nada de lógica quebrou**
Run: `cd "D:/PROJETOS/COMERCIAL GTI/MAQUINA COMERCIAL PESSOAL" && node --test`
Expected: todos os testes continuam passando (a suíte não valida cor/CSS, só comportamento — uma troca de paleta não deveria derrubar nenhum). Preste atenção especial ao teste `interface e arquivos operacionais usam somente a identidade pessoal` (`tests/personal-branding.test.mjs`) — ele lê `public/css/app.css` procurando strings de marca "Grupo GTI"; os valores hex novos não contêm essas strings, então deve continuar passando.
- [ ] **Step 5: Checagem visual ao vivo — página de login**
Usando o Claude Browser: `navigate` para `http://127.0.0.1:3910` com `force: true`, tirar um `read_page`/`get_page_text` e confirmar visualmente (screenshot, se a pane permitir) que o fundo está escuro (`#0b0c10`-ish), o card de login com fundo `#16171d`-ish, texto claro legível, sem nenhum resquício de fundo claro/branco aparecendo.
- [ ] **Step 6: Checagem visual ao vivo — aba Capturar Leads (já vem ativa por padrão) e aba Tratar Leads**
Clicar na aba "Tratar Leads", conferir que os `stat-tiles`, tabela de leads, badges de classificação (excelente/bom/médio/baixo) e gráficos de ranking estão legíveis e com contraste adequado no fundo escuro novo. Não deve haver texto escuro sobre fundo escuro (herança de alguma cor que não passou a usar variável).
Não há commit nesta etapa (projeto sem git commits).
---
### Task 2: Tratamento "Dispatch Board" nos cards de campanha e números de estatística
**Files:**
- Modify: `public/css/app.css` (seção `/* campanhas */`, a partir de `.campaign-cards`)
- Modify: `public/css/app.css:522-525` (`.stat-row .mini b`)
- Modify: `public/css/app.css:562` (`.tile .valor`)
**Interfaces:**
- Consumes: tokens `--muted`, `--critical`, `--good`, `--radius`, `--border` de Task 1.
- Produces: nada que outra tarefa dependa — mudança visual isolada.
- [ ] **Step 1: Adicionar borda de status colorida à esquerda do card de campanha**
Na seção `/* campanhas */` de `app.css`, depois da regra `.campaign-card { margin-bottom: 0; }`, adicionar:
```css
.campaign-card {
border-left: 3px solid var(--muted);
border-radius: var(--radius);
}
.campaign-card:has(.chip.warn) { border-left-color: var(--critical); }
.campaign-card:has(.chip.ok) { border-left-color: var(--good); }
```
(`:has()` funciona nos navegadores modernos — Chrome/Edge 105+, Firefox 121+ — e o card já usa `.chip.warn` para pausada e `.chip.ok` para ativa, ver `public/js/campanhas.js` função `renderCard`, então não precisa mexer no JS.)
- [ ] **Step 2: Números tabulares monoespaçados nos contadores de uso/limite e nas estatísticas**
```css
.campaign-usage span,
.stat-row .mini b,
.tile .valor {
font-variant-numeric: tabular-nums;
font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
}
```
- [ ] **Step 3: Rodar a suíte de testes existente**
Run: `node --test`
Expected: todos os testes continuam passando (mudança é puramente visual/CSS, nenhuma classe foi removida, `.chip.warn`/`.chip.ok` continuam existindo do mesmo jeito).
- [ ] **Step 4: Checagem visual ao vivo — aba Campanhas**
Navegar para a aba Campanhas, conferir visualmente: cada card de campanha tem uma borda colorida na lateral esquerda (cinza-neutro para pronta, vermelha para pausada, verde para ativa/rodando); os números de "Manual: X/Y" e "Automático: X/Y" e o bloco de métricas (Visualizados/Aprovados/Enviados/Responderam, visível clicando "Ver fila" numa campanha) estão em fonte monoespaçada tabular. Confirmar que o texto "Pausado: ..." e os botões continuam legíveis e clicáveis.
Não há commit nesta etapa.
---
### Task 3: Toast colorido por sucesso/erro
**Files:**
- Modify: `public/js/api.js:82-94` (função `toast`)
- Modify: `public/css/app.css:682-696` (`.toast`)
**Interfaces:**
- Consumes: `document.getElementById('toast')` (já existe em `index.html`/`login.html`, id `toast`).
- Produces: `toast(message, ms)` continua com a mesma assinatura pública — nenhum call-site em `app.js`/`tratamento.js`/`captura.js`/`campanhas.js` precisa mudar.
**Por que não tem um teste automatizado nesta tarefa:** `tests/campaign-ui.test.mjs` roda `app.js`/`campanhas.js` dentro de um `vm.createContext` cujo objeto de contexto já define `API`, `el`, `h`, `dataBr`, `fmt` como mocks manuais (não carregados de `api.js`). Se `public/js/api.js` fosse executado nesse mesmo contexto via `vm.runInContext` para testar o `toast()` real, o `const API = {...}` de dentro de `api.js` sombrearia/substituiria o `API` mockado que os outros ~15 testes desse arquivo dependem para interceptar chamadas de rede — quebrando a suíte inteira. Isolar só a função `toast()` do resto de `api.js` exigiria transformar o arquivo num módulo ES (`export`), o que está fora do escopo desta tarefa (o frontend inteiro usa `<script>` simples, sem `import`/`export`). Por isso a verificação aqui é só a checagem visual ao vivo do Step 3, como o próprio spec já previa.
- [ ] **Step 1: Implementar a inferência de tipo em `toast()`**
Em `public/js/api.js`, substituir a função `toast` inteira:
```javascript
function toast(message, ms = 3500) {
const box = el('toast');
box.textContent = message;
box.classList.remove('hidden', 'erro', 'sucesso');
box.classList.add(/^erro/i.test(message) ? 'erro' : 'sucesso');
clearTimeout(toastTimer);
toastTimer = setTimeout(() => box.classList.add('hidden'), ms);
}
```
- [ ] **Step 2: Rodar a suíte inteira, confirmando que a mudança em `api.js` não quebrou nada**
Run: `cd "D:/PROJETOS/COMERCIAL GTI/MAQUINA COMERCIAL PESSOAL" && node --test`
Expected: todos os testes continuam passando — `api.js` não é carregado pelo harness de teste (ver nota acima), então essa mudança não deveria afetar nenhum teste existente; isso só confirma que nada mais no repo depende do comportamento antigo de `toast()`.
- [ ] **Step 3: Estilizar as duas variantes no CSS**
Em `app.css`, na regra `.toast { ... }`, adicionar logo depois:
```css
.toast.sucesso { background: var(--surface-2); color: var(--good-text); border: 1px solid color-mix(in srgb, var(--good) 45%, transparent); }
.toast.erro { background: var(--surface-2); color: var(--critical); border: 1px solid color-mix(in srgb, var(--critical) 45%, transparent); }
```
(A regra base `.toast { background: var(--ink); color: var(--page); }` continua existindo em `app.css` — essas duas classes sobrescrevem `background`/`color` especificamente para os dois estados coloridos; sem `.sucesso`/`.erro`, nunca deve sobrar um toast sem uma das duas, já que `toast()` sempre aplica uma.)
- [ ] **Step 4: Checagem visual ao vivo de um toast de cada tipo**
No navegador (Claude Browser), disparar uma ação que gera um toast de sucesso real (ex.: clicar em "Preparar fila" numa campanha) e conferir visualmente que o toast aparece esverdeado; depois provocar um erro real (ex.: tentar uma ação inválida) e conferir que fica avermelhado. Usar `document.getElementById('toast').className` via `javascript_tool` pra confirmar a classe aplicada sem depender só do visual.
Não há commit nesta etapa.
---
## Verificação final (depois das 3 tarefas)
- [ ] Rodar `node --test` uma última vez — suíte completa 100% verde.
- [ ] Rodar `npx playwright test tests/browser/campaign-pilot.spec.mjs --reporter=line` — 42/42.
- [ ] Passar pelas 4 abas + modal de Configurações no navegador real, conferindo que não sobrou nenhum resquício de fundo/texto claro (herança de alguma regra que não usava variável).
- [ ] Confirmar que as campanhas reais do usuário continuam com o mesmo `status`/`pause_reason` de antes desta sessão (nenhuma ação de estado foi tocada, só CSS/JS de apresentação) — checar via `fetch('/api/campaigns')`.