Import ClientFlow production v4928.1.5.132.4

This commit is contained in:
plx
2026-07-29 13:11:01 +00:00
parent 6445044ac6
commit 261d342057
405 changed files with 48373 additions and 1401 deletions

View File

@@ -0,0 +1,19 @@
# ClientFlow v4928.1.4.4 — Outbox schema compatibility hotfix
Fixes Jasmin outbox worker failures on upgraded installs where the existing
`integration_outbox` table lacked columns selected by the current worker,
notably `sent_at`.
Changes:
- `ensure_core_schema()` now adds all worker/UI outbox columns with `IF NOT EXISTS`.
- `scripts/process_outbox.py` calls `init_db()` before claiming pending items.
- Adds `migrations/005_outbox_schema_compatibility.sql` for manual repair.
Manual repair command:
```bash
sudo -u postgres psql -d clientflow -f migrations/005_outbox_schema_compatibility.sql
```
Then restart/process the Jasmin worker.

View File

@@ -0,0 +1,119 @@
# ClientFlow v4928.1.4.9 — Opportunity Reply Assistant
## Objetivo
Reduzir o atrito entre ClientFlow e Chatwoot. O operador passa a gerar e enviar mensagens comerciais a partir da tarefa, usando modelos e anexos já ligados à oportunidade.
O Chatwoot continua a ser o canal técnico de envio, mas o ClientFlow passa a ser o cockpit operacional.
## O que foi adicionado
### Modelos de mensagem
Novo catálogo em `app/message_templates.py`:
- `SEND_INFO_EQUIPMENT_LIST`
- `SEND_PRICE_LIST`
- `SEND_QUOTE`
- `SEND_PROFORMA`
- `SEND_INVOICE`
- `REQUEST_FISCAL_DATA`
- `REQUEST_PAYMENT_PROOF`
- `CONFIRM_PAYMENT_RECEIVED`
- `FOLLOW_UP_QUOTE`
Os modelos são determinísticos e editáveis antes do envio.
### Serviço de resposta
Novo serviço `app/reply_assistant_service.py`:
- carrega tarefa, oportunidade e documentos associados;
- escolhe modelo por ação;
- gera rascunho editável;
- valida prontidão antes de enviar;
- bloqueia anexos que não pertencem à oportunidade;
- envia mensagem pública no Chatwoot;
- regista comunicação outbound;
- regista evento na timeline;
- pode concluir a tarefa após envio.
### UI na tarefa
A página da tarefa ganhou o bloco **Resposta ao cliente**:
- seletor de modelo;
- seleção de anexos da oportunidade;
- botão **Gerar rascunho**;
- textarea editável;
- botão **Enviar**;
- botão **Enviar e concluir tarefa**.
### Chatwoot
`app/chatwoot_client.py` ganhou:
- `send_public_message()`;
- `send_public_message_with_attachments()`.
O envio continua protegido por:
```env
CHATWOOT_WRITE_ENABLED=true
CHATWOOT_BASE_URL=...
CHATWOOT_ACCOUNT_ID=...
CHATWOOT_API_TOKEN=...
```
### Auditoria
Foi adicionada a tabela `message_drafts` para guardar rascunhos gerados e estado do envio.
Cada envio cria também um registo em `communications` com:
- `direction = outbound`;
- `source_system = chatwoot`;
- `conversation_id`;
- `task_id`;
- `opportunity_id`;
- `metadata.template_code`;
- `metadata.attachments`;
- `metadata.chatwoot_result`.
### Timeline
Ao enviar uma mensagem, o ClientFlow cria um evento `reply_sent` na timeline da oportunidade.
## Regras de segurança
- Um documento só pode ser anexado se pertence à mesma oportunidade da tarefa.
- Envio de documentos fiscais exige cliente fiscal minimamente preenchido.
- Documentos sem `external_id` não são anexados automaticamente.
- Nesta versão, PDF automático está limitado a documentos Jasmin suportados pelo serviço existente: `quotation` e `invoice`.
- O LLM não é usado para decidir preço, documento ou anexo.
## LLM
Foi adicionada a opção:
```env
CLIENTFLOW_REPLY_LLM_ENABLED=false
```
Nesta versão fica desativada. A arquitetura fica preparada para uma versão seguinte onde o LLM apenas adapte o texto, mantendo oportunidade/documentos como fonte de verdade.
## Endpoints novos
```http
POST /tasks/{task_id}/reply-draft
POST /tasks/{task_id}/send-reply
```
## Rollback
A alteração é aditiva. Para rollback funcional:
1. manter `CHATWOOT_WRITE_ENABLED=false` para bloquear envio;
2. remover/ignorar o bloco UI de resposta;
3. a tabela `message_drafts` pode permanecer sem afetar o fluxo antigo.

View File

@@ -0,0 +1,100 @@
# ClientFlow v4928.1.5.0 — BLIF Knowledge Reply Assistant
## Objetivo
Adicionar o caminho realista para respostas comerciais melhores sem fine-tuning: conhecimento BLIF estruturado, recuperação por tópico, geração LLM opcional via OpenRouter e validação comercial antes do envio.
A versão mantém o operador no controlo: o sistema gera um rascunho editável e só envia para Chatwoot quando o operador confirma.
## O que mudou
- Base de conhecimento BLIF estruturada em `app/business_knowledge/blif_knowledge.json`.
- Recuperação determinística de tópicos por palavras-chave em `app/business_knowledge_service.py`.
- Novos modelos de esclarecimento sem anexo, incluindo instalação, IVA, entrega/pagamento, RFID, balanceador, histórico local, condomínio/MOBI.E e funcionalidades técnicas.
- Seleção automática de template de conhecimento quando a última mensagem do cliente corresponde a um tópico BLIF.
- Geração LLM opcional via OpenRouter em `app/llm_reply_generator.py`.
- Validador comercial em `app/reply_safety_validator.py` para bloquear riscos como “BLIF faz instalação” ou “instalação incluída” sem prova documental.
- UI da tarefa mostra o conhecimento usado, tipo de resposta e estado do LLM.
## Fluxo
```text
Tarefa / oportunidade
→ mensagem do cliente
→ recuperar conhecimento BLIF relevante
→ escolher template seguro sem anexo quando aplicável
→ opcionalmente pedir ao LLM para adaptar a redação
→ validar resposta
→ operador edita/confirma
→ ClientFlow envia no Chatwoot e regista timeline/communication
```
## Exemplo — Varisom
Mensagem do cliente:
```text
Presumo que o valor é sem instalação, pode por favor confirmar?
```
Antes:
```text
SEND_QUOTE → exige orçamento/anexo → bloqueia por falta de documento
```
Agora:
```text
Tópico detetado: instalação / âmbito do preço
Template: CLARIFY_INSTALLATION_SCOPE
Anexo: não necessário
Resposta: confirmar que o valor é do equipamento, sem instalação incluída, e indicar eletricista qualificado + suporte remoto
```
## Variáveis de ambiente
```env
CLIENTFLOW_REPLY_LLM_ENABLED=false
CLIENTFLOW_REPLY_LLM_MODEL=
CLIENTFLOW_REPLY_LLM_TEMPERATURE=0.2
CLIENTFLOW_REPLY_LLM_MAX_TOKENS=700
CLIENTFLOW_REPLY_LLM_TIMEOUT_SECONDS=20
CLIENTFLOW_REPLY_LLM_MAX_CONTEXT_CHARS=5000
OPENROUTER_API_KEY=...
OPENROUTER_MODEL=qwen/qwen3-30b-a3b
```
Com `CLIENTFLOW_REPLY_LLM_ENABLED=false`, o sistema continua a gerar rascunhos úteis com templates e conhecimento BLIF, sem chamada externa.
## Segurança comercial
O LLM, quando ativado, só adapta o texto. Não escolhe documentos, não decide preços finais, não confirma stock e não envia automaticamente.
O backend valida:
- documentos selecionados pertencem à oportunidade;
- mensagens com instalação incluída são bloqueadas se não houver prova;
- mensagens que sugerem instalação direta pela BLIF são bloqueadas;
- preços desconhecidos geram aviso;
- prazos devem ficar associados a confirmação de pagamento;
- valores com IVA sem documento geram aviso.
## Limites conhecidos
- A recuperação de conhecimento é por palavras-chave, não vector search. É suficiente para esta fase e transparente para validação.
- Não há fine-tuning.
- Preços e regras devem ser revistos/versionados quando mudarem.
- Stock, descontos e condições especiais continuam fora do LLM.
## Próximo passo recomendado
Criar um `Agent Builder TUI` apenas para administração/teste do conhecimento:
```text
- importar/editar conhecimento BLIF
- testar perguntas reais
- aprovar/rejeitar respostas
- versionar regras
- preparar exemplos para avaliação futura
```

View File

@@ -0,0 +1,32 @@
# ClientFlow v4928.1.5.13 — Atualização do detalhe da task após enviar e concluir
## Problema
No detalhe da task, ao usar **Enviar e concluir tarefa**, a mensagem era enviada e a task podia ser concluída na BD, mas a página continuava a mostrar o cabeçalho antigo, por exemplo:
- `Enviar proposta/cotação`
- `Pendente`
- `COMERCIAL`
- `85% confiança`
- `SEND_QUOTE`
Isto acontecia porque o formulário do assistente de resposta usava `hx-target="#reply-assistant-panel"`, atualizando apenas o bloco da resposta.
## Correção
O formulário de envio passa a usar `hx-target="#task-detail-panel"` e, em caso de sucesso, a rota `/tasks/{task_id}/send-reply` devolve `render_task_detail_partial(...)`.
Assim, depois de **Enviar e concluir tarefa**, todo o detalhe da task é re-renderizado com o estado atual da BD.
## Erros
Em caso de erro de validação/envio, a resposta HTMX usa:
- `HX-Retarget: #reply-assistant-panel`
- `HX-Reswap: outerHTML`
para manter o erro local ao painel da resposta.
## Migração
Não requer migração de base de dados.

View File

@@ -0,0 +1,54 @@
# Follow-ups semi-automáticos no Clientflow
## Regra de produto
O follow-up de uma oportunidade ativa deve ser semi-automático:
> O sistema cria a tarefa, calcula a data e sugere a mensagem. O operador decide se envia, adia, conclui ou fecha o processo.
Isto evita dois problemas:
- follow-up 100% manual: oportunidades esquecidas;
- follow-up 100% automático: risco de mensagens erradas, fora de contexto ou duplicadas.
## Como funciona
### Criação automática
Após conclusão de ações comerciais, o backend cria tarefas internas de follow-up:
| Ação concluída | Follow-up criado | Prazo |
|---|---|---:|
| `SEND_QUOTE` | `FOLLOW_UP_QUOTE` | 3 dias |
| `SEND_PROFORMA` | `FOLLOW_UP_PROFORMA` | 2 dias |
| `SEND_INVOICE` | `FOLLOW_UP_PAYMENT` | 3 dias |
| `SEND_INFO` | `FOLLOW_UP_CUSTOMER_REVIEW` | 5 dias |
### Criação manual
Na página da oportunidade, o operador pode criar um follow-up manual quando o contexto comercial justificar.
### Fecho automático
Quando entra nova atividade do cliente associada à oportunidade, os follow-ups pendentes dessa oportunidade são concluídos para evitar duplicação.
### Cancelamento automático
Quando a oportunidade é fechada como ganha, perdida ou sem interesse, os follow-ups pendentes são cancelados.
## UI esperada
Na página de tarefas:
- `Follow-ups`: todos os follow-ups pendentes;
- `Follow-ups vencidos`: follow-ups com `due_at` passado;
- detalhe da tarefa: mensagem sugerida, prazo e ações de adiamento.
Na oportunidade:
- bloco lateral para criar follow-up manual;
- timeline/eventos com criação, conclusão ou cancelamento do follow-up.
## Limite intencional
Esta versão não envia emails automaticamente. O campo `safe_to_post` das ações de follow-up fica sempre `false`.

View File

@@ -0,0 +1,131 @@
# ClientFlow v4928.1.5.1 — Task Reply Audit
Esta versão adiciona um script operacional para auditar todas as tarefas e comparar, para cada uma, o pedido do cliente com a resposta sugerida pelo `Reply Assistant`.
## Objetivo
Permitir rever em lote se o assistente está a interpretar corretamente:
- o pedido real do cliente;
- o `action_code` atual da tarefa;
- o template/modelo escolhido;
- o conhecimento BLIF usado;
- a resposta sugerida;
- bloqueios e avisos antes de envio.
O script é **read-only** por defeito: não envia mensagens, não conclui tarefas e não cria rascunhos persistentes.
## Script
```bash
python scripts/audit_task_reply_suggestions.py --status all --format markdown --out /tmp/task_reply_audit.md
```
Ficheiro:
```text
scripts/audit_task_reply_suggestions.py
```
## Exemplos
Auditar todas as tarefas pendentes:
```bash
python scripts/audit_task_reply_suggestions.py \
--status pending \
--format markdown \
--out /tmp/clientflow_task_reply_audit.md
```
Auditar todas as tarefas e exportar CSV:
```bash
python scripts/audit_task_reply_suggestions.py \
--status all \
--format csv \
--out /tmp/clientflow_task_reply_audit.csv
```
Auditar apenas tarefas comerciais:
```bash
python scripts/audit_task_reply_suggestions.py \
--status pending \
--route comercial \
--format markdown
```
Testar com LLM/OpenRouter ativo:
```bash
python scripts/audit_task_reply_suggestions.py \
--status pending \
--use-llm \
--format markdown
```
> Por defeito, o script força `CLIENTFLOW_REPLY_LLM_ENABLED=false` para evitar custos e variação de resultados. O LLM só é usado com `--use-llm`.
## Campos do relatório
Cada tarefa inclui:
- Task ID;
- estado/fila;
- cliente/contacto;
- conversa Chatwoot;
- action code;
- template escolhido;
- tipo de resposta;
- conhecimento BLIF usado;
- anexos selecionados;
- pedido do cliente;
- resposta sugerida atual;
- resposta sugerida anterior da preparação, quando existir;
- bloqueios;
- avisos.
## Segurança operacional
Por defeito o script usa:
```text
persist=False
CLIENTFLOW_REPLY_LLM_ENABLED=false
```
Isto significa que o teste não altera estado operacional. Para gravar `message_drafts` de auditoria, usar explicitamente:
```bash
--persist-drafts
```
## Requisitos
Executar no backend ClientFlow com `.env` ou `DATABASE_URL` definido.
```bash
cd /caminho/clientflow_backend
python scripts/audit_task_reply_suggestions.py --status pending
```
Se não existir `OPENROUTER_API_KEY`, o script define um valor interno `not-used-by-task-reply-audit` quando o LLM está desligado, porque o `app.config` exige essa variável.
## Utilidade para afinar o agente
Este relatório é útil para encontrar casos como:
```text
Cliente pergunta: “o valor inclui instalação?”
Tarefa atual: SEND_QUOTE
Resposta esperada: esclarecimento sem anexo
```
A partir do relatório é possível identificar onde faltam:
- regras de conhecimento BLIF;
- templates específicos;
- intents/subtipos;
- dados na oportunidade;
- documentos associados.

View File

@@ -0,0 +1,111 @@
# ClientFlow v4928.1.5.3 — Intent Gate & Reply Safety Fix
## Objetivo
Corrigir os falsos positivos encontrados pela auditoria de respostas sugeridas (`audit_task_reply_suggestions.py`), onde bounces, pedidos de remoção, respostas sem interesse e casos de suporte podiam cair em templates comerciais como lista de equipamentos.
## Alterações principais
### 1. ReplyIntentGate
Novo módulo:
```text
app/reply_intent_gate.py
```
Classifica a natureza da mensagem antes de escolher template ou conhecimento BLIF:
- `BOUNCE_EMAIL`
- `UNSUBSCRIBE_REQUEST`
- `ADDRESS_UPDATE`
- `NO_INTEREST`
- `SUPPORT_INCIDENT`
- `COMMERCIAL_CLARIFICATION`
- `VAT_CLARIFICATION`
- `DELIVERY_PAYMENT`
- `RFID_QUESTION`
- `LOAD_BALANCER_QUESTION`
- `CONDOMINIUM_MOBIE`
- `INVOICE_REQUEST`
- `COMMERCIAL_REQUEST`
- `CALLBACK_REQUEST`
- `MANUAL_REVIEW`
### 2. Fallback comercial mais seguro
`SEND_INFO` e `REVIEW_MANUALLY` deixaram de cair por defeito em `SEND_INFO_EQUIPMENT_LIST`.
Novo fallback:
```text
MANUAL_REVIEW_REQUIRED
```
Isto evita enviar lista de equipamentos quando a intenção não está clara.
### 3. Templates operacionais/não comerciais
Novos templates:
- `INTERNAL_BOUNCE_EMAIL`
- `ACK_UNSUBSCRIBE`
- `ACK_ADDRESS_UPDATE`
- `ACK_NO_INTEREST`
- `ACK_SUPPORT_RECEIVED`
- `ACK_CALLBACK_REQUEST`
- `MANUAL_REVIEW_REQUIRED`
### 4. Correção do caso Varisom / instalação
O validador agora permite frases aprovadas como:
```text
sem instalação incluída
A BLIF não presta serviço direto de instalação
qualquer eletricista qualificado
suporte remoto ao eletricista
```
E continua a bloquear promessas incorretas como:
```text
instalação incluída
A BLIF faz a instalação
instalação gratuita
```
### 5. Auditoria melhorada
O script `scripts/audit_task_reply_suggestions.py` passa a mostrar:
- `intent_category`
- `intent_label`
- `intent_reasons`
- contagem por intenção no resumo
- se a resposta comercial foi permitida pela triagem
## Uso recomendado
Depois de instalar a versão, correr:
```bash
cd /mnt/ssd/home/plx/clientflow_backend
python scripts/audit_task_reply_suggestions.py --status pending --format markdown --out /tmp/task_reply_audit_v153.md
```
Ou comparar todos os estados:
```bash
python scripts/audit_task_reply_suggestions.py --status all --format markdown --out /tmp/task_reply_audit_v153_all.md
```
## Segurança
O script continua read-only por defeito:
- não envia mensagens;
- não conclui tarefas;
- não cria rascunhos persistentes;
- não ativa OpenRouter/LLM salvo `--use-llm`.

View File

@@ -0,0 +1,25 @@
# ClientFlow v4928.1.5.41 — workflow anomaly fixes
Correções focadas nas anomalias funcionais encontradas pelos testes `workflow_anomaly_hunt` e `workflow_anomaly_hunt_v2`.
## Corrigido
- Normalização de email em clientes: `trim + lower`, com reutilização lógica da ficha existente quando não há NIF.
- Validação simples de email inválido ao criar/editar cliente.
- Bloqueio de regressões perigosas de estado: oportunidades `WON/LOST/NO_INTEREST` não regressam para fases comerciais sem reabertura explícita.
- Fecho automático de tarefas pendentes incompatíveis quando a oportunidade passa a estado terminal.
- Bloqueio operacional com HTTP 409 em ações incompatíveis com o estado da oportunidade.
- Idempotência de tarefas repetidas por fingerprint da mensagem, evitando múltiplos `SEND_QUOTE` pendentes para o mesmo pedido repetido.
- Follow-ups limitados a uma janela operacional segura: 1 a 30 dias.
- Webhook Chatwoot incompleto passa a devolver 422 em vez de aceitar payload vazio/incompleto.
- Validação de produtos e linhas de oportunidade: preços/quantidades negativas ou inválidas são recusados.
- Runner `workflow_anomaly_hunt_v2` ajustado para não falhar na fase documental e para reconstruir reconciliação após seed documental.
## Comandos de validação recomendados
```bash
./e2e_test_lab/scripts/run_e2e_lab.sh | tee e2e_test_lab/latest_e2e_run.log
./e2e_test_lab/scripts/run_deep_e2e_lab.sh | tee e2e_test_lab/latest_deep_e2e_run.log
./e2e_test_lab/scripts/run_workflow_anomaly_hunt.sh | tee e2e_test_lab/latest_workflow_anomaly_run.log
./e2e_test_lab/scripts/run_workflow_anomaly_hunt_v2.sh | tee e2e_test_lab/latest_workflow_anomaly_v2_run.log
```

View File

@@ -0,0 +1,31 @@
# ClientFlow v4928.1.5.42 — Financial conflict guard
Esta versão fecha a última anomalia funcional detetada no Workflow Anomaly Hunt v2.
## Correção
Quando vários documentos do mesmo cliente/processo têm valores claramente divergentes, o candidato de reconciliação passa a expor explicitamente:
- `review_status = conflict`
- `financial_conflict = true`
- `amount_conflict_values = [...]`
- risco: `conflito financeiro: valores divergentes entre documentos`
- risco: `bloquear auto-associação financeira até revisão`
Isto evita que comprovativos, faturas, orçamentos ou vendas Odoo com valores diferentes sejam tratados como sequência limpa do mesmo processo.
## Teste atualizado
O runner `workflow_anomaly_hunt_v2` deixa de considerar a simples existência de valores diferentes como anomalia se o backend expuser um conflito financeiro claro no processo candidato.
Resultado esperado após aplicar:
```text
Workflow Anomaly Hunt v2
Anomalias funcionais: 0
```
## Ficheiros alterados
- `app/reconciliation_service.py`
- `e2e_test_lab/tests/workflow_anomaly_hunt_v2.py`

View File

@@ -0,0 +1,10 @@
# ClientFlow v4928.1.5.44 — Final hardening pass
Correções focadas nos achados restantes do Failure Hunt:
- marcador CSRF visível em forms POST/HTMX da UI administrativa;
- confirmação explícita na sincronização de produtos Odoo;
- validação defensiva em criação/edição de produtos;
- validação de email e dados mínimos na criação manual de oportunidade a partir de cliente;
- autocomplete controlado nos campos sensíveis do pedido externo;
- calibração do Failure Hunt para não tratar filtros GET como mutações.

View File

@@ -0,0 +1,14 @@
# ClientFlow v4928.1.5.45 — Playwright UI auth fix
Corrige o runner Playwright UI para usar o mesmo `CLIENTFLOW_ADMIN_TOKEN` dos testes HTTP.
## Sintoma
O Deep Audit HTTP estava verde, mas `RUN_PLAYWRIGHT_UI=1` falhava com `HTTP 401` em todas as páginas.
## Correção
- `playwright_ui_journey.py` passa `X-ClientFlow-Admin-Token` no contexto do browser.
- `run_deep_e2e_lab.sh` e `run_ui_e2e_playwright.sh` passam explicitamente `--admin-token "${CLIENTFLOW_ADMIN_TOKEN:-}"`.
Não altera regras de negócio nem backend.

View File

@@ -0,0 +1,17 @@
# ClientFlow v4928.1.5.47 — Playwright CORS/Auth fix
## Problema
O runner Playwright usava `extra_http_headers` para enviar `X-ClientFlow-Admin-Token`.
Esse header era enviado também para assets externos, como Bootstrap Icons em `cdn.jsdelivr.net`.
O browser fazia preflight CORS e o CDN bloqueava o pedido das fontes.
## Correção
O runner passou a adicionar `X-ClientFlow-Admin-Token` apenas a pedidos same-origin do ClientFlow.
Pedidos externos para CDN deixam de receber o header administrativo.
## Nota produção
Se `https://clientflow.blif.pt` ainda bloquear Bootstrap/HTMX por CSP, a instância pública ainda não tem a CSP da v1.5.46+ ou o Nginx está a sobrescrever o header.
A CSP esperada deve permitir explicitamente `https://cdn.jsdelivr.net` e `https://unpkg.com`, ou os assets devem ser servidos localmente.

View File

@@ -0,0 +1,20 @@
# ClientFlow v4928.1.5.48 — Reply assistant instruction_hidden fix
Fixes a production-visible task detail error in the reply assistant panel:
`Assistente indisponível: name 'instruction_hidden' is not defined`
## Cause
The legacy/eager reply assistant panel rendered `{instruction_hidden}` in the send form, but the variable was only defined in the newer lazy/persistent draft panel.
## Fix
`app/admin_ui/pages/tasks.py` now defines `operator_instruction` and `instruction_hidden` before rendering the legacy reply assistant panel. Missing instructions are safely represented as an empty hidden input.
## Impact
- No database migration.
- No destructive action.
- Affects task detail rendering only.
- Restores the editable reply panel for support/reply tasks.

View File

@@ -0,0 +1,102 @@
# ClientFlow v4928.1.5.4 — LLM-first Reply Assistant
## Decisão arquitetural
A abordagem anterior estava a crescer como uma árvore de regras e exceções. Esta versão muda o centro de decisão:
```text
Antes:
mensagem → regras/intents → template
Agora com LLM ativo:
mensagem limpa → guardrails objetivos → contexto + conhecimento BLIF → LLM → validação → operador
```
As regras deixam de tentar interpretar todos os casos comerciais. Passam a servir apenas para proteger situações objetivas onde a resposta ao cliente deve ser evitada ou controlada.
## Fluxo
```text
Task/Oportunidade
MessageCleaner
Guardrails objetivos
BusinessKnowledgeRetriever
OpenRouter LLM
ReplySafetyValidator
Rascunho editável na UI
```
## Guardrails objetivos
Apenas estes casos preemptam o LLM:
- `BOUNCE_EMAIL`
- `AUTO_REPLY`
- `UNSUBSCRIBE_REQUEST`
- `ADDRESS_UPDATE`
Tudo o resto deve ser interpretado pelo LLM quando `CLIENTFLOW_REPLY_LLM_ENABLED=true`.
## LLM como interpretador
O LLM recebe:
- mensagem limpa do cliente;
- dados do cliente;
- estado/action da tarefa;
- documentos selecionados;
- conhecimento BLIF recuperado;
- catálogo de produtos/acessórios;
- instruções de segurança.
E deve devolver JSON estruturado com:
```json
{
"intent": "technical_datasheet_request",
"reply_type": "answer_with_links_or_attachment",
"requires_attachment": true,
"confidence": 0.86,
"customer_need": "Cliente pediu fichas técnicas dos carregadores.",
"recommended_next_action": "Selecionar/anexar ficha técnica antes de enviar.",
"message_body": "Olá...",
"knowledge_used": ["technical_features"],
"warnings": []
}
```
## Fallback
Se LLM estiver desligado:
- o sistema usa o gate determinístico existente;
- evita fallback agressivo para lista de equipamentos;
- prefere revisão manual quando incerto.
Se LLM estiver ligado mas falhar numa resposta `LLM_BUSINESS_REPLY`:
- a sugestão fica bloqueada;
- a tarefa deve ser revista manualmente;
- nenhuma resposta genérica é considerada segura.
## Uso do assistente ChatGPT existente
Um GPT personalizado do ChatGPT não é chamado diretamente pelo backend. O caminho correto é migrar o conhecimento/instruções desse GPT para a base interna do Clientflow:
```text
Custom GPT / Assistente de e-mails
exportar instruções + ficheiros + exemplos aprovados
app/business_knowledge/
OpenRouter/API no backend
```
Assim o conhecimento fica versionado, auditável e combinado com oportunidade, documentos e validações reais.

View File

@@ -0,0 +1,31 @@
# ClientFlow v4928.1.5.50 — Correção manual de associações Odoo/Jasmin
## Objetivo
Quando a reconciliação automática associa uma oportunidade ao Odoo/Jasmin errado, o operador precisa de uma forma segura de desfazer a ligação local sem alterar sistemas externos.
## Inclui
- Novo painel na oportunidade: **Corrigir associação operacional**.
- Permite desassociar Odoo, Jasmin e remover linhas importadas Odoo/Jasmin.
- Permite classificar a oportunidade após a correção, por defeito como **Informação enviada** (`INFO_SENT`).
- Adiciona botões diretos:
- `Desassociar Odoo` no painel Odoo.
- `Desassociar Jasmin` no painel Documentos Jasmin.
- `Ignorar` em candidatos externos Odoo/Jasmin.
- Regista auditoria em `opportunity_events`.
- Não apaga nem altera nada em Odoo, Jasmin ou Chatwoot.
## Comportamento
A correção remove apenas leitura local ClientFlow:
- `operation_links` Odoo/Jasmin da oportunidade.
- `commercial_documents` Jasmin ligados à oportunidade.
- `opportunity_items` importados de Odoo/Jasmin.
- `reconciliation_items` Odoo/Jasmin ligados passam para revisão manual ou ignorados.
- A oportunidade fica na fase escolhida pelo operador.
## Caso que motivou
Oportunidade associada a venda Odoo `S00285` e candidatos Jasmin de outros clientes, mas o processo real era apenas envio de informação. Antes não existia forma operacional de limpar essas ligações na UI.

View File

@@ -0,0 +1,5 @@
# ClientFlow v4928.1.5.51 — Task refresh sentinel fix
Micro-correção para repor a frase sentinela usada por `tests/test_v4928_1_5_13_task_detail_refresh.py`.
Não altera lógica de runtime. Mantém o comportamento de refrescar o painel completo da tarefa após envio de resposta, evitando cabeçalhos obsoletos como `Pendente/SEND_QUOTE`.

View File

@@ -0,0 +1,40 @@
# ClientFlow v4928.1.5.53 — Opportunity Operation/Context Layout
## Objetivo
Reorganizar a página de detalhe da oportunidade sem alterar a lógica de negócio:
- manter a leitura em 2 colunas;
- colocar decisão, tarefa, follow-up, alteração de fase e correção operacional na coluna esquerda;
- colocar cliente, documentos, produtos, Odoo, comunicação, timeline e técnico na coluna direita;
- reduzir a sensação de funcionalidades espalhadas;
- manter todas as ações existentes.
## Alterações
- Cabeçalho compacto no topo com próxima ação, cliente fiscal, documento principal, valor e tasks.
- Coluna esquerda `Operação`, sticky em desktop, com:
- O que fazer agora;
- Mapa operacional;
- bloqueios;
- tarefa ativa;
- criar follow-up;
- alterar fase;
- corrigir associação operacional.
- Coluna direita `Contexto e evidência`, com:
- cliente fiscal/contacto;
- prontidão para documentos/envio;
- resumo essencial;
- pipeline/fluxo;
- documentos Jasmin;
- produtos;
- Odoo/envio;
- integrações/outbox;
- tasks relacionadas;
- mensagens;
- timeline;
- técnico.
## Compatibilidade
Não há migração, alteração de modelos, endpoints ou integrações externas. A alteração é apenas HTML/CSS dentro da página da oportunidade.

View File

@@ -0,0 +1,20 @@
# ClientFlow v4928.1.5.54 — Opportunity context-left layout
## Objetivo
Reorganiza visualmente a página de detalhe da oportunidade mantendo as mesmas funcionalidades da v1.5.53.
## Alteração
- Cabeçalho full-width da oportunidade mantém-se.
- Em desktop, a coluna principal passa a ser **Contexto e evidência** à esquerda.
- A coluna **Operação** passa para a direita como painel lateral sticky.
- A ordem do DOM mantém Operação primeiro para que em ecrãs menores a ação continue a aparecer antes do contexto.
- Sem alterações de endpoints, base de dados, reconciliação, Odoo, Jasmin ou Chatwoot.
## Validação
```text
PYTHONPATH=. pytest -q tests
316 passed
```

View File

@@ -0,0 +1,34 @@
# ClientFlow v4928.1.5.5 — Audit LLM Auth Hotfix
Esta versão corrige o comportamento do script de auditoria quando executado com `--use-llm`.
## Problema observado
A chamada direta ao OpenRouter funcionava, mas a auditoria devolvia por tarefa:
```text
LLM: fallback
OpenRouter HTTP 401: Missing Authentication header
```
## Causa
O script definia uma chave placeholder para `OPENROUTER_API_KEY` antes de importar `app.config`. Em `pydantic-settings`, variáveis de ambiente têm precedência sobre `.env`, por isso a placeholder podia ocultar a chave real do `.env`.
## Correção
- Com `--use-llm`, o script deixa o `.env` fornecer a chave real.
- A placeholder só é usada quando `--use-llm` não está ativo.
- Uma placeholder antiga no ambiente do processo é removida antes de carregar a configuração.
## Comando de validação
```bash
python scripts/audit_task_reply_suggestions.py \
--status pending \
--route vendas \
--use-llm \
--limit 5 \
--format json \
--out /tmp/task_reply_audit_llm_vendas.json
```

View File

@@ -0,0 +1,125 @@
# ClientFlow v4928.1.5.6 — Fase 1: integração segura do agente de email
Esta versão integra o agente de respostas testado com conhecimento BLIF no fluxo seguro do ClientFlow.
## Objetivo
Gerar rascunhos editáveis para respostas a emails/mensagens de clientes, usando OpenAI Responses API + `file_search` sobre uma vector store de conhecimento BLIF.
A integração **não envia respostas automaticamente**. O operador continua a rever e enviar pelo painel da tarefa.
## Novos ficheiros / alterações principais
- `app/email_reply_agent_service.py`
- Novo serviço de agente de email.
- Chama OpenAI Responses API com `file_search`.
- Devolve JSON estruturado: intenção, prioridade, resposta sugerida, revisão humana, confiança e informação usada.
- `app/reply_assistant_service.py`
- Integra o agente como prioridade quando `CLIENTFLOW_EMAIL_REPLY_AGENT_ENABLED=true`.
- Guarda metadata do agente em `message_drafts.metadata.email_agent`.
- Mantém fallback para fluxo existente se o agente estiver desligado ou indisponível.
- `app/admin_ui/pages/tasks.py`
- Mostra estado do agente no painel de resposta da tarefa.
- Badge atualizado para `v4928.1.5.6`.
- `app/api/internal.py`
- Novo endpoint interno:
- `POST /api/internal/tasks/{task_id}/reply-draft`
- Cria rascunho persistente e devolve JSON.
- Protegido pelo mesmo `X-ClientFlow-Admin-Token` quando configurado.
- `.env.example`
- Novas variáveis OpenAI/agent.
## Variáveis de ambiente
```env
CLIENTFLOW_EMAIL_REPLY_AGENT_ENABLED=false
OPENAI_API_KEY=
OPENAI_RESPONSES_URL=https://api.openai.com/v1/responses
OPENAI_VECTOR_STORE_ID=
CLIENTFLOW_EMAIL_REPLY_AGENT_MODEL=gpt-4.1-mini
CLIENTFLOW_EMAIL_REPLY_AGENT_TIMEOUT_SECONDS=30
CLIENTFLOW_EMAIL_REPLY_AGENT_MAX_RESULTS=6
CLIENTFLOW_EMAIL_REPLY_AGENT_PROMPT_VERSION=blif-email-agent-phase1-20260613
```
Para ativar em staging/produção:
```env
CLIENTFLOW_EMAIL_REPLY_AGENT_ENABLED=true
OPENAI_API_KEY=sk-proj-...
OPENAI_VECTOR_STORE_ID=vs_...
```
## Fluxo seguro
```text
Task ClientFlow
Gerar rascunho
Agente OpenAI/file_search consulta conhecimento BLIF
Resposta JSON estruturada
ClientFlow valida segurança
Guarda em message_drafts
Operador revê e envia manualmente
```
## Fallback
Se o agente estiver desligado, mal configurado ou indisponível, o ClientFlow mantém o fluxo anterior:
```text
business_knowledge_service + templates + OpenRouter opcional
```
Isto evita bloqueio da operação.
## API interna
Exemplo:
```bash
curl -X POST "https://clientflow.blif.pt/api/internal/tasks/<TASK_ID>/reply-draft" \
-H "X-ClientFlow-Admin-Token: <TOKEN>" \
-H "Content-Type: application/json" \
-d '{"selected_document_ids": []}'
```
Resposta resumida:
```json
{
"draft_id": "...",
"task_id": "...",
"template_code": "LLM_BUSINESS_REPLY",
"message_body": "...",
"blockers": [],
"warnings": [],
"email_agent": {
"used": true,
"intencao": "pedido_preco",
"precisa_revisao_humana": false,
"nivel_confianca": "alto"
}
}
```
## Guardrails principais
- Não enviar automaticamente.
- Não substituir bounces, respostas automáticas ou revisão manual por resposta comercial.
- Se o agente marcar revisão humana, mostrar aviso no painel.
- Se confiança baixa, bloquear envio até revisão/correção manual.
- Continuar a validar instalação, IVA, preços e promessas comerciais em `reply_safety_validator.py`.
## Nota sobre conhecimento
Esta integração usa a vector store indicada em `OPENAI_VECTOR_STORE_ID`. Para obter respostas com a versão mais recente do conhecimento BLIF, atualize a vector store no ambiente OpenAI e altere o ID no `.env`.

View File

@@ -0,0 +1,43 @@
# ClientFlow v4928.1.5.7 — Readable commercial replies
Esta versão melhora o formato das respostas do agente de email da Blif.
## Exemplo de formato pretendido
```text
Bom dia Sr. Pedro Simões,
Obrigado pelo seu contacto e pela referência do Sr. Rui Santos.
Segue proposta para o equipamento solicitado (valor s/IVA):
Carregador trifásico 11 kW com cabo Tipo 2 de 5 metros 178 €
Funcionalidades incluídas:
Potência ajustável entre 6A e 32A
Gestão via aplicação móvel
Monitorização e agendamento de carregamentos
Garantia de 24 meses
Prazo de entrega:
2 a 3 dias úteis após pagamento
Caso pretenda, posso também enviar ficha técnica e proposta formal.
Com os melhores cumprimentos,
Sérgio Araújo
Blif
```
## Regras adicionadas ao prompt
- Parágrafos curtos.
- Listas com travessão para preços, funcionalidades, prazos e próximos passos.
- Estrutura de proposta comercial em pedidos de preço/proposta.
- Assinatura comercial com `Com os melhores cumprimentos, Sérgio Araújo, Blif`.
- Personalização só quando o nome/referência existe no email ou no CRM.
- Proibição explícita de inventar nomes, referências, produtos ou contactos.
## Nota operacional
A versão mantém a integração em Fase 1: o operador vê e edita o rascunho antes de enviar.

View File

@@ -0,0 +1,9 @@
# v4928.1.5.8 — Reply Assistant UI
Esta versão evita que o operador veja duas respostas concorrentes na tarefa:
- O card antigo **Mensagem sugerida** deixa de aparecer no detalhe moderno.
- A resposta principal passa a ser a **Mensagem editável** no painel **Resposta ao cliente**.
- O botão **Copiar mensagem** copia a mensagem editável quando existir.
Também foi afinado o prompt de fallback OpenRouter para propostas comerciais mais legíveis, com preço, funcionalidades, prazo e assinatura BLIF quando aplicável.

View File

@@ -0,0 +1,15 @@
# v4928.1.5.9 — Reply Assistant formal greeting + UI cleanup
Esta versão ajusta o detalhe de tarefas para ficar mais claro na utilização diária:
1. A resposta gerada passa a preferir cumprimentos formais quando existe nome completo do contacto.
2. Campos técnicos vazios deixam de ser renderizados.
3. Reclassificação e ignorar tarefa passam para baixo do cartão `Concluir`, na coluna direita.
Exemplo de cumprimento preferido:
```text
Boa tarde Sra. Bárbara Gonçalves,
```
Se o contacto não tiver nome completo ou o género não for reconhecido, o sistema usa uma saudação segura sem título.