---
name: "PICKIT: Rules Init"
description: 트리거 × 사용자 유형 × 가격대 × 리뷰 유무 조합으로 ~70개 Rule을 자동 생성합니다. Phase 2 Bandit 학습 데이터를 충분히 확보할 수 있도록 조합을 세분화합니다.
category: PICKIT Workflow
tags: [pickit, rules, init]
---

# PICKIT Rules Init

4개 차원의 조합으로 Rule을 생성합니다. 질문 없이 실행하며, 완성된 파일을 바로 저장합니다.

---

## 조합 차원 (4개)

### 차원 1: 트리거 (10개)

| ID | 이름 | pickit.js 감지 조건 |
|---|---|---|
| T01 | 장시간 체류 | `timeOnPage ≥ 120s` |
| T02 | 반복 방문 | `productViewCount ≥ 3` |
| T03 | 리뷰 탭 클릭 | `reviewTabClick: true` |
| T04 | 옵션 미선택 장바구니 시도 | `has_option=true` + `#actionCart` 클릭 + 옵션 미선택 |
| T05 | 품절 근접 재고 | `stock_number ≤ 5` |
| T06 | 사이즈 가이드 클릭 | `.size_guide_info` 클릭 |
| T07 | 이탈 의도 | 마우스 뷰포트 상단 이탈 (PC) / 뒤로가기 제스처 (모바일) |
| T08 | 수량 증가 | `.QuantityUp` → `quantity ≥ 2` |
| T09 | 로그인 + 구매이력 | `iscache=F` + 서버 구매이력 확인 |
| T10 | 상세페이지 스크롤 완료 | `#prdDetail` scrollDepth ≥ 100% |

### 차원 2: 사용자 유형 (3개)

| 코드 | 조건 |
|---|---|
| `new` | `productViewCount = 1`, `isLoggedIn = false` |
| `returning` | `productViewCount ≥ 2`, `isLoggedIn = false` |
| `logged_in` | `isLoggedIn = true` |

### 차원 3: 가격대 (3개)

| 코드 | 조건 |
|---|---|
| `low` | `product_price < 30000` |
| `mid` | `product_price 30000–80000` |
| `high` | `product_price > 80000` |

### 차원 4: 리뷰 유무 (2개)

| 코드 | 조건 |
|---|---|
| `has_review` | `review_count ≥ 10` |
| `no_review` | `review_count < 10` |

---

## 넛지 타입 선택 로직

조합에 따라 최적 넛지 타입을 다음 우선순위로 결정:

### T07 (이탈 의도) — 가장 중요한 트리거

| 사용자 유형 | 가격대 | 리뷰 | nudge_type | 이유 |
|---|---|---|---|---|
| new | low | any | `social_proof` | 저가 신규, 사회적 증거로 가볍게 전환 |
| new | mid | has_review | `review_summary` | 중가 신규, 리뷰 확인 필요 |
| new | mid | no_review | `shipping` | 리뷰 없음, 배송 혜택으로 전환 |
| new | high | has_review | `review_summary` | 고가 신규, 신뢰 필요 |
| new | high | no_review | `quality` | 고가 리뷰 없음, 품질 보증 |
| returning | low | any | `shipping` | 재방문 저가, 배송 혜택으로 마무리 |
| returning | mid | any | `coupon` | 재방문 중가, 쿠폰으로 전환 유도 |
| returning | high | has_review | `coupon` | 재방문 고가, 쿠폰이 결정적 |
| returning | high | no_review | `quality` | 재방문 고가 리뷰 없음, 품질 보증 |
| logged_in | low | any | `coupon` | 로그인 저가, 쿠폰으로 즉시 전환 |
| logged_in | mid | any | `personalized` | 로그인, 개인화 넛지 |
| logged_in | high | any | `personalized` | 로그인 고가, 구매이력 기반 |

### T01 (장시간 체류)

| 사용자 유형 | 리뷰 | nudge_type |
|---|---|---|
| new | has_review | `review_summary` |
| new | no_review | `social_proof` |
| returning | has_review | `review_summary` |
| returning | no_review | `quality` |
| logged_in | any | `personalized` |

### T02 (반복 방문)

| 사용자 유형 | 가격대 | nudge_type |
|---|---|---|
| returning | low | `social_proof` |
| returning | mid | `coupon` |
| returning | high | `coupon` |
| logged_in | any | `personalized` |

### T03 (리뷰 탭 클릭)

| 리뷰 유무 | nudge_type |
|---|---|
| has_review | `review_summary` |
| no_review | `quality` |

### T04 (옵션 미선택 장바구니 시도)

→ 카테고리와 무관하게 항상 `size_guide`

### T05 (품절 근접 재고)

| 가격대 | nudge_type |
|---|---|
| low | `scarcity_stock` |
| mid | `scarcity_stock` |
| high | `scarcity_stock` + 강도 높임 (body에 재고수 명시) |

### T06 (사이즈 가이드 클릭)

→ 항상 `size_guide`. 가격대 high면 `review_summary`도 병행 Rule 추가.

### T08 (수량 증가)

→ 항상 `shipping`. (묶음 배송 혜택 안내)

### T09 (로그인 + 구매이력)

→ 항상 `personalized`. 가격대 high면 `review_summary` 병행.

### T10 (스크롤 완료)

| 사용자 유형 | 리뷰 | nudge_type |
|---|---|---|
| new | has_review | `social_proof` |
| new | no_review | `shipping` |
| returning | has_review | `review_summary` |
| returning | no_review | `quality` |
| logged_in | any | `personalized` |

### 행동 시퀀스 조합 Rule (Phase 2 Bandit 고도화용)

세션 내 복합 행동을 감지하는 추가 Rule:

| 시퀀스 | nudge_type | 이유 |
|---|---|---|
| T03 → T07 (리뷰 확인 후 이탈) | `review_summary` 강화 | 리뷰 봤지만 결정 못함 → 요약 제공 |
| T06 → T04 (사이즈 확인 → 옵션 고민) | `size_guide` 강화 | 사이즈 의심 → 리뷰어 사이즈 피드백 |
| T01 + T02 (장시간 + 재방문) | `coupon` | 고관여, 결정 장벽이 가격뿐 |
| T08 + T07 (수량 늘리다 이탈) | `shipping` | 묶음 구매 의향 있는데 이탈 |
| T05 + T07 (재고 부족 + 이탈) | `scarcity_stock` 강화 | 이탈 직전 재고 긴박감 최고조 |

---

## 실행 절차

### 1. 전체 Rule 목록 생성

위 로직을 적용해 모든 유효한 조합을 나열. 예상 총 Rule 수: **65~75개**.  
각 Rule에 순번 ID 부여: `R001` ~ `R075`

### 2. 각 Rule JSON 생성

```json
{
  "id": "R{003자리번호}",
  "trigger_id": "T0X",
  "nudge_type": "{타입}",
  "user_segment": "new | returning | logged_in",
  "price_tier": "low | mid | high | any",
  "review_tier": "has_review | no_review | any",
  "name": "{trigger_id}_{user_segment}_{price_tier}_{nudge_type}",
  "description": "한국어 발동 조건 설명",
  "priority": {숫자 — T07 기반 조합이 가장 높음},
  "enabled": true,
  "conditions": [
    { "field": "pageType", "op": "eq", "value": "product" },
    { "field": "timeOnPage", "op": "gte", "value": 120 },       // T01 예시
    { "field": "productViewCount", "op": "gte", "value": 1 },
    { "field": "isLoggedIn", "op": "eq", "value": false },
    { "field": "product_price", "op": "lt", "value": 30000 },
    { "field": "review_count", "op": "gte", "value": 10 }
    // ... 트리거/세그먼트/가격대/리뷰에 맞는 조건
  ],
  "nudge_source": "llm",
  "llm_context_fields": [...],
  "cooldown_sec": 600,
  "max_per_session": 1,
  "sequence_after": null,   // 시퀀스 Rule이면 선행 trigger_id 기재
  "tags": ["T0X", "{nudge_type}", "{user_segment}", "{price_tier}"]
}
```

**우선순위 기준 (priority):**
- T07 기반: 100–90 (이탈 직전 = 최고 우선순위)
- T05 기반: 89–85 (재고 긴박감)
- 시퀀스 조합: 84–80
- T02/T01 기반: 79–70
- 나머지: 69–50

### 3. nudge_copy.json 생성 (LLM 실패 시 폴백)

전체 Rule에 대해 조합별 정적 카피:

```json
"R001": {
  "icon": "...",
  "tag": "PICKIT · {상황 설명}",
  "title": "15자 이내 — 공감 또는 사실",
  "body": "40자 이내 — {user_segment}와 {price_tier}에 맞는 톤",
  "cta": "10자 이내",
  "cta_target": "#review | #actionCart | #prdDetail"
}
```

**톤 가이드:**
- new + low → 가볍고 친근한 ("이 가격에 이 퀄리티면 진짜 득템이에요")
- new + high → 신중하고 정보 중심 ("실구매자 87%가 재구매 의향")
- returning + any → 공감형 ("또 오셨네요, 이 분들도 고민하다 샀어요")
- logged_in → 개인화 힌트 ("회원님이 좋아하는 스타일이에요")

### 4. llm_prompts.py 생성

```python
# server/llm_prompts.py
# 자동 생성 — /pickit:rules-init으로 생성됨

NUDGE_PROMPTS: dict[str, str] = {
    "R001": """
당신은 이커머스 전환율 최적화 전문가입니다.

## 상황
트리거: {trigger_desc}
사용자: {user_segment_desc}
가격대: {product_price}원 ({price_tier})
리뷰 수: {review_count}개

## 활용 데이터
{llm_context_fields_desc}

## 쇼핑몰 브랜드 톤
{brand_voice} — 키워드: {tone_keywords}

## 출력 JSON
{{
  "icon": "이모지 1개",
  "tag": "PICKIT",
  "title": "15자 이내",
  "body": "40자 이내 — 반드시 실제 데이터 기반, 없으면 일반 문구",
  "cta": "10자 이내",
  "cta_target": "{cta_anchor}",
  "personalized": {is_personalized}
}}

## 규칙
- 수치는 실제 값만 사용 (없으면 생략)
- 과장 금지, 공감과 정보 제공 우선
- 한국어 작성
- {user_segment_specific_instruction}
""",
    "R002": """...""",
    # ... R003 ~ R075
}
```

### 5. 파일 저장

세 파일을 직접 생성 (없으면 새로 만들고, 있으면 덮어씀):

| 파일 | 내용 |
|---|---|
| `rules/rules.json` | Rule 배열 전체 |
| `rules/nudge_copy.json` | 폴백 카피 맵 |
| `server/llm_prompts.py` | 프롬프트 딕셔너리 |

저장 완료 후 요약 출력:

```
✅ Rules 초기화 완료
   총 Rule 수: {N}개
   트리거별: T01({n}), T02({n}), T03({n}), ...
   넛지 타입별: review_summary({n}), social_proof({n}), ...
   시퀀스 Rule: {n}개

다음 단계:
  /pickit:build backend  — Rule 엔진 + Bandit 상태 테이블 구현
  /pickit:nudge-gen      — 특정 카테고리용 Rule 개별 추가
  /pickit:debug          — Playwright로 트리거 발동 검증
```

---

## Phase 2 Bandit 연계 설계 원칙

Rule을 이렇게 세분화하는 이유: **Bandit이 (shop_id, rule_id, nudge_type) 단위로 Beta 분포를 학습**하기 때문.

Rule이 적으면 각 Rule에 이벤트가 몰려 Bandit이 세그먼트별 최적 타입을 구분하지 못함.  
Rule이 세분화될수록 "returning + high price에서는 coupon이 best"처럼 세그먼트별 최적화가 가능.

- **cooldown_sec: 600** — 같은 Rule 10분 쿨다운 (중복 발동 방지)
- **max_per_session: 1** — 세션당 1회 (Bandit 피드백 신호 오염 방지)
- **enabled: true** — 모든 Rule 기본 활성화 (CTR 낮은 Rule은 Bandit이 자연스럽게 비선택)
