# 부스터 & 데일리 보상 — 설계 (Boosters & Daily Reward)

작성일: 2026-06-18 · 상태: 승인됨(오너) → 구현 계획 단계로

## 목표 / 맥락

광고 수익형 퍼즐게임 Block Seasons의 **리텐션(복귀) + 광고 노출**을 동시에 키우는
키스톤 기능. 현재 게임엔 플레이어에게 줄 "보상 대상"이 없어 데일리 보상·보상형
광고를 붙일 곳이 없었음 → **가벼운 부스터(파워업) 경제**를 도입해 둘 다 해금한다.

사업자등록이 없어 IAP는 막혀 있으므로 **재화/상점 없이** 부스터를 직접 주고받는다.

## 확정된 결정 (브레인스토밍)

1. **부스터 3종**: 🔨해머 / 🔀셔플 / 💥줄폭탄
2. **획득**: 재화 없음 — 데일리 보상 + 보상형 광고로 부스터를 직접 받아 **비축**
3. **데일리**: 7일 출석 캘린더 (점증, Day7 잭팟) + "광고 보고 2배"
4. **사용**: 게임 중 **부스터 바 → 대상 지정**

## 부스터 규칙 (밸런스, 오너 승인)

- **이동 수 미소모** — 부스터는 보조라 무브 카운터를 깎지 않는다.
- **점수·콤보 미부여, 목표 미반영** — 그리드만 직접 바꾸고 점수/목표 이벤트 파이프라인을
  타지 않는다. 줄폭탄으로 "줄 N개" 목표를 깨거나 해머로 보석을 제거해 "보석 N개"
  목표를 달성할 수 없다(스테이지 난이도 보존). 콤보 상태도 건드리지 않는다(전진·리셋 둘 다 없음).
- **막힌 보드 되살리기 허용** — 부스터 사용 후 phase를 재평가(`_checkStuck`)해, 죽은 판
  (boardDead)을 다시 playing으로 되돌릴 수 있다 → 보상형 '컨티뉴'의 대안.
- **사용 가능 시점** — phase가 `playing` 또는 `stuck`일 때만. `won`/`lost` 후엔 불가.
- **사용 한도** — 별도 횟수 제한 없음. 보유량이 곧 한도(가진 만큼만 사용).
- **엔드리스 모드 포함** — 엔드리스에서도 사용 가능.

### 부스터별 동작
| 부스터 | 동작 | 대상 |
|---|---|---|
| 🔨 해머 | 채워진 칸 1개를 비움 | 칸 1개 탭 |
| 🔀 셔플 | 현재 트레이(3조각)를 새로 교체 | 즉시(대상 없음) |
| 💥 줄폭탄 | 가로 또는 세로 한 줄 전체를 비움 | 줄(행/열) 선택 |

## 아키텍처 (기존 레이어 준수: ui → state → game|data|services)

### 1) 엔진 (순수 Dart, `lib/game/engine/game_engine.dart`)
세 메서드 추가. 성공 시 `true`, 잘못된 대상/시점이면 `false`(보유량 차감 안 하도록).

```
bool useHammer(int x, int y)         // (x,y)가 채워진 칸이면 비움
bool useShuffle()                    // 트레이 재추첨
bool useLineBomb({int? row, int? col}) // row 또는 col 중 하나의 줄을 비움
```

공통: 이동/점수/콤보/목표 불변, 마지막에 `_checkStuck()` 호출. `playing`/`stuck`에서만 허용.
줄폭탄은 `row`와 `col` 중 정확히 하나만 지정(둘 다/둘 다 없음이면 `false`).

### 2) 모델 (순수 Dart, `lib/game/models/booster.dart`)
```
enum BoosterType { hammer, shuffle, lineBomb }
```

### 3) 저장 (`lib/data/save_repository.dart`, JSON blob 확장)
- 보유량: `int boosterCount(BoosterType)`, `Future<void> grantBooster(BoosterType, [int n = 1])`,
  `Future<bool> consumeBooster(BoosterType)`(0이면 false).
- 데일리: `String? dailyLastClaimedYmd`, `int dailyCalendarDay`(1~7),
  `Future<void> recordDailyClaim(String ymd, int day)`.
- JSON에 `boosters: {hammer, shuffle, lineBomb}` 와 `daily: {lastYmd, day}` 추가
  (기존 streak의 ymd 유틸 재사용).

### 4) 상태 (Riverpod, `lib/state/`)
- `BoosterInventoryNotifier` — 보유량 노출 + `grant/consume`.
- `DailyRewardNotifier` — 오늘 받을 수 있는지 + 캘린더 day 계산 + claim.
- `GameSessionNotifier`에 사용 메서드 추가: `useHammer(x,y)` / `useShuffle()` /
  `useLineBomb(...)`. 흐름: **엔진 먼저 호출 → 성공 시에만 인벤토리 차감 → 뷰 갱신**.
  보유 0이면 호출하지 않음(UI가 광고 제안).
- `GameViewState`에 grid가 이미 있어 부스터 후 UI 재렌더 가능.

### 5) 데일리 캘린더 로직 (순수, 테스트 가능)
- 오늘 ymd 계산. `lastClaimedYmd == 오늘` → 이미 받음(비활성).
- 받을 수 있는 경우의 day:
  - `lastClaimedYmd == 어제` → `day = (이전 day % 7) + 1`(연속, 7→1 순환).
  - 그 외(하루 이상 빠짐/최초) → `day = 1`(리셋).
- claim 시 해당 day 보상 지급 + `lastClaimedYmd = 오늘`, `calendarDay = day` 저장.
- **보상표(제안, 튜닝 가능)**:
  | Day | 보상 |
  |---|---|
  | 1 | 🔨×1 |
  | 2 | 🔀×1 |
  | 3 | 💥×1 |
  | 4 | 🔨×1 🔀×1 |
  | 5 | 🔀×1 💥×1 |
  | 6 | 🔨×1 💥×1 |
  | 7 | 🔨×2 🔀×2 💥×2 (잭팟) |
- 시작 보유량: 각 1개(최초 1회).

### 6) UI (`lib/ui/`)
- **부스터 바 위젯** — 보드 아래 3버튼(아이콘+개수). 탭 시 타겟팅 모드 진입.
  - 해머: 채워진 칸 탭 → 제거.
  - 줄폭탄: 보드 가장자리에 행/열 핸들 표시 → 핸들 탭으로 줄 선택(가장 명확한 UX,
    구현 중 세부 조정 가능).
  - 셔플: 즉시 적용.
  - 개수 0인 버튼 탭 → "광고 보고 1개 받기" 다이얼로그.
- **데일리 팝업** — 홈 화면 진입 시 받을 수 있으면 표시. 7칸(과거=체크/딤, 오늘=하이라이트,
  미래=잠금) + [받기] + [광고 보고 2배].

### 7) 광고 (`lib/services/ad_service.dart` 재사용)
- 부스터 0개 → 보상형 광고 → 성공 시 해당 부스터 +1.
- 데일리 2배 → 보상형 광고 → 성공 시 보상 2배 지급.
- `showRewarded()`는 광고 미로드 시에도 true(기존 플레이어 친화 폴백) → 부스터는 지급됨.

### 8) 분석 (`lib/services/analytics_service.dart`)
- `booster_used {type}`
- `booster_granted {type, count, source: start|daily|ad}`
- `daily_reward_claimed {day, doubled}`

### 9) l10n (`lib/l10n/`)
- 부스터 이름·설명, 데일리 보상 UI, "광고 보고 받기/2배" CTA — EN/KO.

## 테스트 전략 (TDD)
- **엔진**: 해머(칸 제거·이동/점수/목표 불변·빈 칸이면 false·죽은 판 되살림),
  셔플(새 트레이·불변·재stuck), 줄폭탄(행/열 제거·불변·재stuck·row^col 검증),
  won/lost 후 사용 차단.
- **저장**: grant/consume/영속, 0에서 consume=false, 데일리 ymd/day 영속.
- **데일리 로직**: 연속 시 day+1, 빠짐 시 리셋, 같은 날 재수령 불가, 보상표 지급, 2배.
- **세션 노티파이어**: 성공 시 차감, 잘못된 대상/0개면 미차감.
- **위젯**: 부스터 바 개수 렌더·타겟팅, 데일리 팝업 상태.

## 구현 단계 (계획에서 상세화)
1. 엔진 부스터 3종 (TDD, 순수)
2. `BoosterType` + SaveRepository 인벤토리 (TDD)
3. 인벤토리/세션 노티파이어 + 사용 흐름 (TDD)
4. 부스터 바 UI + 타겟팅 (위젯 테스트)
5. 데일리 캘린더 로직 + 노티파이어 (TDD)
6. 데일리 팝업 UI
7. 보상형 광고 지급(0-상태 + 데일리 2배)
8. 분석 + l10n
9. 통합 + 전체 테스트 그린

## 비목표 (YAGNI)
- 코인/재화/상점, 부스터 회전·되돌리기, IAP 부스터 판매, 부스터 합성/업그레이드.

## 리스크 / 메모
- 부스터가 점수·목표에 반영되지 않으므로 기존 스테이지 밸런스는 그대로 유효.
- 보상형 광고 미로드 시에도 부스터를 지급(폴백) → 신규 앱 no-fill 기간에도 게임 흐름 유지.
- 새 빌드 필요(부스터·데일리는 다음 릴리스부터). 빌드는 오너 명령 시에만.
