# Painel P2P multi-exchange

Painel de gestão para operação P2P (C2C) em exchanges de cripto. O dono é
comerciante verificado (merchant) na Binance e na Bybit. O painel gerencia
anúncios, ajusta preços automaticamente, e automatiza parte do atendimento
no chat das ordens. Equipe: o dono (admin) + funcionários (operadores).

> Este arquivo é o contexto-mestre. Leia-o inteiro antes de codar.

## Stack

- **Runtime:** Node.js 24 LTS (instalado via NVM no usuário `mzdigital`).
- **Linguagem:** TypeScript (strict). ESM (`"type": "module"`).
- **Backend API:** Fastify.
- **Workers:** processos separados, sempre-vivos (ver Arquitetura).
- **Banco:** MySQL 8.0+ (schema em `db/schema.sql`). Driver: `mysql2/promise`.
- **Cache/fila:** Redis (já disponível no servidor).
- **Frontend:** React + Vite + TanStack Query.
- **Process manager (produção):** PM2.
- **HTTP p/ exchanges:** `fetch` nativo + `undici` `ProxyAgent` (proxy por conta).

Servidor: dedicado, root, 12 vCPU, ~31GB RAM, hostname `host4`, WHM/cPanel.

## Arquitetura

Três processos independentes, todos consumindo o mesmo código de domínio:

1. **API (Fastify):** serve o frontend (REST + WebSocket p/ o painel).
2. **Worker de chat:** mantém conexão WSS por conta com a exchange, espelha
   mensagens no banco, dispara automações e faz a ponte com o Telegram.
3. **Worker de pricing:** loop periódico que reajusta preços dos anúncios
   marcados como auto.

Regra de ouro: **toda chamada a uma exchange passa pelo cliente daquela
exchange** (`src/binance/`, futuramente `src/bybit/`). Ninguém chama a API
da exchange direto. É lá que vivem: assinatura, headers, proxy, rate-limit,
retry e logging.

### Abstração multi-exchange

Definir uma interface comum `ExchangeClient` (listar/criar/atualizar anúncio,
listar ordens, chat, etc.). Binance e Bybit a implementam. A lógica de
negócio (pricing, automações de chat) fala com a interface, não com uma
exchange específica. Hoje a doc da Binance está completa (SAPI v7.4); a da
Bybit (P2P Open API) será integrada depois — desenhe pensando nas duas.

## Segurança — NÃO NEGOCIÁVEL

Este painel detém credenciais que equivalem a dinheiro e dados pessoais de
clientes. Tratar com o cuidado correspondente.

- **Segredos criptografados em repouso (AES-256-GCM):** api_secret das
  exchanges, senha de proxy, token do bot Telegram, e dados pessoais de
  clientes (CPF, telefone, chave PIX). A chave mestra de criptografia vem de
  variável de ambiente (`MASTER_KEY`), **nunca** no banco, **nunca** no Git.
- **Nunca logar segredos.** Nem em log de debug, nem em mensagem de erro.
- **Nunca devolver o secret pro frontend.** Exibir só os últimos 4 dígitos.
  Edição substitui o valor; não revela o atual.
- **Permissões da chave na exchange:** habilitar só o necessário (C2C/trade
  nos pares). **Jamais habilitar saque.** Combinar com whitelist de IP (o IP
  do proxy).
- **`.env` no `.gitignore`.** Commitar apenas `.env.example` sem valores.
- **Controle de acesso:** `admin` vê/edita config sensível (chaves, proxy);
  `operator` opera o dia a dia. Registrar ações no `audit_log`.
- **LGPD:** CPF/telefone/PIX são dados pessoais. Guardar criptografado, usar
  só para a finalidade da operação.

## Domínio: regras de negócio

### Auto-pricing (worker de pricing)

Roda só para anúncios com `ad_pricing_config.enabled = 1`. Para cada um:

1. **Seguir concorrente:** consultar o mercado público de anúncios da exchange
   (Binance: `ads/search`), filtrar concorrentes pelos critérios configurados,
   e calcular `preço_alvo` conforme a estratégia (`beat_top` = ficar
   `beat_amount` melhor que o topo; `match_rank` = casar com o N-ésimo).
2. **Trava de lucro mínimo:** nunca passar do `min_profit_price`.
3. **Trava de spot:** consultar o preço spot do par na Binance
   (`api/v3/ticker/price`, ex: `USDTBRL`) e **nunca** postar pior que
   `spot * spot_margin_ratio`. O spot é a API pública de mercado, SEM
   assinatura — cliente separado do C2C.
4. **Preço final:** para SELL, `max(alvo, piso_lucro, piso_spot)`; para BUY,
   o inverso com `min`. Só chama `ads/update` se a variação exceder
   `min_price_step` (poupa rate-limit). Registrar tudo em `price_adjustments`.

Cuidado: nem todo par P2P tem spot 1:1 — quando faltar, a trava de spot
precisa de fallback (desabilitar a trava para aquele anúncio e avisar).

### Automações de chat (worker de chat)

Mensagens automáticas são **templates editáveis no painel**
(`message_templates`, com variáveis tipo `{nome}`, `{valor}`, `{ordem}`).
Cada gatilho tem liga/desliga. Disparo automático, mas só uma vez por ordem
(flags `orders.asked_validation` / `orders.asked_pix`).

- **`paid_new_customer_validation`:** quando a ordem é marcada como paga E a
  contraparte é cliente **novo/não-validado** (`counterparties.validated=0`),
  enviar template pedindo CPF + telefone. Cliente já validado: não enviar.
- **`counterparty_selling_pix`:** quando o cliente está vendendo cripto (ou
  seja, o anunciante COMPRA), enviar template pedindo a chave PIX.

### Ponte de chat com Telegram

Modelo escolhido: **grupo único com botão responder** (não usar tópicos de
fórum agora).

- Mensagem nova de cliente -> o bot posta no grupo do Telegram com contexto
  da ordem (nº, par, valor, cliente, link) + botão "Responder".
- Operador responde no Telegram (reply à mensagem do bot) -> o sistema
  reenvia para o chat da exchange via API C2C.
- Guardar o mapa em `chat_messages.telegram_message_id`.
- Filtrar ruído: só mensagens de cliente (`direction='in'`), só ordens ativas.
- Tratar ordem expirada/fechada (não tentar responder).
- Token do bot em `app_settings` (criptografado); `chat_id` do grupo também.

## Banco

Schema completo e comentado em `db/schema.sql`. Pontos-chave:
- `utf8mb4` em tudo; valores monetários sempre `DECIMAL(24,8)`, nunca float.
- Campos `*_enc` (`VARBINARY`) guardam ciphertext AES-256-GCM.
- `payload_raw JSON` guarda a resposta crua da exchange (campos ainda não
  promovidos a coluna). Promover a coluna conforme a necessidade.

## Cliente Binance C2C (já existe)

- `src/binance/client.ts` — assinatura HMAC-SHA256, headers obrigatórios
  (`X-MBX-APIKEY`, `clientType`, `x-user-id`), envelope `CommonRet`, erros.
- `src/binance/c2c-api.ts` — métodos tipados (ads, orders, chat, merchant).
  Tipos de resposta estão PARCIAIS de propósito (`[extra]: unknown`): rodar
  contra a API real e completar com o JSON que volta. Confirmar `priceType`
  (fixo vs flutuante) e os códigos numéricos de status com chamadas reais.
- Falta plugar o **proxy** no `client.ts` (via `undici` `ProxyAgent`,
  configurado por conta a partir de `exchange_accounts`).
- O chat usa **WSS** (`retrieveChatCredential` devolve URL + listenKey +
  token). O worker de chat abre essa conexão; o histórico vem por
  `retrieveChatMessagesWithPagination`.

Referência: documentação SAPI v7.4 (PDF do dono).

## Convenções

- Sentido de `trade_type` é sempre do ponto de vista do anunciante (você).
- Não inventar campos da API: confirmar contra a doc/resposta real.
- Toda escrita que dispara efeito externo (postar anúncio, enviar mensagem,
  liberar moeda) deve ser idempotente onde possível e registrada em
  `audit_log`.
- Português nos textos de UI e nas mensagens de cliente.

## Roadmap sugerido (ordem de construção)

1. Infra base: config, conexão MySQL/Redis, camada de cripto (AES-256-GCM).
2. Cofre de chaves + proxy: CRUD de `exchange_accounts` + `ProxyAgent` no
   cliente Binance. Testar uma chamada real autenticada via proxy.
3. Sync de anúncios e ordens (espelhar no banco).
4. Worker de pricing com as três travas (começar com dry-run: registra em
   `price_adjustments` sem aplicar, p/ você conferir antes de ligar).
5. Worker de chat: WSS + espelhar mensagens + automações de template.
6. Ponte Telegram.
7. Frontend (config, anúncios, pricing, ordens, chat).
8. Bybit: implementar `ExchangeClient` para a Bybit P2P Open API.

Sempre que possível, comece em modo de observação (dry-run / só leitura)
antes de habilitar ações que mexem em preço ou dinheiro.
