Sync completo da spec 044, contratos, registry e sidebar no vault VM130. Co-authored-by: Cursor <cursoragent@cursor.com>
175 lines
4.4 KiB
Markdown
175 lines
4.4 KiB
Markdown
# 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 |
|