docs: Sync documentation from private repository

This commit is contained in:
Documentation Bot 2025-11-27 08:40:46 +00:00
parent 85b1c3fbe3
commit 04d199c64a
6 changed files with 486 additions and 35 deletions

View File

@ -2,7 +2,24 @@
라온누리 서버 API 명세서 라온누리 서버 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**: 익명 계정 데이터를 정식 계정으로 마이그레이션 - **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 ## Auth API
### POST `/auth/merge-account` - 익명 계정 데이터 병합 ### POST `/auth/merge-account` - 익명 계정 데이터 병합

View File

@ -1,6 +1,6 @@
# 라온누리 - 데이터 모델 및 스키마 # 라온누리 - 데이터 모델 및 스키마
> 최종 업데이트: 2025-11-18 (팀 코드 예약 시스템 + 다국어 생성) > 최종 업데이트: 2025-11-27 (팀 커버 이미지 시스템)
이 문서는 Firestore 데이터베이스 및 Firebase Realtime Database 구조와 TypeScript 타입 정의를 설명합니다. 이 문서는 Firestore 데이터베이스 및 Firebase Realtime Database 구조와 TypeScript 타입 정의를 설명합니다.
@ -108,15 +108,28 @@ interface Team {
id: string; // 문서 ID id: string; // 문서 ID
code: string; // 팀 코드 (예: "춤추는 파란 사자") code: string; // 팀 코드 (예: "춤추는 파란 사자")
name: string; // 팀 이름 (예: "2학년 1반") name: string; // 팀 이름 (예: "2학년 1반")
ownerId: string; // 팀 소유자 UID (정식 계정) ownerId: string; // 팀 소유자 UID
// 보안 설정 // 보안 레벨 (5단계 시스템)
securityMode: 'simple' | 'normal' | 'open'; securityLevel: TeamSecurityLevel; // 1~5 (OPEN, NAME_LIST, AUTH_REQUIRED, EMAIL_LIST, CLOSED)
requirePin: boolean; // PIN 입력 필요 여부
allowAnonymousJoin: boolean; // 명단 없는 학생 자동 가입 허용
// 멤버 // 명단 관리
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; createdAt: Timestamp;
@ -125,13 +138,15 @@ interface Team {
} }
``` ```
### 보안 모드 ### 보안 레벨 (5단계)
| 모드 | requirePin | allowAnonymousJoin | 설명 | | Level | Enum | 이름 | 익명 허용 | 가입 제한 | 주요 사용처 |
|------|-----------|-------------------|------| |-------|------|------|-----------|-----------|------------|
| `simple` | false | true | 팀 코드 + 이름 (초등 저학년) | | **1** | `OPEN` | 완전 개방 | ✅ | 닉네임 공유 로그인 | 공개 워크샵, 체험 수업 |
| `normal` | true | false | 팀 코드 + 이름 + PIN (보안 강화) | | **2** | `NAME_LIST` | 명단 기반 | ✅ | `allowedNames` 체크 | 저학년 반 (익명이지만 통제) |
| `open` | false | true | 누구나 자유롭게 참여 | | **3** | `AUTH_REQUIRED` | 로그인 필수 | ❌ | 정식 계정 누구나 | 고학년 반 (구글 계정) ⭐ 추천 |
| **4** | `EMAIL_LIST` | 이메일 제한 | ❌ | `allowedEmails` 체크 | 특정 학생만 (전학생 차단) |
| **5** | `CLOSED` | 닫힌 팀 | ❌ | 신규 가입 차단 | 졸업반, 종료된 프로젝트 |
### 예시 데이터 ### 예시 데이터
@ -140,16 +155,24 @@ interface Team {
"id": "team_abc123", "id": "team_abc123",
"code": "춤추는 파란 사자", "code": "춤추는 파란 사자",
"name": "2학년 1반", "name": "2학년 1반",
"ownerId": "teacher_xyz", "ownerId": "user_xyz",
"securityMode": "simple", "securityLevel": 3,
"requirePin": false, "isPublic": true,
"allowAnonymousJoin": 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", "createdAt": "2024-11-06T00:00:00Z",
"updatedAt": "2024-11-07T10:00:00Z", "updatedAt": "2024-11-27T10:00:00Z",
"isActive": true "isActive": true
} }
``` ```

285
NEXT_TASKS.md Normal file
View File

@ -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 (
<Box minH="100vh" display="flex" alignItems="center" justifyContent="center">
<VStack>
<Heading>오류가 발생했습니다</Heading>
<Text>{error.message}</Text>
<Button onClick={reset}>다시 시도</Button>
</VStack>
</Box>
);
}
```
#### 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 시작
**코드 품질 우선이면**: 코드 정리 → 에러 처리 → 성능 최적화
---
어떤 작업부터 시작할까요?

View File

@ -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 전환** - 🔄 **글 상세보기 페이지 Server Component 전환**
- **SEO 최적화**: 서버에서 HTML 생성 (검색엔진 크롤링 가능) - **SEO 최적화**: 서버에서 HTML 생성 (검색엔진 크롤링 가능)
- **SNS 공유 미리보기**: 카카오톡/페이스북 링크 미리보기 지원 - **SNS 공유 미리보기**: 카카오톡/페이스북 링크 미리보기 지원
@ -253,10 +297,11 @@
| **글 상세보기** | `/[locale]/writing/[writingId]` | 🆕 **Server Component 기반 상세 페이지** | 🆕 **SEO 최적화** (서버에서 HTML 생성)<br>🆕 **SNS 공유 미리보기** (카카오톡/페이스북)<br>🆕 **서버 데이터 로딩** (Firebase Admin SDK)<br>제목, 내용, 생성된 이미지 표시<br>주제 및 팀 정보 Badge<br>프롬프트 Collapsible<br>🆕 **CommentList** (Client Component)<br>🆕 **BackButton** 공통 컴포넌트 사용 | ✅ 완료 | | **글 상세보기** | `/[locale]/writing/[writingId]` | 🆕 **Server Component 기반 상세 페이지** | 🆕 **SEO 최적화** (서버에서 HTML 생성)<br>🆕 **SNS 공유 미리보기** (카카오톡/페이스북)<br>🆕 **서버 데이터 로딩** (Firebase Admin SDK)<br>제목, 내용, 생성된 이미지 표시<br>주제 및 팀 정보 Badge<br>프롬프트 Collapsible<br>🆕 **CommentList** (Client Component)<br>🆕 **BackButton** 공통 컴포넌트 사용 | ✅ 완료 |
| **글쓰기** | `/[locale]/write` | Tiptap 기반 순수 텍스트 에디터 + 주제 선택 | 주제 선택 (자유 주제/개인 주제/팀 주제)<br>🆕 **글 수정 기능 (URL params ?id=xxx)**<br>🆕 **수정 모드 배지 표시**<br>🆕 **주제 변경 경고** (작성 중 내용 초기화 알림, 임시 저장 안내)<br>제목 입력 (Editable), 순수 텍스트 에디터 (포맷팅 없음)<br>🆕 **다중 글조각 관리** (최대 10개), "새 글쓰기" / "저장된 글조각" 버튼<br>🆕 **강화된 자동 저장** (2초 debounce, 저장 상태 표시: 저장 중/저장됨)<br>🆕 **저장 시 AI 분석** (실시간 분석 제거, 저장 버튼 클릭 시 분석 수행)<br>🆕 **분석 결과 DB 저장** (WritingAnalysis + spellingErrors + contentHash)<br>템플릿 미리채우기 (제목/내용), Firestore 저장<br>비로그인도 접근 가능 (저장 시 로그인 유도) | ✅ 완료 | | **글쓰기** | `/[locale]/write` | Tiptap 기반 순수 텍스트 에디터 + 주제 선택 | 주제 선택 (자유 주제/개인 주제/팀 주제)<br>🆕 **글 수정 기능 (URL params ?id=xxx)**<br>🆕 **수정 모드 배지 표시**<br>🆕 **주제 변경 경고** (작성 중 내용 초기화 알림, 임시 저장 안내)<br>제목 입력 (Editable), 순수 텍스트 에디터 (포맷팅 없음)<br>🆕 **다중 글조각 관리** (최대 10개), "새 글쓰기" / "저장된 글조각" 버튼<br>🆕 **강화된 자동 저장** (2초 debounce, 저장 상태 표시: 저장 중/저장됨)<br>🆕 **저장 시 AI 분석** (실시간 분석 제거, 저장 버튼 클릭 시 분석 수행)<br>🆕 **분석 결과 DB 저장** (WritingAnalysis + spellingErrors + contentHash)<br>템플릿 미리채우기 (제목/내용), Firestore 저장<br>비로그인도 접근 가능 (저장 시 로그인 유도) | ✅ 완료 |
| **테스트** | `/[locale]/test` | 팀 코드 시스템 테스트 페이지 | 팀 코드 생성/검증 테스트<br>팀/학생 생성 테스트<br>학생 로그인 테스트<br>authStore 상태 확인 | 🔜 예정 | | **테스트** | `/[locale]/test` | 팀 코드 시스템 테스트 페이지 | 팀 코드 생성/검증 테스트<br>팀/학생 생성 테스트<br>학생 로그인 테스트<br>authStore 상태 확인 | 🔜 예정 |
| **팀 목록** | `/[locale]/team` | 내가 만든 팀 목록 (정식 계정 전용) | 팀 카드 그리드, 팀 정보 (코드, 멤버 수, 보안 설정)<br>"새 팀 만들기" 버튼 | 🔜 예정 | | **공개 팀 목록** | `/[locale]/team/all` | 🆕 **공개 팀 둘러보기** | 🆕 **공개된 팀 목록 표시** (isPublic=true)<br>🆕 **TeamCard 그리드** (글래스모피즘)<br>🆕 **페이지네이션** (커서 기반)<br>🆕 **Navbar "공개 팀" 메뉴** | ✅ 완료 |
| **팀 생성** | `/[locale]/team/create` | 새 팀 만들기 (정식 계정 전용) | 팀 이름 입력, 팀 코드 자동 생성<br>🆕 **5단계 보안 레벨 선택** (RadioCard, 애니메이션)<br>🆕 **명단 관리 (Level 2/4)**: TagsInput으로 Enter/쉼표 입력<br>생성 후 `/team/[teamId]`로 이동 | 🔜 예정 | | **내 팀 목록** | `/[locale]/team` | 내가 만든/참여한 팀 목록 (정식 계정 전용) | 팀 카드 그리드, 팀 정보 (코드, 멤버 수, 보안 설정)<br>"새 팀 만들기" 버튼 | ✅ 완료 |
| **팀 멤버 페이지** | `/[locale]/team/[teamId]` | 팀 멤버용 페이지 (멤버/소유자 모두 접근) | 팀 정보, 팀 코드 복사, 멤버 목록<br>소유자는 "팀 관리" 버튼 표시<br>팀 코드 로그인 후 기본 이동 페이지 | 🔜 예정 | | **팀 생성** | `/[locale]/team/create` | 새 팀 만들기 (정식 계정 전용) | 팀 이름 입력, 팀 코드 자동 생성<br>🆕 **5단계 보안 레벨 선택** (RadioCard, 애니메이션)<br>🆕 **명단 관리 (Level 2/4)**: TagsInput으로 Enter/쉼표 입력<br>생성 후 `/team/[teamId]`로 이동 | ✅ 완료 |
| **팀 관리** | `/[locale]/team/[teamId]/manage` | 팀 관리 페이지 (소유자 전용) | 팀 정보 및 코드, 보안 설정 표시<br>**팀 주제 관리 (생성/삭제)**<br>🆕 **주제별 학생 분석** (TopicMemberAnalysisSection)<br>멤버 목록 및 관리<br>🆕 **멤버 메뉴 - 팀 내 글 분석** (by-team)<br>"멤버 페이지 보기" 버튼 | 🔜 예정 | | **팀 상세 (통합)** | `/[locale]/team/[teamId]` | 🆕 **멤버/공개 뷰 통합 페이지** | 🆕 **멤버인 경우**: 멤버 목록, 관리/나가기 버튼<br>🆕 **비멤버 + 공개 팀**: 팀 정보, 공개 글 목록, 참여 버튼<br>🆕 **비멤버 + 비공개 팀**: 접근 불가 메시지<br>팀 코드 로그인 후 기본 이동 페이지 | ✅ 완료 |
| **팀 관리** | `/[locale]/team/[teamId]/manage` | 팀 관리 페이지 (소유자 전용) | 팀 정보 및 코드, 보안 설정 표시<br>🆕 **팀 공개 설정** (isPublic, allowPublicWritings, description)<br>**팀 주제 관리 (생성/삭제)**<br>🆕 **주제별 학생 분석** (TopicMemberAnalysisSection)<br>멤버 목록 및 관리<br>🆕 **멤버 메뉴 - 팀 내 글 분석** (by-team)<br>"멤버 페이지 보기" 버튼 | ✅ 완료 |
### 🚧 구현 예정 ### 🚧 구현 예정
@ -406,6 +451,9 @@
| **GenerateImageDialog** | `GenerateImageDialog.tsx` | 🆕 **AI 이미지 생성 Dialog** (4단계 플로우: 장면 추출 → 장면 선택 → 이미지 생성 → 결과 표시) | ✅ 완료 | | **GenerateImageDialog** | `GenerateImageDialog.tsx` | 🆕 **AI 이미지 생성 Dialog** (4단계 플로우: 장면 추출 → 장면 선택 → 이미지 생성 → 결과 표시) | ✅ 완료 |
| **SceneSelector** | `SceneSelector.tsx` | 🆕 **장면 선택 컴포넌트** (RadioCard 기반, 이모지 표시, 원문 미리보기) | ✅ 완료 | | **SceneSelector** | `SceneSelector.tsx` | 🆕 **장면 선택 컴포넌트** (RadioCard 기반, 이모지 표시, 원문 미리보기) | ✅ 완료 |
| **WritingCard** | `WritingCard.tsx` | 🆕 **글 카드 컴포넌트** (제목, 날짜, 미리보기, 주제/점수/이미지 배지, 메뉴, 삭제) | ✅ 완료 | | **WritingCard** | `WritingCard.tsx` | 🆕 **글 카드 컴포넌트** (제목, 날짜, 미리보기, 주제/점수/이미지 배지, 메뉴, 삭제) | ✅ 완료 |
| **PublicWritingCard** | `PublicWritingCard.tsx` | 🆕 **공개 글 카드** (제목, 공개 범위 배지, 미리보기, 날짜) | ✅ 완료 |
| **VisibilitySelector** | `VisibilitySelector.tsx` | 🆕 **공개 범위 선택** (PUBLIC/TEAM/PRIVATE, RadioCard 기반) | ✅ 완료 |
| **VisibilityBadge** | `VisibilityBadge.tsx` | 🆕 **공개 범위 배지** (아이콘 + 라벨, 색상별 구분) | ✅ 완료 |
| **InteractiveImageViewer** | `InteractiveImageViewer.tsx` | 🆕 **인터랙티브 이미지 뷰어** (왜곡 효과, 애니메이션, 오디오 반응) | ✅ 완료 | | **InteractiveImageViewer** | `InteractiveImageViewer.tsx` | 🆕 **인터랙티브 이미지 뷰어** (왜곡 효과, 애니메이션, 오디오 반응) | ✅ 완료 |
| **GenerateImageDialog** | `GenerateImageDialog.tsx` | 🆕 **AI 이미지 생성 Dialog** (4단계 플로우: 장면 추출 → 장면 선택 → 이미지 생성 → 결과 표시) | ✅ 완료 | | **GenerateImageDialog** | `GenerateImageDialog.tsx` | 🆕 **AI 이미지 생성 Dialog** (4단계 플로우: 장면 추출 → 장면 선택 → 이미지 생성 → 결과 표시) | ✅ 완료 |
| ~~**ScoreDisplay**~~ | ~~`ScoreDisplay.tsx`~~ | ~~실시간 피드백 점수 표시~~ | ❌ 삭제됨 (하이라이트로 대체) | | ~~**ScoreDisplay**~~ | ~~`ScoreDisplay.tsx`~~ | ~~실시간 피드백 점수 표시~~ | ❌ 삭제됨 (하이라이트로 대체) |
@ -494,6 +542,8 @@
| 컴포넌트 | 파일명 | 설명 | 상태 | | 컴포넌트 | 파일명 | 설명 | 상태 |
|---------|--------|------|------| |---------|--------|------|------|
| **TeamCard** | `TeamCard.tsx` | 🆕 **공개 팀 카드** (글래스모피즘, 보안 레벨 배지, 멤버 수, 🆕 커버 이미지 표시) | ✅ 완료 |
| **TeamCoverImageUploader** | `TeamCoverImageUploader.tsx` | 🆕 **팀 커버 이미지 업로더** (드래그앤드롭, 미리보기, 16:9 AspectRatio, 5MB 제한) | ✅ 완료 |
| **TeamTopicManager** | `TeamTopicManager.tsx` | 팀 주제 목록 및 생성/삭제 UI | ✅ 완료 | | **TeamTopicManager** | `TeamTopicManager.tsx` | 팀 주제 목록 및 생성/삭제 UI | ✅ 완료 |
| **AIConfigDialog** | `AIConfigDialog.tsx` | 🆕 **AI 도우미 고급 설정 Dialog** (Slider, 커스텀 CheckboxCard) | ✅ 완료 | | **AIConfigDialog** | `AIConfigDialog.tsx` | 🆕 **AI 도우미 고급 설정 Dialog** (Slider, 커스텀 CheckboxCard) | ✅ 완료 |
| **SecurityLevelSelector** | `SecurityLevelSelector.tsx` | 5단계 보안 레벨 선택 (RadioCard, framer-motion 애니메이션) | ✅ 완료 | | **SecurityLevelSelector** | `SecurityLevelSelector.tsx` | 5단계 보안 레벨 선택 (RadioCard, framer-motion 애니메이션) | ✅ 완료 |

View File

@ -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** | | **미사용 코드 정리** | **koreanWordList.ts 삭제 (AI 분석으로 대체), InteractiveImage.tsx 삭제 (InteractiveImageViewer로 대체), AllowListManager.tsx 삭제 (미통합), 관련 문서 업데이트** | **2025-11-26** |
| **팀 페이지 리팩토링** | **useTeamData 훅 생성 (팀 + 멤버 로딩, 권한 체크, refreshMembers), 팀 페이지 중복 코드 제거 (~200줄 절감), 각 하위 컴포넌트 자체 로딩 스켈레톤 활용** | **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** | | **익명 계정 연결 기능** | **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** |
### 🚧 진행 중 ### 🚧 진행 중

View File

@ -1,6 +1,6 @@
# 라온누리 - 기술 스택 및 개발 환경 # 라온누리 - 기술 스택 및 개발 환경
> 최종 업데이트: 2025-11-21 (홈 페이지 모듈화) > 최종 업데이트: 2025-11-27 (채점 시스템 개편)
--- ---
@ -35,6 +35,7 @@
| **Firebase Auth** | - | 사용자 인증 | | **Firebase Auth** | - | 사용자 인증 |
| **Firestore** | - | NoSQL 데이터베이스 (글 저장) | | **Firestore** | - | NoSQL 데이터베이스 (글 저장) |
| **Firebase Realtime Database** | - | 🆕 **실시간 데이터 동기화** (글쓰기 모니터링) | | **Firebase Realtime Database** | - | 🆕 **실시간 데이터 동기화** (글쓰기 모니터링) |
| **Firebase Storage** | - | 🆕 **파일 저장소** (팀 커버 이미지, AI 생성 이미지) |
| **@google/genai** | 1.29.0 | Google Gemini API SDK (텍스트 분석, 맞춤법 검사) | | **@google/genai** | 1.29.0 | Google Gemini API SDK (텍스트 분석, 맞춤법 검사) |
| **Redis** | - | Cache 데이터 베이스 (예정) | | **Redis** | - | Cache 데이터 베이스 (예정) |
@ -42,6 +43,7 @@
- **Gemini 2.5 Flash-Lite**: 텍스트 분석 (오감/감정/대화/의성어 평가, Delta 전송) - **Gemini 2.5 Flash-Lite**: 텍스트 분석 (오감/감정/대화/의성어 평가, Delta 전송)
- **Gemini 2.5 Flash-Lite**: 맞춤법 검사 (초등학생 눈높이) - **Gemini 2.5 Flash-Lite**: 맞춤법 검사 (초등학생 눈높이)
- **Gemini 2.5 Flash-Lite**: 글 작성 패턴 분석 (최근 10개 글 종합 분석, AI 평가 및 맞춤형 추천) - **Gemini 2.5 Flash-Lite**: 글 작성 패턴 분석 (최근 10개 글 종합 분석, AI 평가 및 맞춤형 추천)
- **Vertex AI Imagen 4.0 Fast**: 이미지 생성 (글 장면 시각화, 일관된 애니메이션 스타일)
- **Vertex AI 모드**: Multi-region failover 지원 (`vertexai: true`) - **Vertex AI 모드**: Multi-region failover 지원 (`vertexai: true`)
- **Response Schema**: JSON 응답 강제 (`Type.OBJECT`, `Type.ARRAY` 등) - **Response Schema**: JSON 응답 강제 (`Type.OBJECT`, `Type.ARRAY` 등)
@ -197,7 +199,8 @@ NEXT_PUBLIC_API_URL=/api
content: string; // HTML content: string; // HTML
wordCount: number; wordCount: number;
charCount: number; charCount: number;
analysis?: { // 🆕 AI 분석 결과 (저장 시 자동 생성) visibility: WritingVisibility; // 🆕 PUBLIC | TEAM | PRIVATE (기본: PRIVATE)
analysis?: { // AI 분석 결과 (저장 시 자동 생성)
score: number; score: number;
breakdown: { sensory, emotion, dialogue, onomatopoeia }; breakdown: { sensory, emotion, dialogue, onomatopoeia };
foundWords: { sensory[], emotion[], onomatopoeia[] }; foundWords: { sensory[], emotion[], onomatopoeia[] };
@ -211,6 +214,7 @@ NEXT_PUBLIC_API_URL=/api
createdAt: Timestamp; createdAt: Timestamp;
updatedAt: Timestamp; updatedAt: Timestamp;
} }
// 🆕 WritingVisibility enum: PUBLIC (전체 공개), TEAM (팀 내 공개), PRIVATE (비공개)
``` ```
- `topics/` ✅ - 글쓰기 주제 (팀 주제 + 개인 주제) - `topics/` ✅ - 글쓰기 주제 (팀 주제 + 개인 주제)
```typescript ```typescript
@ -243,6 +247,10 @@ NEXT_PUBLIC_API_URL=/api
securityMode: 'simple' | 'normal' | 'open'; securityMode: 'simple' | 'normal' | 'open';
requirePin: boolean; requirePin: boolean;
allowAnonymousJoin: boolean; allowAnonymousJoin: boolean;
// 🆕 공개 설정
isPublic: boolean; // 팀 공개 여부 (기본: false)
allowPublicWritings: boolean; // 팀원 글 공개 허용 (기본: false)
description?: string; // 팀 소개 (공개 팀용)
createdAt: Timestamp; createdAt: Timestamp;
updatedAt: Timestamp; updatedAt: Timestamp;
isActive: boolean; isActive: boolean;
@ -1043,9 +1051,10 @@ interface Draft {
#### 참고 파일 #### 참고 파일
**서비스 레이어**: **서비스 레이어**:
- `src/services/vertexAI.ts` - Gemini API 범용 래퍼 (`@google/genai`) - `src/services/vertexAI.ts` - Gemini API 범용 래퍼 (`@google/genai`, temperature=0)
- `src/services/textAnalysisService.ts` - 텍스트 분석 (히스토리 기반) - `src/services/textAnalysisService.ts` - 텍스트 분석 (히스토리 기반, 가중 평균 점수 계산)
- `src/services/spellingService.ts` - 🆕 맞춤법 검사 (독립적) - `src/services/scoringConfigService.ts` - 🆕 채점 설정 병합 (기본→팀→주제 우선순위)
- `src/services/spellingService.ts` - 맞춤법 검사 (독립적)
- `src/services/regionHealthManager.ts` - Region 상태 관리 - `src/services/regionHealthManager.ts` - Region 상태 관리
**API & 컴포넌트**: **API & 컴포넌트**: