# Fontes de Monitoramento (monitoring_sources)

## Visao geral

O sistema usa uma **tabela unica e generica** para cadastrar todas as fontes de monitoramento, independente do tipo (Telegram, WhatsApp, X/Twitter, etc.).

Isso evita criar uma tabela separada para cada plataforma e permite que o sistema cresça sem refatoracao estrutural.

---

## Tipos de fonte suportados

| Tipo | Constante | Descricao |
|---|---|---|
| `telegram` | `TYPE_TELEGRAM` | Canais e grupos do Telegram |
| `whatsapp` | `TYPE_WHATSAPP` | Grupos do WhatsApp (via API oficial) |
| `twitter_x` | `TYPE_TWITTER_X` | Perfis e listas do X (antigo Twitter) |

Novos tipos podem ser adicionados sem alterar a estrutura do banco.

---

## Estrutura da tabela `monitoring_sources`

| Campo | Tipo | Descricao |
|---|---|---|
| `id` | int | Chave primaria |
| `user_id` | int (nullable) | Dono da fonte — preparado para multi-tenant |
| `name` | string | Nome amigavel (ex: "UrubuPromo") |
| `type` | string | Tipo da fonte: `telegram`, `whatsapp`, `twitter_x` |
| `identifier` | string | Endereco da fonte (varia por tipo — ver abaixo) |
| `active` | boolean | Ativo/inativo |
| `last_checkpoint` | string | Ultimo ID processado (generico: message_id, tweet_id, etc.) |
| `read_limit` | int | Quantidade maxima de itens lidos por execucao |
| `config` | JSON | Configuracoes extras especificas por tipo |
| `last_read_at` | timestamp | Ultima vez que a fonte foi lida |

### Campo `identifier` por tipo

| Tipo | Exemplo de identifier |
|---|---|
| `telegram` | `https://t.me/urubupromo` ou `@urubupromo` |
| `whatsapp` | `+5511999999999` ou link de grupo |
| `twitter_x` | `@urubupromo` |

### Campo `config` (JSON)

Usado para configuracoes extras sem precisar de novas colunas.

Exemplos:
```json
// Telegram
{ "delay_seconds": 5 }

// WhatsApp
{ "chip_number": "+5511999999999" }

// X (Twitter)
{ "list_id": "123456789", "filter_retweets": true }
```

---

## Checkpoint generico

O campo `last_checkpoint` e uma string generica que representa o ultimo item processado.

| Tipo | O que guarda |
|---|---|
| `telegram` | ID numerico da ultima mensagem processada |
| `twitter_x` | ID do ultimo tweet processado |
| `whatsapp` | Timestamp ou ID da ultima mensagem |

O sistema **nunca marca como lido na plataforma de origem** — o checkpoint e exclusivamente interno. Isso garante que abrir o app no celular nao interfere no processamento.

---

## Tabelas relacionadas

### `captured_urls`
Log bruto de todas as URLs capturadas por mensagem/post.

| Campo | Descricao |
|---|---|
| `monitoring_source_id` | Fonte de origem |
| `external_id` | ID externo da mensagem/post |
| `url` | URL bruta capturada |
| `platform` | Plataforma detectada: `mercadolivre`, `amazon`, `shopee`, `outros` |
| `published_at` | Data/hora da publicacao original |

### `processed_offers`
Registro de ofertas ja processadas — chave de deduplicacao.

| Campo | Descricao |
|---|---|
| `user_id` | Para isolamento multi-tenant |
| `platform` | Plataforma do produto |
| `dedupe_key` | SHA1(`platform:product_id`) — chave unica de deduplicacao |
| `product_id` | MLB-XXXXX, ASIN, etc. |
| `original_url` | URL original que gerou o registro |
| `monitoring_source_id` | Fonte de origem |
| `external_id` | ID externo da mensagem/post de origem |

---

## Estrategia de deduplicacao

A deduplicacao e feita **por produto**, nunca por URL.

- A URL original muda a cada execucao (parametros `matt_*`, `ref`, etc.)
- O ID do produto (`MLB`, `ASIN`) e estavel
- `dedupe_key = SHA1(platform:product_id)`
- Indice unico em `(user_id, dedupe_key)` garante que nao ha duplicatas mesmo com multiplos workers

---

## Deduplicacao por janela de tempo

O sistema nao reposta o mesmo produto se ele ja foi processado dentro de uma janela de tempo configuravel.

| Configuracao | Padrao | Onde alterar |
|---|---|---|
| Janela de deduplicacao | **24 horas** | `.env` (`TELEGRAM_DEDUPE_HOURS`) ou painel admin (futuro) |

### Comportamento

- Mesmo produto visto nas **ultimas 24h** → ignorado (duplicata)
- Mesmo produto apos **24h** → tratado como novo, pode ser repostado

### Por que 24h?

Em grupos de alta frequencia (100+ posts/dia), o usuario normalmente marca as mensagens como lidas e segue em frente. Um produto que volta a aparecer apos 24h e uma nova oportunidade valida de divulgacao.

### Ajuste futuro no painel admin

O valor de 24h e o padrao recomendado, mas podera ser alterado diretamente pelo painel admin sem necessidade de alterar o `.env` ou fazer deploy.

Exemplos de uso:
- **12h** — grupos com altissimo volume, evitar repeticao no mesmo turno
- **24h** — padrao recomendado
- **48h** — mais conservador, evita repost em dias consecutivos

---

## Limpeza automatica (prune)

| Tabela | Logica | Padrao | Variavel de ambiente |
|---|---|---|---|
| `processed_offers` | Apagar com mais de X horas (janela de dedup) | 24h | `TELEGRAM_DEDUPE_HOURS` |
| `captured_urls` | Apagar com mais de X dias (log de auditoria) | 7 dias | `TELEGRAM_PRUNE_CAPTURED_URLS_DAYS` |

A limpeza roda automaticamente via Cron diario (`telegram:prune`).

Com 24h de janela, a tabela `processed_offers` **nunca cresce** alem das ofertas do dia atual.

Estimativa de tamanho maximo: **< 500 KB** para as duas tabelas juntas.

---

## Multi-tenant

O campo `user_id` em `monitoring_sources` e `processed_offers` prepara o sistema para venda de acesso:

- Cada cliente tem suas proprias fontes, isoladas por `user_id`
- A deduplicacao e por conta (`user_id + dedupe_key`)
- Um cliente nao interfere nas fontes ou ofertas de outro

---

## Configuracao no painel admin (futuro)

Quando o painel visual for implementado, o usuario podera:

- Cadastrar/editar/desativar fontes por tipo
- Configurar o limite de leitura por fonte
- Configurar a frequencia do Cron
- Configurar o limite de prune
- Visualizar URLs capturadas e ofertas processadas

---

## Comandos disponiveis (fase de testes)

| Comando | Descricao |
|---|---|
| `telegram:source-add {identifier} {name}` | Cadastra nova fonte Telegram |
| `telegram:read-links` | Le mensagens pendentes de todas as fontes Telegram ativas |
| `telegram:read-links --channel=URL` | Teste avulso sem banco |
| `telegram:prune` | Limpeza de registros antigos |
| `telegram:prune --dry-run` | Simula limpeza sem apagar |
