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

# 이벤트 규칙 - 속도, 비율, 순서, 상관관계

> Didit의 이벤트 데이터에 대한 속도, 비율, 순서, 교차 주체 상관관계 규칙을 거래 규칙과 같은 규칙 빌더에서 작성하세요.

[이벤트](https://docs.didit.me/ko/transaction-monitoring/events.md)는 거래와 같은 엔진으로 평가됩니다. 규칙 모델, 조건 어휘, 작업 집합은 하나이며, 규칙은 어떤 레코드 종류에 적용되는지만 선언합니다.

## 적용 대상

`scope.record_types`는 규칙이 어떤 레코드에서 실행될지 결정합니다.

| `record_types` | 실행 대상 |
| - | - |
| 생략하거나 `["transaction"]` | 거래만 - **기본값** |
| `["event"]` | 이벤트만 |
| `["transaction", "event"]` | 거래와 이벤트 모두 |

> [!NOTE]
>
> 이 항목을 생략하면 규칙은 거래에만 적용됩니다. 이벤트가 도입되기 전에 작성된 모든 규칙은 이전과 똑같이 동작하며, scope가 비어 있다는 이유만으로 규칙이 로그인과 일치하기 시작하지 않습니다.

콘솔에서는 규칙의 Trigger 단계에 있는 **적용 대상** 선택기가 이에 해당합니다. 이벤트를 선택하면 **이벤트 카테고리** 체크리스트가 나타나 규칙 범위를 더 좁힙니다. 모두 선택하지 않은 상태로 두면 모든 카테고리를 평가합니다.

```json theme={null}
{
  "title": "Failed login burst",
  "scope": {
    "record_types": ["event"],
    "event_categories": ["security"]
  },
  "aggregation": [
    {
      "metric": "count",
      "operator": "gte",
      "value": 3,
      "window": "30m",
      "filters": {
        "subject_vendor_data": "__current__",
        "event.action_type": "login_failed"
      }
    }
  ],
  "actions": [
    { "type": "add_score", "value": 40 },
    { "type": "change_status", "value": "IN_REVIEW" }
  ]
}
```

`"__current__"`는 "평가 중인 이벤트와 같은 값"을 뜻합니다. 규칙이 값을 지정하지 않고도 *대상별*, *기기별* 또는 *라운드별*을 표현하는 방식입니다.

그룹화할 값이 없는 레코드는 서로 묶이지 않습니다. 기기 지문이 없는 이벤트는 지문이 없는 다른 이벤트와 "같은 기기"가 아니며, 대상을 지정하지 않은 이벤트는 다른 익명 이벤트와 "같은 대상"이 아닙니다. 평가 중인 이벤트에 `"__current__"` 필드의 값이 없으면 연산자와 관계없이 해당 집계는 일치하지 않습니다.

## 이벤트 필드

조건은 네임스페이스가 붙은 경로를 읽습니다. 이미 알고 있는 거래 어휘(`action_type`, `subject_vendor_data`, `subject_ip_country`, `custom_values.<key>`)도 이벤트에서 해석됩니다.

| 그룹 | 경로 |
| - | - |
| 이벤트 | `event.category`, `event.action_type`, `event.occurred_at`, `event.amount`, `event.currency`, `event.direction`, `event.session_id`, `event.session_sequence`, `event.score`, `event.status`, `event.ingest_source`, `event.retention_class`, `event.subject_vendor_data`, `event.business_vendor_data` |
| 기기 및 네트워크 | `event.device.fingerprint`, `event.device.persistent_device_id`, `event.device.bot_score`, `event.ip.address`, `event.ip.country`, `event.ip.asn_number`, `event.ip.asn_organization`, `event.ip.is_vpn_or_tor`, `event.ip.is_data_center`, `event.ip.proxy_type`, `event.ip.country_name`, `event.ip.city`, `event.ip.connection_type`, `event.ip.travel_distance_km`, `event.ip.travel_speed_kmh` |
| 게임플레이 | `event.gameplay.game_id`, `event.gameplay.table_id`, `event.gameplay.round_id`, `event.gameplay.hand_id`, `event.gameplay.match_id`, `event.gameplay.market_id`, `event.gameplay.side`, `event.gameplay.role`, `event.gameplay.counterparty_vendor_data`, `event.gameplay.net_result_amount`, `event.bonus.bonus_id`, `event.affiliate.affiliate_code` |
| 결제 및 분쟁 | `event.payment.reference_id`, `event.payment.payment_fingerprint`, `event.payment.instrument_reference_hash`, `event.payment.withdrawal_address_hash`, `event.dispute.dispute_id`, `event.dispute.chargeback_id` |
| 보안 및 책임 있는 게임 | `event.security.changed_field`, `event.responsible_gambling.identity_match_ref` |
| 봇 및 지원 텔레메트리 | `event.bot.timing_variance_ms`, `event.bot.actions_per_minute`, `event.bot.pointer_entropy`, `event.bot.reaction_time_ms_p50`, `event.bot.assistance_indicator` |
| 대상 신호 | `subject.email.risk_score`, `subject.email.social_count`, `subject.email.is_disposable`, `subject.email.deliverability`, `subject.email.domain_reputation`, `subject.email.first_seen_days`, `subject.email.is_breached`, `subject.phone.risk_score`, `subject.phone.line_type`, `subject.phone.social_count`, `subject.phone.carrier`, `subject.phone.country`, `subject.phone.is_disposable` |
| 그 밖의 항목 | `event.payload.<key>`, `custom_values.<key>` |

대상 신호는 모니터링 대상 사용자에 캐시되며 이벤트마다 다시 계산되지 않습니다. 따라서 규칙은 수집 속도로 이 신호를 읽을 수 있습니다.

## 집계

### 벨로시티

거래에서 이미 사용하는 리듀서인 `count`, `sum`, `avg`, `min`, `max`, `distinct_count`를 롤링 `window`(`30m`, `24h`, `7d`, `30d`)에 걸쳐 적용합니다.

### 비율

같은 window에 걸친 두 리듀서입니다. 베팅 대 입금, 출금 대 입금, 보너스 대 입금, 차지백 비율이 이 방식으로 표현됩니다.

```json theme={null}
{
  "metric": "ratio",
  "window": "24h",
  "filters": { "subject_vendor_data": "__current__" },
  "numerator":   { "metric": "sum", "field": "event.amount", "filters": { "event.action_type": "bet_placed" } },
  "denominator": { "metric": "sum", "field": "event.amount", "filters": { "event.action_type": "deposit_completed" } },
  "operator": "lte",
  "value": 0.1
}
```

1,000을 입금하고 20을 베팅한 뒤 출금을 요청하면 비율은 0.02입니다. 전형적인 최소 플레이 자금 세탁입니다.

> [!NOTE]
>
> **분모가 없는 비율은 절대 일치하지 않습니다.** 입금이 없는 경우는 비율 0이 아니라 증거가 없는 상태이며, 이때 규칙이 실행되면 신규 사용자 전원이 플래그로 표시되기 때문입니다.

### 시퀀스

윈도우 안에서 순서가 있는 조건입니다. 각 단계는 `action_type`, `event_category` 또는 임의의 `match` 필터와 일치하며, 시퀀스가 다음 단계로 넘어가기 전에 `min_count`만큼의 발생을 요구할 수 있습니다.

```json theme={null}
{
  "metric": "sequence",
  "key": "ato_drain",
  "window": "24h",
  "steps": [
    { "event_category": "security", "action_type": "login_failed", "min_count": 3 },
    { "event_category": "security", "action_type": "mfa_changed" },
    { "event_category": "payment",  "action_type": "withdrawal_address_changed" },
    { "event_category": "payment",  "action_type": "withdrawal_requested" }
  ]
}
```

자격 증명 스터핑, MFA 탈취, 지급 경로 변경, 자금 인출 순서입니다. 규칙은 체인을 완성하는 이벤트에서 실행되며, 일치한 증거에는 모든 단계의 이벤트 ID가 나열됩니다.

시퀀스 상태는 규칙과 대상별로 유지되므로, 타임라인을 다시 스캔하지 않고 이벤트가 도착할 때마다 진행됩니다. 윈도우보다 오래된 진행 상태는 집계되지 않고 폐기됩니다.

### 상관관계

대상을 넘나드는 조인입니다. 현재 이벤트와 같은 그룹을 공유하는 모든 이벤트에 대해 리듀스합니다.

```json theme={null}
{
  "metric": "correlation",
  "window": "7d",
  "pair": true,
  "group_by": ["subject_vendor_data", "event.gameplay.counterparty_vendor_data"],
  "filters": { "event.action_type": "p2p_settlement" },
  "correlate": {
    "metric": "sum",
    "field": "event.gameplay.net_result_amount",
    "filters": { "event.gameplay.role": "winner" }
  },
  "operator": "gte",
  "value": 500
}
```

`"pair": true`는 두 끝점을 순서 없는 집합으로 일치시키므로 A→B와 B→A가 같은 그룹에 들어갑니다. 이 덕분에 하나의 규칙이 공모의 양쪽을 모두 볼 수 있습니다. 칩 덤핑, 반대 베팅, 제휴사 자기 추천이 모두 이 형태입니다.

상관관계 규칙에는 항상 범위를 좁히는 `filters`를 지정하십시오. 지정하지 않으면 윈도우 안의 모든 이벤트를 대상으로 합니다.

## 실시간 및 비동기 규칙

일부 규칙은 수집 요청 내에서 응답할 수 있고, 일부는 그럴 수 없습니다.

| 실행 시점 | 해당 규칙 |
| - | - |
| **요청 내에서** | 속도, 비율, 제한된 시퀀스(윈도우 최대 24시간) |
| **수 분 내, 비동기로** | 상관관계 규칙, 그리고 윈도우가 24시간을 넘는 시퀀스 |

규칙 처리가 대기 중인 이벤트는 `"correlation_pending": true`와 함께 반환됩니다. 상태와 점수는 비동기 처리가 완료되면 해당 이벤트에서 바로 업데이트됩니다. 재실행은 멱등성이 보장되므로, 규칙이 점수를 두 번 적용하는 일은 없습니다.

이렇게 나눈 것은 의도된 설계입니다. 여러 주체에 걸친 링 쿼리 때문에 로그인이 기다려서는 안 됩니다.

## 작업

거래 규칙과 같은 작업 어휘를 사용합니다. `add_score`, `change_status`, `add_tags`, `add_note`, `add_to_list`, `open_case`가 있습니다.

이벤트에서는 두 가지가 다릅니다.

* `change_status`를 `AWAITING_USER`로 설정하는 것은 거래에만 해당하는 결과입니다(이벤트에는 시정 절차가 없습니다). 이 경우 `IN_REVIEW`로 적용됩니다.
* `open_case`는 케이스를 거래가 아닌 **주체**에 연결하고, 일치한 이벤트 ID를 케이스에 기록합니다.

## 증거

모든 일치 결과에는 확인한 내용이 저장됩니다. 집계 윈도우, 계산된 값, 기대 값, 샘플 이벤트 ID, 그리고 **일치한 각 필드의 출처**가 포함됩니다.

| 출처 | 의미 |
| - | - |
| `server` | Didit이 도출한 값입니다(IP, 사용자 에이전트, origin). 권위 있는 값입니다. |
| `sdk` | Didit SDK가 기기에서 보고한 값입니다. |
| `customer` | 고객의 시스템이 제공한 값입니다. |

따라서 분석가는 일치 결과에 따라 조치하기 전에 서버가 기록한 IP와 클라이언트가 제공한 힌트를 구분할 수 있습니다. 콘솔은 이벤트 드로어에서 일치한 각 필드 옆에 출처를 표시합니다.

## 예시

> [accordion] 최소 플레이 자금세탁
>
> 입금, 토큰 플레이, 빠른 출금. 조건은 `event.action_type eq withdrawal_requested`이며, 여기에 `24h` 동안 `lte 0.1`인 베팅 대 입금 비율을 더합니다.

> [accordion] 우호적 사기
>
> `30d` 동안 주체별 `count(chargeback_opened)` 대 `count(deposit_completed)` 비율이 `gte 0.5`인 경우입니다. 여러 계정에 걸친 하나의 결제 수단을 찾으려면 주체 대신 `event.payment.payment_fingerprint`로 그룹화합니다.

> [accordion] 계정 탈취 자금 인출
>
> 위의 `ato_drain` 시퀀스에 `add_score 90`과 `change_status DECLINED`를 적용합니다.

> [accordion] 칩 덤핑
>
> 위의 쌍 상관관계입니다. `value`를 테이블에서 의미 있는 금액으로 올리고, 게임을 구분하려면 `group_by`에 `event.gameplay.game_id`를 추가합니다.

> [accordion] 봇 플레이 및 실시간 보조
>
> `event.action_type eq bot_signal_observed`, `event.bot.timing_variance_ms lte 10`, `event.device.bot_score gte 90` 조건을 `add_tags`와 함께 사용합니다. 단일 스크립트가 아니라 봇 팜을 찾으려면 IP별 `event.device.fingerprint`의 `distinct_count`와 결합합니다.

> [accordion] 자발적 이용 제한 회피
>
> `event.action_type eq self_exclusion_match` 및 `event.payload.re_registration_attempt eq true` 조건을 사용하고, `open_case`로 에스컬레이션합니다.

## 다음 단계

> [card] [이벤트 수집](https://docs.didit.me/ko/transaction-monitoring/events.md)
>
> 이벤트 엔벨로프, 10개 카테고리, 배치 계약을 다룹니다.

> [card] [Rules API](https://docs.didit.me/ko/transaction-monitoring/rules-api.md)
>
> 프로그래밍 방식으로 규칙을 생성, 업데이트, 백테스트합니다.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.