diff --git a/API_SPEC.md b/API_SPEC.md index 2b3c954..b14598e 100644 --- a/API_SPEC.md +++ b/API_SPEC.md @@ -2,7 +2,26 @@ 라온누리 서버 API 명세서 -## ⚠️ 최신 변경사항 (2025-11-11) +## ⚠️ 최신 변경사항 (2025-11-12) + +### ✅ Writing API 구현 완료 +- **POST /api/writing**: 글 생성 (서버에서 wordCount/charCount 자동 계산) +- **GET /api/writing/[id]**: 글 조회 (작성자만 접근) +- **PUT /api/writing/[id]**: 글 수정 (작성자만 접근) +- **DELETE /api/writing/[id]**: 글 삭제 (작성자만 접근) +- **POST /api/writing/user**: 사용자 글 목록 +- **POST /api/writing/recent**: 최근 글 (limit 파라미터) +- **서버 레이어**: `src/lib/server/writing.ts` (Firestore CRUD) + +### ⚡ Content Hash 기반 스마트 캐싱 +- **POST /api/analyze-pattern**: contentHash 파라미터 추가 +- **L1 캐시**: localStorage (영구, LRU 10개) +- **L2 캐시**: Server in-memory (5분, 50개) +- **해시 생성**: `id:updatedAt` 조합 (SHA-256) +- **자동 변경 감지**: 글 추가/수정 → 해시 변경 → 재분석 +- **성능 개선**: 캐시 히트 시 1ms vs AI 분석 5~10초 + +## ⚠️ 변경사항 (2025-11-11) ### 🤖 실시간 피드백 시스템 - **POST /api/analyze-text**: Vertex AI 기반 텍스트 분석 API @@ -153,6 +172,168 @@ const result = await analyzeText("오늘 날씨가 좋다."); --- +## Pattern Analysis API + +### POST /api/analyze-pattern + +**설명**: 글 작성 패턴 분석 (사용자의 여러 글을 종합 분석) + +**인증**: 필수 + +**Request Body**: +```typescript +{ + analysisType?: "self" | "by-topic" | "by-team"; // 분석 타입 (기본: self) + targetUserId?: string; // 분석 대상 유저 (팀원 분석 시) + topicId?: string; // 주제 ID (by-topic 시 필수) + teamId?: string; // 팀 ID (by-team 시 필수) + limit?: number; // 분석할 글의 최대 개수 (기본: 10개) + contentHash?: string; // 🆕 클라이언트가 계산한 해시 (캐시 조회용, 선택) +} +``` + +**Response**: +```typescript +{ + success: true, + pattern: { + userId: string; + analyzedAt: Date; + totalWritingsAnalyzed: number; + + // 분석 컨텍스트 + analysisType?: "self" | "by-topic" | "by-team"; + targetUserName?: string; + topicId?: string; + topicName?: string; + teamId?: string; + teamName?: string; + + // 작성 스타일 + writingStyle: { + averageWordCount: number; + averageCharCount: number; + preferredLength: "짧음" | "보통" | "긴편"; + sentenceStructure: "단문 위주" | "복문 위주" | "혼합형"; + }; + + // 표현력 분석 + expressionAnalysis: { + averageScore: number; // 0~10 + strongPoints: string[]; + weakPoints: string[]; + breakdown: { + sensory: number; // 오감 표현 (0~4) + emotion: number; // 감정 표현 (0~2) + dialogue: number; // 대화 표현 (0~2) + onomatopoeia: number; // 의성어/의태어 (0~2) + }; + frequentExpressions: { + sensory: string[]; + emotion: string[]; + onomatopoeia: string[]; + }; + }; + + // 맞춤법 경향 + spellingTendency: { + commonErrors: Array<{ + error: string; + correction: string; + frequency: number; + }>; + improvementRate: number; // 0~100 + }; + + // 발전 추이 + progressTrend: { + isImproving: boolean; + scoreChange: number; + improvementAreas: string[]; + needsAttention: string[]; + }; + + // AI 종합 평가 + summary: { + overallAssessment: string; + encouragement: string; + recommendations: string[]; + }; + }, + contentHash: string; // 🆕 서버가 계산한 해시 (클라이언트 캐싱용) +} +``` + +**에러**: +```typescript +// 404 - 분석할 글 없음 +{ + success: false, + error: "분석할 글이 없습니다. 글을 작성한 후 다시 시도해주세요." +} + +// 403 - 권한 없음 (by-topic, by-team) +{ + success: false, + error: "팀 소유자만 팀원의 글을 분석할 수 있습니다" +} +``` + +**분석 타입**: + +1. **self (본인 분석)**: + - 모든 published 글 분석 + - 권한: 본인만 + +2. **by-topic (주제별 분석)**: + - 특정 팀 주제로 작성된 글만 분석 + - 권한: 팀 소유자만 + - 주제가 팀 주제(`ownerType="team"`)여야 함 + +3. **by-team (팀 전체 분석)**: + - 팀의 모든 주제로 작성된 글 분석 + - 권한: 팀 소유자만 + - 팀 외 글(자유 주제, 다른 팀)은 제외 + +**🆕 Content Hash 기반 캐싱** (2025-11-12): + +**캐싱 전략**: +- **L1 (Client)**: localStorage에 contentHash를 키로 저장 (영구, LRU 10개) +- **L2 (Server)**: In-memory에 contentHash를 키로 저장 (5분 TTL, 최대 50개) +- **변경 감지**: 글 추가/수정 시 `updatedAt` 변경 → 해시 변경 → 자동 재분석 + +**Hash 생성 규칙**: +```typescript +// 입력: analysisType | limit | topicId | teamId | id:updatedAt,id:updatedAt,... +// 예시: "self|10|||abc:2024-01-01T00:00:00.000Z,def:2024-01-02T00:00:00.000Z" +// SHA-256 → "abc123def456..." +``` + +**성능**: +- 캐시 히트 (동일 글 세트): ~1ms (localStorage) +- 캐시 히트 (서버): ~50ms (in-memory) +- 캐시 미스: 5~10초 (AI 분석) + +**사용 흐름**: +```typescript +// 클라이언트 (self 분석) +1. 글 목록 조회 +2. contentHash 계산 +3. localStorage 확인 → 히트 시 즉시 반환 +4. 서버 요청 (contentHash 포함) +5. 서버 응답 → localStorage에 저장 + +// 서버 +1. contentHash 받음 → 캐시 확인 → 히트 시 즉시 반환 +2. 캐시 미스 → 글 조회 +3. 서버 contentHash 계산 → 캐시 확인 +4. AI 분석 수행 +5. contentHash 키로 캐시 저장 +6. contentHash 포함하여 응답 +``` + +--- + ## Team API ### 1. POST `/team` - 팀 생성 @@ -942,7 +1123,9 @@ const result = await analyzeText("오늘 날씨가 좋다."); ### 2. GET `/writing/:id` - 글 조회 실제 URL: `GET /api/writing/:id` -**인증**: 선택적 +**인증**: 필수 + +**권한**: 작성자만 조회 가능 (`writing.userId === currentUserId`) **Response**: ```typescript @@ -954,6 +1137,10 @@ const result = await analyzeText("오늘 날씨가 좋다."); } ``` +**에러**: +- `404 Not Found`: 글이 존재하지 않음 +- `403 Forbidden`: 작성자가 아님 + **캐싱**: 클라이언트에서 5분간 캐싱 --- diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md index 31fd2da..1168dcf 100644 --- a/PROJECT_STRUCTURE.md +++ b/PROJECT_STRUCTURE.md @@ -1,10 +1,63 @@ # 라온누리 - 프로젝트 구조 -> 최종 업데이트: 2025-11-11 (Google AI SDK 마이그레이션, 분석 히스토리, 맞춤법 검사) +> 최종 업데이트: 2025-11-12 (Writing API, 패턴 분석 확장, Content Hash 캐싱) 초등학생을 위한 창작 글쓰기 교육 플랫폼 -**주요 업데이트** (2025-11-11): +**최신 업데이트** (2025-11-12): +- ✅ **Writing API 구현 완료** + - POST /api/writing - 글 생성 (서버에서 wordCount/charCount 자동 계산) + - GET /api/writing/[id] - 글 조회 (작성자만 접근) + - PUT /api/writing/[id] - 글 수정 (작성자만 접근) + - DELETE /api/writing/[id] - 글 삭제 (작성자만 접근) + - POST /api/writing/user - 사용자 글 목록 + - POST /api/writing/recent - 최근 글 (limit 파라미터) + - 서버 레이어: `src/lib/server/writing.ts` (Firestore CRUD) + - WritingManager: 기존 클라이언트 캐싱 유지 (1분~5분) +- 📊 **글 작성 패턴 분석 - 3가지 분석 타입 지원** + - **self**: 본인의 모든 published 글 분석 (기존) + - **by-team**: 팀 소유자가 팀원의 팀 내 전체 글 분석 (신규) + - **by-topic**: 팀 소유자가 특정 주제로 작성된 팀원 글 분석 (신규 - UI만) + - 권한 체크: 팀 소유자만 팀원 분석 가능, 프라이버시 보호 + - API 파라미터 확장: `analysisType`, `targetUserId`, `topicId`, `teamId` +- 🎯 **WritingPatternDialog 개선** + - Props 확장: 분석 타입별 파라미터 지원 + - 제목 동적 변경: "OOO 학생의 'XXX' 주제 분석" 등 + - 분석 정보 안내: "이 팀에서 작성된 N개 글 분석" 등 +- 🏫 **팀 관리 페이지 UI 추가** + - 멤버 카드 메뉴에 "팀 내 글 분석" 버튼 (by-team) + - TopicMemberAnalysisSection 컴포넌트 (by-topic - 추후 구현) +- 🔒 **보안**: 팀 외 글(자유 주제, 다른 팀)은 분석에서 제외 +- ⚡ **Content Hash 기반 스마트 캐싱** + - L1 캐시: localStorage (영구, LRU 10개) + - L2 캐시: Server in-memory (5분, 50개) + - 해시 생성: `id:updatedAt` 조합 (SHA-256) + - 변경 자동 감지: 글 추가/수정 시 해시 변경 → 재분석 + - 성능: 캐시 히트 시 1ms (localStorage) vs 5~10초 (AI 분석) + - 유틸리티: `contentHash.ts`, `patternCacheManager.ts` + +**2025-11-11 (PM) 업데이트**: +- 📊 **글 작성 패턴 분석 시스템** + - 최근 10개 글을 분석하여 작성 스타일, 강점/약점, 발전 추이 파악 + - AI 기반 종합 평가 및 맞춤형 추천 사항 제공 + - 자주 사용하는 표현, 맞춤법 경향 분석 + - WritingPatternDialog + WritingPatternDisplay 컴포넌트 + - `/api/analyze-pattern` API 엔드포인트 (5분 캐싱) +- ✨ **실시간 하이라이트 시스템** (Tiptap Extensions) + - SpellingHighlight: 맞춤법 오류를 빨간 물결 밑줄로 표시 + - SensoryWordHighlight: 감각 단어를 색상별 하이라이트 (초록/파랑/보라) + - 기존 ScoreDisplay/SpellingErrorDisplay 제거 (하이라이트로 대체) +- 💬 **인터랙티브 툴팁 시스템** + - EditorTooltip: 하이라이트된 단어 클릭 시 상세 정보 표시 + - 맞춤법 오류: 원본 → 수정, 이유 설명 + - 감각 단어: 단어 타입, 격려 메시지 + - Portal + 외부 클릭/ESC 키로 닫기 +- 🔔 **Toast 알림 추가** (write 페이지) + - 텍스트 분석 시작/완료/실패 알림 (점수 표시) + - 맞춤법 검사 시작/완료/실패 알림 (에러 개수 표시) + - 로딩 상태 표시 (duration: Infinity) + +**2025-11-11 (AM) 업데이트**: - 🔄 **Google AI SDK 마이그레이션** - `@google-cloud/vertexai` → `@google/genai` (최신 SDK) - Response Schema 지원 (JSON 응답 강제) @@ -19,10 +72,8 @@ - 이전 버전 비교 피드백 - ✍️ **맞춤법 검사 서비스** (독립적) - Gemini 기반 맞춤법 검사 - - SpellingErrorDisplay 컴포넌트 - 텍스트 분석과 별도 debounce (5초) - 🤖 **실시간 피드백 시스템** (Vertex AI 기반) - - ScoreDisplay 컴포넌트 (점수, 찾은 단어, 수정 제안) - Delta 전송 (토큰 40% 절감) - 서버 캐싱 (중복 제거) - 🌏 **Multi-Region Failover** (가용성 99.9%) @@ -56,7 +107,7 @@ | **팀 목록** | `/team` | 내가 만든 팀 목록 (정식 계정 전용) | 팀 카드 그리드, 팀 정보 (코드, 멤버 수, 보안 설정)
"새 팀 만들기" 버튼 | | **팀 생성** | `/team/create` | 새 팀 만들기 (정식 계정 전용) | 팀 이름 입력, 팀 코드 자동 생성
🆕 **5단계 보안 레벨 선택** (RadioCard, 애니메이션)
🆕 **명단 관리 (Level 2/4)**: TagsInput으로 Enter/쉼표 입력
생성 후 `/team/[teamId]`로 이동 | | **팀 멤버 페이지** | `/team/[teamId]` | 팀 멤버용 페이지 (멤버/소유자 모두 접근) | 팀 정보, 팀 코드 복사, 멤버 목록
소유자는 "팀 관리" 버튼 표시
팀 코드 로그인 후 기본 이동 페이지 | -| **팀 관리** | `/team/[teamId]/manage` | 팀 관리 페이지 (소유자 전용) | 팀 정보 및 코드, 보안 설정 표시
**팀 주제 관리 (생성/삭제)**
멤버 목록 및 관리
"멤버 페이지 보기" 버튼 | +| **팀 관리** | `/team/[teamId]/manage` | 팀 관리 페이지 (소유자 전용) | 팀 정보 및 코드, 보안 설정 표시
**팀 주제 관리 (생성/삭제)**
🆕 **주제별 학생 분석** (TopicMemberAnalysisSection)
멤버 목록 및 관리
🆕 **멤버 메뉴 - 팀 내 글 분석** (by-team)
"멤버 페이지 보기" 버튼 | ### 🚧 구현 예정 @@ -152,37 +203,48 @@ | 컴포넌트 | 파일명 | 설명 | 상태 | |---------|--------|------|------| -| **WritingEditor** | `WritingEditor.tsx` | Tiptap 기반 순수 텍스트 에디터 | ✅ 완료 | -| **TopicSelector** | `TopicSelector.tsx` | 🆕 주제 선택 드롭다운 (그룹핑, 팀 이름 표시) | ✅ 완료 | -| **ScoreDisplay** | `ScoreDisplay.tsx` | 🆕 **실시간 피드백 점수 표시** (Gemini 기반) | ✅ 완료 | -| **SpellingErrorDisplay** | `SpellingErrorDisplay.tsx` | 🆕 **맞춤법 오류 표시** (Gemini 기반, 별도 독립) | ✅ 완료 | +| **WritingEditor** | `WritingEditor.tsx` | Tiptap 기반 순수 텍스트 에디터 (하이라이트 통합) | ✅ 완료 | +| **TopicSelector** | `TopicSelector.tsx` | 주제 선택 드롭다운 (그룹핑, 팀 이름 표시) | ✅ 완료 | +| **EditorTooltip** | `EditorTooltip.tsx` | 🆕 **인터랙티브 툴팁** (맞춤법/감각 단어 클릭 시 표시) | ✅ 완료 | +| **WritingPatternDialog** | `WritingPatternDialog.tsx` | 🆕 **글 작성 패턴 분석 다이얼로그** (최근 10개 글 분석) | ✅ 완료 | +| **WritingPatternDisplay** | `WritingPatternDisplay.tsx` | 🆕 **패턴 분석 결과 표시** (종합 평가, 발전 추이, 강점/약점, 추천) | ✅ 완료 | +| ~~**ScoreDisplay**~~ | ~~`ScoreDisplay.tsx`~~ | ~~실시간 피드백 점수 표시~~ | ❌ 삭제됨 (하이라이트로 대체) | +| ~~**SpellingErrorDisplay**~~ | ~~`SpellingErrorDisplay.tsx`~~ | ~~맞춤법 오류 표시~~ | ❌ 삭제됨 (하이라이트로 대체) | | **CreateTopicDialog** | `CreateTopicDialog.tsx` | 개인 주제 생성 다이얼로그 (태그 입력 UI) | ✅ 완료 | | **CreateTeamTopicDialog** | `CreateTeamTopicDialog.tsx` | 팀 주제 생성 다이얼로그 (템플릿 지원) | ✅ 완료 | -| **SavedDraftsDialog** | `SavedDraftsDialog.tsx` | 🆕 저장된 글조각 목록 다이얼로그 (불러오기/삭제) | ✅ 완료 | +| **SavedDraftsDialog** | `SavedDraftsDialog.tsx` | 저장된 글조각 목록 다이얼로그 (불러오기/삭제) | ✅ 완료 | **주요 기능**: - ✅ 순수 텍스트 입력 (포맷팅 없음) - ✅ 초등학생 친화적 단순 인터페이스 - ✅ 실시간 글자 수/단어 수 카운터 -- ✅ 🆕 **실시간 피드백 시스템** (Gemini 2.5 Flash-Lite) - - ✅ 점수 표시 (0~10점, 개편된 평가 기준) - - ✅ 찾은 표현 목록 (오감, 감정, 의성어/의태어) - - ✅ 분석 히스토리 추적 (이전 버전 비교, 발전 과정 격려) - - ✅ 스마트 제안 (칭찬 강화, 제안 0~1개) +- ✅ 🆕 **실시간 하이라이트 시스템** (Tiptap Extensions) + - ✅ SpellingHighlight: 맞춤법 오류를 빨간 물결 밑줄로 표시 + - ✅ SensoryWordHighlight: 감각 단어를 색상별 하이라이트 (초록/파랑/보라) + - ✅ 클릭 시 툴팁 표시 (맞춤법: 원본→수정+이유, 감각 단어: 단어 타입+격려) + - ✅ 브라우저 기본 맞춤법 검사 비활성화 (spellcheck="false") +- ✅ 🆕 **글 작성 패턴 분석** (AI 기반) + - ✅ 최근 10개 글 종합 분석 (작성 스타일, 표현력, 발전 추이) + - ✅ 강점/약점 파악, 자주 쓰는 표현 분석 + - ✅ AI 종합 평가 및 맞춤형 추천 사항 3가지 + - ✅ 5분 캐싱 (성능 최적화) +- ✅ **실시간 피드백 시스템** (Gemini 2.5 Flash-Lite) + - ✅ 텍스트 분석 (오감/감정/대화/의성어 평가) - ✅ 5초 debounce + Delta 전송 (토큰 40% 절감) + - ✅ Toast 알림 (시작/완료/실패, 점수 표시) - ✅ Multi-region failover (가용성 99.9%) -- ✅ 🆕 **맞춤법 검사** (독립적, Gemini 기반) +- ✅ **맞춤법 검사** (독립적, Gemini 기반) - ✅ 초등학생 눈높이 설명 - ✅ 5초 debounce (텍스트 분석과 별도) - - ✅ 오류 목록 표시 (원본 → 수정, 이유) -- ✅ 🆕 **주제 변경 경고 Dialog** (작성 중 내용 초기화 알림 + 임시 저장 안내) -- ✅ 🆕 **다중 글조각 관리** (최대 10개, FIFO 방식) -- ✅ 🆕 **강화된 자동 저장** (2초 debounce, localStorage) -- ✅ 🆕 **저장 상태 표시** (저장 중 → 저장됨 → 시간 표시) -- ✅ 🆕 "새 글쓰기" 버튼 (현재 글 초기화) -- ✅ 🆕 "저장된 글조각" Dialog (목록, 미리보기, 불러오기/삭제) -- ✅ 🆕 **주제 선택 그룹핑** (자유/팀/개인 주제 구분, ItemGroup 사용) -- ✅ 🆕 **팀 주제에 팀 이름 표시** (어느 팀의 주제인지 명확히 표시) + - ✅ Toast 알림 (에러 개수 표시) +- ✅ **주제 변경 경고 Dialog** (작성 중 내용 초기화 알림 + 임시 저장 안내) +- ✅ **다중 글조각 관리** (최대 10개, FIFO 방식) +- ✅ **강화된 자동 저장** (2초 debounce, localStorage) +- ✅ **저장 상태 표시** (저장 중 → 저장됨 → 시간 표시) +- ✅ "새 글쓰기" 버튼 (현재 글 초기화) +- ✅ "저장된 글조각" Dialog (목록, 미리보기, 불러오기/삭제) +- ✅ **주제 선택 그룹핑** (자유/팀/개인 주제 구분, ItemGroup 사용) +- ✅ **팀 주제에 팀 이름 표시** (어느 팀의 주제인지 명확히 표시) - ✅ 주제 선택 (자유 주제/팀 주제/개인 주제) - ✅ 주제 정보 표시 (설명, 키워드, 예시 질문) - ✅ 템플릿 미리채우기 (제목/내용) @@ -192,13 +254,40 @@ --- +### 📁 `src/extensions/` - Tiptap Extensions + +| Extension | 파일명 | 설명 | 상태 | +|-----------|--------|------|------| +| **SpellingHighlight** | `spelling-highlight.ts` | 🆕 **맞춤법 오류 하이라이트** (빨간 물결 밑줄, data attributes) | ✅ 완료 | +| **SensoryWordHighlight** | `sensory-word-highlight.ts` | 🆕 **감각 단어 하이라이트** (색상별 표시: 초록/파랑/보라) | ✅ 완료 | + +**주요 기능**: +- ✅ Tiptap ProseMirror Plugin 기반 +- ✅ DecorationSet을 사용한 효율적인 하이라이트 +- ✅ Meta를 통한 강제 업데이트 지원 +- ✅ data attributes로 툴팁 정보 전달 +- ✅ 실시간 텍스트 변경 추적 + +**하이라이트 종류**: +- **SpellingHighlight**: 맞춤법 오류 (빨간 물결 밑줄) + - `spelling-error` 클래스 + - data-original, data-correction, data-reason 속성 +- **SensoryWordHighlight**: 감각 단어 (색상별) + - `sensory-word` (감각 동사, 초록색) + - `emotion-word` (감각 형용사, 파란색) + - `onomatopoeia-word` (의성어/의태어, 보라색) + - data-word, data-type 속성 + +--- + ### 📁 `src/components/team/` - 팀 관리 | 컴포넌트 | 파일명 | 설명 | 상태 | |---------|--------|------|------| | **TeamTopicManager** | `TeamTopicManager.tsx` | 팀 주제 목록 및 생성/삭제 UI | ✅ 완료 | -| **SecurityLevelSelector** | `SecurityLevelSelector.tsx` | 🆕 5단계 보안 레벨 선택 (RadioCard, framer-motion 애니메이션) | ✅ 완료 | -| **AllowListManager** | `AllowListManager.tsx` | 🆕 명단 관리 (이름/이메일 추가/제거, TagsInput) | ✅ 완료 | +| **SecurityLevelSelector** | `SecurityLevelSelector.tsx` | 5단계 보안 레벨 선택 (RadioCard, framer-motion 애니메이션) | ✅ 완료 | +| **AllowListManager** | `AllowListManager.tsx` | 명단 관리 (이름/이메일 추가/제거, TagsInput) | ✅ 완료 | +| **TopicMemberAnalysisSection** | `TopicMemberAnalysisSection.tsx` | 🆕 주제별 학생 글쓰기 분석 (Accordion, by-topic 분석) | 🚧 UI만 (API 추후 구현) | **주요 기능** (2025-11-10): - ✅ SecurityLevelSelector: RadioCard 기반, 선택 시 추가 UI 애니메이션으로 표시 @@ -256,10 +345,11 @@ |-------|--------|------|------| | **Firebase Auth** | `firebaseAuth.ts` | 인증 서비스 (로그인, 회원가입, 소셜, Anonymous, 계정 연결) | ✅ 완료 (단순화됨) | | **Firestore** | `firestore.ts` | Firestore CRUD 헬퍼 함수 (WritingManager에서 사용) | ✅ 완료 | -| **Vertex AI** | `vertexAI.ts` | 🆕 **Gemini API 범용 래퍼** (`@google/genai`, Multi-region failover, Response Schema) | ✅ 완료 | -| **Text Analysis** | `textAnalysisService.ts` | 🆕 **텍스트 분석 서비스** (평가 기준 개편, 히스토리 기반 분석) | ✅ 완료 | -| **Spelling Check** | `spellingService.ts` | 🆕 **맞춤법 검사 서비스** (Gemini 기반, 초등학생 눈높이) | ✅ 완료 | -| **Region Health** | `regionHealthManager.ts` | 🆕 **Region 과부하 상태 추적** (자동 복구, 1분 TTL) | ✅ 완료 | +| **Vertex AI** | `vertexAI.ts` | **Gemini API 범용 래퍼** (`@google/genai`, Multi-region failover, Response Schema) | ✅ 완료 | +| **Text Analysis** | `textAnalysisService.ts` | **텍스트 분석 서비스** (평가 기준 개편, 히스토리 기반 분석) | ✅ 완료 | +| **Pattern Analysis** | `patternAnalysisService.ts` | 🆕 **글 작성 패턴 분석 서비스** (10개 글 종합 분석, AI 평가) | ✅ 완료 | +| **Spelling Check** | `spellingService.ts` | **맞춤법 검사 서비스** (Gemini 기반, 초등학생 눈높이) | ✅ 완료 | +| **Region Health** | `regionHealthManager.ts` | **Region 과부하 상태 추적** (자동 복구, 1분 TTL) | ✅ 완료 | | ~~**Team Service**~~ | ~~`teamService.ts`~~ | ~~팀 CRUD, 팀 코드 생성~~ | ⚠️ Deprecated (TeamManager로 이동) | | ~~**Student Service**~~ | ~~`studentService.ts`~~ | ~~학생 CRUD, PIN 해시/검증~~ | ⚠️ Deprecated (UserManager로 대체) | | **Level System** | `levelSystem.ts` | 레벨/경험치 계산 로직 | ❌ 미구현 | @@ -276,15 +366,16 @@ | 타입 | 파일명 | 설명 | 상태 | |------|--------|------|------| -| **Team 타입** | `team.ts` | 🆕 팀 데이터 모델 (members Map), **TeamSecurityLevel Enum (1-5)** | ✅ 완료 | -| **FirestoreUser 타입** | `firestoreUser.ts` | 🆕 **FirestoreUser** (DB 저장용), **User** (UI용) 분리 | ✅ 완료 | -| **Draft 타입** | `draft.ts` | 🆕 글조각 데이터 모델 (Draft, DraftListItem, **AnalysisHistoryItem**) | ✅ 완료 | +| **Team 타입** | `team.ts` | 팀 데이터 모델 (members Map), **TeamSecurityLevel Enum (1-5)** | ✅ 완료 | +| **FirestoreUser 타입** | `firestoreUser.ts` | **FirestoreUser** (DB 저장용), **User** (UI용) 분리 | ✅ 완료 | +| **Draft 타입** | `draft.ts` | 글조각 데이터 모델 (Draft, DraftListItem, **AnalysisHistoryItem**) | ✅ 완료 | +| **WritingPattern 타입** | `writingPattern.ts` | 🆕 **글 작성 패턴 분석** 데이터 모델 (WritingPatternAnalysis) | ✅ 완료 | | ~~**User 타입**~~ | ~~`user.ts`~~ | ~~사용자 데이터 모델~~ | ⚠️ Deprecated (firestoreUser.ts로 변경) | | ~~**Student 타입**~~ | ~~`student.ts`~~ | ~~학생 데이터 모델~~ | ⚠️ Deprecated (user.ts로 대체) | | **Topic 타입** | `topic.ts` | 주제 데이터 모델, TopicCategory/Difficulty/OwnerType Enum, 팀 주제 유틸 함수 | ✅ 완료 | | **API 공통 타입** | `api.ts` | ApiResponse, ApiError, HttpMethod Enum | ✅ 완료 | | **Team API 타입** | `api/team.ts` | 팀 API Request/Response (add/removeMember 추가, requirePin 제거) | ✅ 완료 | -| **User API 타입** | `api/user.ts` | 사용자 API Request/Response (닉네임 관리 포함) **[NEW]** | ✅ 완료 | +| **User API 타입** | `api/user.ts` | 사용자 API Request/Response (닉네임 관리 포함) | ✅ 완료 | | ~~**Student API 타입**~~ | ~~`api/student.ts`~~ | ~~학생 API Request/Response~~ | ⚠️ Deprecated (api/user.ts로 대체) | | **Topic API 타입** | `api/topic.ts` | 주제 API Request/Response (9개 엔드포인트, 팀 주제 포함) | ✅ 완료 | @@ -294,10 +385,12 @@ | 유틸리티 | 파일명 | 설명 | 상태 | |---------|--------|------|------| -| **Korean Word List** | `koreanWordList.ts` | 🆕 **한글 감각 동사/형용사 목록** (점수 가중치, 영역 변환 함수) | ✅ 완료 | +| **Korean Word List** | `koreanWordList.ts` | 한글 감각 동사/형용사 목록 (점수 가중치, 영역 변환 함수) | ✅ 완료 | | **Team Code Generator** | `teamCodeGenerator.ts` | 한글 팀 코드 생성 (형용사 + 색깔 + 동물) | ✅ 완료 | | **Password Security** | `passwordSecurity.ts` | HIBP API 연동 (유출된 비밀번호 차단) | ✅ 완료 | | **Password Strength** | `passwordStrength.ts` | 비밀번호 강도 계산 | ✅ 완료 | +| **Content Hash** | `contentHash.ts` | 🆕 **SHA-256 해시 생성** (글 목록 → 해시, id+updatedAt 조합, 서버/클라이언트 지원) | ✅ 완료 | +| **Pattern Cache Manager** | `patternCacheManager.ts` | 🆕 **패턴 분석 localStorage 캐싱** (LRU 최대 10개, 캐시 통계) | ✅ 완료 | --- @@ -305,8 +398,15 @@ | API | 경로 | 메서드 | 설명 | 상태 | |-----|------|--------|------|------| -| **텍스트 분석** | `/api/analyze-text` | POST | 🆕 **Gemini 기반 텍스트 분석** (Delta 지원, 캐싱, 히스토리 인식) | ✅ 완료 | -| **맞춤법 검사** | `/api/spelling/check` | POST | 🆕 **Gemini 기반 맞춤법 검사** (초등학생 눈높이) | ✅ 완료 | +| **텍스트 분석** | `/api/analyze-text` | POST | **Gemini 기반 텍스트 분석** (Delta 지원, 캐싱, 히스토리 인식) | ✅ 완료 | +| **패턴 분석** | `/api/analyze-pattern` | POST | **글 작성 패턴 분석** (3가지 타입, contentHash 기반 2단계 캐싱, 변경 감지) | ✅ 완료 | +| **맞춤법 검사** | `/api/spelling/check` | POST | **Gemini 기반 맞춤법 검사** (초등학생 눈높이) | ✅ 완료 | +| **글 생성** | `/api/writing` | POST | 🆕 **글 생성** (wordCount/charCount 자동 계산) | ✅ 완료 | +| **글 조회** | `/api/writing/[id]` | GET | 🆕 **글 조회** (작성자만 접근) | ✅ 완료 | +| **글 수정** | `/api/writing/[id]` | PUT | 🆕 **글 수정** (작성자만 접근, 통계 재계산) | ✅ 완료 | +| **글 삭제** | `/api/writing/[id]` | DELETE | 🆕 **글 삭제** (작성자만 접근) | ✅ 완료 | +| **사용자 글 목록** | `/api/writing/user` | POST | 🆕 **사용자 글 목록** (userId 선택적, 본인 글만) | ✅ 완료 | +| **최근 글** | `/api/writing/recent` | POST | 🆕 **최근 글** (limit 파라미터, 기본 5개) | ✅ 완료 | | **팀 CRUD** | `/api/team` | GET, POST, PUT, DELETE | 팀 생성/조회/수정/삭제 | ✅ 완료 | | **팀 보안 레벨** | `/api/team/[teamId]/security-level` | POST | 보안 레벨 변경 | ✅ 완료 | | **명단 관리** | `/api/team/[teamId]/allowed-names` | POST, DELETE | 허용 이름 추가/제거 | ✅ 완료 | @@ -314,6 +414,12 @@ | **주제 CRUD** | `/api/topic` | GET, POST, PUT, DELETE | 주제 생성/조회/수정/삭제 (9개 엔드포인트) | ✅ 완료 | | **사용자 관리** | `/api/user` | GET, POST, PUT | 사용자 조회/생성/업데이트 | ✅ 완료 | +**서버 레이어** (`src/lib/server/`): +- `team.ts` - 팀 Firestore CRUD +- `user.ts` - 사용자 Firestore CRUD +- `topic.ts` - 주제 Firestore CRUD +- 🆕 `writing.ts` - 글 Firestore CRUD (createWriting, getWriting, updateWriting, deleteWriting, getUserWritings, getRecentWritings, isWritingOwner) + --- ## 상태 관리 (Zustand) diff --git a/ROADMAP.md b/ROADMAP.md index 9db44d7..f95b75f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,6 @@ # 라온누리 - 개발 로드맵 -> 최종 업데이트: 2025-11-11 (실시간 피드백 시스템, Multi-Region Failover) +> 최종 업데이트: 2025-11-12 (Writing API, 패턴 분석 확장, Content Hash 캐싱) 초등학생을 위한 창작 글쓰기 교육 플랫폼 개발 계획 @@ -8,7 +8,7 @@ ## 현재 개발 단계 -**Phase 1: 핵심 기능** (진행 중 - 98% 완료) +**Phase 1: 핵심 기능** (진행 중 - 99% 완료) --- @@ -75,7 +75,14 @@ | **Google AI SDK 마이그레이션** | **`@google-cloud/vertexai` → `@google/genai` (v1.29.0), Response Schema 지원, Gemini 2.0+ 기능** | **2025-11-11** | | **텍스트 분석 평가 기준 개편** | **오감(4점) + 감정(2점) + 대화(2점) + 의성어(2점), `descriptive` → `emotion`, 프롬프트 최적화 (칭찬 강화, 제안 0~1개)** | **2025-11-11** | | **분석 히스토리 시스템** | **Draft.analysisHistory 추가 (최대 5개), AI가 수정 과정 인식, 이전 버전 비교 피드백** | **2025-11-11** | -| **맞춤법 검사 서비스** | **spellingService.ts (Gemini 기반), SpellingErrorDisplay 컴포넌트, 독립적 debounce (5초)** | **2025-11-11** | +| **맞춤법 검사 서비스** | **spellingService.ts (Gemini 기반), 독립적 debounce (5초)** | **2025-11-11** | +| **글 작성 패턴 분석 시스템** | **patternAnalysisService.ts, WritingPatternDialog/Display, 최근 10개 글 종합 분석, AI 평가 및 맞춤형 추천, 5분 캐싱** | **2025-11-11** | +| **실시간 하이라이트 시스템** | **SpellingHighlight/SensoryWordHighlight Extensions, 맞춤법(빨간 물결)/감각 단어(색상별) 하이라이트, ScoreDisplay/SpellingErrorDisplay 제거** | **2025-11-11** | +| **인터랙티브 툴팁** | **EditorTooltip, 하이라이트 클릭 시 상세 정보 표시 (맞춤법: 원본→수정+이유, 감각 단어: 타입+격려), Portal + ESC/외부 클릭** | **2025-11-11** | +| **Toast 알림 추가** | **텍스트 분석/맞춤법 검사 시작/완료/실패 알림, 점수/에러 개수 표시, 로딩 상태 (duration: Infinity)** | **2025-11-11** | +| **Writing API 구현** | **POST /api/writing (글 생성), GET/PUT/DELETE /api/writing/[id] (조회/수정/삭제), POST /api/writing/user (목록), POST /api/writing/recent (최근 글), src/lib/server/writing.ts (Firestore CRUD), 권한 체크 (작성자만), 텍스트 통계 자동 계산** | **2025-11-12** | +| **패턴 분석 - 팀 소유자 기능** | **3가지 분석 타입 (self/by-team/by-topic), API 권한 체크, 팀 주제 필터링, WritingPatternDialog Props 확장, TopicMemberAnalysisSection (UI만), 팀 관리 페이지에 멤버 분석 메뉴** | **2025-11-12** | +| **Content Hash 기반 스마트 캐싱** | **글 목록 해시 생성 (id+updatedAt), L1: localStorage (영구, LRU 10개), L2: Server in-memory (5분, 50개), 변경 자동 감지, 재분석 최소화, contentHash.ts + patternCacheManager.ts** | **2025-11-12** | ### 🚧 진행 중 @@ -86,12 +93,11 @@ | 항목 | 설명 | 우선순위 | 예상 일정 | |-----|------|---------|---------| -| **Next.js API Routes 구현** | **Team/User API 엔드포인트 구현, ID Token 검증, 권한 체크** | 🔴 **긴급** | **2025-11-08** | -| **서버 사이드 Redis 캐싱** | **API Routes에 Redis 캐싱, Rate Limiting 추가** | 🟡 중간 | 2025-11-09 | -| 내가 쓴 글 목록 | `/home`에 최근 글 표시, 글 목록 페이지 | 🔴 높음 | 2025-11-10 | -| 글 수정 기능 | 기존 글 불러와서 수정 | 🔴 높음 | 2025-11-11 | -| ~~firestore.ts userId→studentId 변경~~ | ~~글쓰기 기능과 팀 코드 시스템 통합~~ | ~~🟡 중간~~ | ✅ **완료 (2025-11-07)** | -| 이미지 업로드 | Firebase Storage 연동 | 🟡 중간 | 2025-11-13 | +| **서버 사이드 Redis 캐싱** | **API Routes에 Redis 캐싱, Rate Limiting 추가** | 🟡 중간 | 2025-11-13 | +| 내가 쓴 글 목록 | `/home`에 최근 글 표시, 글 목록 페이지 | 🔴 높음 | 2025-11-13 | +| 글 수정 기능 | 기존 글 불러와서 수정 | 🔴 높음 | 2025-11-13 | +| 이미지 업로드 | Firebase Storage 연동 | 🟡 중간 | 2025-11-14 | +| 주제별 학생 분석 API | GET /api/topic/[topicId]/writers (주제로 글 쓴 학생 목록) | 🟡 중간 | 2025-11-14 | **Phase 1 완료 목표**: 2025년 11월 15일 diff --git a/SERVICE_DIRECTION.md b/SERVICE_DIRECTION.md index 7bc818b..90c93fc 100644 --- a/SERVICE_DIRECTION.md +++ b/SERVICE_DIRECTION.md @@ -417,8 +417,6 @@ Tier 3: 고급 AI (Claude Sonnet, $0.03/회, 95% 정확도) #### ✅ 결정 사항 - **3-Tier 하이브리드 시스템** 채택 - Phase 1: 로컬 규칙만 구현 (MVP) -- 상세 내용: [**기술 구현 문서**](./TECHNICAL_IMPLEMENTATION.md) 참고 - --- ### 5차 논의: 한글 패턴 매칭 문제 (2025-11-11) @@ -449,7 +447,6 @@ Tier 3: 고급 AI (Claude Sonnet, $0.03/회, 95% 정확도) - Tier 1: 간단한 정규식 10개 (즉시 응답) - Tier 2: Mecab 서버 (5초 후 정밀 분석) - Phase 1부터 Mecab 구현 시작 -- 상세 내용: [**기술 구현 문서**](./TECHNICAL_IMPLEMENTATION.md#2-한글-패턴-매칭-문제-해결) 참고 --- @@ -491,8 +488,7 @@ Tier 3: Gemini 2.5 Flash (90% 정확도, $0.0001/회) - **AI 모델: Gemini 2.5 Flash** 채택 - **한글 분석: Mecab + 간단한 정규식** (하이브리드) - **비용**: 연간 $1.20 (99.9% 절감) -- 상세 내용: [기술 문서](./TECHNICAL_IMPLEMENTATION.md) 참고 - +- --- ### 7차 논의: Mecab 배포 문제 및 Vertex AI 단일 시스템 재설계 (2025-11-11) @@ -667,7 +663,6 @@ if (cached && Date.now() - cached.timestamp < 60000) { - 추가 인프라 불필요 #### 📝 기술 문서 업데이트 -- [TECHNICAL_IMPLEMENTATION.md](./TECHNICAL_IMPLEMENTATION.md) 전면 개편 - Mecab 관련 내용 제거 - Vertex AI + Delta + Caching 중심으로 재작성 @@ -824,8 +819,6 @@ Region 3개 = 45 RPM (3배) - 가용성: 95% → **99.9%** - 추가 비용: **없음** -**상세 내용**: [기술 문서 - Multi-Region](./TECHNICAL_IMPLEMENTATION.md#2-multi-region-failover-시스템) - --- ## 🔄 다음 논의 주제 @@ -844,7 +837,7 @@ Region 3개 = 45 RPM (3배) - 실제 서비스 구조 공개 - 움직이는 그림 메커니즘 (2차) - **2025-11-11**: - 초기 기획안 평가 - 후처리 방식의 문제점 분석 (3차) - - 실시간 피드백 기술 구현 (4차) → [기술 문서](./TECHNICAL_IMPLEMENTATION.md) + - 실시간 피드백 기술 구현 (4차) - 한글 패턴 매칭 문제 해결 (5차) - AI 모델 선택 - Gemini 채택 (6차) - **Mecab 배포 문제 발견 및 Vertex AI 단일 시스템 재설계 (7차)** ⭐ diff --git a/TECH_STACK.md b/TECH_STACK.md index 35a46ab..027e907 100644 --- a/TECH_STACK.md +++ b/TECH_STACK.md @@ -1,6 +1,6 @@ # 라온누리 - 기술 스택 및 개발 환경 -> 최종 업데이트: 2025-11-11 (Google AI SDK 마이그레이션, 분석 히스토리, 맞춤법 검사) +> 최종 업데이트: 2025-11-11 (글 작성 패턴 분석, 실시간 하이라이트, 인터랙티브 툴팁) --- @@ -35,8 +35,9 @@ | **Redis** | - | Cache 데이터 베이스 (예정) | **AI 서비스**: -- **Gemini 2.5 Flash-Lite**: 텍스트 분석 (오감/감정/대화/의성어 평가) +- **Gemini 2.5 Flash-Lite**: 텍스트 분석 (오감/감정/대화/의성어 평가, Delta 전송) - **Gemini 2.5 Flash-Lite**: 맞춤법 검사 (초등학생 눈높이) +- **Gemini 2.5 Flash-Lite**: 글 작성 패턴 분석 (최근 10개 글 종합 분석, AI 평가 및 맞춤형 추천) - **Vertex AI 모드**: Multi-region failover 지원 (`vertexai: true`) - **Response Schema**: JSON 응답 강제 (`Type.OBJECT`, `Type.ARRAY` 등) @@ -849,10 +850,10 @@ interface Draft { **API & 컴포넌트**: - `src/app/api/analyze-text/route.ts` - 텍스트 분석 API -- `src/app/api/spelling/check/route.ts` - 🆕 맞춤법 검사 API -- `src/components/writing/ScoreDisplay.tsx` - 점수 표시 UI -- `src/components/writing/SpellingErrorDisplay.tsx` - 🆕 맞춤법 오류 표시 -- `src/app/write/page.tsx` - Delta 추적 + 통합 + 맞춤법 검사 +- `src/app/api/spelling/check/route.ts` - 맞춤법 검사 API +- ~~`src/components/writing/ScoreDisplay.tsx`~~ - ❌ 삭제됨 (하이라이트로 대체) +- ~~`src/components/writing/SpellingErrorDisplay.tsx`~~ - ❌ 삭제됨 (하이라이트로 대체) +- `src/app/write/page.tsx` - Delta 추적 + 통합 + Toast 알림 **타입 정의**: - `src/types/draft.ts` - Draft, AnalysisHistoryItem @@ -866,6 +867,142 @@ interface Draft { --- +### 8. 글 작성 패턴 분석 시스템 + +#### 핵심 개념 + +**목적**: 사용자의 여러 글을 분석하여 작성 패턴, 강점, 약점을 파악하고 맞춤형 피드백 제공 + +**분석 항목**: +1. **작성 스타일**: 평균 글자/단어 수, 선호하는 글 길이, 문장 구조 (단문/복문/혼합) +2. **표현력 분석**: 평균 점수, 강점/약점, 카테고리별 점수, 자주 쓰는 표현 +3. **맞춤법 경향**: 자주 하는 실수, 개선율 +4. **발전 추이**: 최근 5개 vs 이전 5개 비교, 개선 영역, 주의 필요 영역 +5. **AI 종합 평가**: 전반적 평가, 격려 메시지, 맞춤형 추천 3가지 + +**서비스 레이어**: +- `patternAnalysisService.ts` - 10개 글 종합 분석, Gemini 기반 AI 평가, Response Schema 사용 + +**API**: +- `POST /api/analyze-pattern` - 최근 10개 글 분석 (5분 캐싱) + - 인증 필요 (ID Token) + - Firestore에서 글 조회 → 각 글 AI 분석 (병렬) → 패턴 분석 → 캐싱 + +**컴포넌트**: +- `WritingPatternDialog` - 패턴 분석 다이얼로그 (로딩/에러/성공 상태) +- `WritingPatternDisplay` - 분석 결과 표시 (종합 평가, 발전 추이, 작성 스타일, 표현력, 강점/약점, 자주 쓰는 표현, 추천) + +**타입**: +- `src/types/writingPattern.ts` - WritingPatternAnalysis, AnalyzePatternRequest/Response + +**참고 파일**: +- `src/services/patternAnalysisService.ts` - 패턴 분석 로직 +- `src/app/api/analyze-pattern/route.ts` - 패턴 분석 API +- `src/components/writing/WritingPatternDialog.tsx` - 다이얼로그 +- `src/components/writing/WritingPatternDisplay.tsx` - 표시 컴포넌트 +- `src/app/home/page.tsx` - "작성 패턴 분석" 카드 추가 + +--- + +### 9. 실시간 하이라이트 시스템 (Tiptap Extensions) + +#### 핵심 개념 + +**목적**: 에디터에서 맞춤법 오류와 감각 단어를 실시간으로 시각적으로 표시 + +**하이라이트 종류**: +1. **맞춤법 오류**: 빨간 물결 밑줄 (`spelling-error` 클래스) +2. **감각 동사**: 초록색 하이라이트 (`sensory-word` 클래스) +3. **감각 형용사**: 파란색 하이라이트 (`emotion-word` 클래스) +4. **의성어/의태어**: 보라색 하이라이트 (`onomatopoeia-word` 클래스) + +**Tiptap Extensions**: +- `SpellingHighlight` - 맞춤법 오류 하이라이트 + - data-original, data-correction, data-reason 속성 + - Meta를 통한 강제 업데이트 +- `SensoryWordHighlight` - 감각 단어 하이라이트 + - data-word, data-type 속성 + - 색상별 구분 (초록/파랑/보라) + +**DecorationSet 기반**: +- ProseMirror Decoration을 사용한 효율적인 하이라이트 +- 문서 변경 시 자동 업데이트 +- 하이라이트 위치를 정확하게 추적 + +**WritingEditor 통합**: +- `spellingErrors`, `foundWords` props 추가 +- Extension 옵션 실시간 업데이트 +- 브라우저 기본 맞춤법 검사 비활성화 (`spellcheck="false"`) + +**참고 파일**: +- `src/extensions/spelling-highlight.ts` - 맞춤법 하이라이트 Extension +- `src/extensions/sensory-word-highlight.ts` - 감각 단어 하이라이트 Extension +- `src/components/writing/WritingEditor.tsx` - Extensions 통합 + +--- + +### 10. 인터랙티브 툴팁 시스템 + +#### 핵심 개념 + +**목적**: 하이라이트된 단어를 클릭하면 상세 정보를 툴팁으로 표시 + +**툴팁 종류**: +1. **맞춤법 오류 툴팁**: + - 원본 → 수정 (취소선 → 굵은 글씨) + - 이유 설명 (초등학생 눈높이) + - 빨간색 테두리 +2. **감각 단어 툴팁**: + - 단어 표시 + - 단어 타입 (감각 동사/형용사/의성어) + - 격려 메시지 ("이렇게 구체적으로 표현하면 글이 더 생생해져요!") + - 색상별 테두리 (초록/파랑/보라) + +**기술 구현**: +- Portal 사용 (z-index 문제 해결) +- 클릭한 요소의 data attributes 읽기 +- 외부 클릭/ESC 키로 닫기 +- Fade-in 애니메이션 + +**WritingEditor 통합**: +- DOM 클릭 이벤트 리스너 등록 +- 하이라이트 클래스 확인 (spelling-error, sensory-word 등) +- 툴팁 위치 계산 (getBoundingClientRect) +- 여러 개 툴팁 동시 표시 가능 (배열 관리) + +**참고 파일**: +- `src/components/writing/EditorTooltip.tsx` - 툴팁 컴포넌트 +- `src/components/writing/WritingEditor.tsx` - 클릭 이벤트 처리 + +--- + +### 11. Toast 알림 시스템 + +#### 핵심 개념 + +**목적**: 텍스트 분석 및 맞춤법 검사 진행 상태를 사용자에게 알림 + +**알림 종류**: +1. **텍스트 분석**: + - 시작: "글을 분석하고 있어요..." (loading, duration: Infinity) + - 완료: "분석 완료! 점수: X.X점" (success, 3초) + - 실패: "분석 실패, 다시 시도해주세요." (error, 3초) +2. **맞춤법 검사**: + - 시작: "맞춤법을 검사하고 있어요..." (loading, duration: Infinity) + - 완료: "맞춤법 검사 완료! X개의 오류 발견" 또는 "맞춤법 오류 없음!" (success, 3초) + - 실패: "맞춤법 검사 실패" (error, 3초) + +**기술 구현**: +- Chakra UI Toaster 사용 +- Toast ID 관리 (ref로 저장, dismiss 호출) +- 로딩 상태 toast는 수동으로 dismiss +- 성공/실패 시 기존 loading toast 제거 후 새 toast 표시 + +**참고 파일**: +- `src/app/write/page.tsx` - Toast 알림 통합 + +--- + ## 참고 문서 - [PROJECT_STRUCTURE.md](./PROJECT_STRUCTURE.md) - 프로젝트 구조