# Auditoria QA — BusinessCode / CampaignAI

**Escopo:** cobertura de testes, edge cases, fluxos críticos sem teste, regressões prováveis.
**Método:** inventário de `backend/tests/`, leitura de Feature tests, cruzamento com fluxos críticos do produto (auth, campanhas, créditos, checkout, webhooks).

---

## Inventário de testes

```
tests/Feature/
├── AuthFlowTest.php                 (3 testes: register, login, password strength)
├── CampaignStateMachineTest.php     (não lido — assumido cobrindo transições)
├── CouponTest.php                   (5 testes: valid, expired, maxed, % e fixed)
├── ExampleTest.php                  (lixo)
├── InfobipServiceTest.php           (não lido)
├── InfobipWhatsAppProviderTest.php  (não lido)
├── MetaWhatsAppProviderTest.php     (não lido)
├── TenantIsolationTest.php          (2 testes: update e list cross-tenant)
├── WebhookTest.php                  (não lido)
└── WhatsAppServiceResolverTest.php  (não lido)

tests/Unit/
└── ExampleTest.php                  (lixo)
```

**Cobertura estimada:** baixa-média. Áreas sensíveis de dinheiro (Payment, Subscription, MP) totalmente sem teste.

---

## Bugs e falhas

### QA-BUG-01 — Zero testes para `PaymentController` e `SubscriptionController`
**Descrição:** não há nenhum teste cobrindo:
- PIX payment criação + status pending
- Boleto payment criação
- Credit card purchase de créditos
- Subscription store com cupom
- Subscription cancel
- Webhook MP atualizando Payment approved → creditando saldo
- Webhook MP com assinatura inválida rejeitando
- Webhook MP idempotência (request_id duplicado)

O módulo que mexe em dinheiro é o que **mais precisa de teste** para não ter regressão. Lançar sem isso é loteria.
**Evidência:** ausência dos arquivos.
**Severidade:** crítico
**Esforço:** L (≈20 testes Feature + mocks MP)
**Bloqueador de launch:** sim

### QA-BUG-02 — Zero testes para `CreditService`
**Descrição:** `reserve`, `release`, `debit`, `deduct`, `lockCampaignIfInsufficient` — todos sem teste. Cenários críticos não testados:
- Saldo insuficiente (retorna false)
- Saldo exato (usa tudo)
- Concorrência: 2 jobs tentando reservar simultaneamente
- Release após reserve (retorna ao saldo)
- Debit duplo do mesmo reference_id (idempotência? hoje não há)
**Severidade:** crítico
**Esforço:** M (unit tests + 2-3 feature tests com locks)
**Bloqueador de launch:** sim

### QA-BUG-03 — `TenantIsolationTest` só cobre Campaign
**Descrição:** o teste válido existe para `campaigns` (update e list). Faltam os mesmos testes para:
- `contacts` / `contact_lists` / `imports`
- `ai_generation_sessions` / `ai_content_models`
- `audio_generations`
- `conversations` / `conversation_messages`
- `funnels` / `funnel_nodes` / `funnel_edges`
- `payments` / `subscriptions` (especialmente crítico — ver SEC-BUG-04)
- `credit_transactions`
- `audit_logs`

Cada recurso que tem `tenant_id` precisa de teste de isolamento.
**Severidade:** alto
**Esforço:** M (table-driven test com provider por model)
**Bloqueador:** backlog (recomendado pré-launch)

### QA-BUG-04 — Nenhum teste de LGPD/privacidade
**Descrição:** sem teste confirmando que `opted_out=true` impede envio, sem teste de export de dados do tenant, sem teste de exclusão em cascata (usuário pede remoção → contacts, campaigns, credit_transactions devem ser anonimizados/removidos).
**Severidade:** alto
**Esforço:** M
**Bloqueador:** backlog (obrigatório até 6 meses de operação)

### QA-BUG-05 — Sem teste do fluxo end-to-end de campanha
**Descrição:** não existe teste "happy path" que:
1. Registra tenant + user
2. Cria contact_list + contacts
3. Cria campanha SMS
4. Chama sendNow
5. Verifica que `ProcessCampaignJob` foi despachado
6. (Queue::fake) simula a execução do job
7. Verifica que `credit_transactions` tem o débito
8. Verifica que `campaign_dispatches` foram criados
9. Simula webhook Infobip `delivered`
10. Verifica status final do dispatch

Esse teste detectaria 80% das regressões no core business.
**Severidade:** alto
**Esforço:** M
**Bloqueador:** backlog

### QA-BUG-06 — `ExampleTest.php` em Unit e Feature
**Descrição:** limpeza básica — remover.
**Evidência:** `tests/Unit/ExampleTest.php`, `tests/Feature/ExampleTest.php`.
**Severidade:** baixo
**Esforço:** S
**Bloqueador:** backlog

### QA-BUG-07 — Sem teste para webhook Infobip `validateSecret`
**Descrição:** função aceita secret via header OU query string (ver SEC-BUG-01). Precisa de teste:
- secret correto no header → 200
- secret ausente → 401
- secret errado → 401
- secret como query → **hoje aceita** (falha, deveria recusar após fix)
**Severidade:** alto
**Esforço:** S
**Bloqueador:** backlog (após decidir fix SEC-BUG-01)

### QA-BUG-08 — Sem teste de `SubscriptionController` retry após PIX pendente
**Descrição:** cenário DEV-BUG-03 — teste que reproduza: assinatura pending, 25h depois, cliente tenta novamente, deve conseguir.
**Severidade:** alto
**Esforço:** S
**Bloqueador:** backlog (após implementar o fix)

### QA-BUG-09 — Sem teste de cenário "cupom já usado por este tenant"
**Descrição:** `SubscriptionController::store` tem check em `coupon_usages`. `CouponTest.php` cobre validade global, mas não "mesmo tenant tentando reusar". Cenário crítico: prevenção de fraude.
**Severidade:** médio
**Esforço:** S
**Bloqueador:** backlog

### QA-BUG-10 — Sem teste de `CampaignsController` com `adhoc_phones` fora de formato E.164
**Descrição:** regex `/^\+[1-9]\d{6,14}$/` é aplicada. Testar:
- `+5511999999999` → ok
- `11999999999` (sem +) → falha
- `+0511...` → falha (primeiro dígito 0)
- array com 10001 itens → falha por `max:10000`
- email no meio do array → falha
**Severidade:** médio
**Esforço:** S
**Bloqueador:** backlog

### QA-BUG-11 — Sem teste de `throttle` por endpoint
**Descrição:** rate limits definidos (login 5/1min, register 3/1min, campanhas disparo throttle custom) — nenhum teste garante que o 6º request no minuto é 429. Fácil quebrar sem notar em refactor de rotas.
**Severidade:** médio
**Esforço:** S
**Bloqueador:** backlog

### QA-BUG-12 — Tests usam MySQL real? SQLite? Não validei `phpunit.xml`
**Descrição:** se testes rodam em SQLite em memória, algumas queries MySQL-específicas (`DATE_FORMAT(sent_at, '%Y-%m-%d %H:00')` em `ReportController::campaign`) **não funcionam** em SQLite. Teste daquela rota falharia em CI se usar SQLite. Validar `phpunit.xml` e considerar matriz de CI MySQL+SQLite.
**Evidência:** `ReportController.php:110-113`.
**Severidade:** médio
**Esforço:** S
**Bloqueador:** backlog

---

## Melhorias

### QA-IMP-01 — Seeder canônico `TestSeeder` com 2 tenants + plans + users
Reduz boilerplate em cada teste. Factory helpers já ajudam, mas seeder mínimo acelera testes de permissão.

### QA-IMP-02 — Factory para Payment, Subscription, Coupon, CreditTransaction
Hoje só existem factories para User/Tenant/Plan/Campaign (implícito). Sem factory, testes de billing ficam verbosos.

### QA-IMP-03 — Snapshot tests para respostas da API
Usar `spatie/laravel-snapshot-assertions`. Qualquer mudança de shape da resposta JSON vira teste amarelo, evitando quebra silenciosa de clientes (web, mobile futuro, API).

### QA-IMP-04 — CI com matriz PHP 8.2/8.3 + cov mínima 60%
Hoje não vi `.github/workflows/`. Adicionar pipeline com limite mínimo de cobertura + falha se bater abaixo.

---

## Fluxos críticos SEM teste (resumo executivo)

| Fluxo | Tem teste? | Risco |
|---|---|---|
| Register + auto-login | ✅ parcial | baixo |
| Login | ✅ | baixo |
| Password reset | ❌ | médio (não testado) |
| Criar campanha → disparar → creditar → webhook delivery | ❌ | **alto** |
| PIX payment → webhook approved → creditar saldo | ❌ | **crítico** |
| Subscription credit card + cupom | ❌ | **crítico** |
| Cancelar subscription | ❌ | alto |
| Tenant isolation em Payment/Subscription | ❌ | **alto** (ver SEC-BUG-04) |
| Webhook MP signature inválida | ❌ | alto |
| Webhook MP idempotência | ❌ | alto |
| LGPD opt-out impede envio | ❌ | alto |
| Limite do plano (max_campaigns, max_contacts) | ❌ | médio |
| Funis: criar → ativar → enroll → executar | ❌ | médio |
| ElevenLabs sync de vozes | ❌ | baixo |

---

## Novas features QA

### QA-FEAT-01 — Suite E2E com Pest/Playwright
1 happy path em Playwright: landing → register → criar campanha SMS → disparar para 2 contatos mock → ver dispatch completo.

### QA-FEAT-02 — Ambientes de staging por PR
Preview deploy por PR aumenta confiança da review e permite QA manual antes do merge.

### QA-FEAT-03 — Smoke test pós-deploy
Script que bate em `/health`, `/api/v1/plans` (público após fix), `/api/v1/checkout/config` e valida respostas esperadas. Executa automaticamente em rollback-trigger.
