# ONDA 0 — AUDITORIA (15/08/2026)

> Documento de diagnóstico. Nada de produção foi alterado para produzi-lo.
> Fontes lidas: `Sistema MMN Oferta Distribuidora/CLAUDE.md`, `ESTADO.md` (1.425 linhas),
> `CRM-PLANO.md` e leitura direta do código (2.951 arquivos, 92 deles tocam a Nuvemshop).

---

## A) DIAGNÓSTICO ATUAL

### A.1 O que existe hoje

| Camada | Realidade |
|---|---|
| Linguagem | PHP puro (8.3, LiteSpeed), sem framework, sem Composer no core |
| Banco | MySQL/MariaDB 10.6 `ofertadi_os` — **75 tabelas**, ~11 MB, via PDO |
| Fuso | `America/Cuiaba` no PHP + `SET time_zone='-04:00'` no MySQL |
| Hospedagem | cPanel compartilhado (`/home4/ofertadi`), deploy por espelho WinSCP |
| Publicação | **Sem git remoto, sem staging, sem teste automatizado** — o WinSCP publica direto em produção |
| Painéis | `vo/` (ERP), `afiliado/` (PWA afiliado+montador), `cliente.` (painel do cliente), `motorista.`, `catalogo.` |
| Crons | 29–30 linhas no cPanel, todas `cron-*.php` protegidas por `?chave=oferta_cron_2026` |
| Externos | Nuvemshop/Tiendanube, Evolution GO (WhatsApp), Meta Graph API (Ads/CAPI/Lead Ads), OpenAI, Google Drive (backup), Web Push + FCM |

### A.2 Módulos vivos que **não podem ser recriados**

ERP/PDV · MMN (3 níveis) · CRM (5 ondas entregues) · Marketing OS (M1–M13) · Agente IA de
WhatsApp · Painel do cliente · Cashback (ledger) · Montadores/OS · Motoristas/leads ·
Backup criptografado · Monitor + vigia de erros.

### A.3 A descoberta que muda o briefing

**Não existe integração de gateway de pagamento neste sistema.** O briefing diz
"manter Mercado Pago inicialmente" — não há uma linha de Mercado Pago no repositório
(as únicas ocorrências do termo estão dentro das bibliotecas `mpdf`/`dompdf`, sem relação).

Como funciona hoje, de verdade:

1. O cliente paga **dentro do checkout da Nuvemshop** (gateway contratado lá dentro).
2. `vo/api/sincronizar.php` importa o pedido para `pedidos_cache`.
3. Uma **pessoa** abre `vo/pedidos.php` e clica em **"dar baixa"**.
4. Só então `vo/api/dar-baixa.php` gera comissão MMN, cashback, evento CAPI, marca lead e conversa.

Ou seja: **a confirmação de pagamento é humana, não é webhook.** Isso tem duas
consequências para o projeto novo:

- A loja nova precisa apenas **produzir um pedido compatível**; o dinheiro continua
  sendo confirmado no PDV. É o caminho de menor risco e mantém comissão/cashback
  intocados.
- Quando existir gateway próprio com webhook, ligar "pago automaticamente" na baixa é
  **decisão do dono**, não consequência técnica (ver Riscos R5).

### A.4 O que a Nuvemshop realmente é hoje

Ela **não é só transporte**. É fonte de verdade de cinco coisas:

| Papel | Fonte de verdade? | Detalhe |
|---|---|---|
| Catálogo (produto, variante, preço, custo, estoque, foto) | **SIM** | Nenhuma tabela local de produto. `catalogo_indice` é só um índice derivado do agente IA |
| Pedido | **SIM** | `pedidos_cache` é espelho; a chave é `nuvemshop_id` (UNIQUE) |
| Checkout / carrinho abandonado | **SIM** | `GET /checkouts` é a única fonte |
| Cupom | **SIM** | Cashback e cupom de afiliado são criados via API na loja |
| Cliente | **Parcial** | `clientes` é fonte local de identidade; `ns_customer_id` é uma das 4 chaves |
| Atribuição de afiliado | **Transporte** | `customer_visit.utm_parameters.utm_content` carrega o código `GO_n` |
| Pagamento | **SIM** (checkout) | Mas a confirmação comercial é manual no PDV |

---

## E) MAPA DE DEPENDÊNCIAS DA NUVEMSHOP

Credenciais únicas: `STORE_ID 5466314`, `ACCESS_TOKEN` em `vo/config/db.php:14-17`
(**hardcoded, e repetido à mão** em `afiliado/api/venda-manual.php:17-19`,
`afiliado/diag-busca.php:7`, `cliente./config.php:59`, `vo/config/cashback.php:242`).

### E.1 Crítico — quebra dinheiro se sair do ar

| # | Arquivo | Chamada NS | O que faz | Substituto na loja nova |
|---|---|---|---|---|
| 1 | `vo/api/sincronizar.php` | `GET /orders`, `GET /products/{id}` | Importa pedido → `pedidos_cache`; **atribui afiliado por UTM**; cria/liga cliente; confirma uso de cupom de cashback; notifica afiliado e admin | `POST` da Commerce API para um endpoint novo no ERP (`vo/api/loja-pedido.php`), com a atribuição já resolvida no backend |
| 2 | `vo/api/dar-baixa.php` | — (indireto) | Motor de comissão MMN 3/2/1 %, cashback, CAPI, meta, CRM | **Não muda.** A loja nova só precisa entregar o pedido no formato dele |
| 3 | `afiliado/api/venda-manual.php:323` | `POST /orders`, `GET /products` | Venda manual do afiliado **cria o pedido dentro da Nuvemshop** | Passa a criar o pedido na loja nova (mesmo endpoint da Commerce API) |
| 4 | `vo/config/cashback.php:299-352` | `POST/PUT/DELETE /coupons` | Resgate: saldo vira cupom de 24h, cancelamento devolve saldo | Cupom nativo da loja nova (mesma assinatura de função `cbApiCupom`) |
| 5 | `vo/cron-carrinho-abandonado.php:101` | `GET /checkouts` | Única fonte de carrinho abandonado (WhatsApp 1h/24h) | Eventos próprios `cart_*`/`checkout_*` — **fica melhor** que hoje |
| 6 | `afiliado/api/criar-cupom.php:31` | `POST /coupons` | Cupom do afiliado | Cupom nativo |

### E.2 Alto — quebra operação, não dinheiro

| # | Arquivo | Chamada | O que faz |
|---|---|---|---|
| 7 | `vo/config/precificacao.php:45,64,81` | `PUT /products/{id}/variants/{id}` | **Escreve preço** na loja (motor de precificação) |
| 8 | `vo/aplicar-precos.php`, `vo/reverter-precos.php`, `vo/restaurar_kit_dalia.php` | `GET/PUT /products` | Aplicação e reversão de preços em lote (`precos_backup`) |
| 9 | `vo/painel-lucro.php`, `vo/nao-precificados.php`, `vo/relatorio-precificacao.php`, `vo/atualizar-custo-pendentes.php`, `vo/check-custo.php` | `GET /products` | Custo/margem por SKU (`painel_lucro_sku`) — **trava a baixa** quando falta montagem |
| 10 | `vo/agente/core/Catalog/CatalogIndexer.php:147,362` · `SearchEngine.php` · `agente/catalogo_api.php:430` · `agente/nuvemshop.php` | `GET /products` | Alimenta `catalogo_indice` — é **como a Helena (IA) acha produto no WhatsApp** |
| 11 | `vo/marketing-criativos.php:62,187` | `GET /products` | Vitrine automática, banner 1080×1080, lote de anúncios Meta |
| 12 | `catalogo.ofertadistribuidora.com.br/catalogomaisleve.php`, `gerar.php` | `GET /products` | Gerador de catálogo PDF por afiliado (⚠️ **mora fora do espelho do repo**) |

### E.3 Médio — dentro da própria loja (tema/scripts)

| # | Onde | O que é |
|---|---|---|
| 13 | GTM da loja (`docs/gtm-cupom-cashback.html`, `vo/gtm-cupom.txt`) | Pop-up de cupom de cashback quando chega `?coupon=CODIGO` (ES5 puro, exigência do GTM) |
| 14 | Script do banner de afiliado (`afiliado/api-afiliado-banner.php`) | Widget que aparece na loja com o WhatsApp do afiliado |
| 15 | Meta Pixel `623465246911282` | Instalado **na Nuvemshop**; o CAPI (`vo/config/meta.php`) deduplica por `event_id=pedido-{id}` |
| 16 | `linkAfiliado()` — `afiliado/config.php:513` | `LOJA_URL/?utm_source=AFF&utm_medium={nome}&utm_campaign=AFF&utm_content={go}` |

### E.4 Ferramentas / diagnóstico (baixo)

`vo/gerar_token_ns.php`, `vo/diag-cupom-api.php`, `vo/diag-checkouts.php`,
`vo/diag-cliente-nuvemshop.php`, `vo/diag-548.php`, `vo/api/ver-pedido-cru.php`,
`vo/reprocessar_afiliados.php`, `vo/teste-anuncio-m8.php`, `afiliado/diag-busca.php`.

### E.5 Webhooks e crons

- **A Nuvemshop não manda webhook para o sistema.** Zero. Tudo é *polling*.
  O único `webhook.php` do repositório é o da **Evolution/WhatsApp** (`vo/agente/webhook.php`).
- Crons que dependem da Nuvemshop: **`cron.php`/`sincronizar` (pedidos)**,
  **`cron-carrinho-abandonado.php`** (`*/15`), **`cron-cashback.php`** (`0 * * * *`,
  mata cupom vencido), `cron-catalogo-lead.php` e `cron-gerar-catalogos-dia.php`
  (dependem do gerador de catálogo, que lê a NS).

### E.6 O detalhe que salva a migração

`pedidos_cache.nuvemshop_id` é **`VARCHAR(20) NOT NULL UNIQUE`** — não é inteiro.
Pedido da loja nova pode entrar como **`LP-000123`**: não colide com id numérico da
Nuvemshop, o `ON DUPLICATE KEY` continua protegendo, e o `sincronizar.php` **nunca**
vai encostar nessas linhas (ele só casa com ids que a NS devolve).
→ **Nenhuma alteração destrutiva de schema é necessária para receber o primeiro
pedido da loja nova.** (Confirmar contra produção com `SHOW CREATE TABLE`, porque
`banco.sql` está desatualizado.)

---

## H) RISCOS

| # | Risco | Gravidade | Mitigação |
|---|---|---|---|
| R1 | **Infra**: Medusa/Vendure não rodam em cPanel compartilhado (precisam Node + Postgres + Redis). Hoje não existe servidor para isso | 🔴 Bloqueante | VPS dedicada (ver ARCHITECTURE §Infra). É a única decisão que trava a Onda 1 |
| R2 | **Comissão duplicada**: pedido entrar por dois caminhos (loja nova + sync NS) e gerar comissão 2× | 🔴 Alta | `nuvemshop_id` UNIQUE + `comissoes_geradas=1` + `ON DUPLICATE KEY` já protegem. Testar explicitamente na Onda 6 |
| R3 | **Catálogo divergente** entre NS e loja nova durante a transição (preço/estoque) | 🟠 Alta | NS é fonte de verdade até o cutover; sincronização **uma via só** (NS → loja nova). Nunca escrever na NS a partir da loja nova |
| R4 | **Atribuição perdida** — afiliado vende e não recebe | 🔴 Alta | Atribuição resolvida e persistida no **backend** (cookie 1st-party + `attribution` no carrinho). Nunca confiar no front. Regra "sem `go` = sem atribuição" (lição de 25/07: `GO_1` levava a comissão de todos os motoristas) |
| R5 | **Baixa automática por webhook** mudaria o significado de "pago" e dispararia comissão sem humano | 🟠 Média | Onda 5/6 mantém baixa manual. Ligar automático só depois, com decisão registrada |
| R6 | **Sem staging / sem teste** no lado PHP; publicação é WinSCP direto em produção | 🟠 Média | Todo código novo do lado ERP é **aditivo** (arquivo novo), nunca reescrita. Espelho conferido com `vo/espelho-conferir.php` |
| R7 | **Credenciais hardcoded** (banco, NS, Evolution, Meta) espalhadas em ≥5 arquivos | 🟠 Média | A loja nova nasce com `.env` + secrets fora do repo. Não copiar segredo nenhum para o projeto novo |
| R8 | **Pixel/CAPI duplicando Purchase** durante a coexistência (loja velha + nova) | 🟠 Média | `event_id = pedido-{id}` já é a chave de dedupe. Manter **um** emissor de Purchase por pedido |
| R9 | Gerador de catálogo PDF e o subdomínio `catalogo.` estão **fora do espelho** e com token antigo (pendência #7 do monitor, aberta desde 10/08) | 🟡 Média | Tratar na Onda 13; não misturar com a loja |
| R10 | SEO: trocar de plataforma sem mapa de redirects derruba ranking | 🟠 Alta | Exportar todas as URLs da NS antes do cutover e criar 301 1:1 (Onda 12/15) |
| R11 | Frete/entrega: as regras reais estão configuradas **dentro da Nuvemshop**, não no código | 🟠 Alta | Precisa de leitura do admin da NS (ver pedido de prints abaixo) |
| R12 | Custo de infra novo (VPS + Postgres + Redis + CDN) sem orçamento definido | 🟡 Baixa | Estimativa em ARCHITECTURE §Infra |

---

## O QUE EU AINDA NÃO SEI (preciso do admin da Nuvemshop)

Não dá para inventar isso a partir do código — está tudo dentro do painel da NS:

1. **Formas de pagamento ativas** e qual gateway está por trás (Nuvemshop Pagamentos? Mercado Pago? PagSeguro?), com as taxas e o parcelamento configurado.
2. **Frete**: quais métodos, faixas de CEP, valores, prazo, frete grátis, retirada.
3. **Aplicativos instalados** na loja (cada app é uma funcionalidade que a loja nova precisa reproduzir).
4. **Quantidade real**: nº de produtos publicados, variantes, categorias, clientes, pedidos.
5. **Campos extras no checkout** (CPF/CNPJ obrigatório? observação? data de entrega?).
6. **Cupons ativos** hoje (fora os de cashback/afiliado).
7. **Tema**: banners da home, vitrines, páginas institucionais, blog.
8. Se existe **certificado/domínio** já apontando e onde o DNS é gerenciado.

Prints dessas telas (ou export CSV de produtos) encurtam a Onda 2 em dias.

---

## LIMITES DESTA AUDITORIA

- Li o **espelho local** do sistema. Produção pode ter arquivos que o WinSCP não desce
  (é uma falha conhecida e registrada: o espelho só sobe).
- `catalogo.ofertadistribuidora.com.br` no repositório é uma **cópia defasada** — o
  gerador de verdade mora no servidor (registrado em ESTADO.md, 26/07).
- `banco.sql` está desatualizado; a lista de colunas foi reconstruída pelo código.
  Antes de qualquer migração, rodar `SHOW CREATE TABLE` nas tabelas tocadas.
- **Nada foi executado, alterado ou apagado no sistema atual.**
