From 04d199c64a97cdb5d64fe93dfad2dd1cab505a34 Mon Sep 17 00:00:00 2001 From: Documentation Bot Date: Thu, 27 Nov 2025 08:40:46 +0000 Subject: [PATCH] docs: Sync documentation from private repository --- API_SPEC.md | 79 +++++++++++- DATA_MODELS.md | 67 ++++++---- NEXT_TASKS.md | 285 +++++++++++++++++++++++++++++++++++++++++++ PROJECT_STRUCTURE.md | 62 +++++++++- ROADMAP.md | 9 +- TECH_STACK.md | 19 ++- 6 files changed, 486 insertions(+), 35 deletions(-) create mode 100644 NEXT_TASKS.md diff --git a/API_SPEC.md b/API_SPEC.md index 8e6700c..63afd9a 100644 --- a/API_SPEC.md +++ b/API_SPEC.md @@ -2,7 +2,24 @@ 라온누리 서버 API 명세서 -## ⚠️ 최신 변경사항 (2025-11-26) +## ⚠️ 최신 변경사항 (2025-11-27) + +### 🖼️ 팀 커버 이미지 API +- **POST /api/team/[teamId]/cover-image**: 팀 커버 이미지 업로드 + - FormData로 이미지 파일 전송 (JPEG/PNG/WebP/GIF, 최대 5MB) + - Firebase Storage 업로드 (`teams/{teamId}/cover-{timestamp}.{ext}`) + - 기존 이미지 자동 삭제 + - 파일 공개 설정 (makePublic) + - 팀 문서 coverImage 필드 업데이트 + - 권한: 팀 소유자만 +- **DELETE /api/team/[teamId]/cover-image**: 팀 커버 이미지 삭제 + - Storage에서 파일 삭제 + - 팀 문서 coverImage 필드 제거 + - 권한: 팀 소유자만 +- **TeamManager 메서드**: `uploadCoverImage()`, `deleteCoverImage()` +- **컴포넌트**: TeamCoverImageUploader (드래그앤드롭, 미리보기, AspectRatio 16:9) + +## ⚠️ 변경사항 (2025-11-26) ### 🔗 익명 계정 연결 기능 - **POST /api/auth/merge-account**: 익명 계정 데이터를 정식 계정으로 마이그레이션 @@ -861,6 +878,66 @@ await teamManager.removeMember(teamId, currentUser.uid); --- +### 🆕 17. POST `/team/:teamId/cover-image` - 팀 커버 이미지 업로드 +실제 URL: `POST /api/team/:teamId/cover-image` + +**설명**: 팀 커버 이미지를 Firebase Storage에 업로드하고 팀 문서를 업데이트합니다. + +**인증**: 필수 (팀 소유자만) + +**Request**: +```typescript +// FormData 형식 +{ + file: File; // 이미지 파일 (JPEG/PNG/WebP/GIF, 최대 5MB) +} +``` + +**Response**: +```typescript +{ + success: true, + data: { + coverImageUrl: string; // 업로드된 이미지의 공개 URL + } +} +``` + +**처리 로직**: +1. 파일 타입 검증 (JPEG/PNG/WebP/GIF만 허용) +2. 파일 크기 검증 (5MB 이하) +3. Firebase Storage 업로드 (`teams/{teamId}/cover-{timestamp}.{ext}`) +4. 파일 공개 설정 (`makePublic()`) +5. 기존 이미지가 있으면 Storage에서 삭제 +6. 팀 문서 `coverImage` 필드 업데이트 + +**캐시 무효화**: 해당 팀, 공개 팀 목록 + +--- + +### 🆕 18. DELETE `/team/:teamId/cover-image` - 팀 커버 이미지 삭제 +실제 URL: `DELETE /api/team/:teamId/cover-image` + +**설명**: 팀 커버 이미지를 Storage에서 삭제하고 팀 문서를 업데이트합니다. + +**인증**: 필수 (팀 소유자만) + +**Response**: +```typescript +{ + success: true +} +``` + +**처리 로직**: +1. 팀 문서에서 `coverImage` URL 조회 +2. Storage에서 파일 삭제 +3. 팀 문서 `coverImage` 필드 제거 + +**캐시 무효화**: 해당 팀, 공개 팀 목록 + +--- + ## Auth API ### POST `/auth/merge-account` - 익명 계정 데이터 병합 diff --git a/DATA_MODELS.md b/DATA_MODELS.md index c4a4b7a..62548e7 100644 --- a/DATA_MODELS.md +++ b/DATA_MODELS.md @@ -1,6 +1,6 @@ # 라온누리 - 데이터 모델 및 스키마 -> 최종 업데이트: 2025-11-18 (팀 코드 예약 시스템 + 다국어 생성) +> 최종 업데이트: 2025-11-27 (팀 커버 이미지 시스템) 이 문서는 Firestore 데이터베이스 및 Firebase Realtime Database 구조와 TypeScript 타입 정의를 설명합니다. @@ -106,17 +106,30 @@ interface TeamCodeReservation { ```typescript interface Team { id: string; // 문서 ID - code: string; // 팀 코드 (예: "춤추는파란사자") + code: string; // 팀 코드 (예: "춤추는 파란 사자") name: string; // 팀 이름 (예: "2학년 1반") - ownerId: string; // 팀 소유자 UID (정식 계정) + ownerId: string; // 팀 소유자 UID - // 보안 설정 - securityMode: 'simple' | 'normal' | 'open'; - requirePin: boolean; // PIN 입력 필요 여부 - allowAnonymousJoin: boolean; // 명단 없는 학생 자동 가입 허용 + // 보안 레벨 (5단계 시스템) + securityLevel: TeamSecurityLevel; // 1~5 (OPEN, NAME_LIST, AUTH_REQUIRED, EMAIL_LIST, CLOSED) - // 멤버 - studentIds: string[]; // students 컬렉션 참조 + // 명단 관리 + allowedNames?: string[]; // Level 2용: 허용된 이름 목록 + allowedEmails?: string[]; // Level 4용: 허용된 이메일 목록 + + // AI 글쓰기 도우미 설정 + aiAssistanceConfig?: AIAssistanceConfig; + + // 공개 설정 + isPublic?: boolean; // 팀 공개 여부 (기본: false) + allowPublicWritings?: boolean; // 외부 글 공개 허용 (기본: false) + description?: string; // 팀 소개 (공개 팀용) + coverImage?: string; // 🆕 팀 커버 이미지 URL (Firebase Storage) + + // 멤버 관리 (uid를 키로 사용) + members: { + [uid: string]: TeamMember; // 팀별 메타데이터 + }; // 타임스탬프 createdAt: Timestamp; @@ -125,31 +138,41 @@ interface Team { } ``` -### 보안 모드 +### 보안 레벨 (5단계) -| 모드 | requirePin | allowAnonymousJoin | 설명 | -|------|-----------|-------------------|------| -| `simple` | false | true | 팀 코드 + 이름 (초등 저학년) | -| `normal` | true | false | 팀 코드 + 이름 + PIN (보안 강화) | -| `open` | false | true | 누구나 자유롭게 참여 | +| Level | Enum | 이름 | 익명 허용 | 가입 제한 | 주요 사용처 | +|-------|------|------|-----------|-----------|------------| +| **1** | `OPEN` | 완전 개방 | ✅ | 닉네임 공유 로그인 | 공개 워크샵, 체험 수업 | +| **2** | `NAME_LIST` | 명단 기반 | ✅ | `allowedNames` 체크 | 저학년 반 (익명이지만 통제) | +| **3** | `AUTH_REQUIRED` | 로그인 필수 | ❌ | 정식 계정 누구나 | 고학년 반 (구글 계정) ⭐ 추천 | +| **4** | `EMAIL_LIST` | 이메일 제한 | ❌ | `allowedEmails` 체크 | 특정 학생만 (전학생 차단) | +| **5** | `CLOSED` | 닫힌 팀 | ❌ | 신규 가입 차단 | 졸업반, 종료된 프로젝트 | ### 예시 데이터 ```json { "id": "team_abc123", - "code": "춤추는파란사자", + "code": "춤추는 파란 사자", "name": "2학년 1반", - "ownerId": "teacher_xyz", + "ownerId": "user_xyz", - "securityMode": "simple", - "requirePin": false, - "allowAnonymousJoin": true, + "securityLevel": 3, + "isPublic": true, + "allowPublicWritings": false, + "description": "창의적인 글쓰기를 배우는 우리 반입니다!", + "coverImage": "https://storage.googleapis.com/raonnuri-84830.firebasestorage.app/teams/team_abc123/cover-1732688400000.png", - "studentIds": ["student_001", "student_002", "student_003"], + "members": { + "user_001": { + "joinedAt": "2024-11-06T00:00:00Z", + "role": "member", + "nickname": "춤추는 작가" + } + }, "createdAt": "2024-11-06T00:00:00Z", - "updatedAt": "2024-11-07T10:00:00Z", + "updatedAt": "2024-11-27T10:00:00Z", "isActive": true } ``` diff --git a/NEXT_TASKS.md b/NEXT_TASKS.md new file mode 100644 index 0000000..c02009f --- /dev/null +++ b/NEXT_TASKS.md @@ -0,0 +1,285 @@ +# 다음 작업 계획 + +> 작성일: 2025-11-25 +> Phase 1 마무리 및 기능 고도화 + +--- + +## ✅ 최근 완료된 작업 + +- **글 분석 및 상호작용 기능** (2025-11-25) + - `/api/writing/[id]/analyze` API 추가 + - 글 분석 결과에 따른 상호작용 컴포넌트 추가 (`components/interaction/*`) + - 점수 기반 영역 해금 로직 (`utils/areaLimit.ts`) +- **이미지 왜곡 영역 기능** (2025-11-25) + - `DistortionAreaData` 모델 추가 + - `InteractiveImageViewer` 컴포넌트 추가 + - 글 수정 시 왜곡 영역 저장 지원 +- **팀 멤버 닉네임 추가** (2025-11-25) + - `POST /api/team/add-member`에 닉네임 파라미터 추가 + +--- + +## 🔴 최우선 작업 (오늘~내일) + +### 1. Firebase Security Rules 작성 및 배포 ⚡ (30분) + + +**현재 문제**: Firestore에 보안 규칙이 없어 누구나 모든 데이터 접근 가능 💥 + +**작업 내용**: +``` +1. firestore.rules 파일 생성 +2. 컬렉션별 규칙 작성: + - users: 본인만 수정 가능 + - teams: 소유자만 수정, 멤버는 읽기 + - writings: 본인만 CRUD + - topics: 소유자만 수정 + - patternAnalyses: 읽기 전용 (캐시용) +3. Firebase Console에 배포 +4. 테스트 (권한 없는 접근 차단 확인) +``` + +**우선순위**: 🔴 높음 (보안 필수) + +--- + +### 2. Level 1 실제 작동 테스트 🧪 (30분) + +**목적**: 구현한 UID 기반 중복 체크 로직 검증 + +**테스트 시나리오**: + +#### 시나리오 A: 첫 로그인 +``` +1. npm run dev +2. Level 1 팀 생성 (완전 개방) +3. 로그아웃 (또는 시크릿 모드) +4. 팀 코드 입력 → "철수" 입력 +5. 예상: 새 익명 계정 생성 ✅ +6. 확인: /team/{teamId} 페이지에서 멤버 확인 +``` + +#### 시나리오 B: 재로그인 (핵심) +``` +1. 로그아웃 +2. 동일 팀 코드 → "철수" 입력 +3. 예상: Custom Token으로 기존 계정 로그인 ✅ +4. 확인: 이전 글이 그대로 있는지 확인 +``` + +#### 시나리오 C: 다른 브라우저 (중요) +``` +1. 다른 브라우저 또는 시크릿 모드 +2. 동일 팀 코드 → "철수" 입력 +3. 예상: 동일 계정으로 로그인 ✅ +4. 확인: 크로스 디바이스 로그인 작동 +``` + +#### 시나리오 D: 정식 계정 이름 중복 (보안) +``` +1. Google 로그인 → 팀 가입 → 닉네임 "영희" +2. 로그아웃 +3. 비로그인 상태에서 "영희" 입력 +4. 예상: "이미 사용 중인 이름입니다" 에러 ✅ +5. 확인: 정식 계정 탈취 방지 +``` + +#### 시나리오 E: 로그인 상태에서 중복 +``` +1. "철수"로 로그인된 상태 +2. 팀 참여 시도 → "철수" 입력 +3. 예상: "이미 이 팀에 가입되어 있습니다" 에러 ✅ +``` + +**우선순위**: 🔴 높음 (복잡한 로직, 검증 필수) + +**예상 버그**: +- Custom Token API 경로 오류 가능성 +- 에러 메시지 번역 누락 가능성 +- Firebase Admin SDK 권한 문제 + +--- + +### 3. 코드 정리 및 최적화 🧹 (30분) + +**체크리스트**: +``` +□ console.log 제거 또는 조건부 처리 (process.env.NODE_ENV === 'development') +□ 사용하지 않는 import 제거 +□ TODO 코멘트 확인 및 처리 +□ 중복 코드 리팩토링 +□ 불필요한 any 타입 제거 +□ ESLint 경고 수정 +``` + +**대상 파일**: +- `src/services/firebaseAuth.ts` (많은 로그) +- `src/components/auth/StudentLoginFlow.tsx` +- `src/managers/WritingSessionManager.ts` (디버그 로그) + +**우선순위**: 🟡 중간 + +--- + +## 🟡 이번 주 완료 목표 + +### 4. 에러 처리 개선 (1시간) + +**작업 내용**: + +#### A. 전역 에러 바운더리 +```tsx +// src/app/[locale]/error.tsx 생성 +'use client'; + +export default function Error({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + return ( + + + 오류가 발생했습니다 + {error.message} + + + + ); +} +``` + +#### B. 404 페이지 개선 +```tsx +// src/app/[locale]/not-found.tsx 개선 +// 현재: 없음 +// 추가: 사용자 친화적 디자인, 홈으로 돌아가기 +``` + +#### C. API 에러 통합 처리 +```typescript +// src/utils/apiErrorHandler.ts 생성 +// 일관된 에러 토스트 표시 +``` + +**우선순위**: 🟡 중간 + +--- + +### 5. 성능 최적화 체크 (30분) + +**체크 항목**: +``` +□ React DevTools Profiler로 불필요한 리렌더링 확인 +□ 번들 크기 분석 (npm run build 후 확인) +□ 이미지 최적화 (Next.js Image 사용) +□ Lighthouse 점수 측정 (목표: 90+) +□ 초기 로딩 속도 (목표: 2초 이내) +``` + +**예상 개선점**: +- WritingEditor 메모이제이션 +- 큰 컴포넌트 lazy loading +- 사용하지 않는 라이브러리 제거 + +**우선순위**: 🟡 중간 + +--- + +### 6. Phase 1 문서 최종 검토 (30분) + +**체크리스트**: +``` +□ CLAUDE.md - 최신 정보 반영 확인 +□ PROJECT_STRUCTURE.md - 모든 파일 반영 +□ ROADMAP.md - 완료 항목 이동 +□ API_SPEC.md - 모든 엔드포인트 문서화 +□ README.md - 설치/실행 가이드 확인 +□ DATA_MODELS.md - 스키마 최신화 +``` + +**우선순위**: 🟢 낮음 + +--- + +## 🟢 다음 주 시작 작업 + +### 옵션 A: Phase 2 - 학습 시스템 설계 + +#### 7. 학습 페이지 설계 (2-3시간) +``` +1. /learn 페이지 와이어프레임 +2. Lesson 데이터 모델 설계: + - id, title, content, category, difficulty + - prerequisites (선수 레슨) + - quizzes (연습 문제) + - completionCriteria +3. UI 컴포넌트 설계: + - LessonCard (썸네일, 제목, 난이도) + - LessonContent (이론, 예시) + - QuizSection (문제 풀이) + - ProgressBar (진행률) +``` + +#### 8. 첫 레슨 콘텐츠 작성 (1-2시간) +``` +예시: "문장 만들기 첫걸음" +- 이론: 주어와 서술어 +- 예시: "나는 달린다", "고양이가 잔다" +- 연습: 주어를 고르세요 (4지선다) +- 평가: 문장 3개 만들기 +``` + +--- + +### 옵션 B: 베타 테스트 준비 + +#### 9. 베타 테스터 모집 (1주일) +``` +1. 초등학교 선생님 1-2명 섭외 +2. 테스트 계정 준비 +3. 사용 가이드 작성 +4. 피드백 수집 양식 준비 (Google Forms) +``` + +#### 10. 실제 수업 시나리오 테스트 +``` +시나리오: 초등 2학년 반 (25명) +1. 선생님이 팀 생성 (Level 2, 명단 등록) +2. 학생들 팀 코드로 로그인 +3. 팀 주제 "오늘의 날씨" 작성 +4. 선생님 실시간 모니터링 +5. 피드백 수집 +``` + +--- + +## 💡 제 최종 추천 순서 + +### 오늘 (1.5시간): +1. **Firebase Security Rules** (30분) ⚡ 최우선 +2. **Level 1 테스트** (30분) 🧪 검증 필수 +3. **코드 정리** (30분) 🧹 품질 확보 + +### 내일 (선택): +4. **에러 처리 개선** (1시간) - Phase 1 완성도 +5. **성능 최적화** (30분) - 사용자 경험 + +### 다음 주 (선택 1개): +- **옵션 A**: Phase 2 시작 (학습 시스템) - 기능 확장 +- **옵션 B**: 베타 테스트 준비 - 실사용 피드백 + +--- + +## 📋 작업 선택 가이드 + +**빠른 출시를 원하면**: Firebase Rules → 테스트 → 베타 테스트 +**기능을 더 만들고 싶으면**: Firebase Rules → 테스트 → Phase 2 시작 +**코드 품질 우선이면**: 코드 정리 → 에러 처리 → 성능 최적화 + +--- + +어떤 작업부터 시작할까요? \ No newline at end of file diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md index 4159595..d034d4f 100644 --- a/PROJECT_STRUCTURE.md +++ b/PROJECT_STRUCTURE.md @@ -1,10 +1,54 @@ # 라온누리 - 프로젝트 구조 -> 최종 업데이트: 2025-11-22 (Server Component 전환 + 공통 컴포넌트) +> 최종 업데이트: 2025-11-27 (채점 시스템 개편) 초등학생을 위한 창작 글쓰기 교육 플랫폼 -**최신 업데이트** (2025-11-22): +**최신 업데이트** (2025-11-27 PM-2): +- 📊 **채점 시스템 전면 개편** + - **0~1 품질 기반 점수**: 기존 "표현 1개당 1점" → 5단계 품질 평가 (0, 0.25, 0.5, 0.75, 1.0) + - **가중 평균 0~100점**: 최종 점수 = Σ(영역 점수 × 가중치) × 100 + - **계층적 설정**: 기본값 → 팀 설정 → 주제 설정 (우선순위 오버라이드) + - **타입 시스템**: `ScoringConfig`, `ScoringWeights`, `ScoringRubric`, `AreaRubric` + - **설정 병합 서비스**: `scoringConfigService.ts` (mergeScoringConfig 함수) + - **AI 일관성**: temperature=0 설정으로 점수 결정론적 출력 + - **TeamScoringSettings 컴포넌트**: 4개 영역 가중치 슬라이더 (합계 100% 검증) + - **TeamRubricSettings 컴포넌트**: 5단계 채점 기준 직접 편집 (아코디언 UI) + - **팀 관리 페이지 통합**: AI 설정 → 채점 가중치 → 채점 기준 순서 + - **다국어 지원**: `team.manage.scoring.*`, `team.manage.rubric.*` (ko/en/ja) + - **UI 컴포넌트 업데이트**: ScoreBadge (0~100), ImprovementHint (퍼센트 표시) + +**최신 업데이트** (2025-11-27 PM): +- 🖼️ **팀 커버 이미지 시스템 추가** + - **Team 타입 확장**: `coverImage?: string` 필드 추가 + - **Firebase Storage 업로드**: 이미지 → Storage → 공개 URL + - **TeamCoverImageUploader 컴포넌트**: 드래그앤드롭 지원, 미리보기 + - **API Route**: POST/DELETE `/api/team/[teamId]/cover-image` + - **TeamManager 메서드**: `uploadCoverImage()`, `deleteCoverImage()` + - **팀 생성**: 생성 시 이미지 선택 가능 (선택적) + - **팀 관리**: 공개 설정에서 이미지 즉시 업로드/삭제 + - **TeamCard 표시**: 커버 이미지가 있으면 카드 상단에 140px 높이로 표시 + - **다국어 지원**: `team.coverImage.*` (ko, en, ja) + - **이미지 제한**: JPEG/PNG/WebP/GIF, 최대 5MB, 16:9 권장 + +**최신 업데이트** (2025-11-27 AM): +- 🌐 **글 공개 범위 시스템 추가** + - **WritingVisibility enum**: PUBLIC (전체 공개), TEAM (팀 내 공개), PRIVATE (비공개) + - **VisibilitySelector 컴포넌트**: 글 저장 시 공개 범위 선택 + - **VisibilityBadge 컴포넌트**: 글 목록에서 공개 범위 표시 +- 🏢 **팀 공개 설정 추가** + - **Team 타입 확장**: `isPublic`, `allowPublicWritings`, `description` 필드 + - **공개 설정 UI**: 팀 관리 페이지에서 공개/비공개 전환 +- 📋 **공개 팀 목록 페이지** (`/team/all`) + - **TeamCard 컴포넌트**: 글래스모피즘 스타일 팀 카드 + - **페이지네이션**: 커서 기반 무한 스크롤 + - **Navbar 메뉴 추가**: "공개 팀" 링크 +- 🔀 **팀 상세 페이지 통합** (`/team/[teamId]`) + - **멤버 뷰**: 멤버 목록, 관리/나가기 버튼 + - **공개 뷰**: 팀 정보, 공개 글 목록, 참여 버튼 + - **비공개 팀**: 접근 불가 메시지 + +**업데이트** (2025-11-22): - 🔄 **글 상세보기 페이지 Server Component 전환** - **SEO 최적화**: 서버에서 HTML 생성 (검색엔진 크롤링 가능) - **SNS 공유 미리보기**: 카카오톡/페이스북 링크 미리보기 지원 @@ -253,10 +297,11 @@ | **글 상세보기** | `/[locale]/writing/[writingId]` | 🆕 **Server Component 기반 상세 페이지** | 🆕 **SEO 최적화** (서버에서 HTML 생성)
🆕 **SNS 공유 미리보기** (카카오톡/페이스북)
🆕 **서버 데이터 로딩** (Firebase Admin SDK)
제목, 내용, 생성된 이미지 표시
주제 및 팀 정보 Badge
프롬프트 Collapsible
🆕 **CommentList** (Client Component)
🆕 **BackButton** 공통 컴포넌트 사용 | ✅ 완료 | | **글쓰기** | `/[locale]/write` | Tiptap 기반 순수 텍스트 에디터 + 주제 선택 | 주제 선택 (자유 주제/개인 주제/팀 주제)
🆕 **글 수정 기능 (URL params ?id=xxx)**
🆕 **수정 모드 배지 표시**
🆕 **주제 변경 경고** (작성 중 내용 초기화 알림, 임시 저장 안내)
제목 입력 (Editable), 순수 텍스트 에디터 (포맷팅 없음)
🆕 **다중 글조각 관리** (최대 10개), "새 글쓰기" / "저장된 글조각" 버튼
🆕 **강화된 자동 저장** (2초 debounce, 저장 상태 표시: 저장 중/저장됨)
🆕 **저장 시 AI 분석** (실시간 분석 제거, 저장 버튼 클릭 시 분석 수행)
🆕 **분석 결과 DB 저장** (WritingAnalysis + spellingErrors + contentHash)
템플릿 미리채우기 (제목/내용), Firestore 저장
비로그인도 접근 가능 (저장 시 로그인 유도) | ✅ 완료 | | **테스트** | `/[locale]/test` | 팀 코드 시스템 테스트 페이지 | 팀 코드 생성/검증 테스트
팀/학생 생성 테스트
학생 로그인 테스트
authStore 상태 확인 | 🔜 예정 | -| **팀 목록** | `/[locale]/team` | 내가 만든 팀 목록 (정식 계정 전용) | 팀 카드 그리드, 팀 정보 (코드, 멤버 수, 보안 설정)
"새 팀 만들기" 버튼 | 🔜 예정 | -| **팀 생성** | `/[locale]/team/create` | 새 팀 만들기 (정식 계정 전용) | 팀 이름 입력, 팀 코드 자동 생성
🆕 **5단계 보안 레벨 선택** (RadioCard, 애니메이션)
🆕 **명단 관리 (Level 2/4)**: TagsInput으로 Enter/쉼표 입력
생성 후 `/team/[teamId]`로 이동 | 🔜 예정 | -| **팀 멤버 페이지** | `/[locale]/team/[teamId]` | 팀 멤버용 페이지 (멤버/소유자 모두 접근) | 팀 정보, 팀 코드 복사, 멤버 목록
소유자는 "팀 관리" 버튼 표시
팀 코드 로그인 후 기본 이동 페이지 | 🔜 예정 | -| **팀 관리** | `/[locale]/team/[teamId]/manage` | 팀 관리 페이지 (소유자 전용) | 팀 정보 및 코드, 보안 설정 표시
**팀 주제 관리 (생성/삭제)**
🆕 **주제별 학생 분석** (TopicMemberAnalysisSection)
멤버 목록 및 관리
🆕 **멤버 메뉴 - 팀 내 글 분석** (by-team)
"멤버 페이지 보기" 버튼 | 🔜 예정 | +| **공개 팀 목록** | `/[locale]/team/all` | 🆕 **공개 팀 둘러보기** | 🆕 **공개된 팀 목록 표시** (isPublic=true)
🆕 **TeamCard 그리드** (글래스모피즘)
🆕 **페이지네이션** (커서 기반)
🆕 **Navbar "공개 팀" 메뉴** | ✅ 완료 | +| **내 팀 목록** | `/[locale]/team` | 내가 만든/참여한 팀 목록 (정식 계정 전용) | 팀 카드 그리드, 팀 정보 (코드, 멤버 수, 보안 설정)
"새 팀 만들기" 버튼 | ✅ 완료 | +| **팀 생성** | `/[locale]/team/create` | 새 팀 만들기 (정식 계정 전용) | 팀 이름 입력, 팀 코드 자동 생성
🆕 **5단계 보안 레벨 선택** (RadioCard, 애니메이션)
🆕 **명단 관리 (Level 2/4)**: TagsInput으로 Enter/쉼표 입력
생성 후 `/team/[teamId]`로 이동 | ✅ 완료 | +| **팀 상세 (통합)** | `/[locale]/team/[teamId]` | 🆕 **멤버/공개 뷰 통합 페이지** | 🆕 **멤버인 경우**: 멤버 목록, 관리/나가기 버튼
🆕 **비멤버 + 공개 팀**: 팀 정보, 공개 글 목록, 참여 버튼
🆕 **비멤버 + 비공개 팀**: 접근 불가 메시지
팀 코드 로그인 후 기본 이동 페이지 | ✅ 완료 | +| **팀 관리** | `/[locale]/team/[teamId]/manage` | 팀 관리 페이지 (소유자 전용) | 팀 정보 및 코드, 보안 설정 표시
🆕 **팀 공개 설정** (isPublic, allowPublicWritings, description)
**팀 주제 관리 (생성/삭제)**
🆕 **주제별 학생 분석** (TopicMemberAnalysisSection)
멤버 목록 및 관리
🆕 **멤버 메뉴 - 팀 내 글 분석** (by-team)
"멤버 페이지 보기" 버튼 | ✅ 완료 | ### 🚧 구현 예정 @@ -406,6 +451,9 @@ | **GenerateImageDialog** | `GenerateImageDialog.tsx` | 🆕 **AI 이미지 생성 Dialog** (4단계 플로우: 장면 추출 → 장면 선택 → 이미지 생성 → 결과 표시) | ✅ 완료 | | **SceneSelector** | `SceneSelector.tsx` | 🆕 **장면 선택 컴포넌트** (RadioCard 기반, 이모지 표시, 원문 미리보기) | ✅ 완료 | | **WritingCard** | `WritingCard.tsx` | 🆕 **글 카드 컴포넌트** (제목, 날짜, 미리보기, 주제/점수/이미지 배지, 메뉴, 삭제) | ✅ 완료 | +| **PublicWritingCard** | `PublicWritingCard.tsx` | 🆕 **공개 글 카드** (제목, 공개 범위 배지, 미리보기, 날짜) | ✅ 완료 | +| **VisibilitySelector** | `VisibilitySelector.tsx` | 🆕 **공개 범위 선택** (PUBLIC/TEAM/PRIVATE, RadioCard 기반) | ✅ 완료 | +| **VisibilityBadge** | `VisibilityBadge.tsx` | 🆕 **공개 범위 배지** (아이콘 + 라벨, 색상별 구분) | ✅ 완료 | | **InteractiveImageViewer** | `InteractiveImageViewer.tsx` | 🆕 **인터랙티브 이미지 뷰어** (왜곡 효과, 애니메이션, 오디오 반응) | ✅ 완료 | | **GenerateImageDialog** | `GenerateImageDialog.tsx` | 🆕 **AI 이미지 생성 Dialog** (4단계 플로우: 장면 추출 → 장면 선택 → 이미지 생성 → 결과 표시) | ✅ 완료 | | ~~**ScoreDisplay**~~ | ~~`ScoreDisplay.tsx`~~ | ~~실시간 피드백 점수 표시~~ | ❌ 삭제됨 (하이라이트로 대체) | @@ -494,6 +542,8 @@ | 컴포넌트 | 파일명 | 설명 | 상태 | |---------|--------|------|------| +| **TeamCard** | `TeamCard.tsx` | 🆕 **공개 팀 카드** (글래스모피즘, 보안 레벨 배지, 멤버 수, 🆕 커버 이미지 표시) | ✅ 완료 | +| **TeamCoverImageUploader** | `TeamCoverImageUploader.tsx` | 🆕 **팀 커버 이미지 업로더** (드래그앤드롭, 미리보기, 16:9 AspectRatio, 5MB 제한) | ✅ 완료 | | **TeamTopicManager** | `TeamTopicManager.tsx` | 팀 주제 목록 및 생성/삭제 UI | ✅ 완료 | | **AIConfigDialog** | `AIConfigDialog.tsx` | 🆕 **AI 도우미 고급 설정 Dialog** (Slider, 커스텀 CheckboxCard) | ✅ 완료 | | **SecurityLevelSelector** | `SecurityLevelSelector.tsx` | 5단계 보안 레벨 선택 (RadioCard, framer-motion 애니메이션) | ✅ 완료 | diff --git a/ROADMAP.md b/ROADMAP.md index 95c681b..6b6b5d2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,6 @@ # 라온누리 - 개발 로드맵 -> 최종 업데이트: 2025-11-22 (Server Component 전환) +> 최종 업데이트: 2025-11-27 (채점 시스템 개편) 초등학생을 위한 창작 글쓰기 교육 플랫폼 개발 계획 @@ -116,6 +116,13 @@ | **미사용 코드 정리** | **koreanWordList.ts 삭제 (AI 분석으로 대체), InteractiveImage.tsx 삭제 (InteractiveImageViewer로 대체), AllowListManager.tsx 삭제 (미통합), 관련 문서 업데이트** | **2025-11-26** | | **팀 페이지 리팩토링** | **useTeamData 훅 생성 (팀 + 멤버 로딩, 권한 체크, refreshMembers), 팀 페이지 중복 코드 제거 (~200줄 절감), 각 하위 컴포넌트 자체 로딩 스켈레톤 활용** | **2025-11-26** | | **익명 계정 연결 기능** | **POST /api/auth/merge-account API (Firestore + Realtime DB 데이터 마이그레이션), mergeAndLoginWithEmail/mergeAndLoginWithGoogle 함수 (firebaseAuth.ts), mergeWithEmail/mergeWithGoogle 액션 (authStore.ts), LoginForm/SignupForm mode prop 추가 ('auth'\|'link'), LoginDialog link 모드 지원 (3개 소셜 버튼 표시), LinkAccountFlow 삭제 (기존 폼 재사용), 용어 변경 ("병합" → "연결", "익명" → "임시"), 다국어 지원 (linkAccountDescription, naverMerge/kakaoMerge/googleMerge, mergeButton/linkButton, ko/en/ja 15개 키)** | **2025-11-26** | +| **글 공개 범위 시스템** | **WritingVisibility enum 추가 (PUBLIC/TEAM/PRIVATE), VisibilitySelector 컴포넌트 (글 저장 시 공개 범위 선택), VisibilityBadge 컴포넌트 (글 목록에서 공개 범위 표시), Writing 타입 확장 (visibility 필드), 기본값 PRIVATE, 공개 범위별 조회 API 추가, 다국어 지원 (ko/en/ja)** | **2025-11-27** | +| **팀 공개 설정 시스템** | **Team 타입 확장 (isPublic, allowPublicWritings, description 필드), 팀 관리 페이지에 공개 설정 UI 추가, 공개 팀 조회 API (getPublicTeams, 커서 기반 페이지네이션), 공개 글 조회 API (팀별 공개 글 목록), 다국어 지원 (team.manage.publicSettings namespace, ko/en/ja)** | **2025-11-27** | +| **공개 팀 목록 페이지** | **/team/all 페이지 구현, TeamCard 컴포넌트 (글래스모피즘 스타일), 페이지네이션 (커서 기반 무한 스크롤), Navbar "공개 팀" 메뉴 추가, 공개 팀만 표시 (isPublic=true), 다국어 지원 (teams namespace, ko/en/ja)** | **2025-11-27** | +| **팀 상세 페이지 통합** | **/team/[teamId] 페이지 완전 재구성, 3가지 뷰 모드 (멤버 뷰/공개 뷰/접근 불가), 멤버 뷰: 멤버 목록 + 관리/나가기 버튼, 공개 뷰: 팀 정보 + 공개 글 목록 + 참여 버튼, PublicWritingCard 컴포넌트, 다국어 지원** | **2025-11-27** | +| **팀 커버 이미지 시스템** | **Team 타입 확장 (coverImage?: string), Firebase Storage 업로드 (adminStorage.bucket()), TeamCoverImageUploader 컴포넌트 (드래그앤드롭, 미리보기, AspectRatio 16:9, 5MB 제한 JPEG/PNG/WebP/GIF), POST/DELETE /api/team/[teamId]/cover-image (FormData 업로드, 기존 이미지 자동 삭제, makePublic, extractPathFromUrl 헬퍼), TeamManager 메서드 (uploadCoverImage, deleteCoverImage, fetch FormData, 캐시 무효화), 팀 생성 페이지 이미지 선택 (선택적), 팀 관리 페이지 즉시 업로드/삭제 (공개 설정 내), TeamCard 표시 (이미지 있으면 상단 140px, 그라데이션 오버레이), 다국어 지원 (team.coverImage namespace 16개 키, ko/en/ja)** | **2025-11-27** | +| **팀 멤버 아바타 표시 개선** | **Avatar 컴포넌트 도입 (photoURL 표시), 익명 계정 LuUser 아이콘 + gray 색상, 정식 계정 FaUserGraduate 아이콘 + teal 색상, "정식계정/익명" 텍스트 표시 제거, 닉네임과 실명이 다른 경우만 실명 이탤릭 표시** | **2025-11-27** | +| **채점 시스템 전면 개편** | **0~1 품질 기반 점수 (5단계: 0, 0.25, 0.5, 0.75, 1.0), 가중 평균 0~100점 변환, 계층적 설정 (기본→팀→주제 우선순위), ScoringConfig/ScoringWeights/ScoringRubric 타입, scoringConfigService.ts (설정 병합), temperature=0 일관성, TeamScoringSettings 컴포넌트 (가중치 슬라이더), TeamRubricSettings 컴포넌트 (5단계 기준 편집, 아코디언 UI), 팀 관리 페이지 통합, 다국어 지원 (ko/en/ja)** | **2025-11-27** | ### 🚧 진행 중 diff --git a/TECH_STACK.md b/TECH_STACK.md index 73defaf..0ed17d0 100644 --- a/TECH_STACK.md +++ b/TECH_STACK.md @@ -1,6 +1,6 @@ # 라온누리 - 기술 스택 및 개발 환경 -> 최종 업데이트: 2025-11-21 (홈 페이지 모듈화) +> 최종 업데이트: 2025-11-27 (채점 시스템 개편) --- @@ -35,6 +35,7 @@ | **Firebase Auth** | - | 사용자 인증 | | **Firestore** | - | NoSQL 데이터베이스 (글 저장) | | **Firebase Realtime Database** | - | 🆕 **실시간 데이터 동기화** (글쓰기 모니터링) | +| **Firebase Storage** | - | 🆕 **파일 저장소** (팀 커버 이미지, AI 생성 이미지) | | **@google/genai** | 1.29.0 | Google Gemini API SDK (텍스트 분석, 맞춤법 검사) | | **Redis** | - | Cache 데이터 베이스 (예정) | @@ -42,6 +43,7 @@ - **Gemini 2.5 Flash-Lite**: 텍스트 분석 (오감/감정/대화/의성어 평가, Delta 전송) - **Gemini 2.5 Flash-Lite**: 맞춤법 검사 (초등학생 눈높이) - **Gemini 2.5 Flash-Lite**: 글 작성 패턴 분석 (최근 10개 글 종합 분석, AI 평가 및 맞춤형 추천) +- **Vertex AI Imagen 4.0 Fast**: 이미지 생성 (글 장면 시각화, 일관된 애니메이션 스타일) - **Vertex AI 모드**: Multi-region failover 지원 (`vertexai: true`) - **Response Schema**: JSON 응답 강제 (`Type.OBJECT`, `Type.ARRAY` 등) @@ -197,7 +199,8 @@ NEXT_PUBLIC_API_URL=/api content: string; // HTML wordCount: number; charCount: number; - analysis?: { // 🆕 AI 분석 결과 (저장 시 자동 생성) + visibility: WritingVisibility; // 🆕 PUBLIC | TEAM | PRIVATE (기본: PRIVATE) + analysis?: { // AI 분석 결과 (저장 시 자동 생성) score: number; breakdown: { sensory, emotion, dialogue, onomatopoeia }; foundWords: { sensory[], emotion[], onomatopoeia[] }; @@ -211,6 +214,7 @@ NEXT_PUBLIC_API_URL=/api createdAt: Timestamp; updatedAt: Timestamp; } + // 🆕 WritingVisibility enum: PUBLIC (전체 공개), TEAM (팀 내 공개), PRIVATE (비공개) ``` - `topics/` ✅ - 글쓰기 주제 (팀 주제 + 개인 주제) ```typescript @@ -243,6 +247,10 @@ NEXT_PUBLIC_API_URL=/api securityMode: 'simple' | 'normal' | 'open'; requirePin: boolean; allowAnonymousJoin: boolean; + // 🆕 공개 설정 + isPublic: boolean; // 팀 공개 여부 (기본: false) + allowPublicWritings: boolean; // 팀원 글 공개 허용 (기본: false) + description?: string; // 팀 소개 (공개 팀용) createdAt: Timestamp; updatedAt: Timestamp; isActive: boolean; @@ -1043,9 +1051,10 @@ interface Draft { #### 참고 파일 **서비스 레이어**: -- `src/services/vertexAI.ts` - Gemini API 범용 래퍼 (`@google/genai`) -- `src/services/textAnalysisService.ts` - 텍스트 분석 (히스토리 기반) -- `src/services/spellingService.ts` - 🆕 맞춤법 검사 (독립적) +- `src/services/vertexAI.ts` - Gemini API 범용 래퍼 (`@google/genai`, temperature=0) +- `src/services/textAnalysisService.ts` - 텍스트 분석 (히스토리 기반, 가중 평균 점수 계산) +- `src/services/scoringConfigService.ts` - 🆕 채점 설정 병합 (기본→팀→주제 우선순위) +- `src/services/spellingService.ts` - 맞춤법 검사 (독립적) - `src/services/regionHealthManager.ts` - Region 상태 관리 **API & 컴포넌트**: