feat(crm): Fase 5 — tela cheia estilo WhatsApp, auto-sync de contato …#53
Conversation
…e correção do travamento Ataca os dois problemas relatados (conversas travando, sem chat pra escrever) e o pedido de uma experiência "nível WhatsApp" dentro do CRM. Correção do travamento (causa raiz identificada em 2 pontos) - listarMensagensDoLead não tinha limite: conversas com muito histórico carregavam TODAS as mensagens de uma vez, travando a página. Agora pagina (60 mensagens por vez, igual WhatsApp Web) com "↑ Carregar mensagens anteriores" no topo da thread — preserva a posição de scroll ao carregar mais, e não perde as páginas já carregadas quando chega mensagem nova (merge em vez de substituir). - enviarAudioAction guardava o base64 CRU (até 8MB) direto no banco quando o upload pro Storage falhava — algumas conversas ficavam com várias mensagens de vários MB cada, travando ao abrir. Agora só usa esse fallback pra áudios pequenos (≤300KB); acima disso a mensagem fica sem player mas a entrega no WhatsApp continua normal. Migração 20260713 já limpa o que ficou travado (zera midia_url de áudios gigantes salvos por engano). Auto-sync de contato (nome/foto) sem precisar clicar - Abrir uma conversa sem nome/foto já dispara a busca no WhatsApp sozinho (silencioso, respeita nome_manual). Throttle de 6h evita martelar a Evolution em conversas sem informação disponível. - Cron diário novo (/api/crm/sincronizar-contatos) cobre o backlog de leads que ninguém abriu ainda — sem depender de abrir cada conversa uma por uma. - Botão manual "↻ Atualizar do WhatsApp" continua disponível, sempre forçando nova tentativa. Redesign: CRM em tela cheia, estilo WhatsApp Web - Seletor no topo (Conversas / Kanban / Calendário) via ?view= — cada modo ocupa a tela inteira, em vez de ficarem empilhados. Compatível com ?lead= (ex: card do Kanban abre em "?view=conversas&lead=X"). - Conversas: sidebar + thread ocupando praticamente toda a altura da janela. - Kanban: preenche a tela inteira; colunas mais altas. Kanban: etapas personalizáveis - "+ Nova etapa" cria uma coluna custom por usuário (nome + cor), sem afetar as 7 etapas padrão compartilhadas. Dono pode excluir a própria (com confirmação inline) — leads voltam pra "sem etapa" em vez de sumir. moverLeadAction valida que a etapa é sua antes de mover um lead pra ela. Migração 20260713: crm_etapas.usuario_id (etapa custom), crm_leads. perfil_sync_tentado_em (throttle do auto-sync), repara midia_url gigante. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThe CRM dashboard now supports query-driven Conversations, Kanban, and Calendar views. Conversations load paginated history, Kanban supports user-owned stages, and contact profile synchronization gains throttling, scheduled execution, and forced refresh behavior. ChangesCRM platform enhancements
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant CRMPage
participant Thread
participant MessageAction
participant Supabase
CRMPage->>Supabase: Load initial message page
CRMPage->>Thread: Pass mensagensIniciais and temMaisAntigasInicial
Thread->>MessageAction: Request older messages with cursor
MessageAction->>Supabase: Query earlier crm_mensagens
Supabase-->>MessageAction: Return paginated messages
MessageAction-->>Thread: Return messages and temMaisAntigas
Thread->>Thread: Merge messages and preserve scroll position
sequenceDiagram
participant VercelCron
participant SyncRoute
participant Supabase
participant Evolution
VercelCron->>SyncRoute: Invoke scheduled contact synchronization
SyncRoute->>Supabase: Query eligible leads and CRM instances
SyncRoute->>Evolution: Fetch contact profile
Evolution-->>SyncRoute: Return profile fields
SyncRoute->>Supabase: Update lead profile and attempt timestamp
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/crm-leads-actions.ts (1)
101-119: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
achouAlgocan report success when nothing was actually written.
achouAlgochecksperfil.nome || perfil.sobre || perfil.foto, butpatch.nomeis only set when!lead.nome_manual. If Evolution returns only anomefor a manually-named lead (nosobre/foto),patchends up with just timestamp fields, yetachouAlgois stilltrueand the action returns{ ok: true }— misleading the caller (and triggering an unnecessaryrouter.refresh()) into thinking something changed.Suggested fix
const { error } = await db .from("crm_leads") .update(patch) .eq("id", leadId) .eq("usuario_id", usuario.id) if (error) return { ok: false, erro: error.message } revalidatePath("/dashboard/crm") - const achouAlgo = Boolean(perfil.nome || perfil.sobre || perfil.foto) + const achouAlgo = Boolean(patch.nome || patch.sobre || patch.foto_url) if (!achouAlgo) return { ok: false, erro: "Nada novo encontrado para este contato." }🤖 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 `@lib/crm-leads-actions.ts` around lines 101 - 119, Update the success check in the action containing the patch construction so it reflects fields actually written, not merely values returned in perfil. Base achouAlgo on whether patch includes a meaningful CRM field (nome, sobre, or foto_url), excluding the timestamp fields, while preserving the existing no-change error response and revalidation behavior.
🧹 Nitpick comments (1)
supabase/migrations/20260713_crm_fase5_etapas_custom_sync_throttle.sql (1)
27-30: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winUnbatched full-table
UPDATEoncrm_mensagens.This scans the entire
crm_mensagenstable (no index onmidia_url/length()) and updates every matching row in one statement. If run in the same transaction as the index builds above, it extends the write-lock window oncrm_leadsuntil commit. For a large/active messages table, consider batching (e.g., byidranges or aLIMIT-based loop) to reduce lock/transaction duration.🤖 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 `@supabase/migrations/20260713_crm_fase5_etapas_custom_sync_throttle.sql` around lines 27 - 30, Replace the unbatched full-table UPDATE in the migration with a bounded batching approach using the table’s existing primary-key symbol, processing matching crm_mensagens rows in small batches until none remain. Preserve the midia_url filter and null assignment while minimizing lock and transaction duration.
🤖 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 `@app/api/crm/sincronizar-contatos/route.ts`:
- Around line 9-14: Reduce the batch size constant LOTE and add a wall-clock
budget to the sequential contact-processing loop so buscarPerfilContatoEvolution
calls cannot exceed maxDuration. Before each iteration, stop processing when the
elapsed time approaches the 60-second limit, while preserving updates for
contacts already completed.
In `@lib/crm-mensagens-actions.ts`:
- Around line 21-44: Update carregarMensagensAntigasAction to use the same
null-safe ordering as the thread, falling back to created_at when wa_timestamp
is null, and implement a tie-broken cursor that includes messages sharing the
boundary timestamp. Ensure rows with null wa_timestamp remain reachable while
preserving descending pagination and the existing limit/result behavior.
In `@supabase/migrations/20260713_crm_fase5_etapas_custom_sync_throttle.sql`:
- Around line 27-30: Align the cleanup predicate in the crm_mensagens migration
with the LIMITE_FALLBACK_INLINE cap used by the inline audio fallback, replacing
the 200000-character threshold with the same effective limit. Preserve the
existing data-URL filter and nullification behavior.
- Around line 9-19: Update the index creation statements for
crm_leads_perfil_sync_pendente_idx and crm_etapas_usuario_idx to use concurrent
index creation, preserving their existing columns and partial predicate. Ensure
the migration remains compatible with the transaction requirements of concurrent
index creation.
---
Outside diff comments:
In `@lib/crm-leads-actions.ts`:
- Around line 101-119: Update the success check in the action containing the
patch construction so it reflects fields actually written, not merely values
returned in perfil. Base achouAlgo on whether patch includes a meaningful CRM
field (nome, sobre, or foto_url), excluding the timestamp fields, while
preserving the existing no-change error response and revalidation behavior.
---
Nitpick comments:
In `@supabase/migrations/20260713_crm_fase5_etapas_custom_sync_throttle.sql`:
- Around line 27-30: Replace the unbatched full-table UPDATE in the migration
with a bounded batching approach using the table’s existing primary-key symbol,
processing matching crm_mensagens rows in small batches until none remain.
Preserve the midia_url filter and null assignment while minimizing lock and
transaction duration.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 03b0e8c4-254b-4f15-8f00-8583bea8dea0
📒 Files selected for processing (13)
app/api/crm/sincronizar-contatos/route.tsapp/dashboard/crm/page.tsxcomponents/crm/Calendario.tsxcomponents/crm/Kanban.tsxcomponents/crm/PainelKanbanCalendario.tsxcomponents/crm/Thread.tsxlib/crm-etapas.tslib/crm-kanban-actions.tslib/crm-leads-actions.tslib/crm-leads.tslib/crm-mensagens-actions.tssupabase/migrations/20260713_crm_fase5_etapas_custom_sync_throttle.sqlvercel.json
💤 Files with no reviewable changes (1)
- components/crm/PainelKanbanCalendario.tsx
| export const maxDuration = 60 | ||
|
|
||
| // Batelada por execução — folgado o bastante pra não estourar maxDuration=60s | ||
| // (cada chamada à Evolution tem timeout de 12s), mas limitado pra não | ||
| // martelar a API em contas com muitos leads sem foto/nome de uma vez. | ||
| const LOTE = 25 |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect target file with line numbers
sed -n '1,260p' app/api/crm/sincronizar-contatos/route.ts | nl -ba
echo
echo '--- search for related symbols ---'
rg -n "buscarPerfilContatoEvolution|maxDuration|LOTE|ORCAMENTO_MS|Date\.now\(\)|AbortController|timeout" app/api/crm -SRepository: sejaanomalo-web/metas-anomalo
Length of output: 207
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
path = Path('app/api/crm/sincronizar-contatos/route.ts')
for i, line in enumerate(path.read_text().splitlines(), 1):
print(f"{i:4d}: {line}")
PY
echo
echo '--- search for related symbols ---'
rg -n "buscarPerfilContatoEvolution|maxDuration|LOTE|ORCAMENTO_MS|Date\.now\(\)|AbortController|timeout" app/api/crm -SRepository: sejaanomalo-web/metas-anomalo
Length of output: 5329
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find the evolution helper implementation
fd -a "evolution.*" .
echo
rg -n "function buscarPerfilContatoEvolution|const buscarPerfilContatoEvolution|buscarPerfilContatoEvolution|AbortController|timeout|12000|12s|12_000" lib src app -SRepository: sejaanomalo-web/metas-anomalo
Length of output: 1762
Batch can still exceed maxDuration=60
buscarPerfilContatoEvolution uses a 12s timeout, and this loop runs sequentially for up to 25 leads. In the worst case, the batch can run for several minutes and get cut off mid-run, leaving partial updates.
Lower LOTE and/or add a wall-clock budget before entering the next iteration.
🤖 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 `@app/api/crm/sincronizar-contatos/route.ts` around lines 9 - 14, Reduce the
batch size constant LOTE and add a wall-clock budget to the sequential
contact-processing loop so buscarPerfilContatoEvolution calls cannot exceed
maxDuration. Before each iteration, stop processing when the elapsed time
approaches the 60-second limit, while preserving updates for contacts already
completed.
| export async function carregarMensagensAntigasAction( | ||
| leadId: string, | ||
| antesIso: string, | ||
| limite = MENSAGENS_POR_PAGINA | ||
| ): Promise<PaginaMensagens> { | ||
| const usuario = await getUsuarioAtual() | ||
| if (!usuario) return { mensagens: [], temMaisAntigas: false } | ||
| const db = getSupabaseAdmin() | ||
| if (!db) return { mensagens: [], temMaisAntigas: false } | ||
| const { data, error } = await db | ||
| .from("crm_mensagens") | ||
| .select("*") | ||
| .eq("lead_id", leadId) | ||
| .eq("usuario_id", usuario.id) | ||
| .lt("wa_timestamp", antesIso) | ||
| .order("wa_timestamp", { ascending: false, nullsFirst: false }) | ||
| .limit(limite) | ||
| if (error) { | ||
| console.error("[crm_mensagens] carregar antigas error", error.message) | ||
| return { mensagens: [], temMaisAntigas: false } | ||
| } | ||
| const linhas = ((data ?? []) as CrmMensagemRow[]).reverse() | ||
| return { mensagens: linhas, temMaisAntigas: linhas.length === limite } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show the relevant file with line numbers
sed -n '1,220p' lib/crm-mensagens-actions.ts | nl -ba
# Find the caller and cursor construction
rg -n "carregarMensagensAntigasAction|maisAntiga\.wa_timestamp|created_at" components src lib -S
# Inspect the caller file around the pagination logic
caller=$(rg -l "carregarMensagensAntigasAction|maisAntiga\.wa_timestamp|created_at" components src lib -S | head -n 1 || true)
if [ -n "${caller:-}" ]; then
echo "=== CALLER: $caller ==="
sed -n '1,260p' "$caller" | nl -ba
fi
# Locate the row type to confirm nullability
rg -n "type CrmMensagemRow|interface CrmMensagemRow|wa_timestamp" lib src components -SRepository: sejaanomalo-web/metas-anomalo
Length of output: 207
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '=== lib/crm-mensagens-actions.ts ==='
awk '{printf "%4d %s\n", NR, $0}' lib/crm-mensagens-actions.ts | sed -n '1,220p'
printf '\n%s\n' '=== search: caller + cursor construction ==='
rg -n "carregarMensagensAntigasAction|maisAntiga\.wa_timestamp|created_at" components src lib -S
printf '\n%s\n' '=== CrmMensagemRow / wa_timestamp ==='
rg -n "type CrmMensagemRow|interface CrmMensagemRow|wa_timestamp" components src lib -SRepository: sejaanomalo-web/metas-anomalo
Length of output: 13597
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '=== lib/crm-leads.ts (row types) ==='
awk '{printf "%4d %s\n", NR, $0}' lib/crm-leads.ts | sed -n '1,180p'
printf '\n%s\n' '=== components/crm/Thread.tsx (pagination + sort) ==='
awk '{printf "%4d %s\n", NR, $0}' components/crm/Thread.tsx | sed -n '1,220p'
printf '\n%s\n' '=== crm_mensagens writes / wa_timestamp assignments ==='
rg -n "from\\(\"crm_mensagens\"\\)|wa_timestamp|created_at" lib components -SRepository: sejaanomalo-web/metas-anomalo
Length of output: 20178
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '=== lib/crm-inbound.ts (wa_timestamp source) ==='
awk '{printf "%4d %s\n", NR, $0}' lib/crm-inbound.ts | sed -n '450,520p'
printf '\n%s\n' '=== exact query shape in lib/crm-mensagens-actions.ts ==='
awk '{printf "%4d %s\n", NR, $0}' lib/crm-mensagens-actions.ts | sed -n '21,45p'Repository: sejaanomalo-web/metas-anomalo
Length of output: 4121
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '=== waTs provenance in lib/crm-inbound.ts ==='
rg -n "waTs|wa_timestamp" lib/crm-inbound.ts -n -S
awk '{printf "%4d %s\n", NR, $0}' lib/crm-inbound.ts | sed -n '380,500p'
printf '\n%s\n' '=== any explicit null writes to wa_timestamp ==='
rg -n "wa_timestamp:\s*null|wa_timestamp\s*=\s*null|wa_timestamp.*null" lib components app -S
printf '\n%s\n' '=== all crm_mensagens inserts/upserts/updates ==='
rg -n "from\\(\"crm_mensagens\"\\)|upsert\\(|insert\\(|update\\(" lib components app -SRepository: sejaanomalo-web/metas-anomalo
Length of output: 13629
Strict wa_timestamp paging can drop history. .lt("wa_timestamp", antesIso) makes rows with wa_timestamp = null unreachable, and using only wa_timestamp as the cursor can skip messages that share the boundary timestamp. The thread already falls back to created_at when sorting, so the query needs the same null-safe, tie-broken cursor.
🤖 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 `@lib/crm-mensagens-actions.ts` around lines 21 - 44, Update
carregarMensagensAntigasAction to use the same null-safe ordering as the thread,
falling back to created_at when wa_timestamp is null, and implement a tie-broken
cursor that includes messages sharing the boundary timestamp. Ensure rows with
null wa_timestamp remain reachable while preserving descending pagination and
the existing limit/result behavior.
| alter table public.crm_etapas add column if not exists usuario_id uuid; | ||
| create index if not exists crm_etapas_usuario_idx on public.crm_etapas (usuario_id); | ||
|
|
||
| -- perfil_sync_tentado_em: carimbo da última tentativa de buscar nome/foto/ | ||
| -- recado no WhatsApp (manual ou automática) — evita bater no Evolution a | ||
| -- cada abertura de conversa/rodada de cron pra contato sem informação | ||
| -- disponível (throttle, não trava o dado já sincronizado). | ||
| alter table public.crm_leads add column if not exists perfil_sync_tentado_em timestamptz; | ||
| create index if not exists crm_leads_perfil_sync_pendente_idx | ||
| on public.crm_leads (perfil_sync_tentado_em) | ||
| where nome_manual = false; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the migration and surrounding migration runner/config to determine
# whether this file is executed inside a transaction and whether CONCURRENTLY is allowed.
git ls-files | rg '(^|/)(supabase/migrations/20260713_crm_fase5_etapas_custom_sync_throttle\.sql|supabase/|migrations/|db/|sql/|package\.json|README\.md)$'
printf '\n--- migration file (lines 1-120) ---\n'
cat -n supabase/migrations/20260713_crm_fase5_etapas_custom_sync_throttle.sql | sed -n '1,120p'
printf '\n--- search for migration runner / transaction settings ---\n'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/.git/**' \
'transaction|BEGIN;|COMMIT;|CREATE INDEX CONCURRENTLY|migrations.*transaction|supabase db push|db push|seed|migration' \
. | sed -n '1,240p'Repository: sejaanomalo-web/metas-anomalo
Length of output: 3817
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- package.json ---\n'
cat -n package.json | sed -n '1,220p'
printf '\n--- README.md (migration-related sections) ---\n'
rg -n -A4 -B4 'supabase|migration|apply_migration|transaction|concurrently' README.md supabase docs | sed -n '1,260p'
printf '\n--- search for apply_migration definition/usages ---\n'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/.git/**' 'apply_migration' . | sed -n '1,240p'Repository: sejaanomalo-web/metas-anomalo
Length of output: 13975
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- README.md (migration-related sections) ---\n'
rg -n -A4 -B4 'supabase|migration|apply_migration|transaction|concurrently' README.md supabase docs | sed -n '1,260p'
printf '\n--- search for apply_migration definition/usages ---\n'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/.git/**' 'apply_migration' . | sed -n '1,240p'Repository: sejaanomalo-web/metas-anomalo
Length of output: 12786
🌐 Web query:
Supabase CLI migration files transaction default CREATE INDEX CONCURRENTLY migration transaction block docs
💡 Result:
The Supabase CLI manages migrations by running them inside a transaction block by default [1]. However, certain PostgreSQL operations, such as CREATE INDEX CONCURRENTLY, cannot be executed within a transaction block [2][3][4]. Recent updates to the Supabase CLI (as of June 2026) have introduced intelligent handling for these incompatible statements [5][6]. When the CLI detects pipeline-incompatible statements—specifically CREATE INDEX CONCURRENTLY, VACUUM, REINDEX CONCURRENTLY, ALTER SYSTEM, and CLUSTER—it automatically adjusts its execution strategy [5][6]: 1. It flushes any open transaction batch. 2. It executes the incompatible statement as a standalone command outside of any transaction block. 3. It resumes batching subsequent statements within a transaction. This mechanism ensures that migrations containing these operations can proceed without causing SQLSTATE 25001 errors, while still maintaining the atomicity of the surrounding migration steps [5][6]. If you are encountering issues in older versions of the CLI or specific edge cases, it is recommended to ensure your CLI is updated to the latest version to leverage this native support [5][6]. Alternatively, for complex migrations, some developers prefer to execute these operations via a separate, non-transactional script or psql command to have full control over the execution environment [4].
Citations:
- 1: https://supabase-supabase.mintlify.app/database/migrations
- 2: https://supabase.com/docs/guides/database/postgres/indexes
- 3: https://pgfence.com/blog/concurrently-in-a-transaction-silent-footgun/
- 4: https://www.iloveblogs.blog/guides/zero-downtime-supabase-migrations
- 5: feat(cli): port migration commands to native TypeScript (CLI-1312) supabase/cli#5671
- 6: supabase/cli@b48fad6
Make the crm_leads index concurrent
create index on public.crm_leads will block writes while it builds, and this table is on a hot webhook path. Switch crm_leads_perfil_sync_pendente_idx to CREATE INDEX CONCURRENTLY; crm_etapas_usuario_idx can follow the same pattern for consistency.
🧰 Tools
🪛 Squawk (2.59.0)
[warning] 10-10: During normal index creation, table updates are blocked, but reads are still allowed. Use concurrently to avoid blocking writes.
(require-concurrent-index-creation)
[warning] 17-19: During normal index creation, table updates are blocked, but reads are still allowed. Use concurrently to avoid blocking writes.
(require-concurrent-index-creation)
🤖 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 `@supabase/migrations/20260713_crm_fase5_etapas_custom_sync_throttle.sql`
around lines 9 - 19, Update the index creation statements for
crm_leads_perfil_sync_pendente_idx and crm_etapas_usuario_idx to use concurrent
index creation, preserving their existing columns and partial predicate. Ensure
the migration remains compatible with the transaction requirements of concurrent
index creation.
Source: Linters/SAST tools
| update public.crm_mensagens | ||
| set midia_url = null | ||
| where midia_url like 'data:%' | ||
| and length(midia_url) > 200000; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Cleanup threshold doesn't match the ongoing insert cap.
This one-time cleanup wipes midia_url above 200000 chars, but lib/crm-mensagens-actions.ts's LIMITE_FALLBACK_INLINE (300 * 1024 ≈ 307,200 bytes) allows new inline audio fallbacks up to a larger size going forward. Messages inserted in the 200KB–300KB range after this migration runs won't be caught by any future cleanup, contradicting the stated intent of capping oversized inline media.
🤖 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 `@supabase/migrations/20260713_crm_fase5_etapas_custom_sync_throttle.sql`
around lines 27 - 30, Align the cleanup predicate in the crm_mensagens migration
with the LIMITE_FALLBACK_INLINE cap used by the inline audio fallback, replacing
the 200000-character threshold with the same effective limit. Preserve the
existing data-URL filter and nullification behavior.
…e correção do travamento
Ataca os dois problemas relatados (conversas travando, sem chat pra escrever) e o pedido de uma experiência "nível WhatsApp" dentro do CRM.
Correção do travamento (causa raiz identificada em 2 pontos)
Auto-sync de contato (nome/foto) sem precisar clicar
Redesign: CRM em tela cheia, estilo WhatsApp Web
Kanban: etapas personalizáveis
Migração 20260713: crm_etapas.usuario_id (etapa custom), crm_leads. perfil_sync_tentado_em (throttle do auto-sync), repara midia_url gigante.
Summary by CodeRabbit
New Features
Improvements
Bug Fixes