# Análises de IA



# Auditoria Arquitetura React Console

## 1. Arquitetura e Grafo de Dependencias

### 1.1 Hierarquia: App -&gt; Layouts -&gt; Pages -&gt; Components

```mermaid
graph TD
    EntryPoint["src/index.js"] --> ConfigProvider["ConfigProvider - AntD"]
    ConfigProvider --> App["src/App/index.js"]
    App --> GlobalThemeProvider["GlobalThemeProvider"]
    GlobalThemeProvider --> RoutesContainer["RoutesContainer"]
    RoutesContainer --> Routes["src/Routes/index.jsx"]
    Routes --> FunctionalContainer
    FunctionalContainer -->|nao logado| Login["Login"]
    FunctionalContainer -->|logado| Router["BrowserRouter"]
    Router --> AuthProvider
    AuthProvider --> NotifyProvider
    NotifyProvider --> CustomFeaturesProvider
    CustomFeaturesProvider --> ConsoleContainer
    ConsoleContainer --> TopAppBar
    ConsoleContainer --> RoutesApp["Rotas por App"]
    RoutesApp --> Guidelines["Guidelines Layout"]
    RoutesApp --> Monitoramento["Monitoramento Layout"]
    RoutesApp --> Movimentacao["Movimentacao Layout"]
    RoutesApp --> Distribuicao["Distribuicao Layout"]
    RoutesApp --> CopiaIntegral["CopiaIntegral Layout"]
    RoutesApp --> Protocols["Protocols"]
    RoutesApp --> Intimations["Intimations"]
    RoutesApp --> GlobalRoutes["Rotas Globais"]
```

**Numeros aproximados:**

- `src/pages/` -- ~513 arquivos
- `src/components/` -- ~198 arquivos
- `src/ui/components/` -- ~50 arquivos
- `src/ui/layouts/` -- ~29 arquivos
- `src/context/` -- ~20 arquivos
- `src/services/` -- ~30 arquivos

**Stack:**

- React 16.14 + react-router-dom v4 + CRA (react-scripts 1.1.5)
- Estilizacao: styled-components + Ant Design 4 + Semantic UI + Bootstrap 4
- Build: Create React App (sem webpack/vite config exposto)

### 1.2 Estado e Dados

**Estado Global:**

- **Zustand** (`src/useStore.js`) -- store global com persistencia em localStorage
    
    
    - Dominios: `spreadsheet`, `protocols`, `intimations`, `inboxState`, `apps`, `statsData`, `loading`
- **18+ Context Providers** aninhados em [src/Routes/index.jsx](https://wiki.oystr.com.br/src/Routes/index.jsx):
    
    
    - Auth, Notify, CustomFeatures, OystrApi, Inbox, Intimations, Monitoramento, Distribuicao, Classifier, Protocolo, LegacyIntimation, CopiaIntegral, Guidelines, Movimentacao, Pautas, Xtrim, Executions

**Problema critico:** Estado duplicado entre Zustand e Context (ex: `inboxState` existe em ambos). Nao ha uma camada unica de verdade (single source of truth).

**Data Fetching:** Axios manual via `useEffect` + services. **Sem react-query/SWR** -- nao ha cache, invalidacao ou retry automatico.

**Componentes Smart (logica + data fetching):**

- [src/pages/Intimations/index.jsx](https://wiki.oystr.com.br/src/pages/Intimations/index.jsx) -- 20 `useState`, fetching de tabelas, execucoes, tags
- [src/pages/Intimations/Inbox/IntimationContent.jsx](https://wiki.oystr.com.br/src/pages/Intimations/Inbox/IntimationContent.jsx) -- Context + useStore + services
- [src/pages/Protocols/UploadLote/index.js](https://wiki.oystr.com.br/src/pages/Protocols/UploadLote/index.js) -- upload, validacao, API calls
- [src/pages/Auth2F/index.js](https://wiki.oystr.com.br/src/pages/Auth2F/index.js) -- 21 `useState`
- [src/pages/PwdCredentials/index.js](https://wiki.oystr.com.br/src/pages/PwdCredentials/index.js) -- 24 `useState`

### 1.3 Acoplamento

**Componentes com muitas dependencias externas:**

- [src/pages/Intimations/index.jsx](https://wiki.oystr.com.br/src/pages/Intimations/index.jsx) -- 20 `useState`, multiplos services, Context, Zustand
- [src/pages/Protocols/DashProtocols/index.js](https://wiki.oystr.com.br/src/pages/Protocols/DashProtocols/index.js) -- 3.398 linhas, "God Component"
- [src/components/Intimation/Perfis/index.js](https://wiki.oystr.com.br/src/components/Intimation/Perfis/index.js) -- 1.664 linhas, logica que deveria ser hooks

**Prop Drilling identificado (3+ niveis):**

- `Intimations -> Inbox -> Views -> IntimationContent`: props como `gridPermission`
- `Intimations -> Perfis`: 11+ props de controle de formulario (`openForm`, `closeForm`, `djen`, `diarioOficial`, etc.)
- `Intimations -> Inbox`: 10+ props (`inboxRequest`, `setInboxRequest`, `refreshExecutions`, `handleTabChange`, etc.)
- `SchedulerHomePage -> SchedulerStep -> filhos`: `context`, `credentialsOption`, `uploadError`, etc.

---

## 2. Auditoria de Qualidade e Code Smells

### 2.1 Top 10 arquivos mais complexos

- **\#1** `src/pages/Protocols/DashProtocols/index.js` -- **3.398 linhas** -- God Component, deve ser dividido em 6-8 subcomponentes
- **\#2** `src/components/Intimation/Perfis/index.js` -- **1.664 linhas** -- Logica de form + apresentacao misturadas
- **\#3** `src/pages/Intimations/Inbox/templates.jsx` -- **1.636 linhas** -- Templates que deveriam ser componentes separados
- **\#4** `src/pages/Intimations/index.jsx` -- **1.544 linhas** -- 20 useState, orquestrador de tudo
- **\#5** `src/pages/Protocols/DashProtocols/ProtocolTab.js` -- **1.237 linhas** -- Aba com logica de negocio pesada
- **\#6** `src/pages/Intimations/Inbox/IntimationContent.jsx` -- **1.226 linhas** -- 73 estilos inline, ReactDOM.render em useEffect
- **\#7** `src/pages/execution/ExecutionJournal.js` -- **1.192 linhas** -- Mistura de logica + apresentacao
- **\#8** `src/pages/scheduler/home/ProtoQueue/index.js` -- **1.067 linhas** -- Fila de protocolos monolitica
- **\#9** `src/pages/Monitoramento/MonitoramentoBatchEdit/index.js` -- **1.056 linhas** -- Form complexo nao decomposto
- **\#10** `src/pages/Protocols/DashProtocols/ModalRetryProtocol/index.js` -- **1.027 linhas** -- Modal com logica de retentativa pesada

### 2.2 Logica Duplicada

**Modais identicos em 4 modulos:**

- `src/components/Guidelines/Modal/index.js`
- `src/components/Movimentacao/Modal/index.js`
- `src/components/LegacyIntimation/Modal/index.js`
- `src/components/Intimation/Modal/index.js`

Sugestao: Extrair para `src/components/shared/Modal/index.js`.

**Dropzones duplicados (3 modulos):**

- `src/components/DropzoneMovimentacao/index.js`
- `src/components/DropzoneCopiaIntegral/index.js`
- `src/components/DropzoneGuidelines/index.js`

Mesma logica de `parse`, `payloadFile`, `checkFile`, `onDrop`. Sugestao: `useDropzoneUpload(service)` hook.

**DataTable duplicado:**

- `src/pages/Intimations/ReportDashboard/components/DataTable/index.jsx`
- `src/pages/Intimations/ReportDashboardGrid/components/DataTable/index.jsx`

**Perfis duplicados (Guidelines vs Movimentacao):**

- `src/pages/Guidelines/Perfis/index.js`
- `src/pages/Movimentacao/Perfis/index.js`

**Validacao de formulario duplicada:**

- `src/pages/Protocols/DashProtocols/ModalNewProtocol/index.js`
- `src/pages/Protocols/DashProtocols/ModalRetryProtocol/index.js`

Sugestao: `useFormValidation()` hook.

### 2.3 Codigo Morto

**Arquivos nao importados:**

- `src/api/xtrim/uploads.js` -- codigo quebrado (usa `baseUrl` e `res` indefinidos)
- `src/api/index.js` -- exporta `api = true`, sem uso

**Exports nao usados:**

- `Bitrix` em `src/App/integrations/Bitrix/index.jsx` -- import comentado
- `MandeUmZap` em `src/App/integrations/MandeUmZap/index.jsx` -- sem imports
- `registerServiceWorker.js` -- nao importado
- `listAllAccounts`, `listAllApps` em `services/appsManagement/`
- `getClients` em `services/legacyIntimations/entities/clients.js`
- `handleSaveExport` em `pages/Guidelines/models.js`
- `updateSpecificBatch` em `pages/Monitoramento/models.js` (funcao vazia)
- Tipos em `context/Monitoramento/types.js` e `context/Distruibuicao/types.js`
- `defaultNotification` em `libs/notification/utils.js`
- `convertVhToPx` em `styles/cssSnippets.js`
- `FileInput` e `CircleStop` em `src/ui/components/`

**Dependencias nao utilizadas no package.json:**

- `semantic-ui-calendar`, `semantic-ui-calendar-react`
- `archiver`, `unzipper`
- `rsuite`, `react-ace`, `react-ace-editor`
- `start`, `yarn`

---

## 3. Matriz de Refatoracao

**Prioridade Critica (P0):**

- `DashProtocols/index.js` (3.398 linhas) -- Complexidade 10/10 -- God Component -- Decompor em TabManager, FilterPanel, DataView, ActionBar, etc.
- `Intimations/index.jsx` (1.544 linhas) -- Complexidade 9/10 -- Estado monolitico -- Extrair hooks: `useIntimationData`, `useIntimationTags`, `useIntimationFilters`
- `IntimationContent.jsx` (1.226 linhas) -- Complexidade 8/10 -- 73 estilos inline + ReactDOM.render legado -- Migrar estilos para styled-components e remover ReactDOM.render

**Prioridade Alta (P1):**

- `Perfis/index.js` (1.664 linhas) -- Complexidade 8/10 -- Logica misturada -- Separar em FormPerfil, ListPerfis, hooks
- `templates.jsx` (1.636 linhas) -- Complexidade 7/10 -- Templates monoliticos -- Separar cada template em componente
- `ProtocolTab.js` (1.237 linhas) -- Complexidade 7/10 -- Aba pesada -- Decompor em subcomponentes
- `ExecutionJournal.js` (1.192 linhas) -- Complexidade 7/10 -- Mistura de logica + UI -- Extrair hooks
- Modais duplicados (4 arquivos) -- Complexidade 3/10 -- DRY violation -- Unificar em componente compartilhado
- Dropzones duplicados (3 arquivos) -- Complexidade 4/10 -- DRY violation -- Criar `useDropzoneUpload` hook

**Prioridade Media (P2):**

- `ProtoQueue/index.js` (1.067 linhas) -- Complexidade 6/10 -- Decompor
- `MonitoramentoBatchEdit/index.js` (1.056 linhas) -- Complexidade 6/10 -- Decompor
- `ModalRetryProtocol/index.js` (1.027 linhas) -- Complexidade 6/10 -- Extrair validacao para hook
- DataTable duplicado (2 arquivos) -- Complexidade 3/10 -- Unificar
- Perfis duplicados (Guidelines vs Movimentacao) -- Complexidade 4/10 -- Parametrizar

---

## 4. Tarefas de "Mare Baixa" (Low-Hanging Fruit) -- Detalhado

### 4.1 BUGS e problemas criticos (corrigir primeiro)

- **BUG: `window.reload()` nao existe** em `src/ui/components/HeaderMenu/index.jsx:67` -- corrigir para `window.location.reload()`
- **BUG: media query sem unidade** em `src/pages/HomePage/styles.js:91` -- `@media (max-width: 699)` deve ser `699px`
- **XSS: `dangerouslySetInnerHTML` sem sanitizacao** em `src/pages/Monitoramento/MonitoramentoTable/index.js:211` -- `aiInterpretation.result_html` vem da API sem sanitizacao. Usar `DOMPurify.sanitize()`
- **Lifecycle deprecado: `componentWillMount`** em `src/pages/Protocols/DashProtocols/ModalRetryProtocol/index.js:75` e `ModalNewProtocol/index.js:107` -- migrar para `componentDidMount`
- **Lifecycle deprecado: `UNSAFE_componentWillUpdate`** em `src/pages/BotsPages/index.js:188` -- migrar para `componentDidUpdate` ou `getDerivedStateFromProps`

### 4.2 Memory leaks (event listeners e timers sem cleanup)

- **Event listener sem cleanup** em `src/Routes/index.jsx:185` -- `document.addEventListener("keydown")` sem `componentWillUnmount`
- **Event listener sem cleanup** em `src/pages/Guidelines/Detalhes/index.js:134`, `src/pages/Movimentacao/Detalhes/index.js:150`, `src/pages/CopiaIntegral/Detalhes/index.js:150`, `src/pages/Pautas/Detalhes/index.js:110` -- `addEventListener("keydown")` sem cleanup
- **Event listener sem cleanup** em `src/pages/BotsPages/index.js:244` -- `addEventListener("keydown")` sem cleanup
- `**window.addEventListener("resize")` sem cleanup\*\* em 5 arquivos: `Executions/index.js` de CopiaIntegral, Movimentacao, LegacyIntimations, Intimations, Guidelines
- **removeEventListener com funcao errada** em `src/components/DebugBtn/index.js:74-77` e `ValidateCredentials/DebugBtn/index.js:71-74` -- passa `() => {}` em vez da mesma referencia da funcao
- **scroll listener sem cleanup** em `src/ui/components/AiWidget/index.jsx:102-108`
- **setInterval sem cleanup** em `src/pages/Movimentacao/Home/index.js:241`, `Pautas/index.js:190`, `DashProtocols/index.js:257`, `CopiaIntegral/Home/index.js:242`, `Guidelines/Home/index.js:254`
- **setTimeout sem clearTimeout** em `src/pages/Intimations/Inbox/IntimationContent.jsx:162-198`, `ShowAuthCode/index.js:23-32`
- `**setInterval(setTimeout(...))` -- uso incorreto\*\* em `src/components/ShowAuthCode/index.js:54,62` e `src/pages/Auth2F/index.js:90`

### 4.3 Substituir `var` por `const`/`let` (~50 ocorrencias)

- `src/components/oystrCredentials/simpleCredentials/index.jsx:245`
- `src/pages/execution/ExecutionJournalGrid.js:829-830,854`
- `src/shared/utils.js:271-272`
- `src/App/integrations/Delighted/index.js:13,33,38,44,53`
- `src/pages/Guidelines/UploadSheet/index.js:133-134`
- `src/pages/Intimations/Inbox/IntimationContent.jsx:784,1043,1048,1051,1083`
- `src/pages/Intimations/GridSidepanel/IntimationsGridSidepanel.jsx:40,47-48,83-84,122,124,128`
- `src/pages/Intimations/index.jsx:813-814,816,821,1217-1218,1252`
- `src/pages/BotsPages/index.js:177,180`
- `src/pages/BotsPages/Modal/About/actions.js:5,7,16-17`
- `src/pages/Movimentacao/UploadSheet/index.js:142-143`
- `src/pages/CopiaIntegral/UploadSheet/index.js:135-136`
- `src/pages/Pautas/UploadSheet/index.js:67-68`
- `src/pages/execution/ExecutionJournal.js:842-843,867`
- `src/pages/execution/ExecutionDetail.js:67`
- E outros ~15 arquivos com usos esporadicos

### 4.4 Substituir `==` por `===` (~14 ocorrencias)

- `src/pages/Protocols/DashProtocols/ModalNewProtocol/index.js:228,238` -- `restoreIndex == null`
- `src/pages/Protocols/DashProtocols/ModalRetryProtocol/index.js:206,216` -- `restoreIndex == null`
- `src/pages/DuplicateTiming/index.jsx:60,64` -- `hours == null`, `remainingHours == 0`
- `src/components/Auth2FForm/index.js:39` -- `tokens == null`
- `src/pages/settings/ApiSettings.js:51` -- `item.id == user.account.id`
- `src/pages/scheduler/home/MasterFile.js:189` -- `violations == null`
- `src/pages/Distribuicao/DistribuicaoTermsBlockConfig/index.js:157` -- `data.codTipo == 1`
- `src/components/ReportDownloadManager/index.js:214` -- `res.status == "RETRY"`
- `src/App/integrations/Bitrix/index.jsx:11` -- `process.env.REACT_APP_MODE == "local"`

### 4.5 Remover `console.log` de producao (~50+ ocorrencias)

- `src/pages/PwdCredentials/NewCredential/index.jsx:17` -- `console.log("arroz")` (lol)
- `src/components/PageModal/index.js:5` -- `console.log(props)`
- `src/api/Classifier/index.js` -- 10 ocorrencias (linhas 9,17,25,30,35,43,62,78,86,94)
- `src/pages/scheduler/home/SchedulerHomeController.js` -- 12 ocorrencias
- `src/pages/scheduler/confirm/SchedulerConfirmPage.js` -- 6 ocorrencias (176,253,259,297,312,427)
- `src/pages/Protocols/UploadLote/index.js` -- 4 ocorrencias (316,341,569,571)
- `src/pages/Protocols/DashProtocols/index.js` -- 3 ocorrencias (337,528,682)
- `src/pages/Intimations/Inbox/IntimationContent.jsx` -- 3 ocorrencias (148,910,1088)
- `src/services/cnab/index.js` -- 2 ocorrencias (14,29)
- `src/components/LegacyIntimation/Configurations/index.js` -- 2 ocorrencias (48,201)
- `src/components/DropzoneMovimentacao/index.js` -- 2 ocorrencias (50,113)
- `src/components/DropzoneCopiaIntegral/index.js` -- 2 ocorrencias (49,112)
- `src/components/DropzoneGuidelines/index.js` -- 2 ocorrencias (31,49)
- `src/pages/Pautas/UploadSheet/index.js` -- 5 ocorrencias (43-47,58,116-117)

### 4.6 Deletar codigo morto

- Deletar `src/api/xtrim/uploads.js` -- codigo quebrado, nao importado, usa `baseUrl` e `res` indefinidos
- Deletar `src/api/index.js` -- exporta `api = true`, sem uso em lugar nenhum
- Deletar `src/registerServiceWorker.js` -- nao importado por ninguem
- Deletar pasta `src/App/integrations/Bitrix/` -- import comentado em `context/auth.js`
- Deletar pasta `src/App/integrations/MandeUmZap/` -- sem nenhum import
- Remover exports nao usados: `listAllAccounts` e `listAllApps` de `services/appsManagement/index.js`
- Remover export `getClients` de `services/legacyIntimations/entities/clients.js`
- Remover export `handleSaveExport` de `pages/Guidelines/models.js`
- Remover funcao vazia `updateSpecificBatch` de `pages/Monitoramento/models.js`
- Remover types nao usados de `context/Monitoramento/types.js` (`addProcessToSelector`, `removeProcessFromSelector`, `clearSelector`, `selectAll`)
- Remover types nao usados de `context/Distruibuicao/types.js`
- Remover `defaultNotification` de `libs/notification/utils.js`
- Remover `convertVhToPx` de `styles/cssSnippets.js`
- Avaliar remocao de `FileInput` e `CircleStop` de `src/ui/components/`

### 4.7 Limpar codigo comentado

- `src/pages/Monitoramento/models.js:147-156` -- funcao `formatTermsDelete` inteiramente comentada
- `src/pages/OystrApi/templates.js:145-199` -- `dataSourceTemplate` inteiramente comentada
- `src/pages/Protocols/DashProtocols/ModalNewProtocol/styles.js:124-215` -- estilos comentados
- `src/pages/Protocols/DashProtocols/DocumentKits/styles.js:299-350` -- estilos comentados
- `src/pages/Intimations/index.jsx:893-895` -- "Selecionar todos" comentado
- `src/pages/Intimations/Perfis/index.js:808-822,1069-1083` -- checkbox e botao comentados
- `src/components/Intimation/Perfis/index.js:1008-1018` -- InputContainer comentado
- `src/pages/Protocols/Settings/Step/EditPart/index.js:2-5` -- imports comentados

### 4.8 Corrigir typos e naming

- **Typo no diretorio:** `src/context/Distruibuicao/` -- renomear para `src/context/Distribuicao/` (atualizar todos os imports)
- **Typo no arquivo:** `src/pages/HomePage/DonwloadTableBtn.js` -- renomear para `DownloadTableBtn.js` (atualizar import em `HomePage/index.js:21`)
- **Naming inconsistente de estilo:** 3 arquivos usam `style.js` enquanto 359+ usam `styles.js` -- padronizar para `styles.js`:
    
    
    - `src/ui/components/Select/style.js`
    - `src/ui/interfaces/DropdownInput/style.js`
    - `src/ui/components/MultiInput/style.js`

### 4.9 Corrigir manipulacao direta do DOM (anti-pattern React)

- `src/components/Intimation/Configurations/index.js:101,106,110` -- `classList.add("error")` / `classList.remove("error")` -- usar estado React
- `src/pages/Guidelines/Detalhes/index.js:342,355,363,373` -- `classList.add/remove("hidden")` -- usar estado React
- `src/pages/Pautas/Detalhes/index.js:299,312,319,328` -- `classList.add/remove("hidden")` -- usar estado React
- `src/pages/Movimentacao/Detalhes/index.js:316,325` -- `classList.remove("hidden")` -- usar estado React
- `src/pages/CopiaIntegral/Detalhes/index.js:314,323` -- `classList.remove("hidden")` -- usar estado React
- `src/pages/Auth2F/index.js:64` -- `inputKey.value = ""` -- usar ref ou estado
- `src/components/TopAppBar/index.js:43` -- `document.getElementById().style.visibility` -- usar estado React
- `src/components/LegacyIntimation/Perfis/index.js:185,187,202-203` -- `innerHTML`, `classList` -- usar estado React
- `src/components/LegacyIntimation/Configurations/index.js:50,53,170,175,179` -- `innerHTML`, `classList` -- usar estado React
- `src/ui/components/TableAnt/index.jsx:627` -- `style.innerHTML` -- usar styled-components

### 4.10 Adicionar `alt` em imagens e `type` em botoes (acessibilidade)

- `src/pages/Intimations/Inbox/interfaces.jsx:52` -- `<img src={MailNotify} />` -- adicionar `alt`
- `src/pages/Intimations/Inbox/interfaces.jsx:192` -- `<img src={DocFiles} />` -- adicionar `alt`
- `src/pages/BotsPages/NotFoundBot.js:31` -- `<img src={notFoundSvg} />` -- adicionar `alt`
- `src/pages/OystrApi/index.js:266` -- `<img src={BotSelect} />` -- adicionar `alt`
- Adicionar `type="button"` em ~15+ botoes sem type: `Intimations/Executions`, `Intimations/SensibleProcess`, `components/Guidelines/ListItems`, `components/LegacyIntimation/ListItems`, `CopiaIntegral/Detalhes`, `Movimentacao/Detalhes`, `ui/components/TableCustomMenu`, `ui/components/TagsInput`, `ui/components/TableAnt/Cog`

### 4.11 Remover dependencias nao usadas do package.json

- `semantic-ui-calendar` -- nenhum import
- `semantic-ui-calendar-react` -- nenhum import
- `archiver` -- nenhum import
- `unzipper` -- nenhum import
- `rsuite` -- nenhum import
- `react-ace` -- nenhum import
- `react-ace-editor` -- nenhum import
- `start` -- possivelmente tool, verificar
- `yarn` -- tool, nao deveria estar em dependencies

### 4.12 Substituir `window.location` por react-router

- `src/pages/Monitoramento/MonitoramentoAddProcess/index.js:68` -- `window.location.href = "/oystr360/batchEdit"`
- `src/pages/Intimations/Comparison/ComparisonUpload.jsx:34` -- `window.location.href = "/intimation/compare"`
- `src/pages/Proconsumidor/index.jsx:160` -- `window.location.href = "/proconsumidor/info"`
- `src/services/base/homePage.js:22` -- `window.location = location`
- `src/pages/execution/BotExecutionGrid.js:194` -- `window.location = location`
- `src/pages/execution/BotExecutionPage.js:189` -- `window.location = location`

### 4.13 Mover URLs hardcoded para variaveis de ambiente ou constantes

- `src/services/distribuicao/index.js:7` -- `"http://localhost:3070"` hardcoded
- `src/services/legacyIntimations/index.js:9,12` -- URL GCS e `localhost:4000` hardcoded
- `src/services/monitoramento/index.js:9` -- `"http://localhost:3000"` hardcoded
- `src/services/intimations/executions.js:6` -- `"http://localhost:4000"` hardcoded
- `src/api/Classifier/index.js:55` -- `"https://api.preambulo.com.br/..."` hardcoded
- `src/pages/Protocols/DashProtocols/ModalNewProtocol/index.js:982` -- `"https://console4.oystr.com.br/..."` hardcoded
- `src/pages/Proconsumidor/index.jsx:17,23` -- URLs GCS e webhook hardcoded
- `src/components/TopAppBar/utils.js:113,131` -- URLs Movidesk hardcoded
- `src/services/intimations/profiles.js:121,128` -- URLs PJE hardcoded

### 4.14 Substituir error handling fraco por tratamento adequado

- `src/pages/Movimentacao/Perfis/index.js:48,101,112,123` -- `.catch((error) => console.log(error.response))` -- usar notificacao de erro
- `src/pages/Guidelines/Perfis/index.js:48,101,112,123` -- mesmo padrao
- `src/pages/Distribuicao/models.js:106,141,155` -- `.catch(console.log)`
- `src/pages/Monitoramento/models.js:235,308,347,365,523,541` -- `.catch(console.log)`
- `src/services/oraculo/index.js:11,19,27,35,43,52` -- `.catch` fraco em todos os metodos
- `src/api/Classifier/index.js` -- 10 `.catch(console.log)` em chamadas de API
- `src/api/Protocolos/endpoints.js:217,333` -- `.catch` que so loga

### 4.15 Remover `useEffect` duplicado e padroes legados

- `src/pages/Intimations/Inbox/IntimationContent.jsx:83-113` -- dois `useEffect` identicos para animacao de spinner
- `src/pages/Intimations/Inbox/IntimationContent.jsx:51-67` -- `ReactDOM.render` dentro de `useEffect` (padrao legado, risco de memory leak)

### 4.16 Resolver TODOs pendentes

- `src/pages/scheduler/home/Uploader.js:44` -- `// TODO: Execute "curl -v -X PUT..." on the client`
- `src/components/oystrCredentials/savedCredentials/index.jsx:401` -- `{/* TODO: align-self: center */}`
- `src/components/oystrCredentialsNew/savedCredentials/index.jsx:410` -- `{/* TODO: align-self: center */}`
- `src/pages/settings/ApiSettings.js:328` -- link placeholder `href="#todo"`

### 4.17 Corrigir ternarios aninhados (legibilidade)

- `src/pages/execution/ExecutionJournal.js:32` -- `!active ? (step === 0 ? 2 : 0) : step < 2 ? step + 1 : 0` -- extrair para funcao `getNextStep()`
- `src/pages/execution/ExecutionJournalGrid.js:32` -- mesmo padrao duplicado

### 4.18 Criar constantes para rotas e strings repetidas

- Centralizar rotas em `src/constants/routes.js`:
    
    
    - `"/pautas-novo"` -- 30+ ocorrencias
    - `"/protocols/dash_protocols"` -- 15+ ocorrencias
    - `"/protocols/upload_lote"`, `"/protocols/validate"`, `"/protocols/habilitacao"`
- Centralizar identificadores de interface em `src/constants/interfaces.js`:
    
    
    - `"open-intimation"` -- 4 ocorrencias
    - `"generate-report"` -- multiplas ocorrencias

### 4.19 Extrair numeros magicos para constantes

- Intervalos de polling: `60000 * 15` (15 min), `30000`, `2500`, `1500` -- criar `POLLING_INTERVALS`
- Timeouts de UI: `100`, `2000` -- criar `UI_TIMEOUTS`
- Limites de scroll: `scroll: { x: 300, y: 600 }` -- criar `TABLE_SCROLL_CONFIG`

---

## 5. Plano de Adocao de Boas Praticas

### 5.1 Padroes de design que fazem mais falta

**Container/Presentational (Custom Hooks + Pure Components):**

Os arquivos maiores (DashProtocols, Intimations, Perfis) misturam logica de negocio, data fetching e renderizacao no mesmo componente. Extrair a logica para custom hooks (`useProtocolsDash`, `useIntimationData`, `usePerfisForm`) e manter o componente apenas como "apresentacao" reduziria drasticamente a complexidade.

**Composition Pattern:**

`DashProtocols/index.js` com 3.398 linhas e um componente com comportamento de "god component". Deveria compor seus filhos via children/render props ao inves de renderizar tudo internamente.

**Early Returns:**

Varios componentes grandes tem if/else profundos para estados de loading/error/empty. Early returns simplificariam a leitura.

### 5.2 Performance

**Context excessivo:**

18+ Context Providers aninhados em `Routes`. Qualquer update em um provider causa re-render em cascata. Recomendacao: migrar mais estado para Zustand (que ja esta no projeto) e manter Context apenas para temas/auth/notificacao.

**Falta de memoizacao:**

`useMemo`/`useCallback` aparecem em apenas ~35 arquivos de ~760+. Componentes como `DataTable` (11 useState, 6 useEffect, 0 useMemo) recriam funcoes a cada render. `IntimationContent.jsx`: funcoes `getColumns` e `F` recriadas a cada render.

**Recomendacao de data fetching:**

Adotar **TanStack Query (react-query)** para substituir os `useEffect` manuais de fetching. Isso traria cache, invalidacao, retry, loading/error states automaticos e eliminaria dezenas de `useState` + `useEffect` repetitivos.

### 5.3 Design Tokens e Consistencia Visual

**Problemas identificados:**

- 80+ cores hex distintas fora do tema, enquanto `GlobalStyles.js` define apenas ~35 tokens
- Sem escala de espacamento -- valores como 5px, 7px, 11px, 13px, 17px, 22px, 26px usados aleatoriamente
- Sem escala tipografica -- font-sizes de 10px a 26px sem padrao
- Z-index sem escala -- valores de 0 a 2147483647, sem sistema
- 30+ breakpoints distintos, incluindo `699` sem unidade (bug)
- `!important` usado ~200+ vezes para sobrescrever Ant Design e Semantic UI
- 3 bibliotecas de UI (Ant Design, Semantic UI, Bootstrap) misturadas no mesmo render

**Recomendacao:** Criar `src/styles/tokens.js`:

- `COLORS` -- mapear as 80+ hex para variaveis semanticas
- `SPACING` -- escala de 4px (4, 8, 12, 16, 24, 32, 48, 64)
- `TYPOGRAPHY` -- escala de font-size (12, 14, 16, 18, 20, 24, 32)
- `Z_INDEX` -- escala (dropdown: 100, sticky: 200, modal: 1000, overlay: 2000, tooltip: 3000)
- `BREAKPOINTS` -- unificar em 4-5 valores (mobile: 480px, tablet: 768px, desktop: 1024px, wide: 1366px, ultra: 1920px)

### 5.4 Migrar componentes de classe para funcoes

100+ componentes ainda usam `class extends Component`. Priorizar os que precisam de refatoracao por outros motivos (ex: `DashProtocols`, `ExecutionJournal`, `Home` pages).

### 5.5 Roadmap de modernizacao (longo prazo)

1. **Fase 1 - Limpeza (2-3 sprints):** Remover codigo morto, console.logs, corrigir bugs, memory leaks, mas praticas rapidas
2. **Fase 2 - Deduplicacao e Design System (2-3 sprints):** Unificar modais, dropzones, DataTables, Perfis; criar hooks compartilhados; criar design tokens
3. **Fase 3 - Decomposicao (3-5 sprints):** Quebrar os 10 arquivos maiores em subcomponentes + custom hooks
4. **Fase 4 - Infra (3-5 sprints):** Migrar CRA para Vite, atualizar React 18, react-router v6, antd 5
5. **Fase 5 - Data Layer (2-3 sprints):** Adotar TanStack Query, consolidar estado em Zustand, reduzir Contexts
6. **Fase 6 - Qualidade (ongoing):** Adicionar ESLint strict rules, testes unitarios, CI com cobertura minima

# Auditoria Profunda: Console Oystr

## Contexto

Aplicacao React SPA matura (~1052 arquivos JS/JSX, 28+ modulos de paginas, 82 componentes compartilhados) com debito tecnico acumulado ao longo de anos. A stack base esta criticamente desatualizada (React 16.14, react-scripts 1.1.5/Webpack 3 de 2017, React Router 4.2.2). A aplicacao mistura 3 frameworks de UI (semantic-ui-react, antd, react-bootstrap), 4 bibliotecas de data (moment, date-fns, luxon, date-format), e padroes de componentes class + functional sem consistencia.

---

## URGENCIA 1 — Seguranca e Erros Criticos em Runtime

### 1.1 `dangerouslySetInnerHTML` sem sanitizacao

- **Arquivo**: `src/pages/Monitoramento/MonitoramentoTable/index.js:211`
- **Problema**: XSS — `aiInterpretation.result_html` renderizado direto, sem DOMPurify ou equivalente
- **Fix**: Instalar `dompurify` e sanitizar antes de injetar

### 1.2 Credenciais hardcoded no codigo fonte

- **Arquivo**: `src/services/handleApi.js`
- **Problema**: `X-Oystr-Auth: env.TOKEN` e headers de teste no source. Se alguem clonar o repo, tem acesso
- **Fix**: Garantir que tokens de teste so existam em `.env.local` (gitignored), nunca no codigo

### 1.3 Error handling silencioso na camada de servicos

- **Arquivos**: 35+ arquivos em `src/services/` (~173 catch blocks)
- **Problema**: Quase todos fazem `catch (err) { console.error(err) }` sem re-throw, retornando `undefined` — downstream recebe null e explode
- **Exemplos piores**: `src/services/monitoramento/index.js` (46 catches), `src/services/distribuicao/index.js` (23 catches)
- **Fix**: Criar padrao de error handling centralizado no interceptor do axios em `handleApi.js`. Catches devem re-throw ou retornar error objects consistentes

### 1.4 `ReactDOM.render()` fora do entry point

- **Arquivos**: `src/pages/execution/ExecutionJournal.js:184`, `ExecutionJournalGrid.js:184`, `src/pages/Intimations/Inbox/IntimationContent.jsx`
- **Problema**: `ReactDOM.render(portal, container)` dentro de `componentDidMount` — nao e limpo no unmount (memory leak), conflita com React lifecycle, vai quebrar no React 18
- **Fix**: Substituir por portais declarativos no JSX (`ReactDOM.createPortal` retornado no `render()`)

### 1.5 Null pointer em `rowGetter` (ExecutionJournal)

- **Arquivo**: `src/pages/execution/ExecutionJournal.js:726`
- **Problema**: `const { processo = null } = request` — `request` pode ser `null` (ja corrigido com `|| {}` nesta sessao, mas `ExecutionJournalGrid.js` precisa do mesmo fix)
- **Fix**: Aplicar `|| {}` defensivo em ambos os arquivos

---

## URGENCIA 2 — Warnings Massivos no Console

### 2.1 Lifecycle methods deprecados

- **Arquivos**: 
    - `src/pages/Protocols/DashProtocols/ModalNewProtocol/index.js:107` — `componentWillMount()`
    - `src/pages/Protocols/DashProtocols/ModalRetryProtocol/index.js:75` — `componentWillMount()`
    - `src/pages/BotsPages/index.js:187` — `UNSAFE_componentWillUpdate()`
- **Problema**: Warnings no console a cada render, vao ser removidos no React 18+
- **Fix**: Mover logica para `componentDidMount` ou converter para functional components com `useEffect`

### 2.2 DOM manipulation direta (31 arquivos!)

- **Principais**: `ExecutionJournal.js`, `ExecutionJournalGrid.js`
    - `document.getElementsByClassName("form-control")` — para mudar placeholder
    - `document.querySelector(".react-grid-checkbox-container")` — para injetar checkbox
- **Problema**: Race conditions com virtual DOM, warnings no StrictMode
- **Fix**: Usar `ref` + `useEffect`/`componentDidMount` com refs

### 2.3 Heranca de classes de UI library

- **Arquivo**: `ExecutionJournal.js` e `ExecutionJournalGrid.js`
    - `class CustomRow extends Row` (react-data-grid)
    - `class CustomTollbar extends Toolbar` (react-data-grid-addons — DEPRECATED)
- **Problema**: Fragil — qualquer update da lib quebra. A lib `react-data-grid-addons` nao recebe mais updates
- **Fix**: Composition ao inves de inheritance — wrapping components

### 2.4 `await this.setState()` (nao faz nada)

- **Arquivos**: `ExecutionJournal.js` (5+ ocorrencias), `ExecutionJournalGrid.js`
- **Problema**: `setState` nao retorna Promise; `await` nao espera nada. Pode causar bugs onde o codigo assume que o state ja atualizou
- **Fix**: Usar callback de `setState` ou converter para functional com `useState`

### 2.5 541 console.log/info/error em producao (189 arquivos)

- **Problema**: Polui o console, pode expor dados sensiveis
- **Fix**: Criar wrapper de logging ou usar babel-plugin-transform-remove-console para build de producao. O ESLint ja tem `no-console: 0` (desabilitado) — reabilitar

---

## URGENCIA 3 — Duplicacao e Manutencao

### 3.1 ExecutionJournal.js (1235 linhas) vs ExecutionJournalGrid.js (1079 linhas) — 90% identicos

- **Problema**: Bug fix precisa ser aplicado nos dois arquivos (como vimos hoje com `onGridSort`). Divergencias silenciosas se acumulam
- **Fix**: Extrair logica compartilhada para um hook ou HOC. Manter so as diferencas de UI em cada arquivo

### 3.2 `typeName()` — switch com 15 cases duplicado 2x em cada arquivo

- **Arquivos**: `ExecutionJournal.js:254-448` e `ExecutionJournalGrid.js` (identico)
- **Tambem**: `rowGetter()` tem outro switch de 15 cases para msgmErr com labels quase identicos
- **Fix**: Mapa de configuracao: ```js
    const TYPE_CONFIG = {
      INVALID: { label: "Invalido", color: DefaultColors.invalid },
      QUEUED: { label: "Nao enviado", color: DefaultColors.queued },
      ...
    }
    
    ```

### 3.3 `.map()` usado para side effects (7+ ocorrencias)

- **Arquivos**: `ExecutionJournal.js:787,790,851,875,885`, `ExecutionJournalGrid.js` (idem)
- **Problema**: `array.map(x => result.push(x))` — retorna array de `undefined`, ignora retorno
- **Fix**: Trocar por `.forEach()` ou simplesmente `result = array.filter(...).map(...)`

### 3.4 Arquivos gigantes

- `src/pages/Protocols/DashProtocols/index.js` — **3397 linhas**
- `src/components/Intimation/Perfis/index.js` — **1664 linhas**
- `src/pages/Intimations/Perfis/index.js` — **1203 linhas**
- **Fix**: Decompor em sub-componentes focados

### 3.5 Mutacao direta do state

- **Arquivos**: 7 arquivos, ex: `DashProtocols/index.js````js
    let filters = this.state.filterByColumn
    filters[column] = term.trim()  // muta this.state!
    
    ```
- **Fix**: Spread/clone antes de mutar: `let filters = { ...this.state.filterByColumn }`

---

## URGENCIA 4 — Arquitetura e Modernizacao

### 4.1 Mistura de 3 frameworks de UI

- **semantic-ui-react** (0.78.2) — 40 arquivos
- **antd** (4.17.0) — 40 arquivos
- **react-bootstrap** (1.0.0-beta.15) — uso menor
- **Problema**: CSS conflicts, bundle enorme (~800KB+ combinado), UX inconsistente
- **Recomendacao**: Consolidar em **antd** (mais moderno, ja em 40 arquivos). Migrar semantic-ui e bootstrap gradualmente

### 4.2 Quatro bibliotecas de data

- **moment** (2.29.4) — 111 imports em 104 arquivos (67KB minificado, deprecated)
- **date-fns** (2.14.0) — 23 imports
- **luxon** (3.3.0) — 3+ imports
- **date-format** (1.2.0) — imports esparsos
- **Recomendacao**: Consolidar em **date-fns** (tree-shakeable, moderno). Remover moment por ultimo

### 4.3 React 16.14 → React 18

- **Impacto**: Blocking para muitas melhorias (concurrent features, automatic batching, Suspense)
- **Pre-requisitos**: Corrigir todos os lifecycle deprecados (2.1), remover `ReactDOM.render` portais (1.4), atualizar react-scripts
- **Risco**: Alto — precisa de testes extensivos

### 4.4 react-scripts 1.1.5 → Vite ou CRA 5

- **Impacto**: Webpack 3 → Webpack 5 ou Vite. Build significativamente mais rapido, tree-shaking real, code-splitting
- **Recomendacao**: Migrar para **Vite** (mais moderno que CRA 5, build rapido, HMR excelente)

### 4.5 React Router 4.2.2 → v6

- **70 arquivos** usando `withRouter` HOC (deprecado)
- **Fix**: Migrar para hooks (`useNavigate`, `useParams`, `useLocation`)
- **Impacto**: Precisa tocar 35+ arquivos

### 4.6 Class → Functional Components

- **~181 class components** espalhados pelo codebase
- **Priorizar**: Contextos (`auth.js`, `Notify/index.js`) e paginas de alta complexidade
- **Approach**: Migrar file-by-file conforme tocam o codigo

### 4.7 ESLint 5.16 → ESLint 9+ com flat config

- **Problema**: ESLint 5 nao suporta regras modernas, `no-console: 0` permite lixo no console
- **Fix**: Atualizar ESLint, habilitar regras mais estritas

### 4.8 TypeScript (longo prazo)

- **151 ocorrencias de PropTypes** em 76 arquivos
- **Recomendacao**: Adotar TypeScript incrementalmente (renomear .js → .tsx conforme edita)

---

## URGENCIA 5 — Performance e Bundle

### 5.1 Bundle bloat — imports nao otimizados

- **antd** importado inteiro (700KB+)
- **lodash** importado inteiro (`import _ from "lodash"` em vez de `import get from "lodash/get"`)
- **moment** + locales (67KB+)
- **Fix**: Imports seletivos, babel-plugin-import para antd

### 5.2 Sem code-splitting

- `src/Routes/index.jsx` — 33KB, 100+ imports sincronos
- **Fix**: `React.lazy()` + `Suspense` para rotas

### 5.3 Sem testes

- **49 arquivos de teste** no total, maioria minimal
- **1 E2E test** (Cypress) — verifica navegacao basica
- **Recomendacao**: Adicionar Jest + React Testing Library para componentes criticos

---

## Resumo por Prioridade

<table id="bkmrk-urgencia-categoria-i"><thead><tr><th>Urgencia</th><th>Categoria</th><th>Itens</th><th>Esforco</th></tr></thead><tbody><tr><td>1</td><td>Seguranca/Runtime</td><td>XSS, credenciais, error handling, memory leaks, null pointers</td><td>2-3 dias</td></tr><tr><td>2</td><td>Console Warnings</td><td>Lifecycles, DOM direto, heranca, await setState, console.logs</td><td>3-5 dias</td></tr><tr><td>3</td><td>Duplicacao/Manutencao</td><td>Merge ExecutionJournal\*, refactor switches, .map→.forEach, state mutation</td><td>1-2 semanas</td></tr><tr><td>4</td><td>Arquitetura</td><td>UI framework, date libs, React 18, Vite, Router v6, class→functional</td><td>2-3 meses</td></tr><tr><td>5</td><td>Performance/Bundle</td><td>Tree-shaking, code-splitting, testes</td><td>1-2 meses</td></tr></tbody></table>

---

## Verificacao

Para validar as correcoes:

1. **Urgencia 1**: Testar paginas de Monitoramento, execucoes e servicos com network errors simulados
2. **Urgencia 2**: Rodar app com `<React.StrictMode>` e verificar console limpo
3. **Urgencia 3**: Garantir que ExecutionJournal e ExecutionJournalGrid compartilham logica sem divergencia
4. **Urgencia 4-5**: Bundle analyzer (`webpack-bundle-analyzer`) antes/depois para medir impacto

# Atualização do React

### Situação atual

<table id="bkmrk-pacote-vers%C3%A3o-atual-"><thead><tr><th>Pacote</th><th>Versão atual</th><th>Versão mais recente</th></tr></thead><tbody><tr><td>`react` / `react-dom`</td><td>16.14.0</td><td>19.x</td></tr><tr><td>`react-scripts` (CRA)</td><td>**1.1.5**</td><td>5.0.1 (último)</td></tr><tr><td>`webpack`</td><td>3.10.0</td><td>5.x</td></tr><tr><td>`eslint`</td><td>5.16.0</td><td>9.x</td></tr></tbody></table>

O gargalo principal **não é o React em si, é o `react-scripts 1.1.5`** — esta é a versão do Create React App de 2018. Ele fixa versões de webpack, babel e eslint de forma incompatível com React 17+.

---

### Caminho recomendado: React 16 → 17 → 18

Pule React 19 por ora — a maioria das libs do projeto ainda não tem suporte estável.

---

### Etapa 1: Atualizar `react-scripts` primeiro

Esta é a mudança mais crítica e arriscada.

```bash
yarn add react-scripts@5.0.1

```

**Quebras esperadas nesta etapa:**

- `eslint` precisa ser `>=7`. O projeto está em `5.16.0` — o CRA 5 instala o próprio internamente, mas conflitos podem ocorrer. Remova o `eslint` das `dependencies` e deixe o CRA gerenciar.
- `webpack` `3.x` nas `devDependencies` vai conflitar — remova-o, o CRA 5 usa webpack 5 internamente.
- `@types/react` e `@types/react-dom` precisam bater com a versão do React escolhida.

```bash
yarn remove eslint webpack

```

---

### Etapa 2: Atualizar para React 17

React 17 não adiciona features novas — é uma versão de transição. A principal mudança é o **novo JSX transform** (não precisa mais de `import React from 'react'` em todo arquivo).

```bash
yarn add react@17.0.2 react-dom@17.0.2 @types/react@17.0.80 @types/react-dom@17.0.25

```

**Quebras esperadas:**

- `react-router-dom@4.2.2` funciona com React 17, mas não com 18+. Pode ficar por ora.
- `reactour@1.18.3` — pode ter problemas. Verifique se há versão compatível.
- `rsuite@4.3.3` — não suporta React 17+. Precisaria ir para `rsuite@5.x`, que tem breaking changes de API.
- `react-data-grid@4.0.8` e `react-data-grid-addons@4.0.8` — versões muito antigas, abandonadas. O `react-data-grid` foi reescrito (v7+) com API completamente diferente.
- `semantic-ui-react@0.78.2` — funciona com React 17, mas não com 18. Para React 18 precisaria ir para `2.x`.
- `react-bootstrap@1.0.0-beta.15` — muito antiga, mas deve funcionar.
- `react-ace@9.0.0` — compatível com React 17.
- `react-datepicker@2.14.1` — compatível com React 17, mas versões mais novas têm melhorias.
- `antd@4.17.0` — compatível com React 17. Para React 18 precisaria do `antd@5.x`.

---

### Etapa 3: Atualizar para React 18 (mais complexo)

```bash
yarn add react@18.3.1 react-dom@18.3.1 @types/react@18.x @types/react-dom@18.x

```

**Mudança obrigatória na entry point** (`src/index.js`):

```diff
- import ReactDOM from 'react-dom'
- ReactDOM.render(<App />, document.getElementById('root'))
+ import { createRoot } from 'react-dom/client'
+ const root = createRoot(document.getElementById('root'))
+ root.render(<App />)

```

**Mudanças de comportamento que podem causar bugs silenciosos:**

- **Automatic batching**: React 18 agrupa todos os `setState` (inclusive dentro de `setTimeout`, `Promise`, eventos nativos). Código que dependia de re-renders imediatos pode se comportar diferente.
- **StrictMode duplo render**: Em desenvolvimento, React 18 monta/desmonta/remonta componentes para detectar side effects. Qualquer `useEffect` com lógica de inicialização única (como os `useRef(true)` de `isMounted` do projeto) pode ter comportamento inesperado.

**Libs que precisariam atualizar para React 18:**

<table id="bkmrk-lib-atual-problema-s"><thead><tr><th>Lib atual</th><th>Problema</th><th>Solução</th></tr></thead><tbody><tr><td>`semantic-ui-react@0.78.2`</td><td>Não suporta React 18</td><td>Migrar para `2.1.5` — tem breaking changes</td></tr><tr><td>`rsuite@4.3.3`</td><td>Não suporta React 18</td><td>Migrar para `5.x` — API diferente</td></tr><tr><td>`antd@4.17.0`</td><td>Suporta React 18 parcialmente</td><td>Migrar para `5.x` para suporte completo</td></tr><tr><td>`react-router-dom@4.2.2`</td><td>Não suporta React 18</td><td>Migrar para `v6` — API completamente diferente</td></tr><tr><td>`react-data-grid@4.0.8`</td><td>Abandonado</td><td>Reescrever partes que usam com `v7+`</td></tr><tr><td>`reactour@1.18.3`</td><td>Pode não suportar</td><td>Verificar ou substituir</td></tr></tbody></table>

---

### Avaliação de risco

<table id="bkmrk-etapa-esfor%C3%A7o-risco-"><thead><tr><th>Etapa</th><th>Esforço</th><th>Risco</th></tr></thead><tbody><tr><td>`react-scripts` 1 → 5</td><td>Médio</td><td>Alto — build pode quebrar completamente</td></tr><tr><td>React 16 → 17</td><td>Baixo</td><td>Médio — principalmente `rsuite` e `semantic-ui`</td></tr><tr><td>React 17 → 18</td><td>Alto</td><td>Muito alto — `react-router-dom` v4→v6 é reescrita de rotas</td></tr></tbody></table>

---

### Recomendação prática

Dado o tamanho do projeto e a quantidade de libs antigas, o caminho menos arriscado é:

1. **Agora**: `react-scripts` 1.1.5 → 5.0.1 (ganho de build speed, webpack 5, HMR melhor)
2. **Depois**: React 16 → 17 (praticamente sem mudanças de API)
3. **Futuramente**: Avaliar React 18 junto com migração de `react-router-dom` v6 e `antd` v5, que são as maiores mudanças de API do projeto

# Estratégia de Harness

## Contexto

O `oystr-console` hoje roda em produção sobre uma stack legada (React 16.14, react-router-dom 4.2, CRA 1.1.5/react-scripts, webpack 3) sem nenhuma automação de CI/CD: todo deploy é feito manualmente por um dev rodando `scripts/deploy.js` (git-flow release + `scp` + symlink-swap SSH num host único) ou `scripts/deploy-dev.js` (push de imagem Docker pro GCR). Cobertura de teste automatizado é quase inexistente (3 arquivos de unit test em todo o repo) e o único spec Cypress relevante está com `it.only` travado e aponta direto para produção.

Em paralelo, já existe uma reescrita completa em andamento na branch `main` (React 18 + Vite + Tailwind v4 + TypeScript incremental + Vitest + React Query), migrada página a página via branches `refactor/*`, rodando localmente lado a lado com o app legado (nginx multiplexando portas 3000/3001). Testes Vitest já começaram a aparecer organicamente nessa branch, sem um padrão formal ainda.

O objetivo desta estratégia é dar ao time uma rede de segurança e automação que sustente **deploys constantes** sem travar a velocidade atual, aproveitando o fluxo git-flow já em uso, cobrindo **os dois mundos em paralelo** (legado e v2), e validando os **5 whitelabels** (oystr, faz, preambulo, lawareTech, msmConsult) antes de cada release — tudo com base no que já existe no repo (Cypress, Mockoon, Dockerfile, git-flow, oystrFlow), sem redesenhar a infraestrutura de deploy atual no MVP.

Decisões já validadas com o usuário:

1. **CI**: Bitbucket Pipelines (o remoto já é `bitbucket.org/oystrdev/console`); revisável para runners self-hosted se o host de deploy exigir.
2. **Escopo**: harness cobre legado (`develop`/`master`) e v2 (`main`) em paralelo, não sequencialmente.
3. **Deploy**: manter o mecanismo atual (scp + symlink-swap via SSH) como alvo de automação no MVP; containerização (Dockerfile já existe) fica como evolução futura.
4. **Whitelabel**: validação automatizada (smoke) das 5 marcas conhecidas antes de release.

---

## Parte 1 — Arquitetura de Pipeline CI/CD (Bitbucket Pipelines)

### 1.1 Achados que mudam o desenho (levantados na exploração)

- `scripts/.local.json` **e** `oystrFlow/.local.json` estão versionados no git (contêm usernames SSH `username_o4`/`username_o2`) apesar do `.gitignore` listar só `/scripts/.local.json`. Risco de segurança — precisa ser destrackeado antes de qualquer coisa.
- Existe um script `scripts/deploy-feature-to-main.js` que faz `git merge <branch-atual> --no-edit` **direto em `main` dentro do próprio script**, sem passar por PR/review — não pode ser replicado no CI como está; precisa ser quebrado em (merge via PR normal) + (build/deploy no CI a partir do `main` já mergeado).
- Esse mesmo script grava sempre no destino fixo `/opt/oystr/console/main/console-v0.0.0` — hoje não há rollback possível no deploy do v2. Corrigir para versionar por `<version>`/short SHA, como já é feito no legado.
- Nenhum script `lint` existe hoje no `package.json` (nem legado nem v2), embora `eslint` esteja instalado nos dois. Precisa ser adicionado.
- `react-scripts test` precisa rodar com `CI=true` no pipeline, senão fica em modo watch e trava o job.
- `cy.visitProd()` em `cypress/support/commands.js` é hardcoded para produção — bloqueia qualquer uso seguro de Cypress em CI até virar uma `BASE_URL` configurável.
- O branch `main` já tem ~45 arquivos de teste sob `src/**/__tests__` (bem mais que os 3 do legado) — a v2 já está começando a puxar sua própria dívida de padronização de testes, é o momento de formalizar antes que isso vire bagunça.

### 1.2 Mapeamento git-flow → gatilhos de pipeline

<table id="bkmrk-branch%2Fevento-o-que-"><thead><tr><th>Branch/evento</th><th>O que roda</th><th>Automático ou manual</th></tr></thead><tbody><tr><td>PR para `develop` (de `feature/*`, `bugfix/*`)</td><td>lint (legado) + `CI=true yarn test` + `yarn build`</td><td>Automático, bloqueia merge</td></tr><tr><td>PR para `main` (de `feature/*`, `refactor/*`)</td><td>eslint/`tsc --noEmit` + `yarn test:run` (Vitest) + `vite build`</td><td>Automático, bloqueia merge</td></tr><tr><td>push em `develop`</td><td>tudo do PR + deploy automático para GCR dev (`deploy-dev.js`)</td><td>Automático</td></tr><tr><td>push em `main`</td><td>tudo do PR + deploy automático para `/opt/oystr/console/main/use` (ambiente "v2 preview")</td><td>Automático</td></tr><tr><td>push em `release/*`</td><td>build completo + Cypress e2e (contra dev/preview, nunca prod) + smoke de whitelabel (5 marcas)</td><td>Automático, bloqueante</td></tr><tr><td>push em `master` (pós `git flow release finish`/`hotfix finish`)</td><td>build de produção + deploy scp+symlink</td><td>Build automático; **deploy com approval manual** (Bitbucket Deployment "production" com reviewer obrigatório + `trigger: manual`)</td></tr><tr><td>Pipeline custom `preview-feature` (disparo manual, qualquer `feature/*`)</td><td>build + scp + `oystrFlow/set.js` (rota nginx por feature)</td><td>100% manual, sob demanda — formaliza o canary que hoje é feito via SSH ad-hoc</td></tr><tr><td>Pipeline custom `teardown-preview`</td><td>remove rota nginx + diretório</td><td>Manual</td></tr></tbody></table>

Um único `bitbucket-pipelines.yml` na raiz cobre os dois mundos: o Bitbucket seleciona o bloco por nome de branch, então cada bloco roda com a toolchain correta (Node 18/Yarn/react-scripts para legado, Node 20/Vite/Vitest para v2), sem duplicar arquivos de pipeline.

### 1.3 Esqueleto do `bitbucket-pipelines.yml`

```yaml
image: node:18-alpine

definitions:
  steps:
    - step: &lint-legacy
        name: Lint (legado)
        script:
          - yarn install --frozen-lockfile
          - yarn lint
    - step: &unit-legacy
        name: Testes unitários (Jest/react-scripts)
        script:
          - yarn install --frozen-lockfile
          - CI=true yarn test
    - step: &build-legacy
        name: Build produção (legado)
        script:
          - yarn install --frozen-lockfile
          - yarn build
        artifacts:
          - build/**

    - step: &lint-v2
        name: Lint/typecheck (v2)
        image: node:20-alpine
        script:
          - yarn install --frozen-lockfile
          - yarn lint
          - npx tsc --noEmit
    - step: &unit-v2
        name: Testes unitários (Vitest)
        image: node:20-alpine
        script:
          - yarn install --frozen-lockfile
          - yarn test:run
    - step: &build-v2
        name: Build produção (v2)
        image: node:20-alpine
        script:
          - yarn install --frozen-lockfile
          - yarn build
        artifacts:
          - build/**

pipelines:
  pull-requests:
    'feature/*':
      - step: *lint-legacy
      - step: *unit-legacy
    'bugfix/*':
      - step: *lint-legacy
      - step: *unit-legacy
    'refactor/*':
      - step: *lint-v2
      - step: *unit-v2

  branches:
    develop:
      - step: *lint-legacy
      - step: *unit-legacy
      - step: *build-legacy
      - step:
          name: Deploy dev (GCR)
          deployment: development
          script:
            - IMAGE_TAG=$(git rev-parse --short HEAD)
            - echo $GCP_SA_KEY_BASE64 | base64 -d > /tmp/gcp-key.json
            - gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
            - gcloud auth configure-docker --quiet
            - node scripts/deploy-dev.js "$IMAGE_TAG"

    main:
      - step: *lint-v2
      - step: *unit-v2
      - step: *build-v2
      - step:
          name: Deploy v2 preview
          deployment: v2-preview
          script:
            - apk add --no-cache openssh-client
            - eval $(ssh-agent -s)
            - echo "$PROD_SSH_PRIVATE_KEY" | base64 -d | ssh-add -
            - mkdir -p ~/.ssh && ssh-keyscan -H $PROD_SSH_HOST >> ~/.ssh/known_hosts
            - node scripts/ci/deploy-main.js

    'release/*':
      - step: *lint-legacy
      - step: *unit-legacy
      - step: *build-legacy
      - step:
          name: Cypress e2e (contra ambiente dev)
          script:
            - yarn install --frozen-lockfile
            - CYPRESS_BASE_URL=$DEV_BASE_URL npx cypress run
      - step:
          name: Smoke de whitelabel (5 marcas)
          script:
            - yarn install --frozen-lockfile
            - CYPRESS_BASE_URL=$DEV_BASE_URL npx cypress run --spec "cypress/e2e/integration/whitelabel-smoke.cy.js"

    master:
      - step: *build-legacy
      - step:
          name: Deploy produção (scp + symlink swap)
          deployment: production
          trigger: manual
          script:
            - apk add --no-cache openssh-client
            - eval $(ssh-agent -s)
            - echo "$PROD_SSH_PRIVATE_KEY" | base64 -d | ssh-add -
            - mkdir -p ~/.ssh && ssh-keyscan -H $PROD_SSH_HOST >> ~/.ssh/known_hosts
            - node scripts/ci/deploy-prod.js

  custom:
    preview-feature:
      - variables:
          - name: FEATURE_ROUTE
      - step:
          name: Build e publicar preview de feature branch
          script:
            - yarn install --frozen-lockfile
            - yarn build
            - apk add --no-cache openssh-client
            - eval $(ssh-agent -s)
            - echo "$PREVIEW_SSH_PRIVATE_KEY" | base64 -d | ssh-add -
            - mkdir -p ~/.ssh && ssh-keyscan -H $PREVIEW_SSH_HOST >> ~/.ssh/known_hosts
            - node oystrFlow/set.js "$FEATURE_ROUTE"
    teardown-preview:
      - variables:
          - name: FEATURE_ROUTE
      - step:
          name: Remover preview
          script:
            - node oystrFlow/set.js --remove "$FEATURE_ROUTE"

```

Notas:

- `deployment: production|development|v2-preview` usa **Bitbucket Deployments**: variáveis escopadas por ambiente, histórico visual de deploys, e reviewers obrigatórios configuráveis na UI — cobre o gate manual sem reinventar aprovação.
- `trigger: manual` no step de produção é a segunda camada de proteção.
- Cypress e2e só roda em `release/*` (nunca em `develop`/`main`, para não travar todo push por flakiness) e nunca contra produção.

### 1.4 Validação de whitelabel (5 marcas) — parte do pipeline

A resolução de tema é 100% runtime (hostname → `<span id="server-name">` → fetch de `whitelabels/<partner>/options.json` no GCS). Para testar isso em CI sem depender da infra externa que faz a substituição do `server_name`:

1. Criar `cypress/fixtures/whitelabels/<brand>.json` para as 5 marcas (oystr, faz, preambulo, lawareTech, msmConsult), com cópia sanitizada dos campos usados no render (logo, cores, favicon, nome).
2. Novo spec `cypress/e2e/integration/whitelabel-smoke.cy.js`:

```js
const brands = ["oystr", "faz", "preambulo", "lawareTech", "msmConsult"]

brands.forEach((brand) => {
  describe(`Whitelabel smoke - ${brand}`, () => {
    it("carrega tema e assets corretos", () => {
      cy.intercept("GET", "**/whitelabels/*/options.json", {
        fixture: `whitelabels/${brand}.json`,
      }).as("theme")

      cy.visit(Cypress.env("BASE_URL"))
      cy.get("#server-name").invoke("text", brand)
      cy.wait("@theme")
      cy.get("img[alt='logo']").should("be.visible")
      cy.document().its("title").should("not.be.empty")
    })
  })
})

```

3. Bloqueante em `release/*` — cobre "smoke por marca antes de deploy" sem exigir visual regression (Percy/Applitools) no MVP. Visual regression fica para uma fase futura.

### 1.5 Segredos — variáveis Bitbucket

<table id="bkmrk-vari%C3%A1vel-escopo-%28dep"><thead><tr><th>Variável</th><th>Escopo (Deployment)</th><th>Uso</th></tr></thead><tbody><tr><td>`GCP_SA_KEY_BASE64`</td><td>`development`</td><td>Substitui `gcloud` autenticado localmente em `deploy-dev.js`</td></tr><tr><td>`GCP_PROJECT`</td><td>`development`</td><td>`oystr-cloud-test`</td></tr><tr><td>`PROD_SSH_HOST`</td><td>`production`</td><td>`23.239.27.38`</td></tr><tr><td>`PROD_SSH_USER`</td><td>`production`</td><td>usuário de serviço dedicado (ex.: `oystr-ci`), não reaproveitar chave pessoal</td></tr><tr><td>`PROD_SSH_PRIVATE_KEY`</td><td>`production` (secured)</td><td>chave privada do usuário de serviço, `authorized_keys` restrito ao necessário</td></tr><tr><td>`PREVIEW_SSH_HOST/USER/PRIVATE_KEY`</td><td>`v2-preview`/custom</td><td>mesmo host, chave própria com permissão só em `main/` e `configs/flags.conf`</td></tr><tr><td>`DEV_BASE_URL`</td><td>repository variable</td><td>URL do ambiente onde Cypress roda (nunca produção)</td></tr></tbody></table>

Mudança mínima nos scripts extraídos (ex. `scripts/ci/deploy-prod.js`) para não quebrar uso local:

```js
const username = process.env.CI
  ? process.env.PROD_SSH_USER
  : JSON.parse(fs.readFileSync(LOCAL_USER_PATH, "utf8")).username_o4
const host = process.env.PROD_SSH_HOST || "23.239.27.38"

```

### 1.6 Arquivos a criar/editar (pipeline)

Criar:

- `bitbucket-pipelines.yml`
- `scripts/ci/deploy-prod.js` (build+scp+symlink extraído de `scripts/deploy.js`, lendo env vars em CI)
- `scripts/ci/deploy-main.js` (equivalente para v2, sem o `git merge` embutido)
- `scripts/ci/validate-env.js` (fail-fast se faltar env var exigida)
- `cypress/e2e/integration/whitelabel-smoke.cy.js` + `cypress/fixtures/whitelabels/*.json`
- `scripts/.local.json.example`, `oystrFlow/.local.json.example`

Editar:

- `package.json` — adicionar scripts `lint`, `test:ci`, `deploy:prod`
- `scripts/deploy.js` — remover scp/ssh embutido, vira só orquestração git-flow local
- `scripts/deploy-dev.js` — auth via `GCP_SA_KEY_BASE64` quando `CI=true`
- `oystrFlow/set.js` — aceitar env vars quando `process.env.CI`
- `cypress/support/commands.js` — `cy.visitProd()` → `cy.visitEnv()` lendo `Cypress.env("BASE_URL")`
- `cypress/e2e/integration/release.cy.js` — remover `it.only`, rodar contra `BASE_URL` configurável
- `.gitignore` — adicionar `/oystrFlow/.local.json`

---

## Parte 2 — Estratégia de Testes

### 2.0 O que a exploração confirmou

- **Legado**: os 3 testes existentes só cobrem funções puras, sem `@testing-library` instalado (nem transitivo — `react-scripts` 1.1.5 embute Jest 20 de 2017). Hoje só dá pra testar lógica pura com confiança; testar componente de classe exigiria Enzyme.
- **v2 (`main`)**: já existem **44 arquivos de teste** com Vitest + `@testing-library/react` 16 + `jest-dom`, em `src/pages/*/__tests__/*.test.{ts,tsx}` — mais maduro do que parecia; a tarefa é **formalizar o padrão que já existe**, não criar do zero. `@vitest/coverage-v8` não está instalado (gap real).
- `.cursor/plans/plano_refatoração_console_a4f45b78.plan.md` já exige, por página migrada: *"criar testes, rodar testes, rodar build, commitar"* — já é o roadmap de conteúdo da migração; falta formalizar o gate.
- `.cursor/rules/CODEBASE_GUIDE.md` (seção 13) está desatualizado (diz "não há testes unitários") — corrigir é parte do trabalho, é onde o padrão se fixa.
- Whitelabel é 100% mockável por rede: `GlobalThemeProvider` faz uma única chamada `GET .../whitelabels/<partner>/options.json`; não é preciso simular hostnames reais, basta interceptar essa chamada e variar o fixture.
- Já existe um mecanismo nativo de auth de teste: `env.logical.IS_TESTING` (`src/data/env/logical.js`) é `true` em `hostname === "localhost" && MODE !== "local"`, e nesse caso `handleApi.js` injeta headers fixos de teste (`account:1, user:1`) em vez de exigir login real — deve ser reaproveitado no Cypress em vez de usar credenciais de produção.
- Confirmada a topologia local `/test` (v2, :3000) vs resto (legado, :3001) via `nginx.dev.conf` — usável para E2E parametrizado por ambiente, com ressalva (ver 2.3).

### 2.1 Pirâmide de testes do legado — onde está o ROI

**Princípio**: não perseguir cobertura nos ~90 componentes de `src/components` nem nos componentes de classe de `src/pages` — UI fragmentada, sem tipos, está sendo substituída pela v2; teste de snapshot ali é frágil e não é mantido. O ROI real está em **lógica pura desacoplada de render**, já fisicamente separada em vários módulos:

- `src/shared/utils.js` (907 linhas, já citado como "candidato a divisão" na dívida técnica do projeto) — testar as funções puras antes/durante a divisão.
- `src/services/handleApi.js` — `customHeaders`, `getEndpoint`, `handleAnalytics` são funções puras com regras sensíveis (`IS_TESTING` decidindo headers de auth); bug aqui quebra a API inteira silenciosamente. **Prioridade máxima**.
- `src/shared/partners/index.jsx` (`getServerName`) — pequeno, mas crítico pro whitelabel. **Prioridade máxima**.
- `src/shared/tableDayStamps.js`, `row-formatter.js`, `directory-reader.js`, `bot-registry.js` — transformação de dados usada por várias telas.
- Reducers/lógica de `src/context/*` — extrair a parte `(state, action) => newState` para função pura testável, mesmo sem tocar no Context.
- Camada 2 (contrato de serviço): priorizar `src/services/*` (camada nova) sobre `src/api/*` (legado, saindo de uso) — testar URL/método/headers montados, não golden-master de resposta.
- Camada 3 (componente): só vale a pena para componente de classe grande que mistura lógica com render e não pode ser extraído facilmente — e mesmo assim, preferir extrair a lógica (Camada 1) a testar o componente inteiro. Evitar Enzyme salvo página fora do roadmap de migração dos próximos trimestres.

### 2.2 Padrão de testes para a v2 — formalizar o que já existe

Convenção já em uso no `main`, a tornar regra explícita:

- Localização: `src/pages/<Página>/__tests__/*.test.{ts,tsx}`, colocado ao lado do código.
- Nomenclatura: `<Componente>.test.tsx` (RTL), `utils.test.ts`/`models.test.ts`/`templates.test.ts` (lógica pura), `use<Hook>.test.tsx` (hooks).
- Padrão de mock: `vi.mock` no topo para `services`; componentes filhos irrelevantes mockados como `() => null` (evita re-renderizar árvores de Ant Design inteiras).
- Setup global único em `src/test/setup.js` (já importa `@testing-library/jest-dom`).

Ações concretas:

1. Atualizar `.cursor/rules/CODEBASE_GUIDE.md` seção 13 (está desatualizada) com a convenção acima como regra.
2. Adicionar coluna "Testes" na tabela de páginas pendentes do `.cursor/plans/plano_refatoração_console_a4f45b78.plan.md` — critério de "página migrada = done": teste de componente + teste de toda função extraída para utils/models + teste de todo hook extraído (critério é *presença* de teste, não % ainda).
3. Instalar `@vitest/coverage-v8`, rodar `vitest run --coverage` sem gate bloqueante inicialmente (baseline visível no PR).
4. Estender `lint-staged` para `.ts/.tsx` (hoje só cobre `.js/.jsx` no `main` — gap real).

### 2.3 Estratégia de regressão v1 → v2

1. **Testes de contrato compartilhados** (mais barato, mais valioso): `mocks/responses/{GET,POST,PUT,DELETE}` (Mockoon) já é usado pelos dois apps localmente — criar suíte de contrato que roda dos dois lados contra os *mesmos* fixtures (Jest no legado, Vitest na v2, ambos importando o mesmo arquivo de `mocks/responses/`). Uma mudança de contrato de API quebra os dois ao mesmo tempo.
2. **E2E parametrizado por baseUrl**, reaproveitando a topologia `/test` já existente (`nginx.dev.conf`) via `CYPRESS_TARGET=legacy|v2` no `cypress.config.js`. Ressalva: só faz sentido para specs "estruturais" (login, navegação, logout) ou páginas já migradas — não forçar paridade em páginas ainda não migradas.
3. **Checklist manual assistida** para o que não compensa automatizar ainda (responsividade, pixel-level): checklist curto por página migrada, executado lado a lado nas portas 3000/3001, como parte do critério de review do PR de migração.

### 2.4 Correção do Cypress atual

1. Remover `it.only` de `release.cy.js` (hoje só 1 teste roda de fato).
2. Eliminar `cy.visitProd()`/`PROD_BASE_URL`/`PROD_USER`/`PROD_PASS` de `commands.js`; substituir por `cy.visit()` no `baseUrl` de dev, autenticação via o mecanismo `IS_TESTING` já existente no código (headers de teste fixos, sem credenciais reais), e dados via Mockoon.
3. Quebrar `release.cy.js` em specs por domínio, aproveitando os `describe` já existentes como esqueleto: `settings.cy.js`, `equivalences.cy.js`, `credentials.cy.js`, `auth2f.cy.js`, `header-menu.cy.js`.
4. Atualizar `cypress.env.json.example` removendo `PROD_*`.

### 2.5 Validação de whitelabel (5 marcas)

Ferramenta: Cypress (já instalado — não introduzir Playwright só para isso). Mecanismo: interceptar a única chamada de rede que resolve o tema (`GET .../whitelabels/<partner>/options.json`) e variar o fixture por marca — não precisa simular hostname real.

```js
// cypress/e2e/whitelabel/whitelabel.cy.js
const brands = [
  { key: "oystr", fixture: "whitelabel/oystr.json" },
  { key: "faz", fixture: "whitelabel/faz.json" },
  { key: "preambulo", fixture: "whitelabel/preambulo.json" },
  { key: "lawareTech", fixture: "whitelabel/lawareTech.json" },
  { key: "msmConsult", fixture: "whitelabel/msmConsult.json" }
]

brands.forEach(({ key, fixture }) => {
  describe(`Whitelabel - ${key}`, () => {
    it("carrega tema, título e favicon corretos sem erros de console", () => {
      cy.intercept("GET", "**/whitelabels/**/options.json*", { fixture }).as("theme")
      cy.on("window:before:load", (win) => cy.stub(win.console, "error").as("consoleError"))

      cy.visit("/")
      cy.wait("@theme")

      cy.fixture(fixture).then((options) => {
        cy.title().should("eq", `${options.name} Control Panel`)
        cy.get('link[rel="icon"]').should("have.attr", "href", options.assets.favicon)
      })

      cy.get("@consoleError").should("not.have.been.called")
    })
  })
})

```

- Fixtures `cypress/fixtures/whitelabel/{oystr,faz,preambulo,lawareTech,msmConsult}.json`: cópias sanitizadas/congeladas do `options.json` real de cada marca, versionadas no repo.
- Checagem visual (fase futura, opcional): `cypress-image-snapshot` só na tela de Login (mais estável visualmente) — não tentar snapshot de todas as telas.
- Checagem estática complementar (sem Cypress): script validando que `public/brands/<marca>` tem os arquivos mínimos (favicon, logo).
- Portar a mesma suíte para a v2 assim que o tema for migrado — é regressão v1→v2 também (conecta com 2.3).

### 2.6 Gates de qualidade por fase (gate por diff, não por repositório inteiro)

Princípio: em um app com essa dívida histórica, exigir cobertura global travaria todo deploy. Gate no que o PR toca sustenta velocidade e ainda cria pressão de melhoria incremental.

<table id="bkmrk-fase-legado-v2-1-cyp"><thead><tr><th>Fase</th><th>Legado</th><th>v2</th></tr></thead><tbody><tr><td>1</td><td>Cypress corrigido deve passar — bloqueante. Sem cobertura mínima ainda.</td><td>`vitest run` já deve passar — bloqueante (só falta formalizar no pipeline).</td></tr><tr><td>2</td><td>Testes de função pura novos rodam no CI, reportam cobertura sem bloquear. ESLint em modo relatório.</td><td>Cobertura reportada sem threshold. Teste correspondente exigido por revisão manual em PR de migração de página. `lint-staged` estendido a `.ts/.tsx`.</td></tr><tr><td>3</td><td>ESLint bloqueante nos arquivos tocados pelo PR (não o repo inteiro). Threshold só nos módulos de função pura priorizados.</td><td>Cobertura mínima bloqueante em arquivos novos/alterados (`vitest run --coverage --changed`). TS `strict` incremental por pasta migrada. Suíte de whitelabel como gate obrigatório pré-deploy.</td></tr></tbody></table>

---

## Roadmap consolidado

**Fase 1 — Fundação e correções críticas**

- `bitbucket-pipelines.yml` com lint+unit test em PRs para `develop` e `main` (bloqueante); adicionar script `lint` ao `package.json` dos dois branches; `CI=true` no `test` legado
- Segurança: destrackear `scripts/.local.json`/`oystrFlow/.local.json`, criar `.example`, adicionar `gitleaks`; provisionar usuário de serviço SSH dedicado + service account GCP
- Cypress: remover `it.only`, remover `visitProd`/credenciais de produção, apontar para dev/Mockoon; quebrar `release.cy.js` em specs por domínio
- Formalizar convenção de testes v2 na documentação (`CODEBASE_GUIDE.md`, tabela de páginas pendentes com coluna "Testes")
- Testes de função pura para os 2 módulos de maior blast radius: `src/services/handleApi.js` e `src/shared/partners/index.jsx`
- Instalar `@vitest/coverage-v8` no `main`, reportar cobertura sem gate

**Fase 2 — Deploy automático não-produtivo + consolidação de testes**

- Deploy automático `develop` → GCR; deploy automático `main` → ambiente v2-preview (novo script, sem `git merge` embutido, versionado por SHA — corrige `deploy-feature-to-main.js`)
- Ativar Cypress em `release/*` contra dev/preview
- Suíte de whitelabel automatizada (5 marcas), ainda não bloqueante
- Ampliar cobertura de funções puras do legado (`utils.js`, `tableDayStamps.js`, `row-formatter.js`, `bot-registry.js`) e 2-3 domínios de `src/services/*` de maior volume
- Teste correspondente exigido (bloqueante por revisão) como critério de "página migrada = done" nas próximas páginas do roadmap de migração
- Primeira suíte de testes de contrato compartilhados legado↔v2 para 2-3 endpoints críticos
- Estender `lint-staged` para `.ts/.tsx`; ESLint em modo relatório nos dois branches

**Fase 3 — Gate de produção + whitelabel bloqueante + maturidade de testes**

- Pipeline de `master`: build automático + deploy manual-gated (Bitbucket Deployment "production" com reviewer); extrair `scripts/ci/deploy-prod.js`
- `whitelabel-smoke.cy.js` como gate obrigatório em `release/*`
- ESLint bloqueante por diff nos dois branches; cobertura bloqueante por diff na v2; TS `strict` incremental por pasta migrada
- E2E parametrizado por baseUrl (`legacy`/`v2`) para fluxos estruturais e páginas já migradas

**Fase 4 — Preview/canary formalizado**

- Pipelines custom `preview-feature`/`teardown-preview` reaproveitando `oystrFlow/set.js` com env vars (tira o canary do SSH ad-hoc pessoal)
- Reabilitar e expandir specs desativadas

**Fase 5 — Evolução futura (fora do MVP)**

- Migrar deploy scp+symlink para o Dockerfile/docker-compose já existente
- Visual regression (Percy/Applitools ou `cypress-image-snapshot`) para whitelabel e telas críticas
- Avaliar runners self-hosted se o allowlist de IP do Bitbucket Cloud não for aceitável
- Revisar/descontinuar testes duplicados do legado assim que a página v2 correspondente estabilizar

---

### Arquivos críticos

- `bitbucket-pipelines.yml` (novo)
- `scripts/deploy.js`, `scripts/deploy-dev.js`, `oystrFlow/set.js`
- `cypress/support/commands.js`, `cypress/e2e/integration/release.cy.js`, `cypress.config.js`
- `src/services/handleApi.js`, `src/shared/partners/index.jsx`, `src/context/GlobalTheme/index.js`, `src/services/googleStorage/index.js`
- `.cursor/rules/CODEBASE_GUIDE.md` e `.cursor/plans/plano_refatoração_console_a4f45b78.plan.md` (branch `main`)
- `package.json` (ambos os branches, `develop` e `main`)

## Verificação

- `bitbucket-pipelines.yml` validado localmente com o [Pipe Validator](https://bitbucket-pipelines.atlassian.io/validator) ou `bitbucket-pipelines validate` antes do primeiro push
- Cada fase entra primeiro em modo não-bloqueante (relatório) antes de virar gate — validar rodando o pipeline num PR de teste e confirmando que falso-positivo não trava merge indevido
- Testes novos (função pura + whitelabel) rodados localmente via `yarn test`/`yarn test:run`/`npx cypress run` antes de subir ao CI
- Deploy automatizado de `develop`→GCR e `main`→preview validado num ambiente não-produtivo antes de tocar no pipeline de `master` (produção)
- Suíte de whitelabel validada manualmente contra pelo menos 1 marca real (comparar fixture vs GCS ao vivo) antes de virar gate bloqueante