> ## Documentation Index
> Fetch the complete documentation index at: https://lifters.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Motor de Scoring de Risco

> Engine de decisão em tempo real para análise de risco em depósitos — Camunda BPMN + DMN.

## O que é o Scoring Engine

O **Scoring Engine** do Atlas avalia automaticamente cada evento de depósito em tempo real, calculando um score de risco composto em três dimensões independentes:

<CardGroup cols={3}>
  <Card title="Risco Financeiro" icon="chart-line" color="#F26122">
    Analisa o valor do depósito, volume mensal acumulado e padrão de saques. Detecta operações acima dos limiares regulatórios da SPA/MF e BACEN.
  </Card>

  <Card title="PLD / AML" icon="shield-halved" color="#F26122">
    Aplica as regras da Circular COAF e Lei 9.613/98. Avalia contas vinculadas (smurfing), KYC pendente e depósitos de reporte obrigatório.
  </Card>

  <Card title="Comportamento" icon="brain" color="#F26122">
    Detecta padrões de ludopatia: apostas esportivas e de cassino em volume alto, ganhos atípicos e combinações de risco.
  </Card>
</CardGroup>

### Fórmula do Score Final

O score final é a média ponderada dos três módulos, arredondada ao inteiro mais próximo e limitada entre 0 e 100:

```
score_final = (score_financial × 0.40) + (score_aml × 0.30) + (score_behavior × 0.30)
```

| Dimensão         | Módulo DMN             | Peso    | Score máximo possível |
| ---------------- | ---------------------- | ------- | --------------------- |
| Risco Financeiro | `financial-risk-score` | **40%** | 130 pts (capped 100)  |
| PLD / AML        | `aml-rules`            | **30%** | 125 pts (capped 100)  |
| Comportamento    | `behavior-score`       | **30%** | 90 pts                |

<Info>
  Cada módulo DMN usa `hitPolicy="COLLECT" aggregation="SUM"` — todas as regras que casarem são somadas. Um único depósito pode ativar múltiplas regras simultaneamente.
</Info>

***

## Arquitetura do Pipeline

O Scoring Engine é um módulo Go autônomo que atua como **External Task Worker** do Camunda Platform 7. Não possui banco de dados próprio — o estado de processo vive no Camunda e os resultados fluem para o ClickHouse via Kafka. Recebe triggers exclusivamente via HTTP, sempre vindo do `backend/`.

```
Depósito (PIX / Gateway)
        │
        ▼
  ┌─────────────┐       ┌──────────────────────────────────────────┐
  │  Events API │──────▶│  Kafka  atlas.events.raw.transaction      │
  └─────────────┘       └──────────────┬───────────────────────────┘
                                       │
                                       ▼
                        ┌─────────────────────────────────────────┐
                        │  backend (auto-score consumer)           │
                        │  • Debounce in-memory por (org,brand,user)│
                        │  • Redis SETNX dedup (TTL 10/30min)       │
                        │  • Filtra is_test_account                 │
                        └──────────────┬──────────────────────────┘
                                       │ HTTP POST /api/v1/scoring/transaction/deposit
                                       ▼
                        ┌─────────────────────────────┐
                        │  scoring/ (Go + Camunda)    │
                        │  • Camunda BPMN deposit-scoring │
                        │  1. Financial Risk DMN ───▶ scoresFinancial │
                        │  2. AML Rules DMN      ───▶ scoresAml       │
                        │  3. Behavior Score DMN ───▶ scoresBehavior  │
                        │  4. External Task Worker    │
                        │     Calcula score final     │
                        └──────────────┬──────────────┘
                                       │
                                       ▼
                        ┌──────────────────────────────────────────┐
                        │  Kafka: atlas.l3.user.score              │
                        └──────────────┬───────────────────────────┘
                                       │ ClickPipe (cloud) / Kafka Engine (local)
                                       ▼
                               ClickHouse atlas.tbt_user_score
                                       │
                                       ▼
                                 backend → Dashboard
```

***

## Pipeline Passo a Passo

<Steps>
  <Step title="Ingestão do evento de depósito">
    O `backend/` consome os tópicos `atlas.events.raw.{transaction,casino,sportsbook}` e identifica eventos relevantes para scoring (deposit, withdraw, bet, cashout, etc).

    Eventos com `is_test_account: true` são **descartados silenciosamente** — não passam do consumer.
  </Step>

  <Step title="Debounce + dedup no backend">
    Antes de chamar o scoring, o backend agrupa eventos do mesmo `(organization_id, brand_id, user_ext_id)` em janelas de debounce (5s financial / 30s behavior). Quando a janela fecha, consulta Redis com `SETNX score_dedup:{org}:{brand}:{user}:{categoria} EX <ttl>` (10min financial, 30min behavior).

    Se a key já existe, o trigger é skip silencioso. Se Redis está fora, **falha fechado** — não dispara nenhum trigger até Redis voltar (alarme via métrica `auto_score_redis_unavailable_total`).
  </Step>

  <Step title="Trigger HTTP para o scoring/">
    Quando o dedup permite, o backend faz `POST /api/v1/scoring/transaction/deposit` com o snapshot agregado do jogador (totais financeiros, KYC, scores anteriores). Em caso de 5xx ou timeout, libera a key no Redis para o próximo evento poder retentar.

    O `ScoringSystemClient` no backend tem um circuit breaker em processo: 5 falhas consecutivas em 30s abrem o circuito por 60s.
  </Step>

  <Step title="Deduplicação por EID no Camunda">
    O scoring verifica se já existe uma instância de processo ativa com `businessKey = eid` no Camunda:

    ```
    GET /engine-rest/process-instance?businessKey={eid}&active=true
    ```

    Se uma instância já estiver ativa, o evento é ignorado — garantia de **idempotência** mesmo em redelivery Kafka.
  </Step>

  <Step title="Preparação das variáveis (LGPD-safe)">
    O serviço calcula o `withdrawalRatio` a partir dos totais do payload e constrói o mapa de variáveis do processo **sem nenhum dado de PII**:

    ```
    withdrawalRatio = withdrawals_total_amount / deposits_total_amount
    ```

    Campos como `document` (CPF), `first_name`, `email`, `phone`, `birthdate` e `ip` **nunca chegam ao Camunda**.
  </Step>

  <Step title="Correlação de mensagem no Camunda">
    O serviço correlaciona a mensagem `DepositScoringRequested` ao processo BPMN:

    ```
    POST /engine-rest/message
    {
      "messageName": "DepositScoringRequested",
      "businessKey": "{eid}",
      "processVariables": { ... }
    }
    ```

    O Camunda inicia uma nova instância de `deposit-scoring` e executa os três módulos DMN em sequência.
  </Step>

  <Step title="Avaliação sequencial dos módulos DMN">
    O processo BPMN executa três `businessRuleTask` em sequência:

    1. **Financial Risk Score** → variável `scoresFinancial`
    2. **AML Rules** → variável `scoresAml`
    3. **Behavior Score** → variável `scoresBehavior`

    Cada módulo usa `COLLECT + SUM` — todas as regras que casarem têm seus pontos acumulados.
  </Step>

  <Step title="Cálculo e publicação do score final">
    O External Task Worker `scoring.publish-score` (Go) faz o fetch-and-lock da tarefa, calcula:

    ```go theme={null}
    final := math.Round(float64(financial)*0.40 + float64(aml)*0.30 + float64(behavior)*0.30)
    final = math.Max(0, math.Min(100, final))
    ```

    E publica o `UserScore` em `atlas.l3.user.score`. Em caso de falha, o worker chama `HandleFailure` — o Camunda reentrega com retries decrescentes (3→2→1→0). Com 0 retries, um **Incident** é criado no Cockpit para investigação.
  </Step>
</Steps>

***

## Payload de Saída

O resultado publicado em `atlas.l3.user.score`:

```json theme={null}
{
  "eid": "550e8400-e29b-41d4-a716-446655440000",
  "organization_id": "org_abc123",
  "brand_id": "brand_xyz",
  "user_ext_id": "user_001",
  "event": "score",
  "scores_final": 78,
  "scores_financial": 95,
  "scores_aml": 75,
  "scores_behavior": 60,
  "scores_ludopathy": 0,
  "score_ml": 0
}
```

<Note>
  `scores_ludopathy` e `score_ml` são reservados para módulos futuros e retornam sempre `0` na versão atual.
</Note>

***

## Conformidade LGPD

O Scoring Engine foi projetado com **privacy-by-design**. Nenhum dado pessoal identificável (PII) transita pelo Camunda ou aparece no output de risco.

| Campo                             | Processado em             | Enviado ao Camunda | No output `l3.user.score` |
| --------------------------------- | ------------------------- | ------------------ | ------------------------- |
| `document` (CPF)                  | Consumer Go               | ❌ Nunca            | ❌ Nunca                   |
| `first_name`, `last_name`         | Consumer Go               | ❌ Nunca            | ❌ Nunca                   |
| `email`, `phone`                  | Consumer Go               | ❌ Nunca            | ❌ Nunca                   |
| `birthdate`, `ip`                 | Consumer Go               | ❌ Nunca            | ❌ Nunca                   |
| `amount`, `deposits_total_amount` | Consumer Go + Camunda DMN | ✅ Sim              | ❌ Não                     |
| `eid`, `user_ext_id`              | Consumer Go + Camunda     | ✅ Sim (IDs apenas) | ✅ Sim                     |
| `scores_financial/aml/behavior`   | Camunda DMN               | ✅ Sim              | ✅ Sim                     |

***

## Próximos passos

<CardGroup cols={2}>
  <Card title="Regras de Decisão DMN" icon="table" href="/guides/scoring/decision-rules">
    Todas as 16 regras dos três módulos com exemplos positivos e negativos
  </Card>

  <Card title="Integração e Triggers" icon="plug" href="/guides/scoring/integration">
    Como disparar o scoring via Kafka ou HTTP, schema completo do payload
  </Card>
</CardGroup>
