Skip to content

chore(eslint): fix 21 quick-win errors (Onda 5 PR 5.1)#109

Merged
adm01-debug merged 3 commits into
mainfrom
chore/onda-5-pr-5.1-eslint-quick-wins
May 9, 2026
Merged

chore(eslint): fix 21 quick-win errors (Onda 5 PR 5.1)#109
adm01-debug merged 3 commits into
mainfrom
chore/onda-5-pr-5.1-eslint-quick-wins

Conversation

@adm01-debug
Copy link
Copy Markdown
Owner

@adm01-debug adm01-debug commented May 9, 2026

Resumo

Reduz ESLint errors de 164 → 143 (-21, -13%) corrigindo as categorias de baixo risco.

Antes Depois Δ
164 errors 143 errors -21
1332 warnings 1330 warnings -2

Mudanças

🗑️ Deletado: .eslintrc.tailwind.js

Arquivo órfão com sintaxe TypeScript (import type, Linter.Config, export default) em extensão .js. Não é referenciado em eslint.config.*, package.json, nem .github/. Causava Parsing error: Unexpected token { em todo lint run.

🔧 no-useless-escape (10)

Removidas barras invertidas desnecessárias em regex char classes (onde -, (, ), *, +, ., [, / são literais):

  • scripts/ds-config.ts:57 (negative lookahead)
  • src/features/auth/components/PasswordStrengthMeter.tsx:22 (\[ \/)
  • src/features/inbox/components/chat/MarkdownPreview.tsx:19 (\*)
  • src/features/inbox/components/linkPreviewUtils.ts:2 (2x \+)
  • src/features/inbox/hooks/useSipClient.ts:44 (\( \))
  • src/lib/csvUtils.ts:154 (\.)
  • src/lib/security.ts:115 (\-)

🔧 prefer-const (3)

letconst quando há apenas uma atribuição:

  • src/features/inbox/hooks/useScheduledMediaUpload.ts: removida declaração let mediaUrl solta, inlined const mediaUrl = signedData?.signedUrl
  • src/pages/admin/AdminStressTestPage.tsx: mesmo padrão pra messageId
  • src/hooks/useActionFeedback.ts:52: mantido como let com // eslint-disable-next-line prefer-const — closure assigned depois da definição do toast que usa a variável, refactor exigiria restruturação significativa

🔧 no-empty (4)

Adicionado /* intentionally empty */ em catch blocks vazios intencionalmente:

  • src/components/security/RateLimitRealtimeAlerts.tsx:83
  • src/features/connections/hooks/useConnectionsManager.ts:164
  • src/hooks/useThemeAudit.ts:59
  • src/lib/evolutionDirectClient.ts:18

🔧 no-case-declarations (3)

case 'X': envolvido em case 'X': { ... } para criar escopo léxico:

  • src/components/contacts/ContactsRichView.tsx:125 (case 'f')
  • src/hooks/useCSAT.ts:31 (case 'week')
  • src/hooks/useCSAT.ts:35 (case 'month')

Validação

  • bun run build → built in 60s
  • bun run lint → 143 errors (era 164)
  • ✅ Build sem warnings novos
  • ✅ Mudanças mecânicas, não alteram lógica de negócio

Backlog Onda 5 (próximos PRs)

  • PR 5.2: 14 no-explicit-any + 10 no-unused-expressions + 6 outros (~30 errors)
  • PR 5.3: 108 no-restricted-imports (DDD: 106 INTRA-feature codemod + 2 cross-feature barrel)

Governance

  • 17 files changed, 20 insertions, 38 deletions (delete líquida)
  • PEQUENA conforme governança, mas abrindo PR pra registro/CI verde
  • Stress-test: 7 cenários simulados antes da execução

Refs: backlog Onda 5 em /workspace/notes/

Summary by CodeRabbit

  • Chores

    • Removida configuração de lint específica do Tailwind.
    • Supressão intencional de exceções em pontos de reprodução de áudio, storage e parsing.
    • Várias atualizações em expressões regulares para validação, detecção de URLs, sanitização de nomes de arquivo, normalização de telefones e reconhecimento de cores literais.
    • Ajuste no conjunto de caracteres aceitos para requisito de caractere especial no medidor de senha.
  • Refactor

    • Melhorias de escopo e uso de const/let para maior clareza.
    • Pequena alteração no atalho de teclado para focar busca e exibir notificação.

Review Change Stack

Reduces ESLint errors from 164 → 143 (-13%) by fixing low-risk categories:

**Deleted (1):**
- .eslintrc.tailwind.js — orphan file with TS syntax in .js extension,
  not referenced anywhere (eslint.config.*, package.json, .github/).
  Caused 'Parsing error: Unexpected token {' on every lint run.

**no-useless-escape (10):** removed unnecessary backslashes in regex char classes
- scripts/ds-config.ts:57 (negative lookahead)
- src/features/auth/components/PasswordStrengthMeter.tsx:22 (\[ \/)
- src/features/inbox/components/chat/MarkdownPreview.tsx:19 (\*)
- src/features/inbox/components/linkPreviewUtils.ts:2 (2x \+)
- src/features/inbox/hooks/useSipClient.ts:44 (\( \))
- src/lib/csvUtils.ts:154 (\.)
- src/lib/security.ts:115 (\-)

**prefer-const (3):** let → const where assignment happens once
- src/features/inbox/hooks/useScheduledMediaUpload.ts: removed dangling
  let declaration, inlined const at point of assignment
- src/pages/admin/AdminStressTestPage.tsx: same pattern
- src/hooks/useActionFeedback.ts:52: kept as let with eslint-disable
  comment (closure assigned after toast definition uses it — refactor
  would need significant restructure)

**no-empty (4):** added /* intentionally empty */ comments
- src/components/security/RateLimitRealtimeAlerts.tsx:83
- src/features/connections/hooks/useConnectionsManager.ts:164
- src/hooks/useThemeAudit.ts:59
- src/lib/evolutionDirectClient.ts:18

**no-case-declarations (3):** wrapped case body in braces
- src/components/contacts/ContactsRichView.tsx:125 (case 'f')
- src/hooks/useCSAT.ts:31 (case 'week')
- src/hooks/useCSAT.ts:35 (case 'month')

Validations:
- bun run build → ✓ built in 60s
- bun run lint → 143 errors (was 164), 1330 warnings (was 1332)

Backlog remaining for Onda 5:
- PR 5.2: 14 no-explicit-any + 10 no-unused-expressions + ~6 outros
- PR 5.3: 108 no-restricted-imports (DDD architecture refactor)
Copilot AI review requested due to automatic review settings May 9, 2026 02:20
@vercel
Copy link
Copy Markdown

vercel Bot commented May 9, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
zapp-web Ready Ready Preview, Comment May 9, 2026 10:07am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 9, 2026

Walkthrough

Remove .eslintrc.tailwind.js; normaliza múltiplas regex; padroniza blocos catch para catch { /* intentionally empty */ }; e aplica pequenos refatores de escopo/const e uma supressão ESLint, mantendo comportamento funcional.

Changes

Limpeza de Configuração e Padronização Técnica

Layer / File(s) Summary
Remoção de Configuração
.eslintrc.tailwind.js
Remove configuração ESLint específica do Tailwind incluindo plugin, regras de classes e settings; arquivo deletado.
Simplificação de Padrões Regex
scripts/ds-config.ts, src/features/auth/components/PasswordStrengthMeter.tsx, src/features/inbox/components/chat/MarkdownPreview.tsx, src/features/inbox/components/linkPreviewUtils.ts, src/lib/csvUtils.ts, src/features/inbox/hooks/useSipClient.ts, src/lib/security.ts
Ajusta múltiplas regex removendo escapes desnecessários e normalizando classes de caracteres (cores literais, caractere de senha, bold WhatsApp, URL matching, sanitização de CSV, normalização de telefone, JID).
Padronização de Tratamento de Erros
src/components/security/RateLimitRealtimeAlerts.tsx, src/features/connections/hooks/useConnectionsManager.ts, src/hooks/useThemeAudit.ts, src/lib/evolutionDirectClient.ts
Converte blocos catch vazios para catch { /* intentionally empty */ }, explicitando a supressão de exceções.
Refatoração de Escopo de Variáveis
src/components/contacts/ContactsRichView.tsx, src/features/inbox/hooks/useScheduledMediaUpload.ts, src/hooks/useCSAT.ts, src/pages/admin/AdminStressTestPage.tsx
Local refactor: case 'f' com bloco, remoção de let mediaUrl em favor de const, blocos case isolados para week/month, e messageId derivado inline.
Supressões e Contexto
src/hooks/useActionFeedback.ts
Adiciona // eslint-disable-next-line prefer-const para variável de closure em withUndo.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • adm01-debug/zapp-web#100: Também altera src/hooks/useThemeAudit.ts (catch handling), mostrando sobreposição em padronização de tratamento de erros.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed O título descreve com precisão as mudanças do PR: correção de 21 erros ESLint rápidos, com referência clara ao contexto Onda 5 PR 5.1.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/onda-5-pr-5.1-eslint-quick-wins

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Reduz a contagem de erros do ESLint através de correções mecânicas de baixo risco (ex.: no-useless-escape, prefer-const, no-empty, no-case-declarations) e remove uma config Tailwind ESLint órfã que quebrava o parsing.

Changes:

  • Remoção de .eslintrc.tailwind.js (arquivo órfão com sintaxe TS em .js).
  • Simplificação de regex/char classes para resolver no-useless-escape e pequenos ajustes de escopo (no-case-declarations) e prefer-const.
  • Marcação de catch {} intencionalmente vazios com comentário para satisfazer no-empty.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/pages/admin/AdminStressTestPage.tsx prefer-const ao derivar messageId do resultado do envio
src/lib/security.ts Ajuste em regex de validação de JID removendo escape desnecessário
src/lib/evolutionDirectClient.ts Marca catch vazio como intencional (no-empty)
src/lib/csvUtils.ts Ajuste em regex de sanitização de filename (atenção: risco de regex inválida)
src/hooks/useThemeAudit.ts Marca catch vazio como intencional (no-empty)
src/hooks/useCSAT.ts Adiciona escopo em case para evitar no-case-declarations
src/hooks/useActionFeedback.ts Documenta exceção de prefer-const para variável atribuída após definição do toast
src/features/inbox/hooks/useSipClient.ts Simplifica char class de regex para normalizar telefone (no-useless-escape)
src/features/inbox/hooks/useScheduledMediaUpload.ts prefer-const ao obter signed URL (mediaUrl)
src/features/inbox/components/linkPreviewUtils.ts Simplifica escapes em regex de URL (no-useless-escape)
src/features/inbox/components/chat/MarkdownPreview.tsx Simplifica regex de negação em char class (no-useless-escape)
src/features/connections/hooks/useConnectionsManager.ts Marca catch vazio como intencional (no-empty)
src/features/auth/components/PasswordStrengthMeter.tsx Simplifica escapes em regex de caracteres especiais (no-useless-escape)
src/components/security/RateLimitRealtimeAlerts.tsx Marca catch vazio como intencional (no-empty)
src/components/contacts/ContactsRichView.tsx Adiciona bloco em case para evitar no-case-declarations
scripts/ds-config.ts Remove escape desnecessário em lookahead (no-useless-escape)
.eslintrc.tailwind.js Removido (config órfã que causava erro de parsing)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/csvUtils.ts Outdated
const parts = [prefix, suffix, date].filter(Boolean).join('-');
// Strip unsafe filename chars
return parts.replace(/[^a-zA-Z0-9_\-\.]/g, '_') + '.csv';
return parts.replace(/[^a-zA-Z0-9_\-.]/g, '_') + '.csv';
Comment thread src/hooks/useActionFeedback.ts Outdated
return new Promise((resolve) => {
const { description, undoDuration = 5000, onUndo, onConfirm } = options;
let undone = false;
// eslint-disable-next-line prefer-const -- closure: assigned at line 57 after toast definition uses it
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/features/inbox/hooks/useScheduledMediaUpload.ts (1)

47-52: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Falha silenciosa ao gerar signed URL.

Se createSignedUrl retornar erro, o código segue com mediaUrl indefinida sem notificar o usuário. Isso quebra a promessa de tratamento explícito de erro e pode agendar mídia sem URL válida.

💡 Sugestão de correção
-      const { data: signedData , error } = await supabase.storage
+      const { data: signedData, error: signedUrlError } = await supabase.storage
         .from('whatsapp-media')
         .createSignedUrl(fileName, 604800);
 
-      const mediaUrl = signedData?.signedUrl;
+      if (signedUrlError || !signedData?.signedUrl) {
+        log.error('Scheduled media signed URL generation failed:', signedUrlError);
+        toast({
+          title: 'Erro ao preparar anexo',
+          description: `Upload concluído, mas não foi possível gerar URL temporária para "${attachment.name}". A mensagem será agendada sem o anexo.`,
+          variant: 'destructive',
+        });
+        return { mediaUrl: undefined, messageType: 'text' };
+      }
+
+      const mediaUrl = signedData.signedUrl;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/inbox/hooks/useScheduledMediaUpload.ts` around lines 47 - 52,
The code in useScheduledMediaUpload calls
supabase.storage.from('whatsapp-media').createSignedUrl and then proceeds using
signedData.signedUrl without checking error or undefined, which can silently
schedule media with no URL; update the logic in useScheduledMediaUpload to check
the returned error and signedData (and mediaUrl) after createSignedUrl, handle
failures by returning or throwing an explicit error (or invoking the existing
user-notification/error handler), and prevent scheduling when mediaUrl is falsy;
reference createSignedUrl, signedData, error, mediaUrl and the hook
useScheduledMediaUpload when making the fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/inbox/hooks/useSipClient.ts`:
- Around line 44-45: The phone sanitization in useSipClient.ts currently uses
phone.replace(/[\s\-()]/g, '') which still allows special characters into the
PostgREST .or() filter and can enable injection; change the cleaning to remove
all non-digits (usePhone -> create n from phone by stripping using a non-digit
regex) so the value passed to supabase.from('contacts').select(...).or(...) is
only digits, and fail/return early if result is empty; also fix the analogous
issue in useNewConversation.ts where searchQuery is interpolated into
.or(`name.ilike.%${searchQuery}%,phone.ilike.%${searchQuery}%`) by
validating/sanitizing searchQuery (either allow a safe subset of characters or
escape/normalize percent/quote characters, or reject unsafe input) before
building the query.

In `@src/hooks/useActionFeedback.ts`:
- Around line 52-53: The timeoutId variable in useActionFeedback is typed as
NodeJS.Timeout which couples to `@types/node`; change its type to
ReturnType<typeof setTimeout> to match the project's cross-runtime pattern (as
used in src/lib/debounce.ts and src/pages/VerifyEmail.tsx). Update the
declaration of timeoutId (and any related setTimeout/clearTimeout uses inside
the useActionFeedback hook) to use ReturnType<typeof setTimeout> and remove any
NodeJS-specific typing so the hook remains runtime-agnostic.

---

Outside diff comments:
In `@src/features/inbox/hooks/useScheduledMediaUpload.ts`:
- Around line 47-52: The code in useScheduledMediaUpload calls
supabase.storage.from('whatsapp-media').createSignedUrl and then proceeds using
signedData.signedUrl without checking error or undefined, which can silently
schedule media with no URL; update the logic in useScheduledMediaUpload to check
the returned error and signedData (and mediaUrl) after createSignedUrl, handle
failures by returning or throwing an explicit error (or invoking the existing
user-notification/error handler), and prevent scheduling when mediaUrl is falsy;
reference createSignedUrl, signedData, error, mediaUrl and the hook
useScheduledMediaUpload when making the fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a21aefb0-df2a-4842-9b9a-ae94783892a8

📥 Commits

Reviewing files that changed from the base of the PR and between 43f8e40 and 9e5c649.

📒 Files selected for processing (17)
  • .eslintrc.tailwind.js
  • scripts/ds-config.ts
  • src/components/contacts/ContactsRichView.tsx
  • src/components/security/RateLimitRealtimeAlerts.tsx
  • src/features/auth/components/PasswordStrengthMeter.tsx
  • src/features/connections/hooks/useConnectionsManager.ts
  • src/features/inbox/components/chat/MarkdownPreview.tsx
  • src/features/inbox/components/linkPreviewUtils.ts
  • src/features/inbox/hooks/useScheduledMediaUpload.ts
  • src/features/inbox/hooks/useSipClient.ts
  • src/hooks/useActionFeedback.ts
  • src/hooks/useCSAT.ts
  • src/hooks/useThemeAudit.ts
  • src/lib/csvUtils.ts
  • src/lib/evolutionDirectClient.ts
  • src/lib/security.ts
  • src/pages/admin/AdminStressTestPage.tsx
💤 Files with no reviewable changes (1)
  • .eslintrc.tailwind.js

Comment on lines +44 to 45
const n = phone.replace(/[\s\-()]/g, '');
const { data, error } = await supabase.from('contacts').select('id').or(`phone.eq.${n},phone.eq.+${n},phone.ilike.%${n.slice(-8)}%`).limit(1).maybeSingle();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verifica onde a string .or(...) está sendo montada com interpolação direta
rg -nP --type=ts -C3 '\.or\(`phone\.eq\.\$\{n\},phone\.eq\.\+\$\{n\},phone\.ilike\.\%\$\{n\.slice\(-8\)\}\%`\)'
rg -nP --type=ts -C3 '\bfindContactByPhone\s*\('

Repository: adm01-debug/zapp-web

Length of output: 1480


🏁 Script executed:

# Lê o arquivo completo para entender o contexto
cat -n src/features/inbox/hooks/useSipClient.ts | head -80

Repository: adm01-debug/zapp-web

Length of output: 4749


🏁 Script executed:

# Procura por outras instâncias de phone normalization ou queries diretas ao Supabase
rg -n 'phone\s*=' src/features/inbox/hooks/useSipClient.ts -A 2

Repository: adm01-debug/zapp-web

Length of output: 46


🏁 Script executed:

# Verifica se há migrations ou schema que defina o tipo do campo phone
fd -e sql -e ts | xargs rg -l 'contacts.*phone' | head -5

Repository: adm01-debug/zapp-web

Length of output: 315


🏁 Script executed:

# Procura por outros usos de .or() com interpolação de strings
rg -n '\.or\(`' src/features/inbox/hooks/ -A 1

Repository: adm01-debug/zapp-web

Length of output: 1226


🏁 Script executed:

# Procura por migrations que definem o campo phone
fd -e sql | xargs grep -l 'phone' 2>/dev/null | head -10

Repository: adm01-debug/zapp-web

Length of output: 824


🏁 Script executed:

# Verifica policies de RLS para contacts
fd -e sql | xargs grep -A 3 'policy.*contacts' 2>/dev/null | head -20

Repository: adm01-debug/zapp-web

Length of output: 2142


🏁 Script executed:

# Verifica se há sanitização em useNewConversation que também tem o mesmo padrão
sed -n '40,60p' src/features/inbox/hooks/useNewConversation.ts

Repository: adm01-debug/zapp-web

Length of output: 765


🏁 Script executed:

# Procura pela definição mais recente do campo phone nas migrations
rg -A 5 'CREATE TABLE.*contacts|ALTER TABLE.*contacts' supabase/migrations/ | head -40

Repository: adm01-debug/zapp-web

Length of output: 4262


🏁 Script executed:

# Verifica o tipo do campo phone
rg 'phone\s+(text|varchar|character|numeric|bigint)' supabase/migrations/

Repository: adm01-debug/zapp-web

Length of output: 1293


🏁 Script executed:

# Verifica se há função ou trigger que normaliza phone
rg -i 'normalize.*phone|phone.*format' supabase/

Repository: adm01-debug/zapp-web

Length of output: 5370


Sanitização insuficiente permite injeção de filtro PostgREST

O regex atual /[\s\-()]/g deixa passar caracteres especiais (vírgula, aspas, ponto, etc.) que quebram a sintaxe do filtro .or(). Uma entrada como 123",phone.eq.456,phone.ilike.% passa intacta, corrompendo a query.

Use /\D/g para manter apenas dígitos (números de telefone só precisam disso):

-      const n = phone.replace(/[\s\-()]/g, '');
+      const n = phone.replace(/\D/g, '');
+      if (!n) return null;
       const { data, error } = await supabase.from('contacts').select('id').or(`phone.eq.${n},phone.eq.+${n},phone.ilike.%${n.slice(-8)}%`).limit(1).maybeSingle();

⚠️ Mesmo problema existe em useNewConversation.ts:51: searchQuery não tem sanitização e passa direto para .or(\name.ilike.%${searchQuery}%,phone.ilike.%${searchQuery}%`)`. Adicione validação lá também.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const n = phone.replace(/[\s\-()]/g, '');
const { data, error } = await supabase.from('contacts').select('id').or(`phone.eq.${n},phone.eq.+${n},phone.ilike.%${n.slice(-8)}%`).limit(1).maybeSingle();
const n = phone.replace(/\D/g, '');
if (!n) return null;
const { data, error } = await supabase.from('contacts').select('id').or(`phone.eq.${n},phone.eq.+${n},phone.ilike.%${n.slice(-8)}%`).limit(1).maybeSingle();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/inbox/hooks/useSipClient.ts` around lines 44 - 45, The phone
sanitization in useSipClient.ts currently uses phone.replace(/[\s\-()]/g, '')
which still allows special characters into the PostgREST .or() filter and can
enable injection; change the cleaning to remove all non-digits (usePhone ->
create n from phone by stripping using a non-digit regex) so the value passed to
supabase.from('contacts').select(...).or(...) is only digits, and fail/return
early if result is empty; also fix the analogous issue in useNewConversation.ts
where searchQuery is interpolated into
.or(`name.ilike.%${searchQuery}%,phone.ilike.%${searchQuery}%`) by
validating/sanitizing searchQuery (either allow a safe subset of characters or
escape/normalize percent/quote characters, or reject unsafe input) before
building the query.

Comment thread src/hooks/useActionFeedback.ts Outdated
Comment on lines 52 to 53
// eslint-disable-next-line prefer-const -- closure: assigned at line 57 after toast definition uses it
let timeoutId: NodeJS.Timeout;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verifica se o projeto usa NodeJS.Timeout em código de frontend e como o TS está configurado.

echo "== Procurando tsconfig* =="
fd -i '^tsconfig.*\.json$'

echo
echo "== libs/types nos tsconfig* =="
fd -i '^tsconfig.*\.json$' -x sh -c 'echo "--- $1"; sed -n "1,220p" "$1" | rg -n "\"lib\"|\"types\"|dom|node" -n -C2' sh {}

echo
echo "== Ocorrências de NodeJS.Timeout em src =="
rg -n --type ts --type tsx '\bNodeJS\.Timeout\b' src

echo
echo "== Padrão recomendado já existente (ReturnType<typeof setTimeout>) =="
rg -n --type ts --type tsx 'ReturnType<\s*typeof\s+setTimeout\s*>' src

Repository: adm01-debug/zapp-web

Length of output: 856


🏁 Script executed:

cat -n src/hooks/useActionFeedback.ts | sed -n '48,62p'

Repository: adm01-debug/zapp-web

Length of output: 1153


🏁 Script executed:

#!/bin/bash
echo "== Buscando setTimeout/setInterval/clearTimeout em src =="
rg '(setTimeout|setInterval|clearTimeout|clearInterval)' src -B2 -A2 --no-heading | head -100

echo
echo "== Procurando tipagens de timeout em src =="
rg 'Timeout|ReturnType.*setTimeout' src -n --no-heading | head -50

Repository: adm01-debug/zapp-web

Length of output: 10241


Padronize tipagem de timeout com ReturnType<typeof setTimeout> (linha 53)

O projeto estabelece padrão em src/lib/debounce.ts e src/pages/VerifyEmail.tsx usando ReturnType<typeof setTimeout>. Alinhando useActionFeedback.ts mantém consistência de tipagem cross-runtime sem acoplamento a @types/node em ambiente web.

-      let timeoutId: NodeJS.Timeout;
+      let timeoutId: ReturnType<typeof setTimeout>;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// eslint-disable-next-line prefer-const -- closure: assigned at line 57 after toast definition uses it
let timeoutId: NodeJS.Timeout;
// eslint-disable-next-line prefer-const -- closure: assigned at line 57 after toast definition uses it
let timeoutId: ReturnType<typeof setTimeout>;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/useActionFeedback.ts` around lines 52 - 53, The timeoutId variable
in useActionFeedback is typed as NodeJS.Timeout which couples to `@types/node`;
change its type to ReturnType<typeof setTimeout> to match the project's
cross-runtime pattern (as used in src/lib/debounce.ts and
src/pages/VerifyEmail.tsx). Update the declaration of timeoutId (and any related
setTimeout/clearTimeout uses inside the useActionFeedback hook) to use
ReturnType<typeof setTimeout> and remove any NodeJS-specific typing so the hook
remains runtime-agnostic.

Two micro-fixes after PR review (no scope creep):

1. csvUtils.ts:154 — normalize regex char class
   - Before: /[^a-zA-Z0-9_\-.]/g (dash escaped between _ and .)
   - After:  /[^a-zA-Z0-9_.-]/g  (dash at end, unambiguous)
   - Validated: still produces same output for all test cases.
   - Copilot flagged this as potential SyntaxError risk; runtime test
     confirmed escaped form was valid, but the unescaped/end-position
     form is the cleaner convention.

2. useActionFeedback.ts:52 — eslint-disable comment
   - Removed hardcoded 'line 57' reference (drifts as file changes).
   - New comment describes intent: 'timeoutId is referenced inside
     toast action.onClick (declared above) and only assigned later
     by setTimeout'.

Skipped review feedback (out of scope for Onda 5 PR 5.1):
- useSipClient.ts: phone sanitization PostgREST injection risk
  → Backlog Onda 5 / security pass (escape rule was the only thing
    this PR was supposed to touch on this file).
- useScheduledMediaUpload.ts: createSignedUrl error not handled
  → Pre-existing bug, outside scope. Backlog as separate fix.
- useActionFeedback.ts: NodeJS.Timeout typing
  → Tangential, can ride a future PR.

Validations:
- bun run lint → 143 errors, 1330 warnings (unchanged from previous
  commit, both fixes were within already-touched lines)
- regex tested in isolation: produces identical output
@adm01-debug
Copy link
Copy Markdown
Owner Author

@coderabbitai full review

Address comments aplicados em commit 2b1c0dcd4:

  • ✅ csvUtils.ts: regex char class normalizada (- ao final, sem ambiguidade)
  • ✅ useActionFeedback.ts: comentário sem referência hardcoded a número de linha

Skipped feedbacks documentados em /workspace/notes/backlog-pr109-review-feedback.md (out of scope: useSipClient phone injection é pre-existing, useScheduledMediaUpload error handling é pre-existing bug, NodeJS.Timeout é nit cosmético).

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 9, 2026

@adm01-debug Entendido! Iniciando revisão completa considerando o commit 2b1c0dcd4.

Fixes confirmados:

  • csvUtils.ts: regex normalizada (- ao final, sem ambiguidade semântica)
  • useActionFeedback.ts: eslint-disable sem número de linha hardcoded

Itens de backlog registrados (fora do escopo deste PR):

  • useSipClient: sanitização de phone (pre-existing)
  • useScheduledMediaUpload: error handling no upload (pre-existing bug)
  • NodeJS.Timeout typing (nit cosmético)

Iniciando revisão completa agora...

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/security.ts (1)

102-102: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Pipeline bloqueado por controle de caracteres no regex.

O ESLint está falhando com no-control-regex na linha 102 porque o regex inclui explicitamente caracteres de controle (\u0000-\u001F). Como o objetivo da função é intencionalmente remover esses caracteres (conforme comentário linha 100), o correto é adicionar uma supressão ESLint com justificativa.

🛠️ Supressão sugerida
   // Remove zero-width characters, control chars, and direction overrides
+  // eslint-disable-next-line no-control-regex -- intentionally matching control chars to remove them
   const cleaned = name
     .replace(/[\u200B-\u200F\u202A-\u202E\uFEFF\u0000-\u001F\u007F-\u009F]/g, '')
     .trim();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/security.ts` at line 102, Add an ESLint suppression for the
no-control-regex rule immediately above the
.replace(/[\u200B-\u200F\u202A-\u202E\uFEFF\u0000-\u001F\u007F-\u009F]/g, '')
call to acknowledge the intentional removal of control characters (per the
comment around line 100); use an inline eslint-disable-next-line
no-control-regex with a short justification referencing the deliberate stripping
of control characters so the regex stays unchanged and the linter no longer
fails.
♻️ Duplicate comments (1)
src/features/inbox/hooks/useSipClient.ts (1)

44-45: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Sanitização ainda permite manipular o filtro .or() (issue já reportada).

Em Line 44, remover só espaço/hífen/parênteses não impede caracteres que quebram/alteram o filtro interpolado em Line 45. Restrinja para dígitos e retorne cedo se vazio.

Patch mínimo sugerido
-      const n = phone.replace(/[\s\-()]/g, '');
+      const n = phone.replace(/\D/g, '');
+      if (!n) return null;
       const { data, error } = await supabase.from('contacts').select('id').or(`phone.eq.${n},phone.eq.+${n},phone.ilike.%${n.slice(-8)}%`).limit(1).maybeSingle();
#!/bin/bash
set -euo pipefail

# Verifica a sanitização atual e a interpolação no filtro do Supabase
rg -n --type=ts -C2 'const n = phone\.replace\(' src/features/inbox/hooks/useSipClient.ts
rg -n --type=ts -C2 '\.or\(`phone\.eq\.\$\{n\}' src/features/inbox/hooks/useSipClient.ts

# Resultado esperado após correção:
# - Sanitização com /\D/g
# - Guard clause: if (!n) return null;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/inbox/hooks/useSipClient.ts` around lines 44 - 45, The current
sanitization for the phone variable (const n = phone.replace(/[\s\-()]/g, ''))
still allows non-digit chars that can tamper with the interpolated .or(...)
filter; change the sanitization to strip all non-digits (use
phone.replace(/\D/g, '')) and add a guard clause (e.g., if (!n) return null or
handle early) before calling supabase.from('contacts').select(...).maybeSingle()
so the .or(...) interpolation only receives a purely numeric, non-empty string.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/lib/security.ts`:
- Line 102: Add an ESLint suppression for the no-control-regex rule immediately
above the
.replace(/[\u200B-\u200F\u202A-\u202E\uFEFF\u0000-\u001F\u007F-\u009F]/g, '')
call to acknowledge the intentional removal of control characters (per the
comment around line 100); use an inline eslint-disable-next-line
no-control-regex with a short justification referencing the deliberate stripping
of control characters so the regex stays unchanged and the linter no longer
fails.

---

Duplicate comments:
In `@src/features/inbox/hooks/useSipClient.ts`:
- Around line 44-45: The current sanitization for the phone variable (const n =
phone.replace(/[\s\-()]/g, '')) still allows non-digit chars that can tamper
with the interpolated .or(...) filter; change the sanitization to strip all
non-digits (use phone.replace(/\D/g, '')) and add a guard clause (e.g., if (!n)
return null or handle early) before calling
supabase.from('contacts').select(...).maybeSingle() so the .or(...)
interpolation only receives a purely numeric, non-empty string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 074d6104-fbd9-4243-9b3a-b35c8617bea2

📥 Commits

Reviewing files that changed from the base of the PR and between 43f8e40 and 2b1c0dc.

📒 Files selected for processing (17)
  • .eslintrc.tailwind.js
  • scripts/ds-config.ts
  • src/components/contacts/ContactsRichView.tsx
  • src/components/security/RateLimitRealtimeAlerts.tsx
  • src/features/auth/components/PasswordStrengthMeter.tsx
  • src/features/connections/hooks/useConnectionsManager.ts
  • src/features/inbox/components/chat/MarkdownPreview.tsx
  • src/features/inbox/components/linkPreviewUtils.ts
  • src/features/inbox/hooks/useScheduledMediaUpload.ts
  • src/features/inbox/hooks/useSipClient.ts
  • src/hooks/useActionFeedback.ts
  • src/hooks/useCSAT.ts
  • src/hooks/useThemeAudit.ts
  • src/lib/csvUtils.ts
  • src/lib/evolutionDirectClient.ts
  • src/lib/security.ts
  • src/pages/admin/AdminStressTestPage.tsx
💤 Files with no reviewable changes (1)
  • .eslintrc.tailwind.js

CodeRabbit's 2nd review caught a pre-existing no-control-regex error
on src/lib/security.ts:102 (outside diff but blocks CI).

The regex INTENTIONALLY matches control characters (U+0000-001F,
U+007F-009F) to strip them from display names — exactly what's
documented in the comment on line 100. Adding ESLint suppression
with justification is the correct fix.

Now 142 errors (was 143), no-control-regex zeroed.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/security.ts`:
- Line 116: A constante jidPattern aceita strings sem dígitos porque permite
sequências de hífens; atualize jidPattern (a constante jidPattern) para exigir
explicitamente uma sequência inicial de um ou mais dígitos, opcionalmente
seguida de um hífen e outra sequência de um ou mais dígitos (ou seja, "digits"
ou "digits-hyphen-digits"), antes do @ e do sufixo (s.whatsapp.net | g.us | lid
| newsletter), para impedir entradas como "---@s.whatsapp.net".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 22eb459e-972b-4602-a990-7151b94422b2

📥 Commits

Reviewing files that changed from the base of the PR and between 2b1c0dc and 22c7846.

📒 Files selected for processing (1)
  • src/lib/security.ts

Comment thread src/lib/security.ts
// Individual: 5511999999999@s.whatsapp.net
// Group: 120363XXXX@g.us
const jidPattern = /^[\d\-]+@(s\.whatsapp\.net|g\.us|lid|newsletter)$/;
const jidPattern = /^[\d-]+@(s\.whatsapp\.net|g\.us|lid|newsletter)$/;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Regex de JID permite entradas inválidas sem dígitos.

Com ^[\d-]+...$, valores como ---@s.whatsapp.net passam na validação, embora o formato esperado no próprio docstring exija dígitos (ou digits-timestamp para grupos). Isso pode deixar JID inválido seguir no fluxo.

Diff sugerido
-  const jidPattern = /^[\d-]+@(s\.whatsapp\.net|g\.us|lid|newsletter)$/;
+  const jidPattern = /^(?:\d+@s\.whatsapp\.net|\d+-\d+@g\.us|\d+@(?:lid|newsletter))$/;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const jidPattern = /^[\d-]+@(s\.whatsapp\.net|g\.us|lid|newsletter)$/;
const jidPattern = /^(?:\d+@s\.whatsapp\.net|\d+-\d+@g\.us|\d+@(?:lid|newsletter))$/;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/security.ts` at line 116, A constante jidPattern aceita strings sem
dígitos porque permite sequências de hífens; atualize jidPattern (a constante
jidPattern) para exigir explicitamente uma sequência inicial de um ou mais
dígitos, opcionalmente seguida de um hífen e outra sequência de um ou mais
dígitos (ou seja, "digits" ou "digits-hyphen-digits"), antes do @ e do sufixo
(s.whatsapp.net | g.us | lid | newsletter), para impedir entradas como
"---@s.whatsapp.net".

@adm01-debug adm01-debug merged commit 1824af8 into main May 9, 2026
10 of 11 checks passed
@adm01-debug adm01-debug deleted the chore/onda-5-pr-5.1-eslint-quick-wins branch May 9, 2026 10:18
adm01-debug added a commit that referenced this pull request May 9, 2026
🎉 Fecha Onda 5: 108 → 0 errors (-108).

ESLint TOTAL: 164 → 0 errors em 4 PRs (#109, #110, #111, este).

## Estratégia DDD

Regra `no-restricted-imports` (eslint.config.js) bloqueia:
1. Imports cross-feature deep (`@/features/X/...`) — força entry points
2. Imports relativos profundos (`../../...`)
3. INTRA-feature via alias (`@/features/X/Y` quando arquivo está em X)

## Batch A — INTRA-feature (106 fixes em 42 arquivos)

Pattern: `@/features/X/Y/Z` → caminho relativo via path.relative()

Ex (src/features/inbox/components/chat/ChatHeader.tsx):
- ANTES: `@/features/inbox/components/ai-tools/VisionIcon`
- DEPOIS: `../ai-tools/VisionIcon`

Distribuição:
- 92 inbox (52 chat, 12 contact-details, 8 components, 5 hooks, 3 services, 3 virtualized, 3 conversation-list, 2 realtime, 2 templates, 2 search, 1 monitoring, 1 mocks)
- 7 auth (5 components, 1 hooks, 1 context)
- 3 admin (2 hooks, 1 services)
- 3 connections (2 hooks, 1 services)
- 1 sla (1 components)

Script: /tmp/fix-intra.mjs (Node + path.relative)
- 106/106 sucesso, zero falhas
- 1 read/write por arquivo (eficiente)
- Ordem desc por linha (não invalida índices)

## Batch B — CROSS-feature (2 fixes)

Imports de outra feature DEVEM usar entry point (`@/features/X`),
não path interno (`@/features/X/hooks/...`).

Os barrels já existiam (`auth/index.ts` e `sla/index.ts` fazem
`export * from './hooks'`), só não estavam sendo usados:

- src/features/inbox/components/ChatPanel.tsx:
  `@/features/auth/hooks/useUserRole` → `@/features/auth`
- src/features/inbox/components/RealtimeInboxView.tsx:
  `@/features/sla/hooks/useSLAAlerts` → `@/features/sla`

## Validação

- bunx eslint . → 0 errors, 1330 warnings (Onda 5 ZERADA)
- bunx tsc --noEmit → ✓ sem erros (typecheck pristine)
- bun run build → ✓ built in 58.09s (zero regressões)
- 44 files changed, 108 insertions(+), 108 deletions(-)

## Stress-test (10 cenários)

✓ path.relative gera `../foo` ou `./foo` corretamente
✓ Sem imports circulares (auth/sla não importam inbox)
✓ Comments inline preservados (replace só no string interno)
✓ BOM/CRLF tratados pelo Node
✓ index.ts implícito resolvido pelo TS path mapping
✓ Build não quebrou — tsconfig path mapping continua funcionando
✓ Typecheck sem regressão
✓ Sem sessão paralela (verificado via git reflog)
✓ Barrels já existiam, useUserRole/useSLAAlerts já re-exportados
✓ Eslint --fix NÃO usado (só explicit replace, sem side effects)

## Pós-Onda 5

Próximo do roadmap pré-deploy:
- PR #108 (preserve/faxina) — decidir mergear ou fechar
- 8 dependabots — aplicar recomendação A (fechar com TODO pós-deploy)
- Fase B10 — patch 9 vulns npm
- Fase B5 — ENV_SETUP doc
- Fase C — Dockerfile + deploy zapp.atomicabr.com.br
adm01-debug added a commit that referenced this pull request May 9, 2026
🎉 Fecha Onda 5: 108 → 0 errors (-108).

ESLint TOTAL: 164 → 0 errors em 4 PRs (#109, #110, #111, este).

## Estratégia DDD

Regra `no-restricted-imports` (eslint.config.js) bloqueia:
1. Imports cross-feature deep (`@/features/X/...`) — força entry points
2. Imports relativos profundos (`../../...`)
3. INTRA-feature via alias (`@/features/X/Y` quando arquivo está em X)

## Batch A — INTRA-feature (106 fixes em 42 arquivos)

Pattern: `@/features/X/Y/Z` → caminho relativo via path.relative()

Ex (src/features/inbox/components/chat/ChatHeader.tsx):
- ANTES: `@/features/inbox/components/ai-tools/VisionIcon`
- DEPOIS: `../ai-tools/VisionIcon`

Distribuição:
- 92 inbox (52 chat, 12 contact-details, 8 components, 5 hooks, 3 services, 3 virtualized, 3 conversation-list, 2 realtime, 2 templates, 2 search, 1 monitoring, 1 mocks)
- 7 auth (5 components, 1 hooks, 1 context)
- 3 admin (2 hooks, 1 services)
- 3 connections (2 hooks, 1 services)
- 1 sla (1 components)

Script: /tmp/fix-intra.mjs (Node + path.relative)
- 106/106 sucesso, zero falhas
- 1 read/write por arquivo (eficiente)
- Ordem desc por linha (não invalida índices)

## Batch B — CROSS-feature (2 fixes)

Imports de outra feature DEVEM usar entry point (`@/features/X`),
não path interno (`@/features/X/hooks/...`).

Os barrels já existiam (`auth/index.ts` e `sla/index.ts` fazem
`export * from './hooks'`), só não estavam sendo usados:

- src/features/inbox/components/ChatPanel.tsx:
  `@/features/auth/hooks/useUserRole` → `@/features/auth`
- src/features/inbox/components/RealtimeInboxView.tsx:
  `@/features/sla/hooks/useSLAAlerts` → `@/features/sla`

## Validação

- bunx eslint . → 0 errors, 1330 warnings (Onda 5 ZERADA)
- bunx tsc --noEmit → ✓ sem erros (typecheck pristine)
- bun run build → ✓ built in 58.09s (zero regressões)
- 44 files changed, 108 insertions(+), 108 deletions(-)

## Stress-test (10 cenários)

✓ path.relative gera `../foo` ou `./foo` corretamente
✓ Sem imports circulares (auth/sla não importam inbox)
✓ Comments inline preservados (replace só no string interno)
✓ BOM/CRLF tratados pelo Node
✓ index.ts implícito resolvido pelo TS path mapping
✓ Build não quebrou — tsconfig path mapping continua funcionando
✓ Typecheck sem regressão
✓ Sem sessão paralela (verificado via git reflog)
✓ Barrels já existiam, useUserRole/useSLAAlerts já re-exportados
✓ Eslint --fix NÃO usado (só explicit replace, sem side effects)

## Pós-Onda 5

Próximo do roadmap pré-deploy:
- PR #108 (preserve/faxina) — decidir mergear ou fechar
- 8 dependabots — aplicar recomendação A (fechar com TODO pós-deploy)
- Fase B10 — patch 9 vulns npm
- Fase B5 — ENV_SETUP doc
- Fase C — Dockerfile + deploy zapp.atomicabr.com.br
adm01-debug added a commit that referenced this pull request May 9, 2026
…09) (#113)

Documenta o estado FINAL após:
- Onda 5 completa (164 → 0 errors em 4 PRs: #109, #110, #111, #112)
- 8 dependabots resolvidos (3 mergeados, 5 fechados, 1 preservation closed)

Estado atual:
- HEAD main: f1b3eab
- ESLint: 0 errors, 1330 warnings
- Branches remotas: 2 (main + preserve)
- PRs OPEN: 0

Conteúdo do handoff (718 linhas):
- TL;DR + estado atual com métricas
- Quem é Joaquim e workflow
- Histórico cronológico de TODOS os PRs (Schemas, Faxina pré-Onda, Ondas 1, 2, 5)
- Faxina de branches (491 → 2)
- Resolução técnica dos 8 dependabots
- Decisões técnicas-chave (React 18, Vite reject, Sentry accept, etc)
- 20 lições aprendidas
- Catálogo de notes em /workspace/notes/
- Pendências pré-deploy (Backup Supabase, RabbitMQ 69GB, Drift, Deploy VPS, FX-DEP-02)
- Backlogs de review skipped
- Como retomar (instruções pra próximo Claude)
- Apêndices: comandos úteis, infra VPS, Vercel, workflow

Este doc serve como ponto de retomada pra próxima sessão Claude
sem perder contexto.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants