Last updated: 2026-07-10 — 📣🔍 AUDITORIA DO MOTOR META ADS (criativos + campanhas + Jumper de Terceiros) — plano de execução p/ Opus em
meta-ads/PLANO-EXECUCAO-OPUS-MOTOR-ADS-2026-07-10.md. Auditoria de 4 agentes (loop de otimização, motor de criativos, integração bot/boost terceiros, produção cloudvero) + leitura direta do núcleo do Jumper. 26 achados inventariados, destaques: (P0 ops) reinstalação do crontab ~03/07 APAGOU 8 crons de ads (CAPI, judge Meta+Google, rotate_creative, terceiros_lead_watch, reconcile_boosts — explica o intake de 09/07 do reconcile) porque o mirrorscripts/crontab.cloudvero.txtestava desatualizado E CONTINUA sem as linhas;terceiros_report.pyperdeu ocd(falha diária desde 03/07);select_boosts_ads+enrich_redeNUNCA tiveram cron →ads-candidates-terceiros.jsonstale (vendido continua no carrossel). (P0 conta) nenhuma mutação Meta aplicada desde 27/06 (status=3até 09/07; optimize_meta rodou monitor-only, 16 erros de permissão/run). (críticos de código) colisão de headline bairro+preço → lead atribuído ao imóvel ERRADO (real: 8× "vila andrade ~5xx mil" no ctwa-ad-map); resolver CTWA lê mapa estático ANTES do live (apodrece pós-rotação);expand_*sem idempotência (campanha duplicada a cada--execute); 1 foto 404 mata a faixa inteira; rotação de terceiros julga card por spend acumulado do adset (card novo dropado com 1 dia) e NUNCA atualiza pins geográficos; sem dedup entre terceiros (~12% duplicatas no pool); CAPI nunca reenvia lead qualificado (value=10 inerte) e marca rejeitados como enviados; 3 definições divergentes de "conversa" entre scripts; judge de verba com "total fixo" que na prática varia ±20%/dia. Plano em 7 fases (F0 ops → F1 atribuição → F2 meta_api.py → F3 seleção → F4 rotação → F5 medição → F6 criativo), com aceites em dry-run (--executevetado até liberação do Elie). FASE 0 EXECUTADA na mesma sessão (commitf69f04b): o estrago real era ~35 crons perdidos (não 8 — incluía run-rede-enrich a cada 2min, refresh token IG, "Seu dia", survey de atribuição, top-up noturno de boosts 23h, sync_partnerships, dossiê proprietário, CR outreach…) + 4 zumbis ressuscitados re-desligados (3 Pipeimob 13/06 + ranking competitivo 25/06, que rodava JUNTO com o daily-resumo) + flag--partner-matchda conciliação perdida. Mirror reconstruído +install-crontab.sh(diff vivo↔repo idêntico ✅); NOVO cronselect_boosts_ads04:15 +enrich_rede05:00 UTC (pool do Jumper nunca teve cron); pool regenerado na hora (ISCA 464/VENDE 347/ALTO 117, enrichment 1466 ok);fix_geo_targeting.pyresgatado do runtime pro repo; one-shots perdidos (lead-quality-ab 09/07 + resumo-impacto) rodados manualmente e entregues.rotate_creative+claude_judge_metaCOMENTADOS até liberar a conta Meta. Dano permanente: 50 leads CTWA perderam a janela CAPI de 7d no apagão. NÃO restaurados (decisão Elie): onr-retry-fernanda + matricula-265486-retry (gastam créditos ONR). Isso resolve também o intake 09/07 doreconcile_boosts(causa: o wipe). Memória:reference_crontab_wipe_crons_ads_jul2026. (entrada anterior abaixo)2026-07-09 — 📐🚀 AUDITORIA FV + CALIBRAÇÃO EXECUTADA (motor + cascata + terceiros) — relatório em
AUDITORIA-FV-CASCATA-2026-07-09.md. Auditoria de 4 agentes (motor ACM, cascata feeds, terceiros/ads, produção) + implementação do roadmap na mesma sessão ("vamos implementar todos", Elie). NO AR (5 pushes): (1) Estágio 2WEIGHT_BELOW_MARKET65→25 (1411db1— estava vencido:atjob lembrou 09:00 BRT e ninguém aplicou). (2) Rodada P1 meritocracia (c28ad06): NEUTRO empírico +12 (pesquisa de calibração ABORTADA pelo Elie — corretor não crava valor sem ver conservação; mediana do gap do estoque ancorado = +11,5%) + deadband ±10pp (dentro do MAPE ninguém pontua) + demanda negativa só com exposição (≥30 views ou ≥7d em slot pago — quebra a espiral de invisibilidade) + fila de estreia (novo ≤45d nunca destacado ganha test drive nos 4 slots fairness SUPER_PREMIUM) + flags FV/DEMAND live por default (fecha brecha do boost-rotate computar shadow). (3) fetch_boosts INCREMENTAL (bbc5ebe+hotfix8b62856): causa raiz da rotação de boosts PARADA 5 dias (05-09/07) era orçamento (1.159→1.733 boosts × re-enrich total > 600s); agora reusa cache anterior + 150 refresh + checkpoint; validado em prod (1.733 gravados, enrich 275s→25s); timeout GetMyBoosts 90s + guarda captura parcial. (4) FV nos TERCEIROS (62102ab): módulofv_terceiro.py(gate: ALTA+n_predio≥2+gap≤−8+venda, SÓ bônus, nunca punição) → feed 1000 (topo do bucket below + +15 nos tiers pagos) + Jumper CTWA (selo "💎 Abaixo do mercado" no card SÓ com gate — compliance). (5) EXCEÇÃO ITBI (decisão Elie): fonteitbi_prediono motor (7478b69): estudo prédio-a-prédio (3.273 prédios) provou ITBI FINANCIADO mesmo-prédio ratio=1,00 vs rede (o medo de subdeclaração era artefato: area_construida=1,68× útil + 41% transações parciais); fonte peso 4.5 (financiado, proporção=100%, área convertida por fator do prédio/tipologia única, dedup vs rede, ~50 títulos de logradouro normalizados); backtest anti-vazamento APROVADO: MAPE 11,5→10,7%, cobertura âncora prédio 49→56% (+20%); kill switchFV_ITBI_PREDIO=0. Crons novos cloudvero: harvest_vendidos semanal (fonte peso 8.0 estava CONGELADA desde 02/07 — 1ª colheita rodada: 9.638→9.662), refresh_predio_age mensal, early_warning ter 13:30 UTC (nunca tinha sido cronado). RODADA 2 (mesma sessão, "segue todos os itens" + backtest holdout ZSul) — MOTOR-V2 COMPLETO: P174c4135(filtro 534 blindagem + higiene de preços corrompidos na vendidos.db + soldDate real; half-life default OFF via kill switch — provado que piora em mercado plano). P2d481262(SHRINKAGE hierárquico empirical-Bayes prédio→rua→CEP→bairro [nível mais largo=prior, prédio boost 20, CV→confiança contínua] + CALIBRAÇÃO monotônica luxo-direcionada cross-validada em split de teste: sem-âncora 22,6→19,5%, luxo viés −27→−15% ZSul, tier prédio preservado 10,1→10,0, conf ALTA cobertura↑ acurácia↑ 11,3→10,6%). P3fbe414c(CASAS uso_iptu 10/12/14, pools 100% separados, regressão-zero apto provada per-target, cobertura 34% conf honesta ALTA 2,7%/BAIXA 26,4%, sem calibração de apto, F_idade OFF). Curva no /avaliard686fe0(texto P[venda] estava definido e nunca chamado). Medição Estágio 2f64986b(script + cron 24/07 pinga Elie). Holdout ZSul baseline registrado (geral MAPE med 13,7%, tier prédio 9,8%, viés luxo −27,4%; rede congelada/tmp/bt-netcache.pkl); holdout final before/after rodando. Kill switches em tudo (FV_SHRINKAGE/CALIBRATION/CASA/CASA_IDADE/HALFLIFE/ITBI_PREDIO). Próximo ciclo: half-life+índice de tendência juntos, features de LOTE p/ casa (86% em BAIXA), calibração própria de casa, refit trimestral (k/calibração/guardas itbi), purificar 1 endereço casa+apto colidente, medição real Estágio 2 em 24/07. RODADA 3 (miolo R$600k-1,5M, "luxo não é nosso motor de venda", Elie):e6f540d. Diagnóstico cirúrgico REFUTOU vagas/quartos-match/shrink-k/calibração-de-faixa (todos ganho ~nulo ou artefato); alavanca REAL = expoente de área NBR −0,3→−0,9 (apto; casa mantém −0,3) +FV_CONDdefault ON. Backtest regressão-zero: miolo 600-1500k MAPE med 14,8→12,7%, ±10% 34,6→41,8%; tier prédio/ALTA 10,1→8,7%; geral apto 13,6→11,9%; luxo bônus viés −13,2→−7,4%. Motor no TETO (ALTA/prédio ~9% ≈ erro irredutível de comparáveis); daqui "perfeição" = cobertura de âncora (itbi-prédio + harvest), não modelagem. Cache prod final vivo (n=1142). Kill switches FV_AREA_EXP/CASA/COND. Memórias:reference_auditoria_fv_cascata_jul2026,feedback_pesquisa_fv_abortada_neutro_empirico,feedback_itbi_predio_excecao_preco. (entrada anterior abaixo)_2026-07-08 — 📊🔗 Painel do Corretor ao vivo em
/painel(dashboard, admin-only) + fix de subcontagem cross-source. Réplica do protótipo "Painel do Corretor" servida pelo whatsappbot (rotaGET /painel, reusa auth/magic-link do dashboard; link no menu do SPA, some pra não-admin). Achado crítico: o painel v1 subcontava ~3× porque lia só tabelas nativas do bot e casava comissão por email (commissions_received.agente_gestor_emailé NULL em 73% das linhas de 2026). Fix: atribuir pordeal_code(agent embutido em60130NNNN-S) + cruzarpipeimob_transacoes_agencia(fase Estoque) com captações do bot. Resultado ao vivo: vendas 30→90, comissão R$522k→R$1,21M, estoque 90→305. Auditei as demais views: Comissões recebidas/Atribuição/Reconciliação OK; Financeiro+Funil tinham só rótulo de agente em branco (fixcd0d054, cobertura nome 11%→82%). Commitsd84a96d+cd0d054. Gates 34/34. Memóriareference_painel_corretor_crosssource_dealcode. Backlog Fase 2 no P2. (entrada anterior abaixo)_2026-07-06 (noite2) — 🧭🐛 Minisite do cliente NÃO funcionava pra corretor (caso Luciana Kfouri). Causa:
CONCIERGE_ENABLED_ROLESinclui "corretor" → pula o intent-classifier, onde vivia o roteamentodemanda_comprador→minisite. Pedido "link de aptos na Vila Mascote até 600 mil" caía no chat do concierge (reaproveitava página de terreno velha, chamavacadastrar_imovel, ou recusava). O parserimovel_novoque eu tinha validado estava certo mas o corretor NUNCA chegava nele. Fix: nova toolcriar_demanda_clienteno concierge →/demanda <descrição>(cria a página direto); + limiar baixo p/ pedidos curtos; desambigueicadastrar_imovel/cadastrar_comprador. Validado no código deployado: 5/5 frases reais da Luciana →criar_demanda_cliente. Commitsbeeb402+badb86b. Gates 32/32. Memóriareference_concierge_bypassa_intent_demanda. Lição: fluxo do intent-classifier precisa de tool equivalente no concierge. (entrada anterior abaixo)_2026-07-06 (noite) — ⏰🧾 Watchdog PROATIVO de parcela de comissão (Nível A) + extrator lê datas. Continuação do caso Hanna. (1) Extrator do CCV agora lê o vencimento de cada parcela (mapeia tranche→inciso do preço→data, casando o algarismo EXATO i≠ii≠iii) e trata proporção aninhada como 1 tranche por momento (81% de 50% = 40,5%+9,5%, não agrupa) — corrige o exemplo que ainda mostrava 2 tranches. Validado no 1002-92: p1 40,5%/2026-07-06, p2 9,5%/2026-08-05, p3 50%/null (2 runs consistentes). Commit
72ed45d. (2) Novosrc/scripts/parcela-comissao-watchdog.ts(Nível A: lembrete + 1 toque, NÃO auto-emite) +src/handlers/parcela-cobranca.handler.ts(botõesparcemit_/parcesnooze_) — na data prevista da próxima parcela pendente, cutuca o corretor com [✅ Emitir][⏳ Ainda não]; "Emitir" dispara/cobrar <deal> pN(que ainda tem preview+confirm). Conta emitidas via Stark, anti-spam (3d/teto5/snooze7d), botões só na janela 24h. Commite1100b1, deployado. DRY_RUN ok: 1002-92 → lembraria p1 R$12.150 à Hanna. Gates 32/32. CRON LIGADO (0 13 * * *= 10h BRT, cloudvero, OK Elie 06/07) — 1º disparo real amanhã. Ressalva: fora da janela 24h cai em alerta genérico sem botão (template HSM dedicado ficaria 24/7). (entrada anterior abaixo)_2026-07-06 — 🧾🐛 CCV com comissão em % ANINHADO ("81% de 50%") era extraído errado + gap demanda "prédio novo". Testes reais (Hanna cobrança / Luciana demanda por áudio). (1) Extrator de comissão (
index.ts~24086): o LLM chutava os R$ das parcelas (deal 1002-92: "50%/50% sendo 81%/19%" de R$30k virou R$15.300/R$14.700). FIX determinístico deployado — o modelo devolve o PERCENTUAL literal de cada cobrança e o código calcula o R$ (ajusta última parcela p/ soma exata); vale p/ todo CCV futuro. Typecheck + 32/32. (2) Deal 1002-92 (Hanna) regravado com 3 tranches (decisão final Elie): p1=R$12.150 (40,5%=a-ii) · p2=R$2.850 (9,5%=a-iii) · p3=R$15.000 (50%=parcela b), total R$30k, rateio 4 benef preservado. Idêntico à extração geral → sem override/drift (re-extração dá o mesmo). (3)parseDemandacapturaimovel_novo("prédio novo/recente/lançamento") + match prioriza recentes viaanoConstrucao(enrichmentyearMonthBuilt, bônus soft ≤5a/≤12a/≤25a, nunca exclui). Validado no deploy com a frase real da Luciana (imovel_novo=true, V.Mascote, 600k, conf 0,9). Commitsd03b8b2+f856114. Ambos liberados p/ Hanna e Luciana testarem. (entrada anterior abaixo)_2026-07-03 — ✅🛠️ EXECUÇÃO DA AUDITORIA (Opus 4.8): 5 fixes CRÍTICOS + REF-0 no ar. Todos com worktree→gates→push (typecheck + suíte 24→29 testes, +5 testes novos). FIX-1 ERP:
/aprovarbloqueia payable CANCELLED (classifyPayableApprovalBlock+ date-bucket filtra terminais) — fecha pagamento duplo pós-/alterar. FIX-2/cobrar:findPaidCommissionRowfiltra parcela (COALESCE(parcela,1)=?) — p1 paga não libera dispatch da p2 + alerta financeiro no dispatch-fail. FIX-3/cobrar:split-invariants.util(Σ rateio=comissão ±max(R$1,0,5%), sem CPF dup; Σ splits≤invoice) bloqueia registerDealSplits/fan-out em 2 sites + alerta. FIX-4/precificar:preco-parse.utilBR correto (300.000,00→300k, não 30M) + teto R$500M + anti-deadlock precAdjust×GeoAnálise. FIX-5/dd:party-slot.utiltable-aware (dedup CPF→merge nome→anti-clobber) nos 3 writers laterais (sync-pipeimob 0→1-based, sync-ilist, party_extracted_data) — fim da linha híbrida nome-A/CPF-B. REF-0: deletadocreateCobrarInvoice+cadeiapendingPixCollection(código morto, −659 linhas, index.ts 27585→26926). SEC-1 adiado (mexe em emissão fiscal viva; Elie despriorizou). REFACTOR Bloco A COMPLETO (F1-F5, cada um worktree→gates→push, 29/29 testes): F1 Help→help.handler; F2 /reportar→reportar.handler (+Map exportado); F3 /auditoria//prazos//posse//prazo→prazos.handler; F4 registerWizards→wizards/register-wizards (params p/ evitar circular); F5 deletados schedulers mortos. index.ts 27585→24762 (−2823 na sessão). Padrão validado: extrair via script → merge → typecheck acusa deps faltantes → wirar getters/imports. PENDENTE: Blocos B-E+F19 (~−12k linhas → ~4k). Plano+checklist emPLANO-EXECUCAO-OPUS-2026-07.md. (entrada anterior abaixo)_2026-07-02 (noite) — 🔍🐛 AUDITORIA GERAL DO REPO (6 agentes paralelos, read-only) — relatório completo em
AUDITORIA-GERAL-2026-07-02.md. Cobertura:/cobrar,/dd,/avaliar,/contas/ERP, refactorindex.ts, higiene/segurança. 8 achados CRÍTICOS, destaque: (P0 segurança) senhas dos 3 certs e-CNPJ (Studio76/Suzana/SOCII) hardcoded em scripts COMMITADOS + uma no nome do arquivo.pfx→ trocar senhas + expurgar histórico; cert CENPROT vence 17/07 sem alerta no código. (P0 financeiro) ERP:/aprovaraceita payable CANCELLED (pagamento duplo pós-/alterar) + sintaxe de confirmação de provisão instruída na UI NÃO EXISTE no parser (4.500,00vira ids 4/500/0);/cobrar:tryReleaseAndDispatchlibera splits da p2 usando pagamento da p1 (query sem parcela, index.ts:7690) + Σ rateio do LLM sem validação em código (só no prompt); NFS-e parcelado sai valor cheio na p1 (regime de caixa). (P1) dedup ERP só barcode (pix/folha duplicam); party_index vivo em 3 writers laterais (certidão paga pro CPF errado);/precificar 300.000,00→R$30M (parser); retry Plexi perde?certificate=(CENPROT). Refactor index.ts (27.524 l, +2,1k desde 12/06): plano em 5 blocos A-E → ~4k linhas (Bloco E = /cobrar+fotografia ⛔ congelados, precisa liberação). NADA foi alterado — auditoria pura. [decisões Elie, mesma noite] Certs: NÃO trocar senha/expurgar (só impostos; mover p/ .env). Confirmação de valor PROVISIONAL: deixar como está. Aprovados: FIX ERP CANCELLED + /cobrar parcela-dispatch + Σ rateio + parser /precificar + party_index writers + Refactor COMPLETO A→E+F19 (Bloco E /cobrar+fotografia DESCONGELADO — "concluir de uma vez por todas", alvo ~4k linhas) + REF-0 deletar createCobrarInvoice morto. Merge leadbot de outra sessão não bloqueia. Execução delegada ao OPUS 4.8 (economia de rate limit) viaPLANO-EXECUCAO-OPUS-2026-07.md(checklist com âncoras verificadas, receita de extração, regras de worktree). (entrada anterior abaixo)_2026-07-02 — 🔬📉 Revisão crítica do estudo + 3 estudos novos EXECUTADOS + taxonomia das 3 fontes. Diagnóstico completo em
operations/apresentacoes/estudos-captacao/DIAGNOSTICO-GAPS-E-PROXIMOS-ESTUDOS.md: (1) Taxonomia corrigida (Elie) — rede RE/MAX=PREÇO/tempo realizado; ITBI=ONDE/quanto transaciona (NUNCA preço, subdeclarado; subset financiado a validar — ratios vieram contraintuitivos); ZAP=INTENÇÃO/leading. (2) Early-warning (o achado do dia):webViewsCountdo iList separa brutal — 0 views = 3% de conversão vs 44-56% com 30+; triagem achou 54 de 227 CRs ativos na zona de morte (<10 views/mês, ≥45d, maioria alto padrão + 1 erro de cadastro 011-350 "R$8k"). Produto proposto: cron semanal fix-in-chat de reprecificação. (3) ITBI×expirados (nível de unidade): só 5% "vendeu sem nós" (46% prédio-level era efeito-condomínio) — ~95% dos expirados NÃO transacionam = problema é preço na entrada, não concorrente. (4) Backtest FV-conceito: MAPE 17,8% (bairro+área não basta) = benchmark que o motor FV precisa bater pra sair do shadow (rodar acm_engine em batch nos 447 vendidos = próximo). (5) Playbook do novato (score bairro: Ipiranga 93, Santo Amaro 83; faixa 400-650k, apto 2 dorm, até +15% do FV, cadastro 70+, corredor-escola V.Mascote→Ipiranga). Críticas FV/3D (sair do shadow; 32% confiança BAIXA; score multiplicativo; plugar bairro-liquidez; fechar loop com desfecho dos boosts). Scripts persistidos (49). [tarde] Sequência 1+3 executada: backtest do MOTOR real (MAPE 13,6% vs 17,8% ingênuo; anti-vazamento) revelou confiança INVERTIDA →_conf_calibradaimplantada no ACM (ad7b526, live: ALTA=8,7% MAPE/66% em ±15%; BAIXA se sem-idade ou pool 15+).early_warning.pyLIVE (cron ter 13:30 UTC, piloto→Elie; 1º resumo enviado: 49/214 na zona de morte; 011-350 era locação 8k/mês). route-corretores IMPLEMENTADO e validado (9e040d6): bot/internal/early-warning+ botõesewrp_*(Reprecificar/Falar com dono/Manter — reusa sendPricingGraph; bot NÃO edita preço de ativo, orienta); python gate conf ALTA+gap>25%+cooldown 30d. Cache FV regenerado com_conf_calibrada(ALTA 320→162). Dry-run: dos 49 invisíveis, 1 gate-approved (1080-11 Moema R$2M, gap +36%, justo ~R$1,17M — Gildasio); o suspeito 1011-336 (+234%) caiu pra BAIXA como esperado. Decisão Elie: NÃO pingar número (prova dos 8: 7/8 gate-approved históricos venderam no preço PEDIDO — gap grande seleciona erro do MODELO, não imóvel caro; nem benchmark bairro+área salva). Rota (b): só radar-piloto + melhorar o motor. Implementado tier PRÉDIO (b74212d): backfill vendidos.db 4,5k→9,6k + fonte predio_vendido peso 8.0 → re-backtest MAPE 13,6→10,8% (tier prédio: 6,8%, 74% em ±15%, 49% de cobertura; conf ALTA 7,8% n=141). 6/8 casos-vergonha seguem sem proteção de modelo (prédio sem histórico) → número na boca do bot continua PROIBIDO; ganho vai pro /avaliar. [noite] Auditoria downstream (pergunta do Elie: 'avalanche?'): DESCOBERTO que o FV está LIVE no destaque (±65pts) e na peneira/below_market (FV_SHADOW=0no run-full-sync desde ~15/06) — 16/33 flips vs ZAP no run de hoje, com viés medido (premium −21,6% → "caro" injusto → sem mídia → invisível = condenação auto-realizável). Boost terceiros (select_boosts_ads) LIMPO (zero FV). Fix deployado45ce49d: FV só substitui o ZAP com n_predio≥2 (prova dos 8 aplicada à meritocracia); sem evidência de prédio → ZAP manda (pré-Fase-2). [03/07 manhã] Stress test ZAP + auditoria completa (34 algoritmos): ZAP price_vs_market REPROVOU (39% concordância c/ padrão-ouro prédio; demanda FLAT below 15,1 vs above 13,8 views/mês; 54% do estoque 'below') — maior peso da meritocracia é quase-aleatório individual; flips 15/16 neutralizados pelo gate prédio; cache 15:05 com 187 (24%) ancorados por prédio. Inventário (agente): 34 algoritmos, 30 ✅, 2 ❌ AMBOS NO META: 🚨P0 conta act_2453510681779882 status=3 UNSETTLED (billing!) → CTWA 26→3→0 leads/dia, canal MORTO ~2d, cards zumbi sem poder pausar → AÇÃO ELIE: quitar cartão no Gerenciador; + judge Meta crashava diário (ilist_load 3 valores) → FIXADObf2c391. market-demand stale 22d. Correção: ad-strategy TEM histórico (market-history/ desde 31/05) → backtest ZAP×desfecho possível futuramente. Doc §9-10. [decisões Elie 02/07 tarde] Meta/Google suspensos DE PROPÓSITO (balanço de investimentos) — retirar pressão do cartão; próxima entrega = relatório de resultados de mídia. Estágio 1 LIGADO (313df12: DEMAND_SHADOW=0 no run-full-sync → demanda real ±25pts live no destaque+peneira a partir do sync 17:00 UTC). Estágio 2 agendado 09/07 (peso ZAP 65→25, opinião aceita;atjob 15 lembra o Elie 09:00 BRT). Harvester ZAP: rodou 65/82 bairros + cron semanal seg 01:00 BRT (nunca teve cron — causa do stale). (entrada anterior abaixo)_2026-07-01 (tarde) — 📈🗺️ Precificação v2: curva de TEMPO calibrada POR BAIRRO (rede RE/MAX) + resumo executivo pro Samuel. Evolução da ferramenta de precificação: o gráfico de tempo agora é específico do bairro, calibrado com 7.873 vendas reais da REDE RE/MAX SP (pull
GetListingsToExcel2sem officeFilter, status 533 → 13.453 vendidos, DOM real por bairro).whatsappbot/src/utils/bairro-liquidez.util.ts= 102 bairros (Ipiranga 0,72=78d líquido; Vila Mariana 1,29=138d lento);diasEstimados(ratio,factor);sendPricingGraphresolve o bairro do endereço/rótulo. Só TEMPO — a CHANCE segue global porque testei e ITBI NÃO prediz nossa conversão (r≈-0,2), calibrar chance por ele seria ruído. Implicação: bairro líquido (Ipiranga) → argumento de exclusividade é a CHANCE, não a demora; bairro lento → a demora pesa. Gates typecheck+24/24. Commitaf2057a(pushado, deploy ok, re-disparado pra Luciana+Elie). Scripts da análise persistidos emoperations/apresentacoes/estudos-captacao/scripts/(44 .py + README; dados brutos NÃO versionados, regeneráveis). Resumo 1pág pro CEO (operations/apresentacoes/resumo-ferramenta-precificacao-ceo.md) posicionando a ferramenta como diferencial competitivo (dados proprietários + rede + 102 bairros; +R$2,6M/ano do sell-through). Memória:reference_grafico_precificacao_captacao. (entrada anterior abaixo)_2026-07-01 — 📈💰 Ferramenta de precificação na captação — LIVE em produção. Nasceu do dossiê de captação (30/06): imóvel captado caro converte muito menos. O corretor agora, no
/avaliar(valor justo por ACM) ou no novo/precificar <valor>(valor que ele digita; aliases/precifica/grafico), recebe dois gráficos pra mostrar ao proprietário: chance × preço (qualitativo — zonas baixa/média/alta, sem % cravado) e tempo × preço (banda de dias com a linha da exclusividade 180d; curva inclinada pra cruzar 180d no +30%). Ajuste inline fix-in-chat: botão 🔧 Ajustar valor + responder só um número refaz na hora (sem comando pra decorar). Render SVG→PNG viasharp, em processo (sem Python/matplotlib). Código:whatsappbot/src/utils/pricing-{curve,chart}.util.ts+avaliar.handler.ts(sendPricingGraph) +index.ts. Gates: typecheck + 24/24 testes. Commitsd4575c4→5ccedb9(pushados, deploy confirmado botjuridico). Entregue ao vivo pra Luciana Kfouri (captação studio Ipiranga R$300k) e Elie via webhook local. ⚠️ Calibração v1 GLOBAL apto — NÃO é o motor 3D; recalibrar trimestral (data de venda real viaGetListingsToExcel2); v2 pendente = segmentar por bairro via ITBI. Rodar ACM real antes de cravar preço (studio é segmento fraco). Memória:reference_grafico_precificacao_captacao. (entrada anterior abaixo)_2026-06-30 — 📊🎯 Dossiê de captação (CR) para reunião CEO 03/07 — estudo completo sobre dados reais. Extraí o universo de 2.953 CRs do iList (todos os status) + a data de venda REAL (descoberta: a API
GetListingsnão trazsoldDate; só o exportlistings/GetListingsToExcel2→fileToken→DownloadTempFile, col "Data da Venda" — memóriareference_ilist_data_venda_excel2). Achados: conversão de mandato ~39% (NÃO 25% — o 25% era contaminado por importação legada de 1.087 CRs em 15/05/2023); velocidade mediana 129d, 65% dentro dos 180d do CR (odaysOnMarketda API é furado, não usar); conversão por faixa (400-900k ~50%, +1,3M 27%, locação 2%), por qualidade de cadastro (70+ converte 3× o 50-69), e por coorte (tempo de casa quase não muda — é a "lista de compras"; veterano capta alto padrão que gira menos); estudo 3D mercado(ITBI)×conversão×presença revela concentração em bairro pequeno (Vila Mascote) e ausência nos grandes acelerando (Brooklin/V.Mariana/V.Clementino/Moema). Estratégia "captar menos, captar certo" (5 gates: perfil·preço-FV·geografia·kill-switch mês 9·qualidade). Impacto modelado: 33%→50% sell-through = +R$2,6M VGC/ano (~+R$0,7-0,8M lucro, break-even já coberto), sem captar mais. Entregue:operations/apresentacoes/dossie-captacao-{executivo,tecnico}-03jul2026.md+dossie-captacao-slides.html+ 13 gráficos emdossie-cr-graficos/. Commitede0c2c(+ fold do impacto). Ressalva registrada: não validei "preço>justo→converte menos" (FV só pontua ativos). Pendente ops: push (não dei) + ajuste do matching ITBI por acento. (entrada anterior abaixo)_2026-06-24 (noite, encerramento) — 🎡🏷️ Rótulo do feed do bolsão: "Últimos leads desta rodada" (era "arrematados"). Caren Bertalot (
1083) foi reintroduzida no bolsão de impulsionamento hoje e apareceu 2× na seção de últimos leads (#689 e #672) → alguns corretores estranharam ("pegou duas vezes"). Causa não é furo: o carrossel é 1ª-clica por rodada e zera quando todos pegam (carousel.util.ts); a seção só mostrava o ciclo recente, mas o rótulo "Últimos leads arrematados" soava como placar de quem mais pegou. Fix (5618210, leadbotimpulsionamento.flow.ts): troca nas 2 ocorrências (cauda do perdedor + resumo de observador) para "📊 Últimos leads desta rodada:" — enquadra como lista do ciclo, não favorecimento. Buildtsclimpo, push feito. Decisão Elie: NÃO polemizar — sem broadcast ao time; a mudança de rótulo resolve o estranhamento sozinha. (entrada anterior abaixo)_2026-06-24 (madrugada) — 📸🎬 Mídia do fotógrafo: link Drive pro corretor + Reel com aprovação + conteúdo em imóvel ATIVO. Sessão sobre a entrega da House Way (jobs 1018-386 e 1018-387, "Rua Maratona"). (1) Link do Drive vai pro corretor (
6824ea3):attachLinkAndPushmanda o link do Drive ao corretor dono junto com o pedido de aprovação (fix-in-chat) — antes o link só ficava no DB/iList, o corretor não recebia. (2) Aprovação de Reel por botões (5b5bea2, migration v135youtube_video_queue.approval_sent_at): Reels (fb_reel/ig_handoff) nascem comoawaiting_corretor_approvale o bot pede ✅ Aprovar / ❌ Recusar ao dono ANTES de publicar no FB/IG — antes publicava direto sem aviso (handoff IG ia só pro Elie). Aprovar→pending(worker posta); Recusar→cancelled+aviso admin. (3) Conteúdo de fotógrafo em imóvel ATIVO — exceção sancionada (Elie 23/06) à regra "só Rascunho" de 07/06: fotos (6824ea3, append-only, nunca apaga as existentes) e link YouTube (cadcdac, só grava em Ativo se o campo estiver VAZIO — nunca sobrescreve link do dono) passam pro iList mesmo em Ativo (532). Resolveu o 1018-387 (Ativo) que tinha ficado sem fotos e sem YouTube no iList. Estado verificado: 386 (Rascunho) e 387 (Ativo) com YouTube gravado no iList; FB Reel postado nos dois; IG postado só no 387 (386 falhou por 503 da Meta, ficou em handoff). Bônus: corrigidos 4 literaisBuyerProfilesemextra_ids/exclude_idsque quebravam o typecheck (do commitde07b21). Memória:reference_conteudo_fotografo_ativo_e_aprovacao_reel.md. (entrada anterior abaixo)_2026-06-23 (encerramento) — 🔍📡 Auditoria C2S + fix aviso falso-positivo. Auditoria completa da arquitetura de leads C2S: (1) C2S está ativo —
c2s_api_intake.pyroda a cada minuto, último lead hoje (Isabelli/chavesnamao 88948635→#647). (2) 68 leads transmitidos ao bolsão via WA desde jun/15 com aviso "também no C2S/Vetra"; 44 com aviso correto, 24 sem (pré-implementação). (3) Bug corrigido (e74663c):leadAlsoInC2sdisparava aviso para leads da conta 1000 (terceiros, webhook Canal Pro direto) porquecpro:...era armazenado emc2s_idpara dedup — fix exclui prefixocpro:da checagem. (4) 142 leads com c2s_status=new sem roteamento — maioriaappended_existing(lead já estava em estado terminal quando c2s_id foi anexado), comportamento correto. Memória:reference_c2s_arquitetura_e_auditoria.md. (entrada anterior abaixo)_2026-06-23 (noite) — 🎯🏠 Conversão Google Ads + experiência completa dos minisites (estilo ZAP). Diagnóstico da baixa conversão do Google (~700 cliques/30d → 2 leads = 0,3% vs Meta 106): pipeline de conversão offline (gclid→venda→upload) saudável; LeadForm nativo preso em review (0 impr); conta ficou 4 dias dark (cartão Mastercard recusado — Elie destravou); 1 anúncio reprovado apontava pra imóvel vendido (022-4) → 404 (pausado). Causa raiz = funil/destino: anúncio de busca ampla ("apartamento brooklin") caía num imóvel ÚNICO → bounce (a atribuição JS→bot+GAds + form /lead estava certa). FIX principal — landing pública
/resultado(94feb95): seleção de imóveis below-market por bairro/tipo reusando o motormatchForProfile(espelha o carrossel do Meta), atribuição preservada (CTA→StudioBot+GAds, form→/lead, gclid propagado), indexável, liberada no nginx (location = /resultado); A/B em curso (2 ad groups Brooklin ISCA + Santo Amaro VENDE → /resultado, resto = controle em /imovel/{id}). Reaper+refill (5037596+a5d1210):reconcile_boosts.py --reap --refillpausa ad de imóvel vendido/inativo (espelha o guard de status dos portais — enforce_cr só pausava por CR vencido) + reabastece a vaga Google com o próximo below-market (ticket≤400k, NÃO gap); cron ativado (--execute --prune --reap --refill, 09:30 BRT). Cards estilo ZAP UNIFICADOS em todos os minisites (0c78d1a+af3c5ee):card.tscompartilhado (linha-resumo + ícones m²/quartos/banheiros/vagas + Cond/IPTU + selo 💎) na landing + cliente + corretor + vitrine; fix de dados (mapListing lia campo errado do enrichment: área 0→235/237, IPTU 0→192/237, descrição vinha vazia→ilist_description). Detalhe (b841800): descrição completa + mapa de localização (Google embed sem API key) na own + rede. Navegação (6e1a063): "Imóveis parecidos" não dão mais 404 → rota escopada/c/{slug}/d/{id}(visitante fica na marca do corretor, igual ao minisite do cliente); selfPath correto no WhatsApp. Selo "🤝 em parceria com {dono}" (6e1a063+06eff3d): parecidos, detalhe escopado e storefront do corretor — cobre parceria iList (secundário/representante) + bolsão + curado, validado em 6 corretores. Hotfix (fe5fb36): build de produção quebrado por outra sessão (whatsappServiceno /internal/send-text). A/B agendado (auto):ab_resultado_report.py(4839571, auto-detecta o grupo teste pelo final_url, veredito escalar/segurar/inconclusivo via DM) + jobat#12 no cloudvero dispara 07/07 12:00 UTC (09:00 BRT) → DM do veredito pro Elie. Memórias:reference_landing_form_e_google_leadform_webhook,reference_ads_reaper_e_replacement,reference_minisite_enrichment_campos. (entrada anterior abaixo)_2026-06-23 (observer, anterior) — 👁️🤝 Observer bolsão + Parceria automática minisite — LIVE + backfill 66 pares. (1) Observer bolsão (
2db7cf5+6fa9976): Elie/Suzana/Carine recebem pre-reveal (oferta saindo pro corretor) E reveal completo (nome+tel+briefing+imóvel) via Baileys relay (POST /internal/send-text) — sem restrição de janela 24h que quebrava o Cloud API. (2) Parceria automática de bolsão (873b9c8): quando corretor ganha lead de imóvel alheio (tier 3), o imóvel entra permanentemente no minisite do vencedor com badge "🤝 [nome do dono]";registerBolsaoPartnershipidempotente (source='bolsao', imune ao sync iList); endpointPOST /internal/bolsao-parceria; backfill histórico: 74 casos → 66 pares únicos registrados (inclui Denise 1101 no 1016-285 da Nilza). Observar amanhã conforme leads chegam. (entrada anterior abaixo)_2026-06-22 (anterior) — 💰🔧 ERP A/P: fix PIX-only (Central de Cadastro) + fix GFD FGTS (Contabem) + pagamento FGTS 05/2026. FGTS 05/2026 Studio76 (R$182,73, venc 22/06) pago via Stark (ID 4505199798386688) — a guia recalculada foi skipada com
skipped_third_party_tax(falso-positivo: subject do email Contabem menciona "FGTS Studio76 + Suzana Rodrigues Lee" no mesmo assunto → needle SUZANA + keyword FGTS ativava a regra de terceiro). Dois fixes deployados (1cb23eb): (1) guard Studio76 em detectThirdPartyTax — se description do PDF contém "STUDIO76"/"31317062", retorna null mesmo com needle de terceiro no subject; (2) fallback QR OpenCV para GFD — quandoextractPaymentFromPdfretorna amountCents mas sem barcode/brcode em PDF GFD image-only, converte para PNG via ImageMagick e decodifica QR viacv2.QRCodeDetector(validado funcionar com GFD da Caixa). Varredura de junho/2026: tudo pago exceto FGTS (agora resolvido) + Royalty RE/MAX parcela 4/25 R$4.206,01 vence 30/06 (PENDING). (entrada anterior abaixo)_2026-06-19 (anterior) — 🏠🤝 Minisite do CLIENTE comprador (F1+F2+clique/auto) + Parcerias internas — TUDO LIVE. Sessão entregou, com smokes ponta-a-ponta no cloudvero: (1) Minisite do cliente — página viva por lead (
/c/{slug}/cliente/{token}), seleção FV/ACM (próprio+Boost) + selo "💎 abaixo do mercado", imóvel clicado em HERO no topo, agendar visita (v127visitas, ping fix-in-chat), selo privacidade/noindex, trigger automático quando o lead ganha dono (leadbot→/internal/cliente-auto, manda link pronto pro corretor), e gestão 1-toque (/clientelista interativa + botão 🗑 Remover + remover por nome). Migrations v126/v127. (2) Parcerias internas — Corretor Secundário/Representante do iList → paridade total de ACL (/raiox /dd /dossie /impulsionar /cobrar viacanAccessListing) + imóvel do dono no minisite do parceiro; v128listing_partnerships,sync_partnerships.py(cron 10:00 UTC), 125 parcerias carregadas. (3) Fix entrega da pauta semanal (fila StudioBot, era órfã do wa-assist). Regra firmada: comissão segue co-corretagem, o que vale é o CCV (não é pendência). Memórias:reference_minisite_cliente_comprador,reference_parcerias_internas_ilist,reference_pauta_semanal_automatica. (entrada anterior abaixo)__2026-06-19 (sessão anterior) — 🏠 Minisite Luciana Kfouri (sessão encerrada): UX unificado no checkout local (grade única próprio+rede+interno, sem badge Parceria, busca por código, refresh fotos rede) — não commitado/pushed (
list.view.ts,layout.ts,index.ts,ilist-rede-cache.service.ts). Já em produção (sessões anteriores): compartilhamento interno 60130, CRECI no header, fix botão Tirar do minisite,/ajudaminisite, logo→/c/{slug}, rede em/c/{slug}/rede/{id}. Pendente ops (shell bloqueado nesta sessão): reincluir601301089-18(estúdio Paula) no minisite agente1105— hoje 404 em/c/luciana-kfouri/601301089-18. Scripts prontos:ops-scripts/add-minisite-internal.cjs,trigger-minisite-internal-webhook.cjs; código novo local:/curado-add+GET /admin/minisite-curado-add(precisa deploy). Ação rápida: Luciana manda601301089-18no bot OUssh cloudvero+ tsx addCurado._Sessão 2026-06-18 (noite) — 📊 Leadbot + ACL /leads*: (1) CTWA de corretor cadastrado agora cria lead (
561bd22) — Nicolly 22:17 tinha sido redirecionada pro StudioBot; ad120252418545540110→601301101-3no mapa Proprio_Corretor. (2) /leads* expandido (529b4af): Suzana, Carine e Samuel liberados no StudioBot (Nicolly já tinha override). Pendente: Nicolly retestar clique CTWA p/ confirmar lead novo._Sessão 2026-06-18 (tarde) — 🔍 Consulta ENEL/Yara: ENEL maio/26 (2 faturas: R$30,17 + R$295,75) já pagas em 09/06 por Elie. Yara não tem nenhum payable ENEL — tentativa dela provavelmente não gerou registro (PDF ilegível antes do fix de hoje ou barcode vetorial). Dedup PAID funcional: reenvio Uninove 14:37 bloqueado corretamente.
_Sessão 2026-06-18 — 🧾🔒 ERP A/P: 4 fixes entregues. (1) Bug linha digitável Uninove corrigido (
4d53a30): PDFs com barcode vetorial (Uninove/Santander) agora passam por vision fallback via Claude Haiku — extrai a linha digitável da imagem. (2) Limites de aprovação por usuário viaDIRECT_PAY_LIMITSenv var (09e86c7): Wilton R$500, Yara R$700, Elie/Samuel R$1.000 (padrão). Wilton adicionado aFINANCIAL_ADMIN_NUMBERS. (3) Comprovante PDF via WhatsApp (63bce34):sendComprovanteToRequesterfaz upload do PDF + email ao solicitante — dual-sig via webhook, pagamento direto fire-and-forget logo após/aprovar. (4) Dedup boleto PAID (7d35315+fe229d9):findActivePayableByBarcodeagora inclui payablesPAID— antes excluía, permitindo reregistro de boleto já pago; mensagem diferenciada "já foi pago" vs "já em aberto"._Sessão 2026-06-17 — 📸✅ Ciclo de fotografia Nilza/Estevão + Leo liquidado. (1)
/foto-dispatch <agent_code>admin command deployado (adminDispatchReadyForAgentpublic emcobranca-fotografia.service.ts): força dispatch de sessõesready_to_paysem precisar do fluxo de aprovação via WhatsApp — útil quando botão expirou ou roteamento falhou. (2) Bug "Fernando" corrigido: apelido do fotógrafo estava hardcoded; agora lêfotografos.apelidodo DB. (3) Nilza desbloqueada via/foto-dispatch 1016: R$1.800 PIX Estevão (4 sessões), invoices corretoras emitidas; sessão 285 retida (sem link) → Estevão pinged via HSM → mandou link → 43 fotos arquivadas → R$450 PIX + invoices Nilza R$50 + Caren R$50. (4) Suzana (sessão 63) sem CPF no DB → CNPJ41516818000149(split_receivers) → invoice criada manual via MCP Stark. (5) Auditoria Estevão 16 linhas: R$4.721 = R$1.830 pago + R$2.891 pendente — 100% batido. (6) Auditoria Leo 9 linhas: R$5.800 = R$5.100 pago + R$700 pendente (Angela R$350 + Hanna R$350, sessões 78+77, legítimas). (7) Stark #fotografias center ID =5708512499859456(salvo em memória). Pendente: arquivar planilhas de fotógrafos no Google Drive (feature não iniciada — backlog).Sessão 2026-06-16 — 📞🏷️ Discador de captação testado ponta-a-ponta + abre pelo NOME (Assertiva). Sessão de voz/captação: (1) ramal de teste 9001 agora toca o captador de CR (não o atendedor inbound) — patch no
server.py(3c9bbd8) faz o UUID-sentinela honrarVOICE_CAMPAIGN=captacao; discar 9001 no Zoiper (Tailscale) p/ ouvir a voz. (2) auto_deploy ganhoudeploy_voice_pipecat(a8ec483) —leadbot/voice-pipecat/não era observado por nenhum trigger (agora rsync.py+ restartpipecat-voice; preserva.env/.venv/transcriptsDNC/recordings); rodou sozinho às 16:08 (1º uso). (3) Fluxo encadeado WhatsApp→"📞 Pode me ligar" caía no MockVoiceProvider (não discava) — seteiLEADBOT_VOICE_PROVIDER=pipecat+PIPECAT_SERVICE_TOKENnoleadbot/.env+ restart (era a razão da pendência "validar ponta-a-ponta"). (4) Discador SmartyDeed (smartydeed_dialer.py) validado REAL com Nilza e Hanna (campaign captacao, engine grok, DID 11 5441-0781; CSV de 1 linha p/ mirar sem tocar a lista). (5) NOME na abertura:Nome→lead_name(23d0567); SmartyDeed não tem o nome (campo "Nome / imobiliária" do detalhe vazio 0/12 — só telefone); Assertiva/localize/v3/telefone(telefone→titular) enriquece só no--yes, pós-guards, cacheado, ~R$0,55/nº (76f514d); abertura CONFIRMA "Falo com {nome}?" e pivota gracioso se for familiar (367fb55, decisão Elie — titular da linha pode ser parente: nº da Hanna→"Ignácio Yoshida"). Pendência: ouvir 1 ligação ao vivo com o confirm-name. Memórias:reference_assertiva_telefone_nome.md,reference_discador_captacao_nome_e_9001.md.Sessão 2026-06-14: 📸🌉 Pacote completo de dúvida/correção na cobrança de fotografia + manual embutido no bot. Fechei o fluxo ponta-a-ponta da fotografia: (1) bridge mascarada corretor↔fotógrafo (commit
f730de2, migration v115photo_bridges) — dúvida classificada como "correção" abre relay pelo bot (números nunca trocados); corretora resolve por botão: "Tá certo ✅"→retoma cobrança / "Vai corrigir 🔧"→awaiting_fotografo_fix+lembrete diário ao fotógrafo. (2) Dúvida não detalhada aciona o fotógrafo (76fc7de): corretora abre dúvida e fica calada ~5h → cron alerta o fotógrafo 1×/dia (pagamento parado, contate a corretora) via HSM, escala pro Elie após 5. (3) Correção/retirada sem duplicar (f8ec5f9): supersede deal-scoped em ambos os caminhos de reenvio (texto+imagem) + comandocancelar <código>. (4) 3 HSMs UTILITY aprovados na Meta (studio76_fotografo_duvida/_pendencia/_corretor_sem_detalhe) — REVOGA o "sem HSM fotógrafo" (131047). (5) Manual embutido no bot (62b5426, migration v117manual_v1_sent_at): welcome ganhou seções de corrigir/retirar/dúvida +maybeSendManual()entrega 1× aos 7 fotógrafos já onboardados, na próxima interação (em janela aberta, sem blast/HSM). Tudo no ar e verificado no cloudvero (v117, bot active, gates 18/18). Memória:reference_foto_bridge_e_hsm_fotografo.md.Sessão 2026-06-12: 📸 Fotógrafo Estevão onboardado + raiz do falso "sem valor no iList" corrigida. Cadastrei o fotógrafo Estevão Goes (
5511970748167, PIX chave CNPJ66.735.501/0001-24Nubank, DICT confirmado) no ACLfotografos+ onboarding completo via WhatsApp (cobrança → link → aprovação corretor → PIX → NF). No 1º batch real dele (16 imóveis) caçamos um bug: imóveis apareciam como "sem valor no iList" e travavam a cobrança — mas SEMPRE tiveram valor (intuição do Elie). Causa:getListingPriceCents(ilist.service.ts) fazia 1 tentativa só e retornavanullsilencioso sob carga (15 scrapes paralelos no cold-start pós-restart), e o fluxo tratavanullcomo "sem valor" → bloqueava cobrança legítima. Fix deployado (834e793, schema v113):getListingPriceCentsDetailedcom retry 3×+backoff e flagconfident(distingue "sem preço" de "não consegui ler");enrichRowsBatchedlê em lotes de 4; leitura instável viravalor_indeterminado(não bloqueia, não pinga, pede reenvio). Feature nova: valor CONFIRMADAMENTE ausente → bot pinga o corretor dono via HSMalerta_sistema_studio76("cadastre o valor que libero o pagamento do fotógrafo"), dedup 7d (photo_value_pings). Memória:reference_ilist_scraper_falso_sem_valor.md.Sessão 2026-06-11 (discador): 📞 Discador de voz IA: trunk Directcall NO AR + 1ª conversa real + roteiro de CAPTAÇÃO (commits
112030e,a3fef1b). Trunk SIP ativado (DID 11 5441-0781, login NJ2Z7, Asterisk Registered no cloudvero, firewall só IPs Directcall) e 1ª ligação ponta-a-ponta validada (Samuel/Carine: STT Deepgram + Haiku + Azure TTS pt-BR). Roteiro de captação fria (prompt_captacao.py, CTA=avaliação gratuita;/callaceitacampaign+imovel). Infra de chamada: gravação MixMonitor (asterisk/recordings/), transcrição persistida (transcripts/*.json|txt), escuta ao vivo ChanSpy ramal 8000 (Zoiper via Tailscale). 4 bugs corrigidos ao vivo: peek bloqueante vs timeout 2s do app_audiosocket →wait_for_uuid; output transport semset_transport_ready(TTS todo descartado); keepalive de silêncio no cold-start + write-lock; ECO→auto-interrupção (bot se cortava, fala saía picotada) → gate MEIA-DUPLEX + VAD elevado + pré-aquecimento de modelos. Azure Speech migrado brazilsouth→eastus (servidor é Ashburn: conexão 8ms vs 130ms; Anthropic 2ms, Deepgram 66ms — mover pro Brasil PIORARIA). Pendências amanhã: validar conversa ao vivo em horário comercial,stop_secs0.6→0.4, AMD/caixa postal, latência entre turnos (senão avaliar Vapi/LiveKit/Retell c/ nosso trunk). Memória:project_discador_voz_self_hosted_br.md.Sessão 2026-06-11 (noite): 🧾 NFS-e automática do desk fee — LIVE e validada com pagamento real (commits
540415a+58af752): corretor paga o fee mensal (R$300/R$2000, qualquer valor deDeskFeeRule) → webhook Starkinvoice.credited(#tipo:desk-fee) emite a NF Studio76 com tomador = o próprio corretor e discriminação própria de fee, registra emnfse_emissions(refFEE-<agente>-<YYYY-MM>, sourcefee-auto), appenda na planilha Sheets e manda o PDF via HSMnfse_documento_v4(UTILITY APPROVED — entrega fora da janela 24h, fallback documento cru). Novofee-nfse.handler.tsreusa pipeline do cobrar-auto; CPF viainvoice.taxId→DeskFeeRule→split_receivers; idempotente porinvoice_id. Teste real: Angela Teles 1008 fee jun → NF #918 R$306,10 emitida+planilha+PDF delivered (retroativo viaops-scripts/trigger-fee-nfse-51.cjs— reentrega de webhook do Stark NÃO funciona). Lição HSM: corpo "NFS-e nº/Tomador/Cód. verificação"+emoji = rejeição INCORRECT_CATEGORY; passou espelhando ocomprovante_pagamento_v1sem emoji. Memória:reference_nfse_fee_auto.md.Sessão 2026-06-10 (dia): 🔧 Revisão dos 34 termos do otimizador Google Ads + CPL alvo por campanha. Negativos (commit
684c27e, aplicados nas 3 Search, 51/campanha): geo errada (campo grande ms/mato grosso/mogi das cruzes), MCMV, "direto com proprietário" e 12 marcas de incorporadora/lançamento (vivaz, cury, metrocasa, mac, ledge...) — agora na STOPLIST, campanha futura nasce protegida. Mantidos com estoque confirmado no iList: 1 dorm Brooklin (2 imóveis), Jardim Celeste (1), bairro Campo Grande SP (2 — NÃO negativar sem "ms"). CPL alvo (commit1e3f295, base nos reais da Suzana no Meta: alto R$8,50–30, médio R$5–15): ISCA R$15 / VENDE R$22 / ALTO R$30 + reco PAUSAR (≥40 cliques, 0 conv, ≥3× alvo) — 1º flagrado: kwapartamento brooklinR$75/7d. Delegado a OUTRA sessão (Elie): decisão de orçamento (hoje 60/40/30 = R$130/dia, perda por verba 56–87%; sugerido ISCA→R$90) e destino da kwapartamento brooklin(sugerido lance −30% em vez de pausa). Memória:reference_google_ads_revisao_10jun_cpl_negativos.md.Sessão 2026-06-09: 🚀 Impulsionamento ponta-a-ponta (manual → automático → corretor self-service) + 🧯 incidente /cobrar 1083-34 blindado. Google Ads: ISCA→R$60/dia (Google acusava 78,6% de demanda perdida por orçamento), VENDE/ALTO reativadas (learning + alarme "3 dias sem lead"), 1ª conversão importada via gclid; consentimento: coleta de 67 imóveis → ~49 aprovados;
enforce_consent(recusou→pausa 15min) + regra parceiro (≠60130) isento de consentimento. Peneira de CR:enforce_crnos 3 canais (Google/Meta/Canal Pro), aviso 48h→pausa→auto-religar ao renovar; HSMs dedicados aprovados. Automação de boost:boost_listing.py(1 comando, filtros duros) +price_drop_boostFase 3 (imóvel que baixa pra ABAIXO do mercado oferta 1-clique ao corretor — anti-trapaça viabelow_market+cooldown) + comando/impulsionarno botjuridico (no/ajuda). Fase 2 testada AO VIVO: Arnaldo tocou "Impulsionar agora" e o 1068-4 subiu sozinho Google+Meta. Subiram hoje: 1089-3, 1016-280/274, 1068-4. 🧯 INCIDENTE 1083-34: o/cobrarautomático cruzou 3 negócios (CCV de outro imóvel + partes contaminadas pela matrícula); contido SEM perda financeira, re-cobrado certo R$26.400; 2 guards (03b2bc3picker pula CCV de outro serial +1edadf2divergência CROSSREF crítica bloqueia a extração). PMax: gates consent/CR no build +pmax_readiness(avisa quando cruzar 12 conversões — hora de ligar). Infra: fix do triggerauto_deployp/google-ads/meta-ads+ branch corrigida (estava emfix/cr-post-signature-continuity). *
WIP Limit: 2 (max items in "In Progress" at once)
Rule: Open this file every morning before writing code
| Level | Criteria | Response Time |
|---|---|---|
| P0 | Production down, data loss, money at risk, bot crash loop | Same day |
| P1 | Feature blocking business operations (deals, payments, contracts) | This week |
| P2 | Approved feature improving efficiency, no urgent deadline | Next 1-2 weeks |
| P3 | Nice to have, research, future planning | When P0-P2 are clear |
Full repo audit: bot UX, proactivity, logs, Pipeimob sync, StudioImob, production readiness.
Server inspected via SSH — bot is UP and healthy.
| Metric | Value |
|---|---|
| Bot status | active (running) since Apr 7 18:19 BRT (16h+ uptime) |
| Server uptime | 22 days |
| Memory | 173MB (peak 704MB) |
| DB size | 3.2MB, WAL mode, healthy |
| Schema version | v22 (fully migrated) |
| Deals | 348 (196 CREATED, 128 COLLECTING_DOCS, 16 REGISTRATION, 3 SIGNING, 3 CCV_DRAFT, 2 DD_COMPLETE) |
| Corretores | 57 |
| Checklist items | 3,574 |
| Deal parties | 616 |
| Extracted data (OCR) | 40 party records, 12 matrícula entries |
| Engagement | 291 log entries, digests running daily at 11:00 UTC (8h BRT) |
| Pipeimob sync | 350 deals synced (336 matched, 14 errors) |
| Webhook | cloudvero (https://bot.remaxstudio76.com.br/webhook) |
| Backup | Rotating, latest: Apr 8 02:00 (3.2MB) |
| Active users (last 48h) | Elie, Wilton Lee, Samuel Chen, Carine, Marcelo, Karina Mustafa |
| Dimension | Score | Key Gap |
|---|---|---|
| Proactivity | 6.5/10 | Morning digests + proactive greeting context working; no post-action buttons |
| UX | 5.5/10 | Powerful but text-heavy; needs tap-to-act buttons/lists |
| "Mind Reading" | 5/10 | Proactive greeting context injection works (verified in logs); no state-transition nudges yet |
| Production Readiness | 8/10 | Running in prod, 348 deals, sync working. Tech debt: monolith + no tests |
| Pipeimob Sync | ~75% | 348/350 deals synced, one-way; no write-back |
| CEO Vision Alignment | ~60% | Defense (legal/compliance) strong; Offense (funnel/ads/SDR) absent |
| # | Issue | Severity | Status |
|---|---|---|---|
| ~~BUG-001~~ | ~~Bot down~~ | ~~CRITICAL~~ | RESOLVED — Bot is UP, running since Apr 7 18:19 |
| ~~BUG-002~~ | ~~DB empty~~ | ~~CRITICAL~~ | RESOLVED — 348 deals, 3574 checklist items, data healthy |
| ~~BUG-005~~ | ~~Migrations pending~~ | ~~HIGH~~ | RESOLVED — Schema at v22, all tables present |
| BUG-003 | OBA request failing for 16+ days (HTTP 500) | HIGH | Meta Graph API issue — check Meta Business Manager |
| BUG-006 | Adoption gap — 6 active users out of 57 corretores (~90% unused) | HIGH | Need onboarding campaign |
| ~~BUG-007~~ | ~~No external health monitoring~~ | ~~MEDIUM~~ | RESOLVED 06/05 — Uptime Robot monitorando bot.remaxstudio76.com.br/health, weekly report ativo |
| ~~BUG-008~~ | ~~Wizard sessions in memory (lost on restart)~~ | ~~MEDIUM~~ | RESOLVED 16/abr — Migration v23: wizard_sessions table + WizardManager 100% SQLite-backed |
| BUG-009 | index.ts is 11,120 lines — monolithic God File | MEDIUM | Maintenance risk |
| BUG-010 | 3 disconnected data islands (Pipeimob, Bot SQLite, SmartyDeed MySQL) — /status mostra "documentos faltando" mesmo quando docs existem (dados desatualizados entre sistemas). Corretores reclamam frequentemente. |
HIGH | Causa raiz: cada sistema tem sua verdade parcial. Solução: BD próprio como fonte única → backlog #32 |
| BUG-011 | Pipeimob sync: 14 errors (deals not found via API) | LOW | Likely permission/code format issues |
| BUG-012 | /reportar subconta comissões/royalty — lê erp.receivables (Postgres), que só tem Stark OU Pipeimob por mês e NÃO concilia Bradesco/OFX. Gap medido: Mar −13 vendas/−R$272k, Abr −12/−R$454k, Mai −15/−R$524k vs ledger real commissions_received (bot.db, 9 fontes). Sem impacto compliance (royalty apurado manual à parte), mas ferramenta interna não confiável — bloqueia aposentar Granatum/Pipeimob. Decisão Elie: extratos bancários reconciliados (Bradesco OFX) são a fonte de verdade; Stark já vem estruturado via SDK. Fix: apontar bloco AR do /reportar p/ commissions_received. Laudo: financial-services/LAUDO-subcontagem-reportar-2026-05-31.md |
HIGH — resolver semana 02-06/06 |
project_demanda_corretor_minisite./home/egk/wa-web-assist/ no cloudvero, READY e operacional 02/07 22h — via nohup). O Baileys antigo (wa-assist.service) foi parado e DESABILITADO 02/07 (morto pela passkey; não competir com o daemon novo). Ver memória reference_wa_assist_repareamento.wa-daemon.js (pré-filtro regex de demanda + POST /internal/demanda-grupo no whatsappbot → reusa handleDemandaDetected) + decidir onde responder (PV do corretor recomendado). Pendências da nova stack (outra sessão): device próprio do bot, systemd unit, migrar produtores do outbox pro novo path.Vazio antes de 02/07 (desde 2026-05-20). Os dois itens datados de 2026-04-08 ("Proactive Engagement System" e
"QuintoAndar Tech-Match Sprint") estavam parados há ~6 semanas com todos os checkboxes
desmarcados, enquanto o trabalho real fluía fora desta seção. Movidos para o Backlog P1
(itens "Proactive Engagement (Fase 2.5)" e "QuintoAndar Tech-Match") para o board refletir
a realidade. Pegue um deles aqui quando começar de fato.
Matrícula 398.899 — 1 proprietário, 3 registros, 0 ônus (deal_id=137)BUTTERFLY EVEN EMPREENDIMENTOS → VENDEDOR (matrícula-based)1 divergência CRÍTICA automatically flaggeddashboard.remaxstudio76.com.br → 178.156.155.123 (GoDaddy, TTL 600s)certbot --expand), expira 2026-08-09limit_req_zone dashboard 10r/s burst=20bot.db migration v56 (3 tabelas: dashboard_magic_links, dashboard_sessions, dashboard_access_log)whatsappbot/src/dashboard/ (~1500 LoC: signing HMAC, magic-link via WA, sessões cookie httpOnly+Secure+SameSite=Strict, auth middleware, rotas JSON, SPA HTML+vanilla JS+Chart.js CDN).env cloudvero com DASHBOARD_JWT_SECRET (32B) + whitelist 5511994955337,5511972828498e3ddcb7 — .gitignore *token* (regra de segurança) bloqueava tokens.ts silenciosamente. Renomeado signing.ts. Auto-deploy quebrou no tsc até esse fix subir.fa6643e — WhatsApp prefetch do magic link (IP 173.252.127.x = Meta crawler) consumia o token de uso único antes do clique do user. Fix: GET /dashboard/auth agora mostra página intermediária (peek-only); POST consome. Auto-submit via JS — crawlers não rodam JS, browsers entram transparente. 3/3 falhas viraram 1/1 sucesso.dashboard/ARQUITETURA.md, project_dashboard_web.md, commits 78eaf44 e3ddcb7 fa6643edestaque.py reescrito com pesos halo effect: BELOW_MARKET 40→65, HIGH_CTR=25 (≥4%, mín 30 views), HIGH_VOLUME=10 (≥5 leads). Política por tier: PREMIERE_1 e top-16 SUPER_PREMIUM = mérito puro; bottom-4 SUPER_PREMIUM e PREMIUM = mixed (mérito + fairness). Backup: destaque.db.bak-20260427-*.cnm_generator.py + registrar T0[ERP] Enriquecimento de extrato (ofx-descricao) — fallback de desambiguação por botão — add 2026-07-07. A feature de enriquecer lançamentos do extrato via forward "PIX ENVIADO / DES: …" já está NO AR (commit 2dbae02, validada 4/4 em produção): casa cada bloco com a transaction (bank_adjustment) por valor + data + nome (janela 120d) e grava a descrição de negócio em notes, preservando o memo do banco em description; 📝 aparece no /extrato bradesco. Gap: quando 2+ lançamentos têm valor+data idênticos E nome parecido, o bot marca "⚠️ ambíguo" e não grava (comportamento seguro por padrão, avisa na resposta). Melhoria: oferecer botões #123 / #124 pro admin escolher qual lançamento receber a descrição (fix-in-chat), em vez de só reportar o impasse. Handler: whatsappbot/src/erp/handlers/ofx-descricao.handler.ts (matchTransaction retorna status:"ambiguous"). Baixa urgência — caso raro (dois PIX iguais no mesmo dia com nome quase igual).
[Feed] Extrator de features por IA/Visão — elevar a "Qualidade do Anúncio" — add 2026-06-05. Hoje só MAPEAMOS as features marcadas no iList; não inferimos das fotos → feature visível mas não marcada não pontua. JÁ TEMOS Claude Vision sobre fotos de imóvel em marketing/reels-engine/property_processor.py (download/downscale/base64/loop/cache) — usado p/ Reels, não p/ features. Reusar a plumbing + prompt fechado: "quais amenidades do catálogo estão CLARAMENTE visíveis?" → sugere as faltantes → marca (modo fix-in-chat: bot pergunta ao corretor e marca no iList via estoque-vivo updater; ou feed-only: injeta no <Features> do XML). Só 60130 (boost de parceiro NÃO — alterar representação de terceiro = mesmo risco da exclusividade/bump). Plano completo: canal-pro-feed/PLANO-feature-vision.md. Decisões: modo (a/b), limiar de confiança, estender ao condomínio.
[Boost] Remover de verdade do "Meus Boosts" (não só sendListing=false) — add 2026-06-05. O drop de boost via boost_rotate/boost_executor usa UpdatePortalExportListing sendListing=false, que para de enviar ao portal mas NÃO tira de "Meus Boosts" no iList → o fetch_boosts segue lendo o imóvel (cache cresce 72→94→100…). O feed está protegido (o cap em generator.load_boosts exclui acima-do-mercado e limita a 300−próprios), então não é urgente, mas a hygiene degrada. Fix: achar a API de remover boost do Portal Boost (ou fazer o fetch_boosts respeitar sendListing/portalOptions por portal e zerar boostPortals de quem está false → some do feed naturalmente). Ref: reference_destaque_engine_e_harvest.md, boost_rotate.py, fetch_boosts.py:boost_portals().
[Onboarding] Onboarding de corretor ponta-a-ponta — espelho do distrato (/admitir-corretor) — add 2026-06-09. Possuir o ciclo de admissão e substituir o cadastro no Pipeimob. Disparado pelo incidente Luciana Kfouri (fee indevido por join_date null). Visão (Elie): depois que assina o Contrato de Associação → nosso sistema gera o contrato (como no CR), cria o corretor no iList + nosso DB, entra no bolsão, e a cobrança de fee flui. Blocos já existem: geração de contrato (ccv-generator + clicksign.service.sendForSignature), webhook (clicksign-sync.service), iConnect Playwright (IConnectAutomationService.deactivateUser/transferListingOwner — falta o inverso createUser), hub (hub-minharemax-automation.service), DB (corretores + DeskFeeRule), boas-vindas (cron-concierge-onboarding). Única peça nova de verdade: IConnectAutomationService.createUser (Playwright no painel de novo agente, lê o 60130NNNN gerado). Fases: (1) cadastro automático no nosso DB via gatilho Clicksign + enrich por CPF no iList/Pipeimob (crm_id+celular+data_associacao) — flag-gated, 90% provado no onboarding manual do Marcio 1107; (2) /admitir-corretor gera o contrato (wizard admin → docx → Clicksign multi-signatário: associado + Studio/Samuel + testemunhas Carine/Yara); (3) createUser no iConnect = mata o Pipeimob no onboarding; (4) enroll no bolsão + minisite + treinamento. Liga com #41 (/cadastrar-corretor), decommission Pipeimob (Trilha B) e backlog RH "Onboarding e Offboarding". Fixes de fundo já no ar (jun/2026): cobrar-fee carência fail-safe + expiração default 3d→60d + vencimento por corretor (dia 20 da cláusula 6.1).
Proactive Engagement (Fase 2.5) — ex-In Progress, started 2026-04-08, parado; movido p/ backlog 2026-05-20. Botões de próximo passo pós-comando, nudges de transição de estado, list messages multi-opção, wizard persistido em SQLite (✅ feito desde então — migração v23 WizardManager), re-engajamento de wizard abandonado, follow-up scheduler de lead SDR. Ref: whatsappbot/docs/Fase-2.5-Engajamento-Proativo-StudioImob.pdf. Reavaliar escopo — parte já foi entregue.
QuintoAndar Tech-Match — ex-In Progress, started 2026-04-08, parado; movido p/ backlog 2026-05-20. Busca de imóvel via WhatsApp em linguagem natural, fluxo de proposta/contraproposta digital, agendamento de visita (/agendar), simulação de financiamento (/financiamento), descrição de anúncio via Vision. Ref: operations/quintoandar-tech-competitive-analysis.md + backlog #11-17. Insight: receita de correspondente bancário é royalty-free (cláusula 4.8).
refresh_ilist_cache.py — API-based cache refresh (substituiu exportação CSV manual), 221/221 itemsprice_bump.py — rotação quinzenal +R$100 venda / +R$10 locação (refresh timestamps)run-full-sync.sh — pipeline diário 6am: cache refresh → enrich → generator → cnm → restart → validatealerta_sync_canal_pro 24/7 alerts on sync failurecanal_pro_auto_login.py — login automático com Gmail API polling (código 2FA extraído em <1s)/destaque [imóvel], /anuncio [imóvel]70fc0a1 (latest) | Feed: https://studio76-server.tail92b8aa.ts.net/feed/vrsync.xml0.5. Canal Pro — Caça à Nota 10/10 🎯 EM ANDAMENTO (Sprint 1 = pesquisa + msg Marcelo enviada)
- Motivo: painel de qualidade do Canal Pro hoje em 9.4/10. Bloqueado em 3 frentes: Tour Virtual 0% (217 anúncios · 4 pts), Vídeo 65% (77 anúncios · 3 pts), 6 warnings "Não identificamos o complemento".
- Sessão 14/05/2026:
- [x] Piloto Tour HTML DIY 1080-31 testado — Canal Pro fetch OK (14/05 02:53), 0 erros, MAS painel continua 0% completo após 11h. URL HTML wrapper genérica não pontua mesmo importando sem erro.
- [x] Pesquisa via Agent: doc oficial ZAP exige 3 requisitos pro <LinkTourVirtual> pontuar (página só com tour, sem encurtador, HTTPS). Players reconhecidos: Matterport (dominante), Kuula, EyeSpy360.
- [x] Diagnóstico dos 6 warnings: nenhuma fonte (iList apartamentoNum, Pipeimob apartmentUnit, descrição) tem o número do apto. Hipótese Elie: intencional (privacidade dono) — Carine vai confirmar.
- [x] Bug colateral encontrado: weekly_report/integration_monitor.py ignora total_avisos — ficou cego pros 6 warnings. Precisa fix.
- [x] Mensagem WA pro Marcelo do Canal Pro draftada e enviada (perguntas: 1- formato Tour Virtual válido / self-hosted aceita?, 2- vídeo institucional Studio76 como fallback pontua?).
- Pendente:
- [ ] Resposta da Carine sobre os 6 warnings (intencional ou esquecimento)
- [ ] Resposta do Marcelo (Canal Pro) sobre Tour Virtual + vídeo institucional
- [ ] Caminho A (Carine intencional): whitelist warnings no integration-history.json + monitor alerta só fora dela
- [ ] Caminho B (Carine esquecimento): generator flag + bot WA fix-in-chat pro corretor preencher Apto (reaproveita princípio Estoque Vivo)
- [ ] Caminho Tour Virtual self-hosted (se Marcelo confirmar): captura 1 panorama equirectangular real + Pannellum só com viewer (sem chrome) em feed.remaxstudio76.com.br/tour360/{id}/ → teste em 1 listing → escalar pros 217
- [ ] Fallback Tour Virtual: Kuula PRO ~US$ 16/mês (~R$ 1.000/ano) pros 217
- [ ] Vídeo institucional fallback nos 77 sem vídeo (se Marcelo confirmar)
- [x] Fix integration_monitor.py pra ler total_avisos em qualquer cenário — feito junto com a migração pro e-mail (e-mail traz total_avisos + detalhe por imóvel)
- [x] Monitor migrado pro e-mail diário do ZAP+ (20/05): e-mail grupozap@leads.grupozap.com virou fonte primária (imune a sessão expirada / mudança de UI, que era o que quebrava o scraper); Playwright fica só pra total_removidos, que não vem no e-mail. Dedup por execucao. --no-scraper pra rodar e-mail puro.
- Vídeos institucionais candidatos: youtube.com/watch?v=5X_K-Ucp_8E · youtu.be/Wk_KZSa4SYY
- Refs: project_canal_pro_warnings_complemento.md (memória) · weekly_report/quality_scraper.py · weekly_report/integration_monitor.py · generator.py:606-637
- Effort: Low-Medium (depende das respostas) | Impact: High (9.4 → 10.0 = halo effect Canal Pro algoritmo, mais visualizações orgânicas, item P2 já validado)
dataValidade do contrato de exclusividade. ✅ CODADA 2026-04-18 (demo validado, deploy feito, aguardando piloto real)status, dataValidade, valor. Captação tem whitelist própria. Outros módulos seguem ownership por agent_code.ilist-updater.service.ts + exceção em CLAUDE.md ✅/home/egk/whatsappbot/logs/ era root:root 755 → bash não criou log → comando abortou. Zero ciclos reais no banco (só 3 demos 18/04). Corrigido: (a) sudo chown egk:egk no logs/, (b) dedup por MIN(id) em campaign-runner.ts (resolve 7 duplicatas de agent_code, incluindo 1067 Luciana≠Alex e 1068 Arnaldo≠João), (c) template HSM estoque_vivo_confirmacao_semanal confirmado APPROVED via Graph API. Dry-run pós-dedup: 33 corretores únicos, 218 imóveis, 0 erros. Próximo disparo real: segunda 27/04 09:00.estoque-vivo/plano.md · whatsappbot/src/services/estoque-vivo/1.5. CR → CCV Integration MVP — ALL 4 PHASES LIVE EM PRODUÇÃO ✅ (16/05/2026)
- Motivo: Fechar o "miolo" entre DD vendedor e CCV pronto. Antes, corretor operava fora do bot entre captação e fim — agora todo o fluxo passa por WhatsApp.
- Plano detalhado: juridico/planning/cr-to-ccv-plan.md · Memória: project_cr_to_ccv_plan.md
- Status por gap (todos deployed):
- ✅ #1 + #1a Wizard comprador (/comprador <code>) — OCR RG/CNH + COMP_RESID. Validado e2e no 1079-12 em 16/05.
- ✅ #2 Wizard proposta (/proposta <code>) → deal_values + evento PROPOSTA_ACEITA. Validado e2e no 1079-12.
- ✅ #3 DD do comprador (/dd comprador) — bundle enxuto TJSP+CND+CENPROT (~R$15)
- ✅ #4 Cônjuge anuente do vendedor (defesa em profundidade) — botão pós-/dd se vendedor em comunhão sem CONJUGE
- ✅ #5 Wizard rateio (/dividir <code>) — vendor_type + split %, persiste em deal_rateio_setup (migration v74)
- ✅ #6 Dr. Wilton escolhe modelo (List Message com 6 templates) — disparado quando readiness OK pós-/dividir
- ✅ #7 Aprovação CCV via botões — Wilton recebe PDF + [✅ Aprovado] [📝 Sugerir] [❌ Rejeitar]
- Polish entregue: botão pós-/dd "Cadastrar comprador" · migration v73 father_name · prompt OCR distingue REGISTRO/RG/RENACH na CNH · COMP_RESID PDF via Haiku texto · bug "SCENIC duplicado" mitigado
- Commits: 3bec176 → bf858ad (10 commits, claude/main, ~2k linhas)
- Pendente:
- [x] ~~Smoke test e2e Fases 2-4 em deal real (agendado pra 17/05)~~ — Gap #3 ✅ smoked em prod 18/05 (1079-12, Elie buyer), bug regex compradores? fixado em a2af994. Gaps #5/#6/#7 ainda não exercitados — retomar 19/05 (keyword "retomar smoke crccv 1079-12", memória project_continuar_19mai2026.md).
- [x] ~~Abstrair comandos pro usuário final — ver item 1.6 abaixo~~ — Frente C ✅ validada no smoke (concierge classificou "roda DD do comprador do 1079-12" como dd_comprador corretamente)
- [ ] Reescrita Haiku da CCV ao sugerir alteração (hoje só registra texto)
- [ ] Auto-submit Clicksign pós-CCV_APPROVED (hoje pinga corretor pra rodar /assinar)
- [ ] Coleta PIX dos comissionados no /dividir (deferida pro /cobrar)
- [ ] Plexi CND_FEDERAL_PGFN 422 + Plexi 520 generalizado (TRF3/CND/CENPROT) — descoberto durante smoke 18/05; afeta todas as DDs; abrir chamado Plexi
1.6. Abstrair comandos CR→CCV pro usuário final — UX em linguagem natural 🆕 P1 (16/05/2026)
- Motivo: Fase 1-4 do CR→CCV shipou com 4 comandos novos (/comprador, /proposta, /dividir, /dd comprador) que o corretor precisa lembrar e digitar exatamente com a barra. O bot rejeita "comprador 1079-12" sem / e manda pro Haiku jurídico (validado em prod 16/05 — Elie digitou sem barra, virou pergunta jurídica). Sem abstração, adoção entre os 32 corretores ativos vai ficar baixa: ninguém memoriza 4 comandos.
- Princípio fix-in-chat aplicado: o corretor não precisa saber que existe /comprador — o bot detecta o contexto e oferece a ação por botão, ou interpreta intenção em texto livre.
- Frentes:
- A) Botões fix-in-chat após eventos (já parcialmente feito):
- ✅ Pós-/dd: [👤 Cadastrar comprador] + [👫 Cônjuge vendedor]?
- ✅ Pós-/comprador (geral): [🎯 Proposta agora]
- ✅ Pós-/comprador (comunhão): [Sim cadastrar cônjuge]
- ✅ Pós-/proposta: [👥 Definir rateio]
- ✅ Pós-/dividir (readiness OK): trigger automático pro Dr. Wilton
- ✅ Pós-template escolhido pelo Wilton: gera CCV + 3 botões aprovação
- [ ] Botão pós-/comprador ofertando [🔍 Rodar DD do comprador] (Gap #3 não tem trigger automático)
- B) Intent classifier reconhece comandos sem barra ⚠️ NÃO IMPLEMENTADO:
- Hoje "comprador 1079-12" / "registrar proposta do 1079-12" / "dividir comissão do 1079-12" caem no Haiku jurídico em vez de disparar o wizard.
- Plumb no intent-classifier.service.ts: adicionar intents cadastrar_comprador, registrar_proposta, configurar_rateio, dd_comprador com entities {deal_code}.
- Confidence threshold ≥0.85 → roteia direto pro handler. Caso contrário cai no concierge orchestrator que pergunta.
- Risco: falso positivo (corretor pergunta "como cadastrar comprador" → bot abre wizard sem querer). Mitigar com classificação intent vs question.
- C) Concierge orchestrator entende metas em texto livre ⚠️ NÃO IMPLEMENTADO:
- "vendi o 1079-12, valor 850 mil, parcelado em financiamento Caixa" → bot infere: precisa cadastrar comprador + proposta + dividir, abre wizard certo pelo passo faltante.
- Reutiliza concierge.service.ts (Sonnet 4.6 com tools) — adicionar tools start_comprador_wizard, start_proposta_wizard, start_dividir_wizard, run_dd_comprador.
- Vantagem: corretor expressa intenção como conversa, bot orquestra wizards.
- D) Self-discovery via comando /ajuda ou "como funciona":
- Quando corretor sem contexto manda "oi" / "ajuda" / "como cobrar comissão", o concierge já cobre. Estender com guidance específico do CR→CCV pipeline ("você está no passo X, faltam Y e Z").
- Sequenciamento sugerido:
1. Frente A (botão pós-/comprador p/ DD do comprador) — 30min, fecha o gap dos 6 triggers automáticos.
2. Frente B (intent classifier) — 2-3h, maior adoção rápida. Risco baixo se threshold alto.
3. Frente C (concierge tools) — 3-4h, UX premium mas precisa testing.
4. Frente D — polish.
- Métrica de sucesso: % de uso dos wizards via texto livre / botão vs comando direto /. Target: <10% via comando explícito em 30 dias.
- Refs: feedback_bot_comunicacao_clientes.md, reference_intent_classifier_routing.md, concierge.service.ts, intent-classifier.service.ts
- Effort: Medium (~6-8h total nas 4 frentes) | Impact: Very High (sem isso o CR→CCV todo fica enterrado em comandos que ninguém usa)
/financeiro commandimplementation-plan-2026.md item 1.1.3~~3. External Health Monitoring~~ ✅ DONE 06/05 — Ver Done (May 2026)
Split index.ts into Handler Modules
- Extract from 16,156-line monolith (era 11.120 no audit 8/abr — cresceu +45% em 22 dias) into: command.handler.ts, document.handler.ts, wizard-complete.handler.ts, intent.handler.ts
- Reduces risk of regression bugs, enables parallel development
- Effort: Medium (2 days) | Impact: High (maintainability)
Impulsionamento Digital — automação e tracking 🆕 P1 (24/04)
- Auditoria de gastos com impulsionamento (Meta Ads, Google Ads, Canal Pro, OLX/Zap turbo) por imóvel/corretor
- Reconciliação automática com Granatum (centro de custo "Impulsionamento", categoria 2535141)
- Bot pode aceitar /impulsionar [imóvel] [budget] via WhatsApp (corretor solicita, sistema dispara)
- Pendente: definir canais prioritários, política de subsídio Studio76 vs corretor, métricas de ROI por canal
- Effort: TBD | Impact: High (controle de custo + atribuição de leads)
Marketing — estratégia e execução 🆕 P1 (24/04)
- Plano integrado: branding Studio76 + conteúdo (Instagram, LinkedIn, blog), email marketing, eventos, SEO
- Integração com bot: capturar leads em landing pages → roteamento automático ao corretor via WhatsApp
- Tracking de fonte do lead até fechamento (Canal Pro/CnM/orgânico/indicação) para alocação de orçamento
- Pendente: definir agência vs in-house, calendário editorial, ferramentas (RD Station? HubSpot? in-house?)
- Effort: TBD | Impact: High (geração de leads + posicionamento de marca)
Recrutamento de Corretores — pipeline e onboarding 🆕 P1 (24/04)
- Pipeline de captação de novos corretores (atual: 57 ativos no bot.db)
- Diferencial Studio76 a comunicar: bot jurídico 24/7, automação financeira, dashboards, suporte técnico
- Onboarding automatizado: /onboarding no bot → cadastro Pipeimob + iList + WhatsApp + treinamento + assinatura contrato Clicksign
- Tracking de conversão: candidato → entrevista → contrato → primeira venda
- Integração: site de carreiras, divulgação em RE/MAX network, indicações, eventos
- Pendente: perfil ideal, comissionamento de indicação, material institucional
- Effort: TBD | Impact: Very High (escalabilidade da operação depende de mais corretores produtivos)
Studio Lead Bot — WhatsApp +55 11 97345-7166 (PLANO V2 — intent classifier + 9 buckets) ⚡ P1 (28/04, plano congelado com Yara)
- Número: +55 11 97345-7166 (WhatsApp Studio 76 Leads — separado do botjuridico)
- Status atual (09/05): Bot LIVE no cloudvero, schema v5, 9 buckets implementados, smoke test ponta-a-ponta concluído com 7 buckets validados (1 Comprar, 2 Alugar, 3 Anunciar, 5 Recrutamento, 6 Atendente, 9 Reclamação, 7 B2B). 14 templates HSM APPROVED na WABA (5 novos aprovados nesta sessão). Notificações ao time (Yara/Samuel/Nicolly/Suzana) 100% via HSM — não dependem mais de janela 24h. wa.me/<corretor> deep link no ack do lead pra acelerar primeiro contato. /reset admin-gated pra time interno testar fluxos. Corretor cadastrado mandando "oi" redireciona pro StudioBot. Pendências: bucket 4 Placa em fallback (Sprint C — iList lookup stub); bucket 8 Verificação não testado no smoke; alerta proativo de delivery failed > threshold (futuro).
- Decisão estratégica (28/04 — Yara consultada): Wizard atual é monocaso (assume comprador querendo agendar visita). Substituir por classificador de intenção com 9 buckets cobrindo todos os cenários que a Yara atendia manualmente. Plano congelado, pronto pra codar.
### Arquitetura
- 2 entry points distintos:
- Email watcher (chavesnamao/zap/canalpro) → intent já claro = comprador de imóvel X → buyer-flow (wizard atual sobrevive)
- WhatsApp direto → intent desconhecido → intent-classifier (Claude Sonnet 4.6, system prompt com 9 buckets + few-shot da Yara) → sub-fluxo apropriado
- Suporte a mensagem livre + IMAGEM (Vision) desde o primeiro turno
- Menu fallback (list_reply Meta, até 10 itens) quando classificação ambígua
### 9 buckets de intent
1. Comprar imóvel → coleta região + valor + tipo → busca iList → roteia ao primeiro corretor ativo que aceitar
2. Alugar imóvel → idem 1
3. Anunciar/vender meu imóvel → coleta endereço + modalidade + foto → entra no rodízio de captação
4. Imóvel da placa → pede ENDEREÇO (placas Studio76 não têm código, confirmado Yara) → busca iList → se achar, roteia; se não achar, posta foto no grupo geral de corretores e escala Yara
5. Trabalhar como corretor → triagem inicial (nome, experiência, CRECI, região) → agenda entrevista com Nicolly → relatório diário pra Suzana
6. Falar com atendimento → escala Yara
7. Vendedor B2B oferecendo produto/serviço → declina educadamente
8. Verificação de corretor ("Fulano é da Studio?") → confirma nome + CRECI + telefone oficial; pinga Samuel "cliente X buscou confirmação do corretor Y"
9. Reclamação / quer falar com gerente → escala Samuel
### Rodízio de captação (bucket 3)
- Tabela captacao_rotation: 38 corretores na ordem da planilha Yara (SAMUEL → SUZANA → PAULA → NILZA → FRANCISCO → ... → EDSON), modalidade venda | locacao | ambos, cursor last_assigned_position ciclando, contador anual com backfill da planilha
- Fonte: docs.google.com/spreadsheets/d/1S9iE-AhCkJtvI4kjwPQUkXNdSiij6k8V aba "rodizio 2026" (compartilhada com eliekfouri@remax.com.br)
- Fluxo: bot identifica modalidade → próximo da fila compatível → HSM corretor_oferta_captacao com botões Aceitar/Recusar → timeout 15min sem responder = pula pro próximo → volta completa sem aceite = encerra cordial + escala Yara
- Distinção VENDA vs LOCAÇÃO: FRANCISCO/RODRIGO = ambos, KARINA = ambos+locação separada (planilha)
### Verificação de corretor (bucket 8)
- Bot busca nome no corretores.bot.db (57 ativos)
- Resposta confirma: nome + CRECI + telefone oficial. Não expõe foto/email/endereço
- Notifica Samuel via WhatsApp: "Cliente +55 XX XXXXX-XXXX buscou confirmação do corretor Fulano" (acompanhamento)
- Se nome não cadastrado → "Esse nome não está cadastrado conosco — atenção a possível golpe" + escala Samuel
### Recrutamento (bucket 5) — automação total, ZERO dependência de comando humano
- Robô faz triagem inicial e agenda entrevista com Nicolly (Nicolly continua entrevistando humanos depois)
- Confirmação automática de entrevista: bot agenda no Google Calendar da Nicolly + cria evento; depois do horário (~1h após) bot detecta status do evento (compareceu / no-show via heurística: foi confirmado, candidato respondeu lembrete prévio) — fallback: bot pinga Nicolly UMA mensagem com 2 botões (Compareceu / Não compareceu), 1 clique
- Detecção de saída da empresa: bot detecta inativação no corretores (sync diário do bot.db) — quando corretor some, conta como saída do mês
- Relatório DIÁRIO pra Suzana via WhatsApp (~18h):
- Candidatos novos hoje
- Entrevistas agendadas
- Entrevistas realizadas (compareceu)
- No-shows
- Saídas detectadas
- Template HSM: suzana_relatorio_recrutamento_diario
### Schema DB (novas tabelas)
- intent_classifications (lead_id, intent, confidence, raw_text/image_url, classified_at)
- captacao_rotation (position, corretor_id, modalidade, ativo, count_anual)
- captacao_offers (lead_id, corretor_id, status: pending/accepted/declined/timeout, offered_at, responded_at)
- recruitment_pipeline (lead_id, stage: new/triaged/interview_scheduled/attended/no_show, scheduled_with, scheduled_at, attended_at)
### Templates HSM novos a submeter (Meta, paralelo ao código)
1. corretor_oferta_captacao — UTILITY, botões Aceitar/Recusar
2. gerente_alerta_reclamacao — UTILITY
3. gerente_confirmacao_corretor — UTILITY (notificação Samuel)
4. suzana_relatorio_recrutamento_diario — UTILITY, 5 variáveis
5. corretor_lead_atribuido — UTILITY (buckets 1, 2, 4 quando bot acha corretor responsável)
6. nicolly_confirmar_entrevista — UTILITY, botões Compareceu/Não compareceu
### Sprints
- Sprint A (4-6h): classifier + buckets simples (5, 6, 7, 8, 9) + suporte a imagem (Vision) — funciona com templates v1 já aprovados
- Sprint B (4-6h): rodízio de captação (bucket 3) + buyer-flow refinado (1, 2) + bucket 4 (placa) + relatório diário Suzana — requer templates v2 aprovados (24-48h após submissão)
- Total: ~10-12h de código, 2-3 dias com aprovação de templates em paralelo
### Pendências antes de codar (resolvidas)
- ✅ Recrutamento: Nicolly continua entrevistando humanos, robô faz triagem + agendamento + relatório
- ✅ Verificação corretor: nome + CRECI + telefone OK, expõe ao cliente + ping pra Samuel
- ✅ Timeout captação: 15min
- ✅ Reclamação: escala Samuel
- ✅ Atendimento humano: escala Yara
- ✅ Especialista por região: não existe, qualquer ativo que aceitar primeiro
- ✅ Rodízio: planilha compartilhada com eliekfouri@remax.com.br
### Fora do escopo (delegado)
- Workflow YouTube/Fotos da captação (Yara processa quando corretor pega captação) → vai pro botjuridico (94728-9029) — kickoff em whatsappbot/docs/planning/captacao-midia-workflow-kickoff.md
CRM Próprio (StudioImob/SmartyDeed) substituindo Pipeimob — visão estratégica 🆕 P1 (26/04)
smartydeed-alpha) já é robusto o suficiente para começarmos a substituir o Pipeimob como sistema central de gestão de transações imobiliárias. Esta linha amarra todas as iniciativas que hoje estão dispersas em P2 sob uma direção estratégica única: a Studio 76 vai parar de pagar e depender do Pipeimob./status mente/cadastrarcliente e /user_aprovacao escrevem), upload manual, lockout >30min com 15-20 chamadas rápidas — limita qualquer automação sériafeedback_pipeimob_fallback_only.md): iList (mãe, prevalece) > StudioImob/SmartyDeed (cérebro) > Pipeimob (espelho legado, fallback durante transição)/cobrar (bot WhatsApp → Stark Bank PIX com split). A antiga regra "Pipeimob prevalece em comissão" foi REVOGADA — /cobrar está em produção, Gildasio usou hoje gerou PIX, validação final do split agendada para segunda 28/04. Após validação, declarar /cobrar 100% confiável e migrar todos os corretores. Memórias: feedback_cobrar_ccv_fonte_verdade.md, feedback_pipeimob_prevalece.md (atualizada), project_cobrar_autonomo.md.project_migracao_studioimob.md — 5 fases (Sync Inteligente ✅, Bot como Entrada, Write-Back Pipeimob via Puppeteer, Espelho Funcional, Desligamento Natural)/novavenda no bot popular SmartyDeed direto.project_migracao_studioimob.md, plano-migracao-studioimob.md, plano-migracao-studioimob-ceo.pdfERP Próprio Studio76 — substituição progressiva do Granatum 🚧 F0–F5.0 código pronto 01/05/2026 — F0 baseline Granatum (876 lancamentos). F1: recurring_rules + cron daily + /contas + /aprovar pagamento dispatcher por kind + webhooks. F1.6 OFX (99 lancamentos Bradesco). F2.0+F2.1 WhatsApp PDF→AP completo (Vision extrai, sobe Drive, cria Payable, dispatch BoletoPayment/BrcodePayment/Transfer). /setpix cadastra PIX. F4.0 Stark Invoices→receivables (14 importadas Abr). /receber lista AR. F5.0 /dre [mês] [auto|baseline|erp|tudo] DRE simplificado. Diretriz Stark-only. Bloqueios E2E AP (2 inputs Elie): (a) STARKBANK_PAYMENT_CENTER_ID; (b) AP_REQUESTERS env. Próximo: F4.2/4.3 fee_tracker+Pipeimob → receivables, F2.2 email scanner, F3 conciliação 6h/6h.
bank-statements/ paralelo), mensalidade que sobe sem entregar mais, contaminação por lançamentos de corretores, API/UI insuficientes para fluxos novos (DICT, splits, recorrências por regra, anexos Drive, dupla assinatura). Direção estratégica do CLAUDE.md raiz já prevê substituir SaaS travados (Pipeimob → SmartyDeed, C2S → bot próprio); Granatum entra na mesma lista.financeiro.studio76@gmail.com com cobrança/comprovante/dados PIX (recorrente Contabem + ad-hoc)starkbank.PaymentRequest (não replicar workflow no ERP)whatsappbot/src/erp/ (reuso services), painel admin Filament-PHP (mesma stack do StudioImob — coerência arquitetural), email scanner reaproveita contas-a-pagar/ MCP existente.recurring_rules → cron diário cria draft → WhatsApp Elie aprova → PaymentRequest Stark → Samuel libera web Stark → webhook conciliafinanceiro.studio76@gmail.com → scanner parse → DICT validation → WhatsApp Elie aprova → PaymentRequest → Samuel libera → ERP responde solicitante por email com comprovante automáticofee_tracker.db + Stark Invoices em receivables + trigger NFPaymentRequest + webhook conciliação (4d)financial-services/erp/infra/)whatsappbot/prisma/schema.prisma, npm scripts erp:import:*)CLAUDE.md raiz atualizado com "Granatum → ERP próprio" na lista de SaaS substituíveisfinancial-services/erp/infra/{docker-compose.yml, initdb/01-extensions.sql, README.md}whatsappbot/prisma/schema.prisma (15 modelos: AccountChart, CostCenter, Supplier, Customer, BankAccount, PaymentRequestInternal, Payable, Installment, RecurringRule, Receivable, Transaction, TransactionTag, TransactionEvent, Attachment, ImportRun)whatsappbot/src/erp/scripts/import-granatum-{categorias,cost-centers,pessoas,lancamentos}.tswhatsappbot/src/erp/scripts/validate-against-granatum.ts → gera financial-services/erp-validacao-f0-{stamp}.mdprisma.service.ts, granatum-api.service.ts, import-runner.tserp:import:categorias|cost-centers|pessoas|lancamentos, erp:validate, prisma:migrate:*/app/credentials/erp-postgres.envdocker compose up -d em financial-services/erp/infra/DATABASE_URL no whatsappbot/.envnpx prisma migrate dev --name init + npx prisma generatenpm run erp:import:* na ordem (categorias → cost-centers → pessoas → lancamentos)npm run erp:validate → conferir relatórioverified_suppliers), formato Contabem definido tarde (mitigação: SPED ECD é padrão CFC, baixo risco de rejeição).financial-services/PLANO-ERP-STUDIO76.md (plano completo), financial-services/bank-statements/ (base operacional), financial-services/CLAUDE.md (regras de pagamento), project_erp_proprio.md (memória), item #9 (CRM próprio — mesma filosofia)~~11. Migração canal-pro-feed + dashboards studio76-server → cloudvero~~ ✅ DONE 05/05 — Ver Done (May 2026)
~~12. Dashboard web central Studio76 — Fase 1~~ ✅ LIVE 10/05 — Ver Testing (Fase 1 deployed) e Done (May 2026). Fases 2-6 (Financeiro/Funil/Anúncios/Estoque Vivo/Operacional, ~7d total) viram itens P2 quando priorizados.
needs_deep_reasoning=true)consultar_juridico (RAG do Wilton, 5.626 Q&A) — escala humano só se o corretor pedir ou se RAG não bater/eu, /painel, /2via) executa diretoconcierge.service.ts — Sonnet + prompt cache + function calling pros comandos. Smoke isolado.acl.service.resolveRole(from); tool calls passam por guardrail.handleCommand. Regra: confirmação só pra ação com lado-de-fora; consulta executa direto.handleIncomingMessage (substitui handleLegalResponse/handleSDRResponse). RAG Wilton vira tool consultar_juridico. Opus escala quando needs_deep_reasoning. Feature flag CONCIERGE_BETA=<phones> começa só Elie, depois Samuel, 5 corretores piloto, full./^(ajuda|me ajuda|menu|comandos|o que você (sabe |faz|pode))/i) → resposta curada em prosa (capacidades, não slash).studio_bot_welcome_v1 submetido pra Meta; cron diário detecta corretor ativo sem registro em conversations → dispara 1x.concierge_events (phone, raw_text, intent_parsed, tool_call, role, confirmed_at, completed_at, error_reason); cron semanal reporta top "não mapeei" + taxa de confirmação por corretor.3.3. deal_parties — identidade de parte por CPF, não por party_index 🆕 P1 (20/05)
- Bug: deal_parties é chaveado por (deal_id, role, party_index), e o party_index é contador sequencial atribuído pela ordem de iteração de cada fonte (Pipeimob sync, matrícula/OCR, extração de CCV). Fontes ordenam os vendedores diferente → nome de uma fonte e CPF de outra colidem na mesma linha.
- Incidente: deal 1089-19 — VENDEDOR 1 ficou com nome "JULIANA" + CPF do Daniel; a DD rodou as consultas TJSP no CPF errado. Corrigido à mão 20/05.
- Varredura 20/05: 1 outro deal suspeito — 1016-275 (JULIAN CLEMENTE com 2 CPFs distintos) — conferir matrícula/CCV manualmente.
- Fix: upsert de deal_parties por CPF (identidade estável) quando há CPF; party_index vira só ordem de exibição. Sem CPF, cai pro índice.
- Effort: Medium | Impact: High (afeta DD de qualquer deal multi-vendedor com fontes divergentes)
3.3.1. TRF3 fallback Python — bug de quoting --abrangencia 🆕 P1 (26/05)
- Bug: Log do AutoDD mostra TRF3 fallback falhou (Sem JSON parseável no stdout (stderr tail: export: '--abrangencia': not a valid identifier. Script Python trf3_fallback*.py é invocado com flags mal-quotadas — bash interpreta --abrangencia como export em vez de argumento. Quebra TRF3 fallback em vários deals do último ciclo (1083-19, 1089-16, 1089-19, 1002-120, 1087-12, 1087-14).
- Distinto do issue Plexi (upstream TRF3 portal lento, sem ETA — confirmado pela Plexi 25/05): este é nosso bug local de invocação subprocess. Fix isolado, sem depender do upstream.
- Fix: localizar caller (provavelmente trf3-fallback.service.ts ou cron de re-poll) e revisar quoting (spawn com array em vez de exec com string concatenada, ou escape correto de aspas no shell).
- Effort: Small (15-30min) | Impact: Medium (perdemos a 2ª chance de TRF3 quando Plexi falha — afeta cobertura de DDs)
3.3. Painel do Corretor — Fase 2 🆕 P2 (08/07) — Fase 1 LIVE em /painel (ver Done 08/07). Backlog:
- (a) Abrir pros corretores (isolamento por corretor): criar role corretor em VIEW_ROLES (src/dashboard/index.ts), popular dashboard_user_roles + DASHBOARD_ALLOWED_PHONES com os 45 telefones, e no service filtrar brokers pelo agent_code derivado do req.dashboardPhone (cada um vê só o próprio). Effort: Médio | Impact: Alto (cada corretor acompanha o próprio funil sem admin).
- (b) Tabela de metas por corretor → hoje a "Meta atingida" usa valor padrão fixo R$836.120. Criar metas_corretor (agent_code, ano, meta_gci_cents) + migration, e o painel calcula % real. Effort: Baixo | Impact: Médio.
- (c) Dados mês-a-mês → o toggle "Mês a mês" hoje só troca o rótulo; parametrizar o service por mês. Effort: Baixo-Médio.
- (d) Topo do funil (Ligações/Atendidos/Propostas) → sem fonte no bot.db hoje (exibidos —). Avaliar registrar ligações/atendimentos via bot ou puxar de outra fonte (leadbot/StudioImob). Effort: Alto (depende de captura de dado novo).
- (e) Backfill agente_gestor_email em commissions_received (73% NULL) via deals/corretores por deal_code — o painel já contorna por deal_code, mas outras consultas ad-hoc por email seguem furando. Existe backfill parcial em commissions-ledger.service.ts:1201; estender/rodar. Effort: Baixo.
3.4. ~~DD — consulta Serasa (score + restritivos financeiros)~~ ❌ DESCARTADO (Elie, 21/05)
- Decisão: não vamos contratar Serasa nem o Assertiva Score/Crédito Mix 360. A DD fica sem o bloco de score/restritivos financeiros — protesto já é coberto por CENPROT SP. Item encerrado.
3.5. Crontab cleanup pós-split deal 1080-21 ⏰ (gatilho: segunda 28/04)
- Após o monitor confirmar split funcional, remover do crontab do egk@studio76-server as 2 linhas one-shot (0 12 28 4 * e 0 18 28 4 * rodando monitor_split_1080_21.py) — senão re-disparam 28/04/2027.
- Effort: Trivial (5min) | Impact: Low (apenas higiene)
3.6. HSM próprio do parecer de DD pro jurídico externo 🆕 P2 (20/05)
- As advogadas externas (juridico_externo — Dra. Renata, Dra. Fernanda) recebem o parecer via maybeSendParecerFinal (texto + 2 PDFs anexos Imóvel/Partes), mas só com a janela de 24h aberta.
- Pendência: criar template HSM próprio do parecer (envio garantido fora da janela), com botão "Ver detalhes completos" — SEM o botão "Falar com Dr. Wilton" (elas são a jurídica). Submeter à Meta.
- Pós-aprovação (code): incluir JURIDICO_EXTERNO_NUMBERS no envio do template na conclusão da DD + manter os 2 PDFs anexos.
- Effort: Low (código) / depende de aprovação Meta | Impact: Medium
- Nota: o "preview imediato TJSP eproc" (não esperar a certidão SAJ de 5 dias) foi resolvido em 20/05 — o tjsp-eproc/consulta-processual já roda na DD e o prompt da prévia foi ajustado pra tratá-lo como preview. Scraper do portal eproc investigado e descartado (duplicaria função + risco de bloqueio de IP).
financeiro.studio76@gmail.comimplementation-plan-2026.md item 1.1.64.1. Auto-AP via PDF no WhatsApp — classificador + OCR + preview 🆕 P2 (29/04)
- Tese: Elie/Samuel/Yara/Carine/Nicolly/Wilton mandam PDF de boleto/NF/cobrança no WhatsApp e o bot lança automaticamente em contas a pagar — sem comando, sem /. Risco zero porque Elie+Samuel aprovam pagamento real via dual-sig Stark; mandar PDF não dispara pagamento, só cria draft AP.
- Como funciona:
1. Document handler do bot intercepta PDF/imagem (já existe — usado em CCV, comprovantes, fotos)
2. Classificador zero-shot (Claude Haiku 4.5) decide tipo: {boleto, nfse, comprovante_pagamento, ccv, outro}
3. Se for boleto/NF/cobrança: roda OCR (já existe — OCR Improvements 6 Phases COMPLETE em Testing) + extrai linha digitável + valor + vencimento + CNPJ pagador
4. Lookup fornecedor (bot.db.verified_suppliers + DICT BACEN se chave PIX presente)
5. Cria draft em payment_requests_internal (ou MCP contas-a-pagar no estado-atual)
6. Devolve preview pro remetente: "Boleto Contabem R$ 1.571 vence 05/05. Confirma encaminhar pra aprovação? [Sim] [Editar valor] [Não, é outra coisa]"
7. Confirmado → entra na fila do Elie no botjuridico (mesma fila do email)
8. Confidence baixo → fallback "É boleto? [Sim] [Não]" antes de processar
- Público autorizado a mandar: Elie, Samuel, Yara, Carine, Nicolly, Wilton (lista whitelist por phone number no bot.db.users)
- Reuso: OCR pipeline existente (Testing), MCP contas-a-pagar (parsers + dedup + supplier lookup), document handler do botjuridico, DICT validation
- Diff técnico:
- Novo: classificador de tipo de documento (1 prompt Haiku)
- Novo: hook no document handler ANTES do roteamento atual (CCV/comprovante/etc)
- Novo: whitelist de remetentes em bot.db
- Novo: preview UX com botões inline
- Reuso: tudo o resto
- Encaixe estratégico: entrega antecipada da Fase 2 do ERP (#10) — começa escrevendo no MCP contas-a-pagar atual, troca destino pro Postgres novo quando ERP F2 chegar. Sem reescrever UX.
- Tradeoffs:
- ✅ Fix-in-chat puro — encaminha boleto no WhatsApp e clica Aprovar, zero email/comando
- ✅ Acelera ciclo Yara→pagamento de horas (email) pra minutos (WhatsApp)
- ⚠️ Classificador errado em PDF ambíguo → preview indevido (mitigação: confidence threshold + fallback "É boleto?")
- ⚠️ Volume alto de PDFs irrelevantes mandados por engano → ruído. Mitigação: silent-on-confidence-below-X (ignora sem responder)
- Decisões pendentes:
- Bot que recebe: botjuridico (94728-9029) ou número novo dedicado a financeiro? Recomendado botjuridico (Elie/Samuel/Wilton já usam; Yara/Carine/Nicolly entram via whitelist)
- Yara/Carine/Nicolly têm WhatsApp com botjuridico hoje? Confirmar phones em bot.db
- Roadmap:
- Fase A (~1d): classificador + hook + preview UX, escreve no MCP atual
- Fase B (~0.5d): whitelist remetentes + telemetria de classificação errada
- Fase C (junto com ERP F2): trocar destino pro payment_requests_internal Postgres
- Effort: Low-Medium (~1.5d Fase A+B) | Impact: High (substitui email pra solicitantes WhatsApp-first; alivia Yara/Carine/Nicolly/Wilton)
- Refs: item P1 #10 ERP Próprio Fase 2, MCP contas-a-pagar, whatsappbot/src/handlers/document.handler.ts
4.2. Reconciliação Bancária — UI de revisão de créditos não-classificados 🆕 P2 (15/05)
- Tese: O commissions_received agora ingere créditos do Bradesco/CEF via bank_statements.db (8ª fonte do ledger, refreshFromBankStatements). Regras de SKIP automático cobrem o óbvio (auto-transferência STUDIO76, PIPEIMOB, TRANSF CC PARA CC, RENTAB.INVEST, < R$50). Mas o que sobra (~69 rows, R$412k) inclui mistura de comissão direta, caução, sinal de venda, ressarcimento — precisa revisão humana pra classificar corretamente. Granatum vai descomissionar, então não dá pra continuar usando conta CAUÇÃO de lá como referência.
- Como funciona:
1. Aba nova no dashboard: "Reconciliação Bancária" (admin only)
2. Lista créditos do bank_statements (Bradesco + CEF) ainda não classificados, ordenados por data desc
3. Pra cada row: mostra data, valor, contraparte, descrição + 4 botões:
- ✅ Comissão (mantém em commissions_received)
- ↩ Caução (move pra tabela cauções separada, exclui do ledger)
- 💰 Sinal de venda (registra como recebível pendente, não comissão)
- ❌ Outro (despesa, ressarcimento, etc — exclui do ledger)
4. Cada classificação grava em bank_statements_classifications (account_id+raw_hash → categoria + classified_by + classified_at + deal_code opcional)
5. Regras aprendidas: se classifica X vezes seguidas o mesmo padrão (ex: PIX REM contraparte Y = sempre caução), sugere autoclassificação na próxima
- Schema novo (statements.db ou bot.db?): preferir bot.db migration v68 (bank_statement_classifications) — fica perto de commission_recipients e do dashboard. statements.db continua read-only do importer.
- UI mínima viável:
- Tabela paginada (50 por página) com filtros: período, conta, valor mínimo
- Badges coloridos por status (vermelho = não-classificado, verde = comissão, amarelo = caução)
- Drilldown: clica numa row → mostra outras txns do mesmo contraparte (pode ajudar a decidir)
- Botão "regra automática": "sempre tratar contraparte X como CAUÇÃO" (seed da regra learning)
- Migrar comportamento atual: refreshFromBankStatements deixa de criar row em commissions_received automaticamente. Em vez disso, cria pending em bank_statement_classifications com status='pending'. Só vira commission quando user clica ✅. Isso evita ruído no /reportar e dashboard de Comissões.
- Riscos:
- ⚠️ Backlog inicial grande (69 rows pra revisar) — mitigação: pre-filtrar por valor mínimo R$1k pra atacar primeiro o que importa
- ⚠️ User esquece de revisar → ledger fica incompleto. Mitigação: notificação WhatsApp semanal "X créditos pendentes de classificação"
- Roadmap:
- Fase A (~3-4h): migration v68, endpoint /api/dashboard/reconciliacao/{pendentes,classify,patterns}, mudança no refreshFromBankStatements pra não criar row direto
- Fase B (~2-3h): aba dashboard com tabela + 4 botões + filtros
- Fase C (~1-2h): regras de aprendizado automático (sugestão de classificação)
- Fase D (futuro): notificação WA semanal de pendências
- Effort: Medium (~7-9h total Fase A+B+C) | Impact: High (regime de caixa COMPLETO + base pra ERP próprio reconciliar bancos sem Granatum)
- Refs: commissions-ledger.service.ts:refreshFromBankStatements, statements.db, dashboard "Comissões recebidas" existente
Granatum Categorization (100%)
- Categorize all Granatum entries with correct cost centers
- Effort: Medium | Impact: Medium
- Ref: implementation-plan-2026.md item 1.1.2
Pipeimob → Granatum Commission Reconciliation
- MCP tool: reconcile_pipeimob_granatum
- Auto-compare commission data between CRM and accounting
- Effort: Medium | Impact: Medium
- Ref: implementation-plan-2026.md item 1.1.5
Bot UX Polish Sprint
- Add typing indicators before long operations (DD, OCR, CCV)
- Reduce message fragmentation ratio (4.1:1 → <2.5:1)
- Add WhatsApp list messages (up to 10 options vs 3 buttons)
- Confirmation before destructive state transitions
- Extend conversation expiry from 2h → 4h
- Effort: Medium | Impact: Medium
7.1. Abstrair comando /cobrar — natural language + auto-resolve (from session 2026-04-24 — Elie/Gildasio demo)
- Aceitar cobrar, cobrar comissão, cobrar parcela 2, gerar pix (sem / obrigatório) via intent classifier
- Auto-detectar parcela atual sem precisar p<N> quando há cronograma de parcelas no CCV + sync com pagamentos externos (Pipeimob legacy + Stark Bank histórico de invoices)
- Auto-resolver deal via:
(a) único deal do corretor em estado COMPLETE/SIGNING ✅ implementado 24/04
(b) extração do último deal mencionado na conversa
(c) deals com parcelas pendentes (cronograma vs invoices emitidos)
- Listar com botões interativos quando 2+ candidatos (em vez de pedir digitação)
- Validar CPF/CNPJ via DICT BACEN no momento da extração CCV → se algum não for chave PIX, perguntar chave alternativa via WhatsApp e atualizar verified_suppliers
- Backfill clicksign_document_key em deals legados via Pipeimob documentos_contrato (Pipeimob deprecation: one-shot script)
- Effort: Medium | Impact: High (Gildasio/Samuel/Carine sem precisar lembrar sintaxe)
- Ref: sessão 2026-04-24, plano project_cobrar_autonomo.md (5 fases concluídas), próximo passo refinamento UX
Diagnóstico (auditoria 19/05/2026):
whatsappbot/src/index.tscresceu pra 25.145 linhas (era 11k em abr/8, 16k em abr/30 — ritmo +5k/mês). Sem refatoração, em 3-6 meses qualquer mudança fica arriscada, lenta e propensa a quebrar features sem relação. Outros suspeitos:auto-dd.service.ts(4.091),ilist.service.ts(2.406),cobranca-fotografia.service.ts(2.355),database.ts(2.317),canal-pro-feed/server.py(2.163). Top da auditoria + recomendações em sessão Claude 19/05.
8.8. [P2] Fase 0 — Rede de Segurança ✅ COMPLETO (19/05, commit 668c04d)
- [x] ESLint 8.57 + Prettier 3.3 (.eslintrc.json, .prettierrc.json + ignores) — npm run lint/format
- [x] Hook pre-push (scripts/git-hooks/pre-push) — bloqueia push se tsc --noEmit falhar; ativar local com npm run setup:hooks
- [x] npm test (scripts/run-tests.js) — 8 arquivos / 25 casos: 5 estoque-vivo legados + 3 novos (utils/retry, utils/llm-json, services/commission-calculator)
- [x] Tag git pre-refactor-fase0 (rollback: git reset --hard pre-refactor-fase0)
- Baseline: tsc verde, ESLint 0 errors / 308 warnings (limpeza incremental)
- 🐛 Bug flagrado pelo linter (não corrigido — fica como follow-up): /setpix duplicado no switch de index.ts (linhas ~2109 e ~2296); 2ª ocorrência é dead code (ERP F2.1e captura primeiro).
8.9. [P2] Fase 1 — Quebrar index.ts em handlers/ 🚧 RETOMADA 10/06 (agora via worktree, regra no CLAUDE.md raiz)
- Padrão: src/runtime/services.ts = registry de singletons (evita dependência circular); cada família de comandos vira src/handlers/<família>.handler.ts; index.ts importa + delega.
- Progresso (commits e7ce44e→6d82aa0, todos em claude/main/prod):
- [x] step 1 — /cnpj + runtime registry
- [x] step 2 — /atribuicao
- [x] step 3 — família wizards CR→CCV (/comprador, /proposta, /dividir)
- [x] step 4 — família /dd admin (/dd-preeval, /dd-batch, /dd-sync-clicksign)
- [x] 10/06 — fix /dados duplicado no switch (alias morto no /eu, mesmo padrão do bug /setpix) — commit 24fc693
- [x] 10/06 — cache iList (112 linhas) → services/ilist-cache.service.ts (piloto do fluxo worktree) — commit f107603
- [x] 11/06 — pipeline de extração de documentos (~550 linhas: storeDocumentText, extractPdf/Matricula/Iptu/PropostaAndSave, runCrossReference) → services/document-extraction.service.ts — commit 51a5f9c; extractPdfForQA ficou (chama extractComissaoFromCCV, caminho crítico)
- [x] 11/06 — família /dd principal (~1.090 linhas, 11 funções: handleDueDiligenceCommand, executeDueDiligence, executeDealLessImovelDD, requestFullDdFromWilton, etc.) → handlers/dd.handler.ts; registry +dueDiligenceService/certidaoRepollService/escalationService — commit d5a663b; index.ts 28.139→27.097
- [x] 11/06 — /matricula (consulta ONR, 275 linhas: normalizeCriForOnr + handleMatriculaCommand) → handlers/matricula.handler.ts (junto do /deletar matricula que já morava lá) — commit 339be9e
- [x] 11/06 — /avaliar + ACM colaborativo (~900 linhas: wizard 5 steps, geo-chancela, comps, PDF + 3 Maps de estado) → handlers/avaliar.handler.ts — commit e5f1cc7
- [x] 11/06 — captação-matrícula (~450 linhas, 10 funções + pendingMatriculaCaptacao) → handlers/captacao-matricula.handler.ts; registry +contractRevisionService/crExtractionService — commit 137d444
- [x] 12/06 — botões CCV ccvtmpl_/ccvapp_ (131 linhas) saem do handleIncomingMessage → ccv-fill.handler.ts; handleGerarCCVCommand vira fn-pointer do registry — commit 4f6522d
- Resultado parcial: index.ts 28.667 (10/06) → 25.379 (12/06) — −3.288 linhas; Fase 1 de extrações seguras CONCLUÍDA
- 📋 Conclusão da análise do handleIncomingMessage (12/06): a cadeia de 63 prefixos de botão já é FINA (mediana 7 linhas/branch — os 2 únicos branches gordos não-financeiros eram os ccvtmpl_/ccvapp_, extraídos). A gordura restante (~600 linhas inline) é TODA caminho de dinheiro da família /cobrar (pendingPagadorSelection ~370l, pendingCobrarConfirmations ~120l, confirmação bancária ~50l) = ⛔ congelada de propósito. Conversão completa pra tabela prefixo→handler NÃO compensa: zero ganho de comportamento vs risco de incidente no hot path. Se um dia fizer, exige smoke manual de dia, não madrugada.
- Próximos (oportunista, não campanha):
- extração de branch/handler sempre que mexer neles por outro motivo
- ⛔ /cobrar e fotografia: NÃO extrair (caminhos críticos de dinheiro — feedback_cobrar_fotografia_criticos) — ⚠️ sessão grok mexeu na família fotografia 11/06 (fotografia-reconciliar + fmtBrl): validar com Elie
- Como retomar: keyword "retomar refatoração fase 1"; cada família = 1 worktree wt/refactor-fase1-* → merge no checkout principal → typecheck+test PÓS-merge → push.
- Fase 2 🚧 INICIADA 12/06 (madrugada): auto-dd.service.ts 6.047 → 3.978 linhas em 3 slices:
- [x] slice 1 — extração de dados do contrato (4 fns, ~370l) → dd-contract-extraction.service.ts — commit a78c272
- [x] slice 2 — operações de matrícula (10 métodos, ~790l) → classe DDMatriculaOps em dd-matricula-ops.service.ts (deps explícitas + 3 callbacks); DD_STAKEHOLDERS → dd-constants.ts — commit 213bf96
- [x] slice 3 — parecer/PDF (~820l: generateAndUploadParecerPdf, buildCertidoesBundles, appendAnexosToParecer) → dd-parecer-pdf.service.ts; helpers puros de processo → dd-constants.ts — commit 8da7177
- [x] slice 4 — maybeSendParecerFinal (512l) → dd-parecer-pdf.service.ts c/ delegate fino na classe (compat force-finalize-dd.ts) — commit 71aa16f; auto-dd fechou a noite em 3.476 linhas (−42%)
- próximo slice (mesma receita, exige mais cuidado): processItem (506l) — coração da orquestração
- Fases seguintes (não iniciadas):
- Fase 3: database.ts (2.3k) → connection.ts + migrations/*.sql + repositories/*.repo.ts
- Fase 4: starkbank-mcp/server.py (1.4k, 52 tools) → tools por assunto
- Fase 5: estado conversacional Map em-memória → SQLite (não perde em restart)
- Ref: memória project_refatoracao_anti_monolito.md; auditoria completa na sessão Claude 19/05.
Ciclo Daniel/Leo 06/05 ficou travado por horas, exigiu bypass manual com 5 commits de fix em produção. Itens abaixo evitam repetição. Plano consolidado:
project_fotografia_manual_06_05.md.
8.10. [P1] Mídia completa do fotógrafo → arquivo + YouTube + Reels IG/FB 🆕 (Intake — Elie 19/06)
- Contexto: novo fotógrafo House Way (id 8) entrega via link de pasta do Drive com subpasta (fotos edts/ 24 JPEG, videos edts/ 4 MP4 ~870MB). Arquivos já nomeados por destino: YOUTUBE - …mp4, REEELS - …mp4, SEM INFOS VT - …mp4. Diretriz Elie: "não desperdiçar nenhuma mídia" — fotos + vídeos.
- Decisões (Elie 19/06): destinos = YouTube (link no iList) + Instagram Reels + Facebook Reels; publicação mista (iList+YouTube automáticos, Reels IG/FB com aprovação no WhatsApp); YouTube público.
- ✅ Fase 0 (feita 19/06, commit 894ea9c): getImagesFromDriveLink agora desce em subpastas (recursivo, pagina, respeita max, ignora vídeos). Fotos da House Way voltam a publicar. Validado em produção (0→24 imgs).
- Fase 1 — Arquivar vídeos (sem dependência externa): capturar os MP4 da pasta e copiá-los server-side (drive.files.copy, sem baixar 870MB) pra pasta canônica do imóvel no nosso Drive; registrar em tabela-fila com destino inferido pelo prefixo do nome (YOUTUBE/REEELS/VT) + status archived. Entrega o "não desperdiçar" já.
- Fase 2 — Campo "Link do YouTube" no iList: ✅ FEITA 19/06 — campo é youTubeLink em editData.listing.listings. IListService.updateListingYouTubeLink(code,url) implementado (espelha updateValidadeViaApi: GetListingPageViewModel→set→POST→re-lê e confirma) com guard só Rascunho (543). Testado e2e reversível no rascunho 601301018-386 (grava ∅→URL confirmado, restaura). Commit 0205913.
- Fase 3 — Upload YouTube: ✅ COMPLETA 19/06 (infra + pipeline + orquestrador, e2e em produção). Token youtube.upload+force-ssl (conta remax.studio76@gmail.com, canal UCL-OGF1wF0QpLntssDmlAyg) em /app/credentials/token_youtube.json. YouTubeService (upload stream/delete) + DriveService.getFileStream + IListService.getListingVideoMeta/updateListingYouTubeLink. Orquestrador: migration v129 youtube_video_queue (fila persistente); pushSessionPhotosToIList enfileira YOUTUBE (público)+VT (não-listado); YouTubeQueueService worker (setInterval 5min no bot, reusa iList vivo): stream→upload→grava youTubeLink se Rascunho, senão sobe e avisa admin (decisão Elie). Título=tipo+dorms+preço+bairro. Validado e2e: fila→upload(104MB,6s)→título dinâmico→done→delete. Ver [[reference_youtube_canal_upload]]. Nota: propertyType veio null no DTO (título cai p/ "Imóvel"); ⚠️ vídeo público >15min pode exigir verificação por telefone do canal (reels curtos, ok).
- Fase 4 — Reels IG/FB: ✅ FEITA 20/06 (FB automático + handoff IG). MetaReelsService: publica vídeo na Página FB 100852809540707 via upload RESUMÁVEL em chunks (vídeo grande dá 413 no simples), usando o META_ADS_TOKEN que JÁ temos (pages_manage_posts, SU Studio76Marketing, deriva page token) — sem token novo. Validado e2e: 105MB em 25s + delete. IG orgânico NÃO automatizado: o escopo instagram_content_publish exige adicionar o produto Instagram ao app Leadbot (27329438999991696) no developers.facebook.com + gerar token (trava em aprovação de outro admin) → por ora o REEELS vira handoff: o bot manda no WhatsApp (notifyAdmins) o link do vídeo no Drive + legenda pronta (tipo/bairro/preço/dorms+hashtags) pro admin postar no IG à mão. IG Business confirmado: @remaxstudio76 id 17841410911694905. Enfileiramento: REEELS→fb_reel+ig_handoff (migration v131 UNIQUE por kind). Commits e3b75a6.
- ÉPICO 8.10 — Fases 0–4 COMPLETAS. Pendência única: automatizar IG (quando sair o token instagram_content_publish, plugar no MetaReelsService — a hospedagem de URL pública do MP4 fica pendente p/ isso). Próxima entrega da House Way roda fotos+YouTube+FB sozinho e gera o handoff do IG.
- Effort: High (épico multi-fase) | Impact: High (cada entrega vira foto+vídeo+reels sem trabalho manual)
8.11. [P1] Aprovação de fotografia com dúvida aberta — 2 bugs pendentes 🆕 (caso Nilza 02/07)
- Contexto: Nilza clicou "Aprovar" com sessões em pending_doubt_text → bot mandou "✅ Aprovação registrada" MAS corretorPartnerNo/corretorPartnerYes não incluem pending_doubt_text na query → 0 sessões → "Não encontrei sessão pendente" e broker_approved_at nunca gravado (sucesso falso). Já corrigido em 02/07 (commit cf9b355): comandos com / não são mais sequestrados pelos wizards de fotografia.
- Fix (a): normalizar pending_doubt_text→pending_approvals DENTRO de corretorApprove logo após o fetch (mesmo padrão do caminho por texto "aprovar", linha ~1555 do service) — um ponto conserta todos os fluxos downstream.
- Fix (b): copy do "✅ Aprovação registrada" promete o comando parceiro 1016-XXX NomeParceiro que NÃO tem handler — corrigir a copy (ou implementar o handler).
- Estado atual dos dados: sessões 84/85 (Nilza, 1016-289/290) resetadas p/ awaiting_broker_approval; sessão 85 com trava partner_corretor_id=19 (Hanna Yoshida) pra clique em "Aprovar" abrir a pergunta de parceria (50/50 R$50 cada) em vez de cobrar 100% (R$100).
- Effort: Low | Impact: High (aprovação falsa trava pagamento do fotógrafo e some com declaração de parceria)
8.1. [P1] Cron de SLA — auto-escalação de sessions paradas 🆕
- Detecta photo_sessions em pending_approvals há >12h e auto-escala via texto: aviso à Yara recapitulando o batch + alerta admin (Elie). Cron diário 14h BRT.
- Why: Yara silenciosa por 4h+ no dia 06/05 travou pagamento Daniel — sem notificação automática, ninguém percebe até alguém reclamar.
- How: novo arquivo scripts/sla_fotografia.py (mesmo padrão dos outros crons silent-on-success); query simples; reaproveita HSM cobranca_fotografia_yara se janela 24h fechada.
- Effort: Low (1-2h) | Impact: High (elimina classe inteira de incidente)
8.2. [P1] Status needs_yara_classification + remoção do default subsídio cego 🆕
- Substituir o atual default subsidy_cents=R$200 (commit 5dab8cb) por subsidy_cents NULL + status que bloqueia o disparo do HSM-corretor até Yara classificar venda/locação no fluxo "Editar".
- Why: default silencioso causou Caren receber HSM R$900 em vez de R$100 (sem listing_id, bot assumiu locação errada — imóvel era venda R$670k). Default financeiro nunca deve passar adiante como se fosse legítimo.
- How: schema migration nova coluna boolean needs_classification; dispatchCorretorHsmsForBatch já filtra por r.listing_id (fix C de hoje); estender pra também filtrar por !r.needs_classification.
- REINCIDÊNCIA 20/05 — session #34 deal 601301103-1 (Edson, R. Indiana 1153 Brooklin): valor_imovel_cents=NULL → subsídio caiu no default R$200 em vez de buscar o valor do imóvel (R$1.125.000 → faixa "acima de R$1M" → R$350). Fotógrafo cobrou R$350, então o reembolso correto era R$0 — mas o bot cobrou R$150 do corretor (split 50/50 Edson R$75 + Carine R$75). 2 invoices indevidas (5419601131470848, 6208052034535424). Mesma classe do incidente Caren — segue P1, ainda não resolvido. O fix tem que pegar o valor do imóvel (iList/deal) pra escolher a faixa, não só bloquear o default.
- Effort: Medium | Impact: High (impede repetição do incidente Caren)
8.9. [P1] Parceria de fotografia exige aceite do parceiro antes de cobrar ✅ FIXED 20/05
- Hoje o corretor declara parceria no wizard ("Sim, tem parceria" → digita nome → confirma) e o bot emite invoice direto pro parceiro nomeado, sem nunca perguntar a ele. Um corretor consegue jogar 50% do custo de foto num colega que nunca concordou.
- Why: 20/05 Edson declarou parceria com Carine no deal 1103-1; Carine recebeu cobrança de R$75 e respondeu "Não tem reembolso" — ela nunca foi consultada. (Caso ficou sem reembolso de qualquer forma por causa do bug 8.2, mas o furo de processo é independente.)
- How: ao registrar partner_corretor_id, em vez de emitir a invoice na hora, mandar HSM/botões pro parceiro ("Fulano te indicou como parceiro 50/50 na foto do deal X — confirma?"). Só emite após aceite; se recusar, cobra 100% do corretor declarante e avisa os dois.
- Effort: Medium | Impact: Medium (fecha furo de cobrança não-consentida entre corretores)
8.3. [P1] Comando /forcar-pagamento <fotografo> admin-only 🆕
- Bypass do fluxo Yara+corretor pra disparar invoices+PaymentRequest direto. Replica o que fizemos com script ad-hoc no 06/05.
- Why: quando bot trava por bug ou por humano demorando, não há rota oficial pra forçar — tive que escrever script ad-hoc com SDK Stark direto. Tornar repetível e auditável.
- How: ACL=administrativa, parâmetros: nome fotógrafo + lista de session IDs (ou "all pending"); valida totals; exibe preview; confirma; dispara; loga photo_session_events action='forced_dispatch' actor='elie'.
- Effort: Medium | Impact: High (recovery garantido em ciclos futuros)
8.4. [P2] DICT lookup obrigatório no cadastro de fotógrafo 🆕
- Wizard de cadastro faz starkbank.dictKey.get(pix) e mostra "esse PIX é da conta de {nome real} — confirma?" antes de salvar. Captura casos como Leo Muniz (PIX +5511997040335 é do pai Jose Francisco da Silva Muniz, não dele).
- Why: descoberto 06/05 quando tentei criar PaymentRequest pra Leo com CPF cadastrado errado — Stark rejeitou ("tax ID does not match the receiver's"). Cadastro fica inconsistente até primeira tentativa de pagamento real.
- How: estender handleFotografoSetup em cobranca-fotografia.service.ts:1799 pra fazer DICT lookup após PIX informado; pedir confirmação textual; gravar cpf_cnpj do titular real (pode ser != fotógrafo).
- Effort: Low | Impact: Medium (evita falha tardia em pagamento)
8.5. [P2] Wrapper safeCreateInvoice com validação de description ≤20 chars 🆕
- Pre-flight check pra starkbank.Invoice.descriptions[].value.length. Trunca ou rejeita antes de chamar API.
- Why: descoberto 06/05 — limite hard não-documentado da Stark. 4 invoices falharam ("must be a text with at most 20 characters") até eu identificar e encurtar manualmente.
- How: método novo em starkbank.service.ts que valida + delega; usar em todos os call sites; memória feedback_stark_invoice_desc_20.md documenta o limite.
- Effort: Trivial (30min) | Impact: Low (evita 1 erro específico recorrente)
8.6. [P2] Editor mais completo no fluxo "Editar" da Yara 🆕
- Hoje (commit f61a36e) "Editar" só aceita N subs VALOR (subsídio). Adicionar: corretor (N corretor APELIDO), parceria (N parceria APELIDO), valor cobrado (N valor R$X).
- Why: no 06/05 sessão 12 estava com corretor errado (Maria Izabel ↔ Elizabel Valeria) e sessão 8 não tinha parceria detectada (Hanna+Alessandra) — Yara não tinha como corrigir via fluxo, tive que rodar SQL UPDATE manual.
- How: estender handleYaraTextItemByItem em cobranca-fotografia.service.ts:984; mesma lógica de re-notificação que já implementei pra subsídio.
- Effort: Medium | Impact: Medium (Yara fica autônoma, dispensa Elie como SQL backup)
8.7. [P2] OCR de fotografia aceita PDF nativo 🆕 (11/05)
- ocrSpreadsheet em cobranca-fotografia.service.ts manda PDF pra Claude como {type:"image", media_type:"image/jpeg"} → API rejeita com "Could not process image". Fernando esbarrou 18:23/11-05 ao mandar a planilha em PDF em vez de JPEG.
- Why: fotógrafo manda PDF (export de planilha) e o batch nem é processado — vira "financeiro olha manual". Workaround atual: pedir reenvio como print/JPEG.
- How: se mimeType === "application/pdf" usar bloco {type:"document", source:{type:"base64", media_type:"application/pdf", data:base64}} em vez de image (Sonnet 4.6 aceita PDF nativo). ~15min.
- Effort: Trivial | Impact: Medium (desbloqueia fotógrafos que mandam PDF)
8.8. [P1] Sync iList properties cache quebrado ✅ FIXED 19/05 (commit 991b8f3)
- Bugs corrigidos:
- auto-sync-ilist.js resolvia SYNC_SCRIPT pra src/scripts/sync-ilist-properties.js (só existe .ts); agora aponta pro dist/ com fallback ao src. Atualiza bot.db (deals/parties/properties).
- refresh-ilist-session.ts não chamava dotenv.config() quando rodado fora de index.ts (cron 08:00) → reclamava de ILIST_EMAIL/PASSWORD undefined. Adicionado import "../config/env".
- Bug colateral descoberto durante fix: cobranca-fotografia.service.ts usava dict.taxId.replace(/\D/g,"") direto, mas DICT mascara CPF de PF (***.950.758-** vira 6 dígitos) → Stark rejeitou 1º PR do Paulo Henrique com invalidTaxId. Fix nos 2 sites de createPaymentRequestPix: prioriza f.cpf_cnpj do DB, valida 11/14 digits. Memória reference_dict_cpf_mascarado.md.
- Smoke validado 19/05 19:13-19:15:
- Auto-deploy → bot restart → safety net 45s pegou session #33 do Paulo → PaymentRequest 6642047029084160 criado (R$350, pending dual-sig).
- Auto-sync-ilist manual: 220 imóveis no XLSX, 3 criados + 217 atualizados, exit 0.
- refresh_ilist_cache.py manual: API retornou 220, cache atualizado de 220→220 (substituiu meu insert manual pelo dado real da API).
- Resíduo pendente: refresh_ilist_cache.py (Step 0 do cron 0 9 * * * run-full-sync.sh) FALHOU hoje 09:00 com Login falhou, mas funcionou 19:15 — pode ser transitório do iConnect. Adicionar retry com backoff seria útil (talvez 2-3 tentativas com 30s entre elas). Step 3.5 atual valida frescor do enrichment (>36h), mas não cobre cache JSON stale por dias se Step 0 falhar e Steps 1-3 continuarem usando cache antigo. Considerar bloquear pipeline ou alertar se Step 0 falha.
Trace completo do fluxo de fotografia — 20/05/2026 (sessão de debug,
cobranca-fotografia.service.ts). Bugs 8.10–8.14 abaixo, em ordem de severidade.
8.10. [P1] Subsídio cego em captação — lookupIlist só lê o cache de listings ATIVOS ✅ FIXED 20/05 (iList API GetListings)
- enrichRow → lookupIlist(listing_id) lê data/ilist-properties-cache.json, que só tem os ~218 imóveis ativos. Foto é tirada na captação → listing está em Rascunho → nunca está no cache → ilist_valor_imovel_cents sempre null → cai no branch default_sem_ilist (subsídio R$200). Sistêmico: toda foto de captação pega subsídio errado. Foi a raiz do 1103-1.
- Why: o fluxo de foto e o cache de imóveis são desencontrados — fotografa-se exatamente quando o imóvel ainda é Rascunho.
- How: buscar o valor por uma fonte que enxergue Rascunho — API iList direta por listing_id, ou deals.pipeimob_data/deal_values, ou capturar valor na planilha do fotógrafo (OcrRow não tem campo de valor do imóvel hoje). Enquanto não houver valor, bloquear o HSM (ver 8.2) em vez de cobrar no default.
- Effort: Medium | Impact: High (toda captação fotografada hoje cobra subsídio errado)
8.11. [P1] Botão "Não, é só meu" não limpa parceria auto-detectada ✅ FIXED 20/05
- Se a planilha do fotógrafo traz "X e Y" no apelido, enrichRow auto-detecta e persistPhotoSessions grava partner_corretor_id na session. Depois, no corretorApprove, o bot pergunta "tem parceria?". Se o corretor responde "Não, é só meu", corretorPartnerNo marca broker_approved_at e dispara — mas não zera partner_corretor_id. dispatchPaymentForReadySessions lê o partner_corretor_id da session → cobra o parceiro mesmo o corretor tendo negado.
- How: corretorPartnerNo deve UPDATE photo_sessions SET partner_corretor_id = NULL nas sessions do corretor antes de despachar.
- Effort: Trivial | Impact: High (corretor nega parceria e o colega é cobrado assim mesmo)
8.12. [P1] pending_corretor_cpf é sobrescrito por paid_dispatched — invoice do corretor nunca é criada ✅ FIXED 20/05
- Em dispatchPaymentForReadySessions, quando o CPF do corretor não está cadastrado, as sessions vão pra pending_corretor_cpf (linha 487) e o bot pede o CPF. O fluxo não dá return — segue e cria o PaymentRequest do fotógrafo. Aí a linha 656 if (invoiceId || payRequestId) é verdadeira (por causa do payRequestId) e marca todas as sessions como paid_dispatched, clobberando o pending_corretor_cpf. Quando o corretor manda o CPF, o handler (linha 962, WHERE status='pending_corretor_cpf') não acha nada → invoice nunca é criada → reembolso do corretor nunca é cobrado (vazamento).
- How: o markPaid da linha 657 deve excluir sessions em pending_corretor_cpf (AND status != 'pending_corretor_cpf'), ou só marcar paid_dispatched quando invoice E payRequest estiverem resolvidos.
- Effort: Low | Impact: High (Studio paga o fotógrafo e esquece de cobrar o corretor)
8.13. [P2] Tags hardcoded nas invoices de fotografia (#fotografo:photomaster, #mes:2026-04) ✅ FIXED 20/05
- createInvoice (corretor e parceiro) em dispatchPaymentForReadySessions usa tags: [..., "#fotografo:photomaster", "#mes:2026-04", ...] hardcoded. Errado pra qualquer fotógrafo que não seja o PhotoMaster e pra qualquer mês ≠ abril/2026. O PaymentRequest já computa monthTag certo — só as invoices ficaram com lixo. Corrompe relatório financeiro por tag.
- How: usar #fotografo:${fotografoNome.split(" ")[0].toLowerCase()} e #mes:${new Date().toISOString().slice(0,7)}, igual ao bloco do PaymentRequest.
- Effort: Trivial | Impact: Medium
8.14. [P2] Invoice do corretor principal — descriptions mostra valor cheio em deal com parceria ✅ FIXED 20/05
- dispatchPaymentForReadySessions: o amount da invoice do corretor principal é metade (totalBrokerOwes), mas as linhas de descriptions usam s.broker_owes_cents / 100 (valor cheio por deal). A invoice do parceiro usa /200 (correto). Resultado: invoice do Edson no 1103-1 dizia "R$ 150,00" na descrição com amount R$75. Cosmético, mas confunde.
- How: quando partnerId, dividir a linha por 200 na descrição do corretor principal também.
- Effort: Trivial | Impact: Low
Agent Onboarding Campaign ✅ PHASE 1 COMPLETE
- ~~6 active users out of 57 corretores — need targeted WhatsApp outreach~~
- Executed (Apr 10 2026):
auditoria-pdfs-corretores/)auditoria_ilist_2026 created (PENDING Meta review, ID: 1502036048174090)/auditoria bot command deployed — brokers can request their PDF anytimepython3 campanha_auditoria_corretores.py send-templates-prodDiligência Prévia no Contrato de Gestão — com Dr. Wilton (from Intake Log — Elie)
Ref:
operations/quintoandar-tech-competitive-analysis.md
Strategy: Match QuintoAndar's tech so corretores have same/better tools while keeping full 6% commission.
AI Property Search via WhatsApp (NLP + Claude + iList/iConnect)
/ilist with semantic search layerDigital Proposal/Counter-Offer Flow
Visit Scheduling via Bot (/agendar)
Financing Simulation (/financiamento [valor] [entrada] [prazo])
Automated CMA/Valuation (/avaliar [endereço]) ✅ iCONATUS INTEGRADO VIA PLAYWRIGHT
ACM/PLANO-AUTOMACAO-ACM.md (7 fases, ~60h, 5 semanas)ACM/src/geoanalise_client.py — cliente automatizado Playwrightgeoanalise_client.py no bot + gerar PDFAuto-Generate Listing Descriptions from Photos (Claude Vision)
Multi-Portal Listing Syndication (Canal Pro extraído → item #0 P1)
tecnologiacnm.github.io/cnm-xml-documentation/)cnm_generator.py — XML generator (221 imóveis, 2.044KB XML, 30 destaques)cnm_mappings.py — 20 property type maps, 70+ feature→area mapsconfig.py — CNM_QUOTA_DESTAQUE=30, OUTPUT_CNM_XML_PATHserver.py — /feed/chavesnamao.xml route + cache + status + regeneraterun-full-sync.sh (pipeline diário 6am)ai_descriptions.py)https://studio76-server.tail92b8aa.ts.net/feed/chavesnamao.xmlEliminar C2S (Contact2Sale) — Middleware CRM Interno 🔥
lead_auditor.py, CnM tem API de leads, ImovelWeb via API)/novavenda wizard pré-preenchido)lead_auditor.py — scraper Canal Pro leads (114/121 correct routing, 94.2%)c2s_scraper.py — scraper C2S (1.197 linhas, audit completo)/novavenda wizardsearch_properties, get_property_details, list_neighborhoods, get_agency_info. Streamable HTTP via Tailscale Funnel HTTPS./api/v1/properties, /api/v1/search?q=..., /api/v1/neighborhoodsRealEstateListing + sitemap.xmlilist-enrichment.json)ai-descriptions-cache.json)property_discovery_mcp.py (FastMCP, porta 5077, user systemd, 232 imóveis)/api/v1/properties, /api/v1/search, /api/v1/neighborhoods) + proxy /mcp no Flask + /.well-known/mcp.jsoneliekfouri/studio76 ✅ — URL corrigida, descrição, visibilidade pública, homepagehttps://smithery.ai/servers/eliekfouri/studio76eliekfouri-g8h8/studio76 (2.049 uses, sem acesso p/ deletar) — URL morta, será superadohttps://github.com/chatmcp/mcpso/issues/2320feed.remaxstudio76.com.br/mcpproperty_store.py — data layer (218 imóveis ativos, LGPD-safe); URL dos imóveis agora usa domínio próprio feed.remaxstudio76.com.br/imoveis/{id} (commit bfef903)property_discovery_mcp.py — FastMCP server porta 5077, systemd service (property-discovery-mcp.service)server.py atualizado — /mcp nginx→5077, REST API /api/v1/*, /.well-known/mcp.jsonhttps://feed.remaxstudio76.com.br/mcp ✅initialize ✅ · tools/list (4 tools) ✅ · search_properties ✅ · claude.ai connector ✅relatorio-ai-property-discovery-ceo.pdf, /memories/session/plan.md/captar + Follow-Up Proativo)/captar → rascunho iList → follow-up proativo → contrato de representação auto-gerado → ClickSign → KPIs de desempenho por corretor./captar cria rascunho iList com dados mínimos (corretor+tipo+transação), consulta GeoSampa, retorna ID + SQL + link. Tabelas captacoes + captacao_events no SQLite./captacoes (painel).ccv-latex.service.ts), preenchimento automático, envio via ClickSign (clicksign.service.ts já em produção). Testemunhas: Wilton Lee + Elie (substitui Yara).captacao_events), /desempenho [corretor], /ranking, digest semanal gestor. Métricas: taxa conversão, tempo até visita, tempo até contrato, responsividade.ccv-latex.service.ts — engine LaTeX→PDF (adaptar para Contrato de Representação)clicksign.service.ts — pipeline completo de assinatura digital (produção)contrato_representacao_parser.py — parser OCR de contratos existentesilist.service.ts — já tem createListing() + updateListingStatus() como baseoperations/PLANO-CONSULTA-IMOVEL-PRIMEIRO-CONTATO.mdTransição PipeImob → BD Próprio (Fonte Única de Verdade) 🔥 NOVO
/status mostra "documentos faltando" incorretamente porque cada sistema tem verdade parcial. Corretores reclamam frequentemente. À medida que corretores usam menos o Pipeimob, dados ficam cada vez mais desatualizados.pipeimob_statement.py como referência Bubble.io scraper).refresh_ilist_cache.py já existe como base)./status. Resolve falsos "documentos faltando".pipeimob_statement.py — Playwright scraper para Bubble.io/Pipeimobrefresh_ilist_cache.py — cache de dados iList via APIRelatório de Gestão 🆕
Análise de Últimos Vendidos — Planilhas ITBI da Prefeitura 🆕
itbi_transactions ou similar)/ultimos-vendidos [bairro] ou /itbi [endereço]Jurídico — Automação Consolidada 🆕
/dd) — funcionando em produção/gerarccv) — 6 templates, funcionandoJornada Diária do Corretor — Tracking de Atividades automático 🆕 P2 (28/04)
/prospectar [contato] | A criar (FASE 2) |/agendar [imovel] | A criar (FASE 2) — reusa wizard /agendar-fotos |/captar cria rascunho iList | ✅ Existe (#30 FASE 1) |/avaliar [endereço] | ✅ Existe |/visita [imovel] [cliente] | A criar (FASE 2) |/proposta [imovel] [valor] | A criar (FASE 1, ref. QuintoAndar Tech-Match) |/gerarccv + ClickSign + bot detecta status SIGNED | ✅ Existe |/cheguei) ou geofence | A criar (FASE 3) |corretor_atividades (event sourcing por corretor_id, atividade_tipo, deal_id?, occurred_at); cron noturno consolida por semana ISO; comando /jornada retorna PDF idêntico ao do RE/MAX preenchido com o que o bot já sabe (métricas 4, 5, 9 funcionam dia 1)./prospectar, /agendar, /visita, /proposta (todos thin wrappers que só registram evento + retornam confirmação curta). UX de 1 linha: corretor manda /visita 601301080-21 João Silva e pronto./cheguei para reuniões. Roberto/Carine ganham relatório semanal de presença./jornada-equipe para Roberto/Carine/Samuel com ranking, evolução semanal, gargalos identificados (ex: corretor X tem 50 prospecções mas 0 propostas → problema de qualificação)./captar, fizer ACM com /avaliar, gerar CCV com /gerarccv etc. recebe seu Tracking preenchido. Quem não usa o bot recebe Tracking vazio — incentivo natural à adoção sem cobrança./funil), #30 FASE 6 (KPIs de captação), #33 (Relatório de Gestão). Todos os três consomem corretor_atividades.Automação das atividades da Yara e da Nicolly — mapa para eliminar trabalho manual 🆕 P2 (28/04)
Atividades - Yara 12.2025.docx, atualizado 12/12/2025) lista 7 categorias com ~40 sub-atividades. Nicolly responde por triagem + entrevista de candidatos a corretor. A maioria dessas tarefas é candidata direta a automação via bot WhatsApp + integrações já existentes (Stark Bank, Granatum, ClickSign, Drive, iList, Pipeimob).Quick map atividade ↔ automação existente/em desenvolvimento:
| Atividade Yara | Automação que cobre | Status |
|---|---|---|
| Calcular reembolso de fotos + repasse David | #29 /agendar-fotos Fase 5 (Invoice PIX corretor D+30) + Fase 6 (PaymentRequest fotógrafo D+7) |
⏳ Em desenvolvimento (plano aprovado 18/04) |
| Subir fotos/vídeos ao YouTube + compartilhar com corretores | botjuridico whatsappbot/docs/planning/captacao-midia-workflow-kickoff.md |
⏳ Em desenvolvimento |
| Atendimento WhatsApp/telefone + rodízio de leads + planilha de leads | #8 Studio Lead Bot v2 (WhatsApp +55 11 97345-7166, intent classifier 9 buckets) | ⏳ Em codificação (shadow mode em prod, Sprint A iminente) |
| Ficha de candidatos (Assertiva → planilha + agenda) | #8 bucket 5 + #20 Assertiva integration (já em produção) | ✅ Em produção (#20) + ⏳ #8 |
| Arquivar Contrato de Representação | #30 FASE 5 (CR auto-gerado + ClickSign + Drive) | ⏳ Em fila |
| Confirmar Representações/Vendas/Locações com corretores | #36 Tracking de Atividades (event sourcing corretor_atividades) + #19 Sales KPI Dashboard |
⏳ Em fila |
| Ranking + perfil de Representações | #19 (/funil, /desempenho, /ranking) + #33 Relatório de Gestão |
⏳ Em fila |
| Digitalização/OCR de documentos | data-capture.service.ts (auto-OCR de fotos via WhatsApp) |
✅ Em produção |
| Solicitar portador (Samuel/Suzana) | /portador — a criar, item planejado dentro de #37 |
🆕 A criar |
| Chaves de imóveis | /chave [imóvel] — a criar, item planejado dentro de #37 |
🆕 A criar (Low) |
| Reposição suprimentos + lembretes Samuel | /suprimentos — a criar, item planejado dentro de #37 |
🆕 A criar (Low) |
| Lembrete lixo terça/sexta | Cron WhatsApp simples — item planejado dentro de #37 | 🆕 A criar (Trivial) |
| Placas, crachás, uniformes (confecção + cobrança) | Padrão /agendar-fotos aplicado a fornecedores externos |
🆕 A planejar |
| Artes de vendidos + ranking + painel (balão/termômetro/foto) + certificados | Generator Claude+Imagen+LaTeX (cluster único) | 🆕 A planejar |
| Café, recepção, abrir portas, cópias físicas, orçamentos diversos, cartão de visita, pastas/envelopes | — | ❌ Não automatizar (físico/julgamento humano) |
Detalhe completo abaixo, por bloco do documento original (Yara 12.2025):
1) Organização do escritório (porta/luzes/café/lixo/reposição)
| Atividade | Plano | Status |
|---|---|---|
| Abrir/fechar janelas, persianas, ar condicionado, luzes | Domótica simples (smart plugs + cron + presence) — fora do bot, projeto à parte | Não planejado (P3) |
| Fazer/organizar café (dia-a-dia + mentorias + reuniões) | Manual — não automatizável (parte do "host" do escritório) | Não automatizar |
| Retirar lixo terças (Nilda não vem) + lembrar Samuel sexta | Cron + lembrete WhatsApp pra Samuel terça 17h e sexta 16h | A criar (Trivial, ~1h) |
| Reposição papel higiênico/toalha/detergente/sabonete/açúcar/mexedores | /suprimentos no bot — Yara declara estoque baixo, bot abre pedido recorrente + alerta Roberto | A criar (Low, ~3h) |
| Avisar Samuel quando acabar café/manteiga/leite | Mesma lógica acima — botão "acabou" → notifica Samuel | A criar (Trivial, ~1h, junto com /suprimentos) |
2) Atendimento — recepção, telefone, WhatsApp, rodízio de leads
| Atividade | Plano | Status |
|---|---|---|
| Recepção / abrir portas | Manual (host físico) | Não automatizar |
| Telefone + WhatsApp + rodízio de leads (Telefone/WhatsApp/Nonstop/C2S) preencher planilha | Item #8 — Studio Lead Bot v2 cobre TODO esse bloco: classifier de intenção, rodízio de captação 38 corretores, escalação humana só onde precisa | ✅ Em produção (shadow mode), full v2 em codificação |
| Preencher planilha de leads | Bot escreve direto em intent_classifications + captacao_offers (item #8) — planilha vira read-only espelho | ✅ Coberto por #8 |
3) Compras (material, placas, crachás, cartão, pastas, uniformes, orçamentos)
| Atividade | Plano | Status |
|---|---|---|
| Material de limpeza / higiene / descartáveis | /suprimentos (mesmo do bloco 1) | A criar |
| Material de escritório | Idem | A criar |
| Placas (confecção + conferência + cobrança) | Bot integra com fornecedor de placas: /placa [imóvel] cria pedido, monitora status, gera Invoice PIX cobrança ao corretor (igual ao item #29 de fotografia) | A planejar |
| Crachás (confecção + conferência + confirmação) | Sub-fluxo do /onboarding (item #7) — bot pede foto + dados, dispara confecção, rastreia entrega | A planejar |
| Cartão de visita do escritório | Yara concentra pedido manual — baixa frequência, manter manual | Não automatizar |
| Pastas / envelopes | Manual (consumível baixo volume) | Não automatizar |
| Camisetas uniforme (conferência + confirmação + cobrança) | /uniforme no bot — corretor escolhe tamanho, bot dispara pedido + Invoice PIX | A planejar |
| Orçamentos diversos | Manual — exige julgamento humano | Não automatizar |
4) Arquivo (Contratos, fotos, documentos cartório, chaves, ficha de candidatos)
| Atividade | Plano | Status |
|---|---|---|
| Arquivar Contrato de Representação | Item #30 FASE 5 — CR auto-gerado + ClickSign + Drive | ⏳ Em fila |
| Subir fotos/vídeos ao YouTube + compartilhar com corretores | Workflow delegado pro botjuridico (whatsappbot/docs/planning/captacao-midia-workflow-kickoff.md) — bot recebe Drive, sobe YouTube, posta link | A criar (4-6h) |
| Documentos de cartório (organizar + pedir portador retirar/entregar) | Bot integra com Leandro (portador atual) via /portador — Yara/Samuel/Suzana abrem solicitação, bot rastreia + lembra entrega | A planejar |
| Chaves de imóveis à venda | Tabela chaves_imoveis — quem está com a chave de qual imóvel; bot consulta /chave [imóvel] retorna paradeiro | A criar (Low, ~4h) |
| Ficha de candidatos (após Assertiva → Planilha Geral + aniversário na agenda) | Item #8 bucket 5 (recrutamento) + Assertiva integration (#20 já em produção) — bot grava ficha em recruitment_pipeline, agenda aniversário no Google Calendar | ✅ Coberto por #8 + #20 |
5) Apresentação de resultados (Representações, Vendas, Locações, Ranking, artes, certificados)
| Atividade | Plano | Status |
|---|---|---|
| Organizar Representações do mês (criar pasta, arquivar contrato, verificar data assinatura) | #30 FASE 5 automatiza criação de pasta + ClickSign + arquivamento | ⏳ Em fila |
| Confirmar Representações/Vendas/Locações com corretores | Bot puxa direto do corretor_atividades (item #36) + Pipeimob/SmartyDeed — Yara para de ligar pra cada corretor | ⏳ Depende de #36 |
| Ranking Representações e Vendas | #19 Sales KPI Dashboard + #36 jornada-equipe | ⏳ Em fila |
| Perfil das Representações (gráficos, tipo de imóvel, bairro) | Mesmo dashboard do #19 + filtros | ⏳ Em fila |
| Artes de vendidos + ranking (post WhatsApp/Instagram) | Generator template Claude + Sora/Imagen — bot gera arte ao detectar venda fechada | A planejar (Medium) |
| Certificados | Template LaTeX (reusa engine ccv-latex.service.ts) auto-preenchido por evento | A criar (Low, ~3h) |
6) Fotos (cálculo de reembolso, repasse para David)
| Atividade | Plano | Status |
|---|---|---|
| Calcular reembolso por imóvel + enviar David (cobrança) | Item #29 — /agendar-fotos (Fase 5) cobre 100% — Invoice PIX D+30 corretor | ⏳ Em fila (Fase 5) |
| Passar valor total mensal para David (pagamento fotógrafo) | Item #29 Fase 6 — PaymentRequest D+7, Granatum sync automático | ⏳ Em fila (Fase 6) |
7) Solicitação de portador + cópias + digitalização + artes painel
| Atividade | Plano | Status |
|---|---|---|
| Solicitar/acompanhar portador (apenas Samuel/Suzana — outros pedem direto Leandro) | /portador (mesmo do bloco 4) com ACL Samuel/Suzana | A planejar |
| Tirar cópias de documentos quando tem escritura | Manual (operação física) — não automatizável sem hardware | Não automatizar |
| Digitalizar documentos | Manual (scanner físico) — bot pode receber foto via WhatsApp e fazer OCR (já existe data-capture.service.ts) | ✅ Parcialmente automatizado |
| Artes do painel (Representações + Transações: balão, termômetro, foto) | Generator template (mesmo do bloco 5 — "artes de vendidos") | A planejar |
Fonte oficial (Samuel Chen, WhatsApp 28/04/2026 11:06 + 11:14) — escopo confirmado pelo CEO em duas mensagens.
Quick map atividade ↔ automação existente/em desenvolvimento:
| Atividade Nicolly | Automação que cobre | Status |
|---|---|---|
| Impulsionamento Google Ads + Meta (gestão + recrutamento) | #5 Impulsionamento Digital P1 + #6 Marketing P1 | ⏳ Em fila P1 |
| Monitoramento de campanhas + direcionamento de leads (Samuel marcou: AUTOMATIZÁVEL) | Conector Meta Ads/Google Ads API → relatório bot + leads viam #8 Lead Bot v2 | 🆕 A criar (depende de #5 + #8) |
| Agendamento inicial com candidatos | #8 bucket 5 (Calendar Nicolly via bot) | ⏳ Em fila (#8 Sprint A) |
| 1ª entrevista com candidato (humana) | — | ❌ Não automatizar (intencional) |
| Confirmar comparecimento / no-show | #8 template nicolly_confirmar_entrevista (botões 1-clique) |
⏳ Em fila (#8 Sprint A) |
| Solicitar documentos + checagem + contrato de novo associado | /onboarding-corretor — a criar, reusa #20 Assertiva + #30 FASE 5 ClickSign |
🆕 A criar (Medium) |
| Agenda de treinamento | /agendar-treinamento — a criar (Calendar coletivo + lembretes) |
🆕 A criar (Low) |
| Preparar material de integração (kit dia 1) | Cluster com bloco 3 da Yara (crachás+cartão+uniforme) + #7 Recrutamento P1 | 🆕 A planejar |
| Reportar status de recrutamento pra Suzana | #8 template suzana_relatorio_recrutamento_diario (DIÁRIO 18h) |
⏳ Em fila (#8 Sprint B) |
| Detectar saída de corretor | #8 sync diário corretores bot.db |
⏳ Em fila |
Detalhe completo abaixo, por categoria:
A) Marketing / Mídia paga / Lead ops
| Atividade | Plano | Status |
|---|---|---|
| Impulsionamento de campanhas Google Ads + Instagram (Meta) — focos: (a) imóveis de gestão (vender estoque) e (b) recrutamento de corretores | Conecta diretamente ao item #5 (Impulsionamento Digital P1) + item #6 (Marketing P1): Studio paga, Nicolly opera. Bot pode automatizar criação de criativos (Claude + Imagen), bidding sugestões, recorte de público — execução continua humana enquanto a estratégia amadurece | Em fila P1 (#5, #6) |
| Monitoramento de campanhas + direcionamento de leads (Samuel marcou como AUTOMATIZÁVEL) | Bot agrega métricas de Meta Ads + Google Ads via API (CTR, CPL, CPC, conversões), gera relatório diário Nicolly+Samuel; leads recebidos via webhook entram no #8 Lead Bot v2 e seguem rodízio/intent classifier sem fricção humana | A criar (Medium, ~3 dias) — depende de #5 + #8 |
B) Recrutamento de corretores
| Atividade | Plano | Status |
|---|---|---|
| Agendamento inicial com candidatos | Item #8 bucket 5 — bot agenda no Google Calendar da Nicolly direto, sem Nicolly digitar | ⏳ Em fila (#8 Sprint A) |
| Primeira entrevista inicial com candidato (humano) | Mantém — é o ponto de avaliação humana que NÃO se automatiza (decisão consciente: pessoas avaliando pessoas) | Não automatizar (intencional) |
| Confirmar comparecimento / no-show pós-entrevista | Bot pinga template nicolly_confirmar_entrevista 1h após horário com botões Compareceu/Não compareceu | ⏳ Em fila (#8 Sprint A) |
| Solicitar documentos do candidato + checagem + inserir no sistema (contrato de novo associado) | Sub-fluxo /onboarding-corretor: bot pede docs (RG/CPF/CRECI/comprovante endereço), valida via Assertiva (#20 já em produção), monta contrato de associação, envia ClickSign, registra no Pipeimob/SmartyDeed/corretores bot.db | A criar (Medium, ~5 dias) — reusa #20, #30 FASE 5, ClickSign service |
| Agenda de treinamento do novo corretor | Bot orquestra: ao detectar contrato assinado → cria evento de treinamento no Calendar coletivo, convida corretor + treinadores, manda lembrete D-1, pede confirmação D-0 | A criar (Low, ~2 dias) |
| Preparar material de integração (entrega no dia da integração) | Checklist + template no Drive: bot gera kit personalizado (crachá, cartão visita, manual onboarding, acessos a sistemas, foto de perfil pra iList) e dispara responsáveis (Yara/Roberto/Carine) automaticamente. Cobre também crachás + cartão visita do bloco 3 da Yara | A planejar (Medium) — agrupa com #7 (Recrutamento P1) + bloco 3 Yara |
| Reportar status de recrutamento pra Suzana | Bot manda relatório DIÁRIO ~18h via template suzana_relatorio_recrutamento_diario | ⏳ Em fila (#8 Sprint B) |
| Detectar saída de corretor da empresa | Bot detecta inativação no corretores (sync diário bot.db) | ⏳ Em fila (#8) |
| Status | Yara | Nicolly |
|---|---|---|
| ✅ Em produção / coberto | 3 (atendimento+rodízio leads, ficha candidatos, OCR documentos) | 0 |
| ⏳ Em fila (item já no board) | 7 (CR, fotos×2, ranking, perfil, fotografia ×2) | 5 (impulsionamento #5/#6, agendamento candidato, confirmação, relatório Suzana, detecção saída) |
| A criar (Low/Trivial/Medium) | 6 (lixo lembrete, suprimentos×2, YouTube uploader, chaves, certificados) | 3 (monitoramento campanhas+leads, /onboarding-corretor, agenda treinamento) |
| A planejar (Medium+) | 6 (placas, crachás, uniformes, portador, artes vendidos, artes painel) | 1 (kit material integração — cluster com bloco 3 Yara) |
| Não automatizar (físico/julgamento) | 8 (porta/luz, café, recepção, cartão visita, pastas/envelopes, orçamentos, cópias físicas, entrevista N/A) | 1 (entrevista humana) |
| Total mapeado | 30 | 10 |
/suprimentos + /chave [imóvel] + lembrete lixo (somam ~10h, eliminam 5 atividades manuais)/agendar-fotos) — destrava bloco 6 da Yara (cálculo reembolso + repasse David)/home/egk/Downloads/WhatSie/Atividades - Yara 12.2025.docx (fonte original RH/Operações), leadbot/docs/studio-lead-bot-plano-ceo.md (Nicolly)/agendar-fotos), #30 FASE 5 (CR ClickSign), #36 (Tracking de Atividades), #19 (KPI dashboard), #33 (Relatório de Gestão)Plano 360° do Corretor — briefing matinal + saneamento + onboarding contextual 🆕 P2 (29/04)
operations/PLANO-360-DO-CORRETOR.md (335 linhas, draft aguardando aprovação CEO)corretor_phone='sync-script'). Blocker compartilhado com #36 Tracking — sem isto, nem #36 nem #38 funcionam direito.corretor_atividades pra montar o briefingStudio76 Reels Engine — geração automática de Reels imobiliários 🆕 P2 (11/05) — ✅ MVP COMPLETO (Módulos 1–7) testado e2e no cloudvero (12/05): marketing/reels-engine/ — config.py (chaves xAI/Anthropic, fonte de dados via canal-pro-feed/ JSONs em modo local/ssh/HTTP, Style com todos os knobs do criativo), property_processor.py (briefing.json = cache iList + ilist-enrichment.json + ai-descriptions-cache.json + Claude Vision anotando cada foto — cômodo/luz/destaques/qualidade/hook/movimento de câmera), prompt_engine.py (coração — Claude com prompts/style_studio76.md → storyboard 6–10 cenas + prompt image-to-video por cena + roteiro de narração + CTA/hashtags/thumb; fallback determinístico), video_generator.py (xAI grok-imagine-video image-to-video, REST async + polling, retries; quirk: campo image é struct {url} não string crua → 422), narration.py (xAI grok-voice TTS PT-BR por cena + narracao.mp3; fallback Google/ElevenLabs; --smoke), reel_assembler.py (moviepy: upscale 720→1080×1920, crossfades, legendas animadas via PIL, cards price/cta/logo, mixa VO+trilha, exporta reel.mp4+legendas.srt+thumbnail.jpg+capcut_project.json; shim PIL.Image.ANTIALIAS p/ Pillow≥10), main.py (CLI orquestrador --imovel/--all/--estoque, flags --dry-run/--from-storyboard/--skip-video/--max-scenes, erro por etapa não derruba a montagem). + scaffold (requirements pinando moviepy<2, README, ARQUITETURA.md = referência dos módulos + quirks da API xAI + refinamentos pendentes, .env.example, .gitignore local re-incluindo o .env.example, marketing/CLAUDE.md). Commits 21bb4cf/485fee0/7466d18/da76c44/8def953/2f3234c/e325909 + docs. Teste e2e: imóvel 601301016-283 (Apto Moema R$1,99M) → 8 clipes grok-imagine-video (720×1280, ~1min em paralelo) + 8 faixas grok-voice Rex PT-BR + reel.mp4 1080×1920@30fps ~45s + srt + thumb + capcut json; frames conferidos visualmente (hook+legenda+watermark, cards preço/CTA, CTA com fundo sunset text-to-video) — funciona. Infra cloudvero: ffmpeg 6.1.1 instalado via apt; .venv do canal-pro-feed/ reusado + moviepy<2+numpy; .env em /home/egk/studio76-repo/marketing/reels-engine/.env (rodar de studio76-repo/, não da cópia rsync studio76/). v2 (12/05, commit 901b6f0): ✅ anti-alucinação (system prompt — código de unidade ≠ andar; nada de fato não confirmado), ✅ narração mais curta (limite de palavras/cena, CTA ≤8) + teto na esticada de VO + comprime se estourar max_seconds, ✅ video_generator pede duration que cobre cena+narração (≤15s) e o assembler desacelera o clipe em vez de fazer loop. Rodado no 601301079-9 (Cobertura Jardim Marajoara, 504 m², 27º andar, R$ 6.990.000 — mobiliada/decorada): 9 cenas, reel.mp4 ~38s, "27º andar/504 m²" são reais (não alucinou), narração enxuta — bem superior ao apê vazio. Enviado pro WhatsApp do Elie. v2.1 (12/05, commits 07b04de/1e63e55): corrigidos 3 bugs que o Elie pegou — (a) a voz ainda era a do grok num re-run: o cache vo_NN.mp3 não tinha o provider no nome → reusava o áudio antigo; agora vo_<provider>_NN.mp3 + flags --force-narration/--force → agora é Piper PT-BR de verdade; (b) legendas se sobrepondo no dissolve: moravam dentro do clipe da cena e o crossfade sobrepunha dois clipes; agora legenda+logo são camada única no timeline final (legenda só entra depois do dissolve, sai antes do próximo), dissolve = 0,2s; (c) narração assíncrona: o assembler persistia as durações esticadas no storyboard.json → num re-run com voz diferente as durações velhas não batiam; agora _plan_durations() calcula em memória a partir da duração REAL do clipe (ffprobe), não persiste; se a VO não cabe na cena, acelera (ffmpeg atempo ≤1.5×). Re-rodado o 601301016-283 (v2.1, ~35s) — enviado pro WhatsApp + em ~/Videos/studio76-reels/v2.1_moema_apto_R1.99M.mp4 (comparar com v1_moema...). Elie: "melhorou". >>> PARAMOS AQUI (12/05) <<< próximos passos: (1) trilha sonora — assets/musica/ ainda vazio; precisa de 1-2 .mp3 royalty-free por mood (Elie passar ou autorizar pegar da YouTube Audio Library/FreePD); (2) transições mais elaboradas (whip-pan/zoom-match) + legendas word-by-word de verdade (hoje é pop-in da frase) + duração-alvo ~28-32s; (3) avaliar upgrade de voz (ElevenLabs pago ou Google Cloud TTS — precisa creds do Elie); (4) medir custo $/Reel antes de --all --estoque. Infra cloudvero p/ retomar: rodar de /home/egk/studio76-repo/marketing/reels-engine/ com /home/egk/canal-pro-feed/.venv/bin/python; .env lá (XAI+ANTHROPIC keys, VOICE_PROVIDER=piper); python main.py --imovel <id> [--from-briefing] [--force]. Pós-MVP: UI Streamlit, fila/batch noturno sobre o estoque ativo, integração Meta Ads (#5)+Instagram, comando /reel <imóvel> no WhatsApp bot (#8).
descricao.md de um imóvel, gerar 100% automaticamente um Reel 9:16 (1080×1920) no estilo "top 10 corretor do Instagram" — vídeo + narração .mp3 + legendas .srt + thumbnail sugerida — sem intervenção de editor humano./reel <imóvel> no WhatsApp e recebe o vídeo). Mesma filosofia "Claude como operador universal": corretor não abre CapCut, não escreve roteiro — o sistema entrega o Reel pronto.canal-pro-feed/ já produz, por imóvel ativo, um registro consolidado: ilist-properties-cache.json (base iList via refresh_ilist_cache.py), ilist-enrichment.json (enrich_ilist.py → photos[] em URL Large já ordenadas por sortOrder, descrições local/marketing, amenities[], features[], áreas, quartos/banheiros, vagas, condomínio/IPTU, endereço completo, lat/lng, agentName/Email, qualityMeter, youtubeLink) e ai-descriptions-cache.json (descrição persuasiva PT-BR já gerada pelo nosso algoritmo de melhoria de descrição — Claude Sonnet, ~2.9k chars, cache por hash). O Reels Engine consome esse merged record — id 60130NNNN-X resolve o corretor dono — e reusa a descrição do AI, não re-deriva do zero. descricao.md manual = override opcional. ⚠️ esses JSONs vivem no cloudvero (/home/egk/canal-pro-feed/); o Reels Engine roda lá (ou puxa via feed.remaxstudio76.com.br / rsync) — definir no Módulo 1.output/<id>/ com reel.mp4 (9:16, 20–45s), narracao.mp3, legendas.srt, thumbnail.jpg e capcut_project.json (fallback editável caso a montagem programática não satisfaça).marketing/reels-engine/ standalone no MVP; comando /reel <imóvel> no whatsappbot vem depois (pós-MVP).grok-imagine-video (POST /v1/videos/generations, SDK xAI faz o polling) — modo image-to-video (anima as fotos reais do imóvel como frame inicial → pan/parallax/"drone") + reference-to-video + video-extension. Clipes 1–15s, aspect 9:16 ✅, resolução 720p (480p default) — o reel_assembler faz upscale 720→1080. Opcionalmente grok-imagine-image-quality (text-to-image, 9:16, até 2k) p/ frames extras (capa, cards). video_provider.py continua plugável (Veo 3 / Runway = fallback futuro). ⚠️ 720p é abaixo do 1080p ideal do Reels — aceitável no MVP, revisar quando xAI liberar tier maior.grok-voice-think-fast-1.0 (POST /v1/tts) — 5 vozes (Rex/Leo masculinas confiantes, Ara/Eve femininas, Sal neutra), speech tags inline (pausas, sussurro, ênfase — ótimo p/ narração cinematográfica), saída MP3. ⚠️ PT-BR não está confirmado na doc da xAI (só en documentado p/ TTS; STT suporta 25 idiomas) → testar narração em português logo no Módulo 5; se a voz PT-BR não convencer, fallback = Google Cloud TTS (PT-BR, grátis no nosso volume) ou ElevenLabs. Por isso o narration.py tem adapter de voz plugável.ffmpeg/moviepy programático (transições, legendas animadas, trilha, CTA final) sem depender de CapCut CLI; gerar também capcut_project.json como rede de segurança.marketing/reels-engine/assets/musica/) — sem faixas "trending" (risco de copyright no Instagram).canal-pro-feed/ (cache iList + ilist-enrichment.json + ai-descriptions-cache.json — ver "Entrada / Saída" acima); descricao.md manual = override opcional.config.py — chaves de API (xAI/Anthropic), localização dos JSONs do canal-pro-feed/ (modos local/ssh/remote), Style dataclass com todos os knobs do criativo (duração, hook, cenas, paleta, tom de narração, legendas, CTA, price card), nomes de modelos/endpoints xAI, diretórios, validate() + summary().property_processor.py — carrega o merged record (cache iList + ilist-enrichment.json + ai-descriptions-cache.json), baixa as fotos "Large" pro .cache/, Claude Vision anota cada foto (cômodo, descrição, destaques, luz, qualidade 1-5, hook 1-5, movimento de câmera sugerido) — reusa a descrição do AI como base; override manual por imoveis/<id>/; salva briefing.json.prompt_engine.py — núcleo: dossiê do imóvel → Claude (system de diretor de Reels + prompts/style_studio76.md) → JSON com hook/cenas/cta/hashtags; pós-processa (valida nº de cenas, casa cada cena com foto real única, ajusta durações p/ caírem em [min,max], constrói o prompt final de image-to-video por cena, insere overlays price_card/cta_card); fallback determinístico sem Claude; salva storyboard.json + roteiro_narracao.txt.video_generator.py — gera clipes por cena via grok-imagine-video (image-to-video, polling async, retries), controla consistência visual, paraleliza quando a API permitir.narration.py — gera/segmenta a narração sincronizada com as cenas, sintetiza áudio via grok-voice-think-fast-1.0 (adapter plugável → Google Cloud TTS / ElevenLabs se o PT-BR da xAI não servir). 1ª tarefa do módulo: smoke test de PT-BR.reel_assembler.py — concatena clipes, upscale 720p→1080×1920, transições suaves, legendas grandes/animadas, trilha, cards (preço/CTA/logo), exporta reel.mp4 9:16 + capcut_project.json + thumbnail.jpg.main.py — CLI: --imovel <id> (um imóvel) e --all (batch sobre imoveis/); logging estruturado + tratamento de erros por etapa (falha numa cena não derruba o Reel inteiro)./reel no bot (#8).grok-imagine-video (image-to-video, 9:16, 720p, 1–15s/clipe, async). API key xAI fornecida 11/05 → guardar em .env (gitignored). Adapter plugável; Veo 3 = plano B.grok-voice-think-fast-1.0 (/v1/tts, MP3, speech tags) — stack 100% Grok (vídeo+imagem+voz, 1 vendor, 1 chave). Fallback Google Cloud TTS / ElevenLabs se o PT-BR da xAI não convencer (testar no Módulo 5).marketing/reels-engine/ no MVP; comando /reel no whatsappbot na fase pós-MVP.ilist-enrichment.json + ai-descriptions-cache.json (descrição já melhorada pelo nosso algoritmo); descricao.md manual = override opcional. (Definir no Módulo 1 como o Reels Engine acessa esses JSONs — rodar no cloudvero, puxar via feed.remaxstudio76.com.br ou rsync.)grok-imagine-video (async, "vários minutos" por clipe × 4–6 clipes)./cadastrar-corretor — wizard inline de onboarding no WhatsApp 🆕 P2 (22/05)
Administração → Corretores → Exportar, (3) rodar npx ts-node scripts/import-corretores-from-ilist-xlsx.ts <path> no cloudvero. Toda admissão (frequente) exige Elie pra rodar CLI. Princípio fix-in-chat do CLAUDE.md pede que toda ação operacional aconteça no bot./cadastrar-corretor restrito a roles gerente+administrativa (Elie, Samuel, Roberto, Carine) via acl.service.ts./comprador, /proposta):corretores.whatsapp_phone)agent_code (4 dígitos, lookup no cache iList whatsappbot/data/ilist-corretores-cache.json pra autocompletar nome/email; se não achar, avisa "cadastra no iConnect primeiro")corretores (mesmo UPSERT do import script)corretor_admin_actions com action='cadastro'.scripts/import-corretores-from-ilist-xlsx.ts:213-340 — extrair pra corretor.service.ts e reusar tanto no CLI quanto no wizard. Padrão wizard maduro (/proposta, /comprador, /cancelar-fee).bot.db (espelho ACL). Se quiser eliminar etapa do iConnect, depende de [[project-substituir-pipeimob-crm-proprio]] + CRM próprio./distrato): criar usuário no iConnect (Gryphtech), criar @remax.com.br no hub.minharemax — esses ficam pra fase 2 quando Playwright iConnect estiver maduro do /distrato./distrato <corretor> — orquestração de desligamento em 4 sistemas 🆕 P2 (19/05, escopo refinado tarde do dia)
Motivação: desligar corretor toca 4 sistemas independentes (Stark+ERP, bot.db, Pipeimob, iConnect). Distrato manual da Célia Navarro 1091 hoje exigiu cirurgia em cada um e quase deixou fee fantasma cobrando. Sem orquestração, fica refém de checklist humano.
Sistemas mapeados (descobertos 19/05 tarde) + estratégia alinhada com descontinuação Pipeimob:
| Sistema | Como tocar | Cobertura desligamento |
|---|---|---|
| Stark + ERP + bot.db | comando /cancelar-fee <code> (✅ codado, deployed 19/05 commit 8aaaf11, migration v76) |
invoices fee canceladas + FeeCharge.cancelled + corretores.active=0 + DeskFeeRule.endDate + audit em corretor_admin_actions |
| Stack própria de documento + Clicksign (NÃO Pipeimob) | novo distrato-latex.service.ts no padrão de contrato-representacao.service.ts + ccv-latex.service.ts → PDF → clicksign.service.ts.sendForSignature(...) (já em prod) |
gera distrato Studio76 com cláusulas oficiais (texto do DOCX da Pipeimob como base) + envia pro Clicksign via NOSSA API. Sobrevive à descontinuação do Pipeimob ([[project-substituir-pipeimob-crm-proprio]]). |
| iConnect/iList (Gryphtech) | Administração → Usuários → Corretor → Editar Perfil → aba Configurações → botão Desativar Usuário (via Playwright) |
1 clique, transição Ativo → Inativo. iConnect é RE/MAX HQ, não vai descontinuar — Playwright aqui é investimento que paga. |
RE/MAX HUB (hub.minharemax.com) 🆕 mapeado 19/05 |
login = mesma credencial iConnect (Provedor: Google). Fluxo: /usuarios?name=<nome> → linha do corretor → Ações Editar (URL /usuarios/editar/<id-opaco>) → botão vermelho Inativar usuário topo direito → modal com campo "Motivo (opcional)" → confirma. Aviso da UI: "Essa ação pode não ser concluída imediatamente" (assíncrono). |
É o identity provider central da RE/MAX BR (governa @remax.com.br Google Workspace + propaga Ativo/Inativo). ⚠️ Constraint dura: UI bloqueia inativação se corretor tem imóveis ativos no Gryphtech — mensagem: "Usuário com Imóveis Ativos! Transfira os imóveis do associado na Gryphtech primeiro, antes de tentar a desativação." → ordem forçada: iConnect ANTES de hub. |
Decisão estratégica (19/05 noite — revisão pós-mapeamento): ❌ NÃO automatizar o modal "Instrumento de Distrato" do Pipeimob via Playwright. Razão: Pipeimob está em rota de descontinuação (memória [[project-substituir-pipeimob-crm-proprio]]). Em vez disso, replicamos a geração do distrato com nossa stack LaTeX→PDF + Clicksign nossa — texto extraído do DOCX gerado pelo Pipeimob da Célia (cláusulas oficiais, testemunhas Carine+Yara hardcoded). Quando o CRM próprio (StudioImob/SmartyDeed) substituir o Pipeimob, o fluxo continua igual.
Cenários do distrato Pipeimob (importantíssimo — 2 toggles independentes no modal):
Código Imóvel | Endereço Completo | Nome Completo do Proprietário.Código Imóvel | Endereço Completo | Nome do Cliente atendido pelo EX-ASSOCIADO | Percentual devido ao EX-ASSOCIADO em caso de resultado útil.Fluxo proposto (/distrato 1091):
1. Preview unificada — bot resolve agent_code → mostra status nos 4 sistemas + checklist do que vai fazer. Lista invoices fee em aberto, deals com splits ativos (sugestão pra Tabela 5), listings dele no iList em status Ativo (sugestão pra Tabela 4).
2. Wizard de cenário — bot pergunta via botões/list:
Ativo) → preenche Cláusula 4bot.db/Pipeimob → preenche Cláusula 5 (% padrão = split atual)/cancelar-fee <code> distrato (✅ já existe — handler atual)distrato-latex.service.ts (cópia do padrão contrato-representacao.service.ts) gera PDF com texto das cláusulas oficiais Studio76 + Cláusula 4 (Partilha 12,5%) e/ou Cláusula 5 (Negócios em Curso) condicionais. Manda pro Clicksign via clicksign.service.ts.sendForSignature(...) — Studio + corretor + 2 testemunhas (Carine + Yara hardcoded). Status sync pelo clicksign-sync.service.ts (já em prod).corretor_admin_actions com action='distrato'.Reaproveita: /cancelar-fee (codado), padrão contrato-representacao.service.ts + ccv-latex.service.ts (LaTeX inline → PDF), clicksign.service.ts (createDocument+sendForSignature já em prod), clicksign-sync.service.ts (status sync já em prod), Playwright pattern (geoanalise_client.py, onr_matricula.py) — só pro iConnect, NÃO pro Pipeimob, wizard pattern (/comprador, /proposta, /dividir).
Pendências antes de codar:
(a) ~~modelo de distrato~~ ✅ RESOLVIDO 19/05 — Pipeimob gera nativamente, modelo oficial Studio76 (cláusulas validadas + Carine/Yara como testemunhas hardcoded); texto integral extraído em /tmp/fyzwr_Distrato...txt (5.7KB, fonte = ~/Downloads/WhatSie/fyzwr_Distrato de Associação de CÉLIA NAVARRO com a REMAX Studio 76.doc);
(b) ~~procedimento RE/MAX HQ pra cancelar @remax.com.br~~ ✅ RESOLVIDO 19/05 tarde — descoberto: é o hub.minharemax.com, mesma credencial iConnect (Google SSO). Inativar lá derruba o usuário do Workspace + propaga pra todos os sistemas RE/MAX BR. Confirmação empírica de que tira o email pendente até rodar pra Célia;
(c) política de splits em deals em andamento — preferência hoje: corretor mantém split contratual dos deals abertos onde já fez trabalho. Materializa via Cláusula 5 do Pipeimob (Negócios em Curso) com percentual = split atual dele;
(d) decisão sobre minisite + feed Canal Pro — quando corretores.active=0, derruba dashboard.remaxstudio76.com.br/c/<slug> + remove anúncios dele do vrsync.xml? Sim por default — proteção de marca;
(e) 🆕 sequenciamento síncrono/assíncrono — hub bloqueia se iConnect tem imóveis ativos → ordem forçada: distrato (Clicksign) → aguardar assinatura → iConnect (transferir/desativar imóveis + desativar usuário) → hub (inativar). 3 opções de UX em aberto: (i) síncrono auto via webhook Clicksign, (ii) 2 comandos manuais (/distrato + /distrato-finalizar), (iii) webhook dispara mas pede confirmação por botão;
(f) 🆕 destino dos imóveis ativos no iConnect antes de desativar — 3 opções em aberto: (i) transferir tudo p/ "corretor sumidouro" Studio76 (precisa confirmar se agent_code reservado existe no iList), (ii) só mudar status p/ Off/Inativo sem trocar titular, (iii) wizard caso-a-caso no bot. Nota Célia (19/05): a gestão dela já caiu (não renovada) → 0 imóveis ativos no iList → caso dela é trivial, pula direto pra "Desativar Usuário" + hub. Decisão (f) só vale pra distratos futuros com livro ativo;
(g) 🆕 faseamento da implementação — Fase A (LaTeX+Clicksign+handler skeleton, ~3-4h) entregável hoje vs Fase A+B (Playwright iConnect+hub) em 1 PR de 1-2d.
Status atual (19/05 noite — pausado, retomar com calma):
/cancelar-fee) em produção, smoke pendentesrc/index.ts:2161 switch/case; cancelar-fee.handler.ts lógica acoplada ao WA (extrair core antes de orquestrar); padrão LaTeX maduro em ccv-latex.service.ts+contrato-representacao.service.ts; clicksign.service.ts.sendForSignature() pronto; clicksign-sync.service.ts em prod; bot.db schema corretores (v76) tem active/fee_exempt/deactivated_at/deactivation_reason; Playwright NÃO existe no repo (auto-sync iList usa Puppeteer headless via /snap/bin/chromium, sem persistência de sessão) — iconnect-automation.service.ts + hub-minharemax.service.ts são código novo do zero; faltam tabelas distrato_envelopes (rastreio Clicksign) + auditdistrato-latex.service.ts + Clicksign nossa) — ~0.5-1d, copia padrão do contrato-representacao.service.ts; texto extraído do DOCX da Célia + cláusulas condicionais 4/5🛑 PAUSADO 19/05 ~15h pra decisões (e)(f)(g) com calma — retomar respondendo as 3 perguntas e implementar Fase A primeiro
Effort total: ~2-2.5 dias (passos 3b+3c+wizard) — reduzido vs estimativa anterior 3d porque substitui Playwright Pipeimob (~1.5d) por reuso de stack própria (~0.5-1d) | Impact: High (HR critical path, audit trail, evita fee fantasma + 4 sistemas dessincronizados, código sobrevive à transição Pipeimob→CRM próprio) | Sinergia: ERP próprio #10, CRM próprio (#9, futuro destino do iList + dos documentos), Bot Jurídico (mesmo padrão wizard)
Refs operacionais:
6386694207307776 canceled + FeeCharge #24 cancelled + corretores.active=0 + supplier #174 renomeado (efeito colateral C2S). Distrato Clicksign + iConnect + hub.minharemax ainda NÃO efetivados — pendentedistrato-latex.service.ts): /home/egk/Downloads/WhatSie/fyzwr_Distrato de Associação de CÉLIA NAVARRO com a REMAX Studio 76.doc (gerado pela UI Pipeimob como modelo — não vamos chamar o Pipeimob, só usamos o texto). Texto plano extraído em /tmp/fyzwr_Distrato...txt (5.7KB) — copiar pra whatsappbot/src/services/distrato/template-source.txt quando codar/tmp/celia-images/*.jpegPictures/Screenshots 19/05 12:13hub.minharemax.com (lista usuários + Editar + modal "Inativar usuário" + erro "Usuário com Imóveis Ativos!"): Pictures/Screenshots/Screenshot from 2026-05-19 14-11-28.png + 14-36-41.png + screenshot do erro (anexado por Elie no chat, salvar em ~/Pictures/Screenshots/ se ainda não tá)https://hub.minharemax.com/usuarios?page=1&limit=10&name=<nome> · edit = https://hub.minharemax.com/usuarios/editar/<id-opaco> (não é CPF nem agent_code — é Mongo ObjectId tipo 689256a44ff14b97c947e33f)/funil command with pipeline visualization)implementation-plan-2026.md item 1.3.4/captar: Assertiva lookup CPF→nome do proprietário (já em produção há semanas)/dd A) Enriquecimento automático ✅: due-diligence.service.ts agora chama lookupPessoaByCpf SEMPRE que CPF resolvido, grava date_of_birth, nome_mae, situacao_cpf, address, phone, email em deal_parties via COALESCE (não sobrescreve docs). Migration v29 aplicou colunas novas em produção./dd B) CPF → CNPJs vinculados ✅: novo lookupEmpresasVinculadasByCpf (tenta endpoint dedicado /localize/v3/empresas-vinculadas, fallback para campo participacoes no payload Localize padrão). CNPJs vinculados são anexados ao parties[] mid-loop e o pipeline de certidões PJ (Receita/JUCESP/protestos/processos via Plexi) roda automaticamente. Corretor recebe notificação "🏢 X aparece como sócio de N empresa(s)".whatsappbot/src/services/due-diligence.service.ts:370-430 · whatsappbot/src/services/assertiva.service.ts:395-455 · Migration v29 em whatsappbot/src/db/database.tsACM/src/geoanalise_client.py funciona diretamente nos apps Shiny/auth/application-preferences:iconatus.shinyapps.io/geoanaliseStudio76_105/implementation-plan-2026.md item 1.5.xfisgar_anuncios.json já existe como formato)Virtual Tours (Matterport integration) — 3D tour links in listings
Photo Rendering & AI Virtual Staging Evolution (/staging → /render)
/staging already works (Gemini 2.5 Flash) for empty room → furnished stagingwhatsappbot/src/services/staging.service.ts (180 lines, fully functional)Sistema de Agendamento de Fotografia End-to-End — /agendar-fotos 🆕 PLANO APROVADO 18/04 (escopo completo)
/home/egk/.claude/plans/shimmying-wiggling-engelbart.md/solicitar-pagamento-fotografo) para incluir agendamento proativo, monitor de Drive, publicação automática no iList após aprovação e motor de lembretes escalonados — princípio fix-in-chat./agendar-fotos → wizard (fotógrafo preferido + datas) → confirmação bilateral → lembrete pré-shoot → fotógrafo informa valor + sobe Drive → monitor detecta upload → corretor aprova/rejeita → publica no iList + cria Invoice PIX corretor (D+30) para diferença → D+7 cria PaymentRequest fotógrafo (aguarda aprovação Elie web UI) → DONE. Nag automático em cada atraso.PaymentRequest (Elie aprova web UI). Corretor paga diferença via Invoice PIX D+30.fotografos, corretor_fotografo_preferencia, photo_subsidy_table, photo_sessions, photo_session_events, photo_session_reminders.photo-session, photo-scheduling, photo-subsidy, photo-delivery-monitor, photo-payment, photo-ilist-publisher, photo-nag./agendar-fotos, /setup-fotografos, /relatorio-fotografia [mes] (replica formato Excel atual: COD | ENDEREÇO | PACOTE | VALOR | DATA | CORRETOR | VALOR IMÓVEL | SUBSÍDIO | REEMBOLSO).Rename botjuridico → studiobot 🆕 P3 (29/04, nome confirmado 11/05)
/cobrar, /captar, /dd, /avaliar, Estoque Vivo, agendamento de fotos, NFS-e, contas a pagar, CCV/Clicksign, sentinela, jurídico). "studiobot" descreve o escopo real e já é o nome usado no STARKBANK_PROJECT_ID (6291662236024832 = studiobot) — então o rename consolida em todos os lugares o nome que já é fato de produção em uma das integrações.ssh cloudvero, path /home/egk/whatsappbot/. studio76-server foi decomissionado (só sentinela-heartbeat sobreviveu).systemd no cloudvero: botjuridico.service → studiobot.servicewhatsappbot/botjuridico.service → whatsappbot/studiobot.service + ajustar auto_deploy.sh (que faz systemctl restart botjuridico)journalctl -u studiobot -f1050941431433587, WABA 1249172496869831 e número +55 11 94728-9029 NÃO mudam)whatsappbot/src/index.ts:1254 (header X-Forwarded-By) + :11674 (mensagem de erro com instrução journalctl); grep amplo por botjuridico no reporeference_hsm_templates.md (título), MEMORY.md referências, reference_arquitetura_maquinas.md, reference_server_jobs.mdKANBAN.md, CLAUDE.md (seção "Produção" e auto_deploy), juridico/planning/*, whatsappbot/docs//home/egk/whatsappbot/ permanece (já é genérico)studio76.duckdns.org + nginx + Stark project ID studiobot permanecem inalteradosauto_deploy.sh no cloudvero pra apontar pra studiobot ANTES de tocar no systemd (senão o próximo git push fica em loop tentando systemctl restart botjuridico)ssh cloudvero "sudo systemctl stop botjuridico && sudo systemctl disable botjuridico"ssh cloudvero "sudo mv /etc/systemd/system/botjuridico.service /etc/systemd/system/studiobot.service"ssh cloudvero "sudo systemctl daemon-reload && sudo systemctl enable studiobot && sudo systemctl start studiobot"ssh cloudvero "journalctl -u studiobot -n 50" + envia /dd ou /cobrar no chatwhatsappbot/botjuridico.service → whatsappbot/studiobot.service e commitar/cobranca-fotografia — lookup de listing_id por endereço 🆕 P3 (05/05)
endereco) → linhas sem listing_id ficam sem resolução de imóvel + sem subsídio calculado pelo valor real.data/ilist-properties-cache.json já tem endereco, numeroRua, bairro, cidade — basta normalizar e fazer match.enrichRow é chamado com row.listing_id IS NULL mas row.address IS NOT NULL.POC Scrapling — testar em scrapers ONR 🆕 P3 (03/05)
financial-services/onr_matricula.py, onr_creditos.py, onr_monitor.py) usam Playwright cru com seletores hardcoded mapeados em mar/2026 (#txtEmail, #btnProsseguir, #lblQrCode) + 2captcha. Toda mudança de UI quebra. Scrapling promete adaptive selectors + stealth nativo + auto-retry → manutenção próxima de zero.canal-pro-feed/canal_pro_scraper.py) — Playwright + cookies, fragilidade média-altacanal-pro-feed/c2s_scraper.py) — requests+regex, ganho parcial (e provavelmente descontinuado quando leadbot próprio substituir C2S)onr_matricula.py para Scrapling, rodar lado-a-lado por 2-4 semanas, comparar taxa de sucesso + tempo de manutenção. Se vingar, migrar onr_creditos.py e onr_monitor.py. Canal Pro depois.LLMs open source locais (Hugging Face / Ollama) — músculo barato e privado 🆕 P3 (02/06)
/cobrar, /dd, decisões). Modelos open source entram como camada barata/privada para alto volume e baixa complexidade — onde pagar Opus/Sonnet por token não compensa, ou onde o dado (PII/LGPD) não deveria sair de casa. Hugging Face é o maior hub de download (>1M modelos); Ollama = runtime local fácil.faq_juridico.json tem 5.626 Q&A + 7.368 insights; hoje provavelmente vai contexto bruto pro Claude. Embedding multilíngue local (ex.: bge-m3) → busca os trechos mais relevantes → só esses vão pro Claude. Ganho duplo: resposta mais precisa + prompt menor = menos custo de API por consulta. Começar por aqui.| Date | Item | Notes |
|---|---|---|
| 2026-07-09 | 📡🚀 Raio-X Karina 1040-97 + conta Meta Ads Leadbot pausada p/ avaliação de ROI + fix definitivo do status "no ar" falso no /raiox | Sessão 09/07. (1) Raio-X 601301040-97 (Karina Mustafá): 99 dias ativo, 0 leads, pedido R$538k vs valor justo R$497.014 (8 vendas reais do prédio, confiança ALTA) = +8,2% acima — REPROVADO no gate automático da peneira de impulsionamento (limite +5%) e em risco de cair de PREMIUM→STANDARD no ranking de portal quando o Fair Value sair do modo sombra (canal-pro-feed/PLANO-MERITOCRACIA-EVIDENCIA.md, pendente decisão Elie). (2) Conta Meta Ads "Studio 76 — Leadbot" (act_2453510681779882): crédito negativo regularizado pelo Elie; decisão dele = manter TUDO pausado (campanha+conjunto pausados por ele, + 11 anúncios individuais que ainda estavam ativos pausados via Graph API nesta sessão) enquanto avalia se o investimento do mês passado (R$5.269 Meta+Google/30d, R$0 comissão atribuída até agora — normal dado o ciclo de venda) retornou em venda+comissão; pode levar semanas/meses, resultado_report.py já roda toda sexta 09:20 BRT. Botão manual "🚀 Impulsionar particular" deixado ativo por decisão do Elie — foi usado 1x no 040-97 no mesmo dia (o que revelou o crédito negativo), depois pausado de novo. (3) Bug real encontrado e corrigido (commit c99af0b): /raiox seguia mostrando "🚀 no ar" pro 040-97 horas depois da campanha ter sido pausada — a tabela impulsionamentos só registra que o boost foi ACIONADO um dia, nunca é limpa se pausado por fora do bot. Fix: novo google-ads/check_boost_live.py (reusa google_live()/meta_live() do reconcile_boosts.py, mesma fonte de verdade) chamado sob demanda pelo raiox.service.ts só quando a tabela acha que está impulsionado (evita custo de API no caso comum) — confirma contra a API real e AUTO-CURA a tabela (upsert/delete), idempotente. Achado colateral: reconcile_boosts.py (cron diário documentado numa memória de 17/06) não está mais no crontab do cloudvero — a reconciliação em lote do resto do estoque não roda mais; o fix desta sessão cobre só o caso individual on-demand do /raiox. Vale reavaliar restaurar o cron (ver Intake). Gates 36/36 testes + typecheck limpo; worktree wt/raiox-live-status merged+removido. Memórias: reference_raiox_anuncio (atualizada), project_meta_ads_leadbot_pausa_avaliacao_roi (nova). |
| 2026-07-08 | 🏦 Sessão financeira: Monitor Jurídico mensal + fixes OFX/fuso + leva de payables/DDA | (1) Monitor Jurídico (juridico/monitoramento-juridico/): custo×desempenho da assessoria RR (Renata), cruza deals c/ commissions_received(GCI)+auto_dd_queue(overlap DD do bot) → build-vs-buy (bot faz DD1 a marginal ~R$23 só matrícula ONR; certidões Assertiva R$671+Plexi R$1.000 são fixas compartilhadas, não diferenciam; retainer R$6k≈mão de obra). One-pager PDF pro Samuel (artifact) + cron dia 9 12hUTC via HSM relatorio_semanal p/ Elie+Samuel. (2) Fix OFX (merge wt/ofx-fix, a576c2e): conciliação REVERSA (baixa externa: débito casa payable ABERTO por valor+nome→PAID, resolveu #171 royalty preso) + dedup FITID-agnóstico de duplicata do MESMO arquivo (Bradesco exportou royalty R$30.407,63 + PIX R$12.150 em dobro; PDF=1×). 15 testes. (3) Fix fuso (merge wt/sched-brt, 6022b6f): /aprovar resolve hoje/amanhã em America/Sao_Paulo (era UTC → off-by-one após 21h BRT + aparecia 'ontem' em fuso a oeste). schedule-date.ts+5 testes. (4) Cadastros/pagamentos: Renata fornecedor Stark id26 + payable #257 R$6.000 PAGO; #237 SPD cancelado (dup do #238 já pago via Stark); limpeza de 3 rows fantasma OFX (DRE -R$72.965 de despesa falsa); payables DDA criados #258 (R$1.040,51 a identificar — beneficiário Bradesco ag4150/cc2114-8, não achado em email/histórico), #259 Iconatus R$973, #260 Pura Vida R$199, #261 Canal Pro 1000 R$3.737,92. Gates verdes (36/36 + 34/34), worktrees limpos. Memórias: project_juridico_build_vs_buy_renata, reference_ofx_bradesco_dupe_samefile_e_baixa_externa. |
| 2026-07-08 | 📊🔗 Painel do Corretor ao vivo em /painel + fix de subcontagem cross-source (iList+Pipeimob por deal_code) |
Sessão 08/07. Pedido do Elie: replicar o protótipo HTML "Painel do Corretor" (sidebar RE/MAX, funil captação/compradores, KPIs) e plugar no bot.db ao vivo. Entregue (commit d84a96d): página branded servida pelo whatsappbot em GET /painel (admin-only, reusa auth/sessão/magic-link do dashboard existente — requireDashboardAuth+requireDashboardRole("admin")), API GET /api/dashboard/painel/data, service painel.service.ts (better-sqlite3, cache 60s), link "🏠 Painel do Corretor" no menu do SPA (nav-painel, some pra não-admin no boot via /me). Achado crítico de subcontagem (~3×): o painel v1 lia só tabelas nativas do bot e casava vendas por commissions_received.agente_gestor_email, que é NULL em 73% das linhas de 2026 (83/113) → descartava a maioria. Fix: atribuir por deal_code (agent embutido em 60130NNNN-S, substr(deal_code,6,4)) + gestões via UNIÃO pipeimob_transacoes_agencia(fase=Estoque) ∪ captações do bot, dedup por código de imóvel (datas Pipeimob são DD/MM/YYYY, ≠ ISO). Resultado validado ao vivo: vendas 30→90, comissão R$522k→R$1,21M, estoque 90→305 (45 corretores ativos). Auditoria das demais views (o Elie pediu): só o painel subcontava TOTAIS — Comissões recebidas (usa commission_recipients.agent_code+CPF), Atribuição de canal (deal_attribution_survey) e Reconciliação (deal_code) OK; Financeiro ("Comissões recentes") e Funil ("NFs pendentes") usavam agente_gestor_name só como RÓTULO (nome em branco em 73%, totais corretos) → fix cd0d054 com fallback COALESCE(NULLIF(name,''), corretores.nome via deal_code), cobertura nome 11%→82%. Ressalvas conhecidas: Ligações/Atendidos/Propostas sem fonte no bot.db (exibidos —); meta anual = valor padrão fixo R$836.120 (sem tabela de metas); leads = só clientes_compradores (bot minisite, sem espelho). Gates 34/34 (typecheck+testes) nos 3 deploys, worktrees limpos. Memória reference_painel_corretor_crosssource_dealcode. Backlog Fase 2 abaixo (P2). |
| 2026-07-02 | ↩️ "Devolver lead" pós-aceite (impulsionamento + buyer-broadcast) com strikes automáticos | Sessão 02-03/07. Gatilho: caso Paula (1089)/lead #834 (Ana, imóvel 601301087-11) — aceitou um lead do bolsão fora da sua região e não atendeu; sem mecanismo formal isso era invisível pro sistema (ghosting silencioso, corretor "escolhia" o lead travando os outros). Decisão Elie: não filtrar por região (bolsão continua aberto pra todos), mas quem aceita e devolve não deveria continuar participando sem consequência. Implementado (commits 243a064+483dfd0): botão "🔙 Devolver" na confirmação de aceite (só com janela aberta) → lista de motivo (região/tipo/preço/outro), com aviso explícito de quantos strikes o corretor já tem e que 3 em 60 dias tira do rodízio. Ao devolver: oferta vira RETURNED, grava em lead_returns (migração v30), redispara automaticamente pro resto do pool ativo excluindo quem devolveu (offerBolsao(..., excludeCorretorIds, restart=true) no impulsionamento; BuyerFlow.broadcastToActives(..., excludeCorretorIds) no buyer-broadcast — ambos preservam o carrossel-por-rodada, não dão repescagem pra quem devolveu). 3 strikes em 60 dias → captacao_rotation.ativo=0 automático + aviso pros observadores do bolsão (notifyBolsaoObservers). Strikes contados por modalidade independente (impulsionamento ≠ buyer-broadcast). Validado com smoke test isolado (leadbot/src/jobs/devolver-smoke.ts, DB temporário + envios mockados, zero impacto em prod): 17/17 checks — devolução simples, guard de devolução duplicada, redisparo excluindo quem devolveu, 3º strike removendo do rodízio, mesmo fluxo no buyer-broadcast. Build (npm run build) limpo, deployado via worktree→merge→push→auto_deploy (rsync+tsc+restart confirmado no cloudvero, versão schema v30). |
| Date | Item | Notes |
|---|---|---|
| 2026-06-16 | 🎯 Trilha de ads "Corretor" — impulso sob demanda separado do algoritmo (PAUSED, aguarda ativação) | Sessão 16/06. Objetivo (Elie): placar de performance — medir custo/lead dos anúncios que o ALGORITMO escolhe (expand_estoque, por score/peneira) vs os que os CORRETORES escolhem (botão 🚀 Impulsionar → boost_listing, podem forçar fora da peneira). Verba adicional (não toca o algoritmo): Google R$30/dia + Meta R$40/dia. Criadas (PAUSED): campanha Google Studio76_Search_Corretor (vazia, bucket allow_empty no create_campaigns.py, popula via add_single_google) + campanha/ad set Meta Proprio_Corretor (id 120252418544850110, LEAK-SAFE ✅ pin WABA leadbot …6158, geo Grande SP 40km, seed 601301101-3 da Denise, via meta-ads/create_corretor_adset.py reusando primitivas do expand_estoque). Roteamento: boost_listing.py usa a trilha Corretor sob flag BOOST_TRACK_CORRETOR=1 (default off; Google→Studio76_Search_Corretor, Meta→add_card --adset Proprio_Corretor). NonStop/RE/MAX Boost não afetado (pipeline expand_terceiros_ctwa separado). PENDENTE: (a) Elie revisar + ATIVAR as 2 campanhas no Ads Manager; (b) ligar BOOST_TRACK_CORRETOR=1 no env do botjuridico/price_drop; (c) painel-placar custo/lead (cruza insights Meta/Google por campanha + leads do lead-bot.db por plataforma + tabela impulsionamentos); (d) divulgar /raiox + botão Impulsionar pra turma. |
| 2026-06-16 | 📡 /raiox <id> — Raio-X do Anúncio (por que o imóvel não tem lead) — Fase 1 (on-demand) LIVE |
Sessão 16/06. Dor frequente: corretor acha o imóvel bem precificado e reclama de "zero lead/zero visita" (gatilho: Denise 1101, imóvel 601301101-3, Vila Sônia, 1 dorm 31m² R$381k). Novo comando on-demand pro corretor (e via concierge: "meu imóvel não tem lead") que cruza num só relatório as camadas hoje espalhadas e devolve veredito + botões fix-in-chat (🚀 Impulsionar / 💰 Revisar preço / 📥 Atender lead): (1) Cadastro (iList enrichment: status/fotos/descrição/qualidade), (2) Exposição (presença+destaque nos feeds ZAP/VivaReal+CnM via XML), (3) Leads classificados em relação ao DONO — reachedOwner (atendido) vs pendingOwner (atribuído a ele mas SEM atendimento, parado no C2S) vs unassigned (falha de roteamento) vs toOther, (4) Preço R$/m² vs comparáveis internos (n≥3). Achado-chave do caso: o "zero contato" da Denise tinha 1 lead real (Margarete, Chaves na Mão) atribuído a ela no C2S há 20d com c2s_status='new' — nunca atendido. Arquivos: handlers/raiox.handler.ts + services/raiox.service.ts (novos) + getListingLeadBreakdown em leads-desempenho.service.ts + tool raio_x_anuncio no concierge + switch/botões no index.ts. Ownership igual /dossie. Validado em produção (typecheck + 18/18 testes + buildRaiox('601301101-3') contra dados reais). PENDENTE Fase 2: (a) gatilho proativo (imóvel ativo há N dias sem lead atendido → bot pinga o dono com o raio-x; depende de HSM novo p/ fora da janela 24h); (b) benchmark de preço via ITBI (424k transações reais) — nosso estoque é esparso demais por bairro (1 único ativo em Vila Sônia) p/ servir de comparável. |
| 2026-06-15 | 🧾 /cobrar: 2 fixes (re-extração de proporções do CCV + 1 mensagem por pagador) — deal 1058-49 (LUZIA 87,5% + RAFAEL 12,5%) | Sessão 15/06 (memória reference_sendtextoralert_hsm_trunca). Contexto: deal 601301058-49 tinha CCV_COMISSAO_EXTRACTED do backfill drive_scan_standalone (maio) com pagadores_previstos: [] — o backfill rodou extractComissaoFromCCV direto, sem storeDocumentText. A cláusula 3.1 do CCV declara partilha 87,5% LUZIA / 12,5% RAFAEL (com PIX = CPF embutidos), que o /cobrar não capturava. Fix 1 (commit caa4aa0): handleCobrarCommand detecta ccvIncomplete (evento existe mas pagadores vazio) e apaga o evento stale antes de chamar ensureCCVExtractedNow — antes a guarda de idempotência retornava already_extracted e nunca ia ao Drive. Validado ao vivo 19:44: re-extração baixou o CCV, capturou LUZIA 87,5%+RAFAEL 12,5% com CPFs (backfill em deal_parties), picker mostrou "Conforme CCV" com preview dos valores. Wizard PIX inline (sessão anterior) coletou chaves de LELLO (clientes.69248bradesco@lello.com.br) e SOLANGE (+5511973283768), salvas em split_receivers por CPF/CNPJ (reutilizáveis). 2 PIX gerados (LUZIA R$28.638,75 + RAFAEL R$4.091,25, parcela 1, #parte:1de2/2de2); fan-out dos 7 repasses armado e liberado (todas as chaves confirmadas no DICT). Fix 2 (commit f48970c): processCobrarConfirmation montava UMA mensagem gigante (2 pagadores × 7 repasses + 2 links) → fora da janela 24h ia via template HSM genérico alerta_sistema_studio76 (corpo ~1024 chars) e TRUNCAVA, perdendo o link do RAFAEL (só LUZIA chegou no WhatsApp do Elie, embora ambas invoices OK no Stark). Agora monta payMessages[] — 1 mensagem curta por pagador, cabe no HSM sem truncar; single-pagador inalterado. Ambos commitados, pushados, deployados (dist recompilado 20:18 UTC) e validados (typecheck + 18/18 testes). |
| 2026-06-14 | 📭 Discador: AMD/caixa postal (Asterisk) — implementado e ARMADO | Sessão 14/06 (domingo noite, fora janela Anatel → sem ligação real). A Directcall não faz AMD no tronco → detectamos no Asterisk antes de gastar STT/LLM/TTS com secretária eletrônica. Camada 1: AMD() no dialplan [ai-dialer] antes do AudioSocket() (asterisk/conf/amd.conf.template calibrado pt-BR conservador — greeting 2500, maximum_number_of_words 5, after_greeting_silence 1100; falso-positivo de desligar na cara de lead real é pior que deixar passar caixa postal). Só MACHINE encerra; HUMAN/NOTSURE/HANGUP conectam. Veredito reportado best-effort via CURL→POST /amd-result no server.py (contadores amd_stats no /health + transcripts/amd_results.jsonl). Camada 2: instrução anti-caixa-postal nos prompts (pega NOTSURE). Gate AMD_ENABLED=1 (ligado, reversível). Commit 3763f2f→merge 5cca0db. Deploy: rsync manual studio76-repo→runtime + bash render-and-run.sh + restart pipecat (⚠️ auto_deploy NÃO cobre leadbot/voice-pipecat/). Verificado sem ligar: dialplan OK, amd.conf montado, app_amd Running, SIP Registered, /amd-result incrementa stats. PENDENTE: validar ao vivo segunda 15/06 + ouvir gravações p/ calibrar. Intake: alternativa Grok Voice API (ver Intake Log). Memória project_discador_voz_self_hosted_br. |
| 2026-06-11 | 🤖⚖️ Judges Claude de ads (Google+Meta) LIVE + 🔕 WA-Assist vira secretária eletrônica + pauta/PDFs reunião Leads Improvements | Sessão 11/06 noite. (1) Auditoria de orçamento: plano R$245/dia OK nas 2 plataformas (Google R$110 + Meta R$135 cravados); picos 08-10/06 eram ad sets extras já pausados + flex diário das plataformas; isca_daily_summary agora lê orçamento real via API (commit 548c342, constantes estavam stale 25/40 vs 30/30). (2) Judge Google (google-ads/claude_judge.py, commit 3af9bc8, cron 11:40 UTC): Claude headless julga termos/keywords sem conversão c/ contexto do estoque iList → negativo EXATO/pausa; 1ª run negativou 4 termos (endereços específicos, lançamento Unità). (3) Judge Meta (meta-ads/claude_judge_meta.py, commit 3ee963e, cron 11:50 UTC): realoca verba entre ad sets ATIVOS mantendo total fixo R$135 (±20%/dia, piso R$15, soma forçada); 1ª run: VM_ISCA 40→32 (saturada), Terc_ISCA 20→16 (0 conv), 2× capped 25→30, BM_ISCA 25→27. Campanhas Meta de maio (4× ad set R$50, pausadas) ARQUIVADAS — eram o "R$50/anúncio" do print do Elie (coluna Orçamento da aba Anúncios = ad set pai). (4) WA-Assist custo ~US$10/dia diagnosticado (7 investigações auto US$5,58, jobs de 28-52 turnos + ~119 rascunhos/classificações sem log) → secretária eletrônica (commit 2cde3a2): ativar/desativar/status no self-chat, default DESLIGADO (só captura inbox, zero API), investiga manual segue; daemon também captura GRUPOS agora (commit 5d382b8, kind:group — antes não havia como ler grupo p/ pauta). (5) Materiais reunião 12/06 (gitignored em operations/apresentacoes/): otimizacao-ia-anuncios-judge.pdf + pauta-leads-improvements-12jun.pdf v4 (14 dias, R$2.345 mídia, Festival da Mudança Canal Pro 2×R$3k + conta 1.000 anúncios a R$3/anúncio vs R$6,17 atual, seção canal YouTube p/ Nicolly apresentar, /meuextrato, minisite Boost). Memórias reference_claude_judge_google_ads, reference_wa_assist_daemon_rascunho_aprovacao. (6) Pauta semanal AUTOMÁTICA (operations/gerar_pauta_semanal.py, commits ff9e8c9+b588d88, cron sexta 09:00 UTC): junta commits+KANBAN+grupo WhatsApp+KPIs por campanha Meta/Google (CPC/CTR/custo-conversa)+funil lead→CCV (leads 7d por fonte do lead-bot.db, "pego"=routed_at not null — attended_at quase não é usado; vendas atribuídas via resultado_report.py --days 30) → Claude escreve só o BODY no template da casa (HTML completo truncava o output do claude -p) → weasyprint → PDF no WhatsApp via dm-outbox (funciona c/ secretária desligada). Testado 2× ponta-a-ponta; semana: 57 leads/30 pegos/10 LOST, Meta R$46,30/conversa. Memória reference_pauta_semanal_automatica. |
| 2026-06-11 | 🧾 Fix boleto "sem barcode" (linha digitável crua) + 📒 /meuextrato self-service + fix lookup homônimas + plano canal YouTube | Sessão 11/06 tarde. (1) Payable #172 (Registro Civil/ONR, certidão casamento 1087-19, R$64,46): boleto SIPE imprime linha digitável CRUA (47 dígitos sem máscara) → regex não casava → request sem barcode → /aprovar rejeitava. Fix extractBarcodeFromText (commit dfe11d0): fallback 47 dígitos contínuos validados por DV mod10 FEBRABAN + 48 iniciando em 8; 6 testes novos; barcode gravado à mão no request #177 e pagamento saiu (BoletoPayment 4886160849502208 processing). Comprovante ao solicitante por email JÁ É automático (F1.4a/F1.7b via webhook — não precisa cron). (2) Caso Angela Teles #1008 (áudio): pediu "pendência no meu nome + recibos 2026" e o concierge roteou pra /dd no CPF dela 2× (certidões pagas!) + "fale com Elie/Yara". Fix (commit c76f3e8): novo /meuextrato (débitos em aberto FeeCharge+invoices Stark no CPF incl. reembolso-foto sem tag #agente + pagamentos do ano c/ totais), tool meu_extrato no concierge, guard anti-DD na tool due_diligence. Smoke 1008: reembolso-foto R$100 vencido (1008-85) + fees mai/jun pagos. (3) Fix LGPD (commit 1b039f6): lookup CPF via split_receivers casava 1º nome → "Angela%" devolvia CPF da Teles pra Contiero no /eu; agora nome completo + fallback só se 1 candidato. (4) Plano canal Market Update (modelo Team Sessa Toronto): pesquisa confirmou formato inédito em SP; plano v2 em operations/plano-canal-market-update-studio76.md (Suzana vetou Samuel como âncora; ITBI 28,8k transações = diferencial; curto fisga/longo converte). Memória project_canal_market_update_youtube. (5) Fechamento noite: smoke test do Elie via /simular expôs que o reroute de simulação remendava só a instância do index — handlers com new WhatsAppService() próprio (meu-fee/eu/meu-extrato) mandavam pro corretor REAL (Gildasio, só não entregou por 131047) → fix prototype (446890a); /meuextrato ganhou link PIX por débito aberto (fix-in-chat) + nota "cobre mai/2026 em diante, anteriores c/ Elie" (525227d); Angela respondida pelo bot c/ extrato real (R$100 reembolso-foto aberto + 2 fees pagos); pipeline "2ª via da mensalidade"→minha_mensalidade→/fee validado (QR cobv dinâmico = multa 2%+juros 1% a.m. recalculados pelo banco na hora, sem reemissão); anúncio publicado no grupo GERAL via fila WA-Assist (+ complemento do período). Gotcha: send-group.js trata QUALQUER argv como mensagem (não tem --help) e abre socket Baileys próprio — enfileirar em dm-outbox.jsonl em vez de rodar direto. |
| 2026-06-10 | 🧾 Fatura Canal Pro entra no /contas + fix guard DAS de terceiro (Suzana) | Sessão 10/06 noite. (1) Canal Pro: a fatura mensal (ZAP+) não chega por email — só atrás do login. canal-pro-feed/canal_pro_invoice.py reusa a sessão do canal_pro_auto_login (2FA Gmail), pega a API de faturas (gandalf-api), baixa o PDF do boleto (HPP protegida por POST key=313=3 primeiros do CNPJ Studio76) e ingere no pipeline de AP via novo whatsappbot/src/erp/scripts/ingest-pdf-ap.ts (reusa handleWhatsappPdfAP) → Payable PENDING no /contas, pronto pro /aprovar. Cron 0 12 10 * *. Validado: fatura 3080637 R$1.852,03 venc 20/06 → payable #169 (fornecedor ADYEN, gateway do ZAP); idempotente (dedup por barcode). Memória reference_canal_pro_boleto_fatura_scraper. (2) Guard DAS terceiro: needle de detectThirdPartyTax exigia "SUZANA RODRIGUES LEE"; a Contabem manda "Pendência (SUZANA RODRIGUES)" sem LEE → 2 DAS da Suzana (jan #165 + fev #166) viraram conta a pagar indevida. Fix needle→"SUZANA RODRIGUES" (commit 2944757); #165/#166 cancelados; #162 (DAS Studio76 via Questor) mantido. Memória reference_guard_imposto_terceiro_needle_suzana. |
| 2026-06-10 | 📸 Bug do 2º passo invisível da aprovação de fotografia + destrava Karina/Fernando | Sessão 10/06 noite (memória reference_fotografia_aprovacao_2passos_limbo_parceria). Bug: aprovar cobrança de foto tinha 2 passos — clicar "Aprovar" no HSM → bot pergunta "tem parceria?" (botões Sim/Não) → só então grava broker_approved_at. O 2º passo deixava a sessão em awaiting_broker_approval (indistinguível de "não clicou"), sem reminder e sem fallback; se o corretor não respondia a 2ª pergunta (ou clicava "Tenho dúvida"), travava pra sempre e ele achava que aprovou. Karina 1040-101 tropeçou 3× desde 04/06. Fix (commit 4c302ae): pergunta de parceria só dispara com SINAL real (partner_corretor_id da planilha) → sem sinal = 1 clique aprova; estado explícito awaiting_partnership_answer; anti-limbo repromptPartnershipIfPending (dúvida/texto solto re-apresenta botões) chamado por corretorAskDoubt+guard de texto no index.ts; reminder cron e HANDLED_STATUSES cobrem o novo estado. Também fix tryDispatchAfterLink (commit be903bb): faltava JOIN fotografos → "reading split of undefined" matava todo dispatch pós-link; sessões paid poluíam o picker de link. Destravados: Fernando/Photomasterlab (sessões 54 e 55, links reinjetados no webhook → 2× PIX R$350 11/06) + Karina (aprovação registrada pós-fix → cobra R$100 + paga Fernando). Validado end-to-end no webhook de produção. |
| 2026-06-10 | ✍️🔎 WA-Assist INVESTIGADOR — o "vou verificar e te retorno" agora se cumpre sozinho + verificação Fernando/Fernanda | Sessão 10/06 noite (memória reference_wa_assist_daemon_rascunho_aprovacao). (1) Pedido do Elie: WA-Assist tinha que investigar como a sessão Claude investiga, sem copiar/colar no terminal. Implementado (commits 6628ea2+7b7df5c): classificador devolve investigar+tarefa; novo wa-assist-investigate.js roda claude -p headless no cloudvero (CLI 2.1.170 instalado; cwd /home/egk/studio76; Bash/Read/Grep/Glob read-only, Write/Edit bloqueados; fila 1-por-vez, timeout 15min, persiste wa-assist-jobs.json) e a resposta fundamentada volta como ENVIO PROPOSTO no self-chat (ok N continua sendo o único gate). Comando manual: investiga <tel|#ticket> <tarefa>. Smoke real (caso Fernando) passou: agente achou sozinho as 2 sessões travadas, o aceite do parceiro às 01:31, a falha [131047] do aviso do link e gerou o ticket #19 pronto. (2) Verificação das promessas do dia: Fernando = R$700 pendente é fluxo travado (sessão 54 falta ELE mandar link das fotos — aviso do bot falhou 131047; sessão 55 aguarda aprovação Karina), 13 pgtos anteriores (R$5.050) todos ok na chave dele; Fernanda Pedrini = retry 1058-46 saiu pela chave CPF (Nubank) e não a celular (Itaú) → verified supplier 25 criado com a chave certa + nota "não usar CPF". Reforça intake 09/06 (HSM recorrente p/ sessões de foto travadas — agora com evidência de falha também no aviso ao FOTÓGRAFO). |
| 2026-06-10 | 🦘 Jumper de Terceiros AO VIVO (F0→F5) + harvest Canal Pro destravado + peneira automática + rastreabilidade venda→campanha + corte de verba p/ R$245/dia | Sessão 08-10/06 (memória project_jumper_terceiros_ads). (1) Canal Pro reativou Inteligência de Mercado → harvest_ad_strategy reescrito p/ o modal novo (CSV diário voltou); build_peneira.py = Step 1.65 do sync (peneira regenera diária, layer único Google+Meta; Meta below-market saiu do ITBI→gap Canal Pro, decisão Elie). (2) Jumper: harvest_market_analysis.py (demanda por bairro, 63 zonas) + select_boosts_ads.py (1000 terceiros por demanda×qualidade) + landing rica /imovel-rede/:id (994 enriquecidos via enrich_rede.py, galeria+disclaimer parceria; gotcha nginx ^~ /imovel/ não casa /imovel-rede/) + campanhas Meta CTWA (carrossel top-10/faixa, PIN anti-leak) e Google Search (T_, --campaign terceiros) ATIVAS (Meta verba reduzida 55/dia; gotcha Google: 3º nível ANÚNCIOS via API). Rotação semanal (rotate_terceiros_ctwa) + CPL diário 09:10 + watcher 1º lead 15min. (3) Corte seletivo R$570→R$245/dia (ALTO+4×por-imóvel+EXPO pausados, reversível). (4) Rastreabilidade (resultado_report.py): venda cobrada × lead (fone>email>nome), watcher 1h DMa origem, consolidado sexta, match google→conversão PURCHASE; 1ª rodada 5 vendas ZAP R$113k GCI. FIX-CHAVE: CCV assinado traz Log Clicksign c/ emails dos signatários no FIM — extractPropostaData cortava em 8k → agora cabeça+cauda + prompt minera o log (validado ao vivo 1058-46) → matches ALTA daqui pra frente. (5) PDFs: fluxo estoque→impulsionamento + Máquina de Leads (board). Pendências*: de-acordo captador (jurídico/Elie), CPL 2-4 sem → realocar verba, backfill emails dos 24 CCVs históricos (opcional). |
| 2026-06-10 | 🤝 Pipeline de comissão de PARCERIA (listing externo) + caso Rubens + WA-Assist (assistente de DMs) + nf-gap-watchdog + /corrigir-pagador + backlog recibos Carine | Sessão 09-10/06. (1) Parceria 602151006-101 (Apto 52 Ed. Paracatu, RE/MAX Incorp): partner-deal.service.ts — provisiona Receivable só do que entra no nosso banco (R$11.040 Bradesco, pagador real PLAN3) + NF Studio #916 + NF Suzana #442 + recibo Carine + planilhas + PDFs no grupo automáticos (commits 13d9d68→62368fb); conciliação OFX herda categoria do receivable casado + filtro por banco (2000924); detecção de CCV parceiro no cobrar-ccv avisa financeiro (7415be4). Royalty REMAX de parceria em aberto c/ Contabem. (2) Caso Rubens (memória reference_rubens_confusao_comprovantes_nf_cancelada): comprovante_scope full→self; NFs canceladas tinham sido "enviadas" com falha 131047 silenciosa (gap: distribuição de NF usa sendDocument cru — estender fix 4a3a1c8); auditoria 3-fontes achou 4 recebimentos dele (1051-32 off-band só aparece no fee_tracker) → dados dos 4 tomadores enviados p/ NFs da PJ dele. (3) WA-Assist LIVE (memória reference_wa_assist_daemon_rascunho_aprovacao): daemon Baileys systemd no cloudvero monitora DMs do WhatsApp pessoal do Elie, Sonnet rascunha c/ dossiê read-only (bot.db: deals/splits/NFs/pagadores/CCV), aprovação no self-chat (ok N/skip N/mute N); outbox p/ scripts (send-dm/send-group-doc enfileiram); ENVIO PROPOSTO = gate p/ tudo que a sessão Claude envia; fixes de produção: re-pair da sessão (Bad MAC), flush periódico (buffer preso), self-chat via @lid, convKey unifica nº×lid. (4) 1051-32 off-band sem NF → NF Studio #917 + Suzana #443 + recibo Carine emitidos; nf-gap-watchdog cron diário 9h30 cruza recebimento×emissões e alerta admins. (5) Caso 1040-99 (boleto pro CPF errado, CCV "por conta e ordem"): cancelado + pagador corrigido p/ comprador Alexandre; fix no picker do /cobrar (responsável=COMPRADOR sem comprador na lista → oferece escolha) + novo /corrigir-pagador <deal> fim-a-fim (cancela ativa + botões de pagador + regrava + orienta /cobrar). (6) Backlog recibos Carine (achado do watchdog): 12 recibos emitidos via Clicksign (R$11.736,46, valores por transfers reais); pendentes 2 deals sem pagador identificado (1016-275 R$370, 1082-9 R$1.026). Intake novo: bot reconhece pedido em linguagem natural → sugere comando preenchido. |
| Date | Item | Notes |
|---|---|---|
| 2026-05-27 | 🤖 /gerar-ccv — bot.db como fonte primária + wizard de gaps + 2 parsers documentais + cláusulas condicionais |
Disparado pela pergunta do Elie sobre o deal 1079-5 (Roberto Veiga, Apto Vila Matilde, 5 vendedores Graná — caso feedback_matricula_vs_cr_obito_inventario.md). Antes: buildCCVData puxava de Pipeimob via stub fraco; bot.db local (rico via DD prévia) era ignorado. Commit 6e7a0e3 — extractFromBotDb (services/ccv-bot-extractor.service.ts) lê deal_property+deal_parties+deal_values+deal_splits+deal_event CCV_NEGOTIATION_FIELDS; buildCCVData (index.ts:11820) prefere bot.db, Pipeimob fallback (alinha feedback_pipeimob_fallback_only.md); 2 gates novos no handleGerarCCVCommand: (a) detectDDGaps bloqueia geração se matrícula/CPF/estado civil faltam → manda rodar /dd (DD prévia é pré-requisito do CCV — corretor NÃO deve mandar matrícula nessa fase); (b) detectNegotiationGaps + wizard ccv-fill (handlers/ccv-fill.handler.ts via WizardManager) pergunta APENAS o que não vem de documento (profissão/regime de bens por cônjuge/PIX vendedor/prazos escritura+desocupação); steps com skipIf por gap (5 vendedores + 3 compradores cobertos); persistência via deal_event re-dispara handleGerarCCVCommand no completion. Commit d28c232 — 2 parsers documentais zeram steps do wizard quando dados chegam via foto/PDF: extractCertidaoCasamento (Haiku Vision/text — regime normalizado p/ 4 opções legais + cônjuges/profissões/cartório/data) e extractBancoDados (Haiku Vision — banco/agência/conta/PIX/titular de screenshot Pix); novo DocType "COMP_BANCO" + classifier regex/Vision; processCertidaoCasamento/processComprovanteBancario (services/ccv-doc-extractors.service.ts) match parte→deal_parties por CPF/nome normalizado, merge profundo no event via mergeCCVNegotiationFields (services/ccv-negotiation-fields.service.ts — merge por index pra parser parcial + wizard não sobrescreverem). Cláusulas condicionais (CEDI/IPTU acordo/usufruto/averbação/cessão/exterior) viram 1 step do wizard com resposta livre tipo "1,3" ou "nenhuma". Fluxo final: corretor manda certidão→regime gravado + nome_conjuge atualizado; manda Pix screenshot→vendedorPix gravado; /gerar-ccv→bot só pergunta o que falta + gera DOCX. 9 arquivos novos/modificados, 11/11 test files verdes nos 2 pushes (auto_deploy no cloudvero). Pendentes (fora do escopo, intake log): /ccv-confirmar (revisar antes de gerar), /ccv-editar campo=valor (corrigir erros do parser), detecção auto de cláusulas (CEDI da matrícula, débitos IPTU do carnê), hook pessoas (registry inter-deal), unit tests do match parte→party + merge profundo. |
| 2026-05-23 | 📊 Survey de Atribuição de Canal — bug do trigger corrigido + backfill + dashboard novo | Disparado pela pergunta "como recebo o feedback das respostas?" — tabela deal_attribution_survey vazia há 5 dias apesar do código deployado em 18/05. Causa-raiz: /cobrar tem 2 paths de criação de Invoice (helper extraído data.* em ~4533 e processCobrarConfirmation pending.* em ~5074); o bloco try { surveyService.invite() } só estava no Path A, e os 5 INVOICE_CREATED entre 18-22/05 (deals 42/36/114/140/105) passaram todos pelo Path B. Fix (9eba206): replica o bloco no Path B em volta do pix-confirm kickoff, invite() faz dedupe por deal_id então rodar nos dois paths é seguro. Backfill (scripts/backfill-attribution-survey-invites.ts): 5/5 invites retroativos disparados via botões (janela 24h aberta pros 5 corretores — Marcelo 1075-5, Hanna 1002-106/118, Sabryna 1022-68, Alessandra 1087-3); cron das 17h UTC pegou e mandou 1º lembrete 3min depois. Dashboard dashboard.remaxstudio76.com.br/dashboard#atribuicao (commit 7884974, admin-only): KPIs (convites/respondidos/taxa/pendentes/expirados/skipped), 2 charts (canal + duração), tabela Pendentes (deal/corretor/estado/dias parado/lembretes — ordenada por dias parado descendente) + tabela Respostas (deal/corretor/canal/duração/observação livre/quando — com busca). Service atribuicao.service.ts JOIN com corretores pra nome/agent_code. Range 7d/30d/90d/180d/Tudo. Memória project_attribution_survey.md atualizada. |
| 2026-05-12 | ✅ DD — monitor de certidões assíncronas + fix expiry prematura + DD 1079-5 recomposta | Disparado pela pergunta sobre a DD do deal 1079-5 (Apto Amaro Bezerra Cavalcanti 161, Vila Matilde, captado por Roberto Veiga): as 5 certidões TJSP dos vendedores/antecessores tinham expirado em ~3 dias porque MAX_ATTEMPTS=42 era queimado pelo repoll de startup a cada restart (auto-deploy reinicia o bot a cada commit) — não por idade real. (1) Fix no certidao-repoll.service.ts: expiry agora é por idade (MAX_AGE_DAYS 7→10); attempts virou só rede de segurança (240) e só conta tentativa se a última foi há ≥3h; notifyExpired passou a alertar a equipe de DD (Elie + Wilton) com mensagem acionável (protocolo do tribunal p/ consulta manual, /dd repoll, /dd) — antes só o corretor recebia "emita manualmente" (não-acionável pra ele). (2) Novo cron dd-async-watchdog.ts (diário 13h UTC = 10h BRT no cloudvero): alerta TJSP/TRF3 travadas há ≥2d na Plexi + qualquer certidão expired/failed nos últimos 7d; silencioso quando ok. (3) Novo retrigger-dd.ts (generaliza run-dd-batch-codes.ts) — re-roda DD prévia pra códigos passados na CLI; nota: processItem tem guard que pula se já há certidões → pra re-disparar expiradas use o repoll. (4) 1079-5 re-disparada: ressuscitei as 5 linhas expired de TJSP em pending_certidoes (attempts=0) e rodei runRepoll('601301079-5') → as 5 voltaram POSITIVAS (ações de usucapião envolvendo a família Graná — Foros de Praia Grande/Taboão/Pinheiros; PDFs no Drive StudioImob/VENDA - 1079-5/DD-DILIGENCIA/). Limpei parecer_final_sent_at e rodei finalizeDDIfReady → parecer recomposto de BAIXO/6 → ALTO/4 (PDF PARECER_DD_601301079-5_2026-05-12.pdf), reenviado pro corretor + Dr. Wilton + Samuel + Elie. dd_checklist sincronizado. (5) Parecer dual Claude×Grok agora roda PARCIAL (commit 1469338): o gate de maybeSendParecerFinal era "tudo 100% conclusivo OU nada" — uma única certidão indefinido (PGFN da Gabriela) bloqueava Claude E Grok ("Análise narrativa por LLM não executada"). Agora basta matrícula + cobertura ≥70%; as não-conclusivas entram no payload como pendência explícita pros modelos citarem. Re-rodei o parecer do 1079-5 → dual ok (claude-sonnet-4-6 + grok-4.3), PDF PARECER_DD_601301079-5_2026-05-12.pdf (Drive 1C6IBBhE9CnXtU7CqWrdJUYbqspJp2A2S) reenviado. (6) processItem ganhou flag force (mesmo commit) — ignora os guards "DD já completada"/"certidões já existem", marca as antigas como superseded e re-roda do zero (pra preencher lacunas); retrigger-dd.ts --force repassa. ⚠️ A re-run forçada morre standalone mesmo com handlers de unhandledRejection/uncaughtException (commit c6d267d) — processItem não foi feito pra rodar fora do bot: o repoll cron do bot processa em paralelo as mesmas pending_certidoes (race no SQLite) → processo morre silencioso após ~1 parte. Fix correto: comando "re-rodar DD" DENTRO do bot (backlog). (7) Parecer PDF → subpasta DD-DILIGENCIA (commit 8e0151d, pedido do Elie): era DOCS-REPRE; agora docType=PARECER_DD → getSubfolderForDoc roteia pra DD-DILIGENCIA junto das certidões. (8) 1079-5 — estado final pós-caos: dediquei + re-pollei → 48 completed + 2 pending: os 8 vendedores/antecessores têm agora as 6 certidões pessoais (CENPROT/CNDT/PGFN/TJSP/TRT2/TRT2_PJe) — a lacuna dos 3 antecessores (PGFN+TJSP) está resolvida — + IPTU_SP + TRIBUTOS_IMOB_SP do imóvel; 5 TJSP positivas (usucapião família Graná); 2 TJSP de antecessor (Adilson/Rozeli) ainda protocolado no tribunal → quando resolverem o repoll cron dispara finalizeDDIfReady e regenera o parecer (agora em DD-DILIGENCIA). Única lacuna real: TRF3 ausente em todos — endpoint trf3/certidao-distribuicao da Plexi 503 (confirmado ao vivo). Commits d4420f7/1469338/c6d267d/8e0151d, deployed. (9) Fix da extração de matrícula (commit 9d2bf22, deployed manual): a via "matrícula já no Drive" agora baixa o PDF e roda extractMatriculaPdfText+extractMatriculaData → persiste deal_property + proprietários + R/Av em matricula_entries (novos helpers ocrAndPersistMatriculaFromBuffer/persistMatriculaEntries); a via ONR também passou a popular matricula_entries. Rodei o one-off pro 1079-5 → 10 R/Av extraídos (óbitos, partilhas/inventário, AV-5 = interdição de um proprietário em 2021 ⚠️ relevante p/ DD, alteração estado civil), 0 ônus ativo; deal_property nº 30.524 / 16º RI / SQL 058.102.0073-7. O próximo parecer (quando os 2 TJSP de antecessor resolverem) já vem com o bloco "Apontamentos da Matrícula" + no DD-DILIGENCIA. (10) 3 itens novos deployados (commits 73c05e6/937f8de, deploy manual — auto_deploy atrasado): #1b TRF3 auto-retry no dd-async-watchdog (refireMissingTRF3) — quando o endpoint trf3/certidao-distribuicao sai do 503, re-dispara as TRF3 faltantes de DDs concluídas ≤45d (teto 25/run, aborta na 1ª se ainda 503) → entram pending, repoll cron resolve. #4 matrícula anexada ao parecer (appendMatriculaToParecer, dep nova pdf-lib) — PDF da matrícula do Drive mesclado ao final do parecer → dossiê único. #2b checklist pro corretor (pingCorretoresPendencias, watchdog diário) — pra cada DD concluída ≤21d em deal ativo com pendências do vendedor (certidões não-automatizáveis: TJSP/TRF3 expiradas, CND federal indefinido + docs PENDING), pinga o corretor com a lista + orientação de onde emitir; throttle 1x/semana por deal (deal_events DD_PENDENCIA_CORRETOR), teto 8/run (backlog de ~43 deals escoa aos poucos). Backlog restante: (i) re-rodar DD: NÃO via comando (decisão Elie 12/05 — evitar comandos) — sistema re-roda sozinho e/ou, em falha, HSM com botão pro corretor decidir; (11) #ii gatekeeping de DOB — DONE (commit 2ec8bdc, deploy manual): plexi.runBatch não dispara CND_FEDERAL_PGFN de PF sem dataNascimento (devolve nao_emitida); dispatchVendorDDForNewParties passa o DOB do deal_parties e, se faltar, enriquece via Assertiva (lookupPessoaByCpf) antes; pingCorretoresPendencias pega nao_emitida e, quando o motivo é DOB, pede a data de nascimento ao corretor em vez de mandar ele ao e-CAC. Backlog restante: (iii) re-OCR matrícula dual-AI (Grok extrai R/Av relevantes + cross-check Claude); (iv) chamado Plexi 503 TRF3 (wiki PLEXIAPI é só doc — usar contato comercial); (v) auto_deploy.sh engasga quando outra sessão dá git pull no studio76-repo antes do cron (PRE==POST → pula) → produção stale; trocar pra arquivo de "último commit deployado". |
| 2026-05-06 | ✅ External Health Monitoring — Uptime Robot ativo | Monitor bot.remaxstudio76.com.br/health configurado em 06/05 (testes UP/DOWN às 02:36 UTC validaram o alerting). Email alert pra eliekfouri@remax.com.br em up/down. Weekly uptime report semanal (chegou primeiro report 11/05 cobrindo 03-09/05). Resolve BUG-007. |
| 2026-05-11 | ✅ Bot — /eu self-service reformulado + /dd aberto pro corretor (wizard de botões) + chave PIX por corretor |
Disparado pela reclamação da Fernanda Pedrini (#1058) — comissão de 08/05 caiu na chave-CPF (Nubank) em vez do Itaú e ela não achava onde conferir os dados. (1) /eu (+ aliases /meusdados, /cadastro, /dados) agora devolve: dados cadastrais (CPF, telefone, e-mail, chave PIX de comissões + banco resolvido via DICT), estoque no iList por agent_code (ativos/reservados/vendidos + valor + validades vencendo), mensalidade aberta, comissões YTD, deals em andamento com progresso de docs, e rodapé de showcase (/ilist, /avaliar, /cobrar, dúvida jurídica). (2) Fan-out de comissão (/cobrar → webhook.py dispatch): a chave PIX enviada ao dispatcher passou a usar split_receivers.chave_pix quando preenchida (fallback CPF) — antes era sempre o CPF; chave_pix da Fernanda atualizada manualmente pra +5511994953123 no bot.db de prod. (3) /dd agora é nível corretor (era corretor_senior) com ownership validado no handler (agent_code embutido no 60130NNNN-S + fallback deals.corretor_phone): /dd sem nada → lista interativa dos negócios do corretor; toca no negócio → 3 botões DD Prévia / Pedir DD Completa / Cancelar; DD Prévia roda na hora; Pedir DD Completa (custo de certidões antecessores/PJ) escala pro Dr. Wilton via escalationService (dedup + lembretes + relay); /dd {código} (curto/completo) e /dd {serial} (só o número, ex. /dd 34 → resolve pelo agent_code; admin busca por serial) também funcionam; /dd completa digitado pelo corretor também escala. Admin/gerência continuam rodando /dd completa direto. Ajuda do bot atualizada. Deployed cloudvero. Commits: a084242, 34df5f8, 235aa78, 515ce90. Pendente (intake 11/05): trazer "Meus dados" pro dashboard web. |
| 2026-05-10 | 🖥️ Dashboard web Studio76 Fase 1 — LIVE em produção | Spec → prod em ~3h numa sessão. https://dashboard.remaxstudio76.com.br no ar com auth magic-link via WA, página Leads (KPIs + 3 charts: fonte/dia/corretor + tabela atendimentos + drill-down modal). Stack: backend Express dentro do whatsappbot (rotas /api/dashboard/leads/*), zero deps novas (HMAC nativo Node crypto), zero novos services systemd; frontend HTML + vanilla JS + Chart.js CDN servidos via express.static. Infra: DNS A no GoDaddy (178.156.155.123), cert Let's Encrypt expandido (certbot --expand, exp 09/08/2026), nginx server block + redirect HTTP→HTTPS + rate limit 10r/s burst=20. bot.db migration v56: dashboard_magic_links + dashboard_sessions + dashboard_access_log. Whitelist: Elie + Samuel via DASHBOARD_ALLOWED_PHONES no .env. Bugs corrigidos durante o smoke: (a) .gitignore *token* (regra de segurança pra creds) bloqueou silenciosamente tokens.ts → auto-deploy quebrou no tsc "Cannot find module './tokens'"; renomeado signing.ts (commit e3ddcb7). (b) WhatsApp prefetch (IP 173.252.127.x = Meta) consumia o token de uso único antes do clique do user → 3/3 tentativas falharam; fix: GET /dashboard/auth agora mostra página intermediária (peek-only, sem DB write), POST consome o token. Auto-submit via JS — crawlers não rodam JS, browsers entram transparente (commit fa6643e). Smoke OK pelo Elie; onboarding via WA enviado pro Samuel wamid.HBgN...88A4F2. Commits: 78eaf44 e3ddcb7 fa6643e. Spec/checklist em dashboard/ARQUITETURA.md. |
| 2026-05-10 | ✅ Canal Pro — Relatório Semanal por Corretor (pipeline end-to-end) | Pipeline novo canal-pro-feed/weekly_report/: Playwright headless baixa CSVs de Performance + xlsx de Anúncios (via email assíncrono grupozap@leads.grupozap.com → redirect → advisor-sauron.grupozap.com); analyzer classifica P1 (≤3 views) / P2 (alto tráfego sem contato) / P3 (Destaque sem vídeo); Claude Sonnet sugere 1 ação por imóvel; reportlab gera 1 PDF por corretor. whatsappbot service canal-pro-weekly registra ciclo em canal_pro_weekly_ciclos (migration v55) e manda preview + 3 PDFs amostra no WA do Elie; HSM relatorio_canal_pro_semanal APPROVED dispara após /aprovar canal-pro-YYYY-MM-DD. Cron seg 07h BRT (preview) + quarta 23h BRT (expire). Smoke 10/05: 33 PDFs, 146 calls Claude, ciclo canal-pro-2026-05-04 aguardando aprovação. /ajuda canalpro no bot. Commits: 69cf463, 15c958c, 59126d9. |
| 2026-05-10 | ✅ Canal Pro auto-login 2FA consertado | Gmail polling rejeitava emails recebidos antes do click (Canal Pro dispara o email durante o typing das credenciais) — relaxado pra janela ±90s + pega o mais recente. OTP inputs do React não respondiam a fill() — trocado por page.keyboard.type(code, delay=80) que emite eventos nativos. Login 14:55 OK em 12s end-to-end. Commits: 5517139, 64a518f. |
| 2026-05-10 | ✅ Canal Pro feed: WM rewrite só pra fotos modernas (UUID com hífens) | Relatório de integração reportava 311 fotos FAILED em 8 listings. Causa: generator.py forçava /Large/→/L/WM/Large/ em TODAS as fotos, mas o CDN gryphtech só gera variante watermarked pra uploads modernos (UUID com hífens). Fotos antigas (hex 32 chars) não tinham watermarked → URLs 404. Fix detecta o formato e só reescreve quando watermarked existe. Pós-deploy: feed regenerado com 0 broken URLs (vs 311), 8842 modernas com watermark preservado. Commit: 5862e09. |
| 2026-05-20 | ✅ Monitores de integração migrados/criados pra e-mail | Disparado pelo alerta das 05:00 "não consegui ler a tabela /integracoes/imoveis" — o integration_monitor.py (ZAP+) quebrava sempre que a sessão do Canal Pro expirava ou a UI mudava. (1) ZAP+ — o e-mail diário "Como estão seus anúncios no ZAP+" (grupozap@leads.grupozap.com) virou a fonte primária: imune a sessão/UI, e traz o detalhe por imóvel dos avisos que o scraper nunca pegou; usa o get_gmail_service() que o monitor já importava pro 2FA (sem credencial nova). Playwright fica secundário, só pro total_removidos (único número fora do e-mail) — se falhar, a run degrada graciosamente. Passou a ler total_avisos. Dedup por execucao. Cron movida 09:00→11:30 UTC (pega o e-mail do mesmo dia). Validado em prod (execução 75608251: 0/0/219). Commit 73fdcef. (2) Chaves na Mão — novo weekly_report/cnm_integration_monitor.py, e-mail-only (não há scraper de portal do CnM, nem precisa): parseia o "Resumo Diário de Importação" (nospam@chavesnamao.com.br, ~17:15 UTC), histórico em cnm-integration-history.json, alerta WA quando Não importados/Em revisão/Problema nas fotos/Referências duplicadas > 0 (URGENTE quando sobe). Cron 17:45 UTC. |
| 2026-05-10 | ✅ Canal Pro integration monitor diário | weekly_report/integration_monitor.py: lê tabela "Relatório de integração de imóveis" toda manhã (cron 06h BRT) e dispara alerta WA pro Elie quando total_nao_importados > 0 ou total_removidos > 0; tag URGENTE quando contagem sobe vs última run. Histórico em weekly-reports/integration-history.json (90 checks). Smoke 16:03 capturou 6 não importados da run 15/01 e enviou alerta. Commit: e06aa90. |
| 2026-05-05 | ✅ Migração canal-pro-feed → cloudvero + decommission studio76-server |
Feed XML dos portais migrado integralmente pro cloudvero (feed.remaxstudio76.com.br). Canal Pro: URL trocada 01/05, confirmado crawl diário. CnM: URL trocada semana de 04-08/05 (suporte confirmou), crawler validado via nginx log (18.229.129.241 às 12:13 UTC). run-full-sync.sh migrado 02/05 com smoke test end-to-end (7min14s, 5 steps verdes). 6 crons F11 instalados no cloudvero. Scripts cloudvero (canal-pro-sync.sh, canal_pro_auto_login.py, monitor.py, property_discovery_mcp.py) atualizados para URL nova. studio76-server: canal-pro-feed.service stopped+disabled, property-discovery-mcp stopped+disabled, Tailscale Funnel off, crontab zerado. Único service ativo: sentinela-heartbeat.service (jail SmartyDeed escritório). Script de decommission versionado em operations/decommission-studio76-server.sh. |
| Date | Item | Notes |
|---|---|---|
| 2026-04-30 | 🚚 Migração botjuridico + leadbot para Hetzner cloudvero (CPX31, Ashburn VA) | studio76-server era ponto único de falha (máquina única, dependente de Tailscale Funnel). Decidido aproveitar VM Hetzner já provisionada (24/04, originalmente para Vero Ethereum validator) que tem IP público fixo + nginx-grade infra. Setup completo (~2h30): provisionei Node.js 22 + uv + nginx + certbot, criei deploy key SSH (/home/egk/.ssh/github_studio76), clonei repo, configurei sudoers NOPASSWD para systemctl, abri UFW 80/443 (22 segue só via Tailscale eliegkfouri). Domínio: tentei usar remaxstudio76.net mas DNS é gerenciado pela WebVisão (não RegistraCom) com painel quebrado → optei por DuckDNS gratuito (studio76.duckdns.org → 178.156.155.123, atualizado a cada 5min via cron). Let's Encrypt cert obtido via certbot --nginx, expira 2026-07-29. DBs migrados via dual-tailnet hop (cloudvero está em eliegkfouri, studio76-server em egkhain — sem caminho direto): scp studio76-server→local /tmp→cloudvero. Migrados: bot.db 12MB (60 corretores), lead-bot.db 240KB, payments.db 24KB, fee_tracker.db 108KB. Webhook do Meta: 2 apps atualizados (Studio 76 Imobiliária 925782033618340 + Leadbot Studio76 27329438999991696), verify token studio76-webhook-secret-2026 mesmo de antes, ambos verificados pelo Meta às 03:21/03:22 UTC, mensagens reais já chegando às 03:23 (leadbot phone_number_id=1134727406386158). Auto-deploy preservado: cron 1min do auto_deploy.sh puxa do GitHub, rsync, npm ci, tsc, systemctl restart. Padrão git push continua exatamente igual. Audit semanal audit_cloudvero.sh (sábado 9h UTC, silent-on-success) verifica services ativos, errors graves >20/7d, restarts >30/7d, disco >80%, bot.db >500MB, auto_deploy errors, cert TLS <14d, health endpoint via 127.0.0.1 (NAT hairpinning), HTTPS externo via --resolve — alerta WhatsApp para Elie só quando algo está fora do padrão. Bugs encontrados/corrigidos no script: grep -c \|\| echo 0 produzia "0\n0" (helper count_safe normaliza), curl pra DNS público fail por NAT hairpinning (mudou pra localhost), dig no cloudvero faz timeout no systemd-resolved (substituído por curl --resolve). studio76-server: bots stopped+disabled (sudo systemctl), auto_deploy.sh removido do crontab para não tentar restartar. Memória: reference_arquitetura_maquinas.md reescrita refletindo cloudvero como prod dos bots, MEMORY.md atualizada. botjuridico.service versionado em whatsappbot/botjuridico.service (antes só existia leadbot/leadbot.service no repo). Webhook URL final: https://studio76.duckdns.org/webhook. Pendência crítica próxima sessão: 8+ crons financeiros/operacionais ainda no studio76-server (Estoque Vivo, NFS-e fallback, audit commission_splits, daily-report.js, sync-pipeimob-deals, Canal Pro session renew, monitor_suzana_faturamento, Pipeimob email watcher) leem bot.db LOCAL stale congelado em 30/04 02:30 UTC — migrar para cloudvero ou implementar sync DB hourly. Decisão pendente: Opção 1 (migrar todos crons, ~2-3h trabalho) vs Opção 3 (aceitar snapshot, reavaliar caso a caso). Após 1 semana estável → arquivar/decommissionar studio76-server. |
| 2026-04-25 | /cobrar — fix tag #parcela:N + consolidação de transfers no webhook + bug suppliers (commit 324a815) |
Trio de fixes pré-segunda 28/04 (quando o split do deal 1080-21 deve disparar via webhook pela 1ª vez em prod). Tag #parcela:N: parcela calculada em handleCobrarCommand era perdida ao passar pelo pendingPagadorSelection → processCobrarConfirmation lia (selection as any).parcela como undefined → fallback parcela=1 → invoice tag #parcela:1 mesmo nas parcelas 2 e 3 (visto no deal 1080-21). Fix: persistir parcela no pendingPagadorSelection + ler tipado em ambos os paths (single + n-way split) + também propagar totalCcvCents pro path n-way pra proporção correta. Consolidação de transfers (debounce 30s): quando invoice.credited dispara N transfers automáticos, rajada chega em segundos. Antes: N mensagens isoladas pra admins (deal com 7 splits = 7 msgs). Agora: cada TRANSFER_SUCCESS/FAILED reseta timer 30s por deal_code; ao estabilizar, sendConsolidatedTransferReport envia 1 mensagem com checklist ✅ OK / ❌ falha (motivo) / ⏳ pendente (esperado vs visto via match CPF/CNPJ + fallback nome). Destinatários: financialAdmins + corretor + group_jid. addEvent ganha error_message + tax_id no metadata pra suportar consolidador. Bug suppliers: tabela suppliers não existia em payments.db do servidor → lookupBankDataByCpf gerava 6 SqliteError stacks por /cobrar. Tabela criada vazia (schema do contas-a-pagar) — query agora retorna undefined graciously. Fix feito direto no DB do servidor, sem mexer em código TS. |
| 2026-04-25 | Stark Bank webhook — URL reapontada para Tailscale atual + cron de monitor split | Auditoria do fluxo de notificação PIX revelou que o webhook registrado no Stark Bank apontava pra hostname Tailscale antigo (studio76-server.rab2b6aa.ts.net) que não responde mais (curl HTTP 000). Atual é studio76-server.tail92b8aa.ts.net (HTTP 200, mesmo do webhook WhatsApp Meta). Webhook id=5025684196753408 deletado e recriado como id=4510224121397248 com mesmas subscriptions (invoice/split/transfer). Implicação: handler /webhook/starkbank (index.ts:12710-12986) — completo desde antes (notifica corretor+admins+grupo, grava INVOICE_PAID, dispara NFS-e reminders) — provavelmente nunca rodou em prod por causa do bug do hostname. Daí nunca termos visto o split automático funcionar end-to-end. Em paralelo: instalado cron /home/egk/scripts/monitor_split_1080_21.py (12h e 18h BRT segunda 28/04) como rede de proteção independente — checa invoice 5614137803800576 (Sandro/parcela 2/3) via Stark Bank API + journalctl, manda WhatsApp template alerta_sistema_studio76 + email pra eliekfouri@remax.com.br. Smoke test rodado: WhatsApp 200, Gmail msg 19dc76b4774f9526. Token gmail.send deployado em /home/egk/.credentials/token_gmail_elie_send.json. Cleanup do crontab pendente após confirmar pagamento (entradas anuais — vão re-disparar 28/04/2027 se não removidas). Memória project_monitor_split_webhook_1080_21.md adicionada. |
| 2026-04-25 | deal 601301080-21 — corrigido contador de parcela (2/3 em vez de 3/3) | Bot mostrou preview do /cobrar 1080-21 como "Parcela 3 de 3" hoje 18:48 (PIX gerado pra Sandro Pionkowski R$ 26.250,00, invoice 5614137803800576) quando deveria ser parcela 2. Causa: deal_events tinha 2 INVOICE_CREATED (#59 às 01:22 referenciando invoice cancelada 4559464594407424; #60 às 18:48 referenciando invoice ativo 5614137803800576). Fórmula parcela = COUNT(INVOICE_CREATED) + off_bot_parcelas + 1 deu 1+1+1=3. Fix: deletado evento #59 (referência cancelada não conta) + atualizada description do #60 explicando contexto. Stark Bank invoice tag #parcela:1 (errado nas duas) NÃO foi alterado a pedido do usuário — bug separado do /cobrar que escreve número errado no tag. Próxima /cobrar 1080-21 agora computa corretamente parcela 3 (final). |
| 2026-04-25 | /cobrar — 3 fixes integrados (commit dc58545) |
Sessão completa testando /cobrar 1079-12 end-to-end no studio76-server via webhook simulado. (a) Drive duplicatas: deal 1079-12 tinha 3 pastas VENDA - 1079-12 no shared drive Pós-vendas (uma cheia, duas vazias criadas em runs antigos do ensureDealFolder com formato de nome diferente). findDealFolderByCode antigo pegava files[0] arbitrário e caía na vazia. Fix: nova findDealFoldersByCode plural; ensureCCVExtractedNow itera todas as pastas legacy. (b) Extractor enriquecido: prompt Haiku do extractComissaoFromCCV agora cospe imovel{endereco_completo, logradouro, numero, complemento, bairro, cidade, uf, cep} + valor_imovel (cláusula 1 do CCV). Persiste em deal_property + deal_values.property_value. PDF com prefixo Clicksign- é tratado como assinado → state avança pra COMPLETE automaticamente. Antes o preview mostrava "Endereço não cadastrado / R$ 0 / CCV: Pendente" mesmo com tudo no contrato. (c) UX pagador interativa: 2 candidatos vira 3 botões (pagador_1, pagador_2, pagador_split_1+2); 3-10 candidatos vira lista interativa com seções "Pagador único" + "Divisão igual"; 11+ texto puro. Separador + mais natural ("1+2" lê como "Ana mais André"); parser aceita , retrocompat. Helper shortPersonName encurta "ANA CECILIA DE AZEVEDO" → "Ana Cecilia" pra caber no limite 20 chars. Click no botão sintetiza userText e reusa parser textual. Validado: bot acha CCV na 3ª pasta, extrai R$54k/6%, popula state=COMPLETE+endereço+valor R$900k, mostra preview correto, click "Ambos 50/50" registra PAGADOR_SPLIT. Memória feedback_drive_duplicatas_pasta_deal.md adicionada. Bug separado encontrado nos logs (não-bloqueante): data-capture.service.ts:227 lookupBankDataByCpf — no such table: suppliers (6 stacks ruidosas durante registerDealSplits). |
| 2026-04-24 | Assertiva — credenciais conectadas em produção | ASSERTIVA_API_ID/SECRET/_BASE adicionados ao /home/egk/whatsappbot/.env do studio76-server (login Samuel: samuelchen@remax.com.br). OAuth2 client_credentials testado: token bearer retornado, scope: ALL, expires_in: 1799s. Backup .env.bak.20260424-231006 salvo. Bot reiniciado via sudo systemctl restart botjuridico — ativo. Bot é lazy: token só será obtido na primeira chamada /dd ou /captacao. Memória: reference_assertiva.md (idFinalidade LGPD: 1=DD, 5=captação; cache 30d em assertiva_lookups). Pendência derivada: conectar Assertiva ao Pipeimob para auto-preencher dados de vendedor/comprador nos deals. |
| 2026-04-18 | /dd Assertiva A+B — Enriquecimento + CNPJs vinculados |
Migration v29 (deal_parties.nome_mae/situacao_cpf/empresas_vinculadas/assertiva_enriched_at) aplicada em produção. AssertivaPessoa.empresasVinculadas extraído dos campos participacoes/empresas/vinculosEmpresariais do payload Localize. Novo lookupEmpresasVinculadasByCpf() com fallback gracioso (endpoint dedicado → CPF padrão). /dd agora SEMPRE chama lookupPessoaByCpf quando CPF resolvido e persiste via COALESCE. CNPJs vinculados são anexados ao parties[] mid-loop, certidões PJ (Plexi) rodam automaticamente; corretor recebe notificação "🏢 X aparece como sócio de N empresa(s)". 57/57 testes verdes, build limpo, v29 confirmada nos logs. |
| 2026-04-18 | Estoque Vivo Sprint 2 — Fase 2 (Validade) + Fase 3 (Preço) + Mensagem Final | StatusWizardService expandida com 5 novos steps (40/41/50/51/52) e 10 novos botões. Fase 2: detecta contrato vencido/≤30d via override ou cache iList, oferece [+6m] [+12m] [Não] e em "Não" oferece [Convencional] [Retirar]; renovação chama updateListingDataValidade no iList. Fase 3: 2 telas (Conversou? → Autorização?), grava resposta na fase=3 com SEM_CONTATO/MANTER/NÃO_AUTORIZOU/PODE_REDUZIR_até_X%. Mensagem de fechamento agora consolida resumo por imóvel + "Tudo gravado no iList — não precisa abrir o sistema" (princípio fix-in-chat). 31/31 testes verdes. Deploy via rsync + tsc clean local + servidor. Demo validado no WA do Elie (ciclos 4 e anteriores). Falta apenas Fase 4 (bump). |
| 2026-04-17 | Estoque Vivo Sprint 1 — Fase 1 (Status) + Cron + Supervisor Alerts em Produção | Migration v28 (estoque_vivo_ciclos\|respostas\|eventos). EstoqueVivoUpdater (ownership por agent_code + whitelist 3 campos). StatusWizardService W1.1/W1.2/W1.3 (Ativo/Vendido/Retirado + sub-flows). EstoqueVivoCampaignRunner + CLI estoque-vivo-campaign.ts. AutoInativacaoService + botão evreativar_*. SupervisorAlertsService 4 alertas/semana (seg 08h, qua 10h, sex 17h, dom 23h59) pra Carine + Roberto. Crons instalados via install-estoque-vivo-crons.sh no studio76-server (egk user, sem sudo). ESTOQUE_VIVO_SUPERVISOR_NUMBERS no .env. Template HSM estoque_vivo_confirmacao_semanal aprovado pela Meta. Cron semanal de Fase 1 ainda inativo (aguardando piloto). |
| 2026-04-15 | iList Auto-Refresh + Price Bump + Full Sync Pipeline | refresh_ilist_cache.py — API-based cache refresh (221/221 items, substituiu CSVexport). price_bump.py — rotação quinzenal +R$100 venda/+R$10 locação. run-full-sync.sh — pipeline completo 6am (cache→enrich→gen→cnm→restart→validate). Commits 115d07d + 42f0edc. |
| 2026-04-15 | CnM Feed Deploy + Live na Plataforma | CnM XML regenerado (221 imóveis, 2.044KB, 30 destaques). Painel CnM confirma: 232 Ativos, 30 Destaques. Tailscale Funnel reativado como público (estava "tailnet only"). CnM consumindo feed com sucesso. |
| 2026-04-15 | WhatsApp Monitoring 24/7 via Templates | Migrou TODOS os scripts de notificação WA para template alerta_sync_canal_pro + text fallback (funciona fora da janela 24h). Scripts atualizados: run-full-sync.sh, onr_monitor.py, check-restarts.sh, monitor_suzana_faturamento.py. Token dinâmico via .env. Template genérico alerta_sistema_studio76 criado (pendente aprovação Meta). Commits d7d8ba4 + 70fc0a1. |
| 2026-04-10 | Multi-Bank Smart Reconciliation | smart_reconcile.py extended for 3 sources: Bradesco OFX, Stark Bank JSON (SDK), Pipeimob JSON (Playwright scraper). Claude AI matches bank txns ↔ Granatum lançamentos, classifies categories/cost centers from historical patterns. New scripts: pipeimob_statement.py (headless Bubble.io scraper, login+PIN+extract), starkbank_statement.py (SDK, 5 data types). Fix: fetch_suppliers() infinite loop (Granatum /clientes ignores pagination). Tested e2e on server: Pipeimob (8 txns, 1 match R$9.480) + Stark Bank (47 txns, 3 matches). ~$0.04/run. Commit a28f368. |
| 2026-04-10 | Chaves na Mão — XML Feed Generator | Replicou estratégia Canal Pro para CnM. cnm_generator.py (221 imóveis, 2.044KB XML), cnm_mappings.py (20 tipos, 70+ features→áreas), server.py atualizado com /feed/chavesnamao.xml + cache + status + regenerate. 30/30 destaques alocados (antes: 0/30 no iConnect — oportunidade enorme!). Feed URL: https://studio76-server.tail92b8aa.ts.net/feed/chavesnamao.xml. Deploy concluído 2026-04-15 — CnM consumindo feed com sucesso. |
| 2026-04-09 | Canal Pro FASE 3 — Smart Destaque Rotation | destaque.py: SQLite rotation engine with scoring (base+quality+rotation), manual pins, CLI + 6 API endpoints (/destaque, /destaque/stats, /destaque/history/<id>, /destaque/pins, pin/unpin). First run: 4 PREMIERE_1 + 31 PREMIUM. Commit a33aa9c. |
| 2026-04-09 | Canal Pro FASE 2 — Features & Rich Descriptions | 194/230 listings with <Features> tags, 2,447 total feature tags (avg 12.6/listing). 150+ PT→EN feature mappings. Rich descriptions with parking, fees, floor, diferenciais. XML 442KB→1.9MB (+329%). Commits 0c463ca + bc43dc8. |
| 2026-04-10 | Canal Pro Auto-2FA + Integration Fix | canal_pro_auto_login.py: Playwright + Gmail API auto-2FA (código extraído em <1s). Reconfigurou URL integração (vrsync.xml) após remoção iList por Samuel (email Apr 9). Import agendado 23:40. Email: eliekfouri@remax.com.br recebe relatório. |
| 2026-04-10 | Canal Pro Server Deploy + CEO Report | (1) Auto-login script deployed to server (/home/egk/canal-pro-feed/), Gmail OAuth credentials copied, flexible token path. (2) Weekly cron: 45 5 * * 1 session renewal. (3) CEO visual PDF 8 pages: antes/depois 3 imóveis, KPIs, sem dados técnicos. (4) canal-pro-feed/CLAUDE.md criado com contexto completo das 5 fases. |
| 2026-04-10 | NFS-e Planilhas Overhaul | (1) Fix filtro Studio76+Suzana: normalização tipos (text→number/date), re-sort Z-A por NF, basicFilter auto-expand. (2) Tributos Estimados: fórmulas $B$10→$B$2 (full range), rolling 12 meses dinâmico. Mar/2026 saltou R$204k→R$222k (NFs antes excluídas). (3) Nova aba "Tributos Estimados" Suzana (Anexo V, RBT12 R$565k). (4) DAS→Granatum sync (Abr R$31.051, Mai R$6.920). (5) append_to_sheets corrigido: NF como int, valor como float, re-sort após insert. (6) Cron diário 7:45 nfse_daily_sheets_sync.py |
| 2026-04-10 | NF Suzana 408→409 corrigida | NF 408 cancelada (tomador errado RODRIGO=comprador). NF 409 emitida com MARCUS VINICIUS (vendedor). Causa raiz: pagador_nome PIX usado como tomador. Fix: verify_tomador_consistency() em nfse_auto.py bloqueia divergência CPF/nome entre prestadores do mesmo deal. Skill /emitir-nfe + memória atualizados. |
| 2026-04-10 | Comando /nf no bot | Corretores pedem PDF da NF via /nf [deal]. Lista NFs do corretor ou busca por deal code. Download PDF local→Prefeitura mTLS. Envio WhatsApp documento. ACL: nivel corretor. |
| 2026-04-09 | NFS-e Full Automation | 6 componentes: nfse_auto.py (core), webhook invoice.created, Pipeimob email watcher, nfse_notifications (WA+email), cron fallback, SQLite nfse_emissions. 3 triggers: Stark Bank webhook + Pipeimob Celcoin Gmail + cron diario. Ref: starkbank-mcp/NFSE-AUTOMATION.md |
| 2026-04-09 | NF 860 emitida | Deal 601301090-3, MARIA HELENA VILELA TONELLI, R$ 18.000, cod B4UJJQVA. PDF enviado Samuel via email+WhatsApp |
| 2026-04-08 | Full Repo Audit | UX 5.5/10, Proactivity 6.5/10, Production 7/10. KANBAN restructured. |
| 2026-04-07 | PIX Collection Flow in /cobrar | DictKey resolution, split receiver activation, multi-pagador invoices (commit b32ac74) |
| 2026-04-07 | Deadline Monitoring System MVP | Timeline CRUD + scheduler + extraction |
| 2026-04-07 | Central de Atendimento / Intent Router | IntentClassifierService (Haiku), 26 intents, command routing |
| 2026-04-07 | iList Integration (Puppeteer) | IlistService (Puppeteer + CSV cache), /ilist, /proposta pre-fill, auto-sync-ilist.js cron |
| 2026-04-05 | Docker Removal | Simplified bot deployment |
| 2026-04-03 | StarkBank PIX by DICT Key | + Gmail send fix |
| 2026-04-01 | NFS-e Suzana Lee | Emission + tracking spreadsheet |
| Date | Item | Notes |
|---|---|---|
| 2026-03-01 | Granatum MCP Server | 19 tools, production |
| 2026-03-08 | StarkBank MCP Server | PIX/TED/boleto payments |
| 2026-03-10 | Pipeimob MCP Server | 12 tools, CRM data |
| 2026-03-12 | Google Drive MCP Server | Document access |
| 2026-03-15 | AP Automation Phase 1 | MCP server + 4 parsers + 6 tools |
| 2026-03-20 | Pipeimob API Discovery | API functional, endpoints documented |
| 2026-03-22 | ACL Role-Based Access | Manager vs corretor permissions |
| 2026-03-23 | LGPD Privacy Policy | /privacy endpoint |
| 2026-03-26 | /reportar Command | Commission report with PipeCash |
| 2026-03-28 | CPF/CNPJ Validation | Checksum on /cobrar input |
| 2026-03-29 | OCR Phase 1 | Accept images without active deal |
| 2026-03-30 | Drive CCV Auto-Scan | Auto-scan Drive for contracts |
When someone requests a feature, add it here first. Do NOT start working on it.
Review during morning check and assign priority.
| Date | Requester | Request | Priority | Decision |
| 2026-07-09 | Achado (sessão raio-x Karina) | Restaurar cron do reconcile_boosts.py. Uma memória de 17/06 documenta cron diário 12:30 UTC (--execute --prune), mas o crontab -l do cloudvero não tem essa entrada hoje — a reconciliação em lote (Google+Meta real vs tabela impulsionamentos) não roda mais sozinha, só o /raiox on-demand ficou coberto pelo fix desta sessão (check_boost_live.py, commit c99af0b). Sem o cron, imóveis impulsionados/pausados por fora do bot (Ads Manager, script manual) ficam com a tabela desatualizada até alguém rodar manual ou abrir o /raiox daquele código específico. | P2 | ✅ RESOLVIDO 10/07 — causa raiz: reinstalação de crontab de 04/07 com mirror stale apagou o cron (junto com ~35 outros). Restaurado (30 12 * * *, --execute --prune --reap --refill) e mirror corrigido no commit f69f04b. Ver reference_crontab_wipe_crons_ads_jul2026. |
| 2026-07-08 | Elie | NFS-e onde a Studio76 é TOMADORA deve virar conta a pagar automaticamente. Caso 08/07: Elie encaminhou a NF da Dra. Renata (assessoria jurídica, R$6.000) ao bot SEM legenda → caiu no analisador de documento/scanner de NFS-e (só respondeu "NF já registrada" — tratou como nota recebida), NÃO no fluxo de AP (whatsapp-pdf-ap.handler, que só dispara com legenda pagar/conta/boleto). Resultado: não virou payable, Elie teve que pedir manualmente. Gap: uma NFS-e cujo TOMADOR é a Studio76 (CNPJ 31.317.062/0001-55) é, por definição, uma despesa a pagar → deveria criar payable (supplier=prestador, valor da NF, PIX se conhecido) e cair no /contas, mesmo sem legenda. Ponteiros: scanner NFS-e recebida (nfse-recebida-scanner.ts/handler de doc) precisa, quando tomador.cnpj == Studio76, rotear pro AP em vez de só registrar. Payable #257 criado à mão nesta sessão como contorno. | P2 | ⏳ Intake — não iniciado. |
| 2026-07-08 | Elie | Bot arquiva os PDFs do Jurídico no Google Drive p/ consulta futura. Quando um documento jurídico chega ao bot (NF da assessoria, relatório mensal da RR, parecer, CCV), salvar o PDF numa pasta Jurídico do Drive organizada por deal/mês. Gancho com 2 coisas já em jogo: (1) o AP handler já sobe PDF de conta pro Drive via ap-drive.service.ts/uploadApPdf (pasta AP) — falta uma pasta/rota Jurídico específica; (2) o Monitor Jurídico (juridico/monitoramento-juridico/) precisa do relatório mensal da RR em /home/egk/juridico-relatorios/relatorio-<mês>.pdf — se o bot arquivar o relatório da RR no Drive+path ao recebê-lo, o cron do monitor pega sozinho (fecha a ingestão automática, hoje manual). Ponteiros: whatsappbot/src/erp/handlers/whatsapp-pdf-ap.handler.ts (recebe o PDF), DriveService, pastas Drive VENDA-{código}/DD-DILIGENCIA (padrão da DD). | P2 | ⏳ Intake — não iniciado. Reuso alto (AP→Drive já existe). Decidir taxonomia de pastas (por deal? por mês? "Assessoria RR"?) e o gatilho de classificação (o doc é jurídico?). |
| 2026-07-07 | Ana Galante (via Elie) | Overspamming de mensagens ao corretor (leadbot + whatsappbot). Reclamação recorrente — Ana Galante: "esse monte de informação que a gente acaba se perdendo… é lead toda hora, mensagem de bot… está difícil". Diagnóstico feito nesta sessão (2 agentes mapearam TODO outbound proativo ao corretor): a causa raiz é estrutural — não existe nenhuma camada por corretor que agregue/limite/silencie; cada cron/evento dispara sozinho. O padrão digest (notifyAdmins, 8h/18h) existe só para admins. 3 maiores ofensores: (1) Ofertas do bolsão (leadbot, impulsionamento.flow.ts:854) — broadcast simultâneo a ~33 corretores por lead; o carrossel 1ª-clica só remove quem GANHOU, quem só recebe e não clica leva TODO lead, sem teto diário de recebimento. (2) Briefing matinal "Bom dia, {nome}" (whatsappbot, engagement.service.ts:1201, setInterval 8h) — único que bate em 100% da base todo dia, incondicional (manda o bloco inteiro mesmo sem nada pendente), sem quiet-hours nem frequência (só mute total). (3) Cluster 8h–10h — briefing (8h) + fee-dispatch/CR-watchdog (9h) + fee-overdue/DD-pendências/sentinela-minisite/survey-atribuição (10h) = 6+ disparos distintos em 2h, cada um cego pros outros. Anexo: trilha de feedback do lead ("Como foi?" 3h após ganhar + re-perguntas 24h×2 + quente a cada 2d) escala com quem mais VENCE lead. Já mitigado (não é mais o problema): "lead já foi pego por outro" (era 41% do volume histórico) removido em 04/07. Inertes hoje (código existe, sem cron): Estoque Vivo semanal + watchdog de parcela. Freios que já existem: teto de re-asks, janelas de feedback, cooldown fee 3d/DD 7d, cap cliente-nudge 5. Buraco = nenhum teto/agregação no eixo "corretor". 3 abordagens desenhadas p/ decidir: (a) camada unificada quiet-hours + teto diário por corretor + colapsar cluster num digest; (b) cortes cirúrgicos nos 3 ofensores (teto/auto-pausa no bolsão + briefing condicional + reagendar cluster); (c) self-service /silenciar//frequencia + modo foco. | P1 | ✅ WHATSAPPBOT FEITO 07/07 (deploy f9a4d9f, migration v144, gates 32/32). (1) Briefing "Bom dia" → comando /frequencia (aliases /frequência,/silenciar): corretor escolhe diário/semanal(só seg)/só-urgente/pausar; engagement_preferences.briefing_mode, gate em sendCorretorDigests; default diario preserva comportamento. (2) Desk-fee consolidado (cron-fee-overdue.ts): 1 msg por corretor com total acumulado; crônico 3+ meses = 1 lembrete/30d, recente 1-2m = 3d; reusa HSM desk_fee_vencido. Descoberta-chave: leadbot e whatsappbot são números WhatsApp diferentes → briefing NÃO afeta velocidade de lead. LEADBOT intocado por decisão do Elie (leads são o produto — corretor quer lead). Pendências: ✅ (a) discoverability FEITA (3aaadad: /frequencia no /ajuda — menu principal "💳 Meus dados" + submenu cobrança; sem blast); ✅ (b) smoke UX real FEITO 07/07 (webhook local, número do Elie): lista interativa entregue+lida, clique freq_diario gravou engagement_preferences.briefing_mode + confirmação. Item overspamming COMPLETO no whatsappbot. |
| 2026-07-02 | Elie | Como cobrar/receber a fração Studio76 em parcerias de Boost com outras franquias RE/MAX. Com o impulsionamento do Boost de parceiros crescendo, vai aumentar o volume de negócios em que a Studio76 entra como co-corretora (fora da carteira própria, sem deal_code 60130). Hoje o único caso observado (Rua Visconde de Ourem 204, RE/MAX AIR, 22/05/2026, R$7.080 de fração Studio76) chegou via PIX split direto do Pipeimob — mas Elie não sabe se isso vai ser a regra: "não sabemos como cada parceiro vai pagar nossa parte, alguns pelo pipe outros por pix, talvez podemos gerar um pix cobrança para o parceiro ou para o próprio vendedor". A tabela partner_deal_plans existente (whatsappbot/src/services/partner-capture.service.ts + src/erp/scripts/conciliacao.ts) só cobre o caso "aguarda depósito no Bradesco" (CCV de parceria OCR → Receivable PENDING → concilia com TED/PIX recebido → dispara NF/recibo automaticamente) — não cobre "já recebemos via Pipeimob" nem "vamos gerar cobrança PIX pro parceiro/vendedor". Registrei o negócio de 22/05 manualmente em partner_deal_plans com status recebido_pipeimob (fora do alcance do cron matchPartnerPendingDeposits, que só olha status='aguardando_deposito' — não dispara NF/recibo automático, é só registro). Decisão pendente do Elie: definir o(s) mecanismo(s) de cobrança pra fração Studio76 em parceria (Pipeimob / PIX cobrança pro parceiro / PIX cobrança pro vendedor) antes de desenhar a automação de captura+NF pra esse fluxo. | P2 | ⏳ Intake — não iniciado, decisão de produto pendente com Elie antes de codar. |
| 2026-06-29 | Elie | Carrossel Coletivo / "Vitrine do Time" — pool de cotização de mídia pra corretores com pouca verba/conhecimento. Resolve 2 gargalos: (1) verba individual baixa demais pra entregar bem; (2) corretor não sabe mexer no Gerenciador Meta. Ideia: enquete por DM (HSM) captura opt-in + verba semanal + duração; o sistema monta sozinho carrosséis CTWA coletivos segmentados por faixa de preço (ISCA/VENDE/ALTO), onde cada corretor entra com card(s) do(s) seu(s) imóvel(is), reaproveitando o motor do /impulsionar-privado. Verba do ad set = soma das contribuições da faixa. Decisões travadas (Elie 29/06): rateio por nº de cards/slots (paga mais = mais cards, cap suave 4–5 só p/ diversidade); cobrança semanal recorrente; piloto = broadcast pra todos os ativos; slot R$10/card/dia, piso R$50–100/dia. 🔑 SEM segmentar por faixa — UM ad set coletivo único (aritmética: piso R$50–100/dia = 5–10 cards = um carrossel cheio; quebrar em 3 faixas re-fragmenta a verba e prende cada ad set em "learning limited"; o carrossel já segmenta card-a-card sozinho; raio resolvido com ~6–8km único). Targeting MANUAL no lançamento (regime small-budget hiper-local <~R$150/dia → consenso recomenda detailed/manual; conclusão do Bruno certa por ESCALA de verba, não por raio — local é controle duro no Advantage+ Audience e nunca é expandido). Audience Network sempre excluído. Otimizar pro evento QUALIFICADO do CAPI (value 10), não conversa crua. Broad/Advantage+ Audience = A/B futuro quando pote ≥~R$150/dia, métrica = custo/conversa qualificada. Faixa = evolução futura só quando uma faixa tiver pote próprio ≥ piso. Lead roteia exclusivo pro dono do card clicado (Tier1). Plano detalhado: meta-ads/PLANO-CARROSSEL-COLETIVO.md. | P2 | ⏳ Intake — não iniciado. ~80% é reuso. Reusa: expand_terceiros_ctwa.py/add_card_ctwa.py (carrossel multi-imóvel, agora ad set único), create_priv_carousel.py (overlay, targeting manual), team-ad-wallet.service.ts (PIX+webhook+crédito, re-chavear coletivo+semana), locacao_optin v24 + locacao-optin-broadcast.ts (enquete DM), resolver por-card ctwa-ad-map.ts, cadastro_quality.py+curate_photos.py+angle_ai.py. Novo: enquete 3-campos (migration + HSM), cohort builder (cron semanal), pool wallet pote único/semana, roteamento por-card→agent_code→Tier1 pra estoque próprio 60130, piso mínimo de pote. Fases F1 enquete → F2 cohort+wallet → F3 roteamento → F4 placar /meu-coletivo. Parâmetros já fechados (slot R$10/dia, piso R$50–100/dia, cap suave 4–5). ✅ F1 DEPLOYADA (b9ca740, 29/06): migration v28 coletivo_optin + handler wizard (/coletivo, botões coopt_*) + broadcast (coletivo-optin-broadcast.ts) + HSM submetido (corretor_coletivo_optin, ID 1672300830742318, PENDING aprovação Meta). build leadbot verde. Gate revisto (e091585, 29/06): peneira SAIU do Coletivo (era régua de gasto da empresa, abaixo-do-mercado, cobria só 42/220). Novo build_coletivo_inventory.py (Step 1.86 do run-full-sync) gera coletivo-inventory.json = todo próprio ANUNCIÁVEL (venda+≥100k+CR+cadastro_quality); demanda só ordena. Validado: 119 anunciáveis / 32 corretores (drop 77 CR-vencido, 12 qualidade, 12 tipo/preço); convite subiu de 19→26 ativos. ⚠️ 77 imóveis próprios com CR vencido — oportunidade de higiene (Estoque Vivo/renovação). Broadcast disparado (29/06): 2 HSMs aos 26 (corretor_coletivo_optin + corretor_coletivo_reforco, este liderando com lead exclusivo Tier1). F2 §8 travado (Elie): piso R$50/dia, estorno se não bater, abertura domingo, cap 4, múltiplos carrosséis. F2.1 EM PRODUÇÃO (6b4aab8): migration v139 coletivo_* + coletivo-wallet.service.ts (openWeeklyRound + crédito idempotente + piso→funded) + webhook #tipo:coletivo — dormente até F2.2. Próximo: F2.2 cohort builder (cron domingo, lê coletivo_optin do lead-bot.db + inventário → openWeeklyRound) → F2.3 ad set coletivo + mapa card→dono → F2.4 ativação/notificação → F3 roteamento Tier1 sem limite. Plano detalhado: meta-ads/PLANO-CARROSSEL-COLETIVO-F2.md. |
| 2026-06-25 | Elie | /impulsionar deve auto-ativar a campanha (ou avisar "falta ativar"). Caso real 25/06: Elie subiu o boost do 1100-1 (Angela) via /impulsionar; o ad e o ad set (Proprio_Corretor, R$10/dia, placement auto incl. Instagram) ficaram configured=ACTIVE, mas a campanha-pai Corretor_OnDemand_2026_CTWA (id 120252418544200110) ficou PAUSED → nada entregava no IG/FB até alguém ligar na mão no Ads Manager. Ativei manualmente via Graph API (campanha→ACTIVE, cascateou). Proposta: ao final do /impulsionar (próprio), garantir a campanha-pai ACTIVE — ou, se a trilha Corretor é mantida pausada por design (memória project_impulsionamento_privado_gateway cita "trilha Corretor PAUSED"), pelo menos o bot avisar o corretor "⚠️ boost criado, falta ativar a campanha" + botão de ativar, em vez de silenciosamente não entregar. | P2 | ⏳ Intake — não iniciado. Ponteiros: whatsappbot/src/handlers/impulsionar.handler.ts:137 chama boost_listing.py {code} --execute --authorize (google-ads dir) que monta Google + Meta CTWA; o lado Meta insere o ad no ad set Proprio_Corretor da campanha Corretor_OnDemand_2026_CTWA mas não ativa a campanha. reconcile_boosts.py (cron diário, reaper/refill) bate na API mas não trata ativação. Decidir: (a) auto-ativar campanha no fim do fluxo, ou (b) manter pausada + avisar/botão. Confirmar com Elie se a trilha Corretor deve sair de "PAUSED by design". |
| 2026-06-25 | Elie | Modo conversacional para /nf + comprovante de depósito de comissão no bot. Hoje /nf sem args lista as NFS-e (✅ agora com nome do tomador, commit desta sessão) e /nf {deal} envia o PDF — mas exige saber/digitar o código. Elie quer que o corretor interaja conversacionalmente: bot lista as NFs do corretor com botões/lista interativa (toca na NF → recebe o PDF), no espírito fix-in-chat (CLAUDE.md). Segunda parte: trazer o comprovante de depósito da comissão (PDF do transfer/PIX da Stark que pagou o split do corretor) para o bot, também conversacional — corretor pede/recebe a prova de que a comissão dele caiu, via botões. | P2 | ⏳ Intake — não iniciado. Ponteiros: /nf = handleNfCommand (whatsappbot/src/index.ts:19026), lê tabela nfse_emissions (campos deal_code/prestador/nfse_numero/valor/tomador_nome/status); PDFs em /home/egk/studio76/nf emitida/pdf/NFSe_{inscricao}_{numero}.pdf (cloudvero) + dir do bot whatsappbot/data/nfse-pdfs/; download Prefeitura via download_nfse_pdf (nfse_auto.py, mTLS notaprintpdf.aspx). Comprovante de comissão: transfer Stark do fan-out (webhook.py dispatch via transfer_by_pix_key) — PDF via get_transfer_pdf (MCP starkbank) / getTransferPdf; cruzar split→transfer pela tabela de splits/ledger no bot.db. Reusar WizardManager (migração v23) + sendButtonMessage/lista interativa (padrão dos outros wizards) p/ a UX. Avaliar unificar num só comando ("minhas comissões/notas") com botões NF + comprovante por deal. |
| 2026-06-22 | Elie | Auditar nossos modelos de documento vs os padrões OFICIAIS RE/MAX (packs do REMAX HUB) e adequar. Ver se nossos CRE/CR, ACM, dossiê, ficha técnica, assinaturas de email, papelaria, apresentações estão conforme o padrão RE/MAX. | P2 (fazer outro dia) | ⏳ Caminho TRILHADO 22/06 — é só sentar e comparar. PADRÕES RE/MAX descompactados em /home/egk/studio76/remax-padroes/rem.ax-gelm_packsbasicos/ (gitignored, ~7GB; índice na memória reference_remax_padroes_material): PACK CORRETOR REMAX/CRE - Contrato de Representação Exclusiva/{PF,PJ}/*_Contrato de Representacao Imobiliaria_CRE.pdf · .../ACM/Análise Comparativa de Mercado.pdf (+ LINK CANVA) · .../Dossiê do Corretor · .../Dossiê do imóvel · .../Ficha técnica do imóvel · PACK IMOBILIÁRIA REMAX/{Assinaturas de Email, Papelaria, Cartão de Visita, Crachá, Templates para apresentações, Placas vende_aluga} · BRANDGUIDE/ (cores #0043FF/#FF1200, Montserrat). NOSSOS modelos a comparar (caminhos): CRE/CR → whatsappbot/public/cr-template-sem-testemunhas.docx + whatsappbot/public/cr-capa.pdf + financial-services/contrato de representação remax modelo clicksign...docx; fluxo em operations/PLANO-CAPTACAO-EXECUTIVO.md e operations/handoff-captacao-cr-whatsapp.md. ACM → whatsappbot/src/handlers/avaliar.handler.ts + motor ACM/ (planos em ACM/PLANO-*.md). Dossiê → whatsappbot/src/handlers/dossie.handler.ts + canal-pro-feed/dossie_proprietario.py (exemplo de saída: operations/dossies-proprietario/dossie-601301022-72.pdf). CCV/termos/pareceres → juridico/contratos/{templates,termos} + gerar_*_pdf.py. A FAZER: ler cada PDF RE/MAX × nosso modelo → listar gaps (cláusulas obrigatórias, campos, layout/marca) → adequar (texto + identidade visual já alinhada no minisite). Começar pelo CRE (mais sensível juridicamente) ou pela ACM. |
| 2026-06-19 | Elie | Parcerias internas (Corretor Secundário do iList) → ACL + minisite do parceiro. A maioria dos corretores Studio76 trabalha em parceria interna; a parceria é declarada no iList em "Principal → Representação e Parceria → Corretor Secundário" (ex.: imóvel mostra Roberto Mourao Veiga como secundário; há também "Corretor Representante"). (1) Cadastrar no bot.db, RETROATIVO e só dos imóveis 60130 ATIVOS, a parceria interna de cada imóvel (extraindo do iList). (2) Dar ao corretor PARCEIRO paridade total de ACL com o dono: todos os comandos de corretor habilitados pra ambos (/raiox, /dd, /cobrar, /impulsionar, /cliente, /dossie, /avaliar, etc. — sem exceção, confirmado Elie 19/06) + o imóvel do dono aparece também no minisite do parceiro. | P1 | ⏳ Em planejamento 19/06 (2 explorações: extração iList do corretor secundário + mapa de ownership/ACL dos comandos). Decisões Elie 19/06: paridade TOTAL (inclui /cobrar comissão e /impulsionar verba — logar quem disparou: dono vs parceiro). Linchpins a confirmar: (a) a API do iList expõe o Corretor Secundário/Representante? (b) o campo traz NOME (não agent_code) → precisa lookup nome→agent_code na tabela corretores. ✅ ENTREGUE 19/06 (merges 4de5f0a+dd4b1dc). Linchpin confirmado: GetListingPageViewModel → result.listing.listings retorna secondaryAgentID/representingAgentID como 60130NNNN → agent_code direto, sem fuzzy. Entregue: migration v128 listing_partnerships; sync_partnerships.py (→listing-partnerships.json; cron diário 10:00 UTC; bot re-sync 6h+boot, anti-wipe); listing-partnership.service (canAccessListing=dono OU parceiro); ownership refatorado em /raiox /dd /dossie /impulsionar /cobrar; minisite do parceiro inclui o imóvel do dono com o contato do parceiro+detalhe escopado. Retroativo: 125 parcerias ativas (110 secundário+18 representante; 3 puladas). Smoke OK: 601301002-139 (dono 1002) no minisite da Alessandra (1087) com header dela. Parceiro fora do 60130 ignorado p/ ACL. Memória reference_parcerias_internas_ilist. |
| 2026-06-19 | Elie | Minisite do CLIENTE comprador — vitrine viva e curada por cliente (subpágina do corretor), abastecida automaticamente pelo motor FV/ACM. Inverte o minisite atual (centrado no imóvel /c/{corretor}/{imovel}) para centrado no comprador (/c/{corretor}/cliente/{cliente}): o corretor pega um lead de comprador (que já sabemos o que procura, onde e quanto), e em vez de caçar imóvel a imóvel no WhatsApp (dor do print Fábio Bernardes ↔ Luciana Kfouri), o cliente ganha uma página que se atualiza sozinha com os imóveis mais aderentes da RE/MAX (independe da agência do imóvel) + ranqueados por similaridade e valor justo. Caso-semente: Fábio veio do Panamby 601301089-18 (Luciana 1089). | P2 | ⏳ Plano desenhado 19/06 (3 explorações: minisite, motor FV/ACM, lead/visita). Reaproveita ~80%: minisite Express (whatsappbot/src/minisite/), buyer_demands (já modela a procura do comprador no leadbot), find_comparables() (ACM/src/acm_ilist_comps.py — Haversine+edifício/rua/bairro+área±20%+dorm), PropertyStore.search() (canal-pro-feed/property_store.py), fair_value() (ACM/src/valuation/fair_value.py). Decisões Elie 19/06: (1) Escopo estoque = Próprio (60130) + Rede RE/MAX Boost — exclui NonStop fora-da-rede (mais seguro em compliance/marca); (2) Perfil de busca = auto do imóvel-semente + ajuste por botões (infere do imóvel que originou o lead, reusa buyer_demand, corretor refina no WhatsApp); (3) Agendamento de visita = FASE 2 (não nesta 1ª entrega); (4) URL = slug ofuscado nome+token (/c/luciana-kfouri/cliente/fabio-b-a7f3) + noindex. Arquitetura (ponte Node↔Python, padrão fair-value-cache.json): cron Python match_buyer.py gera buyer-matches-cache.json por cliente → minisite Node lê e renderiza (reusa mapListing/renderList). Faseamento proposto: F1 = geração da página + matching automático (read-only, sem visita); F2 = botão "Quero visitar" → tabela visitas + ping ao corretor dono com botões; F3 (futuro) = relay automático corretor↔parceiro. ✅ F1 ENTREGUE 19/06 (merge 85a329c, pushed → auto_deploy). Migration v126 clientes_compradores; serviços cliente-comprador.service (CRUD+token ofuscado) e cliente-match.service (motor próprio+Boost, matching NO RENDER — sem cron, vitrine sempre fresca; sinal FV "abaixo do mercado" lido defensivo do fair-value-cache, degrada seguro); view cliente.view + rotas /c/:slug/cliente/:token e .../d/:listingId (detalhe escopado ao cliente — SEMPRE header/WhatsApp do corretor dono, resolve etiqueta de comissão na UX); comando /cliente <nome> <código-semente> (cria do imóvel-semente, lista, ajustar) + botões de ajuste. Gates: typecheck limpo + 19/19. ✅ SMOKE ponta-a-ponta no cloudvero 19/06 (semente 601301089-18 Panamby R$285k 1dorm → owner Luciana 1105): página HTTP 200, 24 cards na faixa R$228–342k (21 apto + 3 studio), 9 selos "💎 abaixo do mercado", header/WhatsApp da Luciana; detalhe escopado /d/{id} abre com a marca da Luciana mesmo no imóvel da Paula (1089) — etiqueta de comissão resolvida na UX. Fix FV (commit 85358a3): o fair-value-cache do ACM aninha os imóveis sob .fair (campos gap_pct/gate_ok confirmados: 397 gate_ok, 182 abaixo −8%) — sem isso o selo nunca aparecia. Achado de dado: Luciana = agent_code 1105 (não 1089); 601301089-18 é da Paula compartilhado no minisite dela. Migration v126 aplicada em prod (schema 126). Para usar: Luciana roda /cliente Fabio Bernardes 1089-18 no StudioBot (owner = ela, pelo telefone). ✅ F2 ENTREGUE 19/06 (merge 14ac61c): selo de privacidade no rodapé (página privada/noindex, tranquiliza o cliente) + agendar visita. Botão "📅 Agendar visita" no card → modal (nome/WhatsApp/horário) → POST /c/:slug/cliente/:token/visita → migration v127 visitas + ping fix-in-chat ao corretor DONO (botões ✅ Confirmar / 🔁 Remarcar / 📞 Falei c/ dono via sendButtonMessage, fallback sendTextOrAlert/HSM fora da janela 24h; imóvel de outro corretor/rede sinaliza "parceiro — ligue pro dono"). Anti-duplicata 24h. Smoke ok: POST→visita id 1 criada (Panamby, status solicitada, notified_at setado→ping ao 1102). Handler handleVisitaButton atualiza status. Páginas de cliente são INDEPENDENTES por corretor (token+perfil próprios; ajustes de um não afetam o outro). Comissão (Elie 19/06 — NÃO é pendência): a vitrine/parcerias só dão exposição; o split segue a co-corretagem normal (comprador × vendedor/captador) e o que VALE é o CCV — é no CCV que o split é definido e pode ter ajustes. Fonte de verdade da comissão = CCV extraído pelo /cobrar (já é assim, ver feedback_cobrar_ccv_fonte_verdade). Nada a construir. F3 (relay automático corretor↔parceiro) não iniciada. ✅ F3-clique+auto ENTREGUE 19/06 (merge 9caa1cd): (A) imóvel clicado em destaque no topo — vira HERO fixo ("O imóvel que você viu"), sempre presente mesmo fora da faixa, com "Outras opções que combinam" abaixo (buildCardForListing+heroHtml; matchForProfile exclui a semente da grade). (B) trigger automático — quando o lead ganha dono (portal/site na hora; bolsão ao arrematar), o leadbot chama POST /internal/cliente-auto (localhost) → cria a página com nome do lead + semente e manda o link pronto pro corretor (autoCreateClientePage, idempotente por leadId; hooks em buyer.flow routeToOwner+bolsão accept; deriveProfileFromSeed/getClienteByLeadId). Decisões Elie 19/06: criar sempre que houver dono; mandar link pronto. Smoke OK: POST→hero 601301089-18 no topo + 24 opções abaixo, idempotência created:false no 2º POST, ping ao corretor. Memória reference_minisite_cliente_comprador. |
| 2026-06-18 | Elie | Tirar o motor próprio (fair-value/ACM) do SHADOW: destravar vendas_internas + opção B (guarda-corpo ITBI). | P2 | Investigação 18/06 reenquadrou os 2: (1) vendas_internas (bot.db, peso 3.0) NÃO é desperdício crítico — o endpoint da rede iList (ilist_network.py, officeIds:None) traz a rede RE/MAX INTEIRA, e como o Estoque Vivo marca nossos 60130 como "Vendido", nossas vendas já entram via ilist_network_vendido (peso 2.8). A fonte vendas_internas do bot.db está estruturalmente quebrada (Pipeimob morto → data_registro_publico NULL em 387/387; e area_m2 ausente em 48 dos 55 deals fechados c/ valor → só 1 venda nos últimos 12m teria data+valor+área). Resgatar = COALESCE(registro,contrato,comissão) + fallback de área via enrichment por listing_id, mas ROI baixo (ganho = realce 3.0 + geo fina, sobre dados já capturados via rede). Recomendado: NÃO investir agora. (2) Guard de locação no fair-value: FEITO (commit a5dde0f) — _fv_points retorna None p/ tipoTransacao=Alugar (inerte hoje, blinda quando ligar). (3) Opção B (guarda-corpo ITBI) tem dependência NÃO satisfeita: o itbi_pricing.py NÃO está plugado em lugar nenhum (generator/destaque), e o _merge_fair_value injeta só fv_gate/fv_gap/fv_conf (ACM), não ITBI. Implementar B = projeto médio (plugar itbi_pricing no generator → injetar itbi_gap no ad_report → regra de veto no destaque), cobertura estreita (17 imóveis rock-solid). Pendente decisão Elie: (a) seguir com opção B como projeto, ou (b) validar o fair-value puro (ACM, sem ITBI) saindo do shadow com os 19 flips já medidos. |
| 2026-06-17 | Elie | Locação no destaque pago + auditoria dos algoritmos por tipo de transação. Auditoria do boletim de meritocracia (reunião de sexta) pegou o imóvel 601301011-350 (Vila Mascote) rotulado "venda R$8.000" sendo LOCAÇÃO (R$8.000/mês). Apurado: 11 locações ativas, 3 ocupando slot pago (1 Super Destaque). | P2 | ✅ Boletim corrigido (commit 43ba695): venda e locação em tabelas SEPARADAS + rótulo "aluguel/mês"; o ad-strategy já compara aluguel×aluguel (sem bug de cálculo de preço). Auditoria dos 3 algoritmos quanto a locação: (1) Impulsionamento (build_peneira.py:211) JÁ EXCLUI locação ("venda" not in transacao + PRECO_MIN R$100k) ✅; (2) Terceiros (select_boosts_ads.py) corta por MIN_PRICE R$200k + usa perfil de VENDA → locação não entra ✅; (3) Portais/destaque.py NÃO distingue transação — inclui locação no slot pago junto com venda. Decisão Elie 17/06: deixar competir, só separar no boletim (não mexer no destaque.py). ⚠️ RISCO FUTURO a tratar: o fair-value próprio (ACM, calibrado em VENDAS realizadas) está em SHADOW (FV_SHADOW=1) — ao ligar (FV_SHADOW=0) aplicaria avaliação de venda a aluguel → score de preço ERRADO p/ locação. Pendências: (a) revisitar se locação deve ter cota própria/exclusão no destaque pago (3 slots pagos hoje); (b) guard por tipoTransacao no _fv_points/destaque ANTES de tirar o fair-value do shadow. |
| 2026-06-14 | Elie | Discador — alternativa com Grok Voice API (xAI). Depois do AMD, avaliar/implementar substituir o miolo do discador pelos produtos recentes da xAI, em pt-BR. Doc: docs.x.ai/developers/model-capabilities/audio/voice. | P2 | ✅ POC CONSTRUÍDO 14/06 (commit ce609f9→merge b02b661, deployado INERTE: VOICE_ENGINE=pipecat default, grok só via /call {"engine":"grok"}). Sondas (grok_realtime_probe.py/grok_probe_voices.py) mediram: WS wss://api.x.ai/v1/realtime?model=grok-voice-latest, PCM16 24kHz, eventos OpenAI-style, TTFB ~700ms, server_vad nativo. Cérebro FIXO em grok-voice (grok-4.3 ignorado → Realtime e 4.3 são exclusivos; Elie escolheu Realtime). Voz "Beatriz" não existe na API ("voice not found") → Elie ouviu as 5 disponíveis e escolheu ara (pt-BR). grok_bot.py = ponte AudioSocket⇄WS (reusa Asterisk+Directcall+AMD, troca só o miolo; barge-in via speech_started+response.cancel). PENDENTE: ligação de teste ao vivo (Grok-ara vs stack atual). Memória project_discador_voz_self_hosted_br. (levantamento original abaixo) ⏳ Levantamento 14/06: Realtime speech-to-speech wss://api.x.ai/v1/realtime?model=grok-voice-latest (low-latency turn-taking + Smart Turn EOT — ataca DIRETO nosso gargalo atual de ~2-3s entre turnos); TTS /v1/tts com saída telephony μ-law (casa com G.711 do Asterisk) + voice cloning ≤120s; STT /v1/stt (25 línguas, diarização). Vozes na doc: eve/ara/rex/sal/leo; playground do Elie tem "Beatriz Female Middle-aged pt" + Multilingual (doc não lista pt-BR → VALIDAR sotaque, foi critério do Azure). Pricing: Agent $3/h (=$0,05/min, < Vapi $0,08-0,13 e < nosso self-hosted ~$0,10+SIP), TTS $15/1M chars, STT $0,10-0,20/h. Recomendação: ponte AudioSocket↔WebSocket Grok Realtime no lugar do pipeline Pipecat → reusa Asterisk+Directcall+AudioSocket (telefonia BR barata mantida), troca só bot.py. Trade-off: cérebro deixa de ser Claude (contraria backbone; mas o ganho de latência do speech-to-speech é estrutural, ≠ trocar só o LLM). Sem transport Grok nativo no Pipecat → escrever ponte (como fizemos o AudioSocketTransport). Memória project_discador_voz_self_hosted_br. |
| 2026-06-14 | Elie | Pipeline de parceria passiva (Studio co-corretora externa, ≠60130, sem /cobrar) — smoke test ponta a ponta + Fase 5 atribuição. Caso: temos o CCV de terceiro e só aguardamos o depósito da nossa fração no Bradesco; conciliação OFX dispara NF/recibo; rastrear se a parceria veio do nosso impulsionamento. | P1 | ✅ COMPLETO 14/06 (commits 52013ab+b351870+204a123). Smoke test real Apto 52 (602151006-101) ponta a ponta: capturei CCV → plano R$11.040 pagador ARISTÓTELES conf 0.91 → importei OFX Bradesco (crédito PLAN3) → --partner-match PINGOU certo (valor bate, depositante PLAN3≠ARISTÓTELES, segurança fiscal ok) → --partner-confirm (confirmação 1 clique, migration v118 partner_payer_aliases aprende PLAN3↔ARISTOTELES) fechou: Receivable #41 PAID, 2 NFs idempotent-SKIP (#916/#442), DRE certa, zero emissão errada. BUG achado+corrigido no smoke: emitRecibo criava doc Clicksign ANTES de validar email → recibo sem email (GAP corretores) estourava 422, deixava doc órfão e abortava a emissão; fix = pula recibo sem email + try/catch por recibo + confirm re-executável (modo recuperação se Receivable já PAID); doc órfão da Fernanda cancelado à mão. Fase 5 atribuição (partner-attribution.service.ts, migration v119): cruza comprador do CCV × leads do leadbot RO; regra Elie (mídia paga ctwa/google=sempre; portal canalpro/chavesnamao=só listing terceiro≠60130=Boost; resto=não); CLI --partner-attribution, grava no confirm/match-emit + flag no --partner-status. Matcher validado 3/3. Apto 52 = ➖ não veio do nosso funil. Memória project_parceria_passiva_pipeline. Falta operacionalizar: --partner-match no cron + --partner-emit p/ 100% auto + GAP email recibos. |
| 2026-06-12 | Elie | Melhorias nos judges de ads + avaliação "prontos p/ 1000 anúncios?" | P1 | ✅ Judges melhorados 12/06 (commits 9e71147+006bdb2+873c826): Meta — (a) alvo da distribuição ancorado no PLANO R$135 c/ rampa ±20% (antes: soma corrente → pausar ad set vazava a verba do plano p/ sempre), env META_PLANO_TOTAL_BRL; (b) tier c/ fallback pelo token do nome (carrossel não tem código no nome do ad → ficava sem alvo; match pela KEY do TIER, labels têm emoji); (c) leads_crm_7d por ad set via ctwa-ad-map+lead-bot.db (Meta subconta: 19 conversas vs 29 leads reais/7d); (d) movimentos da última run no prompt (anti-oscilação). Google — funil real no contexto (leads CRM + landing_events origem google): conv=0 da plataforma não condena busca c/ lastro. Dry-runs validados. 1000 anúncios: o modelo CERTO já opera — pool de 1000 (Jumper) + vitrine rotativa (Meta ~20 cards Terceiros + Google 6 ad groups Terceiros, rotação semanal). 1000 ATIVOS simultâneos exigiria: verba 10-20× (R$0,24/anúncio/dia não entrega nada), CPL provado (gate = relatório funil 19/06) e estrutura Meta por zonas (~18 carrosséis ≥R$15/d cada). Escada recomendada: (1º) validar funil 19/06 → (2º) escalar ad groups Google do pool (custo marginal zero, centenas elegíveis) → (3º) Meta por zonas se CPL provar. |
| 2026-06-12 | Carine (via Elie) | Dossiê do proprietário: seção "rede de parceiros trabalhando o imóvel" + eliminar plataforma NonStop. Carine prefere o relatório do NonStop na parte que mostra ~50 imobiliárias parceiras nomeadas anunciando o imóvel (teatro de esforço, mas tranquiliza o vendedor); Elie decidiu ELIMINAR o NonStop e construir estrutura própria (rede RE/MAX via Boost + parceiros credenciados + crawler de detecção em portais). ⚠️ assinatura integrations NonStop vence 30/06/2026 (nonstop.service.ts:12) e o minisite-rede depende dela (inbound). Plano completo em operations/plano-rede-parceria-propria-dossie.md — F0: scrape do relatório NonStop pro dossiê enquanto a assinatura vale; F1: crawler de detecção; F2: rede de parceria própria (cadastro bot + media kit + feed + wa.me rastreado); F3: substituir inbound minisite-rede e não renovar. Ponto de decisão 25/06. | P1 | ✅ F0 FEITO 12/06 + ⏳ F1-F3 intake. F0 (sem depender do NonStop): descoberto que a API de integração NonStop é inbound-only (puxa nossos imóveis, cria lead, lista agentes) — NÃO expõe as estatísticas de gestão (parceiros/views/leads-por-imóvel/anúncios); esses vivem só no painel logado (auth=magic-link email, morre 30/06) e os números headline são vaidade (19.433=rede inteira, igual p/ todo imóvel) ou duplicam a rede RE/MAX que já temos via Boost. Então a seção nova foi construída de dados nossos e duráveis em canal-pro-feed/dossie_proprietario.py (fora do git, no cloudvero): (1) bloco azul "Seu imóvel está publicado em N portais (ZAP·VivaReal·OLX·Chaves na Mão)" — presença REAL lida dos feeds que servimos (vrsync+chavesnamao) + ramo Boost→rede RE/MAX lido do boosts-cache; (2) widget "Custo de manter o imóvel à venda R$X/mês" (Selic s/ capital líquido + condomínio + IPTU, do enrichment iList) — espelha o widget do NonStop que pressiona pela decisão de preço, com mais honestidade. Validado no PDF do 1022-72. A lista nominal de parceiros (o que a Carine mais quer) precisa do crawler F1 — não vem de dado próprio. F1 = crawler de detecção em portais por endereço (acha quem anuncia, autorizado ou não); F2 = rede de parceria própria; F3 = substituir inbound minisite-rede e não renovar (decisão 25/06). |
| 2026-06-12 | Claude (achado durante dossiê) | 🐞 INCIDENTE área: full-sync das 14h BRT (12/06) colapsou totalArea==livingArea em TODOS os 220 imóveis. Raiz: enrich_ilist.py:365 lê totalAreaSqM da API iList e às 17:00 UTC esse campo voltou == livingAreaSqM p/ todos (anomalia provável upstream do iList — nenhum deploy nosso entre a sync das 06h, correta com 221m², e a das 14h). Propagou p/ ilist-enrichment.json + os 2 feeds de portal (vrsync.xml, chavesnamao.xml → compradores veem 123m² total em vez de ~221) + dossiês. Sem backup (enrichment-checkpoint.json é só marcador 102B; 221 perdido em disco). Impacto: avaliação por ITBI usa área total → com total errada escolhe comparáveis errados e diz "+118% vs mercado" (falso; real ~+25%). Guard aplicado no dossiê (commit-equiv. no cloudvero): detecta colapso (útil>0 e total==útil) → suprime avaliação ITBI + comparáveis + área total no cabeçalho, mostra nota honesta "em revisão"; auto-recupera quando total≠útil voltar. Teste decisivo pendente: re-scrape de 1 imóvel inspecionando totalAreaSqM cru da API p/ confirmar upstream vs scrape (enrich_ilist só tem --limit, sem flag de imóvel único — rodar com cuidado, perto da sync das 02h). Cron de envio dossiê = 13h UTC (10h BRT). | P1 | ✅ RESOLVIDO 13/06. Teste decisivo (re-scrape de 3 imóveis, totalAreaSqM cru): a API do iList tem os valores corretos AGORA (1022-72 voltou total=221) — foi glitch transitório do iList no run das 14h (devolveu os 3 campos de área == útil p/ todos), e nosso pipeline sobrescreveu o bom com o ruim sem guard. Dado recuperável. Fixes: (1) enrich_ilist.py robustecido — útil=builtAreaSqM (estável), total=max(total,living,built), + carry-forward anti-colapso (não encolhe total abaixo do conhecido); (2) re-rodei o enrichment (226/226, total=221 recuperado, 51 imóveis voltaram a ter total>útil); (3) regerei os 2 feeds + restart do serviço. Correção do diagnóstico: os portais NUNCA estiveram errados — generator.py/cnm_generator.py usam builtArea (útil) p/ APARTAMENTOS de propósito (regra feedback_area_util_vs_total: portais=área útil), e builtArea=123 foi estável o tempo todo. O colapso só afetava (a) a avaliação ITBI do dossiê (usa total) e (b) o feed de CASAS/terrenos (usam total) — ambos corrigidos (sobrado 079-25 voltou a 204 total / 163 útil). Dossiê 1022-72 agora: 123 útil·221 total, valor mercado R$1.194.744, +25% (não +118%). Guard de colapso do dossiê mantido como backstop. |
| 2026-06-12 | Claude (caso Fernanda) | ONR: 'Concluir Pedido' da matrícula sofre bounce — pedido não é criado (1ª do dia funciona, seguintes não). Repro 12/06: 14h18 pedido 122.248 criado OK (VM029142644); depois 3 tentativas da 127.981 (18h45, 19h51, 20h39) TODAS bounced — log da 20h39 prova o fluxo completo OK (confirmação detectada → Finalidade preenchida → 2captcha resolvido token 2446 chars → injetado, grecaptcha.getResponse() ok → click btnConcluir) e o ONR redireciona de volta pra frmSolicitacaoMatricula.aspx?UF=26 SEM criar pedido, sem cobrar (saldo intocado R$1.177,78; listagem segue só com o pedido da manhã). Log integral: cloudvero:/tmp/onr-full-run.log; screenshots onr_screenshots/ 20:31-20:39. Hipóteses a investigar: trava de sessão/estado pós-1º pedido do dia; token v2 rejeitado server-side na 2ª; storage_state/cookie stale; pedido draft expirando durante solve (~21s). Fixes laterais já aplicados nesta sessão: matching da listagem por nº de matrícula (b94db58 — não entrega mais PDF errado), espera de 12s pela confirmação (18e8391), mensagem honesta + aviso ao time (0022c3f). Workaround: pedido manual no painel. | P2 | ✅ RESOLVIDO 12/06 (mesma noite): causa final = 'Cartório em Manutenção' no portal ONR (banner invisível; body da resposta capturado pela sonda v8) — 14h18 funcionou, 18h45+ manutenção. POST provado idêntico ao humano (anatomia do botão + campos + token ok). 4 fixes nossos no caminho: matching por matrícula b94db58, espera confirmação 18e8391, sitekey dinâmica 9a7d4be, erro honesto 0022c3f; diagnóstico permanente 2eb252a. Retry automático da 127.981 agendado (cron 8h/11h BRT, auto-remove no sucesso, entrega direto pra Fernanda + aviso ao Elie). |
| 2026-06-12 | Elie | Meta/IG: reestruturação 2×3 espelhando o Google + /impulsionar vira CARD (4 decisões aprovadas). Auditoria IG 12/06: VM_ISCA saturado (R$55/conversa, freq 2,2, 53% do gasto 7d), singles morrem no learning (Arnaldo R$12/0 conv), melhor performer (Terceiros_VENDE R$20/conversa) usa só 24% da verba — gargalo é entrega/criativo, NÃO orçamento. | P1 | ✅ Executado 12/06 (commit f0561b4): (1) BelowMkt_→Proprio_ (rename Graph, learning preservado; judge classifica por valor, não por nome — safe); (2) VM_ISCA pausado, judge realoca a verba (teto 135 segue); (3) single 1022-72 (Sabryna) arquivado; (4) meta-ads/add_card_ctwa.py + boost_listing patch: /impulsionar agora adiciona card no carrossel do tier (faixa pelo valor, consent gate próprio, converte single→carrossel movendo a entrada do mapa, derruba card mais fraco por breakdown qdo cheio, pin de geo, mapa NA criação). Cards: Proprio_ISCA 4→8 (002-114/062-27/078-13/083-32) · Proprio_VENDE single→carrossel 2 cards (008-84+016-285). Consent disparado: 037-4, 002-141 (pending). Leadbot rebuild+restart c/ mapa ✓. ⏳ PENDENTE: criar Proprio_ALTO (espera consent do 601301099-5; 008-65 já approved — precisa 2 cards) e Terceiros_ALTO (188 candidatos Jumper; bloqueado por rate limit Graph code 17 — criar amanhã, R$8-10/d, adset no campaign Terceiros existente). |
| 2026-06-12 | Elie | Instrumentar funil pós-clique das landings (Google Ads) antes de subir verba. Auditoria 12/06: as 4 campanhas Search ativas estão genuinamente limitadas por orçamento (IS perdida por verba 78–90%, anúncios em só ~10% das buscas) MAS 233 cliques/14d viraram 1 lead (CPL real ~R$521 vs alvo R$15) — upsell do Google (R$30→120/d) compraria cliques, não leads. Gargalo pós-clique: atribuição furada (155 leads "WhatsApp direto sem referral" podem conter Google não-rastreado) e/ou landing não convertendo visita→CTA. Decisão: medir primeiro, verba depois (judge ganha alavanca de budget qdo CPL ficar confiável). | P1 | ✅ DONE 12/06 (commit d42b001): beacon sendBeacon nas páginas de detalhe (view + clique em a.cta/a.wa, gclid+origem; NÃO toca no caminho de atribuição GAds-/REDE-) → POST /ev no minisite → tabela landing_events (migração v112) → seção "🧪 Funil landing 24h" no resumo diário 09h (isca_daily_summary). Nginx: location /ev adicionado ao whitelist do domínio (faltava → 404). Smoke E2E via domínio público OK. Ler em ~1 semana: se CTA%% alto e leads não chegam → atribuição; se views altos e CTA%% baixo → landing/preço. |
| 2026-06-12 | Claude (incidente Meta) | Resiliência de envio: fila de retry persistente + canário de saída no watchdog. Incidente 12/06 ~10h13–13h45 BRT: Cloud API da Meta parou de aceitar envios (OAuthException code 2 transient / timeout no POST /messages; GET funcionava) nos 2 números (bot+leadbot). Processo ficou vivo → bot parecia "mudo": Carine pediu "Fazer ACM" e a resposta se perdeu PARA SEMPRE (sendTextMessage lança, ninguém re-tenta; ainda gerou unhandled rejection no avaliar.handler). Detectamos só quando o Elie estranhou o silêncio. Fix proposto: (1) fila outbound persistente — envio que falha com erro transiente (5xx/code 2/timeout) entra em outbound_retry (SQLite) com backoff e idempotência, flush automático na recuperação; (2) bot-watchdog.py ganha CANÁRIO de envio (1 msg/30min pro Elie ou pro próprio número; 2 falhas seguidas = alerta via canal alternativo — dm-outbox/WhatsSie); (3) try/catch nos handlers em volta de sends (matar unhandled rejection). | P1 | ✅ (1)+(3) LIVE 12/06 commit 40b83aa: migration v111 outbound_retry + loop 60s c/ backoff (1m→6h, morre 8 tent/24h) + 4 métodos send enfileiram em erro transiente (não lançam mais) + auto-anúncio de recuperação pro Elie ao drenar a fila. (2) canário no bot-watchdog: pendente (o auto-anúncio já cobre detecção pós-fato; canário proativo fica p/ depois). |
| 2026-06-12 | Elie | Aviso de imóvel mal precificado ao corretor dono, com preço sugerido do Canal Pro + card-argumento p/ convencer o proprietário a baixar. Fonte: relatório Ad-Strategy do Canal Pro (CSV semanal que o quality_scraper já baixa — colunas Preço atual/Preço sugerido/views/leads por anúncio; hoje 43 de 229 anúncios >5% acima do sugerido, ex. 601301062-15 +51%, 601301051-35 +43%). Preço a sugerir = "Preço sugerido" do próprio Canal Pro (fonte neutra), reforçado com 2–3 comparáveis reais do ITBI (ACM/itbi_market.py). Fluxo (fix-in-chat): bot manda ao corretor dono um card próprio 1 página (HTML→PNG, branding Studio 76: preço atual vs sugerido, % acima, views/leads vs bairro, comparáveis ITBI — melhor que screenshot do Canal Pro, que exige login headless e quebra com UI) + botões [📞 Vou falar com o proprietário] [✅ Autorizou — informar novo preço] [🚫 Manter]. "Autorizou" → wizard colhe valor → fila p/ admin aplicar no iList (preço é CONTEÚDO de listing ATIVO — bot não edita, regra crítica) → confirma no chat. Ciclo já fecha com motores existentes: redução ≥3% dispara price_drop_boost (impulso 1-clique) e o preço ≤ sugerido destrava +65 no destaque.py (candidato a Destaque Exclusivo + passa na peneira de ads) — argumento pro corretor: "baixou = vitrine top + mídia de graça". Detalhes: cadência semanal (acompanha o CSV), threshold inicial >10% acima, filtro de sanidade (excluir outliers tipo vaga/sala, valor mínimo), estado com dedup p/ não repetir o mesmo imóvel toda semana. ⚖️ Âncora jurídica (Elie 12/06): o card cumpre 3 das 4 obrigações da cláusula 2.1 do CR (modelo Clicksign financial-services/contrato de representação remax modelo clicksign...v2.docx): (ii) execução do Plano de Marketing, (iii) ACM embasando a precificação no momento atual, (iv) prestação de contas — e a cláusula 2/3 condiciona a VIGÊNCIA da exclusividade a essas obrigações (proprietário pode rescindir antecipadamente c/ cura de 10d úteis se descumprirmos). Logo o card = blindagem do CR contra rescisão + justificativa de renovação (1.2). Implicação de design: arquivar cada card enviado por imóvel/deal (trilha de prova de cumprimento, ex. juridico/deals/<id>/ ou tabela no bot.db) e considerar versão formal periódica ao PROPRIETÁRIO via corretor (prestação de contas proativa). 📕 Visão ampliada (Elie 12/06): DOSSIÊ PERIÓDICO DE PRESTAÇÃO DE CONTAS POR IMÓVEL entregue pelo corretor ao proprietário — o card de preço vira um capítulo. Cron único diário que detecta "aniversário" de cada CR (dossiê a cada 30d da assinatura; o do último mês antes do vencimento = argumento de RENOVAÇÃO da exclusividade). Conteúdo (1-2 pág PDF): (1) exposição — views/portal (CSV Ad-Strategy) + dias em destaque/tier (destaque.db); (2) demanda — leads por origem por imóvel JÁ EXISTE (lead-bot.db.leads: listing_id+source ∈ canalpro/chavesnamao/ctwa/google/remax/c2s/site; ex. real 601301087-11=21 leads: 12 ZAP+8 CnM+1 C2S); (3) mercado — preço vs sugerido + ITBI; (4) esforços — mídia paga (harvest_performance/terceiros_report), fotos; (5) recomendação. Entrega: PDF WhatsApp ao corretor dono + texto pronto p/ encaminhar + arquivo por deal. Distinto do weekly_report existente (que é por CORRETOR, interno). Ressalvas: cobertura listing_id 244/458 (53%, leads 'manual' sem atribuição — dossiê pressiona fechar essa disciplina); histórico leadbot começa ~mai/26. | P2 | 🚧 Fase 1 LIVE 12/06 — cloudvero:/home/egk/canal-pro-feed/dossie_proprietario.py (fora do git, como o resto do canal-pro-feed): PDF reportlab por imóvel (identificação, exposição views+dias/tier do destaque.db, demanda por origem do lead-bot.db, posição de preço vs sugerido c/ recomendação ≥10% acima + aviso de RENOVAÇÃO se CR vence ≤21d), --listing/--due (cadência 30d de dataCadastro, só Ativo+CR vigente — vencido é do enforce_cr; prioriza CR vencendo; sanidade preço: ignora <R$100k e sugerido <40% do atual), state dossie-state.json, arquivo dossies/<id>/dossie-YYYY-MM-DD.pdf (trilha cl. 2.1), entrega via Cloud API (doc upload+message). Cron 13:00 UTC diário --due --send-elie --limit 5 — Elie revisa e encaminha. Backlog inicial: 114 imóveis due (~23 dias p/ zerar a 5/dia). Smoke real: 601301089-15 (Paula, 20 leads: 16 IG) gerado+entregue no WhatsApp do Elie. ✅ Fase 2 TAMBÉM LIVE 12/06: (1) comparáveis ITBI no capítulo de preço (ACM/cache/itbi.db, 424k transações: bairro normalizado JD/VL, natureza compra-e-venda, mesmo tipo, área ±35%, últimos 12m + mediana R$/m² qdo área conhecida); (2) capa c/ foto (primária do vrsync.xml, cosmética — nunca derruba o dossiê); (3) mídia por imóvel: anúncio CTWA dedicado → spend real via Graph insights (ctwa-ad-map.ts + META_ADS_TOKEN do leadbot; ex. R$73 no 601301089-15), carrossel → menção; (4) HSM direto ao corretor: template dossie_proprietario_v1 (UTILITY, DOCUMENT header via resumable upload, 2 quick replies) submetido — PENDING na Meta; --send-corretor no cron já ativo c/ fallback automático pro Elie até aprovar; (5) handler dos botões whatsappbot/src/handlers/dossie.handler.ts (commit 2ec1e61, typecheck+18/18 testes, push→auto-deploy): dossie_fwd_<id> registra prestação de contas, dossie_price_<id> responde + notifyAdmins(now) pra gestão aplicar preço no iList (bot não edita listing ativo). Pauta 12/06 atualizada (seção 9 + material) e postada no grupo Leads Improvement c/ o sample dossie-601301089-15 (2/2 via outbox WhatsSie). Falta: Meta aprovar o HSM (cron se auto-promove); Fase 3 = persistir confirmações fwd em tabela + wizard de novo preço. |
| 2026-06-12 | Elie | Notificações do bot pro Elie viraram spam — auditar e criar modo digest. Auditoria 12/06 (madrugada): botjuridico manda 40–107 msgs/dia pro Elie (pico 107 em 05/06; ~470/semana), 75% disparadas por evento + 25% em horário de cron. Fontes identificadas: watchdogs DD/certidões (dd-async-watchdog 13h, DD-completeness, Cenprot-repoll avisa CADA falha de login, notifyExpired de certidão), família CR (CR-button, CRExtraction, cr-watchdog), Clicksign sync, deadline alerts, held-splits 2×/dia, leads daily-report 11h, recrutamento 21h (leadbot), feed observador do bolsão. Mensagens de status repetidas ("ainda processando", "login falhou de novo") são a maior parte — inúteis e ultrapassadas quando ele lê de manhã. Fix proposto (2 partes): (1) notification-ledger (tabela notif_log: phone, source_tag, resumo, ts) preenchido por um wrapper notifyAdmin(tag, msg, {urgency}) — dá atribuição exata e métrica; (2) modo digest: urgency=normal acumula e vira UM resumo agrupado 2×/dia (08h e 18h BRT); urgency=critical (dinheiro travado, bot caído, incidente) passa na hora. Migrar os call sites por fonte, começando pelos top offenders (DD/certidões/CR). | P1 | 🚧 Infra LIVE 12/06 (commit 89aec98, Elie aprovou o corte): migration v110 notif_digest + admin-notify.service (notifyAdmins now/digest) + flush cron 11,21 UTC; 1ª fonte migrada = alerta de equipe do notifyExpired. Auditoria corretores (12/06): Samuel ~48/dia e Wilton ~7/dia eram DD_TEAM (consertados pelo digest); corretores reais top = 3–9/dia, transacional (deals próprios) — saudável; campanha de adoção JÁ é digest matinal + dica semanal com aprovação editorial do Elie (29/05). Pendências: migrar próximas fontes conforme ledger apontar; monitor de volume por corretor (alerta se >15/dia); regra "aviso admin novo nasce no notifyAdmins" no CLAUDE.md do bot. + Loop achado e morto 12/06 (commit d9d9b03): dd-async-watchdog re-anunciava cada certidão falhada por 7 dias seguidos pro time (RECENT_FAIL_DAYS=7 em job diário, sem dedup) — caso real: 13 certs dos deals 1016-27x re-listadas diariamente p/ Elie+Wilton+Samuel desde 07/06. Agora: janela=1d (só novidade) + alerta via digest. Saúde estrutural OK: zero certidões >10d pendentes, zero presas em deal fechado (caps de expiração funcionam). Resolvido 12/06 (decisões Elie): (1) scraper de login CENPROT ELIMINADO do fluxo automático (commit b3fcb69) — Plexi agora aceita modo CERTIFICADO (probe confirmou: endpoint exige campo certificate); com CENPROT_CERTIFICATE setado, CENPROT_NACIONAL volta aos bundles e polla como qualquer certidão. Atualização 12/06 (resposta Plexi chamado 335): NÃO existe self-service de certificado no painel — o provisionamento é feito operacionalmente pela equipe Plexi, que devolve o secretName. Rascunho de resposta formal pedindo o provisionamento (canal seguro p/ .pfx+senha) está nos Rascunhos do Gmail aguardando envio do Elie. Ressalva deles: homologado p/ e-CPF A1; e-CNPJ depende da fonte — nosso acesso manual ao CENPROT com o cert funciona, argumento incluído no rascunho. Até lá CENPROT_NACIONAL não é emitido (SP segue normal). Atualização 15/06 (chamado 342): Plexi respondeu MUDANDO de posição — agora é self-service via API. Seguimos a doc (crawly.atlassian.net/.../Certificados): POST /api/organizations/31317062000155/certificates com o e-CNPJ A1 (.pfx studio76-server:/home/egk/certs/studio76_cenprot_modern.pfx, senha CENPROT_PFX_PASS do ~/.bashrc_secrets). Certificado studio76-ecnpj-a1 cadastrado com sucesso (CN=STUDIO76 INTELIGENCIA IMOBILIARIA LTDA:31317062000155, válido até 17/07/2026). CENPROT_CERTIFICATE=studio76-ecnpj-a1 setado no .env do cloudvero + bot reiniciado. Problema: endpoint cenprot/consulta-protesto ainda rejeita certificate: "studio76-ecnpj-a1" com erro de validação (mesmo comportamento de campo ausente — provável que o certificado precise ser ativado/vinculado do lado da Plexi). Username+secret confirmado pendente-forever (HTTP 202 nunca resolve). Email de follow-up enviado ao chamado 342 explicando o diagnóstico. Aguardando resposta da Plexi. Scraper Camoufox em studio76-server continua como fallback. (2) 9 certidões expiradas dos deals da Nilza (1016-276/277/283/287) → status waived + deal_events DD_CERT_WAIVED — renovação dispensada, somem de todos os alertas/pendências. |
| 2026-06-12 | Elie | Fase 3 minisite-rede: melhorar retirada + auto-remoção de imóvel de parceria vendido/desativado. (a) Retirada: /meu-minisite já lista todos + botão ❌ tirar (resolve "a mensagem se perde"); falta só deixar VISÍVEL — pôr lembrete "pra gerenciar/tirar depois: /meu-minisite" na confirmação de adição (minisite-rede.handler). (b) Auto-remoção (gap real): minisite_rede_curado é snapshot, não re-checa status live → imóvel vendido/desativado pelo parceiro continua na vitrine + geraria lead. Fix = cron diário que re-checa status de cada curado (NonStop API p/ base36; cache iList de rede p/ Boost 60xxx) e, se vendido/inativo/sumido, removeCurado + avisa o corretor ("seu imóvel de parceria X foi vendido, tirei da página"). Espelha o auto-inativacao do Estoque Vivo. | P2 | (b) ✅ DONE 12/06 — cron minisite-rede-staleness (10h BRT diário) live: checkNonstopActive (404/sem-disponibilidade) + enrichFromIListRede null (Boost sumiu do cache) → removeCurado + avisa o corretor; --dry-run ok (detecção active/gone/null validada). (a) visibilidade do /meu-minisite na confirmação: pendente (Sabryna já sabe pela msg). |
| 2026-06-11 | Elie | Fase 2 minisite-rede: picks de parceria do corretor furam o algoritmo e sobem pros portais + impulsionamento. Hoje minisite_rede_curado é isolado (só vitrine + bolsão). Conectar ao pipeline de boost pros imóveis Boost (rede RE/MAX, link remax.com.br, ID numérico 60xxx não-60130) que o corretor escolheu. NonStop (base36) NÃO entra — fica só vitrine+bolsão (compliance). Decisões Elie 11/06: cota 2 por corretor; escopo portal (Canal Pro/CnM) + Meta/Google (os dois); ordem de preenchimento 60130 próprio → picks de parceria (furam o algoritmo) → Jumper preenche o resto; teto global (ex.: ≤20% da capacidade) pra não sufocar nosso estoque. Implementação (cirúrgica): (a) função compartilhada lê bot.db.minisite_rede_curado read-only, filtra Boost-source, aplica 2/corretor + teto; (b) canal-pro-feed/select_boosts.py (portal, já faz 60130-first + ~80 vagas) prepend dos pinned; (c) canal-pro-feed/select_boosts_ads.py/meta-ads/expand_terceiros_ctwa.py (Meta/Google) idem. ⚠️ Risco: mexe em verba de ads + cota paga de portal — buildar com cuidado + validar. Memória reference_remax_boost_vs_nonstop_anuncios.md, project_minisite_rede_curadoria_nonstop.md. | P2 | ⏳ Spec fechada — buildar (Fase 2) |
|------|-----------|---------|----------|----------|
| 2026-06-11 | Claude (achado em deploy) | Plexi: loop apertado sem backoff no repoll de certidão (409→reuse→poll 429→repete). Flagrado às 04:24 UTC no processo antigo do botjuridico: ~17 mil linhas Plexi: poll error ... 429 + Plexi 409 ... reusando requestId em ~5 min (≈56 req/s contra a API), requestIds a1fea5d7/a1feac94 (cnd-federal-pgfn). O restart do deploy 04:28 matou o loop (0 ocorrências no processo novo), mas o bug é latente — provável interação do fix de re-submit 212a0c7 (08/06) com a resposta 409 "consulta já existe": o caminho de reuse re-entra sem delay. Fix proposto: backoff exponencial + teto de tentativas no poll do PlexiService; tratar 429 como "esperar", nunca re-submeter; e o caminho 409-reuse deve agendar próximo poll, não re-entrar síncrono. Diagnosticar por certidao-repoll + journalctl. | P1 | ✅ FIXED 11/06 commit 38cf084 — guard-rails no chokepoint (this.http do PlexiService): throttle global 600ms entre requests, circuit breaker 429 (cooldown 60s→10min), backoff exponencial no waitForResult (15s→120s), dedup de submit em voo (mata stampede 409-reuse). Qualquer topologia de loop fica contida em ~1,6 req/s. |
| 2026-06-10 | Elie (p/ corretora) | Curadoria do minisite do corretor com imóveis de TERCEIROS (rede), via WhatsApp. A corretora quer incluir imóveis de outros escritórios no minisite dela (/c/{slug}). Interface (pedido Elie): UX-friendly via WhatsApp — a corretora manda o LINK do imóvel e o bot ADICIONA/REMOVE do minisite dela (fix-in-chat, sem painel web). Viável: o minisite é nosso (whatsappbot/src/minisite, já serve /c/{slug} + a landing de rede /imovel-rede/{id} em views/rede-detail.view.ts); os 994 imóveis de terceiros já estão enriquecidos (whatsappbot/data/ilist-rede-enrichment.json). Componentes: (1) parser de link → código do imóvel (nossa landing de rede, portais CnM/ZAP/Canal Pro, iList); (2) tabela curadoria (agent_code → listing_ids + add/remove, com ownership por telefone); (3) render: minisite lista próprios + seção "Imóveis da rede" c/ disclaimer parceria; (4) handler WhatsApp add/remove + /meu-minisite pra gerenciar. DECISÕES PENDENTES: (a) atribuição — lead que vem do imóvel de terceiro no minisite dela vai DIRETO pra ela (ela divulgou) ou pro BOLSÃO de parceria (unificado hoje 10/06)? muda a política; (b) que links aceitar (só rede já enriquecida vs qualquer portal → exige enrich on-the-fly); (c) teto de imóveis/minisite (evitar pulverização + competição interna pelos mesmos imóveis); (d) imóvel de terceiro fora dos 994 (de fora da nossa base RE/MAX) é permitido? ⚖️ COMPLIANCE (Elie 10/06: link é do NonStop): ver parecer juridico/contratos/parecer-anuncios-marca-parceria-26mai2026.md §4 — anunciar imóvel NonStop de terceiro é PERMITIDO só no modelo "Representante do Comprador / Buyer's Agent" (8 requisitos): o minisite tem que apresentar como parceria/venda compartilhada (disclaimer + Studio 76 = consultor de compra), NUNCA como captação própria (= "lista paralela" proibida, cláusula 11.5 = risco rescisão de franquia). A landing /imovel-rede já segue isso ("em parceria com {captador}"). Parser precisa do formato de URL NonStop (usenonstop.com); enrich on-the-fly p/ imóvel fora dos 994; validar captador credenciado/CRECI + imóvel não captado por outra unidade RE/MAX. Split sugerido 50/50 (3%+3%, Manual pg 9). Distinto do bloqueio de PORTAIS (project_nonstop_integracao_bloqueada — marca na conta Canal Pro): no NOSSO minisite controlamos a apresentação. 🔧 PARSER MAPEADO (10/06, via Gmail+curl+chrome-headless cloudvero): link NonStop = usenonstop.com/imoveis/{captador-slug}/{ID} (ID Base36 5 chars, ex OC6E3); regex usenonstop\.com/imoveis/([^/]+)/([A-Za-z0-9]{5}). Página é PÚBLICA (sem login) — enrich via og:tags (título=tipo+quartos+m², descrição, og:image cloudfront) + DOM renderizado (quartos/vagas/m² + nome e email do captador p/ o disclaimer, ex "Flavio Bossi Junior"). Alternativa estruturada: API GET https://www.usenonstop.com/api/unstable/imoveis/{ID} (Bearer token do painel usenonstop.com/configuracoes?tab=integration; login = magic-link p/ financeiro.studio76@gmail.com, sem senha). Emails "Novas exclusividades" (no-reply@mail.usenonstop.com) trazem os links prontos. | P2 | ✅ DONE 11/06 — LIVE em prod (commits 409c091 Fases 1-3 + 1a4a6f7 Fase 4). Decisões (Elie): (a) lead → BOLSÃO de parceria (não direto pra ela); (b) só link NonStop por enquanto; (c) teto MINISITE_REDE_MAX=30/minisite; (d) qualquer imóvel NonStop. Componentes entregues: (1) nonstop.service.ts parser+enrich via API unstable (token em /home/egk/.credentials/nonstop.env → .env cloudvero); (2) tabela minisite_rede_curado (migração v109) + minisite-curado.service.ts (ownership por telefone, teto); (3) render: /c/{slug} seção "🤝 Imóveis da rede" + landing /imovel-rede/{base36} reaproveitada (disclaimer "em parceria com {captador}"); (4) handler WhatsApp: corretora manda link → add/toggle-remove, /meu-minisite gerencia; (5) Fase 4 roteamento: marcador REDE-<id> no CTA → leadbot extractRedeListingIdFromText → cascata de impulsionamento como PARCERIA (card com label legível via leitura read-only do bot.db). Smoke E2E em prod OK (enrich OC6E3 + render + cross-DB label). Memória project_minisite_rede_curadoria_nonstop.md. Refinos 11/06: parser aceita link /share/ (botão compartilhar); tipo legível (TIPO_LABEL+prettify); disclaimer mostra escritório (brokerage.name); guarda de imóvel próprio (Studio 76 não entra como rede). 2ª fonte RE/MAX Boost (remax.com.br/{código}) LIVE: enrich pelo cache iList de rede SP (ilist-rede-cache.service, extraído da rota /imovel-rede) — só Grande SP; interior avisa "ainda não" (passo 2 = og/Playwright, adiado). Feeds NonStop→portais estão vazios (não servem). 43/45 corretores têm minisite_slug. Falta p/ rollout amplo: (a) decidir NonStop vs só-Boost (orientação RE/MAX); (b) wording da divulgação no grupo geral c/ ok Samuel/jurídico (sensível: enquadrar parceria, NÃO "lista paralela"); (c) piloto com 1-2 corretores antes do anúncio. |
| 2026-06-10 | Elie | Bot entende pedido em linguagem natural e sugere o comando preenchido ("é fácil esquecer quais comandos existem"). Disparado pelo caso 1040-99: Samuel escreveu "favor cancelar este boleto, o pagador será o comprador" e o bot não orquestrou nada — a solução exigia saber que /corrigir-pagador existe (criado hoje, commit 694ebbe). Proposta: camada de intent-recognition nas mensagens de admins/corretores que NÃO começam com /: classificar a intenção (Haiku) contra o catálogo de comandos e responder com o comando já preenchido + botão de 1-clique pra executar (ex.: detectou "cancelar boleto/pagador errado + deal X" → oferece botão /corrigir-pagador X). Começar pelos fluxos de maior dor: corrigir-pagador, cobrar, recobrar, deal, dd. Cuidado: não atrapalhar o fluxo conversacional existente (handler atual de texto livre) — sugerir, nunca executar direto. | P2 | ⏳ Intake |
| 2026-06-09 | Elie | Lembrete automático via HSM p/ sessões de fotografia travadas (estender fotografia-reminder-24h). Disparado pelas 2 sessões do Fernando (PHOTOMASTERLAB) paradas 5 dias sem nudge: #54 (deal 601301101-5) em awaiting_partner_approval — parceiro Roberto Mourão (1079) nunca aceitou o split 50/50; #55 (deal 601301040-101) em pending_doubt_text — Karina (1040) abriu dúvida e nunca mandou o texto. Causa-raiz = o cron horário src/scripts/fotografia-reminder-24h.ts tem 3 buracos: (1) só varre pending_approvals/pending_yara_review — ignora awaiting_partner_approval, pending_doubt_text e awaiting_broker_approval; (2) manda texto livre (wa.sendTextMessage) que não entrega fora da janela 24h — justamente quando o lembrete importa; (3) dispara 1× só (reminder_24h_sent_at IS NULL), sem recorrência. Fix proposto: estender o cron p/ cobrir os estados travados, trocar p/ HSM (aceite_parceria_fotografia p/ parceiro pendente; aprovacao_fotografia_corretor_v2 p/ corretor pendente — entregam frio), e tornar recorrente com backoff (ex.: a cada 48h, teto 3) usando a tabela photo_session_reminders (hoje vazia) p/ contar/espacar; escalar pro Elie/admin após N tentativas sem resposta. ⚠️ p/ pending_doubt_text, o reenvio do HSM de aprovação exige resetar o status p/ awaiting_broker_approval (senão o botão "Aprovar" não funciona — corretorApprove só age em pending_approvals/awaiting_broker_approval). | P2 | ⏳ Intake — disparei os 2 lembretes à mão nesta sessão via whatsappbot/ops-scripts/remind-foto-fernando-stuck.cjs --send (Roberto HSM aceite_parceria; Karina reset→awaiting_broker_approval + HSM aprovacao_v2; ambos entregues, logados em sent_messages+photo_session_events). O ops-script é o protótipo do fix automático. |
| 2026-06-09 | Elie | Onboarding de corretor automático — gatilho Clicksign (contrato de associação) + carência automática. Disparado pelo caso Luciana Kfouri (PROV-LK): cobrada R$300 de fee indevidamente por estar com join_date=null → carência de 6m não calculou → seleção da rodada fail-open cobrou (invoice 5610202787479552 cancelada; join_date setado p/ 22/05/2026 → em carência até 22/11). Regra: marco de ingresso = data de assinatura do Contrato de Associação no Clicksign → carência 6m automática. Reusar tubulação que JÁ existe: POST /webhook/clicksign + clicksign-sync.service.ts::syncDocument() (hoje só distrato + CR captação) → adicionar 3º tipo "contrato de associação/admissão" que cria/atualiza corretores (SQLite: join_date=assinatura, active=1, fee_exempt=0) + DeskFeeRule (Postgres joinDate) → carência em cobrar-fee.handler.ts:293 calcula sozinha → cron-concierge-onboarding.ts manda boas-vindas (HSM studio_bot_welcome_v1) no dia seguinte. Hardening junto (independe do Clicksign): rodada de fee = fail-safe (join_date null ⇒ NÃO cobra / assume carência) + categoria noJoinDate bloqueia a cobrança em vez de só avisar. Evolução do #41 (/cadastrar-corretor wizard manual). | P1 | Aprovado 09/06 (Elie: admissão passa pelo Clicksign ✅; data vem do contrato). Liga com #41 e backlog RH "Onboarding e Offboarding". Infra de gatilho 100% reusável — trabalho = branch de detecção do template + insert corretores/DeskFeeRule. → Movido p/ Backlog [Onboarding] em 09/06, escopo expandido p/ ponta-a-ponta (nosso sistema gera o contrato + cria no iList via createUser + bolsão = substitui Pipeimob). Decisão Elie: implementar depois. Já feito nesta sessão: cancelamento + join_date Luciana; Marcio Elizio 1107 onboardado manual como referência (em carência até 26/11, fee dia 20); 3 fixes de fundo no cobrar-fee no ar. |
| 2026-06-08 | Elie | Lead quente (score) + feedback do corretor (leadbot). Duas pontas da mesma feature: (A) calcular leads.score 0–100 a partir de sinais que JÁ temos (intent/intent_confidence, buyer_demands+parse_confidence, source CTWA×engagement, velocidade de resposta, nº de msgs inbound, faixa de preço) → rótulo 🔥/😐/❄️ exibido na oferta do bolsão sem PII (reusa coluna leads.score criada e nunca usada). (B) Feedback fix-in-chat 1–2 toques a quem pegou, dentro da janela 24h (texto livre, sem HSM): "como foi o lead? 🔥 Quente·😐 Morno·❄️ Frio·🚫 Fake" + desfecho opcional (visita/proposta/conversa/sem retorno) → nova tabela lead_feedback + outcome no lead. (C) Relatório que cruza feedback×score e mede qualidade por fonte/campanha (qual anúncio traz lixo) → calibra os pesos de A. O feedback é o rótulo que ensina o score. SLA-ack "Atendi/Ainda não" NÃO serve (OFF + só mede contato). | P2 | 📋 Plano v1: leadbot/PLANO-LEAD-QUENTE-FEEDBACK.md. Decisões TRAVADAS 08/06: (1) feedback in-window (texto livre); quem demora → re-ping HSM — ⚠️ NÃO temos HSM de feedback (sla_ack_ping é só contato) → submeter corretor_lead_feedback novo (lead-time Meta); (2) score roda ÀS CEGAS (calcula+grava, não exibe na oferta no v1 — UI fica pro v2); (3) pesos iniciais OK; (4) feedback opcional, fora do ranking. Ordem sugerida: submeter HSM → Parte B (coleta feedback) → Parte A silenciosa → Parte C relatório. ✅ DONE + LIVE 09/06 (Elie deu GO → "abrir pro time todo"): migration v15 lead_feedback + lead-score.service (heurística às cegas, hook no impulsionamento.flow) + lead-feedback.service (watchdog in-window lista 4-opções / HSM 3-botões + handler 2-toques) + job lead-feedback-ask + relatório lead-quality-report + fiação no flow-router. HSM corretor_lead_feedback APPROVED (Meta reclassificou UTILITY→MARKETING, id 2386901635164636). Smoke 17/17, sem regressão. Deployado (commit no auto-deploy 04:26 UTC), .env flag ON + whitelist removida (time todo), cron 1/min ativo (versionado em scripts/crontab.cloudvero.txt). Teste e2e validado comigo (morno→conversa, score_at_ask=72). 1ª passada real = 12 corretores perguntados (backfill 3d). v2 (depois): exibir 🔥/😐/❄️ na oferta após calibrar pesos com o feedback. |
| 2026-06-07 | Elie | Fotos do fotógrafo de QUALQUER nuvem → arquivar no nosso Drive (nome padrão) → iList. Fotógrafos usam nuvens diferentes (cada um a sua). Aceitar o link (qualquer provedor), baixar e re-arquivar no nosso Drive (0APhfIWBEF9zpUk9PVA) como STUDIO76 - 60130 NNNN-X - <endereço>.zip (cópia canônica — decisão Elie "sempre arquivar"), e publicar no iList. Build: resolver multi-nuvem (GDrive ✓ / Dropbox ?dl=1 / URL direta fáceis; OneDrive médio; WeTransfer/iCloud difíceis→fallback manual) + método de upload no DriveService + zip + nome padrão; assíncrono (fotos pesadas). Outreach (feito): HSM fotografo_link_fotos_v1 (UTILITY, id 2013089135986718) submetido à Meta pra perguntar a cada fotógrafo qual nuvem usa + avisar que o link passa a ser exigido pro pagamento; envio aos 6 ativos via whatsappbot/ops-scripts/send-hsm-fotografo-link.cjs --send quando aprovar. | P1 | Liga com a Trilha A (A1). Trava do link já construída (flag OFF). Decidir escopo de nuvens após respostas dos fotógrafos. |
| 2026-06-07 | Elie | Onboarding de imóveis 100% bot-first (tirar humano do portal iList). O /cadastrar já faz captação ponta-a-ponta (Rascunho iList→matrícula OCR→ViaCEP/GeoSampa→dono Assertiva/CR→CR+ClickSign→Estoque Vivo). Gaps de last-mile que ainda prendem o corretor no portal: (A1) upload de fotos via bot (maior alavanca; endpoint DESCOBERTO 07/06: POST https://iconnect10.gryphtech.com/ImageUpload/UploadListingImageAsync, multipart/form-data, inputs #imageUpload/#imageUploadBeta na aba "Imagens e Vídeos" de /listingsEdit/{guid}/details; fonte = ZIP da Drive via findPhotographerArchive; falta nailar campos do multipart+resposta — testar em rascunho VAZIO da Carine 1020, NÃO criar novos; limpar rascunho-teste 601301083-42), (A2) ativação Rascunho→Ativo pelo bot COM confirmação do dono (decisão Elie; viável via listingStatusUID no CreateOrUpdateListings), (A3) wizard de cadastro completo (descrição/características/fotos — whitelist já aprovada), (A0) consolidar escrita no iList via API REST (CreateOrUpdateListings confirmado, auth por cookie; resolve GUID via GetListings.listingId→items[0].id) em vez de Puppeteer. | P1 | 📋 Plano: whatsappbot/PLANO-ONBOARDING-BOT-FIRST.md (Trilha A). Independente do Pipeimob. Scripts de discovery: src/scripts/ilist-photo-upload-discover.ts + ilist-list-drafts.ts. ✅ A1 CORE FEITO 07/06: IListService.uploadListingPhoto (2 passos, verificado ao vivo no 1020-48) + DriveService.getImagesFromDriveLink (pasta/zip/imagem) + trava do link das fotos no fluxo do fotógrafo (cobranca-fotografia: força link na cobrança, sem link PIX retido awaiting_photos_link, ao receber push pro iList + libera; migration v106; flag PHOTO_LINK_GATE_ENABLED default OFF, deployado dormante commits 0c4e475/6c54c9e). Próximo: e2e c/ link Drive real → ligar flag; depois A0/A2/A3. ⚠️ limpar testes no 1020-48 + rascunho 601301083-42. |
| 2026-06-07 | Elie | Desligar o Pipeimob (decommission). Auditoria 07/06: bot já ~95% independente (deal sync desligado 24/05, write-back nunca existiu, portais via XML próprio, /cobrar=CCV, pagamentos Stark). Restam: 3 crons ativos (extrato Playwright 8h30, recebimentos 8h, email-watcher horário), 79 deals origin='pipeimob' (legado) + fallbacks origin==pipeimob no index.ts (~4097/4202/26658), pipeimob-mcp, seed de corretores via Pipeimob, tabelas pipeimob_extrato/recebimentos/transacoes_agencia. Blockers: B1 extrato→API Stark (mata 2 crons), B2 recebimentos→arquivar, B3 cortar dependência viva (remover fallbacks + reclassificar 79 deals), B4 limpeza (corretores←iList, deprecar MCP, drop tabelas), B5 cancelar assinatura. ~1-2 semanas (quase tudo cleanup). | P1 | 📋 Plano: whatsappbot/PLANO-ONBOARDING-BOT-FIRST.md (Trilha B). Independente da Trilha A. Começar por B3 (neutralizar dependência viva). |
| 2026-06-07 | Elie | /cobrar fallback — cobrança a partir do CCV assinado enviado pelo corretor. Auto-oferta fix-in-chat: corretor manda o PDF do CCV assinado → bot detecta (gate: marcador Clicksign + cláusula de comissão), acha o deal por conteúdo (detectDealFromContent), extrai a comissão (extractComissaoFromCCV) e oferece botão "💰 Cobrar comissão deste CCV" que dispara o /cobrar normal (picker pagador → split → Invoice PIX). Inverte a ordem do pendingCCVUpload (hoje exige /cobrar <deal> primeiro). Decisões Elie (07/06): (1) gatilho = auto-oferta ao detectar o CCV; (2) se não casar com deal existente, não cria deal — pede o código; (3) persiste deal_parties+deal_property+evento CCV_SIGNED_COMISSAO. Arquitetura anti-monolito: novo src/handlers/cobrar-ccv.handler.ts (deps via runtime/services). ACL = dono do deal ou admin. Reusa filtro source!='matricula_onr' do fix de 07/06. | P1 | ✅ DONE 07/06 (Elie deu GO). Handler novo src/handlers/cobrar-ccv.handler.ts + 3 fns expostas no runtime/services + hook no handleDocumentMessage (fora de wizard) + dispatch cobrar_ccv_*. Gate estrito (assinatura Clicksign + cláusula de comissão) → resolve deal por conteúdo/filename → ACL dono/admin → extractComissaoFromCCV (grava evento+deal_property) → botão "Sim, cobrar" cai no /cobrar normal. Não cria deal (decisão #2). Smoke 8/8 + suíte 17/17 + typecheck verdes. Plano: whatsappbot/PLANO-COBRAR-FALLBACK-CCV.md. |
| 2026-06-06 | Jorge Barreto (via Elie) | Discador com IA de voz ("3C próprio" + camada qualificadora). Jorge (MCMV/baixa-renda sub-500k) mostrou o 3C Plus — discador preditivo SaaS que disca em massa, descarta caixa postal/não-atende (AMD) e conecta o humano que atende ao corretor "na vez" (turnos). Decisão do Elie nesta sessão: mirar Nível 2 — não só clonar o 3C, mas pôr um agente de IA de voz (Claude como cérebro via Vapi/Retell) que qualifica/lapida o lead (renda/FGTS/aprovação de crédito, script sub-500k = system prompt) e só passa o quente pro corretor. Viabilidade pesquisada: telefonia BR Twilio ~US$0,013/min + AMD US$0,0075/chamada, Telnyx ~US$0,007/min; voz all-in Vapi/Retell ~US$0,13–0,33/min (Bland US$0,11–0,14 bundled). Pluga no leadbot reusando carousel.util (fila "na vez"), padrão webhook Meta + watchdog cron (callback de chamada), broker.util (relé/1º contato); zero código de telefonia hoje = terreno limpo. Lista de discagem já existe: 225 leads NEW nunca respondidos + frios LOST. ⚠️ Anatel mai/2026: 0303 deixou de ser obrigatório, mas "Não Me Perturbe" ampliado a TODAS operadoras (scrub obrigatório) + cautelar anti-abuso até 31/05/2026 (suspensão 15d). Compliance/scrub NMP é pré-requisito, não opcional. | EM PROGRESSO | 📋 Plano: leadbot/PLANO-DISCADOR-VOZ-3C.md. ✅ FASE 0 FEITA 06/06 (Elie mandou começar; build limpo + smoke 12/12; INERTE por dupla trava LEADBOT_VOICE_ENABLED=false+LEADBOT_VOICE_DRY_RUN=true — nada disca): migration v14 voice_calls+voice_dnc; config.voice (janela Anatel seg-sex/sáb/dom por fuso, tetos diário/por-lead, creds Vapi vazias); voice-compliance.util (janela America/Sao_Paulo via Intl + DNC + whitelist + tetos; SEM regra 0303); voice-call.repository; voice-dialer.service (selectCandidates NEW antigos/LOST frios + planCampaign read-only + runCampaignOnce dupla-trava/mock); voice-provider (interface + Mock completo + Vapi stub); prompts/voice-qualify.prompt (script MCMV do Jorge, mcmv-v1); job dry-run voice-dialer-report.js --list (candidatos/discáveis/barrados-por-motivo/custo estimado); smoke test_voice_dialer.ts (13/13 c/ trava C2S). 🔍 DIMENSIONAMENTO real (cloudvero read-only 06/06) MATOU A TESE DO BACKLOG: dos 212 NEW, 206 já tinham corretor atribuído no C2S/Vetra (101 under_negotiation, 100 new-atribuído, 5 lost) — estavam NEW só por SHADOW MODE; cold-call neles = ligar por cima do corretor dono. Virgens reais: só 6 (e ~3 são leads de teste "Baixo Alto", #383 sem telefone) → universo discável ≈3-5. Decisões Elie: (a) POC = os 6 virgens (valida mecânica, não conversão); (b) trava C2S permanente VOICE_EXCLUDE_C2S_WORKED=true (exclui na origem quem tem c2s_assigned_agent/status avançado) — feita em selectCandidates+countC2sExcluded. Implicação: valor NÃO está no backlog (inexistente); fontes reais a decidir p/ Fase 1 = leads estacionados (~100 atribuído-mas-status=new → re-ativar transferindo ao DONO c/ opt-in) · lista externa MCMV (risco legal) · inbound tempo real. ✅ POC VOZ AO VIVO 06/06 (Vapi, aprovado pelo Elie): conta Vapi criada (private key + nº US grátis 5e02c4db); VapiVoiceProvider.placeCall + jobs/voice-poc-call.js (assistant inline). Aprendizados aplicados no código: (1) Vapi tem allowlist própria de modelo → claude-sonnet-4-6/claude-haiku-4-5-20251001 (não -4-5); (2) transcriber Deepgram default é flux-general-en só-inglês → fixado nova-2 pt-BR; (3) roteiro PROÍBE emoji/markdown (TTS lia "rosto sorridente"); (4) qualificação virou CHECKLIST (parava de re-perguntar o já dito) — Elie validou "anotou certo". Cérebro do demo = Haiku 4.5 (latência ~1,2s, aprovado; testou Grok-3/4.3 = empata latência, sai do Claude). Voz Azure pt-BR-FranciscaNeural/AntonioNeural nativa (sotaque aprovado). ⚠️ nº grátis Vapi não disca internacional → telefone BR não toca ainda (precisa BYO Twilio c/ permissão intl OU créditos). Workaround p/ demo Jorge+Samuel: página web call https://bot.remaxstudio76.com.br/voz.html (Vapi Web SDK + public key, hospedada em whatsappbot/public, seletor de voz F/M) — tocam no navegador, sem telefonia. LLM hoje = chaves da Vapi (bundled, ~US$0,08/min), não BYOK — Elie adiou BYOK/self-hosted p/ produção. Commits 6496d74→9780636 (pushed). ✅ DECISÃO 07/06 (Elie) — número dedicado + self-hosted: telefonia de produção = provedor BR local + Asterisk (NÃO Twilio/Telnyx; SIP trunk BR = tarifa móvel mais barata, CNPJ-friendly, R$); número DEDICADO (não portar a linha principal — fixo SP novo, p/ não arriscar suspensão Anatel na recepção); cérebro/voz = Pipecat self-hosted (BYOK Claude + Deepgram + Azure pt-BR, ~US$0,10/min + tarifa SIP). Arquitetura: lead ⇄ SIP BR (DID fixo SP) ⇄ Asterisk (cloudvero) ⇄ AudioSocket (TCP, PCM 8kHz/16-bit/mono, frames 320B) ⇄ voice-pipecat. ⚠️ Pipecat NÃO tem AudioSocketTransport nativo (issue #2702) → escrever o transport nós (refs: silentindark/audiosocket_server, hkjarral/Asterisk-AI-Voice-Agent); reusa todo o miolo Pipecat (pipeline+prompt+vozes), muda só transporte (WS/Twilio→AudioSocket) e originação (Twilio REST→Asterisk ARI). Fases em PLANO §8: F-SIP.0 provisionar (Elie: cotar Directcall+TotalVoice/Zenvia → SIP trunk + 1 DID fixo SP + tarifa móvel + canais + portabilidade; pede Cartão CNPJ+endereço) · F-SIP.1 Asterisk no cloudvero (pjsip+dialplan AudioSocket+ARI originate) · F-SIP.2 AudioSocketTransport no Pipecat · F-SIP.3 wire PipecatVoiceProvider (já existe) + POC real · F-SIP.4 NMP+janela+webhook status+transferência "na vez" (Asterisk bridge↔carousel.util). Próximo: F-SIP.0 (contratar provedor — externo, Elie) ‖ posso adiantar em paralelo F-SIP.2 (escrever AudioSocketTransport) + dialplan Asterisk, que NÃO dependem do provedor. Fonte de leads de produção segue em aberto (estacionados c/ dono / lista externa / inbound). ✅ 08/06 — PROVEDOR ESCOLHIDO: Directcall (decisão Elie). Cotações disparadas: Zenvia (email suporte.voz@zenvia.com, sem resposta) e Directcall (WhatsApp via sessão Baileys "WhatsSie" — relay-dm.js/dm-daemon.js/directcall-watch.js em operations/aniversarios/src/, cron watcher 0 12-21 *1-5 UTC avisa Elie). Proposta Directcall "Linha Local Virtual + API": pré-pago SEM fidelidade, 1º mês R$125 (R$25 ativação+R$25 mensalidade+R$75 créditos), depois R$100/mês; DID fixo SP novo 3 dias úteis; móvel R$0,24/min (pacote R$75); auth IP/SIP (recomendam IP=✅Asterisk); G.711(+G.729); bina=nosso DID; AMD não incluso→fazemos no Asterisk/Pipecat; Anatel SCM+STFC; clientes Embraer/Totvs/Nestlé. Pendente: 3 confirmações técnicas enviadas (30 simultâneas outbound inclusas? recarga via API+validade créditos? entrega SIP trunk p/ Asterisk+CDR) + onboarding/pagamento ativação (Elie). ✅ 08/06 — F-SIP.1 + F-SIP.2 CONSTRUÍDOS (Elie mandou "começa"; tudo que não depende do número, em leadbot/voice-pipecat/): audiosocket.py (protocolo header 3B big-endian + servidor TCP; teste loopback 4/4); audiosocket_transport.py (transport Pipecat 1.3.0 — input push_audio_frame/output write_audio_frame, espelha FastAPIWebsocketTransport); bot.py reescrito p/ API 1.3.0 (VADProcessor silero/LLMContext/PipelineWorker; Deepgram nova-2 pt-BR + Haiku + Azure pt-BR); server.py origina via Asterisk ARI casando UUID↔sessão; asterisk/ Docker (pjsip trunk Directcall, dialplan [ai-dialer]→AudioSocket, ari/http/rtp, render-and-run.sh templating-python que preserva ${UUID}). Import-limpos no venv 1.3.0 do cloudvero; render dry-run validado. Falta só p/ chamada real: trunk Directcall (host/user/pass) + EXTERNAL_IP=178.156.155.123 (IP público cloudvero) + chaves IA + firewall (5060/udp+RTP 10000-10200). Runbook em voice-pipecat/README.md. Em paralelo: docs onboarding Directcall pendentes (endereço fiscal Av. Damasceno Vieira 1068; Enel=Samuel/residência✗, Vivo=empresa/móvel, Sabesp=Samuel; Cartão CNPJ Receita tem captcha → Elie puxa; comprovante = Contrato Social). Próximo: Elie finaliza checkout pré-pago Directcall (Pré II/SP-11/nº novo/Telefone IP-SIP) → manda credenciais SIP → preencher .env Asterisk+Pipecat → F-SIP.3 chamada real. ✅ 08/06 FIM DE SESSÃO — CONTRATADO + PAGO: linha pré-pago Directcall contratada e paga (1º cartão Mastercard 6967 recusou → Elie repagou). Aguardando ativação (≤3 dias úteis; boleto reconhece em até 48h) + e-mail "instruções de uso" com credenciais SIP. Watcher de e-mail ARMADO: operations/aniversarios/src/directcall-email-watch.js (cron 0 12-21 *1-5 UTC) vigia eliekfouri@remax.com.br via getElieGmailClient do bot e avisa Elie no WhatsApp (send-dm) quando a Directcall escrever; dedup pré-seedado c/ os 2 e-mails já chegados (cortesia + pagamento-falhou). Watcher de WhatsApp removido. Retomar: quando chegar o e-mail das credenciais → Elie dá toque "configura a Directcall" → preencher os 2 .env (já tenho EXTERNAL_IP=178.156.155.123, ARI user, porta 9092) → subir Asterisk + abrir firewall (5060/udp+RTP 10000-10200) → 1ª ligação real. Runbook em voice-pipecat/README.md. ⚠️ arquivos novos (voice-pipecat/ + asterisk/ + watchers) estão no cloudvero via scp mas NÃO commitados no git. |
| 2026-06-06 | Elie | Matchmaking interno comprador↔vendedor (leadbot). Unir as duas pontas DENTRO do time: corretor A tem cliente comprador, corretor B tem o imóvel que encaixa — hoje isso se perde no grupo de WhatsApp. Desenho aprovado pelo Elie nesta sessão: (1) nova tabela buyer_demands (espelho do estoque: bairro/faixa/tipo/dorms/objetivo + owner_agent_code + TTL estilo Estoque Vivo) — persistir a procura que hoje é transitória (lead_qualifications morre com o lead). (2) Captura de demanda automática lendo o grupo de WhatsApp (parser Haiku extrai post em texto livre → grava em buyer_demands; prever opt-out por corretor + filtro de confiança p/ não poluir) + também do lead já qualificado no bolsão. (3) Match engine reusando cache iList (ilist-cache.service.ts): score bairro→preço→tipo→dorms, só cruzamento entre corretores distintos. (4) Bidirecional: demanda nova × estoque existente E estoque novo/reativado × demanda aberta (gatilho reverso no captacao.flow/refresh do cache — é o anti-esquecimento de verdade). (5) Notificação fix-in-chat pinga o VENDEDOR primeiro com o PERFIL da demanda (sem PII do cliente, mantém privacidade do bolsão/LGPD) + botões [Conectar / Não é o perfil]; "Conectar" → bot apresenta os 2 corretores e libera PII; registra em internal_match_offers (espelha captacao_offers). (6) Digest semanal de matches pros admins. Valor financeiro: deal interno mantém AS DUAS pernas da comissão (captador+vendedor) na Studio76 → zero vazamento p/ fora da rede. Pontos de injeção mapeados: buyer.flow.ts (pós-QUALIFIED), captacao.flow.ts, novo job internal-match-broadcast.ts, HSM novo match_interno_corretor. | EM PROGRESSO | 📋 Plano: leadbot/PLANO-MATCHMAKING-INTERNO.md. ✅ FASE 1 FEITA 06/06 (build limpo + smoke OK, flag-gated OFF, nada notifica ainda): migration v12 buyer_demands (TTL estilo Estoque Vivo, owner nullable); buyer-demand.repository.ts; price-parse.util.ts (faixa livre→centavos, 10/10 testes — bug de alternância "mil"/"mi" pego) + text-normalize.util.ts (tokenizer compartilhado c/ futuro índice de estoque); captura no buyer.flow.ts:routeToAgent + backfill do dono; job buyer-demands-expire.ts (cron diário). + Wizard enriquecido (pedido Elie): pré-atendimento agora pergunta dormitórios (só residencial) além de objetivo/região/preço/tipo; aparece pro corretor inclusive no HSM (embutido no campo "tipo", sem mexer no template). PDF atualizado deixando as 2 fontes (grupo + lead) explícitas. ✅ FASE 2 FEITA 06/06 (smoke 9/9, dry-run only — nada notifica): inventory-index.service.ts (índice enriquecido do cache iList: preço/tipo/dorms/transação/validade) + internal-match.service.ts (gates dono≠comprador·objetivo↔transação·disponibilidade·preço·dorms + score ponderado bairro/tipo/preço/dorms normalizado) + jobs/internal-match-report.ts (DRY-RUN, --min/--top/--all). Ajuste Fase 1: valor único vira banda ±tolerância na escrita. ✅ FASE 3 CÓDIGO FEITO 06/06 (smoke e2e 9/9 em mock, flag OFF): migration v13 internal_match_offers + internal-match-offer.repository.ts + internal-match-notify.service.ts (notifyMatchesForDemand/notifyMatchesForLead: ping vendedor c/ perfil SEM PII do cliente, dedup por vendedor, top notifyCap, janela→text/HSM; processSellerMatchReply: Conectar→apresenta os 2 corretores c/ contato+imóvel+nota de comissão+marca MATCHED, Recusar→DECLINED) + trigger flag-gated no buyer.flow pós-atribuição + handler no flow-router. Falta pro GO-LIVE: (1) HSM match_interno_vendedor aprovado na Meta (spec no plano §7); (2) 🔴 decisão CEO split → INTERNAL_MATCH_COMMISSION_NOTE; (3) calibrar INTERNAL_MATCH_MIN_SCORE no dado real (precisa deploy+leads); (4) LEADBOT_INTERNAL_MATCH_ENABLED=true. Falta (código): Fase 4 gatilho reverso (estoque novo×demanda antiga) + digest semanal → Fase 5 captura do grupo via Baileys (leadbot é Meta Cloud API, NÃO lê grupos). |
| 2026-06-04 | Elie | F5 — Balancete real (balanço patrimonial) + saldo devedor de empréstimos. Disparado por "atualizar a dívida" do GIROCAIXA PRONAMPE (contrato 1863933, saldo devedor R$ 49.339,05 em 25/05/2026). O ERP é fluxo-de-caixa puro (invariante Σ movimentos ≡ Δ saldos bancários, dre.service.ts:94,171) e não tem onde carregar saldo devedor: conta PASSIVO 156 é só bucket de categorização; lançar o saldo lá quebra a reconciliação (com banco) ou fica invisível (sem banco). Solução: source competency (não-caixa, excluído da reconciliação de caixa pelo filtro já existente) + saldo de abertura por conta contábil + decompor parcela em principal/juros + modelar Loan/LoanInstallment + balancete.service.ts. Spec: whatsappbot/src/erp/PLANO-F5-BALANCETE-REAL.md; plano de implementação: whatsappbot/src/erp/PLANO-F5-IMPLEMENTACAO.md. | P2 | ✅ DONE 04/06 (fundação F5) — Elie pediu implementar. Schema: source competency (não-caixa) + accounts_chart.opening_balance_cents + modelos Loan/LoanInstallment; DDL aplicado no cloudvero. loan.service + balancete.service (saldo devedor lido da fonte de verdade loans, não do bucket de caixa 156). Seed PRONAMPE (erp:seed:loan-pronampe): contrato 1863933, 28 PG + 9 PENDING, saldo devedor R$ 49.339,05 em 25/05/2026. Validado: balancete mostra o saldo + /dre reconciliação ✅ OK (zero transação nova). Commits 3a99ace + 9171d72. Falta (futuro): wiring /balancete no bot, re-categorização dos movimentos de caixa do 156, outros contratos Caixa (017567143). |
| 2026-06-02 | Elie | Google Ads — home/catálogo da agência (landing PMax). Raiz remaxstudio76.com.br/ é só redirect→privacy; falta uma home de nível-agência pra PMax/marca aterrissar. Construir opção A (vitrine completa: grade de destaques + busca + CTA bot via Canal A, reusa minisite + cache iList). | P2 | ✅ DONE 02/06 — Home LIVE em remaxstudio76.com.br/: hero+busca+grade 220 imóveis + /mapa rede RE/MAX SP capital (viewport rendering). nginx apex → app:3000. Pedido extra do Elie: busca incluir parceiros RE/MAX + restringir SP capital (feito; viewport é o fix real da lentidão, SP-capital só cortou 5%). Corrigido landmine nginx .bak em sites-enabled. Memória project_google_ads_integracao. |
| 2026-06-01 | Elie | Google Ads + Leadbot — replicar campanhas estilo Instagram/Meta (CTWA) no Google. Decisões: Search + Performance Max; captura híbrida (landing→WhatsApp reusa cascata + Google Lead Forms→webhook). Reusa leadbot multi-fonte, feed XML iList, loop de performance estilo Canal Pro. Gap único: Google não tem click-to-WhatsApp nativo → atribuição via wa.me com código + gclid + conversões offline. | P1 | 📋 Plano: google-ads/PLANO-GOOGLE-ADS.md. BLOQUEANTE Fase 0: verificar conta Google Ads ativa + pedir developer token (aprovação Google leva dias). Fases 1–3 (atribuição/landing/lead form) avançam sem API. Liga com Intake 24/04 "Impulsionamento Digital" (#5) e "Marketing" (#6). |
| 2026-05-29 | Elie | Melhorias Captação→CR (pós-teste e2e). 10 itens: (F1) endereço completo do imóvel no CR · parceiro no resumo da revisão · botão "mesma do imóvel"; (F2) matrícula MÃE→individualizada (desmembramento: cruzar apto+torre × tabela) + OCR de páginas-chave em matrícula escaneada grande; (F3) evitar OCR duplo · ONR async não-bloqueante · melhorar extração de endereço de comprovante; (F4) ACL /simular só diretoria · smoke do frescor <30d. | P1-P2 | 📋 Plano detalhado: juridico/planning/cr-captacao-melhorias-29mai.md. Começar pela Fase 1 (qualidade do CR) → Fase 2 (mãe/individual, caso real). |
| 2026-04-15 | Samuel | Melhoria /rateio: Falta opção "3 - Parceria com corretor externo" no questionário. Atualmente só tem: Solo e Parceria interna. | P2 | ✅ IMPLEMENTADO 16/abr — Opção 3 adicionada. Ao selecionar 3, pula cat2 e temParceira (auto-true), pede parceiraPct e parceiraNome. |
| 2026-04-15 | Samuel | BUG /reportar: Deals computados errado — 1011-316 em duplicidade, 1058-41 e 1002-107 faltando (recebimento de hoje). | P1 | ✅ PARCIAL 16/abr — Dedup por transacao_uniqueid corrigido (resolve 1011-316). Fallback hardcoded Carine removido (query sem filtro = todos os pagamentos). Deals faltando podem ter sido timing (pagamentos do mesmo dia). Monitorar próximo /reportar. |
| 2026-04-07 | Elie | Diligência prévia na assinatura do contrato de gestão | P2 | Moved to backlog #10 |
| 2026-04-07 | Elie | Planilha "Vendas do Mês" auto-alimentada pelo DB/bot | P2 | Moved to backlog #8 |
| 2026-04-08 | Elie | QuintoAndar tech-match features (from competitive analysis) | P1-P2 | In Progress + backlog #11-17. Ref: operations/quintoandar-tech-competitive-analysis.md |
| 2026-04-10 | Elie | AI Property Discovery — MCP Server Público para AI agents | P2 | Moved to backlog #31. PDF CEO: relatorio-ai-property-discovery-ceo.pdf. Implementação Fase 1: 11/04/2026 |
| 2026-04-08 | Elie | Renderização de fotos via bot (Gemini Imagen / Nano Banana) — /staging já funciona com Gemini Flash, evoluir para rendering de fotos-conceito de imóveis com IA generativa (exterior, fachada, planta→render) | P2 | Moved to backlog #28. Code exists: staging.service.ts |
| 2026-04-08 | Elie | Automação de medição de subsídio de fotógrafos por deal — controle de custo fotográfico por negócio, tracking de gastos vs budget, auto-reconciliação com Granatum | P2 | Moved to backlog #29 |
| 2026-04-10 | Elie | Canal Pro Lead Webhook — URL de Integração (tela "Integração de anúncios") permite receber leads via POST em tempo real. Construir endpoint no servidor que receba leads do Canal Pro, logue, e encaminhe ao corretor via WhatsApp. Atualmente usando C2S como middleware de leads. Primeiro passo para eliminar C2S (backlog #30). | P2 | Backlog — vinculado ao item #30 (Eliminar C2S) |
| 2026-04-14 | Elie | ACM Automação — Automatizar processo de Avaliação Comparativa de Mercado. Gerar PDF profissional via /avaliar [endereço] usando iList + iConatus + ITBI. | P2 | ✅ iConatus integrado via Playwright! geoanalise_client.py funcional. Plano: ACM/PLANO-AUTOMACAO-ACM.md. |
| 2026-04-18 | Elie/CEO | /dd Assertiva A+B — A) Sempre enriquecer party com dataNascimento/nomeMae/endereços/telefones quando CPF presente (hoje só fallback). B) Buscar CNPJs vinculados ao CPF (sócio de empresas) e rodar certidões PJ automaticamente. Assertiva já contratada e em uso no /captar. | P2 | ✅ DONE 2026-04-18 — Migration v29 + enrichment automático no /dd + lookup CNPJs vinculados deployado em produção. Ver Done (April 2026). |
| 2026-04-18 | Elie/CEO | /solicitar-pagamento-fotografo — Comando que calcula subsídio Studio76 + reembolso do corretor por imóvel, gera conta a pagar no Granatum (fotógrafo) e Invoice PIX cobrando corretor. Objetivos: aliviar Yara, forçar engajamento corretor↔bot, facilitar financeiro. | P2 | Aprovado — Moved to backlog #29 (escopo expandido). Pendente: tabela de subsídios (Yara/CEO definem). |
| 2026-04-18 | Elie | Sistema de Agendamento de Fotografia end-to-end — expansão do backlog #29: wizard agendamento bilateral, monitor Drive, aprovação corretor libera pagamento + publica iList, Invoice D+30 corretor, PaymentRequest D+7 fotógrafo, nag engine proativo. Plano: /home/egk/.claude/plans/shimmying-wiggling-engelbart.md. Tabela de subsídio fornecida (R$200/250/300/350 por faixa). | P2 | Plano aprovado 18/04. Escopo integrado ao backlog #29. ~8 dias, 7 fases. |
| 2026-04-24 | Elie | Migração studio76-server (físico) → Hetzner VPS — VPS já provisionada e rodando. De-risca SPOF do servidor físico no escritório. | P1 | ✅ DONE 30/04 — bots no Hetzner cloudvero (https://studio76.duckdns.org/webhook). Ver Done (April 2026). |
| 2026-04-24 | Elie | Impulsionamento Digital — auditoria + automação de gastos com Meta Ads, Google Ads, Canal Pro turbo, etc. Reconciliação Granatum (categoria 2535141). | P1 | Backlog P1 #5 — escopo a refinar com CEO. |
| 2026-04-24 | Elie | Marketing — estratégia e execução — branding, conteúdo (IG/LinkedIn/blog), email mkt, eventos, SEO; integração bot↔landing pages com roteamento automático de leads. | P1 | Backlog P1 #6 — escopo a refinar com CEO. |
| 2026-04-24 | Elie | Recrutamento de Corretores — pipeline de captação + onboarding automatizado via bot, diferenciais Studio76 (bot jurídico, automação, suporte). | P1 | Backlog P1 #7 — escopo a refinar com CEO. |
| 2026-04-25 | Elie | Auditoria Backlog DD vs Contratos de Representação Exclusiva (ClickSign) — Puxar via ClickSign API todos os contratos de representação exclusiva assinados pelas partes e cruzar com pastas/deals para identificar quais não têm diligência prévia executada. Objetivo: gerar relatório do backlog "assinado sem DD" para remediação. Distinto do #10 (forward-looking, novos contratos) — esta é a peça de descoberta/auditoria sobre o que já foi assinado. Reusa clicksign.service.ts (já em produção) + /dd existente para checar cobertura. | TBD | Aguardando triagem — definir prioridade e se vira novo item de backlog ou sub-item do #10/#35. |
| 2026-04-26 | Elie | Bot de Pré-Atendimento de Leads — Bot exclusivo no número Studio76 (+55 11 97345-7166) para responder leads de portais em < 2min, qualificar interesse e rotear ao corretor dono do imóvel. Substitui C2S como middleware de leads. Node.js + Baileys + Claude, DB lead-bot.db. | P1 | Moved to backlog P1 #8. |
| 2026-04-29 | Hanna/Sabryna | Canal Pro: validação cruzada tipo×campos no estoque-vivo — Hoje 4 listings ativos com dormitórios incoerentes pro tipo (ex.: Terreno 1013-26 com 5 dorms quebrava feed; Sítios 1013-1 e 1008-73; Casa de Campo 1087-14). Patch defensivo no generator zera Bedrooms/Bathrooms/Suites pra Terreno (deploy 29/abr 13h). Falta: módulo estoque-vivo do bot detectar incoerência tipo×campos (Terreno c/ dorms>0, Sítio s/ área de terreno, etc.) e pingar corretor com wizard "zerar dormitórios?" inline — princípio fix-in-chat do CLAUDE.md. | P2 | Backlog — vincular ao loop estoque-vivo (project_estoque_vivo.md). |
| 2026-05-12 | Elie | ERP — anexos (invoices/comprovantes/PDF) no Drive + link rápido por transação — AttachmentService genérico: sobe PDF no Drive Compartilhado em pasta por favorecido/fornecedor (AP-ERP/fornecedores/{slug}-{id}/), calcula sha256 (dedup), cria linha attachments (já no schema) ligada a transaction/payable/receivable/payment_request, e devolve webViewLink. "Link rápido": Supplier.driveFolderUrl (todos os docs do fornecedor) + por transação o link do anexo principal (comprovante) — /t/{id} no ERP web fica fase 2. Escopo F1 (decidido 12/05): infra + integrar nos fluxos novos (/contas-a-pagar e pagamento Stark já nascem com invoice+comprovante anexados). Sem backfill histórico. Previsto no PLANO-ERP-STUDIO76.md (linha "Anexos PDF/NF → Drive + ponteiros DB"). | P1 | Aprovado — escopo F1 fechado. A fazer. |
| 2026-05-22 | Elie | /cadastrar-corretor wizard inline — hoje cadastro de corretor novo (Luciana Kfouri 5511980897887 em 22/05) é manual em 3 etapas (iConnect → export XLSX → CLI import). Comando WhatsApp restrito a admin com wizard nome/phone/agent_code/email, lookup no cache iList, UPSERT em corretores. Princípio fix-in-chat. | P2 | Moved to backlog #41 (seção P2 RH renomeada p/ "Onboarding e Offboarding"). |
| 2026-05-26 | Elie | Integração NonStop ↔ feeds Canal Pro/CnM — preencher cota residual (300−iList) com imóveis de imobiliárias parceiras via NonStop. Conta NonStop ativa (financeiro.studio76@gmail.com), 2 feeds XML prontos (usenonstop.com/integracoes/{zap,chavesnamao}/remaxstudio — formato VRSync e CnM nativos), schema validado com listing teste nonstop-B46AW (Vila Mascote, Beatriz Ares). BLOQUEADO por compliance: Canal Pro associa anunciante (logo RE/MAX + "Re/Max Studio 76 — 222 imóveis") à conta inteira, não ao listing — anunciar imóvel de terceiro via nossa conta viola uso da marca RE/MAX + CRECI (responsável pela captação). nonstop_fetch.py foi rascunhado (lat/long swap CnM, #→- no ID, força STANDARD, ContactInfo Studio76) e deletado sem commit. Próximos passos: (a) consultar RE/MAX BR sobre permissão de co-anúncio/parceria multi-marca; (b) plano B em paralelo — criar conta Canal Pro + CnM em nome de entidade separada ("Studio 76 Parcerias" ou similar) pra publicar imóveis NonStop sem contaminar marca RE/MAX, custo +1 plano de cada portal/mês; (c) lead de imóvel NonStop deve cair no nosso leadbot (carrousel/bolsão) — pendente decisão se via webhook NonStop ou via telefone-bot no anúncio. | P2 | Aguardando resposta RE/MAX BR + decisão sobre conta paralela. Memória: project_nonstop_integracao_bloqueada.md. |
| 2026-05-20 | Carine | Carine só quer receber o comprovante da comissão DELA — hoje distributeComprovantes manda pra cada destinatário o bundle completo do deal (todos os transfers: líderes, co-corretores, PJs, Studio). Como a Carine tem override de 2% em todo deal (commission-calculator SIT 1-6), ela entra em deal_splits como receiver is_studio=0 de quase todo deal → recebe o pacote inteiro de todos. Pedido: ela quer receber só o(s) transfer(s) onde ela é a beneficiária, não os dos colegas. Fix: filtro por-destinatário em distributeComprovantes (WA+email) — pra corretor marcado "self-only", transfers filtrado por resolveReceiver(t.tax_id,t.name).corretor_id === <id do destinatário>. Viável: TransferRecord tem tax_id/name e resolveReceiver já resolve corretor_id. Flag sugerida: corretores.comprovante_self_only. Idem distribuição de NFS-e. | TBD | Aguardando triagem — implementação é mudança em prod no fluxo de comprovantes; confirmar se vira flag genérica por corretor. |
| 2026-05-28 | Elie | Recibo de Comissão automático p/ corretor PF (flag) — começa pela Carine — quando o /cobrar dispara as NFS-e das partes pós-pagamento (loop em index.ts ~8200-8360, hoje só os 3 prestadores PJ studio76/suzana/socii), gerar também um Recibo de Honorários de Intermediação Imobiliária (PDF) pros corretores marcados (PF/autônomo que NÃO emite NF) e enviar pro Clicksign pra assinatura do próprio corretor. Modelo (Carine, assinado 26/05, criado pelo Samuel no Clicksign): "Eu, {NOME}, CPF {CPF}, declaro ter recebido R$ {VALOR} de {PAGADOR}, CPF/CNPJ {PAGADOR_DOC}. Refere-se a honorários pela coparticipação na intermediação de compra e venda do imóvel à {ENDEREÇO}, regime autônomo... Em SÃO PAULO aos {DATA}, MP 2.200-2/2001." Decisões (28/05): (a) flag por corretor corretores.emite_recibo — Carine marcada; quem tem flag recebe recibo em vez de NF; (b) via Clicksign assinado — reusa ClicksignService.sendForSignature(pdf, filename, dealCode, [{email do corretor, name, cpf, signAs}]) (já em produção, usado pelo /assinar). A fazer: (1) migração: coluna emite_recibo + marcar Carine; (2) gerador de PDF do recibo (parametrizado: beneficiário, valor=split, pagador=pagador da comissão do deal + CPF, endereço do imóvel, data/local); (3) hook no loop de emissão pós-pagamento — pra split de corretor com emite_recibo=1, gera recibo + manda pro Clicksign (em vez de NF); (4) opcional: watchdog que baixa o PDF assinado e distribui junto com comprovantes. Obs: Maria Izabel e Rubens também são CPF/autônomo — a flag cobre eles quando marcados. | TBD | Aguardando triagem/go — feasibility OK (ClicksignService tem create+signer+notify+downloadSigned). Relacionado ao intake 20/05 (Carine comprovante self-only) — ambos viram flags por corretor. |
| 2026-05-22 | Elie | Webhook Meta Lead Ads → leadbot (roteamento por imóvel) — campanhas pagas no Meta com objetivo "Leads" usam Formulário Instantâneo; o lead chega via webhook field leadgen na assinatura da Página. Construir handler leadgen no leadbot que: (1) recebe o lead, (2) lê o ID do imóvel embutido no anúncio/form (campo oculto ou 1 form por imóvel), (3) roteia direto ao corretor dono via listing_id — modo forte do leadbot, sem passar por C2S/Vetra nem pelo bolsão. Surgiu da campanha de impulsionamento das 2 campanhas de aptos 3-dorm Zona Sul. Pré-req: token Meta com escopos ads_management+pages_*+leads_retrieval (o System User atual é WhatsApp-only). Relaciona com backlog #8 (pré-atendimento de leads) e #30 (eliminar C2S). | P1 | Aguardando triagem — bloqueador da Campanha 1/2 se destino = Formulário de Leads. |
| 2026-05-22 | Elie | Notificação de DD para advogadas externas + resumo diário pro Elie — (A) incluir as advogadas externas como destinatárias das notificações de DD: cada DD que inicia, avança e conclui deve pingá-las (canal a definir — WhatsApp e/ou e-mail). (B) Resumo diário pro Elie: panorama de todas as DDs — quais estão em andamento, quem solicitou cada uma, status/risco, o que falta (certidões pendentes, matrícula, etc.) e quais concluíram. Já existe infra reusável: dd-pending-report.ts (panorama semanal), dd-async-watchdog.ts (alerta diário de DDs travadas), tabela dd_runs + auto_dd_queue. Falta: cadastro das advogadas (contatos), gancho de notificação nos eventos de DD, e o cron do resumo diário consolidado. | TBD | Aguardando triagem — definir contatos/canal das advogadas e se o resumo diário estende o dd-pending-report.ts ou vira cron novo. |
| 2026-05-22 | Elie | Concierge entende "Como estão nossos Leads?" — em linguagem natural o bot não respondia sobre status de leads: ou deflectia ("é pelo CRM/Ixby") ou caía num wizard de brinde aberto. O comando /leads já existia, mas o Concierge não tinha a capacidade mapeada. | P2 | ✅ IMPLEMENTADO 22/05 — tool consultar_leads adicionada ao concierge.service.ts → perguntas tipo "como estão os leads / tá entrando lead / panorama de leads" disparam /leads. Pendência separada: wizard de brinde (cobrar-brinde.handler) não abandona o estado quando recebe input claramente não-relacionado — deveria detectar e sair. Triar como bug à parte. |
| 2026-05-20 | Elie | AP scanner — varrer também o inbox eliekfouri@remax.com.br + auto-pull de boleto do portal Chaves na Mão — o cron erp:scan:emails hoje só lê financeiro.studio76@gmail.com; cobranças da Chaves na Mão (mensalidade ~R$1.773, dia 20) chegam só no @remax do Elie e ficam invisíveis. Pedido: (a) 2º OAuth Gmail p/ a caixa @remax no scanner; (b) detectar email de cobrança e puxar o boleto do portal — boleto, não PIX (QR PIX expira em 50 min, inviável p/ o ciclo dual-sig). | P1 | ✅ DONE 20/05 — novo cron erp:scan:chavesnamao (src/erp/scripts/scan-chavesnamao.ts). Token gmail.readonly do @remax já existia no cloudvero (token_gmail_elie.json). Portal serve boleto em HTML puro → sem Playwright, só 2 GETs (email → mensalidade → boleto → linha digitável). Cria Payable PENDING + notifica /aprovar. Memória reference_chaves_na_mao_billing.md. |
| 2026-05-06 | Suzana/Elie | ACM /avaliar divergência ~50% vs metodologia Suzana — Caso Borba Gato 331 apto 144 (Vila Congonhas) saiu R$ 747.952 vs mercado real R$ 1.0-1.4MM. Suzana enviou 4 docs metodológicos (tutorial, modelo Studio76, Smarty Valuation, GeoAnálise iConatus). Plano de convergência em 5 fases — Fase 1 calibração emergencial em produção. | P1 | ✅ Fase 1 deployed 06/05 noite (commit 6ea5efe): ask discount 18→5%, geocoding sem fallback 50km, faixa ±10% no agregador, ITBI 2026 populado (28.876 txns). Smoke test cloudvero: gap caiu de 47% para ~17-34%. ✅ Fase 2.2 deployed 06/05 noite (commit 931f192): cookies iList auto-renováveis via cron diário 5h BRT (refresh-ilist-session.ts). ✅ ITBI 2024+2025 carregados 12/05 (~424k transações totais no itbi.db) + cron mensal recriado no cloudvero (0 4 6 * * → src.jobs.itbi_downloader, substitui o systemd morto do studio76-server). ✅ Fase 3 deployed 12/05 (commits 3940cfa, 10d1bc2): homogeneização NBR rigorosa — f_idade via Ross-Heidecke (idade × estado Heidecke a–h, parcela de terreno 40% que não deprecia), f_vagas curva marginal IBAPE-SP, f_andar prêmio de andar alto por posição relativa, saneamento de fator ±50% + saneamento de outlier por R$/m² (banda ±2.5× da mediana). Smoke Borba Gato 331 ap.144: R$ 747.952 → R$ 1,2M (R$ 8.518/m²) — gap fechado. Plano em ACM/Plano-Convergencia-ACM-Suzana.pdf. Análise em ACM/ANALISE-GAP-SUZANA.md. ✅ Fix geocoding + PDF deployed 12/05 (commits c06bb71 geocoding, 3a85166 revert do ITBI-extras agressivo): (1) geocoding agora exige resultado dentro do município de São Paulo (clean_address tira apto/sala/bloco/CEP antes; _nominatim_search pega 5 resultados e valida city==São Paulo; viewbox SP como bias; fallback rua+nº+bairro→rua+nº→rua+bairro→rua→bairro). Caso Borba Gato 331 deixou de resolver pra Santo André (rua homônima no Conj. Res. Vila Guiomar) e passou a resolver em Jardim Santo Amaro/SP. (2) libreoffice instalado no cloudvero → o PDF do /avaliar voltou a gerar (antes só saía .pptx). (3) geocode_full()/region_names_from_details() expõem o addressdetails do Nominatim. Smoke pós-fix Borba Gato: R$ ~867k (R$ 8.5k/m²), confiança ALTA, 514 comps, dominado por iList Network vendidos (127 comps, R$ 8.752/m²) — ainda ~13% abaixo do piso da Suzana (R$1,0–1,4M), mas o gap residual é "em que bairro esse endereço realmente está" (Jardim Santo Amaro ≈ R$8-9k/m² vs Vila Congonhas/Campo Belo ≈ R$10-13k/m²), não bug. ITBI ainda problemático: quando retorna comps (testei passar bairros_extras amplos → 16 comps), a mediana sai R$ 5k/m² — subdeclaração de ITBI SP + campo bairro lixo (~40% NULL, OCR tipo "TIPO C CAMPO BELO") + só 230/424k rows geocodadas. Revertido pra não puxar o valor pra baixo; vira tarefa própria. Próximo: (a) ITBI data-quality — usar valor_transacao correto, sanity floor per-fonte (descartar ITBI se mediana <60% das outras fontes), geocodar mais rows em batch, fuzzy match de bairro; (b) Fase 3.4 (padrão construtivo via IPTU rfd-N); (c) Fase 3.5 (calibração backtest c/ vendas Studio76 — hoje 0 vendas no bot.db); (d) Smarty Valuation como fonte/âncora (login Samuel samuelchen@remax.com.br, sem API pública → Playwright); (e) API iConatus solicitada por email 12/05 (Ricardo CEO + João Victor). |
| 2026-05-12 | Samuel/Elie | ACM Colaborativo — corretor co-autor do /avaliar — Guinada do projeto ACM (conversa Elie×Samuel): o /avaliar deixa de ser one-shot automático e vira wizard colaborativo onde o corretor participa de ≥2 etapas: (1) chancela da GeoAnálise (bot roda iConatus AiA, corretor confirma ou ajusta via deep-link); (2) manda 5 links de imóveis à venda parecidos, prioridade prédio>rua>bairro (bot raspa preço/área/quartos/vagas, fallback manual; corretor marca proximidade + flag "venda fechada que conheço"). Nova fonte comps_corretor no agregador, peso 3.0 + sub-peso proximidade (prédio×1.5/rua×1.2/bairro×1.0). Gating rígido: sem as 2 etapas → só "prévia automática" carimbada incompleta, sem PDF oficial do PTAM (que sai assinado pelo corretor). Decisões fechadas (Elie 12/05): bot-roda-GeoAnálise/corretor-confirma · gating rígido · scraping+fallback manual. Infra: tabela acm_solicitacoes (state machine resumível) + scrapers de portais (ZAP/VivaReal/OLX/CnM/Loft/QuintoAndar/Imovelweb) + wizard multi-turno no index.ts + seção do corretor no PDF. Spec: ACM/PLANO-ACM-COLABORATIVO.md; PDF p/ Suzana e Samuel: ACM/Plano-ACM-Colaborativo.pdf. Aberto: quais as outras etapas além das 2 (padrão construtivo? foto fachada? metragem vs IPTU?); quem pula o gating; validar pesos/proximidade com a Suzana. | P1 — EM PROGRESSO | 🚧 F1 + F2 deployed 12/05 (commits acm-collab v59 → 8412e5c): F1.1 migração v59 acm_solicitacoes (state machine resumível) + src/services/acm-collab.service.ts. F1.2 /avaliar virou colaborativo por default (--rapido mantém o one-shot p/ admin): após a prévia automática → cria solicitação, guarda a prévia, manda valor + GeoAnálise + 3 botões (✅ Confirmo / ✏️ Quero ajustar → instrui refazer no iConatus e captura o valor colado / 🔄 Refazer). F2 src/services/listing-scraper.service.ts — scrapeListing(url) extrai preço/área/quartos/vagas/endereço via JSON-LD + blobs JSON embutidos (__NEXT_DATA__/__NUXT__/__INITIAL_STATE__) + Open Graph + regex (sem browser headless; portal que bloqueia cai no fallback manual preço \| área \| quartos \| vagas); isLikelyListingUrl rejeita páginas de busca; botões de proximidade 🏢prédio/🛣️rua/📍bairro por comparável; só encerra com 5 comps + todos com dados + proximidade. Bugs corrigidos no caminho: /avaliar endereço de fora sem --area agora entra no wizard (não "reenvie com --area"); o passo "tipo" do wizard é list_message → handler usava só buttonId, passou a usar interactiveId. Testado OK no WhatsApp (wizard fluindo, fluxo colaborativo entra). Falta F3: recálculo incluindo a fonte comps_corretor no agregador (ACM/src/sources/ + acm_engine.py + pesos prédio×1.5/rua×1.2/bairro×1.0, venda-fechada sem desconto), PDF oficial do PTAM com seção do corretor + autoria, gating rígido (hoje _acmFinalize entrega só a prévia + PDF). Falta F4/F5: flag "venda fechada" por comp · reforço do scraper p/ portais que bloqueiam · piloto. Aberto p/ Samuel: quais as etapas além das 2; quem pula o gating; validar pesos/proximidade com a Suzana. Spec: ACM/PLANO-ACM-COLABORATIVO.md; PDF: ACM/Plano-ACM-Colaborativo.pdf. |
| 2026-05-11 | Elie | Preview ao aprovar impostos + NÃO auto-pagar imposto da Suzana — (a) /aprovar pagamento N agora detecta payable de imposto (barcode segmento 8 ou keyword DAS/DARF/GFD/GPS/FGTS) e exige confirmação explícita /aprovar pagamento N confirmar, mostrando preview (beneficiário, valor, vencimento, código mascarado, descrição) + aviso "vai direto pro Stark sem dual-sig". (b) scan-financeiro-emails.ts ganhou detectThirdPartyTax — quando o email de imposto for de um contribuinte de terceiro (Suzana — CNPJ 41.516.818/0001-49 / nome no subject), cria só o PaymentRequestInternal (registro) sem Payable, manda alerta distinto ("não entrou na fila — mútuo Suzana, decisão manual") e não fica aprovável via /aprovar. (c) approveOnePayable também bloqueia payable em chart "Mútuo Suzana Lee" + tax-like. Disparada por: a DAS 04/2026 da Suzana (R$ 6.721,42) executou sem o Elie ver o detalhamento ("me assustei com o pagamento do DAS direto sem dual-sig"). | P1 | ✅ Implementado 11/05 (commit pendente push) — aprovar-pagamento.handler.ts, scan-financeiro-emails.ts. Falta (futuro): regra de 2ª assinatura no workspace Stark p/ impostos ≥ R$ X. |
| 2026-05-11 | Elie | Bug ERP/AP — fila de "aprovar" acumula pagamentos já pagos — PaymentRequestInternal/Payable ficavam em DRAFT/AWAITING_ELIE/AWAITING_DUALSIG mesmo depois do pagamento executar, quando a execução acontecia fora do fluxo de aprovação do bot. | P1 | ✅ Resolvido 11/05: (1) fix de código — payment-success-match.handler.ts e payment-request-webhook.handler.ts agora fecham o PaymentRequestInternal linkado (→ PAID quando executa, → REJECTED quando negado) junto com o Payable (commit pendente push). (2) sweep one-off de limpeza FEITO (manual): #51/#52 reclassificados p/ Mútuo Suzana + PAID, #53/#54 cancelados, PR-int 54/55 PAID, 56/57 CANCELLED; DAS Suzana #60 PAID/lançada; #19/#36/#39/#41/#47/#48/#58/#59 (já executados na Stark) → PAID + lançamentos #1014-#1021; 7 PR-int de payables PAID → PAID; 12 PR-int de payables CANCELLED → CANCELLED; PR-int #37 (FGTS dup) → CANCELLED. Fila do /contas caiu de ~37 p/ 14 itens (todos legítimos). Falta (futuro): dedup de Payable por (supplier, valor, mês) no webhook; reconciliar também pagamentos via /pagar-conta. |
| 2026-05-11 | Elie | Auto-gerar a GPS/INSS mensal da Leonilda (cód. 1406) — não há API pública (só Meu INSS/login gov.br ou o SAL); fui pela opção A (calcular a linha digitável localmente). | P2 | ✅ Implementado 11/05 (commit 1f... pendente push): whatsappbot/src/erp/services/gps-barcode.ts gera a linha digitável de GPS a partir de (código, competência AAAAMM, NIT, valor) seguindo a spec FEBRABAN de arrecadação (pos: 8+segmento 5+8+DVgeral / valor 11d / órgão 0270 / código 4d / NIT 14d / competência 6d / tipo 3; DVs módulo-11 dos 4 campos + DV geral). Self-test integrado (assertGpsBarcodeSelfTest): reproduz exatamente a GPS real comp 01/2026 (85850000003-7 24200270140-3 60001169885-1 02172026013-5, R$324,20) — lança se a spec mudar; o cron chama antes de gerar. Schema: RecurringRule.barcodeSpec JSON (ALTER aplicado em prod); generate-payable-drafts.ts detecta barcodeSpec → gera o barcode (competência = mês anterior ao venc, pois paga-se M+1 a competência M) e cria o payable já como boleto PENDING com a linha pronta. Rule #20 atualizada (amountVariable=false + barcodeSpec={"type":"GPS_INSS","codigo":1406,"nit":"11698850217"}); payable #66 (GPS venc 15/05, comp 04/2026) já recebeu o barcode 85870000003-0 24200270140-3 60001169885-1 02172026043-7. Pagar: /aprovar pagamento N → /aprovar pagamento N confirmar (vai direto pro Stark, sem dual-sig, como toda arrecadação segmento 8). ⚠️ revisar o valor R$324,20 (= 20% × piso R$1.621) em janeiro. Memória: project_leonilda_zeladora.md. |
| 2026-05-16 | Elie/CEO | Telemetria unificada bot_messages_log — relatório executivo de uso do bot pela equipe — Hoje a contagem de mensagens trocadas com corretores está fragmentada: messages (só texto conversacional), sent_messages (só HSMs instrumentados), concierge_events (só Concierge desde 15/05) e o resto fica apenas em app.log. Resultado: o dashboard #uso (deploy 16/05) subestima o tráfego real. Proposta: criar tabela bot_messages_log(id, phone, direction in/out, channel text/template/button/list/media, kind intent/template_name/tool_name, content_excerpt, wamid, related_entity, status sent/delivered/read/failed, error_code, created_at) + middleware no whatsapp.service.ts que escreve TODO send/receive ali (in/out, HSM/texto/botão/lista). Migration v63 + backfill best-effort dos últimos 30d a partir de app.log. Slice mensal vira o relatório p/ diretoria IT + CEO. Estimativa: 1-2h. | P2 | A fazer — gera fonte definitiva pro dashboard #uso e habilita relatório mensal pro Samuel/Elie. Quick-win das views atuais já entregue (commit 74e5449). |
| 2026-05-28 | Elie | Captação via nº-matrícula+RI → ONR puxa matrícula completa → extrai p/ CR + dispara DD1 imóvel — Evolução do fluxo (validado no teste real Sabryna 28/05): o corretor quase sempre só tem nº da matrícula + cartório (RI), e a foto que manda é parcial/desatualizada (caso 442342 veio incompleta → faltou endereço do imóvel). Redesenho proposto: em vez de depender do upload, o /cadastrar pede nº matrícula + RI (ou extrai de qualquer coisa enviada) → puxa o inteiro teor atualizado via ONR (R$22,95, reusa requestMatriculaONR/skill matricula-onr, tem pré-check de frescor <30d) → extrai TUDO pro CR (endereço do imóvel, todos os proprietários, ônus) → e esse estágio já dispara a DD do imóvel (DD1 imóvel). Unifica captação + DD numa fonte autoritativa única (a matrícula oficial), elimina digitação de endereço e o problema de matrícula parcial. Building blocks existem (ONR no auto-dd, extração, trigger DD). Sub-refinamento: passos de endereço do wizard aceitarem foto/comprovante (boleto de condomínio tem o endereço) e fazer OCR. UX de entrada da matrícula (Elie 29/05): o corretor pode (a) escrever o nº da matrícula + CRI de forma conversacional, OU (b) wizard pergunta "você tem a matrícula digital (PDF/foto) ou só o número + CRI?" → se DIGITAL: manda o doc (fluxo OCR atual); se SÓ Nº+CRI: wizard pergunta o número da matrícula e, separado, o número do CRI (com exemplo: "11º, 8º") → daí puxa o inteiro teor via ONR. | P1 | A fazer — feature de fluxo (não cowboy). Aguardando go do Elie p/ construir. Hoje o fluxo já fecha o CR com os 2 endereços digitados (fallback deployado 28/05). |
| 2026-05-28 | Elie | Captação/CR sem digitação — OCR de matrícula (e RG opcional) auto-preenche o proprietário + limpar nomenclatura captação×cadastro — Disparado pelo 1º teste da Carine (não conseguiu gerar o CR; flow exige captação com proprietário nome/CPF/RG/email/tel/endereço/estado civil digitados). (A) Auto-fill por documento: o corretor manda a matrícula (PDF/foto) e o bot extrai proprietário(s) (nome/CPF/RG/estado civil/nacionalidade) + dados do imóvel — RG/docs do vendedor viram opcionais (a matrícula já tem tudo, inclusive cônjuge por regime). Motor JÁ EXISTE: cr-extraction.service.ts (Claude+Grok cross-check, flag divergência) + matricula-crosscheck.service.ts (inclui cônjuge "casado em comunhão") + data-extraction.service.ts (OCR/Vision). Falta só o fio: aceitar upload no onboarding da captação → popular captacoes/captacao_proprietarios_adicionais → /contrato_captacao. Único campo que nenhum doc carrega: e-mail + telefone (matrícula/RG nunca têm contato) → digitar ou puxar do /prospectar/Assertiva. Espelhar o padrão já feito no CCV (detectDDGaps + wizard ccv-fill que pergunta SÓ o que doc não dá — KANBAN 27/05). (B) Nomenclatura confusa (Elie 28/05): hoje /captar=/prospectar (achar telefone do dono) colide com /captacao=/cadastrar (rascunho no iList) — palavras quase iguais em pontas opostas do funil. Decidir esquema único: prospecção → captação (assinar CR) → cadastro (iList). | P1 | (A) ✅ IMPLEMENTADO 28/05 (commit 60c62f9, pending push) — após /cadastrar o bot pede a matrícula (PDF); handleMatriculaCaptacaoUpload extrai proprietário(s)+imóvel via cr-extraction, backfill da captação, salva proprietários adicionais, mostra resumo p/ revisão e abre wizard captacao_dados_finais (só email/tel/valor) → dispara /contrato_captacao. Cirúrgico via pendingMatriculaCaptacao (espelha pendingCCVUpload), DD intacta, foto rejeitada c/ orientação. (B) naming: Elie decidiu DEIXAR COMO ESTÁ 28/05. |
| 2026-05-14 | Elie | Afrouxar detector de texto AP — pegar "paga 50 pro joão" / "transferi R$ 100 ontem" — looksLikePaymentRequestText hoje exige (valor monetário com R$ ou "reais") E (palavra-chave de pagamento OU CPF/CNPJ). Fica de fora: número solto sem R$ + verbo (paga 50 pro joão), relato sem pedido explícito, valor sem CPF/CNPJ. Custo de afrouxar: falsos positivos. Risco zero porque tudo cai em AWAITING_ELIE + dual-sig Stark. Local: whatsappbot/src/erp/handlers/whatsapp-pdf-ap.handler.ts:881. | P3 | A fazer — feature solicitada após /pagar auto-detect (commits ab61eac/0eff2f2 cobrem URL+QR). |
| 2026-05-14 | Elie | Reformular bot default — "Concierge" no lugar do jurídico — princípio: abstrair comandos, adivinhar o que o usuário quer. Hoje o fallback cai no jurídico/RAG Wilton mesmo pra pedido operacional ("cobra o 1083", "minha mensalidade"). | P1 | ✅ ESCOPO FECHADO 14/05 — virou backlog P1 #13. Decisões cravadas: (a) Sonnet 4.6 default + Opus 4.7 escalação; (b) RAG Wilton via tool consultar_juridico (escala humano só se pedir); (c) confirmar c/ ACL — ação com lado-de-fora pede confirmação, consulta executa direta; (d) 1 tool call por turno; slash continua como atalho power-user; "ajuda"/sinônimos viram resposta curada em prosa. 7 fases ~4 dias (F1 concierge service / F2 ACL / F3 confirmação / F4 plugar c/ flag / F5 ajuda / F6 onboarding HSM / F7 telemetria). Aguardando "go" pra implementar. |
| 2026-05-11 | Elie | RecurringRule semanal + recorrentes da Leonilda (zeladora) — Leonilda é zeladora do escritório (chart 3 "Caixinha Zelador" / CC 4 Operacional, não é Mútuo Suzana) — histórico jan-abr já reclassificado retroativo p/ chart 3/CC 4 (25 lançamentos); #332 crachás Nicolly Palacio R$168,70 revertido de Mútuo Suzana → chart 7 Despesas administrativas. | P2 | ✅ Implementado 11/05 (commit 8dbe671 deployado): RecurringRule ganhou frequency (MONTHLY/WEEKLY, default MONTHLY) + weekday (0-6) + lastGeneratedDate (migration aplicada em prod via ALTER); generate-payable-drafts.ts trata WEEKLY (1 payable por ocorrência, idempotente por data, leadDays config). 3 rules criadas (chart 3/CC 4): #18 semanal segunda-feira R$360 fixo (gera PENDING direto, sem confirmação — supplier #98 sem pixKey ainda, 1º /aprovar pede /setpix); #19 vale transporte mensal R$95 fixo (último dia, dayOfMonth=31); #20 GPS/INSS mensal R$324,20 (dia 15, cód 1406, NIT 116.98850.21-7, amountVariable=true → PROVISIONAL de propósito: precisa do barcode do mês gerado em sal.gov.br/e-CAC, pagar via /pagar-conta, NÃO /aprovar). Memória: project_leonilda_zeladora.md. |
| 2026-05-11 | Elie | "Meus dados" / self-service do corretor — bot + dashboard — Fernanda Pedrini (#1058) reclamou que a comissão caiu na chave-CPF (Nubank) em vez do Itaú e não achava onde conferir os dados dela. (1) ✅ Bot: /eu (+ aliases /meusdados, /cadastro, /dados) reformulado — dados cadastrais (CPF, telefone, e-mail, chave PIX + banco via DICT), estoque iList por agent_code, mensalidade, comissões YTD, deals com progresso de docs, rodapé de showcase; e fan-out de comissão passou a honrar split_receivers.chave_pix (antes era sempre o CPF). Deployed 11/05 (commit a084242). (1b) ✅ Bot: /fee (+ /mensalidade, /meufee, /minhamensalidade, /2via) e reconhecimento em linguagem natural ("preciso do boleto do fee", "minha mensalidade", "2ª via do fee"…) — corretor pega link/PIX da própria mensalidade em aberto (puxa FeeCharge pending por agent_code, enriquece com brcode/link frescos do Stark, trata isento/pago/cancelado); só dispara p/ corretores cadastrados, pré-exclui financiamento/condomínio/aluguel. Deployed 11/05 (commit b37f5a2). (1c) ✅ /cobrar-fee status virou relatório gerencial completo (atrasados acumulados de todos os meses por corretor — valor devido, dias de atraso, telefone, link, último lembrete — + bloco do mês: pagos com data / no prazo / total esperado / canceladas); extraído buildFeeReport() em whatsappbot/src/erp/services/fee-report.builder.ts, reusado pelo cron quinzenal (cron-fee-report-biweekly.ts); explicado no /ajuda financeiro. Deployed 11/05 (commits 07a7271, 74edf60, e183caf). Disparada por: Jacinta (#1090) não achou o PIX do fee (invoice reemitido limpo, R$300 venc 15/05) + José Arakelian (#1013) pediu pra não cobrar (trabalha c/ incorporação, Samuel não o classifica como corretor de terceiros) → invoice mai/2026 dele cancelado + fee_exempt=1 no corretores (Samuel pode reverter). (2) ⏳ Pendente: trazer "Meus dados" pro dashboard web (dashboard.remaxstudio76.com.br) — view/cartão do corretor com os mesmos blocos + auto-update da chave PIX inline. Oportunidade de showcase: estimular corretores a usar o bot no dia a dia (estoque, deals, jurídico). | P2 | Bot ✅ no ar (/eu, /fee, /cobrar-fee status). Dashboard pendente — vincular a project_dashboard_web.md (dashboard/ARQUITETURA.md), possível Fase 4/5. |
| 2026-05-11 | Hanna | Canal Pro: "CEP vazio" em 3 anúncios (601301083-37, 601301016-285, 601301011-370) com CEP cadastrado no iList. | P1 | ✅ RESOLVIDO 11/05 — causa-raiz: run-full-sync.sh usava python3 cru (sem playwright no system python do cloudvero) → refresh_ilist_cache.py+enrich_ilist.py falhavam no import desde 08/05 → ilist-enrichment.json (fonte do CEP — cache iList vem sempre cep="") congelado em 07/05. Fix: re-rodei enrichment via .venv/bin/python (218/218), patchei 601301083-18, regerei XMLs, restartei canal-pro-feed.service → feed público 219/219 <PostalCode>; commit f01da74 força .venv/bin/python no cron (pendente push). |
| 2026-05-11 | Elie | AP intake via WhatsApp para todos os administrativos — alternativa ao Gmail financeiro.studio76@gmail.com — Yara, Wilton, Suzana, Carine, Roberto, Nicolly poderem encaminhar uma conta pro bot (PDF de boleto ✅ já funciona p/ alguns; falta: mensagem de texto encaminhada, foto/print de boleto, PIX copia-e-cola, texto livre "pagar X pra Y") → bot extrai (Claude), classifica, cria PaymentRequestInternal + Payable em PENDING + sobe anexo no Drive + pinga Elie. NÃO paga — só fica pronto pro /aprovar pagamento → Stark PaymentRequest (dual-sig). Disparada pelo episódio Yara/Buda Express R$35 (11/05): forward de texto caiu em enviar_dados_bancarios → Legal AI alucinou um fluxo de pagamento inexistente. Escopo confirmado pelo Elie 11/05: (1) os 6 só mandam conta — aprovação/fila continua só do financeiro; (2) solicitante recebe retorno quando Elie aprova ("✅ conta #N aprovada, indo pro Stark") e quando rejeita ("❌ conta #N rejeitada: {motivo}") — precisa criar /rejeitar pagamento [id] [motivo], hoje não existe; (3) /contas precisa mostrar quem requisitou (Yara/Nicolly/Suzana/Roberto/Carine/Wilton) — hoje requesterLabel é gravado em PaymentRequestInternal mas só aparece em /payable [id]; e o handler de PDF carimba label genérico ("Carine"/"AP requester"), não o nome real → tem que resolver telefone→nome real e exibir em cada linha do /contas + no retorno do /aprovar. Gaps técnicos: (a) handler de texto/foto/PIX (hoje whatsapp-pdf-ap.handler só aceita PDF; trigger de texto exige ≤30 chars); (b) whitelist — hoje só Elie+Samuel+Carine(ADMINISTRATIVO_NUMBERS)+Yara(AP_REQUESTERS); falta Suzana, Roberto, Nicolly, Wilton (Wilton tem WILTON_PHONE mas não está na whitelist AP) → preciso dos nºs de WhatsApp de Suzana/Roberto/Nicolly; (c) roteamento de intent — forward de conta de admin tem que ir pro AP intake e responder "✅ solicitação #N criada, aguardando aprovação do Elie", não pro Legal AI. | P1 | ✅ DONE 11/05 (commit a7162ec, deployed cloudvero 17:09 UTC). (1) extractApFromText no pdf-ap-extractor — extrai valor/beneficiário/CPF-CNPJ/PIX/boleto de texto livre encaminhado. (2) looksLikePaymentRequestText + handleWhatsappTextAP no whatsapp-pdf-ap.handler — cria PaymentRequestInternal (DRAFT) + Payable (PENDING), responde solicitante, notifica financeiro; requesterLabel agora = nome real (contactName). (3) index.ts roteia texto-payable de remetente na whitelist AP pro handler ANTES do intent/Legal-AI (corrige o caso Yara/Buda do dia — não cai mais no jurídico). (4) /rejeitar pagamento {id} {motivo} (alias /recusar): Payable CANCELLED + PaymentRequestInternal REJECTED + avisa solicitante; /cancelar idem c/ motivo. (5) /contas mostra 📨 {solicitante} por linha; /aprovar mostra "Solicitado por" e ao aprovar avisa o solicitante. (6) .env cloudvero: FINANCIAL_ADMIN_NUMBERS = só Elie(5511994955337)+Samuel(5511972828498); AP_REQUESTERS = Yara(5511974346286)+Roberto(5511991111957)+Nicolly(5511951515189)+Wilton(5511989104493)+Suzana(5511970419468 — movida do FINANCIAL_ADMIN p/ "só mandar conta"); Carine via ADMINISTRATIVO_NUMBERS. Follow-ups DONE (commit e834597, deployed 17:24 UTC): (a) conta por texto sem CPF/CNPJ → bot lembra a solicitação 15min e completa quando o admin responde só com o CPF/CNPJ (handleApCompletionReply — cria supplier + Payable + notifica financeiro; "cancelar" descarta); (b) novo PaymentRequestSource.whatsapp_text (ALTER TYPE aplicado no Postgres do cloudvero) — handleWhatsappTextAP usa esse source agora, não reusa whatsapp_pdf. Status REJECTED já existia, sem migração disso. Robustez (commits 1b8c333+594dc82+86f3960, deployed 17:46–18:42 UTC): (c) legal.prompt.ts proíbe o Legal AI de escrever "PIX gerado"/QR Code/chave PIX/"cobrança registrada" e o ensina a pedir os dados ou usar /cobrar//fee (raiz da alucinação do print da Yara — "PIX gerado! QR Code: [QR_CODE_GERADO_PELO_SISTEMA]"); (d) coletor conversacional ApDraft (handleApDraftReply/startApDraft, TTL 15min): "pagar"/"a pagar"/"cobrar" de admin AP → bot pergunta 💰 valor → 🧾 CPF/CNPJ → 🔑 chave PIX (se CNPJ; "não tem" pula) e cria o Payable; cada resposta absorve o que tiver (regex: valor/CPF-CNPJ/e-mail/telefone/EVP/BR Code/linha digitável/nome), então reenviar a cobrança inteira no meio também serve; looksLikePaymentRequestText mais generoso ("pix" solto, "prestação de serviço", etc.). Não precisa mais "mensagem exata". Conversa da Yara com o bot resetada (26 msgs apagadas). |
| 2026-05-11 | Elie | Bug ERP/AP — boleto de arrecadação (DAMSP/DARF/concessionária) trava no bot: nunca vira Payable, não dá /aprovar — boleto de arrecadação (código de barras segmento 8 — prefeitura, DAS/DARF/GARE/GPS/FGTS, concessionárias) não traz CPF/CNPJ do beneficiário, então findOrCreateSupplier devolvia null → nenhum Payable era criado → só ficava o PaymentRequestInternal (DRAFT) → /aprovar pagamento N respondia "Payable #N não encontrado" e o bot ainda mandava "Sem CPF/CNPJ — solicite o documento e reenvie" (conselho impossível p/ esse tipo de guia). Disparada por: a DAMSP/PMSP de R$ 23,90 do Dr. Wilton (deal 601301071-7, R. José Pompeu 188 — "Serviços de Expedição de Certificados / Histórico"), mandada pelo bot pelo Elie em 11/05 → /aprovar 70 falhou. (As taxas da Prefeitura de SP costumam dar erro no Stark — mas o createPaymentRequestBoleto já trata: tenta UtilityPayment p/ segmento 8 e, se o Stark recusa com "type ISS", cai pra taxPayment.create() direto sem dual-sig.) | P1 | ✅ DONE 11/05 (commit 9d46c26, deployed cloudvero 21:01 UTC). payables.service: isArrecadacaoBarcode() + ensureArrecadacaoSupplier() (cria/acha supplier "órgão público" pelo nome do beneficiário, cpfCnpjDigits null — Stark resolve o beneficiário pelo próprio barcode). whatsapp-pdf-ap.handler + scan-financeiro-emails: boleto de arrecadação sem CNPJ usa esse supplier → cria o Payable em vez de abortar; mensagem de "sem CPF/CNPJ" reescrita (não pede mais reenvio impossível). aprovar-pagamento.handler: se o nº passado for de um PaymentRequestInternal (não de um Payable), mostra o nº do payable correspondente ou o motivo de não ter payable, em vez de só "não encontrado". Resolução do caso: depois do deploy do fix, Elie reenviou o PDF pro bot → request #73 / payable #67 criado OK; /aprovar pagamento 67 → UtilityPayment recusou (rota não permite ISS) → taxPayment.create() direto → TaxPayment 5328853234876416 criado, scheduled p/ 16/05/2026 (vencimento do boleto). Requests órfãos #65 (e-mail) e #70 (WhatsApp pré-fix) → CANCELLED. Comprovante pro Dr. Wilton: setei requesterEmail=wiltonlee@remax.com.br+emailMessageId no request #73, mas o webhook só dispara sendComprovanteToRequester em eventos de PaymentRequest/utility-payment, não em tax-payment direto → o comprovante do dia 16/05 vai precisar de step manual (ou da feature da linha abaixo + assinar tax-payment no webhook Stark). |
| 2026-05-11 | Elie | Comprovante de pagamento volta como RESPOSTA ao e-mail original do solicitante — hoje sendComprovanteToRequester (F1.4a, payment-request-webhook.handler) manda o comprovante PDF num e-mail novo pro requesterEmail; Elie quer que, quando o pedido veio por e-mail (Gmail financeiro.studio76@gmail.com), o comprovante seja enviado respondendo a mesma thread (Re: + In-Reply-To/References, ou threadId no Gmail API) — caso concreto: a DAMSP que o Dr. Wilton mandou por e-mail. Gaps: (a) PaymentRequestInternal guarda emailMessageId (Gmail id interno) mas não o Message-ID RFC822 nem o threadId — precisa buscar os headers do original via Gmail API, ou guardar emailThreadId no scanner; (b) o endpoint ${STARK_WEBHOOK_BASE}/email/send-with-pdf (servidor de webhook) precisa aceitar thread_id/in_reply_to/references e repassar pro Gmail API; (c) sendComprovanteToRequester passa esses campos quando houver emailMessageId. Não cobre o caso do Wilton retroativo (pago manual, sem comprovante Stark) — esse o Elie repassa à mão. | P2 | Backlog — vincular ao ERP Próprio (#10) e ao AP-intake-WhatsApp. Quick-ish mas toca o servidor de webhook (email endpoint). |
| 2026-05-11 | Elie | Gmail scanner financeiro — pega o anexo errado quando o e-mail tem >1 PDF; e-mails sem PDF parseável passam batido — (1) Kit Filter (19e16fca…) tem 2 anexos: 2571 - STUDIO 76_.pdf (a NF, sem código de barras) e 2571 BC.pdf (o boleto) — o scanner pegou só o 1º → extractPaymentFromPdf sem barcode → sem supplier → criou PaymentRequestInternal #63 sem Payable. (2) C2S (19e16e9a…) tem Boleto 15/05/2026.pdf anexo mas o e-mail é o "vencerá em breve" (HTML, link) → não entrou nos candidatos do scanner. Fix: scanner deve iterar TODOS os anexos PDF e escolher o que rende barcode/payable (não só attachment[0]); e o filtro de candidatos deve pegar e-mails do C2S/contact2sale mesmo sendo HTML, desde que tenham PDF anexo. Backfill manual feito 11/05: Kit Filter → payable #68 (R$243, venc 25/05, supplier #93, barcode 34191…); C2S → request #74 / payable #69 (R$546, venc 15/05, supplier TECH INNOVATION LTDA #174 CNPJ 24.574.913/0001-80, barcode 46191…). Os 2 prontos pro /aprovar pagamento 68|69. | P2 | ✅ (1) anexo certo: DONE 11/05 (commit 8f72446, deployed) — quando o email tem >1 PDF anexo, o scanner extrai cada um e fica com o que tem barcode/brcode (= o boleto), fallback p/ o 1º com valor, sem re-extrair. (2) C2S não virou candidato: ainda aberto — o email do C2S ("vencerá em breve") tem o boleto anexo e o subject tem "fatura", então em teoria deveria casar has:attachment OR subject:fatura no listBillingCandidates — investigar por que não entrou (talvez o anexo não tenha attachmentId+filename no payload Gmail, ou algum filtro extra). Backfill já cobriu maio. |
| 2026-05-11 | Elie | Cron de reconciliação Stark → ERP — pega pagamentos success que o webhook não cobre (tax-payment direto + perdas) — webhook ao vivo cobre boleto-payment.success/utility-payment.success/brcode-payment.success mas não tem subscription pra tax-payment, então TaxPayments diretos (caminho do UtilityPayment ↻ ISS → taxPayment.create()) ficam órfãos: DAS Suzana 06/05 e DAMSP Wilton 11/05 vinham sendo flipados à mão ("reconciliação manual"). Hoje também não há rede de segurança quando o webhook perde evento. | P1 | ✅ DONE 11/05 (commit 5254a6f+456acc2+477f016, deployed cloudvero 22:19 UTC). Novo script whatsappbot/src/erp/scripts/cron-stark-reconcile.ts + npm erp:cron:stark-reconcile + entrada no crontab a cada 15min (5,20,35,50 * * * *, log em logs/erp-stark-reconcile.log). Para cada Payable em AWAITING_DUALSIG com starkbankPaymentRequestId, usa batchFetchStarkStatus (cobre PR + TaxPayment + UtilityPayment) + paymentRequest.query({ids}) (p/ pegar pr.payment.id/status em PRs aprovados) + fallbacks transfer.get/boletoPayment.get/brcodePayment.get. Em success → Payable→PAID + PR-int→PAID + cria Transaction (idempotente via findFirst(sourcePayableId)) + dispara sendComprovanteToRequester (agora exportado) + notifica admins. Em failed/denied/canceled → Payable→CANCELLED + PR-int→REJECTED + notifica. Idempotente em concorrência via updateMany WHERE status=AWAITING_DUALSIG. Flags --dry-run e --no-comprovante. Dry-run inicial OK: 9 candidatos, 0 flipados (tudo ainda processing/pending). DAMSP Wilton vai flipar no próximo run após Stark virar success — comprovante sai automático pro Wilton (requesterEmail setado em #73). Real-time tax-payment no webhook Stark — DONE 11/05 (commit 74b8630, bot reiniciado 22:33 UTC; webhook Stark recriado como 4805217291665408 com 9 subs incluindo tax-payment): index.ts roteia tax-payment.success/failed pros mesmos handlers de boleto/utility/brcode; payment-success-match.handler aceita tax-payment no kind union E dispara sendComprovanteToRequester após o flip (só quando efetivamente flipa — skip-if-PAID evita duplicar com payment-request.executed). Cron cron-stark-reconcile fica como safety net pros eventos que o webhook perder. |
| 2026-05-11 | Elie | Studio76 Reels Engine — sistema de geração automática de Reels imobiliários (pasta de fotos + descricao.md → vídeo cinematográfico 9:16 + narração + legendas + thumbnail, 100% automatizado). Stack Python: Claude (roteiro/storyboard/Vision) + provider image-to-video plugável (Veo 3/Grok Imagine/Runway) + ElevenLabs PT-BR + ffmpeg/moviepy. 7 módulos. | P2 | ✅ Detalhado no backlog como item #39 (seção "P2 — Marketing & Conteúdo"). Bloqueado em 5 decisões (provider de vídeo, ElevenLabs sim/não, repo standalone vs comando do bot, fonte de entrada manual vs cache iList, música royalty-free vs trending) + "go" do Elie/Samuel antes de começar o Módulo 1. |
| 2026-05-12 | Elie | /reportar — categoria "corretor externo/autônomo" separada de "Corretores RE/MAX". Hoje summarizeSplits (commissions-ledger.service.ts) classifica qualquer CPF como "Corretores RE/MAX"; uma corretora autônoma externa (ex.: Marilda Soares Antunes Ferreira, deal 1016-275, CPF, CRECI próprio) entra no balde errado. Fix: corretor_id IS NULL && doc.length<=11 → categoria "corretor externo/autônomo" (usa split_receivers.corretor_id da migration v60). Pré-req já pronto. | P3 | Backlog — anotado. Oposto do bug já resolvido (agente interno virando "parceira" via CNPJ da PJ — corrigido 12/05 com migrations v58/v60 + resolveCorretorIdForDoc). |
| 2026-05-19 | Elie | /distrato <corretor> — automação de desligamento (gera distrato DOCX → ClickSign → cancela fee invoices Stark → marca corretor inativo no bot.db → opcional: email RE/MAX HQ p/ cancelar @remax). Gatilho: distrato manual da Célia Navarro hoje quase deixou fee fantasma cobrando. | P2 | Moved to backlog #40 (P2 — RH / Offboarding). Pendente: Samuel enviar template oficial DOCX + processo RE/MAX HQ desconhecido. Quick-win /cancelar-fee antes do flow completo. |
| 2026-05-19 | Elie | /checar-cpf <CPF> <Nome Completo> — DD pessoal pré-CR (vendedor potencial) — Standalone, sem precisar de deal/CR/iList. Roda em paralelo: TJSP-SP, TRF3, TRT2, TRT2-PJe, CNDT, Receita CND PF, CENPROT-SP (7 certidões via Plexi). Devolve em ~2-5 min parecer 🟢/🟡/🔴 + lista de pendências. Custo ~R$60 (igual /dd previa, sem matrícula). | P2 | ✅ DONE 19/05 (mesma sessão). Decisões cravadas: input = CPF + Nome (sem cônjuge/PJ/multi-estado); Option C de persistência (tabela própria cpf_certidoes + hook silencioso de promoção em saveDealParty quando CPF vira VENDEDOR de deal real). Implementação: migration v77 cpf_certidoes (cpf indexado, sem FK pra deals, com promoted_to_deal_code); services/cpf-certidoes.service.ts (runCheckCpf reusa cache <30d, persiste cada cert via callback, classifica 🟢/🟡/🔴/⚠️); handlers/checar-cpf.handler.ts (parser CPF+Nome robusto, progress updates inline); wire em index.ts (cases /checar-cpf /checarcpf) + /ajuda juridico. Hook em deal.manager.saveDealParty promove certidões cacheadas pra pending_certidoes quando o CPF aparece como VENDEDOR de deal real — idempotente via INSERT OR IGNORE em request_id UNIQUE. Risco: judicial positivo → ALTO, cadastral positivo → MÉDIO, tudo negativo → BAIXO, erros → ⚠️. Manual Manual_Bot_Corretores_Studio76.pdf v3 atualizado com card /checar-cpf no top-10 + Fluxo 2 dedicado. Build/lint/smoke test (7/7 cenários, incl. idempotência, reuso 30d, CPF inválido) OK. Commit pendente push (auto-deploy cloudvero). |
| 2026-05-20 | Elie | /cobrar-brinde — cobrança PIX de brindes RE/MAX retirados na recepção com a Yara — Hoje a lojinha de brindes RE/MAX (Cordão R$7,00 · PIN Balão R$15,00 · Chaveiro Casa R$7,50 — "pedido e retirada com Yara") só tem como cobrança o card com PIX CNPJ 31.317.062/0001-55 que o corretor paga na mão: sem rastreio, sem vencimento, sem lembrete; se o corretor esquece, ninguém sabe. Pedido: comando para a Yara registrar a retirada na recepção e o bot cobrar o corretor por PIX, no mesmo molde do fluxo de fotografia. Reusa a infra de Invoice do cobranca-fotografia.service.ts (lookup de CPF do corretor via lookupCorretorCpf/verified_suppliers, criação de Stark Invoice PIX, tags #tipo:reembolso-brinde). Fluxo provável: Yara /cobrar-brinde <corretor> → bot lista os itens com botões de quantidade → bot cria a cobrança. Decisão de modelo pendente (não decidida na triagem 20/05): Invoice formal por retirada vs. conta acumulada mensal vs. só lembrete de PIX — valores são baixíssimos (R$7–15), Invoice por item pode ser overkill. Definir o modelo antes de codar. | P3 | ✅ DONE 20/05 (mesma sessão). Decisões cravadas (Elie): modelo = Invoice por retirada (multi-item); catálogo fixo no código. Implementação: migration v80 brinde_charges (carrinho restart-safe na própria linha do DB); handler src/handlers/cobrar-brinde.handler.ts — /cobrar-brinde <corretor> (aliases /cobrarbrinde, /brinde, /brindes) abre carrinho via List Message (Cordão R$7 · PIN R$15 · Chaveiro R$7,50), Yara escolhe itens nos botões → Finalizar → Confirmar → cria 1 Invoice PIX no Stark (tag #tipo:reembolso-brinde, venc D+15) e manda o link pro WhatsApp do corretor via sendTextOrAlert (sobrevive fora da janela 24h). ACL = administrativa/gerente/Yara. CPF do corretor resolvido por histórico de brindes → split_receivers, ou passado no comando. Wired no index.ts (dispatch + roteamento brinde_* + /ajuda financeiro). typecheck + 8/8 testes + smoke test de parsing/CPF OK. Commit pendente push (auto-deploy cloudvero). |
| 2026-05-20 | Elie | Enriquecimento de leads de vendedores no SmartyDeed via Checkonn + Captei — Plugar duas plataformas externas (Checkonn checkonn.com e Captei captei.com) como fonte/enriquecimento de leads de vendedores no SmartyDeed (repo Laravel/Filament em /home/egk/smarteed — captação que roda antes do CRM/funil). Contexto verificado no código (20/05): o SmartyDeed hoje raspa portais públicos via scrapers Python (só ImovelWeb configurado no .env) → POST /api/scraped-listings/import (header X-Internal-Token) → staging scraped_listings → comando PromoteScrapedListingsToLeads → tabela leads. O gargalo está marcado no próprio código: em ScrapedListing::toLeadPayload() os campos contato_nome/contato_telefone/contato_whatsapp/contato_email levam o comentário "⭐ FOCO DO PROBLEMA" — o anúncio raspado quase nunca traz o contato real do proprietário. É esse buraco que as duas preenchem, e cada uma encaixa num shape diferente: (1) Captei = fonte de leads — centraliza anúncios de todos os portais + descobre proprietário (nome/idade/telefones/e-mails enriquecidos, flag WhatsApp validado); entra como mais uma fonte do /api/scraped-listings/import (portal=captei). (2) Checkonn = passo de enriquecimento — empresa de inteligência de dados; a partir do endereço devolve proprietário (CPF/CNPJ, telefones, WhatsApp, sócios, pessoas/vínculos relacionados, veículos); resolve direto o contato_* do ScrapedListing antes de virar Lead. Pesquisa de custo/API (20/05): Captei — planos R$215,28/mês (corretor) · R$349,30 (imob. pequena) · R$489,30 (média) · R$629,30 (grande); contrato mín. 3 meses; sem API/developer portal público — integração via export Google Sheets/CSV, ou pedir API ao CS (cs@captei.com.br), ou Playwright sobre app.captei.com.br. Checkonn — preço não público (modelo pré-pago/pacote de consultas, consumo via relatórios gerenciais); TEM integração WebService (confirmado no site — vantagem sobre a Captei p/ integração limpa); credencial = usuário/senha em app.checkonn.com; contato comercial comercial@checkonn.com / (11) 5026-8200 / WhatsApp (11) 93398-1627. A triar: docs reais do WebService Checkonn + cotação; se Captei libera API; dedup contra partners/partner_phones (imobiliária ≠ proprietário); como difere de iConatus CAP / Assertiva já em uso; roteamento do lead (StudioLeadReservation + lead-bot #8 / rodízio). Vincula a #9 (CRM próprio), #30 (Captação automatizada), #8 (Lead Bot). | TBD — aguardando fornecedores | E-mails de cotação enviados pelo Elie em 20/05 (comercial@checkonn.com — docs WebService + preço; cs@captei.com.br — se há API + planos imobiliária). Próximo passo: quando responderem, fechar a triagem (prioridade + escopo) e decidir se vira item de backlog próprio ou sub-item de #9/#30. Nota: /home/egk/smarteed é repo Laravel próprio, separado do studio76. |
| 2026-05-13 | Elie | Minisite público por corretor — vitrine HTML + feed Studio76 estendido — URL pública estilo https://gildasioalmeida.remax.com.br/ mas na infra Studio: path por corretor (remaxstudio76.com.br/c/<slug>), noindex (meta robots, header X-Robots-Tag, robots.txt Disallow: / — não aparece no Google/Bing). Vitrine mostra 3 fontes: (a) rascunhos iList sem gestão (com aceite explícito do corretor por imóvel), (b) ativos iList com gestão, (c) off-market via novo /anunciar no bot. "Impulsionar nos portais" = gerador canal-pro-feed/generator.py passa a incluir (a)+(c) além dos ativos iList; tudo sai pelo feed Studio76 único (Canal Pro só aceita 1 URL/conta, confirmado 13/05 via probe Playwright). Reusa canal-pro-feed/ + refresh_ilist_cache.py + dashboard infra (nginx cloudvero + Let's Encrypt). | P2 — pronto pra começar | Bloqueador respondido 13/05 (probe Playwright): Canal Pro = 1 feed XML por conta (campo "URL de Integração" singular, não tem "+ nova integração"). Caminho A escolhido: feed Studio76 único estendido. Decisões fechadas: ✅ escopo XML (ativos + rascunho-sem-gestão autorizado + off-market) · ✅ /anunciar no bot pra off-market (foto + endereço + preço + descrição) · ✅ aceite explícito por imóvel do corretor (não viola "bot não ativa iList") · ✅ slug por corretor · ✅ Canal Pro 1-feed. Em aberto (não bloqueador): confirmar idêntico na CnM (Chaves na Mão) por simetria — provavelmente igual. Risco a mitigar: imóvel sem-gestão sair como anúncio Studio no portal pode confundir branding; mitigação = campo <Username> por agente + descrição padrão "Atendimento direto com o corretor". Esforço: ~8-12 dias (cadastro off-market 2-3d, vitrine HTML pública 3-4d, ext. gerador feed 1-2d, noindex/robots 0.5d, fluxo aceite-publicar 1d). Sinergias: #6 Marketing, #5 Impulsionamento, #30 Captação (rascunhos), #11 Canal Pro Feed. Próximo passo: virar item numerado no backlog P2 (provavelmente #40) na próxima triagem ou agora se Elie aprovar. |
| 2026-05-26 | Elie | /cobrar — pré-check de pré-condições do CCV antes de gerar invoice de comissão — Caso 26/05: Wilson (líder do deal 601301051-32) rodou /cobrar na quitação dos recursos próprios (R$ 397k via PIX), mas a cláusula 6 do CCV diz textualmente "no ato do recebimento total do preço, incluindo-se os recursos provenientes do FGTS" e ainda faltam R$ 103k do FGTS — ou seja, o gatilho contratual da comissão não tinha sido atingido. O bot disparou wizard PIX p/ 6 recebedores, externos foram notificados (DIDU/Rubens), e tudo isso teve que ser revertido com cancel_invoice. Proposta: antes de gerar a invoice, /cobrar puxa do CCV (já temos text_content em deal_documents_text + extrator que detecta cláusula 6) o momento_pagamento (já existe campo no Pipeimob, ex.: "CCV", "Escritura", "Recebimento Total"), os marcos de pagamento (forma_pagamento[] com "Sinal", "Concomitante à escritura", "FGTS", etc.) e pergunta ao corretor: "O CCV diz que a comissão é devida no recebimento total do preço, incluindo FGTS. As parcelas já caíram? · ✅ Sim, todas · ⏳ Só parte (recursos próprios) · ❓ Não sei". Se "Só parte" ou "Não sei", bot mostra o que falta (puxando da timeline Pipeimob/iList ou perguntando) e só prossegue com confirmação explícita ("seguir mesmo assim — assumo o risco"). Mata erro recorrente de cobrança antecipada. Ref: caso Marcelino #a2fe78c (wizard inline quando cobrança já existe) é o padrão de UX a reusar — PersistentPendingMap + botões + handlers. | P2 | Backlog — adicionar item dedicado. Quick-win pode ser apenas mostrar momento_pagamento + parcelas do CCV como preview antes de pedir confirmação final no /cobrar. |
| 2026-05-26 | Elie | /cobrar — editar/cancelar cobrança in-chat (estender wizard fix-in-chat do #a2fe78c) — Hoje, depois que /cobrar gera a invoice, não existe comando user-facing pro corretor cancelar ou editar a cobrança (só admin via MCP cancel_invoice ou Stark Dashboard). O wizard de cobrança-já-existe (commit a2fe78c, caso Marcelino 1075-5) já oferece Cancelar/refazer · Mudar vencimento · Manter quando /cobrar é rodado num deal com invoice ativa — mas o corretor precisa rodar /cobrar de novo pra acessar essas opções. Proposta: comando dedicado /cobranca <deal> (ou /cobrar status <deal>) que mostra a invoice ativa + abre o mesmo wizard de 3 botões (Cancelar · Mudar vencimento · Mudar valor/splits). Bonus: opção Mudar valor (re-extrair do CCV ou ajustar manualmente — usa o splits recomputado), e Mudar pagador (caso comum: comprador paga em vez de vendedor). Pré-req: reusar PersistentPendingMap, starkBankService.updateInvoiceDue, cancelInvoice. Vincular ao pré-check do CCV (item acima) — depois de cancelar, oferecer "rodar /cobrar de novo quando as parcelas caírem?" com agendamento. Caso disparador: 26/05, Wilson teve que pedir admin pra cancelar a invoice 5843718750076928 — sem auto-serviço. | P2 | Backlog. Eu (Elie) cancelei via MCP cancel_invoice nessa sessão; ideal seria Wilson ter feito sozinho via bot. |
| 2026-05-20 | Elie/Samuel | /reembolso — reembolso de despesa paga por sócio — Cupom fiscal pago do bolso por Elie ou Samuel (caso concreto 20/05: NFC-e Kalunga R$450,90, material de escritório — papel, clips, caneta, grampo, pilha, pasta) cai hoje no fluxo proativo de Contas a Pagar (tryProactiveApPreview, index.ts:16624) porque os dois estão em config.financialAdminNumbers/isApRequesterWhitelisted. O Vision lê o cupom, extrai beneficiário=KALUNGA SA / R$450,90 / kind=OUTRO e oferece "✅ Enviar pagamento" — ou seja, o bot ia pagar a loja de novo, sendo que o cupom já está quitado ("FORMA PAGAMENTO: CARTÃO CRÉDITO — VALOR PAGO R$450,90"). Na 2ª tentativa do Elie a imagem foi sequestrada por um wizard de brinde pendente ("2 cordão, 1 chaveiro"). O bot não tem o conceito de reembolso: documento fiscal já pago por um sócio, onde a despesa é da agência mas quem recebe o dinheiro de volta é o sócio, não a loja. Decisões cravadas (Elie/Samuel, AskUserQuestion 20/05): (1) Gatilho = ambos — comando /reembolso explícito (ou legenda "reembolso" na foto) + auto-detecção: quando um sócio manda um cupom fiscal JÁ PAGO, o bot pergunta "isso é reembolso?" em vez de oferecer pagar. (2) Ação = registra despesa + cria PIX — lança a despesa categorizada no ERP e cria o PIX de reembolso pro sócio (dual-sig Stark) na hora. (3) Categoria = bot sugere, sócio confirma — Claude lê os itens do cupom e sugere a categoria do plano s76-*; sócio confirma ou troca por botão. Esboço de implementação: (a) detector de "documento fiscal já pago" no pdf-ap-extractor/Vision — reconhecer NFC-e / "Documento Auxiliar da Nota Fiscal de Consumidor Eletrônica" / SAT / "VALOR PAGO" / "FORMA PAGAMENTO CARTÃO" (≠ boleto a pagar, que tem linha digitável + vencimento futuro); quando o remetente é sócio e o doc é cupom já pago → não ofertar "Enviar pagamento", ofertar o wizard de reembolso; (b) handler novo src/handlers/reembolso.handler.ts (regra anti-monolito) — extrai estabelecimento/CNPJ/valor/data/itens via Vision, Claude sugere categoria s76-*, preview com botões confirma/troca → cria Transaction de despesa categorizada no ERP + PaymentRequest PIX pro sócio (dual-sig) + anexa o cupom no Drive (reusa AttachmentService do #1503); (c) garantir que wizard pendente (brinde/fotografia) não sequestra a imagem de reembolso. Pré-req: chave PIX de Elie e Samuel cadastradas como destino do reembolso. | P2 | ✅ DONE 20/05 (mesma sessão). Migração v82 reembolso_requests (wizard restart-safe). Detector de cupom-já-pago: ExtractedAP ganhou docType+alreadyPaid; o SYSTEM prompt do pdf-ap-extractor reconhece NFC-e/SAT/cupom fiscal como cupom_fiscal/alreadyPaid=true. No tryProactiveApPreview: sócio + cupom já pago → não oferece "Enviar pagamento", chama offerReembolso. Handler novo src/handlers/reembolso.handler.ts: /reembolso (aliases /reembolsar//reembolsos) + legenda "reembolso" + auto-detecção; lê o cupom via Claude Vision (estabelecimento/CNPJ/valor/data/itens), Claude Haiku sugere a categoria do plano s76-desp-* (15 cats verificadas em prod), preview com botões Confirmar/Trocar categoria/Cancelar (lista curada de 10 cats no override). Ao confirmar: registra a chave PIX do sócio (1ª vez — valida via DICT, cria/atualiza Supplier keyado por phone) e cria PaymentRequestInternal+Payable PENDING cujo beneficiário é o próprio sócio, categoria = accountChartId escolhido; botão "💸 Mandar pro pagamento" → /aprovar pagamento N (dual-sig Stark). Wired no index.ts (comando, roteamento reemb_*, texto p/ chave PIX/valor, imagem antes do fluxo AP) + /ajuda financeiro. typecheck + 8/8 testes OK. Follow-up: anexar a foto do cupom no Drive quando o AttachmentService #1503 estiver pronto. Commit pendente push (auto-deploy cloudvero). |
| | | | | |
Tasks agents currently do manually in Pipeimob that the bot can automate.
| # | Task | Current (Pipeimob) | With Bot | Effort | Impact |
|---|---|---|---|---|---|
| 1 | Create new deal | 6-tab web form, 15+ fields | /novavenda wizard (3 msgs) |
✅ Done | High |
| 2 | Upload party documents | Manual upload per document | Send photo → auto-OCR + classify | ✅ Done | High |
| 3 | Track document checklist | Manual spreadsheet / memory | /checklist with auto-status |
✅ Done | High |
| 4 | Run due diligence | Visit 5+ govt portals manually | /dd → automated in 30s |
✅ Done | Very High |
| 5 | Generate CCV contract | Lawyer drafts manually | /gerarccv → 6 templates |
✅ Done | Very High |
| 6 | Collect commission via PIX | Manual bank transfer + tracking | /cobrar → Stark Bank Invoice |
✅ Done | High |
| 7 | Calculate commission split | Excel spreadsheet | /rateio with 6 scenarios |
✅ Done | Medium |
| 8 | Search property listings | Log into Pipeimob portal | /ilist → instant search |
✅ Done | Medium |
| 9 | View sales funnel/pipeline | Pipeimob dashboard | Not built — need /funil |
Medium | High |
| 10 | Schedule property visits | Manual coordination | Not built — need /agendar (QuintoAndar match) |
Low | High |
| 11 | Track financing status | Phone calls + memory | Not built — need /financiamento (QuintoAndar match) |
Low | Medium |
| 12 | AI property search (NLP) | Log into portals manually | Not built — Claude + iList (QuintoAndar QPreco match) | Medium | High |
| 13 | Digital proposal/counter-offer | Phone/email back-and-forth | Not built — structured WhatsApp flow (QuintoAndar match) | Medium | High |
| 14 | Auto-generate listing descriptions | Agent writes manually | Not built — Claude Vision from photos (QuintoAndar match) | Low | Medium |
| 15 | CMA / property valuation | Manual research | Not built — need /avaliar + iConatus API |
Medium | High |
| 16 | DIMOB tax declaration | Pipeimob built-in export | Not built — need export script | High | Medium |
| 17 | Compare market prices | iConatus / manual research | Not built — need iConatus API | High | High |
| 18 | Multi-deal dashboard for CEO | Log into Pipeimob admin | Not built — need /funil |
Low | High |