+ {/* 선택됐을 때만 보이는 안내 메시지 */}
+ {isFocused && (
+
backspace 또는 del 키를 통해 삭제
+ )}
+
+ {/* 실제 이미지를 보여주는 컴포넌트 */}
+
+
+ // ...
+);
+```
+
+#### LazyEditorImage의 특징
+
+* **최적화**: 이미지가 화면에 보일 때만 로딩(`Lazy Loading`)하고, 불필요한 함수 생성을 막기 위해 `useCallback`을 사용해요.
+* **사용자 경험(UX)**: 이미지를 선택하면 테두리로 시각적 피드백을 주고, 키보드로 쉽게 삭제할 수 있게 만들어 사용자가 편하게 쓸 수 있어요.
+
+-----
+
+## 🔄 노드는 어떻게 태어나고 변할까요? (생명주기)
+
+### 1\. 이미지 노드가 만들어지는 과정
+
+```mermaid
+sequenceDiagram
+ participant U as 유저
+ participant P as 플러그인
+ participant E as 에디터
+ participant N as ImageNode
+ participant C as LazyEditorImage
+
+ U->>P: 이미지를 끌어다 놓는다
+ P->>E: "이미지 넣어줘!" (INSERT_IMAGE_COMMAND)
+ E->>N: `$createImageNode()`로 노드 생성
+ N->>E: "나 여기 들어갈래!" (노드 트리에 삽입)
+ E->>N: "이제 화면에 네 모습 보여줘." (decorate() 호출)
+ N->>C: "이 컴포넌트로 그려줘!" (LazyEditorImage 반환)
+ C->>U: 화면에 이미지가 짠!
+```
+
+### 2\. 노드 정보가 바뀌는 과정 (e.g. 크기 조절)
+
+불변성 원칙에 따라, 노드를 직접 바꾸는 게 아니라 복사본을 만들어 수정해요.
+
+```typescript
+// 1. 유저가 이미지 크기를 조절하면
+editor.update(() => {
+ const node = $getNodeByKey(imageNodeKey);
+
+ // 2. 쓰기 가능한 복사본을 만들어서
+ const writableNode = node.getWritable();
+
+ // 3. 복사본의 값을 바꿔치기해요.
+ writableNode.setWidthAndHeight(newWidth, newHeight);
+
+ // 4. 그럼 Lexical이 알아서 화면을 다시 그려줘요.
+});
+```
+
+-----
+
+## ⚡️ 빠릿빠릿한 에디터를 위한 최적화 이야기
+
+### 1\. 메모리 사용량 줄이기
+
+**지연 로딩 (Lazy Loading)**
+`LazyImage` 컴포넌트는 React.lazy를 사용해서 만들었어요. 덕분에 당장 화면에 보이지 않는 이미지는 로드하지 않아 초기 로딩 속도가 빨라지죠.
+
+```typescript
+// LazyImage 컴포넌트는 필요할 때만 불러와요.
+const LazyImage = lazy(() => import('@/components/commons/LazyImage'));
+
+...
)}
+```
+
+**똑똑한 이벤트 핸들러**
+`useCallback`을 사용해 `isSelected` 같은 상태가 변경될 때만 `onClick` 함수를 새로 만들도록 해서 렌더링 성능을 아낄 수 있어요.
+
+-----
+
+## 🧩 새로운 기능 추가하기 (확장성)
+
+PostEditor의 노드 시스템은 새로운 기능을 붙이기에 아주 좋은 구조예요. 만약 '비디오' 노드를 추가하고 싶다면 어떻게 해야 할까요?
+
+1. 비디오 정보를 담을 `VideoNode` 클래스를 만들고,
+2. 화면에 보여줄 `VideoPlayer` React 컴포넌트를 만들고,
+3. `VideoNode`의 `decorate` 메서드가 `VideoPlayer`를 반환하게 연결해주면 끝\!
+
+여기에 "비디오 추가" 커맨드와 그 커맨드를 처리하는 플러그인까지 만들면 새로운 기능을 완벽하게 추가할 수 있죠.
+
+-----
+
+## 👍👎 노드 시스템의 장단점
+
+### ✅ 좋은 점
+
+1. **안전성**: 타입스크립트 덕분에 타입 관련 버그가 거의 없어요.
+2. **체계성**: 모든 콘텐츠가 정해진 구조를 가져서 데이터를 다루기 편해요.
+3. **데이터 관리**: DB에 저장하고 불러오기가 아주 깔끔해요.
+4. **확장성**: 비디오, 투표, 지도 등 새로운 기능을 추가하기 쉬워요.
+5. **성능**: 똑똑한 렌더링 덕분에 긴 글에서도 빠릿빠릿해요.
+
+### ⚠️ 아쉬운 점
+
+1. **배워야 할 게 좀 있어요**: Lexical의 노드 시스템에 익숙해지는 데 시간이 필요해요.
+2. **코드가 길어져요**: 간단한 기능 하나를 추가하려 해도 여러 파일을 만들어야 해서 코드가 복잡해 보일 수 있어요.
+3. **디버깅**: 눈에 보이는 HTML과 실제 데이터 구조(노드 트리)가 달라서 디버깅이 조금 더 까다로울 수 있어요.
+
+-----
+
+## 마무리하며
+
+PostEditor의 노드 시스템은 처음엔 복잡해 보일 수 있지만, 그 구조를 이해하고 나면 **안정적이고 확장성 높은 에디터**를 만드는 데 이보다 더 좋은 방법은 없다는 걸 알게 됩니다.
+
+- **불변성**으로 데이터 흐름을 예측 가능하게 만들고,
+- 데이터(**Node**)와 화면(**Component**)의 **역할을 명확히 분리**해서 코드를 깔끔하게 유지하고,
+- **최적화 기법**들을 녹여내어 좋은 성능을 보장하죠.
+
+이런 탄탄한 설계 덕분에 PostEditor는 앞으로 더 복잡하고 다양한 기능들을 안정적으로 품을 수 있는 훌륭한 기반을 갖추게 되었습니다.
\ No newline at end of file
diff --git a/.docs/editor/PostEditor Plugins.md b/.docs/editor/PostEditor Plugins.md
new file mode 100644
index 00000000..0aa8e3ba
--- /dev/null
+++ b/.docs/editor/PostEditor Plugins.md
@@ -0,0 +1,387 @@
+
+-----
+
+# PostEditor 플러그인 탐험기 🗺️
+
+## 시작하며
+
+PostEditor가 글꼴을 바꾸고, 이미지를 끌어다 놓고, 마크다운을 뿅 하고 변환하는 등 마법 같은 일들을 해내는 비결은 무엇일까요? 바로 **플러그인(Plugin) 시스템** 덕분입니다.
+
+PostEditor는 12개의 전문 플러그인들이 레고 블록처럼 각자 맡은 역할을 수행하고, 서로 유기적으로 협력해서 만들어진 결과물이에요. 이번 문서에서는 에디터의 핵심 기능을 담당하는 플러그인들이 각각 어떤 역할을 하고, 내부적으로 어떻게 똑똑하게 작동하는지 함께 탐험해 보겠습니다.
+
+-----
+
+## 목차
+
+- [플러그인은 어떻게 작동할까? (아키텍처)](https://www.google.com/search?q=%23%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%91%EB%8F%99%ED%95%A0%EA%B9%8C-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98)
+- [핵심 플러그인 톺아보기](https://www.google.com/search?q=%23%ED%95%B5%EC%8B%AC-%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0)
+ - [1. ToolbarPlugin: 에디터의 얼굴](https://www.google.com/search?q=%231-toolbarplugin-%EC%97%90%EB%94%94%ED%84%B0%EC%9D%98-%EC%96%BC%EA%B5%B4)
+ - [2. CodeActionPlugin: 개발자를 위한 작은 배려](https://www.google.com/search?q=%232-codeactionplugin-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%EC%9E%91%EC%9D%80-%EB%B0%B0%EB%A0%A4)
+ - [3. FloatingLinkEditorPlugin: 똑똑한 링크 편집기](https://www.google.com/search?q=%233-floatinglinkeditorplugin-%EB%98%91%EB%98%91%ED%95%9C-%EB%A7%81%ED%81%AC-%ED%8E%B8%EC%A7%91%EA%B8%B0)
+ - [4. ImagePlugin: 이미지 삽입의 해결사](https://www.google.com/search?q=%234-imageplugin-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%82%BD%EC%9E%85%EC%9D%98-%ED%95%B4%EA%B2%B0%EC%82%AC)
+ - [5. DraggablePlugin: 블록을 자유롭게 이동](https://www.google.com/search?q=%235-draggableplugin-%EB%B8%94%EB%A1%9D%EC%9D%84-%EC%9E%90%EC%9C%A0%EB%A1%AD%EA%B2%8C-%EC%9D%B4%EB%8F%99)
+ - [6. ClipboardPlugin: 스마트한 복사/붙여넣기](https://www.google.com/search?q=%236-clipboardplugin-%EC%8A%A4%EB%A7%88%ED%8A%B8%ED%95%9C-%EB%B3%B5%EC%82%AC%EB%B6%99%EC%97%AC%EB%84%A3%EA%B8%B0)
+ - [7. GrabContentPlugin: 실시간 내용 전달자](https://www.google.com/search?q=%237-grabcontentplugin-%EC%8B%A4%EC%8B%9C%EA%B0%84-%EB%82%B4%EC%9A%A9-%EC%A0%84%EB%8B%AC%EC%9E%90)
+ - [8. HighlightCodePlugin: 코드를 아름답게](https://www.google.com/search?q=%238-highlightcodeplugin-%EC%BD%94%EB%93%9C%EB%A5%BC-%EC%95%84%EB%A6%84%EB%8B%B5%EA%B2%8C)
+ - [9. InitContentPlugin: 저장된 글 불러오기](https://www.google.com/search?q=%239-initcontentplugin-%EC%A0%80%EC%9E%A5%EB%90%9C-%EA%B8%80-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0)
+ - [10. MaxIndentPlugin: 들여쓰기 경찰](https://www.google.com/search?q=%2310-maxindentplugin-%EB%93%A4%EC%97%AC%EC%93%B0%EA%B8%B0-%EA%B2%BD%EC%B0%B0)
+ - [11. MarkdownShortcuts: 마크다운 마법사](https://www.google.com/search?q=%2311-markdownshortcuts-%EB%A7%88%ED%81%AC%EB%8B%A4%EC%9A%B4-%EB%A7%88%EB%B2%95%EC%82%AC)
+ - [12. Utils: 우리들의 연장통](https://www.google.com/search?q=%2312-utils-%EC%9A%B0%EB%A6%AC%EB%93%A4%EC%9D%98-%EC%97%B0%EC%9E%A5%ED%86%B5)
+- [플러그인들은 어떻게 협업할까?](https://www.google.com/search?q=%23%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8%EB%93%A4%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%98%91%EC%97%85%ED%95%A0%EA%B9%8C)
+- [빠릿한 에디터를 만드는 비결](https://www.google.com/search?q=%23%EB%B9%A0%EB%A6%BF%ED%95%9C-%EC%97%90%EB%94%94%ED%84%B0%EB%A5%BC-%EB%A7%8C%EB%93%9C%EB%8A%94-%EB%B9%84%EA%B2%B0)
+
+-----
+
+## 🤔 플러그인은 어떻게 작동할까? (아키텍처)
+
+### 중앙 소통 채널, '커맨드 시스템'
+
+플러그인들은 서로를 직접 호출하지 않아요. 대신 Lexical의 **커맨드 시스템**이라는 중앙 소통 채널을 통해 "나 이런 일 좀 해줘\!" 하고 요청(dispatch)하거나, "이런 요청이 오면 내가 처리할게\!" 하고 등록(register)하는 방식으로 동작해요. 덕분에 각 플러그인은 독립성을 유지하면서도 서로 협력할 수 있죠.
+
+```typescript
+// 이런 패턴으로 커맨드를 등록해요
+editor.registerCommand(
+ COMMAND_TYPE, // 어떤 종류의 요청인지 (예: FORMAT_TEXT_COMMAND)
+ commandHandler, // 요청이 오면 실행할 함수
+ COMMAND_PRIORITY_LEVEL // "내가 먼저 처리할래!" (우선순위)
+);
+```
+
+### 플러그인의 삶 (생명주기)
+
+대부분의 플러그인은 `useEffect`를 이용해 에디터가 처음 생길 때 필요한 기능을 등록하고, 사라질 때 깨끗하게 정리하는 간단한 구조를 가져요.
+
+```typescript
+export const MyPlugin = () => {
+ const [editor] = useLexicalComposerContext();
+
+ useEffect(() => {
+ // 1. 플러그인이 태어날 때
+ // 2. "이런 커맨드 오면 나한테 알려줘!" 하고 등록
+ const cleanup = editor.registerCommand(...);
+
+ // 3. 플러그인이 죽을 때 등록했던 걸 해제 (메모리 누수 방지!)
+ return cleanup;
+ }, [editor]);
+
+ return null; // 보통 UI는 없어요
+};
+```
+
+-----
+
+## 🚀 핵심 플러그인 톺아보기
+
+### 1\. ToolbarPlugin: 에디터의 얼굴
+
+**파일**: `ToolbarPlugin.tsx`
+**역할**: 우리 눈에 가장 잘 보이는 상단 툴바예요. 글자 스타일을 바꾸는 모든 버튼과 드롭다운의 로직을 담당하죠.
+
+#### 어떻게 작동하나요?
+
+**1. 현재 텍스트 상태 추적하기**
+유저가 드래그해서 선택한 영역의 텍스트가 굵게(bold)인지, 기울임(italic)인지 등을 실시간으로 감지해서 툴바 버튼의 활성화 상태를 바꿔줘요.
+
+```typescript
+const updateToolbarOnSelect = useCallback(() => {
+ const selection = $getSelection();
+ if ($isRangeSelection(selection)) {
+ // 선택 영역이 'bold' 포맷을 가졌는지 확인
+ setIsBold(selection.hasFormat('bold'));
+ // ... 다른 포맷들도 확인
+ }
+}, []);
+```
+
+**2. 상태 변화 감지하고 툴바 업데이트하기**
+`SELECTION_CHANGE_COMMAND`와 `registerUpdateListener`를 이용해 유저의 선택 영역이 바뀌거나 글자 내용이 바뀔 때마다 `updateToolbarOnSelect` 함수를 호출해서 툴바 UI를 최신 상태로 유지해요.
+
+```typescript
+useEffect(() => {
+ return mergeRegister(
+ // 선택 영역이 바뀔 때마다 알려줘!
+ editor.registerCommand(
+ SELECTION_CHANGE_COMMAND,
+ () => { updateToolbarOnSelect(); return false; },
+ COMMAND_PRIORITY_CRITICAL
+ ),
+ // 에디터 내용이 바뀔 때마다 알려줘!
+ editor.registerUpdateListener(...)
+ );
+}, [editor, updateToolbarOnSelect]);
+```
+
+> `useCallback`으로 함수를 감싸서 불필요한 리렌더링을 막는 건 성능을 위한 기본 센스\!
+
+**3. 텍스트 스타일 적용하기**
+유저가 '굵게' 버튼을 누르면, `FORMAT_TEXT_COMMAND`를 에디터에 보내 "선택된 영역을 굵게 만들어줘\!" 하고 요청해요.
+
+```typescript
+const formatText = (format: TextFormatType) => {
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
+};
+
+