Commit Graph

401 Commits

Author SHA1 Message Date
Rodribm10
e94cadbdf6 feat(captain): pix_mode manual_static pra Padova e Express
Adiciona caminho paralelo de PIX manual estático pra unidades sem
integração Inter (Padova, Express AL). Mudança 100% aditiva — todas as
outras unidades continuam no fluxo Inter inalterado (default
pix_mode=inter_dynamic aplicado pela migration).

Backend (sem SOUL/SKILL ainda — Frente 7 vem depois):
- Migration concurrent: pix_mode + 4 campos manual_pix_* em captain_units;
  provider + manual_proof_payload + manual_review_reason em captain_pix_charges
- Captain::Unit: enum pix_mode (prefix), validação condicional manual_*
- Captain::PixCharge: status estendido (awaiting_proof, pending_review),
  scope manual/inter, nota interna ramificada por modo
- GeneratePixTool MCP: branch manual_static (chave fixa, mensagem direta
  sem QR/Inter), preserva fluxo Inter intacto
- 4 tools MCP novas: verificar_comprovante_pix (vision gpt-5.3-codex),
  criar_nota_interna (genérica), confirmar_reserva_pix_manual (wrapper
  do ConfirmationService), marcar_reserva_pendente
- ConfirmationService: source_label cobre 'manual_pix_proof'

Próximos passos manuais (não inclusos neste commit):
1. Rodar migration em prod (entrypoint não roda no boot)
2. Seed Padova/Express com pix_mode=manual_static + chaves Stone
3. Deploy nova imagem via docker service update
4. Editar SOUL/SKILL Padova/Express na VPS Hermes + kill+boot

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 16:01:01 -03:00
Rodribm10
5ef59ecc12 fix(captain): captain_unit_id em captain_assistants — fim do lookup quebrado
Captain::Assistant agora aponta direto pra Captain::Unit. Antes a relação
ia via CaptainInbox, mas isso quebrou quando re-apontamos as inboxes pros
Hermes — assistants captain_interno (Juliana, Bianca, Lara, Nina,
Valentina) ficaram SEM CaptainInbox associada e o lookup
unit_for(assistant) retornava nil.

Resultado: get_assistant_pricing(3) (Lara) caía no fallback de scenario
text. Construtor reportava "veio cenário/prompt, não tabela estruturada".

Migration adiciona captain_unit_id (FK opcional). Backfill explícito:
- 1 Juliana → unit 3 (Qnn01)
- 2 Bianca → unit 2 (PrimeAL)
- 3 Lara → unit 2 (PrimeAL — mesmo brand)
- 4 Nina → unit 5 (Express)
- 6 Valentina → unit 4 (Dolce Amore)
- 9 Lara.H → unit 2 (via parent_assistant_id=3)

Tools get_assistant_pricing_tool e save_agent_spec_tool atualizados pra
usar assistant.captain_unit primeiro (nova relação direta), com fallback
pro CaptainInbox se nulo (pra retrocompatibilidade).

Validado live: tool retorna grid markdown com Stilo/Alexa/Hidromassagem
em Seg-Qua + Qui-Dom corretamente.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 12:45:53 -03:00
Rodribm10
22eab86302 fix(captain/mcp): get_assistant_pricing lê do DB + save_agent_spec expande
ROOT FIX (não paliativo) das 3 lacunas que travavam o Construtor:

1. get_assistant_pricing_tool: lia de Captain::Mcp::PricingTables::TABLES
   (hash Ruby) que NÃO EXISTE MAIS desde a migração pra DB. Caía no
   fallback de scenario raw. Refactor: lê de Captain::PricingCategory +
   Captain::PricingAmount, formata grid markdown agrupado por day_bucket.

2. save_agent_spec_tool: Construtor salvava REFERÊNCIAS
   (pricing_source.copied_from_assistant_id) mas hermes-provision script
   espera DADOS EXPANDIDOS (categories[] com amounts, soul_md+skill_md).
   Refactor: tool agora EXPANDE server-side — busca PricingCategory do
   parent, monta categories array, gera SOUL.md (template + identity +
   disclosure_policy) e SKILL.md (template + pricing + rules + identity).
   Output já é spec consumível pelo script.

3. Captain::PricingAmount::PERIODS: adicionado '1h' (Prime tem 1h).

4. Seed pras 3 units faltando: Hotel Recanto (1) + PrimeAL (2) + Qnn01
   (3). Agora os 6 units existentes têm pricing em DB.

Hot-patched ambos tools + USR1 no Puma. Construtor pronto pra criar
Bianca/Juliana etc end-to-end sem intervenção manual.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 12:37:53 -03:00
Rodribm10
7995bc6fe6 feat(captain): pricing em DB + colunas de provisionamento Hermes
Migra a tabela de preços do PricingTables.rb hardcoded pras tabelas
captain_pricing_categories + captain_pricing_amounts no DB. Mantém a
mesma API pública Captain::Mcp::PricingTables.calculate(...) — código
chama o banco via novos modelos Captain::PricingCategory e
Captain::PricingAmount.

Seed db/seed_pricing_tables.rb faz backfill idempotente pra Dolce Amore
(unit 4) e Express (unit 5) com a mesma estrutura que tava no Ruby.

Adiciona em captain_assistants:
- hermes_subscription_secret (gerado pelo script de provisionamento)
- hermes_port (alocado no range 8650-8699)
- parent_assistant_id (link informativo Hermes → captain_interno parent
  pra sombrear FAQs/scenarios via header X-Captain-Assistant-Id)

Adiciona em captain_units: extra_person_fee + currency.

Primeiro milestone do roadmap arquitetural pro Construtor autônomo
(decisões em memory/project_construtor_autonomo_decisions.md).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 09:04:50 -03:00
Rodribm10
3182002bd9 feat(captain): engine column + DB-driven Hermes routing + Express pricing
Marca cada Captain::Assistant com engine ('captain_interno' | 'hermes')
e move o roteamento Hermes do env var pro banco — admin troca engine
re-apontando a inbox no painel, sem deploy. Mantém fallback pras env
vars antigas (CAPTAIN_HERMES_INBOX_IDS etc) durante a migração gradual,
pra não quebrar Valentina antes da re-associação.

Frontend: badge "Hermes" (âmbar) ou "Interno" (cinza) ao lado de cada
assistant no dropdown switcher e no card da listagem, com chaves i18n
em en + pt_BR.

Tabela de preço (pricing_tables.rb): adiciona unit Express (id=5) e
estende a estrutura pra aceitar preço por dia da semana
(mon_wed/thu_sun) — necessário pro Express, retrocompatível com Dolce
Amore (preço único).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 07:54:01 -03:00
Rodribm10
8fab08ba57 fix(captain): regra de pessoa extra do Dolce Amore — taxa a partir da 3ª
Bug reportado por cliente real: "valor extra não é a partir da 3ª pessoa?
Porque aí é para casal, ou seja sempre vai ter duas pessoas".

Cliente está certo. A base do quarto pra casal JÁ INCLUI 2 pessoas; taxa
extra começa na 3ª pessoa, não na 2ª. A documentação anterior (modelo +
skill Hermes + scenario 21 em prod) tinha "a partir da 2ª pessoa", o que
fazia Valentina cobrar extra pra ambos do casal — erro.

Mudanças:
- Texto da regra: "a partir da 3ª pessoa" pra Apartamento/Suítes/Mini
  Chalé 45, com nota explícita "base do quarto já inclui 2 pessoas".
- Exemplo de cálculo refeito: 4 pessoas Suíte Master pernoite sex/sáb =
  180 + (2 × 45) = R$ 270 (era 180 + 3×45 = 315, errado).

Categorias maiores (Chalé 2 Suítes, Suíte Ouro, Chalé Master 4 Suítes)
mantidas como antes (4ª e 8ª pessoa) — Rodrigo precisa revisar essas
separadamente já que cada uma tem capacidade diferente.

Aplicado em 3 lugares:
- db/seed_prompts/_modelos/scenarios/jasmine_dolce_amore__daniela_reservas.md
- /root/.hermes/profiles/valentina/skills/dolce-amore-reservas/SKILL.md
- DB do Captain prod scenario 21 (via update_columns, +363 chars)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 15:52:09 -03:00
Rodribm10
9b8ef5a828 feat(captain): Dolce Amore como nova unidade + handoff silencioso PrimeAL/Dolce
Dolce Amore (Valentina, assistant 6):
- Novo assistant principal + 5 cenários (daniela_reservas, disponibilidade_suites,
  maria_fotos, outras_unidades, reclamacoes_ouvidoria) com tabela de preços
  motel-first (Apartamento, Master, Luxo, Temática, Mini Chalé 45, Chalé 2 Suítes,
  Chalé Master 4 Suítes, Suíte Ouro), regras Inter Pix, e tom adequado a motelaria.
- Cross-reference da Dolce nas 4 outras unidades (Express, PrimeAL, PrimeVL, Qnn01)
  no scenario outras_unidades, com aviso "use só se cliente perguntar por Natal".

Handoff silencioso PrimeAL + Dolce (Bianca + Valentina):
- Mensagem ÚNICA "Um momento." substitui as antigas frases robotizadas
  ("vou te encaminhar pra atendente local...").
- Nova regra "ROTEIE PRO CENÁRIO PRIMEIRO": orquestradora deve sempre tentar
  rotear pra cenário (handoff_to_daniela_reservas, handoff_to_maria_fotos, etc)
  antes de considerar handoff humano.
- Nova regra "NA DÚVIDA, TRANSFERE": após descartar todos os 6 cenários, se a
  pergunta não cabe em nenhum deles, handoff silencioso pra humano.
- Proibição explícita de mencionar nomes de cenário (Daniela, Maria) pro cliente.
- maria_fotos: REGRA #0 — se foto pedida não está na galeria (numeração inexistente,
  característica fora do mapa, área não-suíte), responde "Um momento." + handoff
  em vez de oferecer alternativa.
- daniela_reservas: novo gatilho de handoff "pergunta sobre reserva fora do prompt".

Rollback documentado em docs/captain/rollbacks/2026-05-01_handoff_silencioso.md
com snapshot completo dos prompts ANTES da mudança em prompts_snapshot.json,
permitindo reversão via update_columns.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 11:22:08 -03:00
Rodribm10
1b31e88934 chore(captain): ajustes de unit + migration + schema + seed README
Pequenos ajustes em Captain::Unit (app + enterprise), migration de seed
inicial dos prompts Jasmine/Daniela, schema regenerado, e atualização do
README de seed_prompts pra refletir o estado atual dos modelos.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 11:21:38 -03:00
Rodribm10
c5cd15665e feat(captain): provisionamento automático de Captain::Unit em reserva_hotel.unidades
Hook after_commit on:create no Captain::Unit dispara
ProvisionUnitInSupabaseJob, que upserta a unit em reserva_hotel.unidades
via Supabase REST (UNIQUE on tenant_id+chatwoot_unit_id) e grava IDs no
Captain::Unit (supabase_unit_id, supabase_tenant_id, supabase_marca_id).

Sem isso, criar nova unidade no painel Pix não habilitava roleta — a row
no Supabase ficava ausente e OfferService caía em "tenant não resolvido".

Inclui rake captain:reprovision_unit_in_supabase[id] + provision_all
pra reconciliação manual e migration retroativa.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 00:21:20 -03:00
Rodribm10
6eb7f99ea4 feat(captain): comportamento humano + fix "valores curto" nas 4 Jasmines
Bug raiz observado em conversa real (Rayssa Lorranny / PrimeAL, 25/04 12:44):
- Jasmine alucinou "não tenho a tabela exata por horas aqui neste momento"
- Pediu "qual dia?" quando cliente disse só "Valores" (deveria mostrar tabela completa)
- Mencionou "tabela qui-dom/feriado" entre parênteses na resposta (entrega que é IA)

3 mudanças aplicadas nos 4 daniela_reservas (PrimeAL, PrimeVL, Qnn01, Express):

1. Nova seção "🤖➡️👤 SE COMPORTE COMO HUMANA" no topo, com lista de frases
   proibidas (todas que entregam IA) e exemplos de substituição humana
2. Nova "🚨 REGRA DE OURO — VALORES CURTO" antes de B): cliente disse só
   "valor"/"valores"/"preço" sem especificar → manda tabela completa direto,
   nunca pergunta dia/suíte primeiro
3. 3 proibições novas em "🚫 Proibições": dizer que não tem tabela,
   mencionar "tabela qui-dom/seg-qua" na resposta, responder pergunta com pergunta

Inclui também o questionario_nova_unidade.md já postado no Mattermost top-team.

Refs: análise da conversa Rayssa Lorranny / Operacoes 2026-04-25
2026-04-25 13:52:34 -03:00
Rodribm10
fc2663be2c feat(captain): tabelas de preço corrigidas + sync automático em deploy
- Express: adiciona Singles/Família/Singles Duplo, Master qui-dom 5h, diárias preço único
- Qnn01: renomeia Master→Luxo, remove Pole Dance e 12h, Hidromassagem preço único
- PrimeAL/PrimeVL: estrutura seg-qua + qui-dom, Pernoite Especial Prime, hora excedente
- Adiciona docs/precos/ com tabelas oficiais por marca pra consulta humana
- Implementa rake task captain:sync_prompts lendo de _modelos/
- Liga a task no chatwoot_prepare → sync automático em todo deploy

Refs ROD-14 (Captain Review 2026-04-25)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 10:31:55 -03:00
Rodribm10
c0b54c6783 feat(prompts): modelos de Qnn01, PrimeVL e Express (3 assistants + 15 scenarios)
Some checks failed
Build and Push to GHCR (multi-arch) / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push to GHCR (multi-arch) / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Build and Push to GHCR (multi-arch) / merge (push) Has been cancelled
Gerados usando o modelo validado do PrimeAL como base, adaptando:
- Nome do hotel, suítes, links (WhatsApp/Maps), saudação por unidade
- Tabela de preços específica de cada unidade
- Lista de outras unidades (exclui a própria, inclui as outras 8)
- Observação de atendimento exclusivo por unidade

Particularidades por unidade:
- Qnn01: 4 suítes (Standard/Master/Pole Dance/Hidromassagem), tabela seg-qua + qui-dom, tem 12h
- PrimeVL: 3 suítes (Stilo/Alexa/Hidromassagem), tabela seg-qua + qui-dom-feriado, tem 1h e hora excedente
- Express: 2 suítes (Standard/Master), tabela seg-qua + qui-dom, redireciona pra Prime quando cliente pede hidro

reclamacoes_ouvidoria.md é idêntico nas 4 unidades (framework LAST é universal).

Testado em staging: aplicado nos 3 assistants respectivos, scenarios novos criados (outras_unidades + Reclamacoes_Ouvidoria), FAQs de blocos de prompt deletados, FAQs de preço duplicados removidos. Aguardando validação via WhatsApp real.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:18:13 -03:00
Rodribm10
86bee38474 chore(prompts): reorganiza pastas (_prod_snapshot→_producao_atual, _staging_current→_modelos) e prefixa arquivos por unidade
- Renomeia _prod_snapshot → _producao_atual (refletindo melhor o papel: snapshot do que está rodando hoje em prod, só leitura)
- Renomeia _staging_current → _modelos (modelos aperfeiçoados que vão virar nova prod)
- Todos os arquivos em _modelos/ agora usam o prefixo jasmine_<slug>__ (ex: jasmine_primeal.md), seguindo a mesma convenção já usada em _producao_atual/
- Atualiza README com a nova convenção e checklist de validação por unidade

Isso prepara a estrutura pra adicionar modelos das outras 3 unidades (Qnn01, PrimeVL, Express).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:17:33 -03:00
Rodribm10
b457e84c2f fix(captain): route embeddings to legacy OpenAI + retry transient errors
Resolve duas camadas de problema identificadas em teste end-to-end:

1. Embeddings falhavam com HTTP 404 (/codex/v1/embeddings não existe).
   Solução: Captain::Llm::EmbeddingService sempre usa OpenAI tradicional
   via Llm::Config.with_api_key(legacy_settings). ProviderConfig expõe
   legacy_openai_settings pra isso.

2. Servidor Codex ocasionalmente responde com response.failed +
   code=server_error (instabilidade transitória). Client agora retenta
   até 2x com backoff exponencial (0.5s, 1.5s) em erros retryable:
   HTTP 5xx, server_error no response.failed, ou stream inacabado.

Outras correções nesta etapa:
- Scenario#agent_model: em modo Codex, ignora CAPTAIN_OPEN_AI_MODEL_SCENARIO
  (que pode ter gpt-4o legado) e usa ProviderConfig.model.
- ExtractionService/ContradictionCheckerService/TranslateQueryService:
  trocam constantes hardcoded gpt-4o-mini/gpt-4.1-nano por
  ProviderConfig.light_model (respeitando o provider ativo).
- ProviderConfig.DEFAULT_CODEX_MODEL agora é gpt-5.2 (reconhecido pelo
  RubyLLM; gpt-5.4 não está no catalog do gem).

Validado ponta-a-ponta: WhatsApp → Chatwoot → Jasmine → handoff Daniela
→ faq_lookup com embedding OK → resposta com preços corretos.

Docs em docs/captain-codex-oauth.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:42:31 -03:00
Rodribm10
928b1ec6b9 feat(captain): Codex OAuth auth module + proxy controller
Implementa Fases 1+2 do plano Captain Codex OAuth.

Fase 1 — Auth módulo:
- Migration captain_codex_credentials (tokens AR-encrypted)
- Model Captain::CodexCredential (singleton-ish com .current)
- Captain::Codex::AuthService com device flow completo:
  start_device_login, poll_once, exchange_for_credential,
  valid_access_token (auto-refresh), refresh!
- Rake task captain:codex:{login,status,refresh}
- Sidekiq job Captain::Codex::RefreshTokensJob rodando a cada 30min

Fase 2 — Proxy Chat Completions → Responses:
- Captain::Codex::Translator (chat ↔ responses, tools, tool_calls)
- Captain::Codex::Client (streaming SSE → agregado)
- Api::Internal::CodexProxyController expondo
  POST /codex/v1/chat/completions
- 10 specs do Translator passando

Próximo: Fase 3 (feature flag + fallback) e reconfiguração dos
clientes RubyLLM/Agents/ruby-openai pra apontarem pro proxy quando
CAPTAIN_LLM_PROVIDER=openai_codex_oauth.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 15:07:01 -03:00
Rodribm10
c512e3e5f6 chore(prompts): split prod snapshot from staging from target
Some checks failed
Build and Push to GHCR (multi-arch) / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push to GHCR (multi-arch) / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Build and Push to GHCR (multi-arch) / merge (push) Has been cancelled
Reorganized db/seed_prompts/ into three clear bins:

  _prod_snapshot/   — 16 prompts pulled from iachat_production
                      (4 Jasmines + 12 scenarios). Read-only baseline.

  _staging_current/ — 6 prompts active in iachat-v2 right now
                      (Jasmine + 5 scenarios, including
                      outras_unidades and Reclamacoes_Ouvidoria
                      which were created on this branch).

  target/           — empty for now. Source of truth: the seed
                      migration only writes from here. Files we
                      review and approve land here, then deploy
                      pushes them to prod.

Updated the seed migration to walk target/ and to support both
generic scenarios (apply to every unit) and unit-scoped scenarios
(file prefixed with assistant slug, only that unit). Empty files
are skipped — useful for staged rollouts.

This guarantees no prompt ships to prod by accident: only what
ends up in target/ is applied.
2026-04-22 11:31:42 -03:00
Rodribm10
d0a2688dd2 chore(prompts): snapshot 16 production prompts + dynamic seed migration 2026-04-22 11:24:41 -03:00
Rodribm10
95d3e99652 feat(retention): version the Jasmine + Daniela prompts as seed files
The orchestrator prompt (Jasmine) and scenario instruction (Daniela)
live in the database. When we merge this branch to main and deploy to
production, the prod DB will keep its OLD prompts — the new ones would
only exist in staging. That defeats the point of merging.

Fix: commit the current staging prompts as .md files under
db/seed_prompts/ and add a data migration that syncs them into the DB
on deploy. Idempotent (no-ops when content already matches).

From now on, prompt changes follow the same workflow as code: edit the
.md file, migration resyncs on deploy. The DB row becomes a mirror of
the file, not the source of truth.
2026-04-22 11:00:06 -03:00
Rodribm10
f6488ce2de feat(retention): foundation for customer retention metrics
Lays the data + job foundation for tracking customer interactions,
recurrence, and Pix conversion on Contact. Design decisions negotiated
with Rodrigo (see docs to come):

Rules:
- Gap of 30h from last message defines separate interactions
- Qualified interaction = >=2 customer msgs + >=2 attendant msgs,
  both with textual content (>= 2 letters)
- One-shot consultation = >=1+1 but below the qualified threshold
  (tracked as secondary KPI)
- Excludes contacts labeled `equipe_interna`
- is_recurring = interactions_count >= 2
- pix_generated_count counts all PixCharges; reservations_paid_count
  only counts those with status = paid

Surface area:
- Migration adds denormalized stats to contacts + indexes for fast filtering
- Captain::ContactStats::InteractionCalculatorService computes the stats
  for a single contact (pure, no persistence)
- Captain::Retention::RecalculateContactStatsJob persists them for one
  contact (idempotent)
- Captain::Retention::RecalculateAllContactStatsJob runs daily at 3am BRT,
  enqueues per-contact jobs for everyone active in the last 120 days
- Event-driven refresh: CaptainListener#conversation_resolved enqueues
  recalc; Captain::PixCharge after_create/after_update enqueues recalc
  on status change

No UI yet — that's the next layer.
2026-04-22 09:50:23 -03:00
Rodribm10
cfffea9c16 feat(captain): semantic memory fixes + roleta + reclamações + analytics
Consolida o trabalho desta branch de abril/2026 em um bloco pronto pra
testar em staging antes do merge pra main.

## Correções de memória semântica
- ExtractionService: Princípio Zero + Regra de Ouro (ação consumada vs intenção).
- Cenário Daniela_Reservas: Passo 0 de classificação (consulta/intenção/fora).

## Roleta da Sorte (end-to-end)
- Schema Supabase + 7 RPCs atômicas (server-side, idempotentes).
- Services: Offer, Redeem, WeeklyReport.
- Jobs: OfferRouletteJob (hook em ConfirmationService após Pix pago),
  NotifyRevealed + Scheduler de fallback.
- Tool manual GenerateRoletaLinkTool + endpoint público /roleta/notify.
- Dashboard /captain/roleta com Resgate + Relatório + anomaly detection.

## Cenário Reclamacoes_Ouvidoria
- Triagem P1-P4, framework LAST, Three-level listening, Self-check.
- Sem compensação material, detecção de cliente frustrado eleva prioridade.

## Analytics
- Funil de conversão /captain/funnel: 5 etapas via regex, zero LLM.
- Detector de churn via ChurnOutreach* (cron dias úteis 10h-17h BRT).

## Trabalho pré-existente incluído
- Captain Executive Reports (ceo_digest, mattermost_delivery).
- get_reserva_preco_tool, Lifecycle ajustes, Reservations UI polimentos.

## Outros
- .gitignore: patterns pra credenciais.
- Migrations de scenarios idempotentes.
- i18n completa pt_BR+en pra roleta/funnel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 15:36:25 -03:00
Rodribm10
575af02aff feat(captain-memory): cascade delete memories on account/contact removal (LGPD) 2026-04-18 23:50:14 -03:00
Rodribm10
ca662a528c docs(captain-memory): document intentional omission of secondary FKs 2026-04-18 23:49:21 -03:00
Rodribm10
cae1ae36d6 feat(captain-memory): create captain_contact_memories table with pgvector index 2026-04-18 23:38:23 -03:00
Rodribm10
5639c3ae1d chore(lifecycle): add demo seed script for manual pipeline testing 2026-04-15 09:31:11 -03:00
Rodribm10
1c89ef73ff feat(lifecycle): add captain_lifecycle_* tables and concierge columns on captain_units
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 01:10:49 -03:00
Rodrigo Borba
06ffb93d9c fix(landing-page): update model/schema attributes and eslint warnings
- Add missing visual fields to LandingHosts table
- Add custom_config to permitted landing_host_params
- Fix ESLint warnings causing commit block in LandingHostsConfig.vue
2026-03-03 14:30:06 -03:00
Rodrigo Borba
fe24d381cd feat: configuração de landing pages por domínio e generalização da galeria 2026-03-03 11:19:41 -03:00
Rodrigo Borba
a0fcf37e33 feat(landing): add public LP flow, attribution labels, and report filters 2026-03-02 18:57:22 -03:00
Rodrigo Borba
98252e968a feat: add landing click attribution tracking and stats endpoint 2026-03-02 17:37:28 -03:00
Rodrigo Borba
118f52e239 feat: lead attribution tracking - landing page origin detection
- Cria modelo LeadClick para registrar cliques das landing pages
- Cria modelo LandingHost para mapear hostname → inbox_id
- Endpoint público POST /track/click para receber eventos de clique
- Leads::AttributionMatcherService para correlacionar clique com conversa
- Integração com IncomingMessageWuzapiService para atribuição automática
- API REST para gerenciar LandingHosts por inbox (index/create/destroy)
- UI: nova aba 'Landing Pages' nas configurações da caixa de entrada
- Dashboard API client dedicado (landingHosts.js)
- RuboCop: refatora shift_signature_name, TrackingController, AttributionMatcherService e WuzapiService
2026-03-02 14:40:35 -03:00
Rodrigo Borba
84fff38d94 refactor: move notification templates de units para inboxes
- Arquitetura corrigida: templates agora pertencem à inbox (WhatsApp),
  não à unidade PIX (que é uma config financeira, não de mensagens)
- Migration: troca FK captain_unit_id -> inbox_id (up/down explícito)
- Model: belongs_to :inbox; scope for_inbox
- Controller: escopo via account.inboxes.find(inbox_id)
- Rotas: move de captain/units/:id → inboxes/:id/notification_templates
- Scanner job: joins(:conversation).where(conversations: {inbox_id:})
- UI: página /captain/notifications com seletor de inbox no topo
  (chips clicáveis, templates carregam por watch no selectedInboxId)
- i18n PT/EN: novas keys INBOX_LABEL, SELECT_INBOX_HINT, EMPTY
2026-03-01 22:17:27 -03:00
Rodrigo Borba
44908f32d1 feat: sistema de notificações de reserva com templates configuráveis
- Adiciona check_in_at/duration_hours ao schema do tool CreateReservationIntent
  para que a IA capture o horário EXATO de chegada informado pelo cliente
- Cria captain_notification_templates: label, content, timing_minutes,
  timing_direction (before/after), active, position
- Implementa SendNotificationService com interpolação de variáveis
  (guest_name, check_in_time, check_out_time, suite_name, unit_name)
- Implementa NotificationScannerJob (Sidekiq-cron a cada 5min) com
  janela de tolerância de ±5min e idempotência via metadata JSONB
- API REST: /captain/units/:unit_id/notification_templates (CRUD)
- Store Vuex captainNotificationTemplates + API client
- UI: página de gestão de templates com editor inline e botão '+'
- Configura rota captain_settings_notifications
- i18n PT/EN para todas as strings novas
- Rubocop e ESLint: zero offenses
2026-03-01 21:53:11 -03:00
Rodrigo Borba
c1b8534ea7 feat: Adiciona prompt orquestrador configurável para assistentes Captain com editor UI. 2026-02-27 11:57:59 -03:00
Rodrigo Borba
58f348c98d feat: Implementa funcionalidade de Relatórios Captain, permitindo a geração de insights por caixa de entrada e unidade, com interface de usuário dedicada. 2026-02-27 10:16:53 -03:00
Rodrigo Borba
87bff8126c feat(captain): add AI reports page with insights generation
Implementa a página Relatórios IA com geração de análises semanais
por IA baseadas nas conversas de cada unidade/caixa de entrada.

Funcionalidades:
- Página /settings/captain/reports com dois tabs (Insights IA / Operacional)
- Botão "Gerar Análise" que enfileira job Sidekiq
- Filtro por unidade ou caixa de entrada
- Exibe insights com status (pendente/processando/concluído/falhou)
- Mostra top_topics, ai_failures e period_summary
- Estado vazio com CTA para gerar primeiro relatório

Backend:
- InsightsController com endpoints index/show/generate
- GenerateInsightsJob que processa conversas com LLM
- ConversationInsightService com chunking e merge inteligente
- Migração para adicionar inbox_id à tabela captain_conversation_insights
- Link sidebar "Relatórios IA" em /settings/captain/reports

Frontend:
- Vuex store captainReports com actions/mutations/getters
- API client CaptainReportsAPI (getInsights, generateInsight)
- i18n en e pt_BR para CAPTAIN_REPORTS.*

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 07:05:58 -03:00
Rodrigo Borba
972fc5c67b feat(captain): improve suite photo search accuracy with AI guidance
Melhorias na ferramenta send_suite_images para resolver confusão entre
categoria e número de suíte:

1. **Descrições de parâmetros mais claras**
   - suite_category: exemplos específicos (Hidromassagem, ALEXA, STILO)
   - suite_number: apenas números (101, 102, 103) - remove exemplos confusos

2. **Instruções explícitas no system prompt**
   - Seção [Galeria de Fotos] com regras claras
   - Prioriza suite_category quando ambíguo
   - Evita confirmações desnecessárias com cliente

3. **Mensagens de erro melhoradas**
   - Sugere buscar por categoria quando busca por número falha
   - Feedback mais útil para a IA

Resultado esperado:
- Cliente: "Me manda foto da suite Alexa"
- IA: busca por suite_category="Alexa" ✓ (sem pedir confirmação)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-26 23:04:28 -03:00
Rodrigo Borba
c022f4ce5d feat(units): allow one Pix unit to link to multiple inboxes (N:N) 2026-02-26 21:33:23 -03:00
Rodrigo Borba
0e7dc282c4 chore(style): fix rubocop offenses and update typing indicators 2026-02-25 15:06:58 -03:00
gabrieljablonski
9a4c5058f3 Merge branch 'main' into chore/merge-upstream-4.11.0 2026-02-17 23:05:26 -03:00
Sojan Jose
9eb3ee44a8 Revert "chore: Upgrade Rails to 7.2.2 and update Gemfile dependencies (#11037)"
This reverts commit ef6ba8aabd.
2026-02-03 21:09:42 -08:00
Sojan Jose
ef6ba8aabd
chore: Upgrade Rails to 7.2.2 and update Gemfile dependencies (#11037)
Upgrade rails to 7.2.2 so that we can proceed with the rails 8 upgrade
afterwards
 
 # Changelog
- `.circleci/config.yml` — align CI DB setup with GitHub Actions
(`db:create` + `db:schema:load`) to avoid trigger-dependent prep steps.
- `.rubocop.yml` — add `rubocop-rspec_rails` and disable new cops that
don't match existing spec style.
- `AGENTS.md` — document that specs should run without `.env` (rename
temporarily when present).
- `Gemfile` — upgrade to Rails 7.2, switch Azure storage gem, pin
`commonmarker`, bump `sidekiq-cron`, add `rubocop-rspec_rails`, and
relax some gem pins.
- `Gemfile.lock` — dependency lockfile updates from the Rails 7.2 and
gem changes.
- `app/controllers/api/v1/accounts/integrations/linear_controller.rb` —
stringify params before passing to the Linear service to keep key types
stable.
- `app/controllers/super_admin/instance_statuses_controller.rb` — use
`MigrationContext` API for migration status in Rails 7.2.
- `app/models/installation_config.rb` — add commentary on YAML
serialization and future JSONB migration (no behavior change).
- `app/models/integrations/hook.rb` — ensure hook type is set on create
only and guard against missing app.
- `app/models/user.rb` — update enum syntax for Rails 7.2 deprecation,
serialize OTP backup codes with JSON, and use Ruby `alias`.
- `app/services/crm/leadsquared/setup_service.rb` — stringify hook
settings keys before merge to keep JSON shape consistent.
- `app/services/macros/execution_service.rb` — remove macro-specific
assignee activity workaround; rely on standard assignment handlers.
- `config/application.rb` — load Rails 7.2 defaults.
- `config/storage.yml` — update Azure Active Storage service name to
`AzureBlob`.
- `db/migrate/20230515051424_update_article_image_keys.rb` — use
credentials `secret_key_base` with fallback to legacy secrets.
- `docker/Dockerfile` — add `yaml-dev` and `pkgconf` packages for native
extensions (Ruby 3.4 / psych).
- `lib/seeders/reports/message_creator.rb` — add parentheses for clarity
in range calculation.
- `package.json` — pin Vite version and bump `vite-plugin-ruby`.
- `pnpm-lock.yaml` — lockfile changes from JS dependency updates.
- `spec/builders/v2/report_builder_spec.rb` — disable transactional
fixtures; truncate tables per example via Rails `truncate_tables` so
after_commit callbacks run with clean isolation; keep builder spec
metadata minimal.
- `spec/builders/v2/reports/label_summary_builder_spec.rb` — disable
transactional fixtures + truncate tables via Rails `truncate_tables`;
revert to real `resolved!`/`open!`/`resolved!` flow for multiple
resolution events; align date range to `Time.zone` to avoid offset gaps;
keep builder spec metadata minimal.
- `spec/controllers/api/v1/accounts/macros_controller_spec.rb` — assert
`assignee_id` instead of activity message to avoid transaction-timing
flakes.
- `spec/services/telegram/incoming_message_service_spec.rb` — reference
the contact tied to the created conversation instead of
`Contact.all.first` to avoid order-dependent failures when other specs
leave data behind.
-
`spec/mailers/administrator_notifications/shared/smtp_config_shared.rb`
— use `with_modified_env` instead of stubbing mailer internals.
- `spec/services/account/sign_up_email_validation_service_spec.rb` —
compare error `class.name` for parallel/reload-safe assertions.
2026-02-03 14:29:26 -08:00
Gabriel Jablonski
fb6fec167b
chore: general improvements (#204)
* chore: update scheduled messages author association to nullable and adjust related specs

* chore: update sender handling for WhatsApp messages and add external sender name
2026-02-01 14:25:06 -03:00
Cayo P. R. Oliveira
f9d1146cb0
feat: mensagens agendadas (#198)
* feat:  Adds model for scheduling messages

* feat: Implement scheduled message handling and processing jobs

* feat: Add ScheduledMessagesController and associated specs for managing scheduled messages

* refactor: Simplify scheduled message job specs and improve metadata handling

* feat: Add ScheduledMessagePolicy for managing access to scheduled messages

* feat: Add routes for managing scheduled messages

* feat: Add scheduled message event handling and broadcasting

* feat: Add JSON views for scheduled messages creation, destruction, updating, and indexing

* feat: Update scheduled message status and dispatch update event after message creation

* feat: Ensure scheduled message updates trigger dispatch event

* feat: Add mutation types for managing scheduled messages

* feat: Add additionalAttributes prop to Message component and provider

* feat: Implement scheduled message handling in ActionCable and Vuex store

* feat: Add unit tests for scheduled messages actions and mutations

* feat: implement scheduled messages functionality

- Added support for scheduling messages in the conversation dashboard.
- Introduced new components: ScheduledMessageModal and ScheduledMessages for managing scheduled messages.
- Enhanced ReplyBottomPanel to include scheduling options.
- Updated Base.vue to handle scheduled message styling.
- Integrated Vuex store module for managing scheduled messages state.
- Added necessary translations for scheduled messages in English and Portuguese.

* feat: add pagination to scheduled messages index and update tests accordingly

* chore: update scheduled messages specs for future time validation and response status

* chore: enhance scheduled messages API with pagination and add skeleton loader component

* feat: add create_scheduled_message action to automation rule attributes

* feat: implement create_scheduled_message action and enhance attachment handling

* feat: add scheduled message functionality with UI components and localization

* test: enhance scheduledMessages mutations tests with meta handling and structure

* chore: update label to display file name upon successful upload in AutomationFileInput component

* feat: add initialAttachment prop to ScheduledMessageModal and update ReplyBox to pass attachment

* chore: prepend_mod_with to ScheduledMessagesController for better module handling

* fix: attachment visibility in ScheduledMessageItem component

* chore: enhance ScheduledMessage model with validations and reduce controller load

* refactor: simplify ScheduledMessagesAPI methods by removing unnecessary instance variable

* chore: update event emission for scheduled message creation in ReplyBox and ScheduledMessageModal

* refactor: update status configuration to use label keys

* chore: update date formatting in ScheduledMessageItem component

* refactor: collapse logic to checkOverflow and update related functionality

* chore: add author indication for current user in scheduled messages

* chore: enhance scheduled message metadata with author information and localization

* fix: send message shortcut

* chore: handle errors in scheduled message submission

* chore: update scheduled message modal to use combined date and time input

* chore: refactor scheduled messages handling to remove pagination and update related tests

* fix: ensure scheduled messages update status and dispatch on failure

* fix: update scheduled message due date logic and simplify sending checks

* refactor: rename build_message method for send_message

* fix: update scheduled message creation time and improve test reliability

* chore: ignore unnecessary check

* chore: add scheduled message metadata handling  in message builder, add scheduled message factorie and update specs

* refactor: use scheduled message factorie creation in specs

* chore: streamline error handling in scheduled message job and remove dispatch logic

* fix: change scheduled_messages association to destroy dependent records

* refactor: remove unused attributes from scheduled message payload builder

* chore: update scheduled message retrieval to use conversation association

* chore: correct cron format for scheduled messages job

* chore: remove migration for author_type in scheduled_messages

* feat: enhance scheduled messages management with delete confirmation and error handling

* chore: set cron poll interval to 10 seconds for improved scheduling precision

* feat: include additional_attributes in message JSON response

* feat: enhance scheduled message validation and localization support

* chore: update scheduled message display

* Merge branch 'main' into Cayo-Oliveira/CU-86aenh268/Mensagens-agendadas

* feat: add scheduled message indicators and validation for message length

* fix: remove unnecessary condition from line-clamp class binding

* feat: update scheduled messages localization and enhance content validation

* feat: update scheduled messages order, enhance scheduledAt computation, and add message association

* fix: reorder condition for Facebook channel message length computation

* fix:  change detection for attachments in scheduled messages

* fix: remove unnecessary colon from close-on-backdrop-click prop in ScheduledMessageModal

* chore: add error handling for scheduled message deletion and update localization for delete failure

* fix: enforce minimum delay of 1 minute for scheduled messages and update validation

* fix: remove unused private property and improve locale formatting for scheduled messages

* fix: adjust positioning of DropdownBody in ReplyBottomPanel and clean up schema foreign keys

* docs: add scheduled messages management APIs and payload definitions

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
2026-01-30 22:08:16 -03:00
Pranav
e9e6de5690
fix: Increase the parallelism config to fix flaky tests, revert bad commits (#13410)
The specs break only in Circle CI, we have to figure out the root cause
for the same. At the moment, I have increased the parallelism to fix
this.
2026-01-30 12:49:31 -08:00
Shivam Mishra
6a482926b4
feat: new Captain Editor (#13235)
Co-authored-by: Aakash Bakhle <48802744+aakashb95@users.noreply.github.com>
Co-authored-by: Vishnu Narayanan <iamwishnu@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
Co-authored-by: aakashb95 <aakashbakhle@gmail.com>
2026-01-21 13:39:07 +05:30
gabrieljablonski
6ab1898992 Merge branch 'main' into chore/merge-upstream-4.10 2026-01-16 14:01:53 -03:00
Pranav
a8b302d4cd
feat(ee): Review Notes for CSAT Reports (#13289)
CSAT scores are helpful, but on their own they rarely tell the full
story. A drop in rating can come from delayed timelines, unclear
expectations, or simple misunderstandings, even when the issue itself
was handled correctly.

Review Notes for CSAT let admins/report manager roles add internal-only
context next to each CSAT response. This makes it easier to interpret
scores properly and focus on patterns and root causes, not just numbers.


<img width="2170" height="1680" alt="image"
src="https://github.com/user-attachments/assets/56df7fab-d0a7-4a94-95b9-e4c459ad33d5"
/>


### Why this matters

* Capture the real context behind individual CSAT ratings
* Clarify whether a low score points to a genuine service issue or a
process gap
* Spot recurring themes across conversations and teams
* Make CSAT reviews more useful for leadership reviews and
retrospectives

### How Review Notes work

**View CSAT responses**
Open the CSAT report to see overall metrics, rating distribution, and
individual responses.

**Add a Review Note**
For any CSAT entry, managers can add a Review Note directly below the
customer’s feedback.

**Document internal insights**
Use Review Notes to capture things like:

* Why a score was lower or higher than expected
* Patterns you are seeing across similar cases
* Observations around communication, timelines, or customer expectations

Review Notes are visible only to administrators and people with report
access only. We may expand visibility to agents in the future based on
feedback. However, customers never see them.

Each note clearly shows who added it and when, making it easy to review
context and changes over time.
2026-01-15 19:53:57 -08:00
Shivam Mishra
7b51939f07
fix: country_code should be checked against the contact (#13186) 2026-01-13 14:47:27 +05:30
Tanmay Deep Sharma
e58600d1b9
fix: the webhook url to be text (#13157)
## Description
Change the url type from string to text, to support more than 255
characters

Fixes # (issue)
https://app.chatwoot.com/app/accounts/1/conversations/65240

## Type of change

Please delete options that are not relevant.

- [ ] Bug fix (non-breaking change which fixes an issue)


## Checklist:

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
2026-01-06 15:23:54 +05:30
gabrieljablonski
549214e96d Merge branch main into chore/merge-upstream 2025-12-20 12:44:31 -03:00