Skip to main content

정책 룰이란?

정책 룰(Policy Rule) 은 조건 → 액션의 쌍입니다. 입력 facts가 조건을 만족하면 룰의 액션이 실행됩니다. 룰은 우선순위 순서 (0이 가장 높은 우선순위)로 평가됩니다.
각 룰은 특정 정책 버전에 속하며, 이름 / 우선순위 / 조건(트리 구조 로직) / 하나 이상의 액션을 가집니다.

조건 문법

조건은 SINGLEGROUP 두 노드 타입의 트리 구조입니다.
LexQ는 type: "SINGLE" / type: "GROUP", field, operator, value, valueType 필드를 사용하는 자체 condition DTO 포맷을 사용합니다. Console 내부 폼 표현(다른 필드명 사용 가능)과 혼동하지 마세요. API 또는 CLI 호출 시에는 항상 엔진 포맷을 사용해야 합니다.

SINGLE 조건

단일 fact를 값과 비교하는 leaf 노드:

GROUP 조건

자식 조건을 AND 또는 OR로 결합하는 branch 노드:

연산자

IN / NOT_IN의 경우 호환 타입 열은 검사 대상 fact의 타입(STRING 또는 NUMBER)을 가리킵니다. 제공하는 value는 리스트 자체이며, 그 valueTypeLIST_STRING 또는 LIST_NUMBER입니다.

값 타입

중첩 조건 예시

(customer_tier = "VIP" AND payment_amount >= 100000) OR region IN ["KR", "JP"]
위 예시에서 customer_tier, region, payment_amount는 사용자 정의 fact로 Fact Definitions에 등록하는 것이 좋습니다. 등록 전에 참조해도 되며 — LexQ는 미등록 키를 거부하지 않고 비차단 경고로 알립니다 — 등록하면 타입 검증과 requirements analyzer가 활성화됩니다. 기본 제공 시스템 fact는 user_id, user_tags 두 개뿐입니다.

액션 타입

LexQ 엔진의 액션은 도메인 중립 원시(primitive) 입니다. 엔진은 숫자와 구조만 봅니다 — 커머스 / 핀테크 / 보험 / 특정 비즈니스 모델을 가정하지 않습니다. 도메인 의미는 fact 이름과 integration 페이로드에 담깁니다.

MUTATE_FACT — Percentage

payment_amount를 10% 감소:
payment_amount가 200,000이면 → 180,000으로 감소. 변화량(-20,000)은 generatedVariablespayment_amount__delta로 노출됩니다.

연산자(Operator)

DIV + PERCENTAGE 조합은 DRAFT 저장 시점에 거부됩니다. DIV + value=0도 마찬가지입니다.

MUTATE_FACT — Fixed Amount

MUTATE_FACT — 반올림(Rounding)

기본적으로 calculator 출력은 무손실(lossless) 정밀도로 보존됩니다. 고정 자릿수가 필요할 때만 선택적 rounding 필드를 사용하세요.
rounding.scale[0, 16] 범위의 정수. rounding.modeHALF_UP(default), HALF_DOWN, HALF_EVEN, FLOOR, CEILING, DOWN, UP 중 하나. rounding을 생략하면 무손실 정밀도가 유지됩니다 — 가능하면 엔진이 아니라 다운스트림(예: 통화 표시 시점)에서 반올림하세요.

INCREMENT_FACT — Percentage

payment_amount의 1%를 total_point에 적립:
payment_amount가 100,000이면 → total_point가 1,000 증가. 증분량은 generatedVariablestotal_point__delta로 노출됩니다.
INCREMENT_FACT는 엔진 내부 fact 변경만 수행합니다. 외부 시스템(예: 포인트 서비스) 동기화가 필요하면 동일 룰 안에서 [INCREMENT_FACT, EMIT_EVENT] 체인으로 구성하세요. 엔진은 INCREMENT_FACT 대신 외부 시스템을 호출하지 않습니다 — 이는 엔진 상태와 외부 상태 사이의 audit-grade 분리를 보존하기 위함입니다.

INCREMENT_FACT — Fixed Amount

EMIT_EVENT

외부 integration에 generic 이벤트 페이로드를 발행합니다. 엔진은 integrationId와 비어있지 않은 eventPayload 맵의 존재만 검증합니다 — 페이로드 구조는 integration provider의 책임입니다.
도메인 전용 키(couponId, ticketId, claimId 등)는 integration provider가 라우팅합니다. 이로써 EMIT_EVENT는 진정한 generic primitive가 됩니다 — 쿠폰 발행, 티켓 생성, 보험 청구 제출 등 어떤 이벤트성 외부 호출에도 사용할 수 있습니다.

EMIT_NOTIFICATION

외부 integration을 통해 알림을 발송합니다.
targetVar는 수신자 fact를 지정합니다 (예: phone_number, email, device_token). notificationPayload는 채널, 템플릿, 변수 매핑을 integration provider에 전달 — 엔진은 이 키들을 해석하지 않습니다.

BLOCK — 요청 차단

SET_FACT — Output Variable

SET_FACT리터럴 값 setter이지 expression evaluator가 아닙니다. 출력의 키에 고정 값을 할당합니다. 산술 표현식이나 다른 fact 참조는 지원하지 않습니다.

ADD_TAG

리스트 fact에 태그를 추가합니다. 중복은 자동으로 방지됩니다. targetVar를 생략하면 user_tags가 기본값입니다.

EMIT_WEBHOOK — Basic

payloadTemplate 없이 사용하면 엔진은 모든 input/output facts를 요청 본문으로 전송합니다 (시스템 변수 제외).

EMIT_WEBHOOK — With Payload Template

payloadTemplate로 요청 본문을 커스터마이징하세요. 템플릿 변수는 실행 시점에 치환됩니다.

사용 가능한 템플릿 변수

Slack{"text": "..."}, Discord{"content": "..."} 형식이 필요합니다. 각 플랫폼이 기대하는 형식에 맞춰 payloadTemplate을 사용하세요.
{{fact.xxx}}{{output.xxx}}는 동일한 데이터 맵을 참조합니다. 이전 액션(예: MUTATE_FACT)이 payment_amount를 변경하면, {{fact.payment_amount}}{{output.payment_amount}} 모두 변경된 값을 반영합니다.

생성 변수 (Generated Variables)

변경된 facts와 별도로, 엔진은 액션별 변화 정보를 generatedVariables로 노출합니다: 한 룰에서 여러 액션이 같은 fact를 변경하면 __delta는 누적 변화량을 보고합니다. 액션별 스냅샷은 audit drill-down용으로 executionTraces에 보관됩니다.

Mutex — 룰 단위 충돌 해소

한 버전 내에서 룰들은 mutex 그룹에 속할 수 있으며, 이를 통해 매칭되는 룰 중 몇 개를 발화시킬지 제어합니다. mutexModeEXCLUSIVE이면 winning 룰 하나만 발화합니다. MAX_N이면 우선순위 순서로 최대 mutexLimit개의 룰이 발화합니다. 발화하지 못한 다른 매칭 룰은 Decision Trace에 status BLOCKED + reason MUTEX_PRIORITY_LOST 또는 MUTEX_LIMIT_REACHED로 기록됩니다 (Decision Trace 참조).

Decision Trace

룰 평가 결과는 모두 decision trace 엔트리로 기록되어 해당 룰이 발화했는지 / 왜 그렇게 결정됐는지를 설명합니다. 이는 LexQ의 audit-grade 추론 영역의 핵심입니다 — 모든 결과는 특정 status와 reason code로 추적할 수 있습니다. decision trace 엔트리는 두 분류 필드를 가집니다:
  • status — 결과의 상위 분류
  • reasonCode — 그 분류 안에서의 구체적 사유

DecisionStatus

DecisionReasonCode

Status × ReasonCode 매핑

“왜 내 룰이 발화하지 않았지?”를 디버깅할 때 decision trace는 두 단계로 답을 줍니다 — status는 어떤 분류의 필터링이 룰을 제거했는지 알려주고, reasonCode는 정확히 어떤 검증이 룰을 거부했는지 알려줍니다.

완전한 룰 예시

다음 단계

Fact Definitions

룰이 기대하는 입력 변수를 정의하세요.

Dry Run

배포 전에 룰을 테스트하세요.