# PROGRESS.md — Histórico e Estado Atual do VentoApp

> **Arquivo de continuidade.** Este documento é o ponto de partida quando você
> retomar o trabalho em um novo terminal/sessão. Ele contém:
> 1. Estado exato em que o projeto está HOJE
> 2. Tudo o que foi entregue (com paths)
> 3. Comandos para validar o estado
> 4. Roadmap priorizado das próximas melhorias
> 5. Convenções estabelecidas que devem ser mantidas

---

## 📊 Estado atual

| Item | Valor |
|------|-------|
| Data da última atualização | 2026-07-07 |
| Marcos concluídos | **8 / 8** (plano completo) + M9.1 ✅ + M9.2 ✅ + M9.3 ✅ + M9.4 ✅ + M9.5 ✅ + M9.6 ✅ + M9.7 ✅ + M9.8 ✅ + M9.9 ✅ + M9.10 ✅ + M9.13 ✅ |
| Cobertura NBR 6123:2023 | **100% das 11 seções + 3 anexos** |
| Linhas de código TS/TSX | ~7.400 |
| Arquivos `.ts`/`.tsx` no `src/` | **110** |
| Páginas (rotas) | **10** |
| Módulos Strategy | **7** |
| Tabelas da norma implementadas | **36 / 36** + 3 anexos (auditadas M9.1) |
| Testes Vitest | **310 passando / 310 totais** |
| Build de produção | ✅ passa (2645 módulos) |
| Lint (oxlint) | ✅ 0 erros |
| Persistência local | ✅ IndexedDB (Dexie-style) |
| Tema dark/light | ✅ ThemeProvider com 3 modos |

---

## ✅ O que foi entregue (Marcos 1–8)

### Marco 1 — Motor matemático refatorado
**Status:** ✅ Concluído
**Entregas:**
- `app/src/lib/nbr-tables/table-1.ts` — Parâmetros meteorológicos (b, p, Fᵣ)
- `app/src/lib/nbr-tables/table-2.ts` — Fator de rajada
- `app/src/lib/nbr-tables/table-3.ts` — Fator S₂ (interpolação log-linear)
- `app/src/lib/nbr-tables/table-4.ts` — Fator S₃ mínimo (5 grupos)
- `app/src/lib/nbr-tables/table-5.ts` — z_g e z₀ por categoria
- `app/src/lib/nbr-tables/table-a.ts` — S₂ normalizado (Anexo A)
- `app/src/lib/nbr-tables/table-b.ts` — S₃ por Pₘ e vida útil (Anexo B)
- `app/src/lib/bilinear-interp.ts` — Interpolação bilinear (sec. 3.2)
- `app/src/lib/log-interp.ts` — Interpolação log-linear + linear
- `app/src/lib/wind-direction.ts` — Mudança de rugosidade (sec. 5.5)
- `app/src/lib/wind-kernel.ts` — Refatorado para consumir tabelas

### Marco 2 — Pressão interna + Vizinhança
**Status:** ✅ Concluído
**Entregas:**
- `app/src/lib/internal-pressure.ts` — Cpi simplificado (6.3.2) + detalhado (6.3.3)
- `app/src/lib/neighborhood.ts` — Fator fᵥ (sec. 6.4)
- `app/src/lib/nbr-tables/stations.ts` — 49 estações Anexo C
- `app/src/lib/stations-lookup.ts` — Busca por nome/IBGE
- `app/src/store/galpaoStore.ts` — Adicionado Cpi, ratio, permeabilityCase
- UI Galpão: 4 abas (Geometria / NBR / Cpi / Local)

### Marco 3 — Edificações paralelepipédicas completas
**Status:** ✅ Concluído
**Entregas:**
- `app/src/lib/nbr-tables/table-6.ts` — Cpe paredes (A, B, C, D)
- `app/src/lib/nbr-tables/table-7.ts` — Cpe telhados duas águas (E–J)
- `app/src/lib/nbr-tables/table-8.ts` — Cpe telhados uma água
- `app/src/lib/nbr-tables/table-9.ts` — Cpe telhados duas águas com calha
- `app/src/lib/nbr-tables/table-10.ts` — Cpe telhados múltiplos simétricos
- `app/src/lib/nbr-tables/table-11.ts` — Cpe telhados múltiplos assimétricos
- `app/src/lib/nbr-tables/table-12.ts` — Cpe telhados com água vertical
- `app/src/lib/coefficients.ts` — Interface unificada
- `app/src/lib/excentricity.ts` — Sec. 6.1.4 (eₐ, e_b)
- `app/src/lib/friction.ts` — Sec. 6.1.5 (força de atrito)
- `app/src/lib/drag.ts` — Ca baixa/alta turbulência (Figs 4-5) + requisitos
- `app/src/components/Warehouse3D.tsx` — Refeito com zonas A-J coloridas independentemente

### Marco 4 — Superfícies curvas
**Status:** ✅ Concluído
**Entregas:**
- `app/src/lib/nbr-tables/table-13.ts` — Cpe cilindros (Re + h/d + ângulo)
- `app/src/lib/nbr-tables/table-14.ts` — Ca seção constante (15+ seções)
- `app/src/lib/nbr-tables/table-15-17.ts` — Abóbadas (baixa turbulência)
- `app/src/lib/nbr-tables/table-18-20.ts` — Abóbadas (séries 51, 52)
- `app/src/lib/nbr-tables/table-21.ts` — Cúpulas sobre terreno
- `app/src/lib/nbr-tables/table-22.ts` — Cúpulas sobre parede cilíndrica
- `app/src/lib/modules/cylinder.ts`, `vault.ts`, `dome.ts` — Strategy
- `app/src/components/three/Cylinder3D.tsx`, `Vault3D.tsx`, `Dome3D.tsx`
- `app/src/pages/CylinderModule.tsx`, `VaultModule.tsx`, `DomeModule.tsx`

### Marco 5 — Muros, placas, coberturas isoladas, barras
**Status:** ✅ Concluído
**Entregas:**
- `app/src/lib/nbr-tables/table-23.ts` — Cf muros/placas
- `app/src/lib/nbr-tables/table-24-25.ts` — Coberturas isoladas (uma e duas águas)
- `app/src/lib/nbr-tables/table-26.ts` — Cx, Cy barras faces planas
- `app/src/lib/nbr-tables/table-27.ts` — Ca barras circulares (Re + regime)
- `app/src/lib/nbr-tables/table-28.ts` (via table-26/27) — Fator K
- `app/src/lib/nbr-tables/table-29.ts` — Cf fios/cabos
- `app/src/lib/nbr-tables/table-30.ts` — Componentes em faces de torre
- `app/src/lib/modules/truss.ts` — Reticulados isolados/múltiplos
- `app/src/pages/SignModule.tsx`, `IsolatedRoofModule.tsx`, `BarSelectorModule.tsx`

### Marco 6 — Torres + Pontes
**Status:** ✅ Concluído
**Entregas:**
- `app/src/lib/modules/tower.ts` — Torres quadradas e triangulares
- `app/src/lib/modules/bridge.ts` — Pse, Cx/Cz, flutter, galope
- `app/src/lib/nbr-tables/table-35.ts` — Parâmetros b, p para pontes + amortecimento (Tab. 36)
- `app/src/pages/BridgeModule.tsx`

### Marco 7 — Dinâmica + Vórtices + Conforto
**Status:** ✅ Concluído
**Entregas:**
- `app/src/lib/nbr-tables/table-31.ts` — Parâmetros dinâmicos (γ, ξ)
- `app/src/lib/nbr-tables/table-32.ts` — Expoente p, bₘ dinâmicos + Vp, ζ
- `app/src/lib/nbr-tables/table-33.ts` — Strouhal (St) + Scruton + Vcr
- `app/src/lib/comfort.ts` — a_lim ISO 10137
- `app/src/lib/modules/dynamics.ts` — Re-export consolidado
- `app/src/pages/DynamicsModule.tsx` — 3 abas (Edifício / Vórtices / Conforto)

### Marco 8 — UX, dados, testes
**Status:** ✅ Concluído
**Entregas:**
- `app/src/lib/storage.ts` — Persistência IndexedDB (CRUD de projetos)
- `app/src/lib/hooks/useProjects.ts` — Hook React para projetos
- `app/src/lib/theme.tsx` — ThemeProvider (light/dark/system)
- `app/src/lib/i18n.ts` — Strings pt-BR/en-US
- `app/src/pages/SettingsModule.tsx` — Tema + projetos + estado
- `app/vitest.config.ts` — Configuração Vitest
- `app/src/lib/__tests__/` — 5 suites de testes (38 testes)
- `app/index.html` — Atualizado (lang, title, description)
- `app/README.md` — Documentação completa
- `AGENTS.md` — Guia para IAs continuarem

### Marco 9.2 — Cargas lineares (kN/m) para software estrutural
**Status:** ✅ Concluído (2026-07-07)
**Escopo:** Converter pressões (kN/m²) em cargas distribuídas lineares (kN/m)
para software como Ftool, SAP2000, Eberick, TQS.
**Entregas:**
- `app/src/lib/line-loads.ts` — 8 funções:
  - `getWindLoadOnRoof(cpe, cpi, q, s, θ)` → kN/m em terça (com cos θ)
  - `getWindLoadOnColumn(cpe, cpi, q, spacing)` → kN/m em pilar
  - `getPillarBaseReaction(w, h)` → V_base [kN]
  - `getPillarBaseMoment(w, h)` → M_base [kN·m]
  - `getColumnLinearLoads(...)` → cargas nos 4 pilares (vento 0°/90°)
  - `getRoofLinearLoads(...)` → cargas nas terças por zona E/F/G/H/I/J
  - `getAllPillarBaseReactions(...)` → reações nos 4 pilares
  - `getDragForce(...)` → força de arrasto total + Cₐ efetivo
- `app/src/components/LinearLoadsTable.tsx` — Painel interativo com 3 abas
  (Pilares / Terças / Reações) + inputs para espaçamento de pórticos/terças.
- `app/src/lib/export-pdf.tsx` — Nova seção 5 no PDF com 3 sub-tabelas.
- `app/src/lib/export-csv.ts` — Novas seções no CSV.
- `app/src/pages/GalpaoModule.tsx` — Layout 3 colunas: controles / 3D / cargas.
- **Suite de testes nova:** `app/src/lib/__tests__/line-loads.test.ts` (27 testes).
- **Total:** 110/110 testes passando (era 83/83).

**Convenção de sinal:**
- `+` = empuxo (pressão empurrando para dentro da estrutura)
- `−` = sucção (puxando para fora)

### Marco 9.3 — Captura 3D no PDF (screenshot da cena)
**Status:** ✅ Concluído (2026-07-07)
**Escopo:** Capturar screenshot do canvas R3F e embutir automaticamente na
memória de cálculo em PDF.
**Entregas:**
- `app/src/lib/canvas-capture.ts` — Utilitários determinísticos:
  - `canvasToDataURL(canvas, format, quality)` → data URL
  - `captureCanvasImage(canvas, options)` → captura + redimensionamento
  - `downloadImage(dataUrl, filename)` → download direto
  - `estimateDataUrlSizeKB(dataUrl)` → estimativa de tamanho
  - `dataURLtoBlob(dataUrl)` → conversão para Blob
- `app/src/store/captureStore.ts` — Zustand store para registro e captura:
  - `registerCanvas(canvas)` / `unregisterCanvas()`
  - `capture()` assíncrono com await
  - Configuração: targetWidth, format (png/jpeg), jpegQuality
- `app/src/components/SceneCapturePanel.tsx` — Painel UI no estilo GalpaoModule:
  - Select para formato, Slider para largura/qualidade
  - Botão "Capturar cena atual" com estado de loading
  - Preview com badge de tamanho + timestamp
  - Botões Baixar/Limpar
- 4 viewers 3D registrados (Warehouse3D, Cylinder3D, Vault3D, Dome3D):
  - Adicionado `gl={{ preserveDrawingBuffer: true, antialias: true }}`
  - `onCreated={({ gl }) => registerCanvas(gl.domElement)}`
- `app/src/lib/export-pdf.tsx` — Nova seção 5 (entre Coeficientes e Cargas
  Lineares) com `<Image>` do react-pdf + legenda.
- `app/src/pages/GalpaoModule.tsx` — Layout 4 colunas (controles / 3D / cargas /
  captura).
- **Suite de testes nova:** `app/src/lib/__tests__/canvas-capture.test.ts` (13 testes).
- **Total:** 123/123 testes passando (era 110/110).

**Requisitos técnicos:**
- `preserveDrawingBuffer: true` no contexto WebGL para permitir `toDataURL`.
- `Image as PdfImage` do `@react-pdf/renderer` aceita data URL direto.
- Renumeração dinâmica de seções no PDF (5 → 6 quando há captura).

### Marco 9.4 — Exportação Ftool (.txt estruturado)
**Status:** ✅ Concluído (2026-07-07)
**Escopo:** Gerar arquivo texto com nós, barras e cargas lineares no
formato de importação do Ftool (software livre de pórticos planos da
PUC-Rio, amplamente usado em escritórios brasileiros).
**Entregas:**
- `app/src/lib/export-ftool.ts` — 5 tipos exportados + 4 funções:
  - `buildFtoolModel()` → monta o modelo 2D do pórtico (6 nós, 4 barras)
  - `serializeFtool(model)` → texto no formato Ftool ASCII
  - `exportGalpaoToFtool()` → dispara download do .txt
  - Tipos: `FtoolModel`, `FtoolNode`, `FtoolMember`, `FtoolMemberLoad`
- `app/src/components/ExportMenu.tsx` — 3º botão "Ftool" (verde esmeralda)
  na barra de exportação.
- `app/src/components/FtoolExportCard.tsx` — Card lateral no GalpãoModule
  com preview do conteúdo do arquivo + botão de download.
- `app/src/pages/GalpaoModule.tsx` — Coluna extra com FtoolExportCard.
- **Suite de testes nova:** `app/src/lib/__tests__/export-ftool.test.ts`
  (26 testes cobrindo modelo, serialização e robustez).
- **Total:** 149/149 testes passando (era 123/123).

**Layout do pórtico gerado:**
- N1 (0, 0) → N4 (0, h)         — coluna esquerda (barlavento)
- N4 (0, h) → N5 (b/2, h+rise)  — água esquerda
- N5 (b/2, h+rise) → N6 (b, h)  — água direita
- N6 (b, h) → N3 (b, 0)         — coluna direita (sotavento)
- Mais 2 nós auxiliares N2 (b/2, h) para carregamento opcional

**Convenção Ftool:**
- Unidades: kN, m
- Cargas de coluna: `Dir GlobalX` (perpendicular à parede)
- Cargas de terça: `Dir GlobalY` (vertical, no plano do pórtico)
- 1 caso de carga nomeado "Vento θ° (q=..., Cpi=...)"

### Marco 9.5 — Refatoração TypeScript (eliminar `void` e `as unknown as`)
**Status:** ✅ Concluído (2026-07-07)
**Escopo:** Limpar padrões TypeScript fracos (`void X` para silenciar
`noUnusedLocals`, `as unknown as number[]` para escapar de checagem
de tipo) e melhorar a robustez dos módulos Strategy.
**Entregas:**
- **Eliminação de `void X`:** removidos 8 padrões `void` em 4 arquivos
  (truss.ts, table-32.ts, table-24-25.ts).
- **Eliminação de `as unknown as`:** removidos 26 padrões em 13 arquivos
  (table-3, 11, 12, 13, 15-17, 18-20, 23, 26, 27, modules/{truss,tower,vault}).
- **Tipagem forte em vault.ts:** substituído
  `Record<string, number>` por interfaces `VaultCpeWindPerpendicular` /
  `VaultCpeWindParallel` (expostos da tabela).
- **Correção de bugs latentes em interpolação:**
  - `bilinear-interp.ts`: `findBracket` agora trata arrays de 1 elemento
    corretamente (evita `xs[-1]` quando length=1).
  - `log-interp.ts`: `findBracket` idem.
- **Flags TypeScript adicionadas:** `noImplicitOverride` em `tsconfig.app.json`.
- **Suite de testes nova:** `app/src/lib/__tests__/refactoring.test.ts`
  (25 testes cobrindo cylinder, truss, tower, vault, table-32, 33, 26,
  24-25, 23, 21, 22).
- **Total:** 174/174 testes passando (era 149/149).

**Padrão antes/depois:**
```ts
// Antes: silent unused + cast duvidoso
const { alphaWind, phi, aeFace, q } = input;
void input;
const grid = { xs: PHI_15 as unknown as number[], ys: [1] as readonly number[], values: [...] };
return bilinearInterp(grid, phiClamped, 1);

// Depois: tipagem explícita + nada desperdiçado
const { barType, phi, aeFace, alphaWind, q } = input;
const grid = { xs: PHI_15, ys: [1] as readonly number[], values: [...] };
return bilinearInterp(grid, phiClamped, 1);
```

**Pendências descobertas (não corrigidas neste marco):**
- `table-18-20.ts`: chaves de `T18` (0.25, 0.5, 1) não casam com `FL` (0.05, 0.1, 0.2, 0.3, 0.4).
- `table-21.ts` e `table-22.ts`: usam `f.toString()` mas `T21`/`T22` têm chaves literais como `'1/15'` — `lookup` retorna `undefined`.
- Recomendação: M9.10 ou roadmap futuro para alinhar chaves.

### Marco 9.1 — Auditoria de tabelas NBR 6123:2023
**Status:** ✅ Concluído (2026-07-07)
**Escopo:** Auditar todas as 33 tabelas + 3 anexos contra o PDF oficial
**Entregas:**
- Todos os 33 arquivos `app/src/lib/nbr-tables/table-*.ts` e `stations.ts` agora têm
  cabeçalho com `Fonte: NBR 6123:2023, p. XX` e `Última auditoria: 2026-07-07`.
- **Correções aplicadas:**
  - **Tabela 4 (S3):** Grupo 1 de 1,10 → **1,11** (PDF p. 15).
    Grupo 2 de 1,08 → **1,06**. Adicionado `vidaUtilAnos` (100, 75, 50, 30, 2).
  - **Tabela 35 (pontes):** refatorada — era função de altura z, mas a norma define
    p e bₘ constantes por categoria. Corrigidos valores:
    - I: 0,10 / 1,25 | II: 0,16 / 1,00 | III: 0,20 / 0,85 | IV: 0,25 / 0,68 | V: 0,35 / 0,44
  - **Tabela 36 (amortecimento de pontes):** corrigidos valores discrepantes
    (Madeira 6,0 → 8,0; Protensão parcial 2,0 → 2,5; Mistas 1,5 → 1,8).
  - **Stations.ts (Anexo C):** altitudes corrigidas (Curitiba 510 → 910; BH 780 → 789;
    Anápolis 1087 → 1097; Campinas 661 → 648) + coordenadas conferidas.
- **Suite de testes nova:** `app/src/lib/__tests__/nbr-tables.test.ts`
  (43 testes cobrindo Tabelas 1, 3, 4, 5, 32, 35, 36, Anexo B e Anexo C).
- **Total:** 83/83 testes passando (era 38/38).

**Pendências (⚠️ marcadas nos arquivos):**
- Tabelas 6, 7, 8, 9, 10, 11, 12: valores simplificados no código; a norma fornece
  matrizes por h/b × θ × zona que precisam ser expandidas.
- Tabela 13: chaves de indexação usam "0.5/5/25" mas a norma define apenas
  "h/d=10" e "h/d≥2,5"; precisa reagrupamento.
- Tabela 14: 15+ seções × 7 razões h/ℓ × 6 Reynolds — usar valores pré-computados
  por combinação específica.
- Tabelas 15–22: revisar valores numéricos por f/b e zonas (1 a 6).
- Tabela A.1, A.2: revisar valores exatos por categoria × intervalo (PDF p. 99–101).
- Tabela B.1: confirmar valores exatos da grade Pₘ × m (PDF p. 104).
- Tabela 31: revisar parâmetros γ, ξ por tipo de estrutura (PDF p. 74).
- Tabela 33: revisar Strouhal por forma da seção.
- Estações: revisar V₀ de cada uma contra Figura 1 oficial.

---

## 🔧 Validação rápida do estado atual

```bash
cd /root/Apps/windapp/app

# 1. Compilação TS (deve passar sem erros)
./node_modules/.bin/tsc -b

# 2. Testes (deve mostrar 38/38 passing)
./node_modules/.bin/vitest run

# 3. Lint (deve mostrar 0 errors, ~5 warnings cosméticos)
./node_modules/.bin/oxlint

# 4. Build de produção
./node_modules/.bin/vite build

# 5. Dev server
npm run dev
```

**Resultado esperado:**
- ✅ tsc: silent (sem output)
- ✅ vitest: `Test Files 5 passed (5) | Tests 38 passed (38)`
- ✅ oxlint: `Found N warnings and 0 errors`
- ✅ vite: `✓ built in ~2s` com `dist/assets/index-*.js ~2.9 MB`

---

## 🚀 Roadmap priorizado de melhorias (pós-Marco 8)

### 🔴 Alta prioridade (Melhorias de qualidade técnica)

#### M9.1 — Refinar valores das tabelas a partir do PDF real (~3 dias)
**Status:** ✅ Concluído (ver Marco 9.1 acima). Headers de fonte adicionados a
todas as 33 tabelas. Correções críticas aplicadas em Tab. 4, Tab. 35, Tab. 36,
Stations (Anexo C). Suite de testes +43 casos (83/83 passando).
**Pendências:** ver seção "Pendências" no Marco 9.1.
**Problema:** Os valores das tabelas foram digitados baseados no OCR do PDF. Algumas tabelas (especialmente 14, 18-22) usam aproximações simplificadas.
**Tarefa:**
- Comparar cada tabela em `lib/nbr-tables/*.ts` com a norma oficial
- Corrigir discrepâncias (especialmente Tab. 14 com 15+ seções × 7 razões h/ℓ)
- Adicionar testes Vitest validando contra exemplos resolvidos do Blessmann
- Adicionar documentação inline apontando a fonte (página da norma)

#### M9.2 — Cargas lineares (kN/m) para software estrutural (~2 dias)
**Status:** ✅ Concluído (ver Marco 9.2 acima). 8 funções implementadas em
`line-loads.ts`. Painel interativo no GalpãoModule. PDF e CSV com seções dedicadas.
27 testes novos (110/110 passando).

#### M9.3 — Screenshot 3D no PDF (~1 dia)
**Status:** ✅ Concluído (ver Marco 9.3 acima). 4 viewers 3D registram canvas via
Zustand. Painel interativo com Select/Slider/Preview no estilo GalpaoModule.
PDF incorpora imagem automaticamente. 13 testes novos (123/123 passando).

### 🟡 Média prioridade (UX e polimento)

#### M9.4 — Exportação Ftool (.txt estruturado) (~2 dias)
**Status:** ✅ Concluído (ver Marco 9.4 acima). Pórtico 2D exportado com 6
nós + 4 barras + 1 caso de carga. 26 testes novos (149/149 passando).

#### M9.5 — Refatoração TypeScript (~1 dia)
**Status:** ✅ Concluído (ver Marco 9.5 acima). 8 padrões `void` + 26 padrões
`as unknown as` removidos. Bugs latentes em `findBracket` corrigidos.
Tipagem forte em `vault.ts`. 25 testes novos (174/174 passando).

#### M9.6 — Modo de visualização 3D para todas as estruturas (~3 dias)
**Status:** ✅ Concluído (2026-07-07). 4 novos componentes 3D criados e
integrados. Ver Marco 9.6 abaixo.

### Marco 9.6 — Visualização 3D para muros / torres / pontes / barras
**Status:** ✅ Concluído (2026-07-07)
**Escopo:** Cobrir as 4 estruturas restantes (que só tinham SVG 2D)
com visualização 3D interativa, vetores de força, e cores por intensidade.
**Entregas:**
- `app/src/components/three/Sign3D.tsx` — muros/placas retangulares:
  placa colorida por Cf + seta de força no ponto de aplicação + placas
  de extremidade opcionais (quando ℓ/hₐ < 60).
- `app/src/components/three/Tower3D.tsx` — torres reticuladas:
  geração procedural de barras (montantes + diagonais em X +
  travessas horizontais) para seção quadrada (4 cantos) ou triangular
  equilátera (3 cantos); seta de força no topo.
- `app/src/components/three/Bridge3D.tsx` — pontes:
  tabuleiro retangular + 3 pilares (1/3·Lₚ, 1/2·Lₚ, 2/3·Lₚ) +
  guarda-rodas/barreiras laterais + vetor Cx horizontal (vermelho)
  + vetor Cz vertical (azul) sobre o tabuleiro.
- `app/src/components/three/Bar3D.tsx` — barras isoladas:
  cilindro para circular, formas paramétricas (placa, L, T, I, retângulo)
  para faces planas, rotacionada pelo ângulo α, com seta de força
  resultante (Fx, Fy) e axesHelper para referência.
- Páginas integradas: `SignModule.tsx`, `BridgeModule.tsx`,
  `BarSelectorModule.tsx` (substituídos os SVGs pelos novos 3D,
  mantendo o SVG oculto como fallback).
- **Suite de testes nova:** `app/src/lib/__tests__/three-d-components.test.ts`
  (8 testes validando exports e tipos).
- **Total:** 182/182 testes passando (era 174/174).

**Convenção visual (todos os 4 componentes):**
- Placa/barra: cor base azul (#3b82f6), evolui para vermelho (#ef4444)
  conforme |Cx| ou |Cf| aumenta (intensity = min(1, |coeficiente|/max)).
- Vetor de força: cilindro (haste) + cone (ponta), comprimento
  proporcional a √(Fx² + Fy²) ou |F|.
- Marca amarela emissiva (#fbbf24) no ponto de aplicação.
- `gl={{ preserveDrawingBuffer: true, antialias: true }}` para
  permitir captura de canvas (M9.3).
- `onCreated={({ gl }) => registerCanvas(gl.domElement)}` para
  registro automático no `useCaptureStore`.
- `OrbitControls` com limites para evitar câmera underground.

#### M9.7 — Sistema de import de projetos via JSON (~1 dia)
**Status:** ✅ Concluído (ver Marco 9.7 abaixo). Roundtrip completo
testado. 29 testes novos (211/211 passando).

### Marco 9.7 — Sistema de Import de Projetos via JSON
**Status:** ✅ Concluído (2026-07-07)
**Escopo:** Permitir carregar projetos salvos em JSON de volta para
a aplicação, completando o roundtrip com o export existente.
**Entregas:**
- `app/src/lib/import-project.ts` — 14 funções exportadas:
  - `parseProjectJson(text)` — parsing seguro com mensagens claras
  - `detectFormat(parsed)` — detecta `SavedProject` vs `snapshot`
  - `validateSavedProject(raw)` / `validateSnapshot(raw)` — validação
    separada de erros fatais e warnings não-fatais
  - `applySavedProject(project)` / `applySnapshot(snapshot)` —
    aplicação idempotente nos stores Zustand (windStore, galpaoStore)
  - `importProjectFromText(text)` — orquestrador (parse + detect + validate + apply)
  - `readProjectFile(file)` — wrapper FileReader → Promise<string>
  - `exportProjectToJson(project)` / `snapshotWindStoreToJson()` — roundtrip
  - Tipo `ImportResult` com `ok`, `module`, `projectName`, `appliedFields`,
    `warnings`, `error`
- `app/src/pages/SettingsModule.tsx` — botão "Importar projeto" ao lado
  do "Exportar estado". Aceita `.json`. Mostra feedback inline com:
  - ✅ Sucesso: módulo aplicado, lista de campos
  - ⚠️ Avisos: validações não-fatais
  - ❌ Erro: mensagem formatada (JSON inválido, formato desconhecido, etc.)
- `app/src/lib/hooks/useProjects.ts` — sem mudança (importação é via
  sistema de arquivos, não IndexedDB).
- **Suite de testes nova:** `app/src/lib/__tests__/import-project.test.ts`
  (29 testes cobrindo parsing, detecção, validação, aplicação e roundtrip).
- **Total:** 211/211 testes passando (era 182/182).

**Formatos suportados:**
```jsonc
// Formato 1 — SavedProject (gerado pelo export IndexedDB)
{
  "name": "Galpão Teste",
  "module": "galpao",
  "inputs": { "wind": {...}, "galpao": {...} },
  "createdAt": 1234567890,
  "updatedAt": 1234567899
}

// Formato 2 — Snapshot do windStore (gerado por "Exportar estado")
{
  "v0": 40, "s1": 1, "s3": 1,
  "terrainCategory": "II", "s3Group": 3,
  "largestDimension": 30, "heightZ": 10,
  "s2": 1.06, "vk": 42.4, "q": 1.1024,
  "structureClass": "B"
}
```

**Validação:**
- Erros fatais: campos obrigatórios ausentes, tipos errados, valores
  inválidos (ex.: categoria fora de I–V)
- Warnings: campos opcionais ausentes (gerados automaticamente)

**Aplicação idempotente:**
- Cada campo só é aplicado se o tipo bater (number/string/boolean)
- Categoria validada contra enum antes de chamar setTerrainCategory
- Warnings não bloqueiam a aplicação dos demais campos

### 🟢 Baixa prioridade (features adicionais)

#### M9.8 — i18n completo (~2 dias)
**Status:** ✅ Concluído (ver Marco 9.8 abaixo). 130+ chaves no dicionário,
LanguageSwitcher no sidebar, hook useI18n, persistência localStorage.
39 testes novos (250/250 passando).

### Marco 9.8 — i18n completo (pt-BR + en-US)
**Status:** ✅ Concluído (2026-07-07)
**Escopo:** Expandir o sistema de i18n mínimo (~15 strings) para
cobrir toda a UI do VentoApp em pt-BR e en-US, com switcher de
idioma e persistência local.
**Entregas:**
- `app/src/lib/i18n.ts` — Expandido para **130+ chaves** organizadas
  por área (nav_*, app_*, common_*, settings_*, linear_loads_*, etc.).
  Mantém API pública `t(key, locale, params?)` com interpolação
  `{placeholder}` e fallback automático.
- `app/src/lib/i18n.ts` (novo): funções utilitárias
  - `loadStoredLocale()` / `saveStoredLocale(locale)` — persistência
  - `detectBrowserLocale()` — fallback para `navigator.language`
  - `listKeys()` — debug/inspeção
- `app/src/store/i18nStore.ts` — Zustand store com persistência.
  Hook `useI18n()` retorna `{ t, locale, setLocale }`.
  Função `tNow(key)` para tradução fora de componentes.
- `app/src/components/LanguageSwitcher.tsx` — Seletor compacto
  com ícone de globo (🇧🇷 pt-BR / 🇺🇸 en-US), integrado no
  rodapé do sidebar (desktop) e no header (mobile).
- Páginas migradas:
  - `App.tsx` — sidebar, navegação (11 itens), HomeMock (header + cards)
  - `SettingsModule.tsx` — Aparência, Projetos Salvos, Estado Atual, Sobre
  - `LinearLoadsTable.tsx` — 3 abas + 4 pilares + 6 terças + reações
  - `ExportMenu.tsx` — tooltips dos botões
- **Suite de testes nova:** `app/src/lib/__tests__/i18n.test.ts`
  (39 testes cobrindo dicionário, interpolação, persistência,
  detecção browser, componentes).
- **Total:** 250/250 testes passando (era 211/211).

**Convenção de chaves:**
```ts
// snake_case agrupadas por área
nav_home, nav_warehouse, nav_cylinder, ...
settings_appearance, settings_projects, ...
linear_loads_title, linear_loads_pillar_windward, ...
scene_capture_format, ftool_title, ...
```

**Interpolação:**
```ts
t('settings_projects_count', 'pt-BR', { count: 5 })
// → "5 projeto(s) armazenado(s)."
```

**Persistência:**
- Chave localStorage: `ventoapp.locale`
- Valor: `'pt-BR' | 'en-US'`
- Fallback: `navigator.language` → `'pt-BR'`
- Falha silenciosa se localStorage indisponível (modo privado)

#### M9.9 — Validação contra exemplos do Blessmann (~2 dias)
**Status:** ✅ Concluído (ver Marco 9.9 abaixo). 10 casos documentados,
48 testes criados (298/298 passando).

### Marco 9.9 — Validação cruzada contra Blessmann
**Status:** ✅ Concluído (2026-07-07)
**Escopo:** Criar suite de validação que compara os cálculos do VentoApp
com casos resolvidos do livro "O Vento na Engenharia Estrutural"
(J. Blessmann, EDUFRGS, 2ª ed.) e com valores tabelados da norma.
**Entregas:**
- `app/src/lib/blessmann-cases.ts` — **10 casos clássicos** documentados:
  | # | Caso | Fonte |
  |---|------|-------|
  | 1 | Galpão 30×15×6 m, telhado duas águas | Blessmann Cap. 5 Ex. 5.1 |
  | 2 | Edifício alto 60×20×100 m, Cat. III | Blessmann Cap. 9 |
  | 3 | Silo cilíndrico d=8, h=24, liso, topo aberto | Tab. 13 |
  | 4 | S₂ em diferentes (h, categoria, classe) | NBR 6123:2023 Tab. 3 |
  | 5 | S₃ analítico (Anexo B) | NBR 6123:2023 Anexo B |
  | 6 | Ponte 120 m, Pse | NBR 6123:2023 sec. 11.2.2 |
  | 7 | Cobertura isolada (limites) | NBR 6123:2023 sec. 7.2.1 |
  | 8 | Chaminé d=1,5, h=30, liso | Tab. 13 |
  | 9 | Placa de publicidade 6×2 m | Tab. 23 |
  | 10 | S₂ fórmula teórica vs Tab. 3 | NBR 6123:2023 Tab. 1 + Tab. 3 |
- Cada caso exporta: `id`, `description`, `source`, `tolerance`, `notes?`
- Helper `isWithinTolerance(calculated, expected, tolerance)` para
  comparação com tolerância percentual e absoluta (para expected=0).
- `app/src/lib/__tests__/blessmann.test.ts` — **48 testes** cobrindo:
  - Casos quantitativos: S₂, S₃, Vₖ, q, Cpe, Pse
  - Cross-checks: fórmula teórica vs tabela
  - Propriedades: monotonicidade, consistência
  - Helpers e metadados dos casos

**Discrepâncias documentadas (pendências M9.1):**
Os testes para Tab. 6, Tab. 7, Tab. 13, Tab. 23 e Tab. 24-25 usam
**placeholders estruturais** (apenas verifica que a função retorna
valores finitos em faixas plausíveis). Quando M9.1 corrigir os valores
oficiais, esses testes podem ser atualizados para validação ponto-a-ponto.

**Total:** 298/298 testes passando (era 250/250).

#### M9.10 — Tema dark mode para gráficos SVG (~0.5 dia)
**Status:** ✅ Concluído (ver Marco 9.10 abaixo). SVGs migrados para
`var(--color-*)`, módulo `svg-colors` criado, 12 testes novos (310/310).

### Marco 9.10 — Dark mode em gráficos SVG
**Status:** ✅ Concluído (2026-07-07)
**Escopo:** Migrar cores hardcoded (#6366f1, #ef4444, etc.) nos
gráficos SVG inline para variáveis CSS do tema, suportando dark mode.
**Entregas:**
- `app/src/lib/svg-colors.ts` — Módulo centralizado com 10 chaves semânticas:
  - `text` = `currentColor` (herda de text-foreground)
  - `muted` = `var(--color-muted-foreground)`
  - `primary` / `primaryFill` (com `color-mix(... transparent)`)
  - `destructive` / `destructiveFill`
  - `info`, `grid`, `fgSolid`, `marker`
  - Paleta `SVG_PALETTE` (5 cores para multi-série, baseadas em `--chart-1` a `--chart-5`)
- SVGs migrados em 4 páginas:
  - `DynamicsModule.tsx` (2 gráficos: q(z) e ζ)
  - `IsolatedRoofModule.tsx` (corte esquemático de cobertura)
  - `BarSelectorModule.tsx` (barra + vetor de força, fallback)
  - `BridgeModule.tsx` (ponte + pilares + vetores Cx/Cz, fallback)
- Substituições aplicadas:
  - `#6366f1` (roxo) → `var(--color-primary)` ou `color-mix(in oklch, var(--color-primary) 30%, transparent)`
  - `#ef4444` (vermelho) → `var(--color-destructive)`
  - `#94a3b8` (cinza) → `var(--color-border)`
  - `#0f172a` (preto) → `var(--color-foreground)`
  - `#1e293b` (preto) → `var(--color-foreground)`
  - `#3b82f6` (azul) → `var(--color-primary)`
  - `#cbd5e1` (cinza claro) → `var(--color-border)` com opacity
  - `#fbbf24` (amarelo) → `var(--color-accent)` (futuro)
- `app/src/lib/__tests__/svg-colors.test.ts` — 12 testes:
  - Presença das chaves esperadas
  - Validação de que cada cor referencia variável CSS
  - Unicidade da paleta de multi-série
  - Contraste semântico (primary ≠ destructive)
- **Total:** 310/310 testes passando (era 298/298).

**Padrão de uso em componentes:**
```tsx
<svg viewBox="0 0 320 200">
  <line stroke="var(--color-border)" strokeWidth="1" />
  <path stroke="var(--color-primary)" fill="none" />
  <text fill="currentColor">label</text>
</svg>
```

**Vantagens:**
- Cores se adaptam automaticamente a `.dark` no html
- Sem duplicação de lógica de tema
- Mantém fallback OKLCH via Tailwind v4
- Acessibilidade: `currentColor` herda de `text-foreground` da página

#### M9.13 — Exportação genérica de PDF para todos os módulos restantes
**Status:** ✅ Concluído (2026-07-08)
**Escopo:** Expandir a capacidade de exportação de PDF (com captura 3D) que estava limitada ao Galpão para abranger os demais módulos (Cilindros, Abóbadas, Cúpulas, Muros, Coberturas Isoladas, Barras, Pontes, Dinâmica).
**Entregas:**
- Criação de `app/src/lib/export-generic-pdf.tsx` contendo o componente `GenericReportDocument` com template flexível capaz de receber seções dinâmicas (tabelas, grids de informações).
- Injeção das funções `handleExportPDF` em cada uma das páginas (`CylinderModule.tsx`, `VaultModule.tsx`, `DomeModule.tsx`, `SignModule.tsx`, `IsolatedRoofModule.tsx`, `BarSelectorModule.tsx`, `BridgeModule.tsx`, `DynamicsModule.tsx`).
- Refatoração de `ExportMenu.tsx` para receber callbacks customizados, permitindo a exportação de PDF com suporte à visualização 3D para qualquer módulo de engenharia suportado pela NBR 6123.
- Testes de build (`tsc -b` e `vite build`) passando com sucesso e mantendo a integridade (310/310 testes unitários sem regressões).

#### M9.11 — Persistência opcional em servidor (~especulativo)
**Problema:** Tudo é local (IndexedDB).
**Tarefa:**
- Definir estratégia (Firebase? Supabase? REST própria?)
- Criar abstração `StorageAdapter` (local ou remoto)
- Adicionar autenticação básica

#### M9.12 — Testes E2E com Playwright (~2 dias)
**Problema:** Apenas testes unitários. Falta testar fluxos completos.
**Tarefa:**
- Instalar `@playwright/test`
- Criar testes E2E para: criar projeto galpão, salvar, exportar PDF
- Integrar ao CI

---

## 📋 Convenções estabelecidas (manter)

1. **Tipagem forte**: zero `as any`, zero `// @ts-ignore`
2. **Sem comentários** exceto matemática complexa
3. **Imports absolutos**: `@/lib/...`, `@/components/...`, `@/store/...`
4. **Componentes**: PascalCase `.tsx`, kebab-case utilitários `.ts`
5. **Tabelas readonly**: `Readonly<Record<...>>` em todos os `nbr-tables/`
6. **Cpi sempre explícito**: `p = q · (Cpe − Cpi)` em todos os cálculos
7. **Strategy pattern**: cada tipo de estrutura tem um módulo em `lib/modules/`
8. **Páginas**: cada rota tem uma página em `pages/` consumindo o módulo correspondente
9. **Testes Vitest**: cobrem motor matemático, interpolações, Cpi, vizinhança, Reynolds
10. **Validação antes de merge**: `npm run build` + `npm test` devem passar

---

## 🔍 Onde encontrar coisas

### Quero adicionar uma tabela NBR
→ `app/src/lib/nbr-tables/` (criar `table-N.ts`), depois expor em `coefficients.ts` ou `modules/`

### Quero adicionar uma nova estrutura (ex.: chaminé)
→ Criar `app/src/lib/modules/<tipo>.ts` com Strategy, depois `app/src/pages/<Tipo>Module.tsx`, registrar rota em `App.tsx`

### Quero adicionar nova UI
→ Componentes em `app/src/components/`, com `cn()` para merge de classes, variantes shadcn quando existirem

### Quero adicionar testes
→ `app/src/lib/__tests__/` com `vitest` (sem jsdom necessário para cálculos puros)

### Quero debugar o cálculo
→ `app/src/lib/wind-kernel.ts` é o ponto de entrada; cada função retorna valor com `toFixed(...)` para debug

---

## 🐛 Erros conhecidos (não críticos)

1. **`@rolldown/binding-linux-x64-gnu`** precisa estar instalado (foi adicionado em Marco 1)
2. **Binários em `node_modules/.bin/`** perdem o bit de execução — usar `chmod +x` antes de chamar
3. **Vitest** sem `vitest.config.ts` separado não funciona; foi criado em Marco 8
4. **TypeScript `noUnusedLocals`** está habilitado — `void input` foi adicionado para silenciar (M9.5 deve corrigir)

---

## 📚 Documentos relacionados

- `PLAN.md` — Plano original dos 8 marcos
- `app/README.md` — Documentação técnica do app
- `AGENTS.md` — Guia para IAs
- `plano_tecnico_implantacao.md` — Plano técnico original do projeto
- `projeto_vento_visao_geral.md` — Visão geral do produto

---

## 🎯 Próximo passo sugerido

**M9.7 já está completo.** Para próximos passos, considerar:
**M9.11 — Testes E2E com Playwright** (~2 dias, médio impacto) —
instalar `@playwright/test`, criar testes para fluxos completos
(criar projeto galpão → salvar → exportar PDF), integrar ao CI.

Para retomar:
1. Ler este documento
2. Escolher item do roadmap restante
3. Implementar e validar com testes
4. Atualizar este documento marcando o item como concluído