chore: Initialize environment for new Wiki categories
- Created Index.md for Topics_Art, Topics_Biz, Topics_Blog, Topics_GD\n- Established P-Reinforce entry points for specialized knowledge domains
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# Datacollector Bridge Connection Refused Run Script Fix
|
||||
|
||||
Date: 2026-04-25 21:07:52 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
사용자가 앱 실행 후 `POST http://127.0.0.1:3002/api/check-connection net::ERR_CONNECTION_REFUSED` 오류를 확인했다.
|
||||
이는 NotebookLM 인증 실패가 아니라 MCP Bridge 서버가 실행되지 않아 브라우저가 `3002` 포트에 연결하지 못한 상태였다.
|
||||
|
||||
## Root Cause
|
||||
|
||||
실행 경로가 여러 개였고 일부 경로는 프런트엔드 Vite 서버만 실행했다.
|
||||
|
||||
- `run_mac.command`: Bridge와 Vite를 함께 실행
|
||||
- `run_app.sh`: Vite만 실행
|
||||
- `npm run dev`: Vite만 실행
|
||||
|
||||
따라서 `run_app.sh` 또는 `npm run dev`로 앱을 켜면 UI는 열리지만 `/api/check-connection` 요청을 받을 Bridge 서버가 없어 `ERR_CONNECTION_REFUSED`가 발생했다.
|
||||
|
||||
## Changes Made
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/run_app.sh`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/README.md`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/api.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
|
||||
|
||||
핵심 변경:
|
||||
|
||||
- `run_app.sh`가 Bridge 서버와 Vite 서버를 함께 실행하도록 변경
|
||||
- `run_app.sh` 시작 시 기존 `3000`, `3002` 포트 프로세스를 정리
|
||||
- 종료 시 Bridge 백그라운드 프로세스도 함께 종료하도록 trap 추가
|
||||
- README의 실행 안내를 `npm run dev` 단독에서 `./run_mac.command` 또는 `npm run start-full`로 변경
|
||||
- `src/lib/api.ts`에 `bridgeFetch()` 추가
|
||||
- Bridge 연결 실패 시 `Failed to fetch` 대신 “Bridge 서버가 실행되지 않았다”는 안내 메시지를 표시하도록 변경
|
||||
- `VITE_BRIDGE_URL`로 Bridge 주소를 override할 수 있게 함
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
npm run build
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- 브리지 문법 체크 통과
|
||||
- TypeScript 타입체크 통과
|
||||
- Vite 프로덕션 빌드 통과
|
||||
|
||||
## Operational Note
|
||||
|
||||
앞으로 앱은 아래 방식으로 실행해야 한다.
|
||||
|
||||
```bash
|
||||
./run_mac.command
|
||||
```
|
||||
|
||||
또는 수동으로 두 서버를 같이 실행한다.
|
||||
|
||||
```bash
|
||||
npm run start-full
|
||||
```
|
||||
|
||||
`npm run dev`만 실행하면 프런트엔드만 뜨므로 NotebookLM, Wiki save, 인증 복구 API가 동작하지 않는다.
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
# Datacollector Codebase Structure Review and Initial Risk Assessment
|
||||
|
||||
Date: 2026-04-25 20:38:01 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
Knowledge Vault: `/Volumes/Data/project/Antigravity/Wiki/00_Raw`
|
||||
|
||||
## Summary
|
||||
|
||||
이 문서는 Datacollector 프로젝트의 첫 구조 파악 및 초기 코드 리뷰 결과를 정리한 기록이다.
|
||||
이번 검토의 목적은 이후 기능 개발 전에 현재 시스템의 책임 분리, 실행 흐름, 외부 의존성, 그리고 우선적으로 손봐야 할 위험 요소를 이해하는 데 있다.
|
||||
|
||||
현재 프로젝트는 단순한 프런트엔드 앱이 아니라, React 기반 UI와 Zustand 상태 저장소, 자율 실행 엔진, 그리고 NotebookLM MCP 및 로컬 LM을 연결하는 Express 브리지 서버가 결합된 자동화 연구 도구 형태로 구성되어 있다.
|
||||
|
||||
## High-Level Architecture
|
||||
|
||||
전체 흐름은 아래와 같다.
|
||||
|
||||
`React UI -> Zustand Store -> KnowledgeEngine -> Express Bridge -> NotebookLM MCP / Local LM / GitHub / Wiki Storage`
|
||||
|
||||
핵심 책임 분리는 다음과 같이 이해했다.
|
||||
|
||||
- `src/components/AgentDashboard.tsx`
|
||||
사용자 인터페이스, 미션 시작/중지/재개, 설정 입력, 로그 표시, 수동 커밋 등 상호작용 담당
|
||||
- `src/store/agentStore.ts`
|
||||
앱 전체 설정값과 실행 상태를 보관하는 단일 전역 상태 저장소
|
||||
- `src/lib/engine.ts`
|
||||
큐를 소비하며 연구, 합성, 링크 추출, 다음 토픽 확장을 반복하는 자율 엔진
|
||||
- `src/lib/gemini.ts`
|
||||
NotebookLM 미연결 시 사용하는 로컬 LM 프롬프트 생성 및 응답 파싱
|
||||
- `src/lib/github.ts`
|
||||
결과 Markdown을 GitHub 저장소의 `00_Raw/` 경로로 업로드
|
||||
- `scripts/mcp_bridge.mjs`
|
||||
NotebookLM MCP 서버와 통신하는 지속 프로세스형 브리지 서버
|
||||
|
||||
## Execution Flow
|
||||
|
||||
실행 흐름은 다음 순서로 이해했다.
|
||||
|
||||
1. 사용자가 `AgentDashboard`에서 주제를 입력하고 미션을 시작한다.
|
||||
2. 주제와 설정이 `agentStore`에 기록되고 상태가 `running`으로 바뀐다.
|
||||
3. `status` 변경을 감지한 UI가 `KnowledgeEngine` 싱글톤을 시작한다.
|
||||
4. `KnowledgeEngine`는 큐의 첫 항목을 읽고 현재 깊이와 루트 주제를 기준으로 처리 여부를 결정한다.
|
||||
5. NotebookLM 연결 상태가 좋으면 브리지 서버를 통해 리서치와 합성을 수행한다.
|
||||
6. NotebookLM이 없으면 로컬 LM 프록시(`/api/lm`)를 통해 대체 연구를 진행한다.
|
||||
7. 생성된 Markdown에서 위키 링크를 추출해 다음 큐를 구성한다.
|
||||
8. 결과는 pending commits, completed 목록, 로컬 위키 Raw 저장소 등에 반영된다.
|
||||
|
||||
## Current Structure Notes
|
||||
|
||||
이번 시점에서 구조적으로 눈에 띈 특징은 다음과 같다.
|
||||
|
||||
- 상태 관리가 거의 전부 Zustand store 하나에 집중되어 있어 흐름 추적은 쉽다.
|
||||
- 대신 엔진과 UI가 store를 매우 직접적으로 공유해서 결합도가 높다.
|
||||
- NotebookLM 경로와 Local LM 경로가 모두 존재해 fallback 전략은 분명하다.
|
||||
- 브리지 서버가 프런트엔드 백엔드이자 외부 도구 래퍼 역할까지 함께 맡고 있어 책임이 넓다.
|
||||
- 문서 저장 흐름이 GitHub 업로드와 로컬 위키 저장으로 이중화되어 있다.
|
||||
|
||||
## Review Findings
|
||||
|
||||
### 1. Sensitive secrets are persisted in browser storage
|
||||
|
||||
`githubToken`과 `notebookLmCookies`가 Zustand persist 설정에 포함되어 있어 브라우저 localStorage에 평문으로 저장된다.
|
||||
이 방식은 세션 쿠키나 GitHub 토큰 같은 민감 정보의 저장 위치로는 안전하지 않다.
|
||||
|
||||
관련 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
|
||||
|
||||
영향:
|
||||
|
||||
- 같은 브라우저 프로필을 사용하는 다른 코드나 도구가 정보에 접근할 수 있다.
|
||||
- 장기적으로 토큰 유출 위험이 커진다.
|
||||
|
||||
### 2. Bridge server is exposed too broadly
|
||||
|
||||
브리지 서버는 `0.0.0.0:3002`로 열리고 CORS도 전부 허용한다.
|
||||
또한 `/api/lm`은 클라이언트가 전달한 임의의 URL로 요청을 프록시할 수 있다.
|
||||
|
||||
관련 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
|
||||
영향:
|
||||
|
||||
- 로컬 개발용으로는 편하지만, 같은 네트워크 안에서 예상하지 않은 접근 통로가 될 수 있다.
|
||||
- 사실상 무인증 프록시처럼 동작할 여지가 있다.
|
||||
|
||||
### 3. Environment portability is weak
|
||||
|
||||
MCP 실행 파일 경로와 위키 저장 경로가 절대경로로 하드코딩되어 있다.
|
||||
|
||||
관련 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
|
||||
영향:
|
||||
|
||||
- 다른 개발자 머신, 다른 사용자 계정, 다른 운영체제에서 그대로 실행하기 어렵다.
|
||||
- 배포보다는 특정 개인 작업 환경에 강하게 종속된다.
|
||||
|
||||
### 4. Manual handoff state is not fully cleared
|
||||
|
||||
`resolveManualNext`가 store에 함수 형태로 저장되는데, `clearState()`에서 정리되지 않는다.
|
||||
수동 합성 대기 중 reset 또는 새 미션 시작이 발생하면 상태 꼬임 가능성이 있다.
|
||||
|
||||
관련 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
|
||||
|
||||
영향:
|
||||
|
||||
- 이전 미션의 대기 상태가 다음 미션에 잔존할 수 있다.
|
||||
- UI 버튼 상태와 실제 엔진 대기 상태가 어긋날 수 있다.
|
||||
|
||||
### 5. API endpoint usage is duplicated and hardcoded
|
||||
|
||||
프런트엔드에는 이미 Vite 프록시가 설정되어 있지만, UI와 엔진 코드 곳곳에서 `http://127.0.0.1:3002`를 직접 호출하고 있다.
|
||||
|
||||
관련 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/vite.config.ts`
|
||||
|
||||
영향:
|
||||
|
||||
- 포트 변경이나 배포 환경 변경 시 수정 지점이 늘어난다.
|
||||
- 런타임 경로 설정이 한 군데에서 관리되지 않는다.
|
||||
|
||||
## Validation Performed
|
||||
|
||||
이번 검토 중 아래 확인을 수행했다.
|
||||
|
||||
- 저장소 파일 구조 및 진입점 확인
|
||||
- UI, store, engine, bridge, GitHub, Local LM 계층 코드 확인
|
||||
- `npm run lint` 실행
|
||||
|
||||
검증 결과:
|
||||
|
||||
- TypeScript 타입체크는 현재 통과했다.
|
||||
|
||||
## Suggested Next Priorities
|
||||
|
||||
우선순위는 아래 순서가 적절하다.
|
||||
|
||||
1. 민감 정보 저장 방식을 localStorage 바깥으로 이동하거나 최소한 분리
|
||||
2. 브리지 서버 바인딩 범위와 CORS 정책 축소
|
||||
3. 절대경로를 환경변수 또는 설정 파일로 치환
|
||||
4. `resolveManualNext`를 포함한 미션 종료 정리 로직 강화
|
||||
5. API 베이스 URL을 단일 설정 지점으로 통합
|
||||
|
||||
## Working Agreement For Future Notes
|
||||
|
||||
사용자 요청에 따라, 앞으로 Datacollector 관련 조사/분석/리뷰 결과는 가능하면 이 지식 창고 경로에 계속 기록한다.
|
||||
|
||||
기본 원칙:
|
||||
|
||||
- 위치: `/Volumes/Data/project/Antigravity/Wiki/00_Raw`
|
||||
- 파일명: `YYYY-MM-DD-<Project>_<Topic>.md` 또는 기존 저장소 관례와 유사한 읽기 쉬운 영어 제목
|
||||
- 내용: 작업 목적, 파악한 구조, 핵심 발견사항, 다음 액션을 포함
|
||||
|
||||
## Source Files Reviewed
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/README.md`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/package.json`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/vite.config.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/main.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/App.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/gemini.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/github.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_caller.py`
|
||||
@@ -0,0 +1,74 @@
|
||||
# Datacollector Local Wiki Save Only Output Mode
|
||||
|
||||
Date: 2026-04-25 20:50:41 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
Datacollector의 생성 결과 저장 방식을 GitHub 업로드 중심에서 로컬 Wiki 저장 전용으로 정리했다.
|
||||
앞으로 앱에서 생성되는 연구 문서는 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`에 저장되고, Git 업로드는 사용자가 나중에 별도로 한 번에 처리하는 운영 방식으로 둔다.
|
||||
|
||||
## Previous Behavior
|
||||
|
||||
기존 흐름은 결과 생성 후 두 경로가 동시에 존재했다.
|
||||
|
||||
- 로컬 Wiki Raw 폴더에 자동 저장
|
||||
- `pendingCommits`에 결과를 쌓고 UI의 `BATCH COMMIT` 버튼으로 GitHub 업로드 가능
|
||||
|
||||
이 방식은 앱 안에 GitHub 토큰과 저장소 설정을 유지해야 했고, 사용자가 의도하지 않아도 Git 업로드 기능이 계속 노출되는 구조였다.
|
||||
|
||||
## New Behavior
|
||||
|
||||
새 흐름은 다음과 같다.
|
||||
|
||||
1. 연구 결과 Markdown 생성
|
||||
2. `savedReports`에 프리뷰용 로컬 캐시 저장
|
||||
3. 브리지 서버의 `/api/wiki/save`를 통해 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`에 Markdown 파일 저장
|
||||
4. GitHub 업로드 버튼이나 토큰 설정 없이 완료
|
||||
|
||||
GitHub 업로드는 앱이 수행하지 않는다.
|
||||
|
||||
## Changes Made
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/.env.example`
|
||||
|
||||
삭제 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/github.ts`
|
||||
|
||||
핵심 변경:
|
||||
|
||||
- `githubToken`, `githubRepoUrl` 상태 제거
|
||||
- `pendingCommits` 제거
|
||||
- `addPendingCommit`, `clearPendingCommits` 제거
|
||||
- `savedReports`와 `addSavedReport` 추가
|
||||
- `BATCH COMMIT` 버튼 제거
|
||||
- 설정 모달의 GitHub Wiki Sync 섹션 제거
|
||||
- `.env.example`의 GitHub 설정 제거
|
||||
- 생성 결과는 기존 Wiki 저장 API를 통해 로컬 Raw 폴더에만 저장
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
npm run build
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- TypeScript 타입체크 통과
|
||||
- Vite 프로덕션 빌드 통과
|
||||
|
||||
## Notes
|
||||
|
||||
로컬 Wiki 저장은 기존 브리지 서버의 `/api/wiki/save` 라우트를 그대로 사용한다.
|
||||
저장 대상 경로는 현재 브리지 서버에 하드코딩된 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`이다.
|
||||
추후 이 경로도 `.env` 설정으로 분리하면 다른 머신이나 폴더 구조에서도 더 쉽게 운영할 수 있다.
|
||||
@@ -0,0 +1,50 @@
|
||||
# Datacollector Mac Windows Launcher Scripts
|
||||
|
||||
Date: 2026-04-25 21:09:42 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
Datacollector 실행 시 Vite 프런트엔드만 뜨고 MCP Bridge 서버가 뜨지 않아 `ERR_CONNECTION_REFUSED`가 발생할 수 있었다.
|
||||
이를 막기 위해 맥용과 윈도우용 실행 파일을 명확히 정리했다.
|
||||
|
||||
## Main Launchers
|
||||
|
||||
- macOS: `/Volumes/Data/project/Antigravity/Datacollector/run_mac.command`
|
||||
- Windows: `/Volumes/Data/project/Antigravity/Datacollector/run_win.bat`
|
||||
|
||||
두 실행 파일 모두 아래를 수행한다.
|
||||
|
||||
1. 프로젝트 폴더로 이동
|
||||
2. `node_modules`가 없으면 `npm install`
|
||||
3. 기존 `3000`, `3002` 포트 프로세스 정리
|
||||
4. MCP Bridge 서버 실행
|
||||
5. Vite 앱 실행
|
||||
|
||||
## Compatibility Wrappers
|
||||
|
||||
기존 실행 파일과의 호환성을 위해 아래 파일은 메인 실행 파일로 위임하도록 단순화했다.
|
||||
|
||||
- `run_app.sh` -> `run_mac.command`
|
||||
- `run_app.bat` -> `run_win.bat`
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
bash -n run_mac.command
|
||||
bash -n run_app.sh
|
||||
npm run lint
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- macOS shell script 문법 통과
|
||||
- TypeScript 타입체크 통과
|
||||
|
||||
## Operational Note
|
||||
|
||||
앞으로 맥에서는 `run_mac.command`, 윈도우에서는 `run_win.bat`만 실행하면 된다.
|
||||
`npm run dev` 단독 실행은 프런트엔드만 켜므로 NotebookLM, Wiki save, 인증 복구 API가 동작하지 않는다.
|
||||
@@ -0,0 +1,68 @@
|
||||
# Datacollector - NotebookLM 인증 브라우저 유지 및 오래된 .env 쿠키 우선순위 문제 해결
|
||||
|
||||
- 작성 시각: 2026-04-25 21:31:00 KST
|
||||
- 프로젝트: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
- 관련 파일: `scripts/mcp_bridge.mjs`, `auth_mac.command`, `auth_win.bat`, `.env.example`
|
||||
|
||||
## 상황
|
||||
|
||||
앱에서 `/api/check-connection` 호출이 500으로 실패했고, 화면에는 다음과 같은 메시지가 반복되었다.
|
||||
|
||||
- `Authentication expired`
|
||||
- `인증 자동 복구 실패. 브라우저 로그인이 필요한 상태일 수 있습니다.`
|
||||
- `MCP initialized: true, pending: 0`
|
||||
|
||||
사용자는 NotebookLM 인증 중 Chrome이 열렸다가 닫히는 점을 보고, 인증 브라우저를 유지해야 하는 것 아니냐고 질문했다.
|
||||
|
||||
## 확인한 내용
|
||||
|
||||
`notebooklm-mcp-auth` 소스 확인 결과, 기본 자동 실행 모드는 인증 후 자신이 띄운 Chrome 프로세스를 종료한다. 반면 `--no-auto-launch --port ... --user-data-dir ...` 모드는 이미 떠 있는 Chrome 디버깅 세션에 붙기 때문에 인증 브라우저를 유지할 수 있다.
|
||||
|
||||
브리지에서 Chrome을 유지하도록 바꾼 뒤 인증 CLI는 성공했다. 하지만 MCP 서버의 `notebook_list`는 여전히 `Authentication expired`를 반환했다.
|
||||
|
||||
추가 확인 결과, `.env`에 예전 `NOTEBOOKLM_COOKIES` 값이 남아 있었다. `scripts/mcp_bridge.mjs`가 `dotenv/config`를 로드한 뒤 MCP 서버를 자식 프로세스로 실행하면서 이 오래된 환경변수 쿠키가 `~/.notebooklm-mcp/auth.json`의 최신 인증 캐시보다 우선 적용되고 있었다.
|
||||
|
||||
즉 실제 핵심 원인은 다음 조합이었다.
|
||||
|
||||
- 인증 CLI는 최신 쿠키를 `~/.notebooklm-mcp/auth.json`에 정상 저장함.
|
||||
- 브리지는 `.env`의 오래된 `NOTEBOOKLM_COOKIES`를 MCP 자식 프로세스에 전달함.
|
||||
- MCP 서버는 캐시 파일보다 환경변수를 우선 사용함.
|
||||
- 결과적으로 새 인증 후에도 MCP는 계속 오래된 쿠키로 NotebookLM API를 호출함.
|
||||
|
||||
## 조치
|
||||
|
||||
`scripts/mcp_bridge.mjs`에서 기본적으로 MCP 자식 프로세스와 인증 CLI 자식 프로세스에 `NOTEBOOKLM_COOKIES`, `NOTEBOOKLM_CSRF_TOKEN`, `NOTEBOOKLM_SESSION_ID`를 넘기지 않도록 수정했다.
|
||||
|
||||
명시적으로 환경변수 인증을 사용해야 할 경우에는 `.env`에 아래 값을 둔다.
|
||||
|
||||
```env
|
||||
USE_NOTEBOOKLM_ENV_AUTH="true"
|
||||
```
|
||||
|
||||
기본값은 `false`이며, 이 경우 `notebooklm-mcp-auth`가 생성한 `~/.notebooklm-mcp/auth.json` 캐시를 우선 사용한다.
|
||||
|
||||
또한 `auth_mac.command`, `auth_win.bat`는 별도 Chrome 프로필과 디버깅 포트를 사용해 NotebookLM 인증 브라우저를 열어두는 방식으로 변경했다.
|
||||
|
||||
## 검증
|
||||
|
||||
다음 검증을 완료했다.
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
curl -sS -X POST http://127.0.0.1:3002/api/check-connection
|
||||
```
|
||||
|
||||
결과:
|
||||
|
||||
```json
|
||||
{"success":true,"count":0}
|
||||
```
|
||||
|
||||
직접 Python MCP 클라이언트로도 같은 인증 캐시를 사용해 `list_notebooks` 호출이 성공했고, 노트북 89개를 읽는 것을 확인했다.
|
||||
|
||||
## 운영 메모
|
||||
|
||||
앞으로는 `.env`에 오래된 `NOTEBOOKLM_COOKIES`가 남아 있어도 기본 브리지 실행에는 영향을 주지 않는다. 다만 혼란을 줄이려면 장기적으로 `.env`에서 `NOTEBOOKLM_COOKIES` 줄을 삭제하거나 주석 처리하는 것이 좋다.
|
||||
|
||||
NotebookLM 인증용 Chrome 창은 닫지 않는 것이 좋다. 인증이 풀렸을 때 브리지가 같은 디버깅 포트의 Chrome 세션에 붙어 자동 복구를 시도할 수 있다.
|
||||
@@ -0,0 +1,85 @@
|
||||
# Datacollector NotebookLM Automatic Auth Recovery
|
||||
|
||||
Date: 2026-04-25 20:47:05 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
컴퓨터 포맷 이후 NotebookLM MCP 인증이 자주 실패하고, 20-30분마다 `auth_mac.command`를 수동 실행해야 하는 문제가 있었다.
|
||||
이번 작업에서는 인증 만료 시 브리지 서버가 자동으로 복구를 시도하도록 개선했다.
|
||||
|
||||
## Root Cause Hypothesis
|
||||
|
||||
기존 구조는 MCP 서버의 `refresh_auth` 도구 호출에만 의존했다.
|
||||
하지만 포맷 이후 로컬 토큰 저장 위치나 Chrome 세션 상태가 달라지면서 `refresh_auth`만으로 복구되지 않는 상황이 발생할 수 있다.
|
||||
|
||||
사용자가 직접 실행하던 파일은 다음 명령의 래퍼였다.
|
||||
|
||||
```bash
|
||||
/Users/g1nation_mac/.local/bin/notebooklm-mcp-auth
|
||||
```
|
||||
|
||||
따라서 자동 복구 흐름에도 이 CLI 인증 명령을 포함시키는 것이 가장 직접적인 개선 방향이다.
|
||||
|
||||
## Changes Made
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/.env.example`
|
||||
|
||||
핵심 변경:
|
||||
|
||||
- 브리지 서버가 `.env`를 읽도록 `dotenv/config`를 추가했다.
|
||||
- `AUTH_PATH`, `AUTH_ARGS`, `AUTH_TIMEOUT_MS`, `AUTH_REFRESH_INTERVAL_MS` 설정을 추가했다.
|
||||
- MCP 인증 에러 발생 시 `refresh_auth`를 먼저 시도한다.
|
||||
- `refresh_auth` 실패 시 MCP 프로세스를 재시작하고 다시 갱신을 시도한다.
|
||||
- 그래도 실패하면 `notebooklm-mcp-auth` CLI를 브리지 서버가 직접 실행한다.
|
||||
- CLI 인증 후 MCP 프로세스를 재시작해 새 토큰을 읽게 만든다.
|
||||
- 장시간 실행 중에는 15분 간격으로 요청이 없는 시점에 인증 상태를 사전 갱신한다.
|
||||
- UI 안내 문구를 수동 재인증 중심에서 자동 복구 중심으로 수정했다.
|
||||
|
||||
## Runtime Behavior
|
||||
|
||||
새 인증 복구 순서:
|
||||
|
||||
1. NotebookLM MCP 요청 실패
|
||||
2. 에러 메시지가 인증 관련인지 판단
|
||||
3. `refresh_auth` 호출
|
||||
4. MCP 프로세스 재시작 후 `refresh_auth` 재시도
|
||||
5. `notebooklm-mcp-auth` CLI 자동 실행
|
||||
6. MCP 프로세스 재시작
|
||||
7. 원래 실패했던 NotebookLM 요청 재시도
|
||||
|
||||
주기적 갱신:
|
||||
|
||||
- 기본 간격: 15분
|
||||
- 설정값: `AUTH_REFRESH_INTERVAL_MS=900000`
|
||||
- 진행 중인 MCP 요청이 있을 때는 건드리지 않고 건너뛴다.
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
npm run bridge
|
||||
curl -s http://127.0.0.1:3002/api/health
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- `node --check` 통과
|
||||
- TypeScript 타입체크 통과
|
||||
- 브리지 서버 시작 성공
|
||||
- MCP 서버 초기화 성공
|
||||
- `/api/health`에서 `connected: true`, `version: 3.3.0`, `authPath` 확인
|
||||
|
||||
## Notes
|
||||
|
||||
완전히 백그라운드 인증이 가능한지는 Google/Chrome 세션 상태에 의존한다.
|
||||
브라우저 로그인이 만료되어 실제 사용자 로그인이 필요한 상태라면 자동 CLI 실행도 브라우저 로그인을 요구할 수 있다.
|
||||
다만 기존처럼 매번 사용자가 batch 파일을 직접 실행하는 흐름보다, 일반적인 토큰 만료와 MCP refresh 실패 상황은 브리지 서버가 먼저 복구하도록 개선되었다.
|
||||
@@ -0,0 +1,84 @@
|
||||
# Datacollector NotebookLM Connection Guard and MCP Restart Fix
|
||||
|
||||
Date: 2026-04-25 21:02:35 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
실행 중 NotebookLM 연결 체크가 500 에러를 반환한 뒤에도 미션이 계속 시작되어 Local LM fallback으로 넘어가고, 결국 `Local LM returned an empty or invalid response` 에러가 발생했다.
|
||||
또한 브리지의 MCP 재시작 로직에서 자동 재시작과 수동 재시작이 겹쳐 여러 `notebooklm-mcp` 프로세스가 남는 문제가 확인되었다.
|
||||
|
||||
## Observed Errors
|
||||
|
||||
브라우저 콘솔:
|
||||
|
||||
```text
|
||||
:3000/favicon.ico 404 (Not Found)
|
||||
127.0.0.1:3002/api/check-connection 500 (Internal Server Error)
|
||||
```
|
||||
|
||||
앱 로그:
|
||||
|
||||
```text
|
||||
NotebookLM 연결 실패: 인증 자동 복구 실패...
|
||||
GENERAL MODE
|
||||
ENGINE ERROR Local LM returned an empty or invalid response.
|
||||
```
|
||||
|
||||
## Root Causes
|
||||
|
||||
1. `testNotebookLmConnection()`이 성공 여부를 반환하지 않았다.
|
||||
2. `handleStart`, `handleResume`, `handleGlobalResume`이 연결 실패 후에도 그대로 `running` 상태로 넘어갔다.
|
||||
3. `restart()`가 MCP 프로세스 종료 이벤트를 기다리지 않고 바로 새 프로세스를 띄울 수 있었다.
|
||||
4. `close` 이벤트의 자동 재시작이 수동 재시작과 겹쳐 MCP 하위 프로세스가 누적될 수 있었다.
|
||||
5. favicon 파일이 없어서 브라우저가 `/favicon.ico` 기본 요청을 404로 표시했다.
|
||||
|
||||
## Changes Made
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/index.html`
|
||||
|
||||
추가 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/public/favicon.svg`
|
||||
|
||||
핵심 변경:
|
||||
|
||||
- `testNotebookLmConnection()`이 `Promise<boolean>`을 반환하도록 변경
|
||||
- NotebookLM 연결 실패 시 신규 미션 시작, 개별 재개, 전체 재개를 보류
|
||||
- 연결 실패 후 Local LM fallback으로 자동 진행되는 흐름 차단
|
||||
- MCP 프로세스를 종료할 때 `close` 이벤트를 기다리는 `_stopCurrentProcess()` 추가
|
||||
- 재시작 중 자동 재시작이 중복 실행되지 않도록 제어
|
||||
- 재시작 테스트 후 MCP 하위 프로세스가 하나만 남는지 확인
|
||||
- SVG favicon 추가 및 `index.html`에 명시
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
npm run build
|
||||
npm run bridge
|
||||
curl -s http://127.0.0.1:3002/api/health
|
||||
curl -s -X POST http://127.0.0.1:3002/api/restart
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- 브리지 문법 체크 통과
|
||||
- TypeScript 타입체크 통과
|
||||
- Vite 빌드 통과
|
||||
- 브리지 시작 성공
|
||||
- `/api/health` 응답 정상
|
||||
- `/api/restart` 후 `notebooklm-mcp` 프로세스가 하나만 남는 것 확인
|
||||
|
||||
## Operational Note
|
||||
|
||||
현재 실행 중이던 오래된 브리지와 누적된 MCP 하위 프로세스는 종료했다.
|
||||
앱은 다시 실행해야 새 브리지 로직이 적용된다.
|
||||
@@ -0,0 +1,70 @@
|
||||
# Datacollector NotebookLM Progress Visibility and Auth Diagnosis
|
||||
|
||||
Date: 2026-04-25 21:17:24 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
사용자가 UI에서 `NotebookLM 연결 상태 점검 중...` 로그만 반복되고 실제 진행 상황을 알 수 없다고 보고했다.
|
||||
확인 결과 앱이 프로젝트 생성 단계까지 가지 못하고 있었으며, 원인은 NotebookLM 연결 확인 단계에서 MCP 인증이 만료 상태로 판단되기 때문이었다.
|
||||
|
||||
## Observed State
|
||||
|
||||
확인한 상태:
|
||||
|
||||
- Vite 서버 `3000` 실행 중
|
||||
- MCP Bridge 서버 `3002` 실행 중
|
||||
- `notebooklm-mcp` 프로세스 실행 중
|
||||
- `/api/health` 응답 가능
|
||||
- `/api/check-connection`은 NotebookLM 인증 만료 오류 반환
|
||||
|
||||
브리지 로그상 자동 인증 CLI는 Chrome을 열고 로그인 및 토큰 추출까지 수행했다.
|
||||
그러나 MCP 서버는 이후에도 `Authentication expired`로 판단하여 NotebookLM notebook list 호출에 실패했다.
|
||||
|
||||
## Changes Made
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
|
||||
핵심 변경:
|
||||
|
||||
- MCP 초기화 타임아웃 추가: `MCP_INIT_TIMEOUT_MS`
|
||||
- NotebookLM 연결 확인 타임아웃 추가: `MCP_HEALTH_TIMEOUT_MS`
|
||||
- `/api/health`에 상세 상태 추가
|
||||
- `initialized`, `processRunning`, `processPid`, `pendingRequests`, `authStatus` 노출
|
||||
- 인증 CLI 진행 단계(`starting`, `running`, `restarting`, `success`, `failed`) 추적
|
||||
- UI 연결 점검 중 5초마다 Bridge/MCP/auth 진행 상태 로그 출력
|
||||
- 중복 연결 점검 요청은 기존 Promise를 재사용하도록 변경
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
npm run build
|
||||
curl -sS --max-time 5 http://127.0.0.1:3002/api/health
|
||||
curl -sS --max-time 25 -X POST -H 'Content-Type: application/json' -d '{}' http://127.0.0.1:3002/api/check-connection
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- 브리지 문법 체크 통과
|
||||
- TypeScript 타입체크 통과
|
||||
- Vite 빌드 통과
|
||||
- Bridge/MCP 프로세스는 실행됨
|
||||
- NotebookLM 연결 확인은 인증 만료 오류로 실패
|
||||
|
||||
## Current Diagnosis
|
||||
|
||||
현재 문제는 앱 실행이나 Bridge 연결 문제가 아니라 NotebookLM MCP 인증 상태 문제다.
|
||||
자동 인증 CLI가 토큰을 저장해도 MCP 서버가 계속 만료로 판단하므로, 다음 단계에서는 NotebookLM MCP 패키지의 인증 저장 형식 또는 권장 인증 방식(`--file` 모드 등)을 확인해야 한다.
|
||||
|
||||
## Operational Note
|
||||
|
||||
확인용으로 실행했던 Bridge/Vite/MCP 프로세스는 종료했다.
|
||||
새 진행 상태 로그를 보려면 앱을 `run_mac.command`로 다시 실행해야 한다.
|
||||
@@ -0,0 +1,25 @@
|
||||
# [[Automatic Batching]]
|
||||
|
||||
## 📌 Brief 시 Summary
|
||||
Automatic Batching(자동 배칭)은 React 18에 도입된 기능으로, 여러 상태(State) 업데이트를 하나의 리렌더링으로 그룹화하여 처리하는 성능 최적화 기법입니다 [1-3]. 이전 버전에서는 React의 네이티브 이벤트 핸들러 내의 업데이트만 배칭되었으나, React 18부터는 프로미스(Promise), setTimeout, 비동기 작업 등 출처와 무관하게 모든 상태 업데이트를 자동으로 배칭합니다 [2, 4-6]. 이를 통해 불필요한 리렌더링과 Virtual DOM의 비교 연산(diffing)을 최소화하여 애플리케이션의 성능과 UI 응답성을 크게 향상시킵니다 [4, 7].
|
||||
|
||||
## 📖 Core Content
|
||||
* **작동 원리 및 도입 배경:**
|
||||
React 18 이전에는 `onClick`과 같은 React 내부 이벤트 핸들러에서 발생하는 상태 업데이트만 배칭 처리가 되었습니다 [2, 6]. 따라서 `setTimeout`이나 비동기 API 호출 내에서 상태를 여러 번 업데이트할 경우, 각 업데이트마다 개별적인 리렌더링이 발생하여 성능 저하의 원인이 되었습니다 [2, 8]. React 18의 자동 배칭 기능은 이벤트 출처와 상관없이 모든 상태 업데이트를 하나로 묶어(Batch) 단 한 번의 렌더링과 DOM 업데이트만 트리거합니다 [3, 7, 9, 10].
|
||||
|
||||
* **렌더링 성능 최적화 효과 ("React가 빠른 이유"):**
|
||||
자동 배칭은 여러 상태 변경이 짧은 시간 안에 연속적으로 발생할 때 불필요한 리렌더링의 수를 줄여줍니다 [10, 11]. 리렌더링 횟수가 감소하면 Virtual DOM의 비교 연산(Diffing)과 CPU 작업량이 최소화됩니다 [1, 4]. 실제로 데이터 집약적인 대시보드 환경에서 자동 배칭을 적용한 결과, 전체 렌더링 횟수가 약 40% 감소하고 피크 로드 시 프레임 속도가 25% 향상되는 등 눈에 띄는 성능 개선을 보여주었습니다 [1, 12]. 이는 "Reflow"와 "Repaint"를 유발하는 브라우저의 DOM 조작 빈도를 줄이는 핵심적인 최적화 원리 중 하나입니다 [7].
|
||||
|
||||
* **자동 배칭 제어 및 예외 처리 (Opt-Out):**
|
||||
개발자가 의도적으로 자동 배칭을 우회하고 상태 업데이트 즉시 DOM에 반영해야 하는 상황이 존재할 수 있습니다. 예를 들어, 사용자의 폼 입력에 즉각적인 피드백을 주거나 렌더링 직후 DOM 요소의 크기를 측정해야 하는 경우입니다 [13]. 이때는 React DOM에서 제공하는 `flushSync` API를 사용하여 강제로 즉각적인 동기적 리렌더링을 발생시킬 수 있습니다 [12-15]. 반대로, 긴급하지 않은 대규모 업데이트(예: 리스트 필터링)의 경우 `startTransition`을 사용하여 우선순위를 낮추고 UI 차단을 방지할 수 있습니다 [12, 13].
|
||||
|
||||
* **주의사항 및 디버깅:**
|
||||
자동 배칭은 기본적으로 제공되는 최적화지만, 일부 서드파티 상태 관리 도구나 UI 라이브러리가 React의 이벤트 시스템을 우회하는 방식으로 동작할 경우 배칭이 제대로 적용되지 않을 수 있습니다 [16, 17]. 이러한 예외 상황을 식별하기 위해서는 React DevTools Profiler를 사용하여 컴포넌트의 렌더링 횟수와 업데이트 트리거를 모니터링하는 것이 권장됩니다 [16].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Virtual DOM]], [[React가 빠른 이유]], [[Reflow / Repaint 최소화 방법]]
|
||||
- **Projects/Contexts:** [[React 18]], [[Performance Optimization]]
|
||||
- **Contradictions/Notes:** 자동 배칭은 성능을 크게 향상시키지만 무조건적으로 유용한 것은 아닙니다. 폼의 입력 값 업데이트나 요소 포커싱처럼 사용자에게 지연 없는 즉각적 피드백을 제공해야 하는 필수적인 상황에서는 `flushSync`를 사용해 배칭을 해제해야 하며, 이를 남용할 경우 배칭으로 얻는 성능 이점을 상쇄할 수 있으므로 주의해야 합니다 [13, 18]. 또한 서드파티 라이브러리 통합 시 React 이벤트 시스템을 우회하면 자동 배칭이 무력화될 수 있다는 함정이 존재합니다 [17].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,20 @@
|
||||
# [[Critical Rendering Path]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Critical Rendering Path (CRP)는 브라우저가 HTML, CSS, JavaScript를 수신하여 화면의 픽셀로 변환하기 위해 거치는 일련의 단계적 과정을 의미합니다[1]. 이 과정은 DOM 트리 및 CSSOM 트리 구축, Render Tree 합성, Layout(Reflow), 그리고 Paint(Repaint) 및 Compositing 단계로 진행됩니다[1, 2]. CRP를 이해하고 최적화하는 것은 렌더링 차단 요소를 줄이고 불필요한 Reflow 및 Repaint를 최소화하여 빠른 초기 렌더링과 매끄러운 사용자 상호작용을 보장하는 프론트엔드 성능 엔지니어링의 핵심입니다[3, 4].
|
||||
|
||||
## 📖 Core Content
|
||||
* **DOM (Document Object Model) 구축:** 브라우저는 서버로부터 HTML 데이터를 점진적으로 파싱하여 DOM 트리를 구축합니다[2, 5]. 수신된 바이트는 토큰 및 노드로 변환되어 계층 구조를 형성하며, 노드의 수가 많을수록 이후 렌더링 경로의 연산 시간이 길어집니다[2, 5, 6].
|
||||
* **CSSOM (CSS Object Model) 구축:** DOM과 달리 CSSOM 구축은 점진적으로 이루어지지 않으며, 파싱이 완료될 때까지 렌더링을 차단(Render-blocking)합니다[6-8]. 이는 스타일이 뒤늦게 덮어씌워지면서 스타일이 적용되지 않은 콘텐츠가 화면에 번쩍이는 현상(FOUC)을 방지하기 위함입니다[6, 7].
|
||||
* **Render Tree 합성:** DOM과 CSSOM이 완성되면, 브라우저는 이 둘을 결합해 화면에 실제로 그려지는 가시적 노드(Visible nodes)만 포함하는 Render Tree를 만듭니다[9-11]. `<script>`, `<meta>` 요소나 `display: none` 스타일이 적용된 노드는 렌더 트리에서 완전히 제외되지만, 레이아웃 공간을 차지하는 `visibility: hidden` 요소는 포함됩니다[9-12].
|
||||
* **Layout (Reflow):** Render Tree를 기반으로 뷰포트 크기와 박스 모델에 맞춰 각 요소의 정확한 기하학적 위치와 크기를 계산하는 단계입니다[13-15]. 창 크기가 변하거나, DOM 요소의 추가/제거, 혹은 너비나 여백 등 레이아웃에 영향을 주는 속성이 변경될 경우 Reflow가 발생하며 이는 매우 큰 연산 비용을 수반합니다[16-19].
|
||||
* **Paint (Repaint) 및 Compositing:** Layout 계산이 끝나면 각 요소를 픽셀로 화면에 그리는 Paint(또는 Rasterizing) 과정이 진행됩니다[20-23]. 레이아웃 변화 없이 배경색 등 시각적 속성만 변할 때는 Repaint만 촉발됩니다[18, 20, 24]. 이후 서로 다른 레이어들을 하나의 화면으로 합치는 Compositing 단계를 거치며, 특정 효과(예: transform)는 GPU로 오프로드하여 성능을 최적화할 수 있습니다[20, 25].
|
||||
* **React 도입과의 연관성:** 전통적으로 브라우저의 DOM을 직접 조작하는 것은 필연적으로 비용이 큰 Reflow와 Repaint 과정을 연쇄적으로 유발하여 속도 저하를 일으킵니다[26]. React는 이 한계를 극복하기 위해 메모리에 경량화된 Virtual DOM을 구축하고, 상태 변경 시 휴리스틱 Diffing 알고리즘(Reconciliation)을 통해 변경된 최소한의 노드만 실제 DOM에 반영하여 렌더링 경로의 비효율을 크게 줄입니다[3, 26, 27].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[브라우저 렌더링 과정 (HTML → CSSOM → Render Tree)]], [[Reflow / Repaint 최소화 방법]], [[DOM vs Virtual DOM]]
|
||||
- **Projects/Contexts:** [[렌더링 최적화 개념 설명 자료]], [[“React가 빠른 이유”]]
|
||||
- **Contradictions/Notes:** CSS 선택자(Selector)의 복잡도는 파싱 속도에 영향을 주지만, 최신 브라우저 엔진은 매우 빠르기 때문에 선택자 구체성을 최적화해서 얻는 성능적 이득은 마이크로초 단위에 불과합니다. 따라서 실질적인 최적화를 위해서는 선택자 구조 개선보다는 불필요한 렌더링 차단 리소스 크기를 줄이거나 로딩 순서를 제어하는 것이 성능 개선(CRP 최적화)에 훨씬 효과적입니다[28, 29].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,36 @@
|
||||
# [[DOM vs Virtual DOM]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
DOM(문서 객체 모델)은 브라우저가 HTML을 파싱하여 생성하는 트리 구조로, 직접적인 DOM 조작은 렌더링 경로(레이아웃 및 페인트)를 매번 트리거하여 성능 저하를 유발합니다 [1, 2]. 반면 Virtual DOM(가상 DOM)은 React가 수동적인 DOM 조작의 비효율성을 해결하기 위해 도입한 개념으로, UI의 이상적인 상태를 메모리에 가벼운 JavaScript 객체 형태로 저장하는 방식입니다 [2-4]. React는 새로운 Virtual DOM과 이전 버전을 비교(Diffing)하여 실제 변경된 부분만 실제 DOM에 반영(Reconciliation)함으로써 브라우저의 리플로우와 리페인트를 최소화하고 렌더링 성능을 최적화합니다 [3-5].
|
||||
|
||||
## 📖 Core Content
|
||||
* **DOM(Document Object Model)의 특성과 한계**
|
||||
* 브라우저는 수신된 HTML 바이트를 문자, 토큰, 노드로 변환하여 점진적으로 DOM 트리를 구축합니다 [1].
|
||||
* DOM은 페이지의 구조와 콘텐츠를 나타내며, 노드 수가 많고 트리의 깊이가 깊을수록 브라우저의 레이아웃(Reflow) 및 페인트(Repaint) 등 중요 렌더링 경로(Critical Rendering Path) 작업에 걸리는 연산 부담이 증가합니다 [6, 7].
|
||||
* 웹 애플리케이션에서 DOM을 직접 수정하는 작업은 본질적으로 느립니다 [2]. DOM의 변경은 레이아웃과 페인트 단계를 트리거하며, 여러 노드를 개별적으로 업데이트할 경우 중복된 재계산을 유발하기 때문입니다 [2].
|
||||
|
||||
* **Virtual DOM의 개념 및 도입 목적**
|
||||
* 수동적인 DOM 조작이 가진 비효율성을 추상화하기 위해 React에서 도입한 아키텍처가 Virtual DOM입니다 [2].
|
||||
* 이는 UI를 메모리 내에 가벼운 JavaScript 객체 형태로 유지하는 표현 방식입니다 [2, 3].
|
||||
* 개발자가 UI의 이상적인 상태를 선언적으로 정의하면, React(ReactDOM 등)가 실제 DOM을 해당 상태와 일치하도록 알아서 동기화하므로, 개발자는 속성 조작이나 이벤트 처리, 수동적인 DOM 업데이트 등을 직접 처리할 필요가 없습니다 [4].
|
||||
* Virtual DOM 트리는 설계상 불변(immutable) 객체로 취급됩니다 [8].
|
||||
|
||||
* **재조정(Reconciliation)과 Diffing 알고리즘**
|
||||
* 상태나 속성(props)이 업데이트되면 React는 새로운 Virtual DOM 트리를 생성하고, 이를 이전 버전의 트리와 비교(Diffing)하여 실제 DOM을 가장 효율적으로 업데이트할 방법을 결정합니다 [2, 3, 9]. 이 동기화 과정을 재조정(Reconciliation)이라고 합니다 [3, 4].
|
||||
* 두 트리를 비교하는 일반적인 알고리즘은 $O(n^3)$의 복잡도를 가져, 요소가 많아질 경우 실시간 연산에 부적합할 만큼 비용이 큽니다 [9-11].
|
||||
* 대신 React는 두 가지 가정을 기반으로 $O(n)$ 복잡도의 휴리스틱 Diffing 알고리즘을 사용합니다 [10, 11].
|
||||
1. 서로 다른 타입의 요소는 전혀 다른 트리를 생성한다고 가정하여 기존 트리를 허물고 완전히 새로 구축합니다 [10-12].
|
||||
2. 개발자가 제공하는 `key` 속성을 통해 여러 렌더링에 걸쳐 안정적으로 유지되는 자식 요소가 무엇인지 식별합니다 [10, 11].
|
||||
* 이러한 접근 방식을 통해 React는 변경된 특정 속성이나 노드만을 수정하고, 기본 DOM 노드와 상태를 가능한 한 보존하여 효율성을 높입니다 [13-15].
|
||||
|
||||
* **성능 최적화 관점 (React가 빠른 이유)**
|
||||
* Virtual DOM은 일시적인 프레젠테이션 상태를 지속적인 애플리케이션 상태와 분리하고 변경되지 않은 프레젠테이션 상태를 보존함으로써, 브라우저의 무거운 DOM 연산을 줄이고 UI 렌더링 성능을 개선합니다 [3].
|
||||
* 그러나 Virtual DOM의 Diffing 작업 자체가 연산 비용이 전혀 없는 것은 아닙니다 [16]. Virtual DOM은 실제 DOM이 업데이트될 필요가 없는 경우는 잘 잡아내지만, 부모 컴포넌트의 상태 변경으로 인해 하위 컴포넌트 전체가 재렌더링되는 폭포수 현상(Re-Render Cascade)이 발생하면 불필요한 Diffing 연산이 낭비될 수 있습니다 [16, 17]. 이를 최소화하려면 `React.memo` 등을 통해 선택적으로 리렌더링을 차단하는 최적화가 병행되어야 합니다 [16].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Critical Rendering Path]], [[Reflow and Repaint]], [[Reconciliation]], [[React Fiber Architecture]]
|
||||
- **Projects/Contexts:** [[프론트엔드 기초 구조 이해]], [[브라우저 렌더링 과정 (HTML → CSSOM → Render Tree)]], [[“React가 빠른 이유” 및 렌더링 최적화 개념]]
|
||||
- **Contradictions/Notes:** Virtual DOM이 수동 DOM 조작 비용을 크게 줄여주어 React의 빠른 성능을 보장하지만, 소스에 따르면 "Virtual DOM의 Diffing 작업 자체가 무료는 아니며(not free), 무분별한 리렌더링 폭포수(Re-Render Cascade)가 발생할 경우 연산 낭비와 성능 저하의 주원인이 될 수 있다"고 경고합니다 [16]. 따라서 완벽한 성능을 위해서는 Virtual DOM에만 의존하지 않고 메모이제이션(Memoization)을 통한 컴포넌트 최적화가 필요합니다 [16].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,25 @@
|
||||
# [[Hydration]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Hydration은 서버에서 생성된 정적 HTML을 클라이언트에서 JavaScript를 통해 완전히 상호작용 가능한 애플리케이션으로 변환하는 과정입니다 [1]. 브라우저가 서버로부터 미리 렌더링된 HTML을 받아 화면에 표시한 후, 다운로드한 JavaScript 번들을 실행하여 이벤트 리스너를 연결하고 상태(state)를 동기화합니다 [2, 3]. 이 과정을 거쳐야만 사용자가 정적인 뼈대(Skeleton) 화면을 넘어 버튼 클릭이나 폼 입력 등의 동적 상호작용을 수행할 수 있게 됩니다 [1, 4].
|
||||
|
||||
## 📖 Core Content
|
||||
* **Hydration의 작동 원리 및 역할:**
|
||||
SSR(Server-Side Rendering) 환경에서 서버는 데이터가 포함된 완전한 HTML을 브라우저로 전송합니다 [2]. 브라우저는 이를 즉시 화면에 렌더링하여 사용자에게 보여주지만(빠른 콘텐츠 표시), JavaScript 번들이 다운로드, 파싱 및 Hydration 되기 전까지는 페이지가 상호작용하지 않습니다 [2, 5]. 즉, Hydration은 서버가 제공한 건조한(Dehydrated) HTML 컴포넌트에 생명을 불어넣어 반응형으로 만드는 필수 단계입니다 [1, 6].
|
||||
* **성능에 미치는 부정적 영향:**
|
||||
기본적으로 React는 화면에 보이지 않는 요소까지 포함하여 전체 페이지를 한 번에 Hydration 하려고 시도합니다 [7]. 이로 인해 불필요한 JavaScript 실행이 발생하여 메인 스레드(Main Thread)가 차단되고, 결과적으로 TBT(Total Blocking Time), FID(First Input Delay), TTI(Time to Interactive)와 같은 핵심 성능 지표가 악화될 수 있습니다 [7, 8]. 시각적 요소는 렌더링되었으나 클릭해도 반응하지 않는 지연 현상이 발생하여 사용자 경험(UX)에 악영향을 미치기도 합니다 [5, 7].
|
||||
* **주요 문제 및 발생 원인:**
|
||||
* **Hydration 에러 (Mismatch):** 서버에서 렌더링된 HTML과 클라이언트 렌더링 결과가 일치하지 않을 때 발생합니다. 주로 환경 조건에 따른 렌더링 차이, 시간 의존적 데이터 변화, 서드파티 라이브러리의 DOM 조작 등이 원인입니다 [9].
|
||||
* **번들 크기 비대화:** Hydration을 위해서는 모든 컴포넌트의 JavaScript 코드가 필요하므로, 번들 크기가 커져 다운로드 및 실행 오버헤드가 증가합니다 [10].
|
||||
* **Hydration 최적화 전략:**
|
||||
* **선택적 및 점진적 Hydration (Selective & Progressive Hydration):** `next/dynamic`과 같은 동적 임포트를 사용하여 중요하지 않은 컴포넌트의 Hydration을 지연시키고 화면 위쪽(Above-the-fold) 콘텐츠를 우선 처리합니다 [10, 11]. React 18의 동시성 렌더링(Concurrent Rendering)은 사용자가 상호작용하는 부분을 우선적으로 Hydration 할 수 있도록 지원합니다 [12].
|
||||
* **뷰포트 기반 지연 (Lazy Hydration):** `IntersectionObserver` API 등을 활용하여 컴포넌트가 화면에 보일 때만 Hydration을 수행함으로써 초기 TBT를 대폭 줄입니다 [11].
|
||||
* **React Server Components (RSC) 도입:** 서버 컴포넌트는 오직 서버에서만 실행되며 클라이언트로 JavaScript를 전송하지 않습니다. 따라서 상호작용이 필요 없는 정적 UI의 경우 Hydration 과정 자체가 필요 없어 번들 크기 및 실행 오버헤드를 근본적으로 제거할 수 있습니다 [13, 14].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Server-Side Rendering (SSR)]], [[React Server Components (RSC)]], [[Time to Interactive (TTI)]], [[Total Blocking Time (TBT)]]
|
||||
- **Projects/Contexts:** [[Next.js 렌더링 최적화]], [[React 18 동시성 렌더링 (Concurrent Rendering)]]
|
||||
- **Contradictions/Notes:** SSR은 초기 콘텐츠를 즉시 렌더링하여 SEO와 FCP(First Contentful Paint)를 향상시키는 장점이 있지만, Hydration 완료 전까지 페이지 조작이 불가능하여 TTI가 지연된다는 뚜렷한 트레이드오프가 존재합니다 [5, 15, 16]. 그러나 React Server Components(RSC)나 선택적 Hydration 기법을 활용하면 인터랙티브한 부분에만 클라이언트 코드를 적용할 수 있어 이러한 SSR의 한계를 상쇄할 수 있습니다 [12, 17].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,29 @@
|
||||
# [[React Fiber]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
React Fiber는 React 16에서 도입된 새로운 재조정(Reconciliation) 엔진이자 아키텍처로, 동시성 렌더링(Concurrent Rendering)을 지원하기 위해 개발되었습니다 [1, 2]. 기존의 동기적이고 중단 불가능한 렌더링 방식의 한계를 극복하기 위해 렌더링 작업을 '작은 작업 단위(Fiber node)'로 분할하여 처리합니다 [1, 3, 4]. 이를 통해 메인 스레드를 차단하지 않고 작업의 우선순위를 유연하게 관리하며 렌더링을 일시 중지하거나 재개할 수 있어, 사용자 상호작용에 빠르고 부드럽게 반응하는 UI를 구축할 수 있습니다 [3, 5, 6].
|
||||
|
||||
## 📖 Core Content
|
||||
* **파이버 노드(Fiber Node)와 작업 루프(Work Loop):**
|
||||
React는 컴포넌트 트리의 각 요소를 파이버 노드로 표현하며, 이는 곧 수행해야 할 개별 '작업 단위(Unit of Work)'가 됩니다 [4, 7]. 파이버 재조정자는 이 작업 단위들을 순차적으로 처리하는 작업 루프를 통해 작동합니다 [4, 8]. 하나의 작업을 처리한 후 남은 프레임 시간을 확인하여, 시간이 부족하거나 고우선순위 작업(예: 사용자 입력)이 대기 중일 경우 브라우저에 제어권을 양보(yield)하여 UI가 멈추는 것을 방지합니다 [5, 9].
|
||||
|
||||
* **두 가지 렌더링 단계(Reconciliation Phases):**
|
||||
React의 재조정 과정은 작업의 중단 및 우선순위 지정을 가능하게 하기 위해 두 가지 페이즈로 나뉩니다 [10].
|
||||
* **렌더 페이즈(Render Phase):** 중단, 취소, 재개가 가능한 비동기적 단계입니다 [10, 11]. 기존 상태와 새로운 상태의 차이를 계산하고 부수 효과(Effect)를 가진 파이버 노드들의 목록을 구성하지만, 이 단계에서는 실제 DOM을 변경하지 않습니다 [10, 11].
|
||||
* **커밋 페이즈(Commit Phase):** 동기적이고 중단할 수 없는 단계입니다 [11, 12]. 렌더 페이즈에서 도출된 모든 DOM 조작(삽입, 삭제, 업데이트 등)을 실제 DOM에 한 번에 반영합니다 [12, 13].
|
||||
|
||||
* **시간 분할(Time-Slicing)과 레인(Lane) 기반 우선순위 모델:**
|
||||
* 파이버는 시간 분할 기능을 활성화하여 무거운 렌더링 작업을 작은 덩어리로 쪼개고, 렌더링 중간에 브라우저가 다른 중요한 작업을 처리할 수 있게 합니다 [3, 6, 9].
|
||||
* 작업의 우선순위를 32비트 정수를 활용한 '레인(Lane)' 모델로 체계적으로 관리합니다 [14, 15]. 타이핑이나 클릭 같은 사용자 입력은 즉시(Sync) 처리되는 가장 높은 우선순위를 갖고, 데이터 페칭 결과나 화면 밖의 렌더링은 상대적으로 낮은 우선순위(Default, Idle)를 갖게 됩니다 [14, 16].
|
||||
* 이러한 우선순위 분배를 통해 `useTransition`이나 `useDeferredValue` 같은 동시성 렌더링 훅이 UI의 반응성을 유지하면서 무거운 연산을 지연시킬 수 있도록 지원합니다 [17].
|
||||
|
||||
* **WIP(Work-In-Progress) 트리 관리:**
|
||||
React는 현재 진행 중인 렌더링 작업(WIP)을 조건에 따라 일시 중지(Pause), 재개(Resume), 혹은 폐기(Discard)할 수 있습니다 [18]. 메인 스레드가 바쁘거나 더 높은 우선순위의 업데이트가 들어오면 현재 작업을 멈추어 두었다가, 유휴 시간이 생기면 다시 재개하여 컴퓨팅 자원을 효율적으로 사용합니다 [18].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Concurrent Rendering]], [[Reconciliation]], [[Virtual DOM]], [[Critical Rendering Path]]
|
||||
- **Projects/Contexts:** [[브라우저 렌더링 과정 최적화 및 UI 반응성 개선]]
|
||||
- **Contradictions/Notes:** React Fiber 아키텍처 이전의 React는 "스택 재조정자(Stack Reconciler)"를 사용하여 컴포넌트 트리를 단일 재귀 호출로 처리했기 때문에, 애플리케이션의 크기가 커질 경우 메인 스레드가 차단(Blocking)되어 사용자 입력이나 애니메이션이 끊기는 고질적인 문제가 존재했습니다. Fiber는 이를 작업 단위 분할로 해결했습니다 [1, 3].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1 @@
|
||||
{"status":"success","answer":"","conversation_id":"7169ba9e-c01c-4675-ab7b-2786649ef6b8"}
|
||||
@@ -0,0 +1,29 @@
|
||||
# [[Reconciliation]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Reconciliation(재조정)은 React가 메모리에 유지되는 가상 DOM(Virtual DOM)과 브라우저의 실제 DOM을 동기화하여 UI를 가장 효율적으로 업데이트하는 과정입니다 [1, 2]. React는 요소의 타입과 `key` 속성에 기반한 $O(n)$ 복잡도의 휴리스틱 Diffing(비교) 알고리즘을 사용하여 전통적인 트리 비교 알고리즘의 비효율성을 극복합니다 [1, 3]. 이를 통해 DOM에 대한 불필요한 수정과 브라우저의 리플로우(Reflow)/리페인트(Repaint)를 최소화하며, "React가 빠른 이유"를 설명하는 핵심적인 메커니즘입니다 [3, 4].
|
||||
|
||||
## 📖 Core Content
|
||||
|
||||
* **가상 DOM(Virtual DOM)과 재조정의 필요성**:
|
||||
브라우저의 DOM을 직접 수정하는 작업은 Critical Rendering Path 상의 레이아웃(Reflow)과 페인트 단계를 트리거하므로 본질적으로 성능 비용이 높습니다 [4, 5]. React는 개발자가 선언적으로 UI 상태를 묘사하면 내부적으로 가벼운 가상 DOM 트리를 구축하고, 상태나 props 변경 시 이전 트리와 새로운 트리를 비교(Diff)하여 변경된 최소한의 부분만 실제 DOM에 반영(Patch)합니다 [2, 4, 5].
|
||||
|
||||
* **휴리스틱 Diffing 알고리즘 ($O(n)$ 최적화)**:
|
||||
두 트리를 완벽하게 비교하는 일반적인 알고리즘은 $O(n^3)$의 시간 복잡도를 가져 대규모 렌더링에 사용할 수 없습니다(1,000개 요소 비교 시 약 10억 번의 연산 필요) [1, 3]. 따라서 React는 다음 두 가지 강력한 가정을 통해 이를 $O(n)$으로 최적화했습니다 [3, 6]:
|
||||
1. **서로 다른 타입의 엘리먼트는 완전히 다른 트리를 생성한다**: 루트 엘리먼트의 태그나 컴포넌트 타입이 변경될 경우(예: `<a>` → `<img>` 또는 `<Article>` → `<Comment>`), React는 기존 트리를 완전히 파괴(Unmount)하고 새로운 DOM 노드를 처음부터 구축합니다 [6, 7].
|
||||
2. **`key` prop을 통한 자식 요소 안정성 보장**: 리스트의 순서가 바뀌거나 맨 앞에 새 엘리먼트가 추가될 때, 자식을 순차적으로 비교하면 모든 요소를 변경하는 비효율이 발생합니다 [8, 9]. 대신 고유한 `key`를 제공하면 원래 트리의 자식과 새로운 트리의 자식을 매칭하여, 불필요한 재생성 없이 요소들의 위치만 효율적으로 이동시킵니다 [6, 9, 10].
|
||||
|
||||
* **동일한 타입의 엘리먼트 및 컴포넌트 처리**:
|
||||
동일한 DOM 태그를 비교할 때는 기본 DOM 노드를 유지하고 `className`이나 `style` 등 변경된 속성 정보만 부분적으로 업데이트합니다 [11, 12]. 사용자 정의 컴포넌트 역시 타입이 같다면 컴포넌트 인스턴스와 상태(State)가 유지되며, 변경된 props만 전달받은 뒤 `render()` 함수를 재실행하여 하위 트리에 대해 재조정을 반복 수행합니다 [8, 12].
|
||||
|
||||
* **Fiber 아키텍처를 통한 스케줄링 및 동시성 렌더링**:
|
||||
과거 React의 재조정은 트리 전체를 한 번에 동기식으로 처리(Stack Reconciler)하여 메인 스레드를 장시간 차단하는 문제가 있었습니다 [13]. React 16부터는 이 엔진을 **Fiber 아키텍처**로 재작성하여 렌더링 작업을 작고 중단 가능한 단위(Fiber nodes)로 나누었습니다 [13-15].
|
||||
재조정 과정은 순수하고 중단 및 재시작이 가능한 **렌더 단계(Render Phase)**와 계산된 DOM 변경 사항(Effect list)을 동기적으로 한 번에 적용하는 **커밋 단계(Commit Phase)**로 분리됩니다 [16-18]. 이를 통해 우선순위(Lanes)에 따라 사용자 입력 같은 긴급한 업데이트가 무거운 렌더링 작업을 중단하고 먼저 처리될 수 있습니다 [19-21].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Virtual DOM]], [[Fiber Architecture]], [[Diffing Algorithm]], [[Reflow / Repaint]]
|
||||
- **Projects/Contexts:** [[React 성능 최적화]] (불필요한 DOM 노드 재생성을 막아 브라우저 렌더링 파이프라인의 오버헤드를 줄이는 프론트엔드 최적화 단계)
|
||||
- **Contradictions/Notes:** React의 재조정 알고리즘은 휴리스틱에 의존하므로, `key`에 배열의 인덱스를 사용하거나 `Math.random()`처럼 매번 변경되는 불안정한 값을 사용하면 안 됩니다. 이 경우 요소의 순서가 변경될 때 내부 상태가 엉키거나 불필요한 DOM 노드가 대량으로 다시 생성되어 성능 저하를 초래합니다 [22, 23].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,28 @@
|
||||
# [[Reflow / Repaint 최소화 방법]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Reflow(Layout)와 Repaint(Paint)는 브라우저 렌더링 과정에서 요소의 크기, 위치를 계산하고 시각적 요소를 화면에 그리는 비용이 높은 작업입니다. 브라우저의 렌더링 최적화를 달성하고 매끄러운 사용자 경험(예: 60fps 유지)을 제공하기 위해서는 DOM 트리의 깊이 감소, 상태 변경의 일괄 처리, 하드웨어 가속 등을 통해 이 과정이 발생하는 빈도와 연산량을 최소화해야 합니다.
|
||||
|
||||
## 📖 Core Content
|
||||
**DOM 구조 및 CSS 규칙 최적화**
|
||||
* 불필요한 DOM 트리의 깊이를 줄여야 합니다. DOM 트리의 특정 노드가 변경되면 루트부터 하위 노드까지 계산이 파급되어 Reflow에 소요되는 시간이 길어집니다 [1]. React의 경우, 불필요한 래퍼(wrapper) 대신 Fragment를 사용하여 DOM 노드 수를 줄이면 브라우저의 레이아웃과 페인트 속도를 개선할 수 있습니다 [2, 3].
|
||||
* 사용하지 않는 CSS 규칙을 최소화하고, 특히 하위 선택자(descendant selectors)와 같이 CPU 연산력을 더 많이 요구하는 복잡한 CSS 선택자의 사용을 피하는 것이 좋습니다 [1]. `display: none`을 사용하면 요소가 Render Tree에서 완전히 제거되어 레이아웃에서 배제되므로, 렌더링을 억제할 때 유용하게 활용할 수 있습니다 [4].
|
||||
|
||||
**DOM 접근 및 수정의 일괄 처리 (Batching)**
|
||||
* 요소의 크기나 위치 등을 계산하는 속성을 반복적으로 읽고 쓰는 작업을 교차로 실행하면 "레이아웃 스래싱(Layout Thrashing)"이라는 비효율적인 Reflow가 발생합니다 [5].
|
||||
* 이를 방지하기 위해서는 DOM 값을 읽는 단계와 수정하는 단계를 명확히 분리하여 렌더링 엔진의 작업을 일괄 처리(batch)해야 합니다 [6, 7].
|
||||
* 루프 내부에서 DOM을 조작하는 것을 피하고, 접근해야 하는 DOM 노드나 속성값을 변수에 캐싱(Caching)하여 불필요하게 DOM 구조에 반복적으로 접근하는 것을 최소화해야 합니다 [6, 8].
|
||||
|
||||
**애니메이션 최적화 및 하드웨어 가속(GPU) 활용**
|
||||
* 박스 모델의 속성(`width`, `height`, `margin`, `top`, `left` 등)을 직접적으로 애니메이션 처리하는 것은 피해야 합니다 [9, 10].
|
||||
* 대신 시각적 변화나 애니메이션 처리를 할 때 CSS의 `transform` 속성(예: `transform: translate()`)이나 `opacity`를 사용하면 브라우저가 새로운 Reflow나 Repaint 주기를 유발하지 않고 GPU를 통해 해당 요소를 자체 레이어에서 처리할 수 있습니다 [11-14].
|
||||
* 복잡한 렌더링 변경이나 애니메이션을 수행할 때는 `position: absolute` 또는 `position: fixed`를 적용하여 해당 요소를 문서의 일반적인 흐름(flow)에서 분리시켜 다른 요소에 미치는 Reflow 영향을 최소화해야 합니다 [1].
|
||||
* JavaScript로 애니메이션을 동기화해야 하는 경우 `window.requestAnimationFrame`을 사용하여 브라우저가 동시 애니메이션을 단일 Reflow 및 Repaint 주기로 통합 최적화할 수 있도록 지원해야 합니다 [13, 15].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[브라우저 렌더링 과정 (HTML → CSSOM → Render Tree)]], [[Virtual DOM]], [[렌더링 최적화 개념 설명 자료]]
|
||||
- **Projects/Contexts:** [[React 기반 프론트엔드 성능 최적화]], [[단일 페이지 애플리케이션(SPA) UI 성능 관리]]
|
||||
- **Contradictions/Notes:** 복잡한 CSS 선택자를 피하는 것은 성능 향상에 도움이 되지만, 소스에 따르면 매우 구체적인 CSS 규칙 최적화로 얻는 렌더링 속도 개선은 마이크로초 단위로 미미한 경우가 많습니다 [16]. 따라서 개발자는 직관적인 CSS 최적화에 매몰되기보다는 반드시 측정 도구를 통해 가장 느린 병목 현상(Reflow/Repaint가 잦은 곳)을 찾아 우선순위를 두고 최적화해야 합니다 [16, 17].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1 @@
|
||||
{"status":"success","answer":"","conversation_id":"65683a4c-14a1-4a03-b043-9aee964a292f"}
|
||||
@@ -0,0 +1 @@
|
||||
{"status":"success","answer":"","conversation_id":"fd149a47-bca0-4e71-a17a-f69d677b2958"}
|
||||
@@ -0,0 +1 @@
|
||||
{"status":"success","answer":"","conversation_id":"e1f5e242-69b1-4c49-8f3d-af31c15be109"}
|
||||
@@ -0,0 +1,24 @@
|
||||
# [[Virtual DOM]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Virtual DOM(VDOM)은 메모리에 유지되는 가볍고 이상적인 UI의 표현(보통 React 엘리먼트 형태의 단순한 JavaScript 객체)을 의미합니다 [1-3]. React와 같은 라이브러리에 의해 실제 DOM과 동기화되며, 이 과정을 '재조정(Reconciliation)'이라고 부릅니다 [1-3]. 이는 개발자가 수동으로 DOM을 업데이트하고 속성을 조작하는 비효율성을 추상화하여, 선언적인 UI 개발을 가능하게 하는 핵심 프로그래밍 개념입니다 [1, 3].
|
||||
|
||||
## 📖 Core Content
|
||||
* **DOM 조작의 비효율성 해결:**
|
||||
실제 브라우저의 DOM을 직접 수정하는 작업은 본질적으로 느립니다. DOM 변경은 브라우저의 중요 렌더링 경로(Critical Rendering Path)에 있는 레이아웃(Reflow)과 페인트(Repaint) 단계를 반복적으로 트리거하기 때문입니다 [1]. 복잡한 애플리케이션에서 여러 노드를 개별적으로 업데이트하면 과도한 재계산이 발생하게 됩니다 [1]. Virtual DOM은 실제 DOM이 업데이트될 필요가 없는 경우를 걸러내어, 이러한 무거운 렌더링 과정을 최소화함으로써 브라우저 렌더링을 최적화합니다 [1, 4].
|
||||
* **재조정(Reconciliation)과 Diffing 알고리즘:**
|
||||
상태가 변경되면 React는 메모리상에서 이전 버전의 Virtual DOM과 새로운 Virtual DOM을 비교(diff)하여 변경 사항을 감지합니다 [2, 5]. 두 트리를 비교하는 일반적인 알고리즘은 $O(n^3)$의 복잡도를 가지지만, React는 엘리먼트의 타입이 다르면 트리를 새로 구축하고 자식 요소들은 `key` 속성을 통해 식별한다는 두 가지 가정을 기반으로 $O(n)$ 복잡도의 휴리스틱(heuristic) 알고리즘을 사용합니다 [6-8]. 이를 통해 실제 DOM을 업데이트하는 데 필요한 최소한의 연산만 수행합니다 [1].
|
||||
* **Virtual DOM의 범위와 구현체:**
|
||||
React 세계에서 Virtual DOM은 주로 UI를 나타내는 'React 엘리먼트' 객체를 지칭하지만, React 16부터 도입된 새로운 재조정 엔진이자 컴포넌트 트리에 대한 추가 정보를 담고 있는 내부 객체인 '파이버(Fiber)' 역시 Virtual DOM 구현의 일부로 간주됩니다 [9, 10].
|
||||
* **Shadow DOM과의 차이점:**
|
||||
Virtual DOM은 웹 컴포넌트의 변수 및 CSS 스코핑을 위해 설계된 브라우저 기술인 Shadow DOM과 다릅니다. Virtual DOM은 브라우저 API 위에 JavaScript 라이브러리를 통해 구현된 프로그래밍 개념입니다 [9].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Reconciliation]], [[DOM]], [[Critical Rendering Path]], [[Reflow / Repaint]], [[Fiber Architecture]]
|
||||
- **Projects/Contexts:** [[React Performance Optimization]]
|
||||
- **Contradictions/Notes:**
|
||||
- Virtual DOM이 실제 DOM의 불필요한 업데이트를 방지하여 성능을 최적화하지만, 이전 Virtual DOM과 새로운 Virtual DOM을 비교하는 Diffing 작업 자체에 비용이 전혀 없는 것은 아닙니다 [4]. 무분별한 렌더링이 발생하면 이 비교 작업 자체가 컴퓨팅 오버헤드를 발생시킬 수 있습니다.
|
||||
- 구현상 Virtual DOM 트리는 설계적으로 불변성(immutable)을 띠도록 다루어집니다 [11].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,25 @@
|
||||
# [[“React가 빠른 이유”]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
React가 빠른 핵심적인 이유는 메모리 상에 가벼운 가상 DOM(Virtual DOM)을 두어, 브라우저의 무거운 렌더링 작업인 레이아웃(Reflow)과 페인트(Repaint)를 유발하는 실제 DOM 조작을 최소화하기 때문입니다 [1, 2]. 더불어 O(n) 복잡도의 휴리스틱 Diffing 알고리즘 [3], 렌더링 작업을 잘게 쪼개 우선순위를 관리하는 Fiber 아키텍처 [4, 5], 여러 상태 업데이트를 한 번에 묶어 처리하는 자동 일괄 처리(Automatic Batching) [6, 7] 등의 최적화 기술이 결합되어 불필요한 연산을 막고 애플리케이션의 반응성을 극대화합니다.
|
||||
|
||||
## 📖 Core Content
|
||||
|
||||
* **가상 DOM(Virtual DOM)과 휴리스틱 Diffing 알고리즘**
|
||||
실제 DOM을 직접 수정하는 것은 브라우저의 Critical Rendering Path(레이아웃 및 페인트)를 거쳐야 하므로 본질적으로 매우 느립니다 [1]. 이를 해결하기 위해 React는 UI 상태를 메모리에 가벼운 객체 형태로 표현하는 가상 DOM을 도입했습니다 [1, 2]. 재조정(Reconciliation) 단계에서 이전 가상 DOM과 새로운 가상 DOM을 비교할 때, React는 두 요소의 타입이 다르면 트리를 완전히 새로 구축하고, 같은 타입이면 변경된 속성만 업데이트하는 O(n) 복잡도의 휴리스틱 알고리즘을 사용합니다 [3, 8, 9]. 이를 통해 실제 DOM 노드를 최대한 보존하며 꼭 필요한 최소한의 부분만 효율적으로 업데이트합니다 [1, 10].
|
||||
* **Fiber 아키텍처와 동시성 렌더링(Concurrent Rendering)**
|
||||
초기 React의 동기적이고 차단되는(blocking) 렌더링 프로세스 한계를 극복하기 위해 도입된 Fiber 아키텍처는 렌더링 작업을 'Fiber 노드'라는 작은 단위로 쪼갭니다 [4, 5, 10]. 이 아키텍처는 렌더링을 중단 및 재개 가능한 'Render 단계'와 동기적으로 DOM을 변이하는 'Commit 단계'로 분리합니다 [11, 12]. 사용자 입력과 같은 긴급한 작업에 우선순위(Lane 모델)를 부여하여 먼저 처리할 수 있도록 제어권을 브라우저에 양보하므로, 복잡한 업데이트 중에도 UI가 멈추지 않고 매끄럽게 동작합니다 [4, 13, 14].
|
||||
* **자동 일괄 처리(Automatic Batching)**
|
||||
React 18부터 적용된 자동 일괄 처리는 이벤트 핸들러, Promise, setTimeout 등 모든 출처에서 발생하는 다수의 상태 업데이트를 단일 리렌더링으로 묶어서(Batch) 처리합니다 [6, 7, 15]. 이는 가상 DOM의 Diffing 연산 횟수를 최소화하고, CPU 작업량과 실제 DOM의 재렌더링을 크게 줄여 성능을 향상시킵니다 [16].
|
||||
* **React Compiler를 통한 렌더링 폭포(Re-render Cascade) 방지**
|
||||
부모 컴포넌트의 상태가 변할 때 props 변경 여부와 상관없이 모든 자식이 재렌더링되는 현상은 React 성능 저하의 주된 원인입니다 [17]. React 19의 컴파일러는 빌드 타임에 AST(추상 구문 트리)를 분석하여 데이터 흐름을 파악하고, 불필요한 재렌더링 및 비싼 계산을 건너뛰도록 최적의 메모이제이션(Memoization) 코드를 자동으로 삽입하여 처리 속도를 대폭 높입니다 [18-21].
|
||||
* **React Server Components (RSC)의 도입**
|
||||
무거운 렌더링 로직이나 데이터 페칭 작업을 브라우저(클라이언트)가 아닌 서버에서 독점적으로 실행하게 합니다 [22, 23]. 이를 통해 클라이언트로 전송되는 JavaScript 번들 크기를 사실상 0바이트로 줄이고, 상호작용하기까지의 시간(INP)을 획기적으로 낮춰 초기 렌더링 속도와 체감 성능을 향상시킵니다 [24-26].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Virtual DOM]], [[Reconciliation]], [[Fiber Architecture]], [[Automatic Batching]], [[React Compiler]], [[React Server Components]], [[Reflow / Repaint 최소화 방법]]
|
||||
- **Projects/Contexts:** [[브라우저 렌더링 과정 (HTML → CSSOM → Render Tree)]], [[렌더링 최적화 개념 설명 자료]]
|
||||
- **Contradictions/Notes:** 소스에 따르면 가상 DOM이 불필요한 실제 DOM 업데이트를 막아주기는 하지만, 가상 DOM 트리를 비교(Diffing)하는 연산 자체도 무료가 아닙니다 [27]. 따라서 가상 DOM 메커니즘 하나만으로 속도가 무조건 보장되는 것은 아니며, 'Automatic Batching'이나 컴포넌트의 불필요한 연산을 막는 'React Compiler(또는 수동 메모이제이션)' 같은 기술이 병행되어야 가상 DOM의 Diffing 오버헤드까지 잡아내어 진정한 속도 최적화를 이룰 수 있습니다 [16, 20, 27, 28].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,28 @@
|
||||
# [[검색 엔진 최적화(SEO) 대응 렌더링 전략 수립]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
검색 엔진 최적화(SEO) 대응 렌더링 전략은 웹 애플리케이션의 콘텐츠가 검색 엔진 크롤러에 의해 효과적으로 색인(Index)될 수 있도록 서버 및 클라이언트의 렌더링 방식을 설계하는 과정입니다. 검색 엔진 봇은 주로 초기 HTML을 수집하므로, 자바스크립트 실행 전 비어 있는 페이지를 제공하는 클라이언트 사이드 렌더링(CSR)은 SEO에 불리할 수 있습니다 [1-3]. 따라서 프로젝트의 콘텐츠 성격, 업데이트 빈도, 보안 요구사항에 맞춰 서버 사이드 렌더링(SSR), 정적 사이트 생성(SSG) 등의 방식을 적절히 혼합하여 최적의 검색 가시성과 성능을 확보하는 것이 핵심입니다 [4-7].
|
||||
|
||||
## 📖 Core Content
|
||||
* **CSR(Client-Side Rendering)의 SEO 한계**
|
||||
CSR은 서버로부터 최소한의 빈 HTML과 자바스크립트 번들을 먼저 받아 브라우저에서 동적으로 UI를 생성합니다 [1, 8-10]. 최신 검색 엔진 크롤러의 자바스크립트 처리 능력이 과거에 비해 다소 개선되었음에도 불구하고, 여전히 콘텐츠 렌더링 전에 빈 페이지만을 인식할 위험이 커서 색인이 지연되거나 누락될 수 있습니다 [1-3, 11]. 따라서 CSR은 SEO가 중요하지 않고 풍부한 상호작용이 필요한 비공개 대시보드나 SaaS 플랫폼에 주로 적합합니다 [12-14].
|
||||
|
||||
* **SSR(Server-Side Rendering)을 통한 즉각적인 콘텐츠 제공**
|
||||
SSR은 요청이 발생할 때마다 서버에서 전체 HTML을 렌더링하여 클라이언트와 크롤러에 전송합니다 [15-17]. 크롤러가 자바스크립트 실행(Hydration)을 기다리지 않고도 구조화된 콘텐츠를 즉시 수집할 수 있으므로 SEO 성능을 크게 향상시킵니다 [6, 15, 18-21]. 또한 메타 태그와 Open Graph 데이터를 온전히 제공하여 소셜 미디어 공유 시 풍부한 미리보기를 생성하는 데 유리합니다 [20, 22]. SSR은 뉴스 사이트나 전자상거래 상품 목록 등 실시간 최신 데이터를 유지하면서 높은 검색 가시성이 필요한 곳에 이상적입니다 [23-25].
|
||||
|
||||
* **SSG(Static Site Generation)와 사전 렌더링의 강점**
|
||||
SSG는 빌드 시점에 모든 페이지의 HTML을 미리 생성해 CDN을 통해 배포합니다 [26-29]. 크롤러는 대기 시간이나 서버 측 연산 없이 완벽하게 구성된 HTML을 즉시 전달받게 되므로 검색 순위와 검색 가능성이 극대화됩니다 [6, 30, 31]. 블로그, 공식 문서, 마케팅 랜딩 페이지 등 변경이 잦지 않은 정적 콘텐츠 웹사이트에 완벽한 렌더링 전략입니다 [27, 32-34].
|
||||
|
||||
* **ISR(Incremental Static Regeneration)을 이용한 균형 잡힌 성능**
|
||||
ISR은 SSG의 초고속 성능을 유지하면서 정해진 시간 간격(예: 60초)이나 필요에 따라 백그라운드에서 특정 페이지를 재생성하여 최신 상태로 업데이트합니다 [26, 35-38]. 대규모 전자상거래의 상품 카탈로그처럼 수많은 페이지에 대해 빠른 초기 로드 속도와 SEO 친화적인 정적 HTML을 제공함과 동시에 주기적인 콘텐츠 업데이트가 필요한 경우 가장 효율적으로 동작합니다 [14, 24, 39].
|
||||
|
||||
* **페이지 맞춤형 혼합(Hybrid) 렌더링 전략의 채택**
|
||||
현대적인 웹 애플리케이션 프레임워크(예: Next.js, Nuxt)를 사용하면 전체 애플리케이션에 단일 전략을 고집할 필요가 없습니다 [4, 40, 41]. 홈페이지와 문서에는 가장 빠른 SSG를, 실시간 재고나 최신 뉴스가 필요한 페이지에는 SSR을, 로그인된 사용자 전용 대시보드에는 CSR을 적용하는 방식으로 페이지별 SEO 중요도 및 동적 요구사항에 맞춰 렌더링 방식을 혼합 구성하는 것이 권장됩니다 [4, 7, 41].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** `[[CSR vs SSR vs SSG]]`, `[[Hydration]]`, `[[React Server Components]]`, `[[Critical Rendering Path]]`
|
||||
- **Projects/Contexts:** `[[대규모 이커머스 플랫폼 렌더링 설계]]`, `[[SEO 중심의 마케팅 및 블로그 사이트 구축]]`
|
||||
- **Contradictions/Notes:** 소스 [2]에서는 검색 엔진이 과거보다 자바스크립트를 크롤링하는 능력이 향상되었다고 언급하지만, 소스 [3, 11, 42] 등에서는 여전히 크롤러가 자바스크립트를 올바르게 실행하는 데 어려움을 겪거나 초기 빈 HTML만을 읽어 콘텐츠가 누락되는 치명적인 한계가 존재한다고 주장합니다. 따라서 SEO가 핵심인 서비스에서는 순수 CSR에 의존하지 않는 것이 일반적인 합의입니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,35 @@
|
||||
# [[단일 페이지 애플리케이션(SPA) 아키텍처 설계]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
단일 페이지 애플리케이션(SPA)은 서버로부터 최소한의 HTML 껍데기와 JavaScript 번들을 제공받은 후, 브라우저에서 동적으로 UI를 구성하고 렌더링하는 클라이언트 사이드 렌더링(CSR) 방식을 주로 활용하는 프론트엔드 아키텍처입니다 [1-4]. 초기 다운로드 크기가 커서 로딩이 느릴 수 있지만, 페이지가 로드된 이후에는 전체 페이지 새로고침 없이 부분적인 데이터만 업데이트하여 매끄럽고 상호작용성이 뛰어난 사용자 경험을 제공합니다 [5-8]. 현대의 SPA는 이러한 CSR의 단점을 극복하기 위해 서버 사이드 렌더링(SSR), 정적 사이트 생성(SSG), 그리고 컴포넌트 기반 아키텍처(CBA)와 같은 전략들을 혼합하여 성능과 확장성을 최적화합니다 [9, 10].
|
||||
|
||||
## 📖 Core Content
|
||||
**브라우저 렌더링 과정 (HTML → CSSOM → Render Tree)**
|
||||
브라우저의 중요 렌더링 경로(Critical Rendering Path)는 HTML을 점진적으로 파싱하여 DOM(Document Object Model) 트리를 구축하고, CSS를 파싱하여 렌더링 차단 리소스인 CSSOM(CSS Object Model)을 생성하는 것으로 시작됩니다 [11-14]. DOM과 CSSOM이 준비되면 이 둘을 결합하여 렌더 트리(Render Tree)를 형성합니다. 렌더 트리는 `<script>`나 `display: none`이 적용된 요소와 같이 화면에 보이지 않는 노드를 제외하고, 가시적인 노드와 그에 일치하는 계산된 스타일 정보만을 포함합니다 [15-18]. 이후 각 시각적 요소의 정확한 크기와 뷰포트 내 위치를 계산하는 레이아웃(Layout/Reflow) 단계를 거쳐, 픽셀을 화면에 그리는 페인트(Paint/Repaint)와 여러 레이어를 화면에 결합하는 합성(Compositing) 과정을 통해 UI가 표시됩니다 [19-23].
|
||||
|
||||
**Reflow / Repaint 최소화 방법**
|
||||
Reflow(레이아웃)는 DOM 구조가 변경되거나 창 크기 조정, 마진, 너비, 높이 등의 기하학적 속성이 변경될 때 트리의 상당 부분을 다시 계산해야 하므로 컴퓨팅 자원을 크게 소모합니다 [24-27]. Repaint는 색상이나 그림자 등 시각적 스타일만 변경될 때 발생합니다 [24, 25, 27]. 성능 최적화를 위해서는 불필요한 DOM 트리의 깊이를 줄이고, CSS 규칙을 간소화하며, DOM 업데이트를 일괄 처리(batching)해야 합니다 [28-30]. 특히 애니메이션 요소는 `top`이나 `left` 대신 `transform`과 `opacity` 속성을 사용하여, 브라우저가 요소를 독립적인 레이어로 분리하고 GPU 가속(Compositing)을 활용하게 함으로써 Reflow를 피하는 것이 핵심입니다 [20, 29-31].
|
||||
|
||||
**DOM vs Virtual DOM 및 React가 빠른 이유**
|
||||
전통적인 방식처럼 DOM을 직접 수정하면 레이아웃과 페인트 연산이 반복적으로 트리거되어 성능이 크게 저하됩니다 [32]. React는 이를 극복하기 위해 UI의 가벼운 메모리 내 표현인 가상 DOM(Virtual DOM)을 사용합니다 [32-34]. React는 컴포넌트의 상태가 변할 때마다 새로운 가상 DOM을 생성하고, 이전 상태와 비교하는 $O(n)$ 복잡도의 휴리스틱 기반 Diffing 알고리즘(Reconciliation)을 실행하여 실제 변경된 속성이나 노드만 선별적으로 실제 DOM에 패치(업데이트)합니다 [32, 33, 35-37].
|
||||
여기에 더해 React 16부터 도입된 파이버(Fiber) 아키텍처는 동시성 렌더링을 가능하게 합니다. 렌더링 작업을 중단, 재개, 혹은 폐기할 수 있는 작은 '작업 단위'로 분할하고, 사용자 입력이나 클릭과 같은 긴급한 작업을 데이터 필터링 같은 작업보다 우선 처리(우선순위 Lane 모델)하여 화면 버벅임(Jank)을 방지하고 반응성을 유지합니다 [38-44].
|
||||
|
||||
**렌더링 최적화 개념 (자동 일괄 처리 및 React Compiler)**
|
||||
최신 React는 성능 병목을 프레임워크 단에서 해결하고 있습니다. React 18의 자동 일괄 처리(Automatic Batching)는 기존 이벤트 핸들러뿐 아니라 `setTimeout`이나 `Promise` 같은 비동기 작업에서 발생하는 다수의 상태 업데이트를 하나의 리렌더링으로 묶어 DOM 렌더링 횟수를 획기적으로 줄여줍니다 [45-48]. 더 나아가, React 19에 도입된 React Compiler는 빌드 단계에서 코드를 정적 분석하여 변경되지 않는 값과 컴포넌트에 메모이제이션을 자동 삽입합니다. 이로 인해 불필요한 재렌더링(Re-render Cascade)이 제거되고 개발자가 수동으로 `useMemo`, `useCallback`, `React.memo`를 작성해야 하는 인지적 부담이 사라집니다 [49-53].
|
||||
|
||||
**CSR vs SSR vs SSG 렌더링 전략 비교**
|
||||
- **CSR (Client-Side Rendering):** 클라이언트(브라우저)에서 JavaScript를 실행해 전체 UI를 구축하고 데이터를 가져옵니다. 매우 동적인 상호작용을 지원하지만, 초기 렌더링까지 사용자가 빈 화면을 보게 되며 자바스크립트 실행이 필수적이라 검색 엔진 최적화(SEO)에 불리할 수 있습니다 [1, 2, 5, 54-57].
|
||||
- **SSR (Server-Side Rendering):** 서버가 각 요청마다 데이터가 포함된 완전한 HTML을 렌더링하여 클라이언트에게 전송합니다. SEO에 매우 유리하며 초기 콘텐츠 페인트(FCP)가 빠르지만, 사용자 인터랙션을 위해 JavaScript 번들을 다운받고 연결하는 '하이드레이션(Hydration)' 과정 동안 입력 지연(TTI 지연)이 발생할 수 있습니다 [58-63].
|
||||
- **SSG (Static Site Generation) & ISR (Incremental Static Regeneration):** 빌드 타임에 HTML을 생성하여 CDN으로 배포하는 방식으로 성능 면에서 가장 빠르나 잦은 데이터 변경에는 취약합니다(SSG). ISR은 이를 보완하여 주기적으로 정적 페이지를 백그라운드에서 재생성합니다 [64-70].
|
||||
- **React Server Components (RSC):** 컴포넌트를 서버에서만 실행하고 직렬화된 데이터만을 클라이언트에 스트리밍하여 전송하는 혁신적 모델입니다. 클라이언트 자바스크립트 번들 크기에 전혀 영향을 주지 않고 서버 리소스(DB 등)에 직접 접근할 수 있게 해, 복잡한 프론트엔드 환경에서 상호작용이 필요한 클라이언트 컴포넌트(Client Component)와 역할을 명확히 분리합니다 [71-76].
|
||||
|
||||
**컴포넌트 기반 아키텍처 (Component-Based Architecture)**
|
||||
최신의 단일 페이지 애플리케이션 설계는 시스템을 분리 가능하고 재사용 가능한 소프트웨어 조각(컴포넌트)으로 구성하는 CBA 방법론을 따릅니다 [77-79]. 각 컴포넌트는 특정한 상태와 UI 로직을 캡슐화(Encapsulation)하여 잘 정의된 인터페이스(Props 등)로 통신합니다 [77, 80]. 이 구조는 코드의 모듈성과 재사용성을 높이고 유지보수와 디버깅을 단순화하며, 여러 개발팀이 독립적으로 기능(예: 검색창, 장바구니 등)을 개발하여 빠르고 유연하게 확장할 수 있는 기반이 됩니다 [81-85].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[브라우저 렌더링 프로세스 (CRP)]], [[가상 DOM (Virtual DOM) 및 재조정(Reconciliation)]], [[React Fiber 및 동시성 렌더링]], [[서버 사이드 렌더링(SSR)과 하이드레이션(Hydration)]], [[컴포넌트 기반 아키텍처 (CBA)]]
|
||||
- **Projects/Contexts:** [[Next.js를 활용한 하이브리드 렌더링 및 React Server Components 도입]], [[React 18 자동 일괄 처리 및 React 19 컴파일러 최적화 적용]]
|
||||
- **Contradictions/Notes:** CSR 방식은 초기 로드 속도와 SEO 측면에서 불리하다는 한계가 널리 알려져 있으나, 실시간 상호작용이 많고 SEO가 중요하지 않은 인증 기반의 SaaS 대시보드나 내부 비즈니스 도구에서는 서버의 렌더링 부하를 줄이고 유연성을 높이기 때문에 여전히 SSR보다 가장 적합한 렌더링 방식으로 권장됩니다 [4, 86, 87]. 또한, React 19 컴파일러가 대부분의 수동 메모이제이션을 불필요하게 만들지만, 외부 타사 라이브러리 연동 시 참조 안정성이 깨지거나 이펙트 의존성 제어가 필요한 특정 상황에서는 여전히 `useMemo` 등을 통한 수동 제어가 필요할 수 있습니다 [88-90].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,28 @@
|
||||
# [[렌더링 최적화 개념 설명 자료]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
렌더링 최적화는 브라우저가 HTML, CSS, JavaScript를 화면의 픽셀로 변환하는 '중요 렌더링 경로(Critical Rendering Path)'를 효율적으로 수행하도록 구성하여 초기 로딩 속도와 상호작용의 반응성을 극대화하는 작업입니다 [1]. 브라우저 관점에서는 연산 비용이 큰 리플로우(Reflow)와 리페인트(Repaint)를 줄이고 GPU 하드웨어 가속을 활용하며, React 환경에서는 불필요한 리렌더링을 차단하고 렌더링 작업의 우선순위를 관리하여 메인 스레드의 부하를 최소화하는 것이 핵심입니다 [2-5].
|
||||
|
||||
## 📖 Core Content
|
||||
* **중요 렌더링 경로(CRP) 최적화:**
|
||||
브라우저는 HTML 및 CSS를 파싱하여 DOM과 CSSOM 트리를 생성하고, 이 둘을 결합해 시각적 정보만 담은 렌더 트리(Render Tree)를 구축한 후, 레이아웃과 페인트 단계를 거쳐 화면을 렌더링합니다 [1, 6, 7]. 렌더링 성능을 높이려면 렌더링을 차단하는 리소스(CSS, 동기식 JavaScript)의 다운로드를 비동기화하거나 지연시키고, 렌더 트리에 포함되는 불필요한 DOM 노드 개수와 CSS 선택자의 복잡성을 줄여 브라우저의 처리량을 최소화해야 합니다 [4, 8, 9].
|
||||
|
||||
* **리플로우(Reflow) 및 리페인트(Repaint) 최소화:**
|
||||
* **리플로우(레이아웃) 방지:** 요소의 기하학적 속성(너비, 높이, 마진 등)이 변경될 때 발생하는 리플로우는 문서 전체의 레이아웃을 다시 계산하게 만들어 연산 비용이 매우 큽니다 [10, 11]. DOM 변경은 일괄 처리(batching)하여 레이아웃 스래싱(Layout Thrashing)을 방지하고, 복잡한 애니메이션 요소는 `position: absolute` 또는 `fixed` 속성을 적용해 문서 흐름(flow)에서 분리해야 합니다 [2, 9, 12].
|
||||
* **리페인트 감소 및 하드웨어 가속:** 시각적 속성(색상, 그림자 등)만 바뀔 때는 리페인트가 발생합니다 [2, 11]. 애니메이션을 구현할 때 `transform`, `opacity` 속성을 사용하면 브라우저가 요소를 별도의 레이어로 승격시켜 CPU가 아닌 GPU에서 합성(Compositing) 작업을 처리하게 하므로, 리플로우와 리페인트를 모두 피하고 성능을 획기적으로 개선할 수 있습니다 [3, 13, 14].
|
||||
|
||||
* **DOM 조작 및 상호작용 최적화:**
|
||||
DOM에 반복적으로 접근하는 것은 처리 속도를 저하시키므로 DOM 노드나 속성값을 캐싱하여 반복문 외부에서 다루어야 합니다 [12, 15]. DOM에 노드를 반복 추가하는 대신 HTML 문자열을 일괄 교체하고, 개별 요소마다 이벤트 핸들러를 등록하는 대신 상위 노드에 이벤트를 위임하는 '이벤트 위임(Event Delegation)' 기법을 적용하여 리소스를 절약해야 합니다 [16, 17].
|
||||
|
||||
* **React 환경에서의 렌더링 최적화:**
|
||||
* **리렌더링 차단 연산:** React는 부모 컴포넌트의 상태가 변하면 하위 컴포넌트가 모두 리렌더링되는 폭포수(Cascade) 현상이 발생합니다 [18]. 이를 방지하기 위해 `React.memo`, `useMemo`, `useCallback`을 활용해 참조와 결과를 메모이제이션하여 불필요한 가상 DOM 연산을 생략합니다 [19, 20]. 인라인 객체 및 함수 생성은 참조를 새롭게 만들어 메모이제이션을 무효화하므로 피해야 합니다 [21].
|
||||
* **자동 배칭 및 동시성 렌더링:** React 18에서 기본 활성화된 자동 배칭(Automatic Batching)은 비동기 작업 및 이벤트 핸들러 내의 여러 상태 업데이트를 묶어 단일 리렌더링으로 처리해 성능을 크게 높입니다 [22, 23]. 또한 `useTransition` 및 `useDeferredValue` 훅을 사용하면 무거운 작업의 렌더링 우선순위를 낮춰, 긴급한 사용자 입력 등에 메인 스레드를 양보할 수 있습니다 [24, 25].
|
||||
* **구조적 아키텍처 개선:** 항목이 많은 리스트에는 화면에 보이는 노드만 렌더링하는 가상화(Virtualization) 기술을 적용하고 [26], 빈번하게 변경되는 전역 상태는 Context를 세분화하여 상태를 구독하는 컴포넌트의 불필요한 렌더링 범위를 축소해야 합니다 [27].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[브라우저 렌더링 과정 (HTML → CSSOM → Render Tree)]], [[DOM vs Virtual DOM]], [[CSR vs SSR vs SSG]], [[Reflow / Repaint 최소화 방법]], [[React가 빠른 이유]]
|
||||
- **Projects/Contexts:** [[컴포넌트 기반 아키텍처 개념 수집 포인트]]
|
||||
- **Contradictions/Notes:** React에서 메모이제이션(`React.memo`, `useMemo` 등)은 보편적인 해결책이 될 수 없습니다. 모든 컴포넌트를 감싸는 것은 얕은 비교를 위한 연산 비용과 메모리 오버헤드를 발생시키므로, 렌더링에 시간이 지연되는 컴포넌트(5~10ms 이상 소요)에만 프로파일링 후 선택적으로 적용해야 합니다 [28]. 또한 React 19의 React Compiler를 사용하면 수동 메모이제이션 작업의 대부분을 빌드 도구가 자동으로 대신 처리할 수 있습니다 [29].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,31 @@
|
||||
# [[브라우저 렌더링 과정 (HTML → CSSOM → Render Tree)]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
브라우저 렌더링 과정, 또는 중요 렌더링 경로(Critical Rendering Path)는 브라우저가 HTML, CSS, JavaScript 코드를 화면의 픽셀로 변환하기 위해 거치는 일련의 단계입니다 [1, 2]. 브라우저는 HTML을 파싱하여 DOM 트리를 만들고 CSS를 파싱하여 CSSOM 트리를 생성한 후, 두 트리를 결합하여 화면에 표시될 요소만 포함된 Render Tree(렌더 트리)를 구축합니다 [2, 3]. 이후 각 요소의 정확한 크기와 위치를 계산하는 Layout(레이아웃) 단계를 거쳐, 최종적으로 화면에 픽셀을 그리는 Paint(페인트) 작업을 수행하게 됩니다 [3, 4]. 이 과정을 최적화하는 것은 초기 로딩 속도를 높이고 끊김 없는 상호작용을 제공하는 프론트엔드 성능 관리의 핵심입니다 [5, 6].
|
||||
|
||||
## 📖 Core Content
|
||||
- **DOM(Document Object Model) 구축 단계**
|
||||
브라우저는 서버로부터 HTML 데이터를 수신하면 점진적(incremental) 파싱을 시작하여 바이트를 문자, 토큰, 노드로 순차적으로 변환하고 최종적으로 DOM 트리 구조를 구축합니다 [1, 7, 8]. DOM 트리는 문서의 구조와 콘텐츠를 나타내며, 파싱 과정이 점진적으로 이루어지기 때문에 브라우저는 네트워크 요청이 진행되는 중에도 트리 생성을 시작할 수 있습니다 [7, 9].
|
||||
|
||||
- **CSSOM(CSS Object Model) 구축 단계**
|
||||
DOM이 콘텐츠를 나타낸다면 CSSOM은 콘텐츠의 스타일과 규칙을 정의합니다 [9, 10]. DOM 구축과 달리 CSSOM 구축은 렌더링 차단(render-blocking) 작업입니다 [9, 10]. 브라우저는 스타일이 지정되지 않은 날 것의 HTML이 화면에 노출되는 현상(FOUC)을 방지하기 위해, 모든 링크된 스타일시트를 다운로드하고 파싱할 때까지 렌더 트리 구성을 차단합니다 [9, 10]. CSS의 계단식(Cascade) 특성 때문에 후속 규칙이 이전 규칙을 덮어쓸 수 있어 이 과정은 점진적으로 화면에 렌더링할 수 없습니다 [11, 12].
|
||||
|
||||
- **Render Tree (렌더 트리) 생성**
|
||||
DOM과 CSSOM 트리가 모두 준비되면 브라우저는 이 둘을 결합하여 렌더 트리를 만듭니다 [13, 14]. 렌더 트리는 화면에 렌더링하는 데 필요한 시각적 노드들만 포함하는 정제된 트리입니다 [3, 13]. `<script>`, `<meta>` 태그나 `display: none` 스타일이 적용된 노드는 시각적 레이아웃에 영향을 주지 않으므로 렌더 트리에서 완전히 제외됩니다 [3, 13-15]. 단, 공간을 차지하는 `visibility: hidden` 요소는 렌더 트리에 포함됩니다 [16, 17].
|
||||
|
||||
- **Layout (레이아웃 또는 Reflow)**
|
||||
렌더 트리가 완성되면 브라우저는 뷰포트 크기와 박스 모델을 기반으로 화면에 표시될 각 요소의 정확한 기하학적 위치(x, y)와 크기(너비, 높이)를 계산합니다 [18-21]. 창 크기를 조절하거나 JavaScript로 요소의 크기 및 위치를 변경하는 작업은 트리 전체에 걸친 연쇄적인 재계산을 유발할 수 있으며, 이 비용이 많이 드는 계산 과정을 보통 'Reflow(리플로우)'라고 부릅니다 [18, 19, 22].
|
||||
|
||||
- **Paint (페인트 또는 Repaint) 및 Compositing (합성)**
|
||||
레이아웃 계산이 완료되면 계산된 기하학적 구조와 스타일(색상, 그림자, 텍스트 등)을 실제 픽셀로 변환하여 그리는 Paint 단계로 넘어갑니다 [19, 23-25]. 시각적 속성만 변경되어 레이아웃 재계산 없이 화면을 다시 그리는 과정은 'Repaint(리페인트)'라고 합니다 [23, 26]. 마지막 단계인 합성(Compositing)에서는 렌더링 엔진이 개별 레이어를 단일 이미지로 결합하여 화면에 출력하며, 애니메이션 등 특정 작업은 GPU 연산을 활용하여 성능을 높일 수 있습니다 [19, 23, 27, 28].
|
||||
|
||||
- **React 아키텍처와의 연관성**
|
||||
수동으로 DOM을 직접 조작하는 것은 본질적으로 느리며 이 과정에서 불필요한 Reflow와 Repaint를 빈번하게 유발하여 화면의 버벅거림(Jank)을 초래합니다 [23, 29, 30]. React와 같은 프레임워크는 이러한 브라우저 렌더링 엔진의 구조적 한계와 비효율성을 극복하기 위해 메모리 내에 가벼운 UI 복사본인 [[Virtual DOM]]을 도입하였으며, 변경 사항을 모아 효율적으로 실제 DOM을 업데이트함으로써 렌더링 최적화를 이룹니다 [5, 29].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Virtual DOM]], [[Reflow 및 Repaint]], [[Critical Rendering Path (CRP)]]
|
||||
- **Projects/Contexts:** [[프론트엔드 성능 최적화 전략]], [[React 컴포넌트 기반 아키텍처]]
|
||||
- **Contradictions/Notes:** 소스에 따르면 HTML의 DOM 파싱은 점진적(incremental)으로 이루어지는 반면, CSSOM 구성은 스타일 덮어쓰기 문제 때문에 완료될 때까지 브라우저 화면 출력을 막는 렌더링 차단(render-blocking) 특성을 가집니다 [7, 9-11].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,30 @@
|
||||
# [[프론트엔드 성능 최적화]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
프론트엔드 성능 최적화는 브라우저의 렌더링 과정을 이해하고, 불필요한 연산을 줄여 사용자에게 빠르고 매끄러운 웹 경험을 제공하는 일련의 과정입니다 [1, 2]. 이를 위해 HTML과 CSS가 DOM과 CSSOM을 거쳐 렌더 트리로 변환되는 중요 렌더링 경로(CRP)를 관리하며, 비용이 많이 드는 Reflow와 Repaint를 최소화합니다 [3, 4]. 또한 React의 Virtual DOM 메커니즘을 활용하여 DOM 조작을 효율화하고, 프로젝트의 목적에 맞게 CSR, SSR, SSG 등의 렌더링 방식을 전략적으로 선택하여 컴포넌트 기반 아키텍처로 유지보수성이 높은 시스템을 설계하는 것을 핵심 목적으로 합니다 [1, 5, 6].
|
||||
|
||||
## 📖 Core Content
|
||||
* **브라우저 렌더링 과정 (HTML → CSSOM → Render Tree):**
|
||||
브라우저는 데이터를 점진적으로 파싱하여 HTML을 문서 객체 모델(DOM)로 생성하고, CSS를 파싱하여 CSS 객체 모델(CSSOM)로 변환합니다 [3, 7, 8]. 이 두 트리가 준비되면 화면에 실제로 표시될 노드와 계산된 스타일 정보만을 포함하는 렌더 트리(Render Tree)로 결합합니다 (`display: none` 등의 시각적으로 숨겨진 요소는 제외됩니다) [9, 10]. 이후 렌더 트리를 기반으로 각 요소의 정확한 크기와 위치를 계산하는 레이아웃(Layout 또는 Reflow) 단계를 거친 후, 계산된 기하학적 형태를 화면의 실제 픽셀로 변환하는 페인트(Paint 또는 Repaint) 단계를 수행합니다 [11-15].
|
||||
|
||||
* **Reflow / Repaint 최소화 방법:**
|
||||
Reflow(레이아웃 계산)는 브라우저 창 크기 조절이나 요소의 크기, 위치(`width`, `height`, `margin` 등)가 변경될 때 발생하며, 문서 흐름에 따라 전체 트리에 연쇄적인 재계산을 유발할 수 있어 연산 비용이 매우 높습니다 [11, 16-18]. 이를 최소화하려면 불필요한 DOM 깊이를 줄이고, 복잡한 CSS 선택자를 피해야 합니다 [19]. 특히 애니메이션과 같이 복잡한 렌더링 변경 시에는 `position: absolute`나 `fixed`를 사용하여 문서 흐름에서 요소를 분리하거나, Reflow를 유발하지 않고 GPU 가속을 활용할 수 있는 `transform` 속성을 사용하는 것이 좋습니다 [4, 12, 19, 20]. Repaint는 색상이나 그림자 등 시각적 속성만 변경될 때 발생하며 Reflow보다 부담은 적지만, 과도하게 발생 시 성능을 저하시키므로 DOM 조작과 변경 사항을 일괄 처리(batching)하는 전략이 필수적입니다 [4, 12, 16, 21].
|
||||
|
||||
* **DOM vs Virtual DOM 및 “React가 빠른 이유”:**
|
||||
실제 DOM을 직접 조작하는 것은 본질적으로 매번 레이아웃과 페인트 단계를 유발해 속도가 느립니다 [22]. React는 이를 해결하기 위해 메모리 내에 UI의 가벼운 표현인 가상 DOM(Virtual DOM)을 유지합니다 [22, 23]. 상태가 변경되면 React는 O(n) 복잡도의 휴리스틱 Diffing 알고리즘을 통해 이전 가상 트리와 새로운 가상 트리를 비교(Reconciliation)하고, 변경된 특정 속성이나 노드만을 계산해 실제 DOM에 한 번에 반영합니다 [22, 24-27]. 이처럼 불필요한 DOM 연산을 최소화하는 방식과 더불어, 렌더링 작업을 잘게 쪼개 우선순위를 매기는 Fiber 아키텍처와 상태 업데이트를 자동으로 그룹화하는 자동 일괄 처리(Automatic Batching) 기능 덕분에 React는 빠르고 반응성 높은 UI를 제공할 수 있습니다 [28-31].
|
||||
|
||||
* **CSR vs SSR vs SSG 렌더링 전략:**
|
||||
* **CSR (Client-Side Rendering):** 서버에서 빈 HTML과 JavaScript를 보내고 브라우저가 화면을 렌더링합니다 [5, 32, 33]. 대시보드나 SaaS 앱처럼 상호작용이 많을 때 유리하지만, 자바스크립트 실행 전까지 화면이 비어 있어 초기 로딩(FCP)이 느리고 SEO에 취약합니다 [5, 34-36].
|
||||
* **SSR (Server-Side Rendering):** 서버가 각 요청마다 완전한 HTML을 렌더링하여 클라이언트에 전달하므로, 초기 화면이 즉시 표시되고 검색 엔진 최적화(SEO)에 매우 유리합니다 [37-40]. 그러나 브라우저가 JavaScript를 다운로드하고 이벤트 리스너를 연결하는 Hydration 과정이 끝날 때까지는 페이지와 상호작용할 수 없는(TTI 지연) 단점이 있습니다 [37, 41-43].
|
||||
* **SSG (Static Site Generation):** 빌드 시점에 정적 HTML을 생성하고 CDN을 통해 즉각적으로 제공하는 방식입니다 [44-46]. 속도가 가장 빠르고 SEO가 뛰어나지만, 실시간 데이터가 필요한 동적 콘텐츠 페이지에는 적합하지 않습니다 [44, 47-49].
|
||||
|
||||
* **컴포넌트 기반 아키텍처 (CBA) 개념:**
|
||||
애플리케이션을 독립적이고 재사용 가능하며 캡슐화된 구성 요소(컴포넌트)로 나누어 조립하는 소프트웨어 설계 방식입니다 [50-53]. 각 컴포넌트는 자체적인 데이터와 UI 로직을 포함하며, 잘 정의된 인터페이스(API)를 통해서만 상호작용합니다 [50, 51, 54]. 이 아키텍처는 코드의 재사용성을 높여 개발 속도를 단축하고, 각 팀이 병렬로 작업할 수 있도록 모듈성을 제공하며, 특정 컴포넌트만 수정 및 교체할 수 있어 시스템의 유지보수성과 확장성을 극대화합니다 [55-59].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[중요 렌더링 경로 (Critical Rendering Path)]], [[가상 DOM과 재조정 (Reconciliation)]], [[Hydration 성능 최적화]], [[Fiber 아키텍처와 동시성 (Concurrent Rendering)]], [[단일 페이지 애플리케이션 (SPA)]]
|
||||
- **Projects/Contexts:** [[웹 프론트엔드 아키텍처 설계]], [[성능 및 SEO 최적화 프로젝트]]
|
||||
- **Contradictions/Notes:** 소스에 따르면 SSR은 서버에서 완전히 렌더링된 HTML을 제공하여 첫 화면 표시(FCP) 속도를 획기적으로 개선하지만, JavaScript 번들을 다운로드하고 하이드레이션(Hydration)이 완료되기 전까지는 사용자가 상호작용할 수 없기 때문에 TTI(Time to Interactive)는 오히려 지연될 수 있습니다. 이는 초기 콘텐츠 렌더링과 상호작용 활성화 사이의 성능 트레이드오프(Trade-off)를 의미합니다 [37, 42, 43, 60].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: index-art
|
||||
category: "[[10_Wiki/Topics_Art]]"
|
||||
last_reinforced: 2026-04-25
|
||||
---
|
||||
|
||||
# 🎨 Art & Aesthetics Knowledge Base
|
||||
|
||||
> "기술은 캔버스고, 아트는 그 위에 피어나는 영혼이다."
|
||||
|
||||
이곳은 Antigravity 프로젝트의 시각적 완결성을 책임지는 지식의 정원입니다. 그래픽, UI/UX 에셋, 디자인 시스템 및 미학적 원칙들이 P-Reinforce에 의해 체계적으로 관리됩니다.
|
||||
|
||||
## 📌 주요 분류 (Primary Focus)
|
||||
- **Visual Effects**: 파티클, 쉐이더 및 연출 기술
|
||||
- **UI/UX Assets**: 인터페이스 디자인 및 에셋 관리 규칙
|
||||
- **3D/2D Modeling**: 캐릭터, 환경 모델링 및 텍스처링 지식
|
||||
- **Aesthetic Principles**: Antigravity만의 독창적인 미학적 가이드라인
|
||||
|
||||
## 🔗 연결된 지식 (Graph)
|
||||
- **Parent**: [[10_Wiki/Index]]
|
||||
- **Related**: [[10_Wiki/Topics_GD]], [[10_Wiki/Topics]]
|
||||
|
||||
---
|
||||
*Generated by P-Reinforce Autonomous Gardener*
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: index-biz
|
||||
category: "[[10_Wiki/Topics_Biz]]"
|
||||
last_reinforced: 2026-04-25
|
||||
---
|
||||
|
||||
# 🏢 Business & Strategy Knowledge Base
|
||||
|
||||
> "전략은 방향을 결정하고, 실행은 가치를 창출한다."
|
||||
|
||||
Antigravity 프로젝트의 지속 가능한 성장과 시장 경쟁력을 확보하기 위한 사업 지식 저장소입니다. 비즈니스 모델, 시장 조사 데이터, 마케팅 전략 및 협력 관계가 이곳에서 정제됩니다.
|
||||
|
||||
## 📌 주요 분류 (Primary Focus)
|
||||
- **Market Research**: 타겟 시장 분석 및 트렌드 데이터
|
||||
- **Business Strategy**: 수익 모델(BM) 및 중장기 로드맵
|
||||
- **Partnerships**: 외부 협력사 및 생태계 구축 정보
|
||||
- **Operations**: 효율적인 조직 운영 및 프로세스 지식
|
||||
|
||||
## 🔗 연결된 지식 (Graph)
|
||||
- **Parent**: [[10_Wiki/Index]]
|
||||
- **Related**: [[10_Wiki/Topics_Blog]], [[10_Wiki/Decisions]]
|
||||
|
||||
---
|
||||
*Generated by P-Reinforce Autonomous Gardener*
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: index-blog
|
||||
category: "[[10_Wiki/Topics_Blog]]"
|
||||
last_reinforced: 2026-04-25
|
||||
---
|
||||
|
||||
# 📝 Blog & Content Knowledge Base
|
||||
|
||||
> "지식은 공유될 때 비로소 거대한 흐름이 된다."
|
||||
|
||||
사용자와 커뮤니티에게 우리의 철학과 기술적 성취를 전달하기 위한 콘텐츠 소스 창고입니다. 블로그 포스팅 초안, 기획 기사, 외부 기고문 및 소셜 미디어 전략이 이곳에 보관됩니다.
|
||||
|
||||
## 📌 주요 분류 (Primary Focus)
|
||||
- **Post Drafts**: 현재 작성 중이거나 발행 예정인 블로그 원고
|
||||
- **Content Strategy**: 콘텐츠 톤앤매너 및 발행 스케줄
|
||||
- **External Media**: 인터뷰, 보도자료 및 외부 기고문 아카이브
|
||||
- **Storytelling**: Antigravity의 세계관과 가치를 담은 스토리 데이터
|
||||
|
||||
## 🔗 연결된 지식 (Graph)
|
||||
- **Parent**: [[10_Wiki/Index]]
|
||||
- **Related**: [[10_Wiki/Topics_Biz]], [[10_Wiki/Topics_Art]]
|
||||
|
||||
---
|
||||
*Generated by P-Reinforce Autonomous Gardener*
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: index-gd
|
||||
category: "[[10_Wiki/Topics_GD]]"
|
||||
last_reinforced: 2026-04-25
|
||||
---
|
||||
|
||||
# 📝 Game Design & Systems Knowledge Base
|
||||
|
||||
> "재미는 우연이 아니라, 정교하게 설계된 수학과 심리학의 결합이다."
|
||||
|
||||
게임의 본질인 '재미'를 설계하고 시스템화하는 공간입니다. 게임 시스템 기획서, 밸런싱 시트, 레벨 디자인 원칙 및 사용자 경험(UX) 시나리오가 이곳에 집대성됩니다.
|
||||
|
||||
## 📌 주요 분류 (Primary Focus)
|
||||
- **Core Systems**: 전투, 성장, 경제 등 핵심 게임 루프 설계
|
||||
- **Level Design**: 스테이지 구성 및 환경 인터랙션 규칙
|
||||
- **Balancing**: 수치 데이터 기반의 난이도 및 보상 밸런싱
|
||||
- **UX Scenarios**: 플레이어의 행동 흐름과 심리적 보상 설계
|
||||
|
||||
## 🔗 연결된 지식 (Graph)
|
||||
- **Parent**: [[10_Wiki/Index]]
|
||||
- **Related**: [[10_Wiki/Topics]], [[10_Wiki/Topics_Art]]
|
||||
|
||||
---
|
||||
*Generated by P-Reinforce Autonomous Gardener*
|
||||
Reference in New Issue
Block a user