# Feature Specification: Relógio por fase — Onboarding VM112 (014)

**Criado:** 2026-06-16  
**Solicitado por:** Roger  
**Status:** Implementação  
**Prioridade:** P1  
**Depende de:** Spec 001 (webhooks VM112), módulo `funnel-timing` (Spec 015)  
**Módulo Desk:** `funnel-timing` (pode ser desactivado sem quebrar o sistema)

---

## Resumo

Exibir **duração entre cada fase** do funil VM112→VM122 e o **tempo total** da sessão (primeiro evento → conclusão ou último evento), em Audit Overview, Tickets e API timeline.

**Princípio:** timestamps já existem em `webhook_events`; esta spec **calcula e apresenta** deltas — não altera o wizard VM112.

---

## Fases medidas

| Ordem | Evento | Label UI |
|-------|--------|----------|
| 0 | `session.started` | Sessão iniciada |
| 1 | `domain.validated` | Domínio validado |
| 2 | `dns.applied` | DNS aplicado |
| 3 | `onboarding.started` | Criar conta |
| 4 | `account.created` | Conta criada |
| 5 | `infra.synced` | Infra sync |
| 6 | `onboarding.completed` | Concluído |

---

## Campos API (quando módulo activo)

Por evento na timeline:

- `duration_from_prev_sec` / `duration_from_prev_label`
- `duration_from_start_sec` / `duration_from_start_label`

Resumo da sessão:

- `total_duration_sec` / `total_duration_label`
- `started_at`, `completed_at`
- `current_phase_elapsed_sec` (se sessão não concluída — tempo desde último evento)

---

## Onde aparece na UI

| Ecrã | Comportamento |
|------|----------------|
| Overview → detalhe domínio | Timeline com relógio entre fases + total |
| Tickets → timeline onboard | Idem |
| Infra 2 → sessões | Badge tempo total (se concluído) ou “parado há X” |
| Módulo desactivado | Timeline clássica só com data/hora (sem regressão) |

---

## Regras

- Duração negativa ou eventos fora de ordem: usar ordem por `id`/`created_at` ASC.
- Backfill (`data.backfill=true`): incluir no cálculo (marca visual opcional).
- SLA futuro (Spec 014-B): alerta se fase > N min — fora do MVP.

---

## Testes

- Sessão `iofficebooks.com`: delta domain→dns ~116s
- Timeline API com módulo ON retorna `total_duration_label`
- Timeline API com módulo OFF não inclui campos `duration_*`
