diff --git a/.coderabbit.yaml b/.coderabbit.yaml
new file mode 100644
index 0000000..ecb145c
--- /dev/null
+++ b/.coderabbit.yaml
@@ -0,0 +1,14 @@
+language: ko-KR
+early_access: false
+reviews:
+ profile: "chill"
+ request_changes_workflow: false
+ high_level_summary: true
+ poem: false
+ review_status: true
+ collapse_walkthrough: false
+ auto_review:
+ enabled: true
+ drafts: false
+chat:
+ auto_reply: true
diff --git a/04-form/README.md b/04-form/README.md
new file mode 100644
index 0000000..b029ec9
--- /dev/null
+++ b/04-form/README.md
@@ -0,0 +1,38 @@
+# 04. 폼 UI 구현하기: controlled vs uncontrolled
+
+## 🎯 요구 사항
+- `Header`의 레스토랑 추가 버튼을 클릭하면 레스토랑 추가 폼이 모달로 뜨도록 구현해 주세요
+ - 이전 단계에서 만들어두었던 `AddRestaurantModal`을 그대로 사용합니다.
+- 카테고리를 선택하고, ``, ``에 값을 입력한 뒤 '추가하기' 버튼을 클릭하면 레스토랑 목록에 추가되도록 구현해 주세요.
+ - 유효성 검사는 하지 않습니다. 아주 간단하게 입력값을 처리해보는 구현만 해도 충분합니다.
+ - id는 `Date.now()`값을 임의로 할당합니다.
+- (optional) 재사용할 수 있는 Modal 컴포넌트를 만들어서 `AddRestaurantModal`, `RestaurantDetailModal`을 Modal 컴포넌트를 활용해 구현하는 것으로 개선해 보세요
+
+## ✅ 키워드
+- controlled vs uncontrolled
+- children props
+
+> 재사용할 수 있는 모달을 만들 때 `children`을 활용해 보세요. 아래와 같은 식으로 UI를 구성할 수 있습니다.
+
+```javascript
+// 설명을 위한 예시용 마크업입니다. 실제로 사용하는 마크업은 template/ 하위의 html을 참고하거나 직접 원하는대로 구현하여 사용해 주세요.
+// 반드시 아래와 같은 형식으로 쓸 필요는 없습니다. 원하는 방식대로 재사용 가능한 컴포넌트를 만들어 보세요.
+
+// AddRestaurantModal.jsx
+
+
+
+
+// RestaurantDetailModal.jsx
+
+
+
+
+```
+
+## 🧙♀️ 진행 가이드
+- 진행 시간: (optional 제외) 2시간 내에 완료하는 것을 목표로 합니다.
+
+## 🔗 참고 문서
+- [Sharing State Between Components](https://react.dev/learn/sharing-state-between-components)
+- [API Reference: ](https://react.dev/reference/react-dom/components/input)
\ No newline at end of file
diff --git a/README.md b/README.md
index 1d0f3a4..e206bd7 100644
--- a/README.md
+++ b/README.md
@@ -1,130 +1,181 @@
-# 조건부 렌더링 활용
+# 재사용 가능한 컴포넌트 설계
## 🎯 개인 목표 및 목표 달성을 위한 행동 가이드
이번 미션을 통해 다음과 같은 학습 경험들을 쌓는 것을 목표로 한다.
-1. 이벤트 핸들러를 통해 사용자 인터랙션에 반응하는 방법을 이해한다.
-2. 조건부 렌더링(`&&`)을 활용해 상황에 따라 컴포넌트를 보여주고 숨긴다.
-3. 어떤 값을 state로 선언해야 하는지 기준을 세운다.
+1. controlled 컴포넌트와 uncontrolled 컴포넌트의 차이를 이해하고, 각각 어떤 상황에서 선택하는지 기준을 세운다.
+2. 어떤 state를 어느 컴포넌트가 소유해야 하는지 판단하고, 필요한 경우 공통 부모로 끌어올리는 패턴(Lifting State Up)을 경험한다.
+3. `children` props를 활용해 재사용 가능한 Modal 컴포넌트를 설계하는 방법을 익힌다.
---
## 📝 기능 구현 목록
-- [x] 음식점 아이템 클릭 시 모달 열기
-- [x] 닫기 버튼 또는 backdrop 클릭 시 모달 닫기
-- [x] 클릭한 음식점 정보를 모달에 전달하여 표시
+- [x] Header의 음식점 추가 버튼 클릭 시 AddRestaurantModal 열기
+- [x] 추가하기 버튼 클릭 시 음식점 목록에 항목 추가
+- [x] 재사용 가능한 Modal 컴포넌트로 AddRestaurantModal, RestaurantDetailModal 개선
---
## 📚 학습 내용
-### 이벤트 핸들러와 데이터 전달
+### Controlled vs Uncontrolled Component
-이벤트 핸들러에 함수를 직접 연결하면 React가 이벤트 객체(`e`)를 자동으로 넘겨준다. 클릭된 아이템의 데이터를 함께 전달하려면 화살표 함수로 한 번 감싸야 한다.
+컴포넌트의 중요한 정보가 **props**에 의해 결정되면 controlled, **지역 state**로 자체 관리되면 uncontrolled이다.
-```jsx
-// 이벤트 객체(e)만 전달됨
-onClick={onRestaurantClick}
+| | Controlled | Uncontrolled |
+|---|---|---|
+| 정보 출처 | props (부모가 제공) | 지역 state (자체 관리) |
+| 부모의 영향 | 동작을 완전히 지정 가능 | 영향을 줄 수 없음 |
+| 유연성 | 여러 컴포넌트와 조정 용이 | 독립적이지만 협력 어려움 |
+| 사용 난이도 | 부모에서 props 설정 필요 | 설정이 적어 사용하기 쉬움 |
-// 클릭된 restaurant 데이터를 직접 전달
-onClick={() => onRestaurantClick(restaurant)}
-```
+**언제 선택하나?**
+- **Controlled** — 부모 컴포넌트와 state를 공유하거나, 여러 컴포넌트의 동작을 함께 조정해야 할 때
+- **Uncontrolled** — 부모와 상태를 공유할 필요 없이 독립적으로 동작해도 될 때
-`() => onRestaurantClick(restaurant)`는 `map` 순회 중인 `restaurant`를 부모까지 전달하는 역할을 한다.
+**이 미션에서의 선택:**
-### 조건부 렌더링
+controlled/uncontrolled는 컴포넌트 전체에 붙이는 레이블이 아니라, 어떤 정보가 어디서 관리되는지를 기준으로 판단한다. AddRestaurantModal은 두 가지가 혼재한다.
-`{condition && }` 패턴으로 조건이 참일 때만 컴포넌트를 렌더링한다.
+- **폼 데이터** (category, name, description) → 지역 state로 자체 관리 → **uncontrolled**
+- **모달 열림/닫힘** → App이 소유 → **controlled**
-```jsx
-{clickedRestaurant && (
-
-)}
-```
+모달 열림 상태를 App이 소유하는 이유는 트리거(Header의 추가 버튼)와 모달이 형제 관계이기 때문이다. 형제끼리는 서로의 state에 접근할 수 없으므로 공통 부모인 App으로 state를 끌어올렸다(Lifting State Up).
+
+`onSubmit`, `onClose`는 state가 아닌 콜백이다. "어떤 값을 누가 소유하냐"의 문제가 아니라 이벤트를 부모로 전달하는 통로이므로 controlled/uncontrolled 구분과는 별개다.
-### State로 선언할 것과 아닌 것
+### form submit 기본 동작과 e.preventDefault()
-**State가 필요한 경우**: 시간이 지나면서 변하고, 렌더링에 영향을 주며, 다른 state나 props로부터 계산할 수 없는 값
+`