diff --git a/ligbox-ops-platform/_sidebar.md b/ligbox-ops-platform/_sidebar.md index ef5ab38..f0206f8 100644 --- a/ligbox-ops-platform/_sidebar.md +++ b/ligbox-ops-platform/_sidebar.md @@ -212,3 +212,10 @@ - [activation-field-mapping.md](specs/043-desk-client-activation-sync/contracts/activation-field-mapping.md) — **fonte única** - [desk-activate-account-api.md](specs/043-desk-client-activation-sync/contracts/desk-activate-account-api.md) - [mail-bundle-api.md](specs/043-desk-client-activation-sync/contracts/mail-bundle-api.md) +- **044-foss-desk-ticket-sync** ⭐ Portal OB- ↔ Desk ↔ FOSS Support + - [📄 spec.md](specs/044-foss-desk-ticket-sync/spec.md) + - [tasks.md](specs/044-foss-desk-ticket-sync/tasks.md) + - [ROLLBACK.md](specs/044-foss-desk-ticket-sync/ROLLBACK.md) + - **contracts/** + - [ticket-field-mapping.md](specs/044-foss-desk-ticket-sync/contracts/ticket-field-mapping.md) — **fonte única IDs** + - [ticket-sync-api.md](specs/044-foss-desk-ticket-sync/contracts/ticket-sync-api.md) diff --git a/ligbox-ops-platform/specs/010-desk-assist-takeover/spec.md b/ligbox-ops-platform/specs/010-desk-assist-takeover/spec.md index 38f92f9..1d69fd8 100644 --- a/ligbox-ops-platform/specs/010-desk-assist-takeover/spec.md +++ b/ligbox-ops-platform/specs/010-desk-assist-takeover/spec.md @@ -5,7 +5,7 @@ **Status:** 📋 **Draft — decisões fechadas, pronta para plano** **Prioridade:** **P0** (bloqueia operação humana no onboarding) **Depende de:** Spec 001 (webhooks VM112), Spec 003 (auth/RBAC) -**Relacionada:** Spec 007 (push escalada), Spec 008 (Kanban/SLA), Spec 011 (OTRS futuro) +**Relacionada:** Spec 007 (push escalada), Spec 008 (Kanban/SLA), Spec 011 (OTRS futuro), **[Spec 044](../044-foss-desk-ticket-sync/spec.md)** (sync FOSS) **API alvo:** `0.9.0-desk-assist` (VM122) + contratos VM112 `assist-v1` --- diff --git a/ligbox-ops-platform/specs/024-openpanel-fossbilling/spec.md b/ligbox-ops-platform/specs/024-openpanel-fossbilling/spec.md index deec132..2d0b95a 100644 --- a/ligbox-ops-platform/specs/024-openpanel-fossbilling/spec.md +++ b/ligbox-ops-platform/specs/024-openpanel-fossbilling/spec.md @@ -134,7 +134,7 @@ bash /opt/ligbox-ops-platform/deploy/vm123-finance-stack/setup-foss-antispam.sh FOSSBilling Server Manager (criar/suspender contas hosting) -Desk VM122 ──webhook/link──► FOSSBilling / tickets +Desk VM122 ──webhook/link──► FOSSBilling / tickets · **[Spec 044](../044-foss-desk-ticket-sync/spec.md)** sync bidireccional Wizard VM112 ──company.validated──► Desk ``` diff --git a/ligbox-ops-platform/specs/041-desk-operational-feed/spec.md b/ligbox-ops-platform/specs/041-desk-operational-feed/spec.md new file mode 100644 index 0000000..18fde4f --- /dev/null +++ b/ligbox-ops-platform/specs/041-desk-operational-feed/spec.md @@ -0,0 +1,203 @@ +# Spec 041 — Central Operacional (Operational Feed) + +**Criado:** 2026-06-29 +**Solicitado por:** Roger +**Status:** Implementado v0.13.0 — **fase mock/simulação** +**Prioridade:** P1 (integrações reais = fases futuras) +**Versão Desk:** `0.13.0-design-system` +**Substitui:** Aba Desk **`Mensagens`** (`data-view="messages"`) +**UI label:** **Central Operacional** (vocabulário: *Operational feed* — nunca «Mensagens») +**Spec UI geral:** [Spec 040](../040-desk-design-system-v013/spec.md) (tokens, principles) +**Host:** VM122 · `desk.ligbox.com.br` + +--- + +## 1. Problema + +A aba «Mensagens» mostrava apenas **pedidos de cadastro** (`/api/v1/auth/registration-requests`). + +Roger definiu **Central Operacional** (mockup img 3): inbox unificada omnicanal com canais, KPIs, feed de eventos, painel conversa, SLA. + +**Decisão:** construir UI completa + **banco simulação** até webhooks/APIs reais (WhatsApp, email inbound, telefonia, etc.). + +Pedidos de cadastro: preservados em `renderRegistrationRequestsLegacy()` — reintegrar via link no Controle de acesso (Spec 040). + +--- + +## 2. Escopo + +| Fase | Estado | +|------|--------| +| **Fase A (actual)** | Mock SQLite + seed 6 eventos + API REST | +| **Fase B** | Webhook email inbound → `ops_inbox_events` | +| **Fase C** | WhatsApp Business API, Telegram, SMS | +| **Fase D** | Integração tickets Desk + agentes A0–A7 | + +--- + +## 3. Arquitetura — Aba Desk + +```text +Nav: «Central Operacional» (#nav-messages, data-view=messages) +View: #view-messages +Host: #messages-content +Module: messages (Spec 015 modules registry) + +app.staging.js +└── renderMessages() + └── DeskOperationalFeed.paint(#messages-content) [OF-FE-001] + +DeskOperationalFeed +├── Sidebar canais (stats.channels) +├── KPI row (stats) +├── Feed entity cards (GET /events) +└── Right panel + ├── Tabs: Conversa | Detalhes | Histórico + ├── Chat (GET event.messages + POST messages) + └── SLA bar + acções (PATCH event) +``` + +**View ID legacy:** `messages` — mantido por compatibilidade módulos/URL; **label UI** = Central Operacional. + +--- + +## 4. Registo de ficheiros (referência futura) + +Código interno: **`OF-{tipo}-{nnn}`** + +### 4.1 Frontend + +| Código | Ficheiro | Global JS | Função | +|--------|----------|-----------|--------| +| **OF-FE-001** | `frontend/assets/operational-feed.js` | `window.DeskOperationalFeed` | UI Central Operacional (layout 3 colunas) | +| **OF-FE-002** | `frontend/assets/ligbox-ds.css` | — | Partilhado Spec 040 — classes `.lb-ops-*` | +| **OF-FE-010** | `frontend/index.html` | — | Script `operational-feed.js?v=20260629v013` | +| **OF-FE-011** | `frontend/assets/app.staging.js` | `renderMessages()` | Delegação para `DeskOperationalFeed.paint` | +| **OF-FE-012** | `frontend/assets/app.staging.js` | `titles.messages` | «Central Operacional» | +| **OF-FE-013** | `frontend/assets/app.staging.js` | `subtitles.messages` | «Spec 041 · Operational feed…» | + +### 4.2 API — Backend + +| Código | Ficheiro | Router | Função | +|--------|----------|--------|--------| +| **OF-API-001** | `api/app/ops_inbox_store.py` | — | Schema + seed + queries SQLite | +| **OF-API-002** | `api/app/ops_inbox_routes.py` | `/api/v1/ops-inbox` | REST endpoints | +| **OF-API-003** | `api/app/main.py` | — | `include_router(ops_inbox_router)` + `init_inbox_schema` | + +### 4.3 Contratos + +| Código | Ficheiro | Função | +|--------|----------|--------| +| **OF-CTR-001** | `specs/041-desk-operational-feed/contracts/ops-inbox-api.md` | Contrato endpoints | +| **OF-CTR-002** | `contracts/stack-services.yaml` | Serviço `vm122-ops-inbox-api` | + +--- + +## 5. Endpoints — arquitectura + +Contrato detalhado: [contracts/ops-inbox-api.md](contracts/ops-inbox-api.md) + +| Código | Método | Path | Descrição | +|--------|--------|------|-----------| +| **OF-EP-001** | GET | `/api/v1/ops-inbox/stats` | KPIs + contadores por canal | +| **OF-EP-002** | GET | `/api/v1/ops-inbox/events` | Lista eventos (filtros) | +| **OF-EP-003** | GET | `/api/v1/ops-inbox/events/{id}` | Detalhe + mensagens | +| **OF-EP-004** | POST | `/api/v1/ops-inbox/events/{id}/messages` | Resposta / nota interna | +| **OF-EP-005** | PATCH | `/api/v1/ops-inbox/events/{id}` | status, assignee, priority | + +**Auth:** Bearer JWT · `can_manage_users` (fase mock — alinhar RBAC dedicado em fase B). + +--- + +## 6. Modelo de dados (SQLite — fase mock) + +### `ops_inbox_events` + +| Coluna | Tipo | Descrição | +|--------|------|-----------| +| id | TEXT PK | ex. `evt-wa-001` | +| channel | TEXT | `whatsapp`, `email`, `tickets`, … | +| event_type | TEXT | `message`, `ticket`, `alert`, `missed_call` | +| priority | TEXT | `normal`, `high`, `critical` | +| title, preview | TEXT | Card feed | +| tags_json | TEXT | JSON array | +| assignee | TEXT | nullable | +| status | TEXT | `open`, `pending`, `resolved` | +| contact_* | TEXT | empresa, CNPJ, client_id | +| sla_minutes, sla_remaining_sec | INT | Barra SLA UI | +| created_at, updated_at | TEXT | ISO8601 | + +### `ops_inbox_messages` + +| Coluna | Tipo | Descrição | +|--------|------|-----------| +| event_id | TEXT FK | | +| author_type | TEXT | `user`, `agent`, `operator`, `internal`, `system` | +| author_label | TEXT | | +| body | TEXT | | + +**Seed:** 6 eventos em `init_inbox_schema()` quando tabela vazia. + +--- + +## 7. Canais (sidebar) + +| ID | Label UI | +|----|----------| +| all | Todos os canais | +| email | Email | +| whatsapp | WhatsApp API | +| voice | Telefonia / Voz | +| sms | SMS | +| telegram | Telegram | +| tickets | Tickets | +| agents | Agentes IA | +| internal | Solicitações internas | +| clients | Clientes | +| alerts | Alertas sistema | + +--- + +## 8. Integrações futuras (stubs) + +| Canal | Endpoint futuro | Notas | +|-------|-----------------|-------| +| Email | `POST /api/v1/ops-inbox/webhooks/email` | Inbound parse → event | +| WhatsApp | `POST /api/v1/ops-inbox/webhooks/whatsapp` | Meta Cloud API | +| Tickets | Link `desk_tickets` | Sync bidireccional — **[Spec 044](../044-foss-desk-ticket-sync/spec.md)** | +| Agentes | `agents/routes.py` threads | Unificar inbox agentes | +| Cadastro | `registration-requests` | Link desde Spec 040 hub | + +--- + +## 9. KPIs (header) + +| KPI | Fonte | +|-----|-------| +| Eventos hoje | COUNT events | +| Pendentes | status open/pending | +| Críticos | priority=critical | +| Aguardando você | assignee NOT NULL + open | +| SLA médio | Mock 96% (fase A) — calcular fase B | + +--- + +## 10. Validação + +```bash +curl -s -H "Authorization: Bearer $TOKEN" \ + https://desk.ligbox.com.br/api/v1/ops-inbox/stats + +curl -s -H "Authorization: Bearer $TOKEN" \ + "https://desk.ligbox.com.br/api/v1/ops-inbox/events?channel=whatsapp" +``` + +UI: Menu **Central Operacional** → feed com 6 cards seed → painel conversa. + +--- + +## 11. Deploy + +Mesmo procedimento Spec 040 — ficheiros **OF-API-001/002** + **OF-FE-001**. + +Health API: `"version": "0.13.0-design-system"` diff --git a/ligbox-ops-platform/specs/043-desk-client-activation-sync/spec.md b/ligbox-ops-platform/specs/043-desk-client-activation-sync/spec.md index d891998..2ffcf7b 100644 --- a/ligbox-ops-platform/specs/043-desk-client-activation-sync/spec.md +++ b/ligbox-ops-platform/specs/043-desk-client-activation-sync/spec.md @@ -37,6 +37,7 @@ O Desk (VM122) é o **orquestrador**: recebe `company.validated`, persiste `bill | [027](../027-desk-rbac-function-matrix/spec.md) | Quem pode activar conta | | [039](../039-ligbox-ops-authorization-catalog/spec.md) | `vm123_foss.*`, `vm123_openpanel.*`, Odoo | | [040](../040-desk-design-system-v013/spec.md) | UI staff Access Control Hub | +| [044](../044-foss-desk-ticket-sync/spec.md) | Sync tickets OB- ↔ Desk ↔ FOSS Support | --- diff --git a/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/ROLLBACK.md b/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/ROLLBACK.md new file mode 100644 index 0000000..60872aa --- /dev/null +++ b/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/ROLLBACK.md @@ -0,0 +1,24 @@ +# Spec 044 — Rollback + +## Feature flag + +```bash +# VM122 .env +FOSS_TICKET_SYNC_ENABLED=false +systemctl restart ligbox-ops-api +``` + +Desactiva espelho Desk→FOSS e ignora webhook FOSS→Desk (HTTP 503 «sync disabled»). + +## Git tags (após implementação) + +| Tag | Descrição | +|-----|-----------| +| `desk-v0.15.0-pre-spec044-ticket-sync` | Antes Spec 044 | +| `desk-v0.15.1-spec044-ticket-sync` | Com sync FOSS tickets | + +## Rollback manual + +1. Remover `foss_sync` de tickets afectados (opcional — dados inofensivos) +2. Tickets FOSS criados manualmente podem permanecer no FOSS admin +3. Portal OB- e Desk continuam funcionando independentemente diff --git a/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/contracts/ticket-field-mapping.md b/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/contracts/ticket-field-mapping.md new file mode 100644 index 0000000..046623d --- /dev/null +++ b/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/contracts/ticket-field-mapping.md @@ -0,0 +1,97 @@ +# Contrato — Mapeamento IDs: Portal ↔ Desk ↔ FOSS + +**Spec:** [044](../spec.md) +**Versão:** 1.0 · 2026-07-01 · Roger +**Status:** Fonte única para correlação de tickets + +--- + +## 1. Identificadores + +| Campo | Formato | Sistema dono | Persistência Desk | +|-------|---------|--------------|-------------------| +| `wizard_ticket_id` | `OB-[A-F0-9]{8}` | VM112 portal | `tickets.payload.wizard_ticket_id` | +| `desk_ticket_id` | inteiro `#N` | VM122 Desk | `tickets.id` | +| `foss_ticket_id` | inteiro FOSS | VM123 FOSS | `tickets.payload.foss_ticket_id` | +| `external_customer_id` | inteiro FOSS client | VM123 FOSS | `billing_accounts.external_customer_id` | +| `session_id` | UUID wizard | VM112 | `tickets.session_id` | +| `domain` | FQDN | — | `tickets.payload.domain` | + +--- + +## 2. Chaves de idempotência + +| Operação | Chave única | Comportamento se duplicado | +|----------|-------------|----------------------------| +| Portal → Desk | `event + session_id + domain` | Actualizar ticket existente (Spec 001 FR-012) | +| Desk → FOSS espelho | `desk_ticket_id` | Retornar `foss_ticket_id` existente | +| FOSS → Desk webhook | `foss_ticket_id + event_type` | Append nota, não criar ticket novo | +| Cliente FOSS novo | `foss_ticket_id` | Lookup Desk; criar só se ausente | + +--- + +## 3. Mapa de estados + +| Desk `status` | Portal OB- `status` | FOSS Support | +|---------------|---------------------|--------------| +| `open` | `open` | `open` | +| `escalated` | `in_review` | `open` | +| `assisting` | `in_progress` | `on hold` | +| `resolved` | `resolved` | `closed` (resolvido) | +| `closed` | `closed` | `closed` | + +**Regra:** Desk é master para ops; FOSS é master para visibilidade cliente billing. + +--- + +## 4. Payload Desk (`tickets.payload` — extensão Spec 044) + +```json +{ + "event": "onboarding.escalated", + "domain": "empresa.com.br", + "session_id": "331b4022-70a5-4a9d-ba3e-08aaa06cb4f4", + "data": { + "wizard_ticket_id": "OB-D424843A", + "client_note": "DNS não propaga", + "reason": "client_support_request" + }, + "foss_sync": { + "foss_ticket_id": 42, + "external_customer_id": 17, + "synced_at": "2026-07-01T18:00:00Z", + "last_foss_event": "ticket.reply", + "foss_url": "https://financeiro.ligbox.com.br/admin/support/ticket/42" + } +} +``` + +--- + +## 5. Pré-requisitos para espelho FOSS + +| Condição | Obrigatório | +|----------|-------------| +| `billing_accounts.external_customer_id` | Sim (Spec 043) | +| Ticket Desk com `domain` | Sim | +| Role staff a criar espelho | `sales_admin`, `sales_support`, `technician`, `ops_lead` | +| Onboarding puro (sem FOSS client) | Espelho **adiado** até Activar conta | + +--- + +## 6. URLs deep-link + +| Destino | URL | +|---------|-----| +| Desk ticket | `https://desk.ligbox.com.br/#ticket/{desk_ticket_id}` | +| Portal OB- tracking | `https://onboard.ligbox.com.br/onboard?session={session_id}&ticket={wizard_ticket_id}` | +| FOSS admin ticket | `https://financeiro.ligbox.com.br/admin/support/ticket/{foss_ticket_id}` | +| FOSS client ticket | `https://financeiro.ligbox.com.br/support/ticket/{foss_ticket_id}` | + +--- + +## Histórico + +| Versão | Data | Autor | Notas | +|--------|------|-------|-------| +| 1.0 | 2026-07-01 | Roger / Cursor | Documento inicial Spec 044 | diff --git a/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/contracts/ticket-sync-api.md b/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/contracts/ticket-sync-api.md new file mode 100644 index 0000000..35d0b8a --- /dev/null +++ b/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/contracts/ticket-sync-api.md @@ -0,0 +1,175 @@ +# Contrato — API Sincronização Tickets Desk ↔ FOSS + +**Spec:** [044](../spec.md) +**VM122:** Desk API · **VM123:** FOSSBilling Admin API +**Status:** 📋 Especificado — implementação pendente + +--- + +## 1. Desk → FOSS — criar espelho + +**Quando:** ticket Desk criado ou escalado **e** `external_customer_id` disponível. + +### `foss_client.create_support_ticket()` (novo módulo VM122) + +``` +POST https://financeiro.ligbox.com.br/api/admin/support/ticket_create +Auth: Basic admin@ligbox.com.br:{FOSS_ADMIN_API_KEY} +Content-Type: application/x-www-form-urlencoded +``` + +| Campo FOSS | Origem Desk | +|------------|-------------| +| `client_id` | `billing_accounts.external_customer_id` | +| `subject` | `tickets.subject` | +| `content` | Primeira nota + link Desk + OB- se existir | +| `helpdesk` | `Ligbox Ops` (departamento default) | +| `priority` | mapa Desk priority → FOSS | + +**Resposta esperada:** `{ "result": { "id": 42 } }` → gravar `foss_ticket_id=42`. + +**Idempotência:** antes de criar, `GET ticket by desk_ticket_id` em cache local ou custom field FOSS `desk_ticket_id`. + +--- + +## 2. FOSS → Desk — webhook inbound + +### `POST /api/v1/webhooks/foss/support` + +**Auth:** header `X-Foss-Webhook-Secret: {FOSS_WEBHOOK_SECRET}` +**Content-Type:** `application/json` + +### Payload + +```json +{ + "event": "ticket.reply", + "foss_ticket_id": 42, + "client_id": 17, + "domain": "empresa.com.br", + "subject": "Problema DNS", + "status": "open", + "message": "Cliente respondeu: ainda não resolveu", + "author": "client", + "created_at": "2026-07-01T18:05:00Z" +} +``` + +| `event` | Acção Desk | +|---------|------------| +| `ticket.opened` | Criar ticket Desk se não existir (cliente abriu no FOSS) | +| `ticket.reply` | Append nota interna + notificar assignee | +| `ticket.closed` | `UPDATE tickets SET status='closed'` | +| `ticket.reopened` | `status='open'` | + +### Response 200 + +```json +{ + "ok": true, + "desk_ticket_id": 45, + "handled": true, + "duplicate": false +} +``` + +### Erros + +| HTTP | Condição | +|------|----------| +| 401 | Secret inválido | +| 404 | `foss_ticket_id` sem correlação e `client_id` desconhecido | +| 409 | Evento duplicado (idempotência) | + +--- + +## 3. Desk — API staff (fase E) + +### `POST /api/v1/support/tickets` + +**Auth:** JWT Desk · roles: `technician+`, `sales_support+` + +```json +{ + "domain": "empresa.com.br", + "subject": "Webmail inacessível", + "body": "Cliente reporta erro 502", + "mirror_foss": true, + "wizard_ticket_id": null +} +``` + +**Fluxo:** +1. Resolve `billing_accounts` por `domain` +2. INSERT `tickets` +3. Se `mirror_foss=true` e `external_customer_id` → `foss_client.create_support_ticket()` +4. Return `{ desk_ticket_id, foss_ticket_id, tracking_url }` + +### `GET /api/v1/support/tickets/{id}/sync-status` + +Retorna estado sync FOSS + links. + +--- + +## 4. Portal VM112 — sem alteração v1 + +Endpoints existentes mantidos: + +| Método | Path | Notas | +|--------|------|-------| +| `POST` | `/api/onboarding/support/ticket` | Cria OB- + webhook Desk | +| `GET` | `/api/onboarding/support/ticket/{OB-}/public` | Portal cliente Spec 026 | + +**Extensão fase E:** resposta inclui `desk_ticket_id` quando sync completo (opcional, não bloqueia cliente). + +--- + +## 5. FOSS — configuração webhook (VM123) + +Opções (escolher uma na implementação): + +| Opção | Prós | Contras | +|-------|------|---------| +| **A** Hook PHP FOSS custom | Tempo real | Requer patch container | +| **B** Cron Desk poll `support/ticket_get_list` | Sem patch FOSS | Latência 1–5 min | +| **C** Traefik + sidecar notifier | Desacoplado | Mais infra | + +**Recomendação v1:** Opção **B** (poll) + Opção **A** quando estável. + +--- + +## 6. Variáveis ambiente (VM122) + +| Variável | Descrição | +|----------|-----------| +| `FOSSBILLING_URL` | `https://financeiro.ligbox.com.br` | +| `FOSS_ADMIN_EMAIL` | Conta M2M admin | +| `FOSS_ADMIN_API_KEY` | API key FOSS (Spec 027) | +| `FOSS_WEBHOOK_SECRET` | Validação inbound FOSS→Desk | +| `FOSS_TICKET_SYNC_ENABLED` | `true` / `false` feature flag | + +--- + +## 7. Testes curl + +```bash +# Webhook simulado FOSS → Desk +curl -s -X POST https://desk.ligbox.com.br/api/v1/webhooks/foss/support \ + -H "X-Foss-Webhook-Secret: $FOSS_WEBHOOK_SECRET" \ + -H "Content-Type: application/json" \ + -d '{ + "event": "ticket.reply", + "foss_ticket_id": 42, + "client_id": 17, + "domain": "empresa.com.br", + "message": "Teste sync Spec 044" + }' +``` + +--- + +## Histórico + +| Versão | Data | Notas | +|--------|------|-------| +| 1.0 | 2026-07-01 | Contrato inicial Spec 044 | diff --git a/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/spec.md b/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/spec.md new file mode 100644 index 0000000..f1225aa --- /dev/null +++ b/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/spec.md @@ -0,0 +1,109 @@ +# Spec 044 — Sincronização Tickets: Portal ↔ Desk ↔ FOSS + +**Criado:** 2026-07-01 +**Solicitado por:** Roger +**Status:** 📋 **Especificado — implementação pendente** +**Prioridade:** P1 (suporte unificado pós-activação) +**Sistemas:** VM112 Portal · VM122 Desk · VM123 FOSSBilling + +--- + +## Resumo + +Hoje existem **três filas de tickets isoladas**: + +| Sistema | ID | Estado | +|---------|-----|--------| +| Portal wizard (VM112) | `OB-XXXXXXXX` | ✅ Activo — JSON local + portal cliente | +| Desk Ops (VM122) | `#N` / `CH-*` | ✅ Activo — webhook VM112 | +| FOSS Support (VM123) | `foss_ticket_id` | ❌ **Sem sync** com portal/Desk | + +Esta spec define a **ponte bidireccional** Desk ↔ FOSS, preservando o portal wizard como canal de entrada do cliente e o Desk como **fonte de verdade operacional**. + +**Contratos:** +- [ticket-field-mapping.md](./contracts/ticket-field-mapping.md) — chaves de correlação +- [ticket-sync-api.md](./contracts/ticket-sync-api.md) — webhooks e endpoints API + +--- + +## Specs relacionadas + +| Spec | Relação | +|------|---------| +| [001](../001-webhook-vm112-integration/spec.md) | Webhooks VM112 → Desk (base) | +| [010](../010-desk-assist-takeover/spec.md) | Escalada, ASM, `onboarding.escalated` | +| [012](../012-abandoned-onboarding-lead/spec.md) | Ticket único por jornada onboarding | +| [024](../024-openpanel-fossbilling/spec.md) | FOSS VM123, módulo Support | +| [027](../027-desk-rbac-function-matrix/contracts/vm123-product-roles.md) | `support` FOSS, roles comercial | +| [039](../039-ligbox-ops-authorization-catalog/spec.md) | `vm123_foss.support.ticket` | +| [041](../041-desk-operational-feed/spec.md) | Central Operacional — canal Tickets | +| [043](../043-desk-client-activation-sync/spec.md) | `external_customer_id` FOSS pós-activação | + +--- + +## Arquitectura alvo + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ VM112 — Portal (onboard.ligbox.com.br) │ +│ OB-* tickets · POST /api/onboarding/support/ticket │ +│ Cliente acompanha: GET .../support/ticket/{OB-}/public │ +└───────────────────────────────┬─────────────────────────────────────────┘ + │ webhook onboarding.escalated (+ started) + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ VM122 — Desk (fonte de verdade ops) │ +│ tickets.payload: wizard_ticket_id, foss_ticket_id, external_customer_id│ +│ Staff: Chamados · Serviços · Central Operacional (041) │ +└───────────────┬───────────────────────────────┬─────────────────────────┘ + │ POST espelho (M2M) │ webhook FOSS → Desk + ▼ ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ VM123 — FOSSBilling Support │ +│ Cliente: financeiro.ligbox.com.br/support │ +│ Staff: /admin/support · API /api/admin/support/* │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Regras de negócio + +1. **Um incidente = um ticket Desk** — nunca duplicar `#N` para a mesma `session_id` ou `foss_ticket_id`. +2. **Portal OB-** continua a existir para onboarding; Desk grava `wizard_ticket_id` no payload (já parcialmente implementado na UI). +3. **FOSS espelho** só após `external_customer_id` conhecido (Spec 043) — tickets de onboarding pré-FOSS ficam só Desk + OB-. +4. **Sync bidireccional de estado:** `open` ↔ `in_progress` ↔ `resolved` ↔ `closed` (mapa em contrato). +5. **Cliente pós-activação** pode abrir ticket no FOSS client area **ou** no portal/console Ligbox; ambos convergem no Desk. + +--- + +## Fases de implementação + +| Fase | Entrega | VM | +|------|---------|-----| +| **A** | Documentação + contratos (esta spec) | CT130 | +| **B** | `foss_client.create_support_ticket()` + espelho Desk→FOSS | VM122 | +| **C** | Webhook FOSS → Desk (`POST /api/v1/webhooks/foss/support`) | VM122 + VM123 | +| **D** | UI Desk: link FOSS ticket + badge sync | VM122 | +| **E** | Portal pós-activação: criar via Desk API (propaga FOSS) | VM112 / Console | + +Ver [tasks.md](./tasks.md). + +--- + +## Fora de escopo (v1) + +- OTRS (→ Spec 011) +- Sync automático e-mail inbound (→ Spec 041 fase B) +- Tickets Odoo Helpdesk + +--- + +## Validação Roger + +```bash +# 1) Cliente abre OB- no wizard → Desk #N com wizard_ticket_id +# 2) Activar conta (Spec 043) → external_customer_id preenchido +# 3) Staff responde no Desk → foss_ticket_id criado no FOSS +# 4) Cliente responde no FOSS → webhook actualiza nota no Desk #N +``` diff --git a/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/tasks.md b/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/tasks.md new file mode 100644 index 0000000..495bbf6 --- /dev/null +++ b/ligbox-ops-platform/specs/044-foss-desk-ticket-sync/tasks.md @@ -0,0 +1,42 @@ +# Spec 044 — Tasks + +## Documentação +- [x] Spec índice `spec.md` +- [x] Contrato `contracts/ticket-field-mapping.md` +- [x] Contrato `contracts/ticket-sync-api.md` +- [x] Registo em `SPEC-REGISTRY.md` +- [x] Ligações cruzadas specs 010/012/024/041/043 +- [x] Sync Obsidian VM130 + +## Fase A — Estado actual (baseline) +- [x] Portal OB- → Desk via `onboarding.escalated` (VM112) +- [x] UI Desk mostra `wizard_ticket_id` (OB-) no painel ticket +- [x] FOSS Support nativo em VM123 (sem bridge) +- [ ] Inventário endpoints FOSS Support API (Roger validar admin) + +## Fase B — Desk → FOSS (espelho) +- [ ] Coluna/payload `foss_ticket_id` em `tickets` +- [ ] `foss_client.create_support_ticket()` — M2M admin API +- [ ] Hook pós-criação ticket Desk: se `billing_accounts.external_customer_id` → espelho FOSS +- [ ] Idempotência: não recriar se `foss_ticket_id` já existe +- [ ] Unit tests `test_foss_ticket_sync_044.py` + +## Fase C — FOSS → Desk (webhook) +- [ ] Endpoint `POST /api/v1/webhooks/foss/support` (auth `FOSS_WEBHOOK_SECRET`) +- [ ] Plugin/hook FOSS ou cron poll — eventos `ticket.opened`, `ticket.reply`, `ticket.closed` +- [ ] Upsert nota / status no ticket Desk correlacionado +- [ ] Log em `webhook_events` source=`vm123-foss` + +## Fase D — UI Desk +- [ ] Painel ticket: badge «FOSS #123» + deep-link `financeiro.ligbox.com.br/admin/support` +- [ ] Serviços IaaS / ficha cliente: «Abrir ticket FOSS» (roles sales_admin, sales_support) +- [ ] Central Operacional (041): evento `desk_tickets` com `foss_ticket_id` + +## Fase E — Portal pós-activação +- [ ] Console `/me/suporte` ou FOSS client area — single entry (decisão Roger) +- [ ] API Desk `POST /api/v1/support/tickets` → cria Desk + FOSS espelho +- [ ] Resposta cliente inclui `tracking_url` (portal ou FOSS) + +## Testes E2E +- [ ] Roger: OB- onboarding → activar conta → staff responde → cliente vê no FOSS +- [ ] Roger: cliente abre ticket FOSS → aparece no Desk Chamados diff --git a/ligbox-ops-platform/specs/SPEC-REGISTRY.md b/ligbox-ops-platform/specs/SPEC-REGISTRY.md index 95cd1da..1e06240 100644 --- a/ligbox-ops-platform/specs/SPEC-REGISTRY.md +++ b/ligbox-ops-platform/specs/SPEC-REGISTRY.md @@ -8,5 +8,6 @@ | **041** | **`041-desk-operational-feed/`** | **Central Operacional (ex-Mensagens) + ops-inbox API** | **0.13.0** | | **042** | **`042-ligbox-nettools-portal/`** | **NetTools — 23 ferramentas OSS em nettools.ligbox.com.br** | — | | **043** | **`043-desk-client-activation-sync/`** | **Mapa campos Wizard→Desk→FOSS→OpenPanel→Odoo + API Activar conta** | — | +| **044** | **`044-foss-desk-ticket-sync/`** | **Sync tickets Portal OB- ↔ Desk ↔ FOSS Support** | — | -Atualizado: 2026-07-01 · Roger · Spec 043 mapeamento activação cliente +Atualizado: 2026-07-01 · Roger · Spec 044 sync tickets FOSS/portal