diff --git a/README.md b/README.md
index 4e47ec6..e5e1b64 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,294 @@
-# Template Backend
+๏ปฟ
-[](https://sonarcloud.io/summary/new_code?id=ureca-mini2-div4_template-backend)
-[](https://sonarcloud.io/summary/new_code?id=ureca-mini2-div4_template-backend)
+# ๐ dabom-processor-usage
+
+### Kafka `usage-events` ๊ธฐ๋ฐ
+### **์ค์๊ฐ ์ฌ์ฉ๋ ํ๋จ ยท DB ์ง์ ์ ์ฐ ยท Notification ๋ฐํ/๋ณต๊ตฌ ์ฐ๊ณ ์๋น์ค**
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+## โจ Overview
+
+`dabom-processor-usage`๋ DABOM ์์คํ
์์ **์ฌ์ฉ๋ ์ด๋ฒคํธ ์ฒ๋ฆฌ ์ ๋ด ๋ ํฌ**๋ค.
+
+์ด ๋ ํฌ๋ ๋จ์ Kafka consumer๊ฐ ์๋๋ผ, ์๋ ํ๋ฆ์ **ํ๋์ ์๋น์ค ์์์ ์ง์ ์ฒ๋ฆฌ**ํ๋ค.
+
+- `usage-events` ์์
+- payload ๋ฐ `familyId-customerId` ๊ฒ์ฆ
+- Redis warmup
+- Redis + Lua ๊ธฐ๋ฐ ์ค์๊ฐ ์ฌ์ฉ๋ ํ๋จ
+- DB ์ง์ ์ ์ฐ
+- notification ๋์ ํ๋จ
+- notification ์ฆ์ ๋น๋๊ธฐ ๋ฐํ
+- ์คํจ ๊ฑด์ ๋ํ Outbox ๊ธฐ๋ฐ ๋ณต๊ตฌ ์ฐ๊ณ
+
+### ๐ At a Glance
+
+
+
+| Area | Responsibility |
+|---|---|
+| โก Real-time Decision | Redis + Lua |
+| ๐งพ Direct Settlement | MySQL |
+| ๐ Publish & Recovery | `notification-events` + Outbox |
+
+
+
+์ฆ ์ด ๋ ํฌ๋ ์๋ ์ญํ ์ ๋์์ ๋ด๋นํ๋ค.
+
+| ์ญํ | ์ค๋ช
|
+|---|---|
+| โก ์ค์๊ฐ ํ๋จ ์๋น์ค | Redis + Lua๋ก ์ฌ์ฉ๋ ์ํ๋ฅผ ๋น ๋ฅด๊ฒ ๊ณ์ฐ |
+| ๐งพ ์ ์ฐ ์๋น์ค | DB๋ฅผ ๊ธฐ์ค์ผ๋ก ์ต์ข
์ฌ์ฉ๋๊ณผ quota๋ฅผ ๋ฐ์ |
+| ๐ ์๋ฆผ ํ์ ์๋น์ค | notification ๋์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๊ณ ๋ฐํ๊ณผ ๋ณต๊ตฌ๋ฅผ ์ฐ๊ณ |
+
+---
+
+## ๐๏ธ Architecture Summary
+
+ํ์ฌ ๊ตฌ์กฐ๋ **`usage-events` ์ค์ฌ ์ง์ ์ฒ๋ฆฌ ๊ตฌ์กฐ**๋ค.
+
+๊ณผ๊ฑฐ์๋ usage ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ `usage-persist`, `usage-realtime`, `notification-events` ๋ฑ ์ฌ๋ฌ Kafka ํ ํฝ์ผ๋ก ๋ถ์ฐ๋๋ ๊ตฌ์กฐ๊ฐ ์์์ง๋ง, ํ์ฌ๋ ๋ค์ ๋ฐฉํฅ์ผ๋ก ๋จ์ํ๋์๋ค.
+
+- DB ์ ์ฐ์ ์ด ์๋น์ค๊ฐ ์ง์ ์ํ
+- notification์ ๋์ ์ด๋ฒคํธ๋ง Outbox์ ์ ์ฅ
+- usage ์๋น์ค๊ฐ ๋จผ์ ์ฆ์ ๋น๋๊ธฐ ๋ฐํ ์๋
+- ์คํจ ๊ฑด์ `PUBLISH_PENDING` ์ ์ง
+
+```mermaid
+flowchart LR
+ A[Kafka: usage-events] --> B[Usage Consumer]
+ B --> C[Validation]
+ C --> D[Redis Warmup]
+ D --> E[Lua Decision]
+ E --> F[DB Settlement]
+ F --> G{Should Notify?}
+ G -- No --> H[Done]
+ G -- Yes --> I[Save Outbox PUBLISH_PENDING]
+ I --> J[Async Publish to notification-events]
+ J --> K{Broker Ack}
+ K -- Success --> L[Mark SENT]
+ K -- Fail --> M[Keep PUBLISH_PENDING]
+ M --> N[External Recovery Process]
+```
+
+> ํต์ฌ์ **๋ค์ค ํ ํฝ ๋ถ์ฐ ๊ตฌ์กฐ๋ฅผ ์ค์ด๊ณ **, usage ์ฒ๋ฆฌ์ ํต์ฌ ์ฑ
์์ ์ด ์๋น์ค ์์ผ๋ก ๋ชจ์๋ค๋ ์ ์ด๋ค.
+
+---
+
+## ๐ฏ Why This Repository Exists
+
+์ฌ์ฉ๋ ์ฒ๋ฆฌ์์๋ ์๋ ์๊ตฌ๊ฐ ๋์์ ์กด์ฌํ๋ค.
+
+- **๋น ๋ฅด๊ฒ ํ๋จํด์ผ ํ๋ค**
+- **์ ํํ๊ฒ ์ ์ฐํด์ผ ํ๋ค**
+- **์ค๋ณต ์ด๋ฒคํธ์ ์ฌ์ฒ๋ฆฌ๋ฅผ ๊ฒฌ๋์ผ ํ๋ค**
+- **์๋ฆผ์ ์ฆ์ ๋ณด๋ด๋ ์คํจ ์ ๋ณต๊ตฌ ๊ฐ๋ฅํด์ผ ํ๋ค**
+
+์ด ๋ ํฌ๋ ์ด ์๊ตฌ๋ฅผ ์๋์ฒ๋ผ ๋ถ๋ฆฌํด์ ํด๊ฒฐํ๋ค.
+
+### Redis + Lua
+- ๋น ๋ฅธ ํ๋จ
+- dedup ์ ์ด
+- ์ค์๊ฐ ์ ์ฑ
์ฒ๋ฆฌ
+- ๊ฒฝ๊ณ /์ฐจ๋จ ์ํ ๊ณ์ฐ
+
+### DB
+- ์ต์ข
์ ์ฐ
+- ์์ ๋ฐ์ดํฐ ๊ด๋ฆฌ
+- source of truth ์ญํ
+
+### Outbox
+- notification ๋์ ์ด๋ฒคํธ๋ง ์ ์ฅ
+- ์ฆ์ ๋ฐํ ์คํจ ์ ๋ณต๊ตฌ ๊ธฐ์ค์ ์ ์ง
+
+```mermaid
+flowchart TD
+ A[Redis + Lua] -->|๋น ๋ฅธ ํ๋จ| D[Usage Processing]
+ B[DB] -->|์ต์ข
์ ์ฐ| D
+ C[Outbox] -->|๋ฐํ ์คํจ ๋ณต๊ตฌ ๊ธฐ์ค์ | D
+```
+
+---
+
+## ๐งฉ Responsibilities
+
+### 1) Validation
+- payload ๊ธฐ๋ณธ ๊ฒ์ฆ
+- `familyId-customerId` ๊ด๊ณ ๊ฒ์ฆ
+- invalid input๋ ๋ค ๋จ๊ณ๋ก ๋ณด๋ด์ง ์์
+
+### 2) Redis + Lua Decision
+- Redis warmup
+- duplicate ํ๋จ
+- ์ฌ์ฉ๋ ๋ฐ์
+- ๊ฒฝ๊ณ /์ฐจ๋จ ์ํ ๊ณ์ฐ
+- ์๋ฆผ dedup ํ๋จ
+
+### 3) Direct DB Settlement
+- `usage_record` ๊ธฐ๋ฐ ๋ฉฑ๋ฑ ์ ์ฐ
+- `customer_quota`, `family_quota` ์ง์ ๋ฐ์
+- blocked ์ด๋ฒคํธ๋ ์ฐจ๋จ ์ํ๋ง ๋ฐ์
+
+### 4) Notification Publish & Recovery
+- notification ๋์ ํ๋จ
+- Outbox์ `PUBLISH_PENDING` ์ ์ฅ
+- `notification-events` ์ฆ์ ๋น๋๊ธฐ ๋ฐํ
+- ์ฑ๊ณต ์ `SENT`, ์คํจ ์ `PUBLISH_PENDING` ์ ์ง
+
+```mermaid
+sequenceDiagram
+ participant K as Kafka usage-events
+ participant U as Usage Service
+ participant R as Redis/Lua
+ participant D as DB
+ participant O as Outbox
+ participant N as Kafka notification-events
+
+ K->>U: usage-events 1๊ฑด
+ U->>U: payload / family-customer ๊ฒ์ฆ
+ U->>R: warmup + Lua ์คํ
+ R-->>U: duplicate, status, shouldNotify
+ U->>D: DB ์ง์ ์ ์ฐ
+ alt shouldNotify = true
+ U->>O: PUBLISH_PENDING ์ ์ฅ
+ U->>N: ๋น๋๊ธฐ ๋ฐํ ์๋
+ alt ack success
+ U->>O: SENT ๋ฐ์
+ else ack fail
+ U->>O: PUBLISH_PENDING ์ ์ง
+ end
+ else shouldNotify = false
+ U->>U: Outbox row ์์ฑ ์์
+ end
+```
+
+---
+
+## ๐จ Kafka Topics
+
+
+
+| Type | Topic |
+|---|---|
+| ๐ฅ Consumed | `usage-events` |
+| ๐ค Produced | `notification-events` |
+| ๐ฐ๏ธ Historical | `usage-persist`, `usage-realtime` |
+
+
+
+---
+
+## ๐๏ธ Key Design Decisions
+
+
+1. Redis์ DB์ ์ญํ ๋ถ๋ฆฌ
+
+
+
+- Redis: ๋น ๋ฅธ ํ๋จ๊ณผ ์ค์๊ฐ ์ํ ๊ณ์ฐ
+- DB: ์ต์ข
์ ์ฐ๊ณผ ์์ ๊ธฐ์ค์
+
+์ฆ, **Redis๋ ์๋**, **DB๋ ์ ํ์ฑ**์ ๋ด๋นํ๋๋ก ๋ถ๋ฆฌํ๋ค.
+
+
+
+
+2. DB ์ ์ฐ์ ๋ฉฑ๋ฑํ๊ฒ ์ฌ์ง์
๊ฐ๋ฅ
+
+
+
+- `usage_record`๊ฐ ์ ํ ๋ฉฑ๋ฑ ๊ฐ๋ ์ญํ
+- quota ๋ฐ์์ ์ insert ์ฑ๊ณต ์์๋ง ์ํ
+- blocked ์ํ๋ ์ฌ์ ์ฉ๋์ด๋ ์ต์ข
์ํ๊ฐ ๊นจ์ง์ง ์์
+
+์ฆ duplicate์ retry๋ฅผ **์์ธ๊ฐ ์๋๋ผ ๊ธฐ๋ณธ ์ ์ **๋ก ๋ณด๊ณ ์ค๊ณํ๋ค.
+
+
+
+
+3. ์๋ชป๋ ์
๋ ฅ์ ์ด์
์์ ์ฐจ๋จ
+
+
+
+membership ๊ฒ์ฆ์ ์ด์
์ผ๋ก ๋์ด์ฌ๋ ค, ๋น์ ์ ์
๋ ฅ์ด Redis, DB, notification ๋จ๊ณ๊น์ง ๋ด๋ ค๊ฐ์ง ์๋๋ก ๋ง๋๋ค.
+
+
+
+
+4. Notification์ ์ฆ์์ฑ๊ณผ ๋ณต๊ตฌ์ฑ์ ํจ๊ป ๊ฐ์ ธ๊ฐ
+
+
+
+- usage ์๋น์ค๊ฐ ๋จผ์ ์ฆ์ ๋น๋๊ธฐ ๋ฐํ
+- ์คํจ ๊ฑด๋ง Outbox์ ๋จ๊ฒจ ํ์ ๋ณต๊ตฌ ๊ฐ๋ฅ
+
+์ฆ, **์ฆ์์ฑ**๊ณผ **๋ณต๊ตฌ์ฑ**์ ๋์์ ๊ณ ๋ คํ๋ค.
+
+
+
+
+5. Outbox๋ publish-candidate only
+
+
+
+- ๋ชจ๋ ์ด๋ฒคํธ๋ฅผ ์ ์ฅํ์ง ์์
+- notification ๋์ ์ด๋ฒคํธ๋ง ์ ์ฅ
+- ๊ณ TPS ํ๊ฒฝ์์ ๋ถํ์ํ DB hot path write๋ฅผ ์ค์ด๊ธฐ ์ํ ์ ํ
+
+
+
+---
+
+## ๐จ Failure Handling
+
+| ์ ํ | ์ฒ๋ฆฌ ๋ฐฉ์ |
+|---|---|
+| IGNORE | payload ๊ณ์ฝ ์๋ฐ, ์๋ชป๋ family-customer ์กฐํฉ |
+| RETRY | Redis ์คํจ, Lua ์คํจ, DB ์ ์ฐ ์คํจ, Outbox ์ ์ฅ ์คํจ |
+| DLQ / Non-Retryable | ์ํ ๊ณ์ฝ ๋ถ์ผ์น, ๋ณต๊ตฌ ๋ถ๊ฐ๋ฅํ ์ง๋ ฌํ/์ญ์ง๋ ฌํ ์ค๋ฅ |
+
+---
+
+## ๐ Further Reading
+
+๊ณต์ ๋ฌธ์๋ `docs/` ์๋ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ๋ค.
+
+- [์๋น์ค ๊ฐ์ ๋ฐ ๊ตฌ์กฐ ๋ณํ](./docs/01_SERVICE_OVERVIEW.md)
+- [ํ์ฌ ์ฒ๋ฆฌ ํ๋ก์ฐ](./docs/02_PROCESSING_FLOW.md)
+- [Outbox ๋ฐ ์ฌ์๋](./docs/03_OUTBOX_AND_RETRY.md)
+- [์์ธ ์ฒ๋ฆฌ ๋ฐ ๋ณต๊ตฌ ์ ๋ต](./docs/04_EXCEPTION_AND_RECOVERY.md)
+- [๋ฐ์ดํฐ ๋ชจ๋ธ ๋ฐ Redis ํค ๊ตฌ์กฐ](./docs/05_DATA_MODEL_AND_KEYS.md)
+
+---
+
+## ๐ Summary
+
+`dabom-processor-usage`์ ํต์ฌ์ ๋ค์์ผ๋ก ์ ๋ฆฌํ ์ ์๋ค.
+
+- ์ด๊ธฐ์ ๋ค์ค ํ ํฝ ๋ถ์ฐ ๊ตฌ์กฐ๋ฅผ ์ค์๋ค.
+- `usage-events` ์ค์ฌ์ผ๋ก DB ์ ์ฐ ์ฑ
์์ ์ด ์๋น์ค์ ๋ชจ์๋ค.
+- Redis + Lua๋ก ์ค์๊ฐ ํ๋จ์ ์ํํ๋ค.
+- notification์ ์ฆ์ ๋น๋๊ธฐ ๋ฐํ๊ณผ Outbox ๊ธฐ๋ฐ ๋ณต๊ตฌ๋ฅผ ๋ถ๋ฆฌํ๋ค.
+- Outbox๋ ๋ฐํ ๋์ ์ด๋ฒคํธ๋ง ์ ์ฅํด ๊ณ TPS ๋น์ฉ์ ์ค์ธ๋ค.
+
+> ์ฆ ์ด ๋ ํฌ๋ ๋จ์ consumer ๊ตฌํ์ด ์๋๋ผ,
+> **์ค์๊ฐ์ฑ ยท ์ ํฉ์ฑ ยท ๋ณต๊ตฌ์ฑ ยท ์ด์ ๊ฐ๋ฅ์ฑ**์ ํจ๊ป ๊ณ ๋ คํด์ ์ ๋ฆฌ๋ usage processing ์๋น์ค๋ค.
\ No newline at end of file
diff --git a/docs/01_SERVICE_OVERVIEW.md b/docs/01_SERVICE_OVERVIEW.md
new file mode 100644
index 0000000..86c470f
--- /dev/null
+++ b/docs/01_SERVICE_OVERVIEW.md
@@ -0,0 +1,331 @@
+๏ปฟ# Service Overview
+
+## 1. Purpose
+
+`dabom-processor-usage`๋ `usage-events`๋ฅผ ์๋นํด ์ฌ์ฉ๋ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ์๋น์ค๋ค.
+
+ํ์ฌ ์ด ์๋น์ค๊ฐ ์ํํ๋ ์ผ์ ์๋์ ๊ฐ๋ค.
+
+- payload ๊ธฐ๋ณธ ๊ฒ์ฆ
+- `familyId-customerId` ๊ด๊ณ ๊ฒ์ฆ
+- Redis warmup
+- Redis + Lua ๊ธฐ๋ฐ ์ํ ๊ณ์ฐ
+- DB ์ง์ ์ ์ฐ
+- notification ๋์ ํ๋จ
+- notification ์ฆ์ ๋น๋๊ธฐ ๋ฐํ ์๋
+- ๋ฐํ ์คํจ ๊ฑด์ ๋ํ ๋ณต๊ตฌ ๊ธฐ์ค์ ์ ์ฅ
+
+์ฆ ์ด ์๋น์ค๋ ๋จ์ consumer๊ฐ ์๋๋ผ, ์ค์๊ฐ ํ๋จ๊ณผ ์ ์ฐ, notification ํ์์ ํจ๊ป ๋ด๋นํ๋ usage processing service๋ค.
+
+## 2. What the Previous Structure Looked Like
+
+์ด๊ธฐ์๋ usage ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ ์ฌ๋ฌ Kafka ํ ํฝ์ผ๋ก ๋ถ์ฐ๋๋ ๊ตฌ์กฐ์๋ค.
+
+- `usage-events`
+- `usage-persist`
+- `usage-realtime`
+- `notification-events`
+
+๋น์ ํ๋ฆ์ ๋๋ต ์๋์ ๊ฐ์๋ค.
+
+1. `usage-events` ์์
+2. Redis/Lua๋ก ์ํ ๊ณ์ฐ
+3. `usage-persist`๋ก DB ์ ์ฐ์ฉ ์ด๋ฒคํธ ๋ฐํ
+4. `usage-realtime`๋ก ์ค์๊ฐ ์ฌ์ฉ๋ ์ด๋ฒคํธ ๋ฐํ
+5. `notification-events`๋ก ์๋ฆผ ์ด๋ฒคํธ ๋ฐํ
+
+์ฆ usage ์ด๋ฒคํธ 1๊ฑด์ด ๋ค์ด์ค๋ฉด, ๊ทธ ๊ฒฐ๊ณผ๊ฐ ์ฌ๋ฌ ํ ํฝ์ผ๋ก ๋ค์ ๋ถ๊ธฐ๋๋ ๊ตฌ์กฐ์๋ค.
+
+```mermaid
+flowchart LR
+ A[usage-events] --> B[Redis + Lua ํ๋จ]
+ B --> C[usage-persist]
+ B --> D[usage-realtime]
+ B --> E[notification-events]
+```
+
+## 3. Why the Structure Changed
+
+์ด์ ๊ตฌ์กฐ๋ ๊ธฐ๋ฅ์ ํ ํฝ์ผ๋ก ๋ถ๋ฆฌํ๋ค๋ ์ ์์๋ ๋จ์ํด ๋ณด์ผ ์ ์์์ง๋ง, ์ค์ usage ์ฒ๋ฆฌ ๊ด์ ์์๋ ์๋ ๋ฌธ์ ๊ฐ ์์๋ค.
+
+### 3.1 DB ์ ์ฐ ์ฑ
์์ด ๋ฉ๋ฆฌ ๋จ์ด์ ธ ์์๋ค
+
+usage ์ํ๋ฅผ ๊ณ์ฐํ๋ ๊ณณ๊ณผ DB ์ ์ฐ์ ์ํํ๋ ๊ณณ์ด `usage-persist` ๊ฒฝ๋ก๋ก ๋ถ๋ฆฌ๋ผ ์์๋ค.
+
+์ด ๋๋ฌธ์:
+- ์ฌ์ฉ๋ ํ๋จ๊ณผ ์ต์ข
์ ์ฐ์ ํ ํ๋ฆ์ผ๋ก ์ค๋ช
ํ๊ธฐ ์ด๋ ค์ ๊ณ
+- ์คํจ ์ ์ด๋๋ถํฐ ๋ค์ ๋ด์ผ ํ๋์ง๊ฐ ๋ถ์ฐ๋์๊ณ
+- ๋ฉฑ๋ฑ์ฑ ๋ณด์ฅ์ ์ด๋ ์ง์ ์ด ์ฑ
์์ง๋์ง ๋ฐ๋ก ์ฝํ์ง ์์๋ค.
+
+### 3.2 ํ๋์ ์ด๋ฒคํธ๊ฐ ์ฌ๋ฌ ํ ํฝ์ผ๋ก ๋ถ๊ธฐ๋๋ค
+
+usage ์ด๋ฒคํธ 1๊ฑด์ด ๋ค์ด์ค๋ฉด `usage-persist`, `usage-realtime`, `notification-events`๋ก ๋ค์ ๋๊ฐ๋ค.
+
+์ด ๋๋ฌธ์:
+- ์ด์์๊ฐ ํ๋์ usage ์ด๋ฒคํธ๋ฅผ ์ถ์ ํ๋ ค๋ฉด ์ฌ๋ฌ ํ ํฝ์ ๊ฐ์ด ๋ด์ผ ํ๊ณ
+- ์ฅ์ ์ โ์ด ์ด๋ฒคํธ๊ฐ ์ด๋ ๋จ๊ณ๊น์ง ์งํ๋๋๊ฐโ๋ฅผ ์ค๋ช
ํ๊ธฐ ์ด๋ ค์ ๊ณ
+- ์ค์๊ฐ ํ๋จ๊ณผ ์ ์ฐ, ์๋ฆผ ์ฌ์ด์ ๊ด๊ณ๊ฐ ๋ฌธ์ ์์ด ์ฝ๋๋ง ๋ด์๋ ์ ๋๋ฌ๋์ง ์์๋ค.
+
+### 3.3 notification์ ์ฆ์์ฑ๊ณผ ๋ณต๊ตฌ ์ง์ ์ด ๋ถ๋ฆฌ๋ผ ์์๋ค
+
+์๋ฆผ์ ๋ฐํ ์์ฒด๋ Kafka ๊ฒฝ๋ก๋ก ๋ณด๋ด์ง๋ง, ๋ฐํ ์คํจ ํ ์ด๋ค ๊ธฐ์ค์ผ๋ก ๋ค์ ๋ณต๊ตฌํ ๊ฒ์ธ์ง๋ ๋ช
ํํ ๊ฒฝ๊ณ๊ฐ ํ์ํ๋ค.
+
+์ด ๋๋ฌธ์:
+- ์ฆ์ ๋ฐํ๊ณผ ๋ณต๊ตฌ ๋ฐํ์ ์ฑ
์์ ๋๋ ํ์๊ฐ ์์๊ณ
+- usage ์๋น์ค๊ฐ ์ด๋๊น์ง ์ฑ
์์ง๋์ง๋ฅผ ๋ถ๋ช
ํ ํด์ผ ํ๋ค.
+
+### 3.4 ์๋ชป๋ ์
๋ ฅ์ ๋ ์์์ ๋์ด์ผ ํ๋ค
+
+usage ์ฒ๋ฆฌ์์ `familyId-customerId` ๊ด๊ณ๊ฐ ํ๋ฆฐ ์
๋ ฅ์ Redis, Lua, DB, notification๊น์ง ๋ด๋ ค๊ฐ์ง ์๋ ๊ฒ์ด ๋ง๋ค.
+
+์ด์ ๋ณด๋ค ๋ ์๋จ์์:
+- payload ๊ณ์ฝ ์๋ฐ
+- family-customer ๋ถ์ผ์น
+๋ฅผ ๋๋ ๊ตฌ์กฐ๊ฐ ํ์ํ๋ค.
+
+## 4. How the Current Structure Solves It
+
+ํ์ฌ ๊ตฌ์กฐ๋ usage ์ฒ๋ฆฌ์ ํต์ฌ ์ฑ
์์ `usage-events` ์ฒ๋ฆฌ ์๋น์ค ์์ผ๋ก ๋ชจ์ผ๋ ๋ฐฉํฅ์ผ๋ก ์ ๋ฆฌ๋์๋ค.
+
+### 4.1 DB ์ ์ฐ์ usage ์๋น์ค๊ฐ ์ง์ ์ํ
+
+์ด์ `usage-events`๋ฅผ ์๋นํ ์งํ:
+- validation
+- Redis/Lua ํ๋จ
+- DB ์ ์ฐ
+์ด ํ๋์ ์๋น์ค ํ๋ฆ ์์์ ์ด์ด์ง๋ค.
+
+ํจ๊ณผ:
+- usage ์ด๋ฒคํธ 1๊ฑด์ด ์ด๋ค ์์๋ก ์ฒ๋ฆฌ๋๋์ง ์ค๋ช
์ด ์ฌ์์ง
+- ์ ์ฐ ๋ฉฑ๋ฑ์ฑ๊ณผ ๋ณต๊ตฌ ์ง์ ์ด ์ด ์๋น์ค ๊ธฐ์ค์ผ๋ก ์ ๋ฆฌ๋จ
+
+### 4.2 ์ค์๊ฐ ํ๋จ๊ณผ ์์ ์ ์ฐ์ ๊ฒฝ๊ณ ๋ช
ํํ
+
+ํ์ฌ ๊ตฌ์กฐ๋ ์ญํ ์ ์๋์ฒ๋ผ ๋๋๋ค.
+
+- Redis + Lua: ๋น ๋ฅธ ํ๋จ๊ณผ ์ํ ๊ณ์ฐ
+- DB: ์ต์ข
์ ์ฐ๊ณผ ์์ ๊ธฐ์ค์
+
+ํจ๊ณผ:
+- Redis๋ ์ค์๊ฐ์ฑ
+- DB๋ ์ ํฉ์ฑ
+์ ๋ด๋นํ๋ค๋ ์ ์ด ๊ตฌ์กฐ์ ์ผ๋ก ๋ถ๋ช
ํด์ก๋ค.
+
+### 4.3 notification์ ๋์ ์ด๋ฒคํธ๋ง ์ ์ฅํ๊ณ , ์ฆ์ ๋ฐํ๊ณผ ๋ณต๊ตฌ๋ฅผ ๋ถ๋ฆฌ
+
+ํ์ฌ notification ํ๋ฆ์ ์๋์ ๊ฐ๋ค.
+
+- notification ๋์์ผ ๋๋ง Outbox row ์์ฑ
+- usage ์๋น์ค๊ฐ ์ฆ์ ๋น๋๊ธฐ ๋ฐํ ์๋
+- ์คํจ ์ `PUBLISH_PENDING` ์ ์ง
+- ์ธ๋ถ ๋ณต๊ตฌ ํ๋ก์ธ์ค๊ฐ pending row๋ฅผ ๋ค์ ๋ฐํ
+
+ํจ๊ณผ:
+- ์ฆ์์ฑ์ usage ์๋น์ค๊ฐ ๋ด๋น
+- ๋ณต๊ตฌ๋ Outbox๋ฅผ ๊ธฐ์ค์ผ๋ก ํ์ ํ๋ก์ธ์ค๊ฐ ๋ด๋น
+- notification ๊ด๋ จ ์ํ๊ฐ DB row ๊ธฐ์ค์ผ๋ก ๊ด๋ฆฌ๋๋ค.
+
+### 4.4 invalid input๋ฅผ ์ด์
์์ ์ฐจ๋จ
+
+`familyId-customerId` ๊ด๊ณ๋ฅผ Redis membership cache์ DB fallback์ผ๋ก ๊ฒ์ฆํ๋ค.
+
+ํจ๊ณผ:
+- ์๋ชป๋ ์
๋ ฅ์ด Redis ์ํ๋ฅผ ์ค์ผ์ํค์ง ์์
+- ์๋ชป๋ ์
๋ ฅ์ด DB ์ ์ฐ์ด๋ notification์ผ๋ก ์ด์ด์ง์ง ์์
+
+## 5. Why These Technologies
+
+## 5.1 Why a Messaging Queue Was Needed
+
+usage ๋๋ฉ์ธ์ ์ฌ์ฉ๋ ์ด๋ฒคํธ๊ฐ ํ ๋ฒ์ ๋ชฐ๋ฆด ์ ์๊ณ , ์์ฐ ์์ ๊ณผ ์ฒ๋ฆฌ ์์ ์ ๋์จํ๊ฒ ๋ถ๋ฆฌํ ํ์๊ฐ ์๋ค.
+
+๋ฉ์์ง ํ๋ฅผ ๋๋ฉด ์๋๊ฐ ๊ฐ๋ฅํด์ง๋ค.
+
+- usage ๋ฐ์ ์๋น์ค์ usage ์ฒ๋ฆฌ ์๋น์ค๋ฅผ ๋ถ๋ฆฌ
+- burst traffic๋ฅผ ํก์ํ๋ฉด์ ์์ฐจ ์ฒ๋ฆฌ ๊ธฐ์ค ์ ์ง
+- consumer ์ฌ์ฒ๋ฆฌ์ ์ฅ์ ๋ณต๊ตฌ ๊ธฐ์ค ํ๋ณด
+- ํ์ ํ์ ์ฒ๋ฆฌ(notification ๋ฑ)๋ฅผ ์ด๋ฒคํธ ์ค์ฌ์ผ๋ก ์ฐ๊ฒฐ
+
+์ฆ ์ด ์๋น์ค์์ ๋ฉ์์ง ํ๋ ๋จ์ ์ ์ก ์ฑ๋์ด ์๋๋ผ, usage ์ด๋ฒคํธ๋ฅผ ์์ ์ ์ผ๋ก ํ๋ ค๋ณด๋ด๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ ๊ธฐ๋ฐ์ด๋ค.
+
+## 5.2 Why Kafka
+
+์ด ์๋น์ค๊ฐ Kafka๋ฅผ ์ฐ๋ ์ด์ ๋ ์๋์ ๊ฐ๋ค.
+
+- usage ์ด๋ฒคํธ๋ ์ค์๊ฐ์ผ๋ก ๋ง์ด ๋ค์ด์ค๋ ์คํธ๋ฆผ ์ฑ๊ฒฉ์ด ๊ฐํ๋ค.
+- ์ด๋ฒคํธ๋ฅผ ์์ ์๊ฒ ๊ณ์ ์๋นํด์ผ ํ๋ค.
+- ์ฅ์ ์ ๊ฐ์ ๋ ์ฝ๋๋ฅผ ๋ค์ ์ฒ๋ฆฌํ ์ ์๋ ์ฌ์ฒ๋ฆฌ ๋ชจ๋ธ์ด ์ค์ํ๋ค.
+- usage, notification์ฒ๋ผ ๋ค๋ฅธ ํ์ ํ ํฝ๊ณผ๋ ์์ฐ์ค๋ฝ๊ฒ ์ฐ๊ฒฐ๋๋ค.
+
+Kafka๋ ์ด๋ฐ usage stream ์ฒ๋ฆฌ์ ์ ๋ง๋๋ค.
+
+- ํ ํฝ ๊ธฐ๋ฐ์ผ๋ก ์ด๋ฒคํธ ํ๋ฆ์ ๋ถ๋ฆฌํ ์ ์๋ค.
+- consumer group์ผ๋ก ์ํ ํ์ฅ์ด ๊ฐ๋ฅํ๋ค.
+- offset ๊ธฐ๋ฐ์ด๋ผ ์ฌ์ฒ๋ฆฌ์ ์ด์ ์ถ์ ์ด ๋ช
ํํ๋ค.
+- ๊ณ TPS ์ด๋ฒคํธ ์คํธ๋ฆผ ์ฒ๋ฆฌ์ ์ ํฉํ๋ค.
+
+๋ํ ์ด ์๋น์ค๋ ๊ฐ์กฑ ๋จ์ ์ํ๋ฅผ ๋ง์ด ๋ค๋ฃฌ๋ค.
+
+- `family_quota`
+- ๊ฐ์กฑ ์์ฌ๋
+- ๊ฐ์กฑ ๋จ์ ๊ฒฝ๊ณ /์ฐจ๋จ ํ๋จ
+
+์ด๋ฐ ๊ตฌ์กฐ์์๋ ๊ฐ์ ๊ฐ์กฑ์ ์ด๋ฒคํธ๋ฅผ ๊ฐ์ ํ๋ฆ์์ ์์ ์๊ฒ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ ๋ฆฌํ๋ค. Kafka๋ key ๊ธฐ๋ฐ partitioning์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ํ๋ฏ๋ก, `familyId`๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฐ์ ๊ฐ์กฑ ์ด๋ฒคํธ๋ฅผ ๊ฐ์ ํํฐ์
ํ๋ฆ์ ํ์ฐ๋ ๋ชจ๋ธ๊ณผ ์ ๋ง๋๋ค.
+
+์ฆ Kafka๋ โ์
๋ฌด ๋ช
๋ น ์ ๋ฌโ๋ณด๋ค โ์ง์์ ์ผ๋ก ์์ด๋ ์ด๋ฒคํธ ์คํธ๋ฆผ ์ฒ๋ฆฌโ์ โ๊ฐ์กฑ ๊ธฐ์ค ์์๊ฐ ์ค์ํ usage ์ฒ๋ฆฌโ์ ๋ ์ ๋ง๋ ์ ํ์ด๋ค.
+
+## 5.3 Why Not RabbitMQ
+
+RabbitMQ ๊ฐ์ ๋ฉ์์ง ๋ธ๋ก์ปค๋ ์ถฉ๋ถํ ํ๋ฅญํ์ง๋ง, ์ด ์๋น์ค๊ฐ ๋ค๋ฃจ๋ ๋ฌธ์ ์๋ ์ฑ๊ฒฉ์ด ์กฐ๊ธ ๋ค๋ฅด๋ค.
+
+RabbitMQ๊ฐ ๋ ์ ๋ง๋ ๊ฒฝ์ฐ๋ ๋ณดํต ์๋์ ๊ฐ๋ค.
+
+- ์์
ํ ๊ธฐ๋ฐ์ ๋ช
๋ น ์ฒ๋ฆฌ
+- ๋ณต์กํ ๋ผ์ฐํ
๊ท์น
+- ๋น ๋ฅธ ๋จ๊ฑด ์ ๋ฌ๊ณผ ack ์ค์ฌ์ ๋ฉ์์ง
+
+๋ฐ๋ฉด `dabom-processor-usage`๋ ์๋ ํน์ฑ์ด ๋ ์ค์ํ๋ค.
+
+- ์ฌ์ฉ๋ ์ด๋ฒคํธ๊ฐ ์ง์์ ์ผ๋ก ๋ค์ด์ค๋ stream ์ฒ๋ฆฌ
+- offset ๊ธฐ์ค ์ฌ์ฒ๋ฆฌ
+- consumer group ํ์ฅ
+- ๊ฐ์ ๊ฐ์กฑ ์ด๋ฒคํธ์ ์์ ์๋ ์ฒ๋ฆฌ
+
+RabbitMQ์์๋ ์ ์ฌํ ๊ตฌ์ฑ์ ๋ง๋ค ์๋ ์์ง๋ง, ์ผ๋ฐ queue ๋ชจ๋ธ์์๋ Kafka์ฒ๋ผ key ๊ธฐ๋ฐ partitioning์ด ๊ธฐ๋ณธ ๋ชจ๋ธ์ ์๋๋ค. ๊ฐ์ ๊ฐ์กฑ์ ์ด๋ฒคํธ๋ฅผ ๊ฐ์ ํ๋ฆ์์ ์์ ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ค๋ฉด ์ถ๊ฐ ๋ผ์ฐํ
์ค๊ณ๋ stream ๊ณ์ด ๊ตฌ์ฑ์ด ํ์ํ๋ค.
+
+์ฆ ์ด ์๋น์ค๋ โํ๋์ ์์
์ ๋๊ฐ ์๋นํ ๊นโ๋ณด๋ค โ๊ณ์ ๋ค์ด์ค๋ usage ์ด๋ฒคํธ ํ๋ฆ์ ์ด๋ป๊ฒ ์์ ์ ์ผ๋ก ์ฒ๋ฆฌํ ๊นโ๊ฐ ๋ ์ค์ํ ์๋น์ค๋ค. ๊ทธ ์ ์์ Kafka๊ฐ ๋ ์์ฐ์ค๋ฝ๋ค.
+
+## 5.4 Why Redis
+
+usage ์ฒ๋ฆฌ์๋ DB๋ง์ผ๋ก๋ ๋ถ์กฑํ ๊ตฌ๊ฐ์ด ์๋ค.
+
+์ด ์๋น์ค๋ ์๋๋ฅผ ๋งค์ฐ ๋น ๋ฅด๊ฒ ํ๋จํด์ผ ํ๋ค.
+
+- ๊ฐ์กฑ ์์ฌ๋์ด ์ผ๋ง๋ ๋จ์๋์ง
+- ๊ฐ์ธ ์ ์ฌ์ฉ๋์ด ์ผ๋ง์ธ์ง
+- ํ์ฌ ์ฐจ๋จ ์๊ฐ๋์ธ์ง
+- ํน์ ์ฑ์ด ์ฐจ๋จ ์ํ์ธ์ง
+- ์ง๊ธ ์๋ฆผ์ ๋ณด๋ด์ผ ํ๋์ง
+
+์ด๊ฑธ ๋งค ์ด๋ฒคํธ๋ง๋ค DB๋ง ๋ณด๊ณ ์ฒ๋ฆฌํ๋ฉด:
+- ์ฝ๊ธฐ ๋น์ฉ์ด ์ปค์ง๊ณ
+- ๋์์ ์ฌ๋ฌ ์ด๋ฒคํธ๊ฐ ๋ค์ด์ฌ ๋ race condition ๊ด๋ฆฌ๊ฐ ์ด๋ ค์์ง๊ณ
+- ์ค์๊ฐ ํ๋จ ์๋๊ฐ ๋จ์ด์ง๋ค.
+
+Redis๋ฅผ ๋๋ฉด:
+- ํ์ํ ์ํ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์์ ๋น ๋ฅด๊ฒ ์ฝ๊ณ
+- Lua๋ก ์์์ ์ผ๋ก ๊ฐฑ์ ๊ณผ ํ๋จ์ ๊ฐ์ด ์ํํ ์ ์๋ค.
+
+์ฆ Redis๋ ๋จ์ ์บ์๊ฐ ์๋๋ผ, usage ์ค์๊ฐ ํ๋จ ์์ง์ ์ผ๋ถ ์ญํ ์ ํ๋ค.
+
+## 5.5 Why Lua
+
+Redis๋ง ์ฐ๋ ๊ฒ์ผ๋ก๋ ์ถฉ๋ถํ์ง ์๋ค. ์ฌ์ฉ๋ ์ฆ๊ฐ, ์ํ ๊ณ์ฐ, ์๋ฆผ dedup ํ๋จ์ด ๋ถ๋ฆฌ๋์ด ์์ผ๋ฉด race condition์ด ์๊ธธ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
+
+Lua๋ฅผ ์ฌ์ฉํ๋ฉด:
+- duplicate ํ์ธ
+- remaining / monthly usage ๋ฐ์
+- ์ฐจ๋จ ํ๋จ
+- ๊ฒฝ๊ณ ํ๋จ
+- alert dedup ๊ธฐ๋ก
+์ ํ ๋ฒ์ ์์์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋ค.
+
+์ฆ Lua๋ โ์ฌ๋ฌ Redis ๋ช
๋ น์ ํ ํธ๋์ญ์
์ฒ๋ผ ๋ฌถ์ด ์ผ๊ด๋ ํ๋จ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋๋ ๋๊ตฌโ๋ค.
+
+## 5.6 Why Direct DB Settlement
+
+ํ์ฌ ๊ตฌ์กฐ๋ usage ์๋น์ค๊ฐ DB ์ ์ฐ์ ์ง์ ์ํํ๋ค.
+
+์ด๋ ๊ฒ ํ ์ด์ ๋ ์๋์ ๊ฐ๋ค.
+
+- usage ์ํ ๊ณ์ฐ๊ณผ ์ ์ฐ์ ํ ํ๋ฆ์ผ๋ก ์ค๋ช
ํ๊ธฐ ์ฝ๋ค.
+- `usage_record` ๊ธฐ๋ฐ ๋ฉฑ๋ฑ ์ ์ฐ์ ๋ฐ๋ก ์ํํ ์ ์๋ค.
+- `usage-persist` ๊ฐ์ ์ค๊ฐ ํ ํฝ์ ์ค์ฌ ์ฒ๋ฆฌ ๊ฒฝ๋ก๋ฅผ ๋จ์ํํ ์ ์๋ค.
+
+์ฆ ์ง์ ์ ์ฐ ๊ตฌ์กฐ๋ โ์ด๋์ ์ต์ข
์ ์ฐ์ด ์ผ์ด๋๋๊ฐโ๋ฅผ usage ์๋น์ค ์์ผ๋ก ๋ช
ํํ ๋ชจ์ผ๋ ์ ํ์ด๋ค.
+
+## 5.7 Why Outbox
+
+notification์ ์ฆ์ ๋ฐํ๋ง์ผ๋ก ๋๋ด๊ธฐ ์ด๋ ต๋ค. Kafka publish๋ ์คํจํ ์ ์๊ณ , ์คํจ ํ ๋ค์ ๋ณด๋ผ ๊ธฐ์ค์ ์ด ํ์ํ๋ค.
+
+Outbox๋ฅผ ๋๋ฉด:
+- notification ๋์ ์ด๋ฒคํธ๋ง DB row๋ก ๋จ๊ธฐ๊ณ
+- ์ฆ์ ๋ฐํ ์คํจ ์ `PUBLISH_PENDING`์ ๊ธฐ์ค์ผ๋ก ๋ค์ ๋ฐํํ ์ ์๋ค.
+
+์ฆ Outbox๋ notification ์คํจ ํ ๋ณต๊ตฌ ๊ธฐ์ค์ ์ญํ ์ ํ๋ค.
+
+## 6. Current Architecture
+
+ํ์ฌ ๊ตฌ์กฐ์ ์ฌ์ค์ ์๋์ ๊ฐ๋ค.
+
+- Kafka listener๋ `usage-events` ํ๋๋ฅผ ์ฒ๋ฆฌํ๋ค.
+- Redis/Lua๋ก `duplicate`, `status`, `shouldNotify`๋ฅผ ๊ณ์ฐํ๋ค.
+- DB ์ ์ฐ์ ์ด ์๋น์ค๊ฐ ์ง์ ์ํํ๋ค.
+- notification ๋์์ผ ๋๋ง Outbox row๋ฅผ ๋ง๋ ๋ค.
+- usage ์๋น์ค๊ฐ notification์ ์ฆ์ ๋น๋๊ธฐ๋ก ๋จผ์ ๋ฐํํ๋ค.
+- ๋ฐํ ์ฑ๊ณต ์ `SENT`, ์คํจ ์ `PUBLISH_PENDING`์ ์ ์งํ๋ค.
+
+```mermaid
+flowchart LR
+ A[Kafka: usage-events] --> B[Usage Consumer]
+ B --> C[Validation]
+ C --> D[Redis Warmup]
+ D --> E[Lua Decision]
+ E --> F[DB Settlement]
+ F --> G{Should Notify?}
+ G -- No --> H[Done]
+ G -- Yes --> I[Save Outbox PUBLISH_PENDING]
+ I --> J[Async Publish to notification-events]
+ J --> K{Broker Ack}
+ K -- Success --> L[Mark SENT]
+ K -- Fail --> M[Keep PUBLISH_PENDING]
+ M --> N[External Recovery Process]
+```
+
+## 7. Core Design Points
+
+### 7.1 Redis์ DB์ ์ญํ ๋ถ๋ฆฌ
+
+- Redis: ๋น ๋ฅธ ํ๋จ๊ณผ ์ค์๊ฐ ์ํ ๊ณ์ฐ
+- DB: ์ต์ข
์ ์ฐ๊ณผ ์์ ๊ธฐ์ค์
+
+### 7.2 DB ์ ์ฐ์ ์ฌ์ง์
๊ฐ๋ฅ
+
+- `usage_record`๊ฐ ์ ํ ๋ฉฑ๋ฑ ๊ฐ๋ ์ญํ ์ ํ๋ค.
+- allowed ์ด๋ฒคํธ๋ ์ `usage_record` insert ์ฑ๊ณต ์์๋ง quota๋ฅผ ๋ฐ์ํ๋ค.
+- blocked ์ด๋ฒคํธ๋ `usage_record` ์์ด ์ฐจ๋จ ์ํ๋ง ๋ฐ์ํ๋ค.
+
+### 7.3 ์๋ชป๋ ์
๋ ฅ์ ์ด์
์์ ์ฐจ๋จ
+
+- `familyId-customerId` ๊ด๊ณ๋ฅผ Redis membership cache์ DB fallback์ผ๋ก ๊ฒ์ฆํ๋ค.
+- ์ค์ ๋ก ์๋ชป๋ ์กฐํฉ์ด๋ฉด `IllegalArgumentException`์ผ๋ก ์ค๋จํ๋ค.
+- Redis/DB ์กฐํ ์์ฒด๊ฐ ์คํจํ๋ฉด retryable ์์ธ๋ก ์ ํํ๋ค.
+
+### 7.4 Notification์ publish-candidate outbox๋ฅผ ์ฌ์ฉ
+
+- ๋ชจ๋ usage ์ด๋ฒคํธ๋ฅผ ์ ์ฅํ์ง ์๋๋ค.
+- notification ๋์ ์ด๋ฒคํธ๋ง `PUBLISH_PENDING` row๋ฅผ ๋ง๋ ๋ค.
+- ์ฆ์ ๋ฐํ ์คํจ ์ row๋ฅผ ๋จ๊ฒจ ํ์ ๋ณต๊ตฌ๊ฐ ๊ฐ๋ฅํ๋๋ก ํ๋ค.
+
+## 8. Kafka Topics
+
+| Type | Topic |
+|---|---|
+| Consumed | `usage-events` |
+| Produced | `notification-events` |
+| Historical | `usage-persist`, `usage-realtime` |
+
+## 9. Service Boundary
+
+### This Repository Handles
+- `usage-events` ์๋น
+- ์ค์๊ฐ ์ฌ์ฉ๋ ํ๋จ
+- DB ์ง์ ์ ์ฐ
+- notification ๋์ ํ๋จ
+- notification ์ฆ์ ๋ฐํ ์๋
+- notification ๋ณต๊ตฌ ๊ธฐ์ค์ ์ ์ฅ
+
+### External Recovery Process Handles
+- `PUBLISH_PENDING` ์กฐํ
+- ์ฌ๋ฐํ ์๋
+- `SENT` ๋๋ `FAILED` ๋ฐ์
diff --git a/docs/02_PROCESSING_FLOW.md b/docs/02_PROCESSING_FLOW.md
new file mode 100644
index 0000000..5077eba
--- /dev/null
+++ b/docs/02_PROCESSING_FLOW.md
@@ -0,0 +1,210 @@
+๏ปฟ# Processing Flow
+
+## 1. End-to-End Flow
+
+ํ์ฌ `dabom-processor-usage`์ usage ์ด๋ฒคํธ ์ฒ๋ฆฌ ํ๋ฆ์ ์๋์ ๊ฐ๋ค.
+
+1. Kafka์์ `usage-events`๋ฅผ ์์ ํ๋ค.
+2. payload๋ฅผ ๊ฒ์ฆํ๋ค.
+3. `familyId-customerId` ๊ด๊ณ๋ฅผ ๊ฒ์ฆํ๋ค.
+4. Redis warmup์ ์ํํ๋ค.
+5. Lua๊ฐ `duplicate`, `status`, `shouldNotify`๋ฅผ ๊ณ์ฐํ๋ค.
+6. Java๊ฐ Lua ๊ฒฐ๊ณผ๋ฅผ ํด์ํ๋ค.
+7. DB ์ ์ฐ์ ์ง์ ์ํํ๋ค.
+8. notification ๋์์ด๋ฉด Outbox์ `PUBLISH_PENDING`์ ์ ์ฅํ๋ค.
+9. notification์ ์ฆ์ ๋น๋๊ธฐ ๋ฐํํ๋ค.
+10. ์ฑ๊ณตํ๋ฉด `SENT`, ์คํจํ๋ฉด `PUBLISH_PENDING`์ ์ ์งํ๋ค.
+11. notification ๋น๋์์ด๋๋ผ๋, ๊ฐ์ `eventId`์ pending row๊ฐ ๋จ์ ์์ผ๋ฉด ์ฆ์ ๋ฐํ์ ๋ค์ ์๋ํ๋ค.
+
+## 2. Validation
+
+### 2.1 Payload Validation
+
+์ด์
์์ ์๋๋ฅผ ๊ฒ์ฆํ๋ค.
+
+- payload null ์ฌ๋ถ
+- `familyId > 0`
+- `customerId > 0`
+- `bytesUsed > 0`
+
+์ด ๊ฒ์ฆ์ ๊ฐ์ฅ ์์์ ์๋ชป๋ ๋ฉ์์ง๋ฅผ ์ฐจ๋จํ๊ธฐ ์ํ ๋จ๊ณ๋ค.
+
+ํจ๊ณผ:
+- Redis ์ํ ์ค์ผ ๋ฐฉ์ง
+- DB ์ ์ฐ ์ค์ผ ๋ฐฉ์ง
+- ๋ถํ์ํ ํ์ ์ฒ๋ฆฌ ๋ฐฉ์ง
+
+### 2.2 Family-Customer Validation
+
+`familyId-customerId` ๊ด๊ณ๋ฅผ Redis membership cache์ DB fallback์ผ๋ก ๊ฒ์ฆํ๋ค.
+
+์์:
+1. Redis `family:{familyId}:members` ํ์ธ
+2. cache hit๋ฉด ํต๊ณผ
+3. miss ๋๋ ๋ถ์ผ์น๋ฉด DB fallback
+4. DB์๋ ์์ผ๋ฉด invalid input
+5. Redis์ DB ์กฐํ๊ฐ ์คํจํ๋ฉด retryable ์์ธ๋ก ์ ํ
+
+์ด ๋จ๊ณ๋ usage ์ด๋ฒคํธ๊ฐ ์ค์ ๊ฐ์กฑ ๊ตฌ์ฑ์ ๊ด๊ณ๋ฅผ ๋ง์กฑํ๋์ง ํ์ธํ๋ ๋จ๊ณ๋ค.
+
+ํจ๊ณผ:
+- ์๋ชป๋ family-customer ์กฐํฉ ์ฐจ๋จ
+- Redis, Lua, DB, notification๊น์ง ์๋ชป๋ ์
๋ ฅ์ด ๋ด๋ ค๊ฐ์ง ์์
+
+## 3. Redis + Lua
+
+### 3.1 Redis Warmup
+
+Lua ์คํ ์ ์ ํ์ํ Redis ์ํ๋ฅผ ์ฑ์ด๋ค.
+
+๋์:
+- ๊ฐ์กฑ info
+- ๊ฐ์กฑ remaining
+- ๊ฐ์ธ ์ ์ฌ์ฉ๋
+- policy constraints
+
+warmup์ Redis์ ๊ฐ์ด ์์ ๋ DB๋ฅผ ์ฝ์ด ํ์ํ ํค๋ฅผ ์ฑ์ฐ๋ ์ญํ ์ ํ๋ค.
+
+ํจ๊ณผ:
+- Lua๊ฐ ํ์ํ ๊ธฐ์ค๊ฐ์ ํญ์ Redis์์ ์ฝ์ ์ ์์
+- ์์ด ์ฒซ ์ด๋ฒคํธ๋ ์บ์ miss ์ํฉ์์๋ ๋์ผํ ์ฒ๋ฆฌ ๊ฒฝ๋ก ์ ์ง
+
+### 3.2 Lua Decision
+
+Lua๋ ์๋๋ฅผ ์์์ ์ผ๋ก ์ํํ๋ค.
+
+- duplicate ์ฌ๋ถ ํ์ธ
+- ์ฌ์ฉ๋ ๋ฐ์
+- ์ฐจ๋จ ์ฌ๋ถ ํ๋จ
+- ๊ฒฝ๊ณ ์ํ ํ๋จ
+- ์๋ฆผ dedup ํ๋จ
+- ๊ฒฐ๊ณผ ์บ์ ์ ์ฅ
+
+๋ํ ๊ฒฐ๊ณผ:
+- `duplicate`
+- `status`
+- `shouldNotify`
+- `totalUsed`
+- `remaining`
+- `monthlyUsed`
+- `userRatio`
+- `monthlyLimit`
+
+์ Lua๋ฅผ ์ฐ๋๊ฐ:
+- Redis read/write์ ์ํ ๊ณ์ฐ์ ํ ๋ฒ์ ์ํํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
+- ์ฌ์ฉ๋ ์ฆ๊ฐ์ ์ํ ํ๋จ์ ๋ถ๋ฆฌํ๋ฉด race condition์ด ์๊ธธ ์ ์๋ค.
+- Lua๋ Redis ๋ด๋ถ์์ ์์์ ์ผ๋ก ์คํ๋๋ฏ๋ก ๊ฐ์ ์ด๋ฒคํธ๊ฐ ๋ชฐ๋ ค๋ ์ผ๊ด๋ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ ๋ค.
+
+## 4. Java Decision
+
+Java๋ Lua status๋ฅผ ์ค์ ๋งคํผ์์ ํด์ํ๋ค.
+
+์ง์ํ๋ status:
+- `NORMAL`
+- `WARNING_50`
+- `WARNING_30`
+- `WARNING_10`
+- `MANUAL`
+- `APP_BLOCK`
+- `TIME_BLOCK`
+- `MONTHLY_LIMIT_EXCEEDED`
+- `FAMILY_QUOTA_EXCEEDED`
+
+์ด ๋จ๊ณ์์ ์๋๊ฐ ์ ํด์ง๋ค.
+
+- DB persist result
+- notification ๋์ ์ฌ๋ถ
+- notification payload ์๋ฏธ
+
+์ฆ Lua๋ ์ํ ๋ฌธ์์ด์ ๋ฐํํ๊ณ , Java๋ ๊ทธ ๋ฌธ์์ด์ ํ์ ์ฒ๋ฆฌ ๊ท์น์ผ๋ก ๋ฐ๊พธ๋ ์ญํ ์ ๋งก๋๋ค.
+
+## 5. Direct DB Settlement
+
+DB ์ ์ฐ์ usage ์๋น์ค๊ฐ ์ง์ ์ํํ๋ค.
+
+### 5.1 allowed ์ด๋ฒคํธ
+1. `usage_record` insert ์๋
+2. ์ insert ์ฑ๊ณต ์์๋ง
+ - `customer_quota`
+ - `family_quota`
+ ๋ฐ์
+
+### 5.2 blocked ์ด๋ฒคํธ
+- `usage_record`๋ ๋ง๋ค์ง ์์
+- `customer_quota` ์ฐจ๋จ ์ํ ๋ฐ์
+
+allowed์ blocked๋ฅผ ๋๋๋ ์ด์ ๋ ์๋์ ๊ฐ๋ค.
+
+- allowed ์ด๋ฒคํธ๋ ์ค์ ์ฌ์ฉ๋ ์ฆ๊ฐ๋ฅผ ์์ํํด์ผ ํ๋ค.
+- blocked ์ด๋ฒคํธ๋ ์ฌ์ฉ์ด ํ์ฉ๋์ง ์์์ผ๋ฏ๋ก ์ฌ์ฉ๋ row๋ฅผ ๋ง๋ค์ง ์๊ณ ์ฐจ๋จ ์ํ๋ง ๋ฐ์ํ๋ค.
+
+๊ฐ์ ์ด๋ฒคํธ๊ฐ ๋ค์ ๋ค์ด์๋ `usage_record`๊ฐ ๋ฉฑ๋ฑ ๊ฐ๋ ์ญํ ์ ํ๋ค.
+
+## 6. Notification Flow
+
+notification์ ์๋ ์กฐ๊ฑด์ ๋ชจ๋ ๋ง์กฑํ ๋๋ง ๋์์ด๋ค.
+
+- status ๊ธฐ์ค์ผ๋ก ์๋ฆผ ๋์
+- Lua ๊ฒฐ๊ณผ ๊ธฐ์ค `shouldNotify = true`
+
+notification ๋์์ด๋ฉด:
+1. Outbox์ `PUBLISH_PENDING` ์ ์ฅ
+2. `NotificationPayload`๋ฅผ ์ง๋ ฌํํด `payload_json`์ ์ ์ฅ
+3. usage ์๋น์ค๊ฐ ์ฆ์ ๋น๋๊ธฐ๋ก ๋ฐํ ์๋
+4. ์ฑ๊ณตํ๋ฉด `SENT`
+5. ์คํจํ๋ฉด `PUBLISH_PENDING` ์ ์ง
+
+notification ๋น๋์์ด๋ฉด ์ Outbox row๋ ๋ง๋ค์ง ์๋๋ค.
+
+์ด ๊ตฌ์กฐ์ ์๋ฏธ๋ ์๋์ ๊ฐ๋ค.
+
+- ์ฆ์์ฑ์ usage ์๋น์ค๊ฐ ๋ด๋นํ๋ค.
+- ๋ฐํ ์คํจ ํ ๋ณต๊ตฌ ๊ธฐ์ค์ ์ Outbox๊ฐ ๋ด๋นํ๋ค.
+- notification ๋์์ด ์๋ ์ด๋ฒคํธ๋ ๋ถํ์ํ DB row๋ฅผ ๋จ๊ธฐ์ง ์๋๋ค.
+
+## 7. Processing Sequence
+
+```mermaid
+sequenceDiagram
+ participant K as Kafka usage-events
+ participant U as Usage Service
+ participant M as Membership Cache
+ participant R as Redis/Lua
+ participant D as DB
+ participant O as Outbox
+ participant N as Kafka notification-events
+
+ K->>U: usage-events 1๊ฑด
+ U->>U: payload ๊ฒ์ฆ
+ U->>M: family-customer ๊ฒ์ฆ
+ U->>R: warmup + Lua ์คํ
+ R-->>U: duplicate, status, shouldNotify
+ U->>D: DB ์ง์ ์ ์ฐ
+ alt shouldNotify = true
+ U->>O: PUBLISH_PENDING ์ ์ฅ
+ U->>N: ๋น๋๊ธฐ ๋ฐํ ์๋
+ alt ack success
+ U->>O: SENT ๋ฐ์
+ else ack fail
+ U->>O: PUBLISH_PENDING ์ ์ง
+ end
+ else shouldNotify = false
+ U->>U: Outbox row ์์ฑ ์์
+ end
+```
+
+## 8. Why This Flow Matters
+
+์ด ํ๋ฆ์์ ์ค์ํ ์ ์ ์๋ ์ธ ๊ฐ์ง๋ค.
+
+1. ์ค์๊ฐ ํ๋จ๊ณผ ์์ ์ ์ฐ์ด ๋ถ๋ฆฌ๋์ด ์๋ค.
+- Redis/Lua๋ ๋น ๋ฅธ ํ๋จ
+- DB๋ ์ต์ข
์ ์ฐ
+
+2. ๋ฉฑ๋ฑ์ฑ์ด ๊ตฌ์กฐ ์์ ๋ค์ด๊ฐ ์๋ค.
+- Redis dedup
+- `usage_record` ๊ธฐ๋ฐ DB ๋ฉฑ๋ฑ ์ ์ฐ
+
+3. notification์ ์ฆ์์ฑ๊ณผ ๋ณต๊ตฌ์ฑ์ ๋์์ ๊ฐ์ง๋ค.
+- ์ฆ์ ๋น๋๊ธฐ ๋ฐํ
+- Outbox ๊ธฐ๋ฐ ํ์ ๋ณต๊ตฌ
diff --git a/docs/03_OUTBOX_AND_RETRY.md b/docs/03_OUTBOX_AND_RETRY.md
new file mode 100644
index 0000000..4987e47
--- /dev/null
+++ b/docs/03_OUTBOX_AND_RETRY.md
@@ -0,0 +1,169 @@
+๏ปฟ# Outbox and Retry
+
+## 1. Outbox Role
+
+`usage_event_outbox`๋ notification ๋ฐํ ์ํ๋ฅผ ๋จ๊ธฐ๊ธฐ ์ํ ํ
์ด๋ธ์ด๋ค.
+
+ํ์ฌ ๊ตฌ์กฐ์ ํต์ฌ์ ์๋์ ๊ฐ๋ค.
+
+- ๋ชจ๋ usage ์ด๋ฒคํธ๋ฅผ ์ ์ฅํ์ง ์๋๋ค.
+- notification ๋์ ์ด๋ฒคํธ๋ง ์ ์ฅํ๋ค.
+- ์ ์ฅ๋๋ payload๋ `EventEnvelope`๊ฐ ์๋๋ผ `NotificationPayload` JSON์ด๋ค.
+- ์ฆ์ ๋ฐํ ์คํจ ์ `PUBLISH_PENDING`์ด ๋จ๋๋ค.
+
+์ฆ ์ด ํ
์ด๋ธ์ usage ์ด๋ฒคํธ ์ ์ฒด ๋ก๊ทธ๊ฐ ์๋๋ผ, notification ๋ฐํ๊ณผ ๋ณต๊ตฌ๋ฅผ ์ํ ์ํ ์ ์ฅ์๋ค.
+
+## 2. Why the Outbox Shape Changed
+
+์ด๊ธฐ์๋ usage ์ฒ๋ฆฌ ์ ์ฒด๋ฅผ ๋ ๋๊ฒ ์ถ์ ํ๋ ๋ฐฉํฅ๋ ๊ณ ๋ คํ ์ ์์์ง๋ง, ํ์ฌ ๊ตฌ์กฐ๋ notification ๋์ ์ด๋ฒคํธ๋ง ์ ์ฅํ๋ ๋ฐฉํฅ์ผ๋ก ์ ๋ฆฌ๋์๋ค.
+
+์ด๋ ๊ฒ ์ ๋ฆฌํ ์ด์ ๋ ์๋์ ๊ฐ๋ค.
+
+- usage ๋๋ฉ์ธ์์๋ notification ๋น๋์ ์ด๋ฒคํธ ๋น์จ์ด ๋์ ์ ์๋ค.
+- ๊ณ TPS ํ๊ฒฝ์์๋ ๋ชจ๋ ์ด๋ฒคํธ๋ฅผ DB row๋ก ๋จ๊ธฐ๋ ๋ฐฉ์์ด ๋ถ๋ด์ด ์ปค์ง๋ค.
+- ์ค์ ๋ก ๋ณต๊ตฌ๊ฐ ํ์ํ ์ง์ ์ notification ๋ฐํ ์คํจ ๊ตฌ๊ฐ์ด๋ค.
+
+๊ทธ๋์ ํ์ฌ Outbox๋ ์๋ ์ญํ ์ ์ง์คํ๋ค.
+
+- notification ๋์ ํ์
+- ์ฆ์ ๋ฐํ ํ ์ํ ์ถ์
+- ํ์ ๋ณต๊ตฌ ํ๋ก์ธ์ค ์ธ๊ณ
+
+## 3. Stored Data
+
+์ฃผ์ ์ปฌ๋ผ ์๋ฏธ:
+- `event_id`: ์๋ณธ usage ์ด๋ฒคํธ ์๋ณ์
+- `family_id`: ๊ฐ์กฑ ID
+- `customer_id`: trigger ์ฌ์ฉ์ ID
+- `status`: `PUBLISH_PENDING`, `SENT`, `FAILED`
+- `payload_json`: ์ต์ข
`NotificationPayload` JSON
+- `retry_count`, `next_retry_at`, `last_error`: ๋ณต๊ตฌ ํ๋ก์ธ์ค ์ํ ๊ด๋ฆฌ์ฉ
+
+์ฌ๊ธฐ์ `event_id`๋ notification ์ด๋ฒคํธ id๊ฐ ์๋๋ผ, ์๋ณธ usage ์ด๋ฒคํธ id๋ค.
+์ฆ ์ด row๊ฐ ์ด๋ค usage ์ด๋ฒคํธ์์ ํ์๋๋์ง๋ฅผ ์ถ์ ํ๋ ํค๋ค.
+
+## 4. Payload Shape
+
+Outbox์๋ `EventEnvelope`๊ฐ ์๋๋ผ ์ต์ข
`NotificationPayload` JSON์ ์ ์ฅํ๋ค.
+
+์ด๋ ๊ฒ ํ ์ด์ ๋ ์๋์ ๊ฐ๋ค.
+
+- ์ฆ์ ๋ฐํ๊ณผ ๋ณต๊ตฌ ๋ฐํ์ด ๊ฐ์ payload๋ฅผ ์ฌ์ฉํ๊ฒ ํ๊ธฐ ์ํด์
+- ๋ณต๊ตฌ ํ๋ก์ธ์ค๊ฐ payload๋ฅผ ๋ค์ ์กฐ๋ฆฝํ์ง ์๊ณ ๋ฐ๋ก ์ฌ๋ฐํํ ์ ์๊ฒ ํ๊ธฐ ์ํด์
+- notification์ business payload์ Kafka envelope ์์ฑ์ ๋ถ๋ฆฌํ๊ธฐ ์ํด์
+
+์ฆ Outbox๋ โ๋ฌด์์ ๋ณด๋ผ ๊ฒ์ธ๊ฐโ๋ฅผ ์ ์ฅํ๊ณ , ์ค์ envelope ์์ฑ์ ๋ฐํ ์์ ์ ์ํํ๋ค.
+
+## 5. Outbox Status
+
+### 5.1 PUBLISH_PENDING
+- notification ๋ฐํ ๋์ ํ์ ์๋ฃ
+- ์์ง ์ฑ๊ณต์ ์ผ๋ก ๋ง๊ฐ๋์ง ์์ ์ํ
+
+์ด ์ํ๋ ์๋ ์ํฉ์ ํฌํจํ๋ค.
+- ์ฆ์ ๋ฐํ ์
+- ์ฆ์ ๋ฐํ ์คํจ ํ
+- ํ์ ๋ณต๊ตฌ ํ๋ก์ธ์ค ๋๊ธฐ ์ค
+
+### 5.2 SENT
+- notification Kafka publish ์ฑ๊ณต์ด ๋ฐ์๋ ์ํ
+
+### 5.3 FAILED
+- ๋ณต๊ตฌ ํ๋ก์ธ์ค๊ฐ ์ต์ข
์คํจ๋ก ๋ง๊ฐํ ์ํ
+
+## 6. Immediate Publish Policy
+
+usage ์๋น์ค๋ notification์ ์ฆ์ ๋น๋๊ธฐ๋ก ๋จผ์ ๋ฐํํ๋ค.
+
+- ์ฑ๊ณต callback์ด๋ฉด `SENT`
+- ์คํจ callback์ด๋ฉด `PUBLISH_PENDING` ์ ์ง
+
+์ฆ usage ์๋น์ค๋ ์ฆ์์ฑ์ ๋ด๋นํ๊ณ , ๋ณต๊ตฌ ํ๋ก์ธ์ค๋ pending row๋ฅผ ๊ธฐ์ค์ผ๋ก ํ์ ๋ฐํ์ ์ํํ๋ค.
+
+์ด ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋ฉด:
+- ์ ์ ์ผ์ด์ค์์๋ ์ฆ์ ์๋ฆผ ์ ํ
+- ์คํจ ์ผ์ด์ค์์๋ row ๊ธฐ์ค ๋ณต๊ตฌ
+๊ฐ ๊ฐ๋ฅํด์ง๋ค.
+
+## 7. Retry Layers
+
+### 7.1 Consumer Retry
+
+lib-kafka ๋ถ๋ฅ ๊ธฐ์ค:
+- `IllegalArgumentException` -> `IGNORE`
+- `KafkaMessageProcessingException` -> `RETRY`
+- `NonRetryableKafkaMessageProcessingException` -> `DLQ`
+
+ํ์ฌ ์ด ๋ ํฌ๋ consumer retry ์ค์ ์ ๋ณ๋๋ก overrideํ์ง ์๋๋ค.
+
+์ฆ usage ์ด๋ฒคํธ ์ฒ๋ฆฌ ๋์ค ๋ฐ์ํ retryable ์์ธ๋ consumer ๋ ๋ฒจ์์ ๋ค์ ์ฒ๋ฆฌ๋๋ค.
+
+### 7.2 Service Re-entry
+
+๊ฐ์ `eventId`๊ฐ ๋ค์ ๋ค์ด์ค๋ฉด ์๋๊ฐ ๋ค์ ์ํ๋ ์ ์๋ค.
+
+- Redis warmup
+- Lua ์คํ
+- DB ์ ์ฐ
+- pending notification ์ฌ๋ฐํ ์๋
+
+์ด ๋ ์ด์ด๋ duplicate์ retry๋ฅผ ์๊ฒฉํ ๊ตฌ๋ถํ๊ธฐ๋ณด๋ค, ๊ฐ์ ์ด๋ฒคํธ ์ฌ์ง์
์ ์์ ํ๊ฒ ํก์ํ๋ ์ญํ ์ ํ๋ค.
+
+### 7.3 External Recovery Process
+
+๋ณต๊ตฌ ํ๋ก์ธ์ค๋ `PUBLISH_PENDING`์ ๋์์ผ๋ก ์๋ ์์๋ก ๋์ํ๋ค.
+
+1. `PUBLISH_PENDING` ์กฐํ
+2. `payload_json` ์ญ์ง๋ ฌํ
+3. `notification-events` ์ฌ๋ฐํ
+4. ์ฑ๊ณต ์ `SENT` ๋ฐ์
+5. ํ์ ์ `retry_count`, `next_retry_at`, `last_error` ๊ฐฑ์
+6. ์ต์ข
์คํจ ์ `FAILED` ๋ฐ์
+
+์ฆ usage ์๋น์ค๋ ์ฆ์ ๋ฐํ๊น์ง, ๋ณต๊ตฌ ํ๋ก์ธ์ค๋ pending row ํ์ ๋ฐํ๊น์ง ๋ด๋นํ๋ค.
+
+## 8. Failure Handling Summary
+
+| ์ ํ | ์ฒ๋ฆฌ ๋ฐฉ์ |
+|---|---|
+| invalid payload / ์๋ชป๋ family-customer | `IGNORE` |
+| membership lookup, Redis warmup, Lua, DB ์ ์ฐ, Outbox ์ ์ฅ ์คํจ | `RETRY` |
+| ์ํ ๊ณ์ฝ ๋ถ์ผ์น / ๋ณต๊ตฌ ๋ถ๊ฐ ์ง๋ ฌํ ์ค๋ฅ | `DLQ` |
+| ์ฆ์ notification ๋ฐํ ์คํจ | `PUBLISH_PENDING` ์ ์ง |
+
+## 9. Outbox Sequence
+
+```mermaid
+sequenceDiagram
+ participant U as Usage Service
+ participant O as Outbox
+ participant N as Kafka notification-events
+ participant B as External Recovery Process
+
+ U->>O: PUBLISH_PENDING ์ ์ฅ
+ U->>N: ์ฆ์ ๋น๋๊ธฐ ๋ฐํ
+ alt ack success
+ U->>O: SENT ๋ฐ์
+ else ack fail
+ U->>O: PUBLISH_PENDING ์ ์ง
+ B->>O: PUBLISH_PENDING ์กฐํ
+ B->>N: ์ฌ๋ฐํ
+ B->>O: SENT ๋๋ FAILED ๋ฐ์
+ end
+```
+
+## 10. Why This Design Matters
+
+ํ์ฌ Outbox ์ค๊ณ์ ํต์ฌ์ ์๋ ์ธ ๊ฐ์ง๋ค.
+
+1. notification ๋์ ์ด๋ฒคํธ๋ง ์ ์ฅํ๋ค.
+- ๋ถํ์ํ row๋ฅผ ์ค์ธ๋ค.
+- ๊ณ TPS ํ๊ฒฝ์์ DB hot path ๋น์ฉ์ ์ค์ธ๋ค.
+
+2. payload๋ฅผ ์ต์ข
notification ํํ๋ก ์ ์ฅํ๋ค.
+- ์ฆ์ ๋ฐํ๊ณผ ๋ณต๊ตฌ ๋ฐํ์ด ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ค.
+- ๋ณต๊ตฌ ํ๋ก์ธ์ค๊ฐ ๋จ์ํด์ง๋ค.
+
+3. ์ฆ์์ฑ๊ณผ ๋ณต๊ตฌ์ฑ์ ๋ถ๋ฆฌํ๋ค.
+- usage ์๋น์ค๋ ์ฆ์ ๋ฐํ์ ๋ด๋น
+- Outbox์ ๋ณต๊ตฌ ํ๋ก์ธ์ค๋ ์คํจ ํ ํ์ ๋ฐํ์ ๋ด๋น
diff --git a/docs/04_EXCEPTION_AND_RECOVERY.md b/docs/04_EXCEPTION_AND_RECOVERY.md
new file mode 100644
index 0000000..ed34470
--- /dev/null
+++ b/docs/04_EXCEPTION_AND_RECOVERY.md
@@ -0,0 +1,163 @@
+๏ปฟ# Exception and Recovery Guide
+
+## 1. Purpose
+
+์ด ๋ฌธ์๋ `usage-events` ์ฒ๋ฆฌ ๊ฐ ๋จ๊ณ์์ ์์ธ๊ฐ ๋ฐ์ํ์ ๋ ํ์ฌ ๊ตฌ์กฐ๊ฐ ์ด๋ค ๋ฐฉ์์ผ๋ก ๋ณต๊ตฌ์ ์ ํฉ์ฑ์ ์ ์งํ๋์ง ์ ๋ฆฌํ๋ค.
+
+ํต์ฌ์ ์๋ ์ธ ๊ฐ์ง๋ค.
+
+- ์๋ชป๋ ์
๋ ฅ์ ์ด์
์์ ์ฐจ๋จํ๋ค.
+- retryable ์์ธ๋ ๊ฐ์ Kafka ๋ ์ฝ๋๋ฅผ ๋ค์ ์ฒ๋ฆฌํ๋ค.
+- duplicate์ ์ฌ์ฒ๋ฆฌ๋ฅผ ๊ตฌ์กฐ์ ์ผ๋ก ํก์ํ๋ค.
+
+## 2. Step-by-Step Recovery
+
+| ๋จ๊ณ | ์คํจ ์ ํ | ์ฒ๋ฆฌ ๋ฐฉ์ | ๋ณต๊ตฌ ์ ๋ต |
+|---|---|---|---|
+| Payload Validation | payload null, ์์/0 ๊ฐ | `IllegalArgumentException` | ์๋ชป๋ ์
๋ ฅ์ผ๋ก ์ข
๋ฃ |
+| Family-Customer Validation | ์ค์ ์์ ๋ถ์ผ์น | `IllegalArgumentException` | ์๋ชป๋ ์
๋ ฅ์ผ๋ก ์ข
๋ฃ |
+| Family-Customer Validation | Redis/DB ์กฐํ ์คํจ | `KafkaMessageProcessingException` | consumer ์ฌ์ฒ๋ฆฌ |
+| Redis Warmup | info/remaining/monthly usage warmup ์คํจ | `KafkaMessageProcessingException` | consumer ์ฌ์ฒ๋ฆฌ |
+| Lua Execution | null ๊ฒฐ๊ณผ, invalid ๋ฐฐ์ด | `KafkaMessageProcessingException` | consumer ์ฌ์ฒ๋ฆฌ |
+| Lua Status Mapping | ์ง์ํ์ง ์๋ status | `NonRetryableKafkaMessageProcessingException` | DLQ |
+| DB Settlement | `usage_record`, quota ๋ฐ์ ์คํจ | ์์ธ ์ ํ | ํธ๋์ญ์
๋กค๋ฐฑ + consumer ์ฌ์ฒ๋ฆฌ |
+| Outbox Serialization | payload JSON ์ง๋ ฌํ/์ญ์ง๋ ฌํ ์คํจ | `NonRetryableKafkaMessageProcessingException` | DLQ |
+| Outbox Save | `PUBLISH_PENDING` ์ ์ฅ ์คํจ | ์์ธ ์ ํ | consumer ์ฌ์ฒ๋ฆฌ |
+| Immediate Publish | Kafka publish ack ์คํจ | ์์ธ ์ฝ๋ฐฑ ์ฒ๋ฆฌ | `PUBLISH_PENDING` ์ ์ง + ๋ณต๊ตฌ ํ๋ก์ธ์ค ์ฌ๋ฐํ |
+
+## 3. Why Each Recovery Strategy Exists
+
+### 3.1 Validation ๋จ๊ณ๋ ์ฌ์๋๋ณด๋ค ๊ฒฉ๋ฆฌ๊ฐ ์ค์ํ๋ค
+
+payload ๊ณ์ฝ ์๋ฐ์ด๋ family-customer ๋ถ์ผ์น๋ ๋ค์ ์ฒ๋ฆฌํด๋ ๋ฐ๋์ง ์๋๋ค.
+
+๊ทธ๋์ ์ด ๋จ๊ณ์ ๋ชฉํ๋:
+- ๋นจ๋ฆฌ ์คํจ์ํค๊ณ
+- ๋ค ๋จ๊ณ๋ฅผ ์ค์ผ์ํค์ง ์๊ณ
+- ๋ถํ์ํ ์ฌ์๋๋ฅผ ๋ง๋ค์ง ์๋ ๊ฒ
+์ด๋ค.
+
+### 3.2 Redis/Lua/DB ๋จ๊ณ๋ ๋ค์ ์ฒ๋ฆฌํ ์ ์์ด์ผ ํ๋ค
+
+์ด ๋จ๊ณ๋ค์ ์ผ์์ ์ธ ์ธํ๋ผ ๋ฌธ์ ๋ ํ์ด๋ฐ ์ด์๊ฐ ๋ฐ์ํ ์ ์๋ค.
+
+๊ทธ๋์ ์ด ๋จ๊ณ์ ๋ชฉํ๋:
+- retryable ์์ธ๋ก ๋ถ๋ฅํ๊ณ
+- ๊ฐ์ usage ์ด๋ฒคํธ๋ฅผ ๋ค์ ์ฒ๋ฆฌํ๊ฒ ํ๊ณ
+- ๊ฐ์ ์ด๋ฒคํธ ์ฌ์ง์
์์๋ ๊ฒฐ๊ณผ๊ฐ ๊นจ์ง์ง ์๊ฒ ํ๋ ๊ฒ
+์ด๋ค.
+
+### 3.3 notification ๋จ๊ณ๋ ๋ณต๊ตฌ ๊ธฐ์ค์ ์ด ํ์ํ๋ค
+
+์ฆ์ ๋ฐํ์ ์คํจํ ์ ์๋ค. ๊ทธ๋์ usage ์๋น์ค๋ ๋ฐํ ๋์์ผ ๋ Outbox์ `PUBLISH_PENDING`์ ๋จ๊ธด๋ค.
+
+์ด ๋จ๊ณ์ ๋ชฉํ๋:
+- ์ ์ ์ผ์ด์ค์์๋ ๋ฐ๋ก ๋ณด๋ด๊ณ
+- ์คํจ ์ผ์ด์ค์์๋ pending row๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ค์ ๋ณด๋ผ ์ ์๊ฒ ํ๋ ๊ฒ
+์ด๋ค.
+
+## 4. Loss Prevention Strategy
+
+### 4.1 Invalid Input Isolation
+
+์๋ชป๋ payload์ ์๋ชป๋ family-customer ์กฐํฉ์ ์ด์
์์ ์ฐจ๋จํ๋ค.
+
+ํจ๊ณผ:
+- Redis ์ค์ผ ๋ฐฉ์ง
+- DB ์ค์ผ ๋ฐฉ์ง
+- ๋ถํ์ํ notification ๋ฐฉ์ง
+
+### 4.2 Redis Re-apply Prevention
+
+Lua๋ `event:dedup:usage:{eventId}` ํค๋ฅผ ์ฌ์ฉํด ๊ฐ์ ์ด๋ฒคํธ๊ฐ ๋ค์ ๋ค์ด์๋ Redis ์ฆ๊ฐ์ ๋ค์ ์ํํ์ง ์๋๋ค.
+
+ํจ๊ณผ:
+- consumer ์ฌ์ฒ๋ฆฌ ์ Redis ์ค๋ณต ๋ฐ์ ๋ฐฉ์ง
+- duplicate์ retry๊ฐ ๊ฐ์ ๊ฒฝ๋ก๋ก ๋ค์ด์๋ Redis ์ํ ์์ ํ
+
+### 4.3 DB Idempotent Settlement
+
+allowed ์ด๋ฒคํธ๋ `usage_record` insert๊ฐ ๋จผ์ ์ํ๋๊ณ , ์ insert ์ฑ๊ณต ์์๋ง quota๋ฅผ ๋ฐ์ํ๋ค.
+
+ํจ๊ณผ:
+- ๊ฐ์ `eventId` ์ฌ์ฒ๋ฆฌ ์ `usage_record`๊ฐ ๋ฉฑ๋ฑ ๊ฐ๋ ์ญํ
+- `customer_quota`, `family_quota` ์ค๋ณต ๋ฐ์ ๋ฐฉ์ง
+
+### 4.4 Notification Recovery Point
+
+notification ๋์ ์ด๋ฒคํธ๋ Outbox์ `PUBLISH_PENDING`์ ์ ์ฅํ ๋ค ์ฆ์ ๋น๋๊ธฐ ๋ฐํ์ ์๋ํ๋ค.
+
+ํจ๊ณผ:
+- ์ฆ์ ๋ฐํ ์ฑ๊ณต ์ `SENT` ๋ฐ์
+- ์ฆ์ ๋ฐํ ์คํจ ์ `PUBLISH_PENDING`์ ๊ธฐ์ค์ผ๋ก ํ์ ๋ณต๊ตฌ ๊ฐ๋ฅ
+
+## 5. Recovery Sequence Examples
+
+### 5.1 Redis ๋ฐ์ ํ DB ์ ์ฐ ์คํจ
+
+```mermaid
+sequenceDiagram
+ participant U as Usage Service
+ participant R as Redis/Lua
+ participant D as DB
+ participant K as Kafka Retry
+
+ U->>R: Lua ์คํ ๋ฐ Redis ๋ฐ์
+ R-->>U: status ๋ฐํ
+ U->>D: DB ์ ์ฐ ์๋
+ D-->>U: ์์ธ ๋ฐ์
+ U-->>K: retryable ์์ธ ์ ํ
+ K->>U: ๊ฐ์ eventId ์ฌ์ฒ๋ฆฌ
+ U->>R: Lua ์ฌ์คํ
+ R-->>U: duplicate ๊ฒฐ๊ณผ ์ฌ์ฌ์ฉ
+ U->>D: DB ์ ์ฐ ์ฌ์ง์
+```
+
+์ด ์๋๋ฆฌ์ค์ ํต์ฌ์ ์๋์ ๊ฐ๋ค.
+
+- Redis๋ ์ด๋ฏธ ๋ฐ์๋์์ง๋ง
+- ๊ฐ์ ์ด๋ฒคํธ ์ฌ์ฒ๋ฆฌ ์ Lua dedup cache๊ฐ Redis ์ฌ๋ฐ์์ ๋ง๋๋ค.
+- DB ์ ์ฐ์ ๋ค์ ์ง์
ํ๊ณ , ์ต์ข
์ ์ผ๋ก ์์ ์ํ๊ฐ Redis ํ๋จ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋ผ๊ฐ๋ค.
+
+### 5.2 Outbox ์ ์ฅ ํ ์ฆ์ ๋ฐํ ์คํจ
+
+```mermaid
+sequenceDiagram
+ participant U as Usage Service
+ participant O as Outbox
+ participant N as Kafka notification-events
+ participant B as Recovery Process
+
+ U->>O: PUBLISH_PENDING ์ ์ฅ
+ U->>N: ์ฆ์ ๋น๋๊ธฐ ๋ฐํ
+ N-->>U: ack ์คํจ
+ U->>O: PUBLISH_PENDING ์ ์ง
+ B->>O: pending row ์กฐํ
+ B->>N: ์ฌ๋ฐํ
+ B->>O: SENT ๋๋ FAILED ๋ฐ์
+```
+
+์ด ์๋๋ฆฌ์ค์ ํต์ฌ์ ์๋์ ๊ฐ๋ค.
+
+- ์ฆ์ ๋ฐํ์ ์คํจํ ์ ์๋ค.
+- ํ์ง๋ง pending row๊ฐ ์ด๋ฏธ ๋จ์ ์์ผ๋ฏ๋ก ๋ณต๊ตฌ ๊ธฐ์ค์ ์ ์ ์ง๋๋ค.
+- ํ์ ๋ณต๊ตฌ ํ๋ก์ธ์ค๋ payload๋ฅผ ๋ค์ ๋ง๋ค์ง ์๊ณ row ๊ธฐ์ค์ผ๋ก ์ฌ๋ฐํํ ์ ์๋ค.
+
+## 6. Stage-by-Stage Guarantees
+
+| ๊ตฌ๊ฐ | ์ ํฉ์ฑ ํฌ์ธํธ |
+|---|---|
+| Validation | ์๋ชป๋ ์
๋ ฅ์ ๋ค ๋จ๊ณ๋ก ๋ด๋ ค๊ฐ์ง ์์ |
+| Redis + Lua | duplicate ๊ฒฐ๊ณผ์ ์ํ ๊ณ์ฐ์ ์์์ ์ผ๋ก ์ฒ๋ฆฌ |
+| DB Settlement | `usage_record` ๊ธฐ๋ฐ ๋ฉฑ๋ฑ ์ ์ฐ |
+| Notification | ๋์ ์ด๋ฒคํธ๋ง Outbox ์ ์ฅ + ๋ฐํ ์ํ ๊ด๋ฆฌ |
+
+## 7. Reading Guide
+
+์ด ๋ฌธ์๋ฅผ ๋ณผ ๋๋ ์๋ ์์๋ก ์ฝ์ผ๋ฉด ๋๋ค.
+
+1. ์ด๋ค ์คํจ๊ฐ retryable์ธ์ง ํ์ธํ๋ค.
+2. ๊ทธ ์คํจ๊ฐ Redis, DB, notification ์ค ์ด๋ ๊ณ์ธต์์ ์ผ์ด๋๋์ง ๋ณธ๋ค.
+3. ์ดํ ์ฌ์ฒ๋ฆฌ ๊ธฐ์ค์ ์ด Redis dedup์ธ์ง, DB ๋ฉฑ๋ฑ์ฑ์ธ์ง, Outbox์ธ์ง ํ์ธํ๋ค.
+
+์ฆ ํ์ฌ ๊ตฌ์กฐ๋ ์คํจ ์ ํ๋ง๋ค ๋ณต๊ตฌ ๊ธฐ์ค์ ์ ๋ค๋ฅด๊ฒ ๋๋ ๋ฐฉ์์ผ๋ก ์ ๋ฆฌ๋์ด ์๋ค.
diff --git a/docs/05_DATA_MODEL_AND_KEYS.md b/docs/05_DATA_MODEL_AND_KEYS.md
new file mode 100644
index 0000000..67eb95d
--- /dev/null
+++ b/docs/05_DATA_MODEL_AND_KEYS.md
@@ -0,0 +1,170 @@
+๏ปฟ# Data Model and Redis Keys
+
+## 1. Purpose
+
+์ด ๋ฌธ์๋ `dabom-processor-usage`๊ฐ ์ฌ์ฉํ๋ ํต์ฌ ์ ์ฅ ๊ตฌ์กฐ๋ฅผ ์ ๋ฆฌํ๋ค.
+
+- MySQL ์์ ๋ฐ์ดํฐ
+- notification outbox payload
+- Redis key ๊ตฌ์กฐ
+- Lua dedup/cache ๊ตฌ์กฐ
+
+ํต์ฌ์ usage ์ด๋ฒคํธ 1๊ฑด์ด ์ด๋ค ์ ์ฅ ๊ตฌ์กฐ๋ฅผ ํต๊ณผํ๊ณ , ๊ทธ ๊ตฌ์กฐ๊ฐ ๊ฐ๊ฐ ์ด๋ค ์ญํ ์ ๋งก๋์ง ์ดํดํ๋ ๊ฒ์ด๋ค.
+
+## 2. MySQL Settlement Model
+
+### 2.1 usage_record
+
+allowed ์ด๋ฒคํธ์ ๋ฉฑ๋ฑ ๊ฐ๋ ์ญํ ์ ํ๋ค.
+
+- ๊ฐ์ `eventId`๊ฐ ๋ค์ ๋ค์ด์ค๋ฉด ์ค๋ณต insert๋ฅผ ๋ง๋๋ค.
+- ์ row๊ฐ ๋ค์ด๊ฐ ๊ฒฝ์ฐ์๋ง quota ๋ฐ์์ด ์ด์ด์ง๋ค.
+
+์ฆ `usage_record`๋ โ์ด usage ์ด๋ฒคํธ๊ฐ ์ค์ ์ฌ์ฉ๋ ์ฆ๊ฐ๋ก ์ ์ฐ๋์๋๊ฐโ๋ฅผ ๊ณ ์ ํ๋ ๊ธฐ์ค์ ์ด๋ค.
+
+### 2.2 customer_quota
+
+๊ณ ๊ฐ ๊ธฐ์ค ์ ์ฌ์ฉ๋๊ณผ ์ฐจ๋จ ์ํ๋ฅผ ๋ฐ์ํ๋ค.
+
+- allowed ์ด๋ฒคํธ: ์ ์ฌ์ฉ๋ ์ฆ๊ฐ
+- blocked ์ด๋ฒคํธ: ์ฐจ๋จ ์ํ ๋ฐ์
+
+์ฆ customer ๋จ์ ์ ์ฑ
๊ณผ ์ ์ฌ์ฉ๋์ ์์ ๊ธฐ์ค์ผ๋ก ๊ด๋ฆฌํ๋ ๊ตฌ์กฐ๋ค.
+
+### 2.3 family_quota
+
+๊ฐ์กฑ ๊ธฐ์ค ์ ์ฌ์ฉ๋์ ๋ฐ์ํ๋ค.
+
+- allowed ์ด๋ฒคํธ์์๋ง ์ฆ๊ฐ
+- ๊ฐ์กฑ ์์ฌ๋๊ณผ ๊ฒฝ๊ณ /์ฐจ๋จ ํ๋จ์ ๊ธฐ์ค์ด ๋๋ค.
+
+์ฆ Redis์์ ๋น ๋ฅด๊ฒ ํ๋จํ๋ ๊ธฐ์ค๊ฐ๋ ๊ฒฐ๊ตญ DB์ `family_quota` ์์ ์ํ๋ฅผ ๋ฐํ์ผ๋ก warmup ๋๋ค.
+
+## 3. Why This Model Matters
+
+ํ์ฌ ์ ์ฐ ๊ตฌ์กฐ๊ฐ ์ด๋ ๊ฒ ๋๋ ์ด์ ๋ ์๋์ ๊ฐ๋ค.
+
+- `usage_record`: ์ด๋ฒคํธ ๋ฉฑ๋ฑ์ฑ ๊ธฐ์ค์
+- `customer_quota`: ๊ณ ๊ฐ ๋จ์ ์ ์ฌ์ฉ๋๊ณผ ์ฐจ๋จ ์ํ ๊ธฐ์ค์
+- `family_quota`: ๊ฐ์กฑ ๋จ์ ์ด ์ฌ์ฉ๋๊ณผ ์์ฌ๋ ๊ธฐ์ค์
+
+์ฆ ํ๋์ ํ
์ด๋ธ์ ๋ชจ๋ ์๋ฏธ๋ฅผ ๋ชฐ์๋ฃ์ง ์๊ณ , usage ์ด๋ฒคํธ์ ์ญํ ์ ๋๋์ด ์์ํํ๋ค.
+
+## 4. Outbox Payload Model
+
+Outbox์๋ `EventEnvelope`๊ฐ ์๋๋ผ ์ต์ข
`NotificationPayload` JSON์ด ์ ์ฅ๋๋ค.
+
+์ฃผ์ ํ๋:
+- `familyId`
+- `customerId`
+- `type`
+- `title`
+- `message`
+- `data`
+
+`data`์๋ ์๋ ์ถ์ ์ ๋ณด๊ฐ ๋ค์ด๊ฐ๋ค.
+- `originEventId`
+- `eventTime`
+- `status`
+- `familyId`
+- `customerId`
+- `appId`
+- `bytesUsed`
+
+์ด๋ ๊ฒ ์ ์ฅํ๋ ์ด์ ๋ ์๋์ ๊ฐ๋ค.
+
+- ์ฆ์ ๋ฐํ๊ณผ ๋ณต๊ตฌ ๋ฐํ์ด ๊ฐ์ payload๋ฅผ ์ฌ์ฉํ๊ฒ ํ๊ธฐ ์ํด์
+- ๋ณต๊ตฌ ํ๋ก์ธ์ค๊ฐ notification ๋ด์ฉ์ ๋ค์ ๊ณ์ฐํ์ง ์๊ฒ ํ๊ธฐ ์ํด์
+- usage ์ด๋ฒคํธ์ notification payload์ ์ฐ๊ฒฐ ๊ด๊ณ๋ฅผ row ์์ ๋ณด์กดํ๊ธฐ ์ํด์
+
+## 5. Redis Key Structure
+
+### 5.1 Family State
+
+- `family:{familyId}:info:{yyyyMM}`
+- `family:{familyId}:remaining:{yyyyMM}`
+- `family:{familyId}:members`
+
+๊ฐ ํค์ ์๋ฏธ:
+- `info`: ๊ฐ์กฑ ์ด quota์ ๋ฉํ ์ ๋ณด
+- `remaining`: ํ์ฌ ๊ฐ์กฑ ์์ฌ๋
+- `members`: family-customer ๊ฒ์ฆ์ฉ membership set
+
+### 5.2 Customer State
+
+- `family:{familyId}:customer:{customerId}:usage:monthly:{yyyyMM}`
+- `family:{familyId}:customer:{customerId}:constraints`
+
+๊ฐ ํค์ ์๋ฏธ:
+- `usage:monthly`: ๊ฐ์ธ ์ ์ฌ์ฉ๋ ์บ์
+- `constraints`: ์ฐจ๋จ ์๊ฐ, ์ฑ ์ฐจ๋จ, ์ ํ๋ ๊ฐ์ ์ ์ฑ
์ ์ฝ
+
+### 5.3 Alert Dedup Keys
+
+๊ฒฝ๊ณ ์๋ฆผ:
+- `family:{familyId}:customer:{customerId}:alert:THRESHOLD:50:{yyyyMM}`
+- `family:{familyId}:customer:{customerId}:alert:THRESHOLD:30:{yyyyMM}`
+- `family:{familyId}:customer:{customerId}:alert:THRESHOLD:10:{yyyyMM}`
+
+์ฐจ๋จ ์๋ฆผ:
+- `family:{familyId}:customer:{customerId}:alert:MANUAL:{yyyyMM}`
+- `family:{familyId}:customer:{customerId}:alert:APP_BLOCK:{appId}:{yyyyMM}`
+- `family:{familyId}:customer:{customerId}:alert:TIME_BLOCK:{yyyyMM}`
+- `family:{familyId}:customer:{customerId}:alert:MONTHLY_LIMIT_EXCEEDED:{yyyyMM}`
+- `family:{familyId}:customer:{customerId}:alert:FAMILY_QUOTA_EXCEEDED:{yyyyMM}`
+
+์ด ํค๋ค์ ์ด๋ฒ ๋ฌ ๊ฐ์ ์ ํ ์๋ฆผ์ ๋ค์ ๋ฐํํ์ง ์๋๋ก ์ ์ดํ๋ ์ญํ ์ ํ๋ค.
+
+### 5.4 Event Dedup Key
+
+- `event:dedup:usage:{eventId}`
+
+์ด ํค์๋ Lua ๊ฒฐ๊ณผ ์บ์๊ฐ ์ ์ฅ๋๋ค.
+
+์ฆ ์ด ํค๋ ๊ฐ์ usage ์ด๋ฒคํธ๊ฐ ๋ค์ ๋ค์ด์์ ๋ Redis ์ฆ๊ฐ์ ๋ค์ ํ์ง ์๊ฒ ํ๋ ๊ธฐ์ค์ ์ด๋ค.
+
+## 6. Lua Result Cache
+
+dedup cache์๋ ์๋ ์ ๋ณด๊ฐ ํจ๊ป ์ ์ฅ๋๋ค.
+
+- `totalUsed`
+- `remaining`
+- `status`
+- `monthlyUsed`
+- `userRatio`
+- `monthlyLimit`
+- `shouldNotify`
+- `duplicate`
+
+์ด ์ ๋ณด๊ฐ ๊ฐ์ด ์ ์ฅ๋๋ ์ด์ ๋ ์๋์ ๊ฐ๋ค.
+
+- ๊ฐ์ ์ด๋ฒคํธ ์ฌ์ฒ๋ฆฌ ์ Redis ์ฌ๋ฐ์ ๋ฐฉ์ง
+- ์ด์ ๊ณ์ฐ ๊ฒฐ๊ณผ ์ฌ์ฌ์ฉ
+- Java๊ฐ ๋์ผํ ์ํ ํด์์ ๋ค์ ์ํํ ์ ์์
+- duplicate์ retry๊ฐ ๊ฐ์ ๊ฒฝ๋ก๋ก ๋ค์ด์๋ ์ผ๊ด๋ ๊ฒฐ๊ณผ ์ ์ง
+
+## 7. Data Flow View
+
+```mermaid
+flowchart TD
+ A[usage-events] --> B[Validation]
+ B --> C[Redis warmup]
+ C --> D[Lua decision]
+ D --> E[usage_record]
+ E --> F[customer_quota]
+ E --> G[family_quota]
+ D --> H[NotificationPayload]
+ H --> I[usage_event_outbox]
+ I --> J[notification-events]
+```
+
+## 8. Reading the Model as a Whole
+
+์ด ๋ชจ๋ธ์ ์ ์ฒด๋ก ๋ณด๋ฉด ์ญํ ์ด ๋ค์์ฒ๋ผ ๋๋๋ค.
+
+- Redis: ๋น ๋ฅธ ์ํ ๊ณ์ฐ
+- `usage_record`: ์ด๋ฒคํธ ๋ฉฑ๋ฑ์ฑ ๊ธฐ์ค์
+- `customer_quota`, `family_quota`: ์ต์ข
์ ์ฐ ๊ธฐ์ค์
+- Outbox: notification ๋ฐํ ์ํ ๊ธฐ์ค์
+
+์ฆ `dabom-processor-usage`๋ ํ๋์ usage ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ฉด์๋, ๊ฐ ์ ์ฅ ๊ตฌ์กฐ๋ฅผ ์๋ก ๋ค๋ฅธ ์ฑ
์์ ๋ง๊ฒ ์ฌ์ฉํ๋๋ก ์ค๊ณ๋ ์๋น์ค๋ค.