docs: Sync documentation from private repository

This commit is contained in:
Documentation Bot 2025-11-12 07:45:19 +00:00
parent aef9314f31
commit d09f99a0cc
4 changed files with 447 additions and 53 deletions

View File

@ -1,29 +1,43 @@
# 라온누리 - 데이터 모델 및 스키마 # 라온누리 - 데이터 모델 및 스키마
> 최종 업데이트: 2025-11-07 > 최종 업데이트: 2025-11-12 (실시간 글쓰기 모니터링)
이 문서는 Firestore 데이터베이스 구조와 TypeScript 타입 정의를 설명합니다. 이 문서는 Firestore 데이터베이스 및 Firebase Realtime Database 구조와 TypeScript 타입 정의를 설명합니다.
**참고**: API 타입 정의는 [API_SPEC.md](./API_SPEC.md)를 참조하세요. **참고**: API 타입 정의는 [API_SPEC.md](./API_SPEC.md)를 참조하세요.
--- ---
## Firestore 컬렉션 구조 ## 데이터베이스 구조
### 컬렉션 개요 ### Firestore (영구 데이터)
``` ```
firestore firestore
├── teams/ # ✅ 팀 (팀 코드 시스템) ├── teams/ # ✅ 팀 (팀 코드 시스템)
├── students/ # ✅ 학생 계정 (Anonymous Auth) ├── users/ # ✅ 사용자 프로필 및 메타데이터
├── users/ # 🔜 사용자 프로필 및 진행 상황
├── writings/ # ✅ 작성한 글 ├── writings/ # ✅ 작성한 글
├── topics/ # ✅ 글쓰기 주제 ├── topics/ # ✅ 글쓰기 주제
├── patternAnalyses/ # ✅ 패턴 분석 결과 (contentHash 캐싱)
├── lessons/ # 🔜 학습 레슨 ├── lessons/ # 🔜 학습 레슨
├── stickers/ # 🔜 스티커 마스터 데이터 ├── stickers/ # 🔜 스티커 마스터 데이터
└── userStickers/ # 🔜 사용자별 스티커 획득 기록 └── userStickers/ # 🔜 사용자별 스티커 획득 기록
``` ```
### Firebase Realtime Database (실시간 데이터)
```
realtime-db
├── monitoring/ # 🆕 실시간 글쓰기 모니터링
│ └── {teamId}/
│ └── {topicId}/
│ └── {userId}/
├── previewRequests/ # 🆕 미리보기 요청
│ └── {userId}/
└── previewResponses/ # 🆕 미리보기 응답
└── {requestId}/
```
**범례**: **범례**:
- ✅ 구현 완료 - ✅ 구현 완료
- 🔜 구현 예정 - 🔜 구현 예정
@ -613,6 +627,160 @@ interface UserSticker {
--- ---
## 9. WritingSession (실시간 글쓰기 모니터링) 🆕
**데이터베이스**: Firebase Realtime Database (휘발성 데이터)
### Realtime DB 구조
#### 9.1. monitoring (글쓰기 통계)
**경로**: `monitoring/{teamId}/{topicId}/{userId}`
```typescript
interface WritingStats {
userId: string; // 작성자 UID
contentLength: number; // 현재 글자 수 (공백 포함)
wordCount: number; // 현재 단어 수
topicId: string; // 현재 작성 중인 주제 ID
lastUpdated: number; // 마지막 업데이트 시간 (timestamp) - 항상 변경됨
}
interface SpeedDataPoint {
speed: number; // 작성 속도 (글자/분)
timestamp: number; // 기록 시간
}
interface MonitoringData extends WritingStats {
displayName: string; // 표시 이름
speedHistory: SpeedDataPoint[]; // 속도 히스토리 (최근 10개)
currentSpeed: number; // 현재 속도 (글자/분)
preview?: string; // 미리보기 (선택적)
}
```
**예시 데이터**:
```json
{
"monitoring": {
"team_abc123": {
"topic_xyz": {
"user_001": {
"userId": "user_001",
"contentLength": 1500,
"wordCount": 300,
"topicId": "topic_xyz",
"lastUpdated": 1731398400000
},
"user_002": {
"userId": "user_002",
"contentLength": 800,
"wordCount": 160,
"topicId": "topic_xyz",
"lastUpdated": 1731398395000
}
}
}
}
}
```
**클라이언트 측 계산** (선생님 화면):
```typescript
// MonitoringData (UI용)
{
userId: "user_001",
contentLength: 1500,
wordCount: 300,
topicId: "topic_xyz",
lastUpdated: 1731398400000,
displayName: "철수",
currentSpeed: 420, // 글자/분 (클라이언트 계산)
speedHistory: [ // 최근 10개 (클라이언트 계산)
{ speed: 480, timestamp: 1731398370000 },
{ speed: 420, timestamp: 1731398375000 },
{ speed: 360, timestamp: 1731398380000 },
{ speed: 0, timestamp: 1731398385000 }, // 멈춤!
{ speed: 0, timestamp: 1731398390000 },
{ speed: 420, timestamp: 1731398395000 }, // 재시작
{ speed: 480, timestamp: 1731398400000 }
]
}
```
#### 9.2. previewRequests (미리보기 요청)
**경로**: `previewRequests/{userId}/{requestId}`
```typescript
interface PreviewRequest {
requestedBy: string; // 요청한 관리자 UID
timestamp: number; // 요청 시간
requestId: string; // 고유 요청 ID
}
```
#### 9.3. previewResponses (미리보기 응답)
**경로**: `previewResponses/{requestId}`
```typescript
interface PreviewResponse {
content: string; // 현재 작성 중인 글 내용
timestamp: number; // 응답 시간
requestId: string; // 요청 ID (매칭용)
}
```
### 업데이트 주기
- **통계 전송**: 5초마다 (학생이 팀 주제로 작성 중일 때만)
- **자동 정리**: `onDisconnect().remove()`로 페이지 이탈 시 자동 삭제
- **미리보기**: 요청 시에만 (10초 타임아웃)
### Security Rules
**파일**: `database.rules.json`
```json
{
"rules": {
"monitoring": {
"$teamId": {
"$topicId": {
"$userId": {
".read": "auth != null && (auth.uid == $userId || root.child('teamOwners').child($teamId).val() == auth.uid)",
".write": "auth != null && auth.uid == $userId"
}
}
}
},
"previewRequests": {
"$userId": {
".read": "auth != null && auth.uid == $userId",
".write": "auth != null"
}
},
"previewResponses": {
"$requestId": {
".read": "auth != null",
".write": "auth != null"
}
}
}
}
```
**권한**:
- 통계 쓰기: 본인만
- 통계 읽기: 본인 + 팀 소유자
- 미리보기 요청: 누구나 쓰기, 대상자만 읽기
- 미리보기 응답: 누구나 읽기/쓰기 (requestId로 필터링)
**TypeScript**: `src/types/writingSession.ts`
---
## TypeScript 타입 정의 파일 ## TypeScript 타입 정의 파일
### 데이터 모델 타입 ### 데이터 모델 타입
@ -622,17 +790,19 @@ interface UserSticker {
``` ```
src/types/ src/types/
├── team.ts # ✅ Team 데이터 모델 ├── team.ts # ✅ Team 데이터 모델
├── student.ts # ✅ Student 데이터 모델 ├── firestoreUser.ts # ✅ User 데이터 모델 (FirestoreUser, User 분리)
├── writing.ts # ✅ Writing 데이터 모델 ├── writing.ts # ✅ Writing 데이터 모델
├── topic.ts # ✅ Topic 데이터 모델 ├── topic.ts # ✅ Topic 데이터 모델
├── user.ts # 🔜 User 관련 타입 (예정) ├── draft.ts # ✅ Draft 데이터 모델 (글조각)
├── writingPattern.ts # ✅ WritingPattern 분석 데이터 모델
├── writingSession.ts # 🆕 WritingSession 실시간 모니터링 타입
├── lesson.ts # 🔜 Lesson 관련 타입 (예정) ├── lesson.ts # 🔜 Lesson 관련 타입 (예정)
├── sticker.ts # 🔜 Sticker 관련 타입 (예정) ├── sticker.ts # 🔜 Sticker 관련 타입 (예정)
└── api/ # ✅ API Request/Response 타입 └── api/ # ✅ API Request/Response 타입
├── team.ts # Team API 타입 (10개 엔드포인트) ├── team.ts # Team API 타입
├── student.ts # Student API 타입 (13개 엔드포인트) ├── user.ts # User API 타입
├── writing.ts # Writing API 타입 (6개 엔드포인트) ├── writing.ts # Writing API 타입
└── topic.ts # Topic API 타입 (6개 엔드포인트) └── topic.ts # Topic API 타입
``` ```
### 사용 예시 ### 사용 예시

View File

@ -1,10 +1,25 @@
# 라온누리 - 프로젝트 구조 # 라온누리 - 프로젝트 구조
> 최종 업데이트: 2025-11-12 (Writing API, 패턴 분석 확장, Content Hash 캐싱) > 최종 업데이트: 2025-11-12 (실시간 글쓰기 모니터링 시스템)
초등학생을 위한 창작 글쓰기 교육 플랫폼 초등학생을 위한 창작 글쓰기 교육 플랫폼
**최신 업데이트** (2025-11-12): **최신 업데이트** (2025-11-12 PM):
- 📡 **실시간 글쓰기 모니터링 시스템**
- Firebase Realtime Database 기반 실시간 통신 (Redis Pub/Sub 방식)
- 팀 주제 선택 시 해당 주제로 작성 중인 학생 실시간 표시
- 5초 주기 자동 업데이트 (글자 수, 단어 수, lastUpdated 타임스탬프)
- **작성 속도 계산** (클라이언트 측, 글자/분 단위)
- **Sparkline 그래프** (Area Chart, 최근 10개 데이터 포인트)
- **인터랙티브 툴팁** (마우스 오버 시 속도 + 몇 초 전 데이터인지 표시)
- 미리보기 요청-응답 시스템 (관리자 클릭 → 학생 응답 → Dialog 표시)
- onDisconnect() 자동 정리 (페이지 이탈 시 세션 자동 삭제)
- LiveWritingMonitor 컴포넌트 (주제 Select, 실시간 카드 그리드)
- WritingSessionManager (Realtime DB 작업, 상세 디버그 로그)
- 완전 무료 (동시 접속 100명까지, 1GB/day)
- Security Rules로 권한 관리 (본인 쓰기, 인증된 사용자 읽기)
**최신 업데이트** (2025-11-12 AM):
- ✅ **Writing API 구현 완료** - ✅ **Writing API 구현 완료**
- POST /api/writing - 글 생성 (서버에서 wordCount/charCount 자동 계산) - POST /api/writing - 글 생성 (서버에서 wordCount/charCount 자동 계산)
- GET /api/writing/[id] - 글 조회 (작성자만 접근) - GET /api/writing/[id] - 글 조회 (작성자만 접근)
@ -289,9 +304,25 @@
| **TeamTopicManager** | `TeamTopicManager.tsx` | 팀 주제 목록 및 생성/삭제 UI | ✅ 완료 | | **TeamTopicManager** | `TeamTopicManager.tsx` | 팀 주제 목록 및 생성/삭제 UI | ✅ 완료 |
| **SecurityLevelSelector** | `SecurityLevelSelector.tsx` | 5단계 보안 레벨 선택 (RadioCard, framer-motion 애니메이션) | ✅ 완료 | | **SecurityLevelSelector** | `SecurityLevelSelector.tsx` | 5단계 보안 레벨 선택 (RadioCard, framer-motion 애니메이션) | ✅ 완료 |
| **AllowListManager** | `AllowListManager.tsx` | 명단 관리 (이름/이메일 추가/제거, TagsInput) | ✅ 완료 | | **AllowListManager** | `AllowListManager.tsx` | 명단 관리 (이름/이메일 추가/제거, TagsInput) | ✅ 완료 |
| **TopicMemberAnalysisSection** | `TopicMemberAnalysisSection.tsx` | 🆕 주제별 학생 글쓰기 분석 (Accordion, by-topic 분석) | 🚧 UI만 (API 추후 구현) | | **TopicMemberAnalysisSection** | `TopicMemberAnalysisSection.tsx` | 주제별 학생 글쓰기 분석 (Accordion, by-topic 분석) | 🚧 UI만 (API 추후 구현) |
| **LiveWritingMonitor** | `LiveWritingMonitor.tsx` | 🆕 **실시간 글쓰기 모니터링** (Firebase Realtime DB, 5초 주기) | ✅ 완료 |
**주요 기능** (2025-11-10): **주요 기능**:
- ✅ **LiveWritingMonitor** (2025-11-12):
- 주제 선택 드롭다운 (Chakra UI Select)
- StudentMonitorCard 컴포넌트 (개별 학생 카드)
- 실시간 통계: 글자 수, 단어 수, 마지막 업데이트 시간 ("N초 전")
- **작성 속도 계산** (클라이언트 측, charDiff * 12 = 글자/분)
- **Sparkline 그래프** (@chakra-ui/charts, Area Chart)
- 최근 10개 데이터 포인트 (speedHistory)
- 0도 표시 (작성 멈춤 시각화)
- Teal 색상, 투명도 30%
- **인터랙티브 툴팁** (Recharts Tooltip)
- 속도 값 ("N자/분")
- 시간 정보 ("N초 전")
- 미리보기 버튼 (Dialog로 현재 작성 중인 글 표시)
- 실시간 구독/구독 해제 (useEffect cleanup)
- 빈 상태 UI (작성 중인 학생 없을 때)
- ✅ SecurityLevelSelector: RadioCard 기반, 선택 시 추가 UI 애니메이션으로 표시 - ✅ SecurityLevelSelector: RadioCard 기반, 선택 시 추가 UI 애니메이션으로 표시
- ✅ AllowListManager: Level 2/4용 명단 관리, Enter/쉼표로 구분 입력 - ✅ AllowListManager: Level 2/4용 명단 관리, Enter/쉼표로 구분 입력
- ✅ 그라데이션 배경 (RadioCard와 자연스럽게 연결) - ✅ 그라데이션 배경 (RadioCard와 자연스럽게 연결)
@ -324,7 +355,8 @@
| **ManagerBase** | `ManagerBase.ts` | 공통 기능 (authenticatedFetch, API 호출, 캐싱) | ✅ 완료 | | **ManagerBase** | `ManagerBase.ts` | 공통 기능 (authenticatedFetch, API 호출, 캐싱) | ✅ 완료 |
| **TeamManager** | `TeamManager.ts` | 팀 관련 API 호출 (생성, 조회, 수정, 삭제, 멤버 관리) | ✅ 완료 | | **TeamManager** | `TeamManager.ts` | 팀 관련 API 호출 (생성, 조회, 수정, 삭제, 멤버 관리) | ✅ 완료 |
| **UserManager** | `UserManager.ts` | 사용자 관련 API 호출 (생성, 조회, 수정, 닉네임 관리) **[NEW]** | ✅ 완료 | | **UserManager** | `UserManager.ts` | 사용자 관련 API 호출 (생성, 조회, 수정, 닉네임 관리) **[NEW]** | ✅ 완료 |
| **DraftManager** | `DraftManager.ts` | 🆕 글조각 관리 (localStorage 기반, 최대 10개, CRUD) | ✅ 완료 | | **DraftManager** | `DraftManager.ts` | 글조각 관리 (localStorage 기반, 최대 10개, CRUD) | ✅ 완료 |
| **WritingSessionManager** | `WritingSessionManager.ts` | 🆕 **실시간 글쓰기 세션 관리** (Firebase Realtime DB 작업) | ✅ 완료 |
| ~~**StudentManager**~~ | ~~`StudentManager.ts`~~ | ~~학생 관련 API 호출~~ | ⚠️ Deprecated (UserManager로 대체) | | ~~**StudentManager**~~ | ~~`StudentManager.ts`~~ | ~~학생 관련 API 호출~~ | ⚠️ Deprecated (UserManager로 대체) |
| **WritingManager** | `WritingManager.ts` | 글쓰기 관련 비즈니스 로직 (CRUD, 통계) | ✅ 완료 | | **WritingManager** | `WritingManager.ts` | 글쓰기 관련 비즈니스 로직 (CRUD, 통계) | ✅ 완료 |
| **TopicManager** | `TopicManager.ts` | 주제 관련 비즈니스 로직 (CRUD, 템플릿 처리) | ✅ 완료 | | **TopicManager** | `TopicManager.ts` | 주제 관련 비즈니스 로직 (CRUD, 템플릿 처리) | ✅ 완료 |
@ -341,6 +373,13 @@
- ✅ **타입 안전성**: Request/Response 타입 완전 정의 - ✅ **타입 안전성**: Request/Response 타입 완전 정의
- ✅ **비즈니스 로직과 UI 레이어 분리** - ✅ **비즈니스 로직과 UI 레이어 분리**
**WritingSessionManager 주요 메서드** (2025-11-12):
- `startMonitoring(teamId, topicId, getStatsCallback)`: 5초 주기 통계 전송 시작
- `stopMonitoring()`: 통계 전송 중지 (페이지 이탈 시)
- `subscribeToTopic(teamId, topicId, callback)`: 실시간 구독 (관리자용)
- `requestPreview(targetUserId)`: 미리보기 요청 (Promise 반환)
- `listenForPreviewRequests(onRequestCallback)`: 미리보기 요청 리스너 (학생용)
### 📁 `src/services/` - 데이터 레이어 (일부 deprecated) ### 📁 `src/services/` - 데이터 레이어 (일부 deprecated)
| 서비스 | 파일명 | 설명 | 상태 | | 서비스 | 파일명 | 설명 | 상태 |
@ -371,7 +410,8 @@
| **Team 타입** | `team.ts` | 팀 데이터 모델 (members Map), **TeamSecurityLevel Enum (1-5)** | ✅ 완료 | | **Team 타입** | `team.ts` | 팀 데이터 모델 (members Map), **TeamSecurityLevel Enum (1-5)** | ✅ 완료 |
| **FirestoreUser 타입** | `firestoreUser.ts` | **FirestoreUser** (DB 저장용), **User** (UI용) 분리 | ✅ 완료 | | **FirestoreUser 타입** | `firestoreUser.ts` | **FirestoreUser** (DB 저장용), **User** (UI용) 분리 | ✅ 완료 |
| **Draft 타입** | `draft.ts` | 글조각 데이터 모델 (Draft, DraftListItem, **AnalysisHistoryItem**) | ✅ 완료 | | **Draft 타입** | `draft.ts` | 글조각 데이터 모델 (Draft, DraftListItem, **AnalysisHistoryItem**) | ✅ 완료 |
| **WritingPattern 타입** | `writingPattern.ts` | 🆕 **글 작성 패턴 분석** 데이터 모델 (WritingPatternAnalysis) | ✅ 완료 | | **WritingPattern 타입** | `writingPattern.ts` | **글 작성 패턴 분석** 데이터 모델 (WritingPatternAnalysis) | ✅ 완료 |
| **WritingSession 타입** | `writingSession.ts` | 🆕 **실시간 모니터링** 데이터 모델 (WritingStats, PreviewRequest/Response, MonitoringData) | ✅ 완료 |
| ~~**User 타입**~~ | ~~`user.ts`~~ | ~~사용자 데이터 모델~~ | ⚠️ Deprecated (firestoreUser.ts로 변경) | | ~~**User 타입**~~ | ~~`user.ts`~~ | ~~사용자 데이터 모델~~ | ⚠️ Deprecated (firestoreUser.ts로 변경) |
| ~~**Student 타입**~~ | ~~`student.ts`~~ | ~~학생 데이터 모델~~ | ⚠️ Deprecated (user.ts로 대체) | | ~~**Student 타입**~~ | ~~`student.ts`~~ | ~~학생 데이터 모델~~ | ⚠️ Deprecated (user.ts로 대체) |
| **Topic 타입** | `topic.ts` | 주제 데이터 모델, TopicCategory/Difficulty/OwnerType Enum, 팀 주제 유틸 함수 | ✅ 완료 | | **Topic 타입** | `topic.ts` | 주제 데이터 모델, TopicCategory/Difficulty/OwnerType Enum, 팀 주제 유틸 함수 | ✅ 완료 |
@ -452,22 +492,36 @@
| 파일 | 설명 | 상태 | | 파일 | 설명 | 상태 |
|------|------|------| |------|------|------|
| `firebase.ts` | Firebase 초기화 및 설정 | ✅ 완료 | | `firebase.ts` | Firebase 초기화 및 설정 (Auth, Firestore, **Realtime DB**) | ✅ 완료 |
| `site.ts` | 사이트 메타데이터 및 설정 | ✅ 완료 | | `site.ts` | 사이트 메타데이터 및 설정 | ✅ 완료 |
**Firebase 서비스** (2025-11-12):
- ✅ Firebase Authentication (Email/Password, Google OAuth, Anonymous)
- ✅ Cloud Firestore (데이터베이스)
- ✅ Firebase Realtime Database (실시간 모니터링)
- ✅ Firebase Analytics (분석)
**Firebase Config**:
- Firebase 설정은 `src/config/firebase.ts`에 하드코딩되어 있습니다
- Public API Key는 Firebase 프로젝트 설정에서 제한 가능
- 환경변수 대신 코드에 직접 포함 (클라이언트 SDK 표준 방식)
--- ---
## 디렉토리 구조 요약 ## 디렉토리 구조 요약
``` ```
src/ project_w/
├── database.rules.json # 🆕 Firebase Realtime DB Security Rules
├── src/
├── app/ # Next.js App Router ├── app/ # Next.js App Router
│ ├── layout.tsx # 루트 레이아웃 │ ├── layout.tsx # 루트 레이아웃
│ ├── page.tsx # 랜딩 페이지 (/) - 로그인 시 /home 리다이렉트 │ ├── page.tsx # 랜딩 페이지 (/) - 로그인 시 /home 리다이렉트
│ ├── home/ │ ├── home/
│ │ └── page.tsx # ✅ 유저 홈 페이지 (/home) │ │ └── page.tsx # ✅ 유저 홈 페이지 (/home)
│ ├── write/ │ ├── write/
│ │ └── page.tsx # ✅ 글쓰기 페이지 (/write) │ │ └── page.tsx # ✅ 글쓰기 페이지 (/write) - 🆕 실시간 모니터링 전송
│ ├── test/ │ ├── test/
│ │ └── page.tsx # ✅ 테스트 페이지 (/test) - 팀 코드 시스템 테스트 │ │ └── page.tsx # ✅ 테스트 페이지 (/test) - 팀 코드 시스템 테스트
│ ├── globals.css │ ├── globals.css
@ -498,8 +552,10 @@ src/
│ │ └── CreateTeamTopicDialog.tsx # ✅ 팀 주제 생성 │ │ └── CreateTeamTopicDialog.tsx # ✅ 팀 주제 생성
│ ├── team/ # ✅ 팀 관련 │ ├── team/ # ✅ 팀 관련
│ │ ├── TeamTopicManager.tsx # ✅ 팀 주제 관리 │ │ ├── TeamTopicManager.tsx # ✅ 팀 주제 관리
│ │ ├── SecurityLevelSelector.tsx # 🆕 보안 레벨 선택 (RadioCard, 애니메이션) │ │ ├── SecurityLevelSelector.tsx # 보안 레벨 선택 (RadioCard, 애니메이션)
│ │ └── AllowListManager.tsx # 🆕 명단 관리 (TagsInput) │ │ ├── AllowListManager.tsx # 명단 관리 (TagsInput)
│ │ ├── TopicMemberAnalysisSection.tsx # 주제별 학생 분석 (UI만)
│ │ └── LiveWritingMonitor.tsx # 🆕 실시간 글쓰기 모니터링 (Realtime DB)
│ └── [미구현] │ └── [미구현]
│ ├── lesson/ # 학습 컴포넌트 │ ├── lesson/ # 학습 컴포넌트
│ ├── sticker/ # 스티커 컴포넌트 │ ├── sticker/ # 스티커 컴포넌트
@ -515,7 +571,11 @@ src/
├── managers/ # ✅ 비즈니스 로직 (Manager 패턴) ├── managers/ # ✅ 비즈니스 로직 (Manager 패턴)
│ ├── ManagerBase.ts # 기본 Manager 클래스 │ ├── ManagerBase.ts # 기본 Manager 클래스
│ ├── WritingManager.ts # 글쓰기 관리 │ ├── WritingManager.ts # 글쓰기 관리
│ ├── TopicManager.ts # ✅ 주제 관리 │ ├── WritingSessionManager.ts # 🆕 실시간 세션 관리 (Realtime DB)
│ ├── TopicManager.ts # 주제 관리
│ ├── TeamManager.ts # 팀 관리
│ ├── UserManager.ts # 사용자 관리
│ ├── DraftManager.ts # 글조각 관리 (localStorage)
│ └── [미구현] │ └── [미구현]
│ ├── LevelManager.ts │ ├── LevelManager.ts
│ └── StickerManager.ts │ └── StickerManager.ts
@ -544,11 +604,15 @@ src/
├── types/ # TypeScript 타입 ├── types/ # TypeScript 타입
│ ├── topic.ts # ✅ 주제 관련 타입 (Enum + 유틸 함수) │ ├── topic.ts # ✅ 주제 관련 타입 (Enum + 유틸 함수)
│ ├── team.ts # ✅ 팀 관련 타입 (Enum) │ ├── team.ts # ✅ 팀 관련 타입 (Enum)
│ ├── student.ts # ✅ 학생 타입 │ ├── firestoreUser.ts # ✅ 사용자 타입 (FirestoreUser, User)
│ ├── draft.ts # ✅ 글조각 타입
│ ├── writingPattern.ts # ✅ 패턴 분석 타입
│ ├── writingSession.ts # 🆕 실시간 모니터링 타입 (WritingStats, PreviewRequest/Response)
│ ├── api/ # ✅ API Request/Response 타입 │ ├── api/ # ✅ API Request/Response 타입
│ │ ├── topic.ts # ✅ 주제 API (팀/개인 주제) │ │ ├── topic.ts # ✅ 주제 API (팀/개인 주제)
│ │ ├── team.ts # ✅ 팀 API │ │ ├── team.ts # ✅ 팀 API
│ │ └── student.ts # ✅ 학생 API │ │ ├── user.ts # ✅ 사용자 API
│ │ └── writing.ts # ✅ 글쓰기 API
│ └── [미구현] │ └── [미구현]
└── utils/ # 유틸리티 함수 └── utils/ # 유틸리티 함수

View File

@ -1,6 +1,6 @@
# 라온누리 - 개발 로드맵 # 라온누리 - 개발 로드맵
> 최종 업데이트: 2025-11-12 (Writing API, 패턴 분석 확장, Content Hash 캐싱) > 최종 업데이트: 2025-11-12 (실시간 글쓰기 모니터링 시스템)
초등학생을 위한 창작 글쓰기 교육 플랫폼 개발 계획 초등학생을 위한 창작 글쓰기 교육 플랫폼 개발 계획
@ -83,6 +83,7 @@
| **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** | | **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** | | **패턴 분석 - 팀 소유자 기능** | **3가지 분석 타입 (self/by-team/by-topic), API 권한 체크, 팀 주제 필터링, WritingPatternDialog Props 확장, TopicMemberAnalysisSection (UI만), 팀 관리 페이지에 멤버 분석 메뉴** | **2025-11-12** |
| **Content Hash 기반 3단계 캐싱** | **글 목록 해시 생성 (id+updatedAt), L1: localStorage (영구, LRU 10개), L2: Firestore patternAnalyses (영구), L3: Server in-memory (5분, 50개), 변경 자동 감지, AI 비용 절감 (전체 사용자 기준 1회 분석), contentHash.ts + patternCacheManager.ts + patternAnalysis.ts** | **2025-11-12** | | **Content Hash 기반 3단계 캐싱** | **글 목록 해시 생성 (id+updatedAt), L1: localStorage (영구, LRU 10개), L2: Firestore patternAnalyses (영구), L3: Server in-memory (5분, 50개), 변경 자동 감지, AI 비용 절감 (전체 사용자 기준 1회 분석), contentHash.ts + patternCacheManager.ts + patternAnalysis.ts** | **2025-11-12** |
| **실시간 글쓰기 모니터링** | **Firebase Realtime Database 기반 실시간 통신 (Redis Pub/Sub 방식), WritingSessionManager (5초 주기 통계 전송, 미리보기 요청-응답, 상세 디버그 로그), LiveWritingMonitor 컴포넌트 (주제 Select, 실시간 카드 그리드, StudentMonitorCard), 글쓰기 페이지 모니터링 전송 (contentRef로 최적화), onDisconnect() 자동 정리, 작성 속도 계산 (클라이언트 측, 글자/분), Sparkline 그래프 (Area Chart, 최근 10개 히스토리, 0도 표시), 인터랙티브 툴팁 (속도 + 몇 초 전 데이터), 마지막 업데이트 시간 표시, database.rules.json (topicId 레벨 읽기 권한), @chakra-ui/charts + recharts 패키지, 완전 무료 (100명까지)** | **2025-11-12** |
### 🚧 진행 중 ### 🚧 진행 중

View File

@ -1,6 +1,6 @@
# 라온누리 - 기술 스택 및 개발 환경 # 라온누리 - 기술 스택 및 개발 환경
> 최종 업데이트: 2025-11-11 (글 작성 패턴 분석, 실시간 하이라이트, 인터랙티브 툴팁) > 최종 업데이트: 2025-11-12 (실시간 글쓰기 모니터링 시스템)
--- ---
@ -19,6 +19,8 @@
| 기술 | 버전 | 용도 | | 기술 | 버전 | 용도 |
|-----|------|------| |-----|------|------|
| **Chakra UI** | v3.28.0 | 컴포넌트 라이브러리 | | **Chakra UI** | v3.28.0 | 컴포넌트 라이브러리 |
| **@chakra-ui/charts** | latest | 🆕 **차트 컴포넌트** (Sparkline, Area/Bar/Line 차트) |
| **Recharts** | latest | 🆕 **차트 라이브러리** (Chakra Charts 내부 사용) |
| **Emotion** | 11.14.0 | CSS-in-JS | | **Emotion** | 11.14.0 | CSS-in-JS |
| **Framer Motion** | 12.23.24 | 애니메이션 라이브러리 | | **Framer Motion** | 12.23.24 | 애니메이션 라이브러리 |
| **React Icons** | 5.5.0 | 아이콘 세트 | | **React Icons** | 5.5.0 | 아이콘 세트 |
@ -31,7 +33,8 @@
| **Firebase** | 12.4.0 | BaaS (Backend as a Service) | | **Firebase** | 12.4.0 | BaaS (Backend as a Service) |
| **Firebase Auth** | - | 사용자 인증 | | **Firebase Auth** | - | 사용자 인증 |
| **Firestore** | - | NoSQL 데이터베이스 (글 저장) | | **Firestore** | - | NoSQL 데이터베이스 (글 저장) |
| **@google/genai** | 1.29.0 | 🆕 **Google Gemini API SDK** (텍스트 분석, 맞춤법 검사) | | **Firebase Realtime Database** | - | 🆕 **실시간 데이터 동기화** (글쓰기 모니터링) |
| **@google/genai** | 1.29.0 | Google Gemini API SDK (텍스트 분석, 맞춤법 검사) |
| **Redis** | - | Cache 데이터 베이스 (예정) | | **Redis** | - | Cache 데이터 베이스 (예정) |
**AI 서비스**: **AI 서비스**:
@ -45,7 +48,14 @@
| 기술 | 버전 | 용도 | | 기술 | 버전 | 용도 |
|-----|------|------| |-----|------|------|
| **use-debounce** | latest | 🆕 React debounce hook (5초 API 호출 제한) | | **use-debounce** | latest | React debounce hook (5초 API 호출 제한) |
### Charts
| 기술 | 버전 | 용도 |
|-----|------|------|
| **@chakra-ui/charts** | latest | 🆕 **Chakra UI 차트 컴포넌트** (실시간 모니터링 그래프) |
| **recharts** | latest | 🆕 **차트 라이브러리** (Area, Line, Bar 차트) |
### State Management ### State Management
@ -118,19 +128,37 @@ import { Navbar } from "@/components/navigation/Navbar";
--- ---
## 환경 변수 ## Firebase 설정
### `.env.local` 파일 구조 ### Firebase Config
Firebase 설정은 `src/config/firebase.ts`에 직접 하드코딩되어 있습니다:
```typescript
// src/config/firebase.ts
const firebaseConfig = {
apiKey: "AIzaSyBXmSq9Sq81oNkEZsbcbc-YA9LO31URby8",
authDomain: "raonnuri-84830.firebaseapp.com",
databaseURL: "https://raonnuri-84830-default-rtdb.firebaseio.com", // 🆕 Realtime DB
projectId: "raonnuri-84830",
storageBucket: "raonnuri-84830.firebasestorage.app",
messagingSenderId: "962894843507",
appId: "1:962894843507:web:91d41427d4de819c47a406",
measurementId: "G-E4VKK56B8G"
};
export const fbAuth = getAuth(fbApp);
export const fbClient = getFirestore(fbApp);
export const fbRealtimeDb = getDatabase(fbApp); // 🆕
```
**보안 참고**:
- Public API Key는 클라이언트 SDK 표준 방식 (Firebase 프로젝트 설정에서 도메인 제한)
- 환경변수 대신 코드에 포함 (일반적인 Firebase 클라이언트 앱 패턴)
### 환경 변수
```bash ```bash
# Firebase 설정 (필수)
NEXT_PUBLIC_FIREBASE_API_KEY=your_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id
# 사이트 URL (프로덕션) # 사이트 URL (프로덕션)
NEXT_PUBLIC_URL=https://raonnuri.com NEXT_PUBLIC_URL=https://raonnuri.com
@ -138,17 +166,6 @@ NEXT_PUBLIC_URL=https://raonnuri.com
NEXT_PUBLIC_API_URL=/api NEXT_PUBLIC_API_URL=/api
``` ```
### 환경 변수 사용 예시
```typescript
// src/config/firebase.ts
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
// ...
};
```
--- ---
## Firebase 설정 ## Firebase 설정
@ -467,14 +484,156 @@ const nickname = teamManager.getMemberNickname(team, uid, user?.name);
└─> migrateLegacyDraft() - 기존 단일 draft 마이그레이션 └─> migrateLegacyDraft() - 기존 단일 draft 마이그레이션
``` ```
### 4. 상태 관리 원칙 ### 4. 실시간 글쓰기 모니터링 아키텍처 (Firebase Realtime Database)
```
관리자 (팀 관리 페이지)
↓ 주제 선택
LiveWritingMonitor 컴포넌트
├─> 주제 드롭다운 (teamTopics)
└─> subscribeToTopic(teamId, topicId, callback)
↓ Firebase Realtime DB 구독
monitoring/{teamId}/{topicId}/{userId}
↑ 5초마다 업데이트
학생 (글쓰기 페이지)
├─> 팀 주제 선택 감지
└─> startMonitoring(teamId, topicId, getStats)
├─> 5초마다 통계 전송 (contentLength, wordCount)
├─> onDisconnect().remove() 설정
└─> 페이지 이탈 시 자동 정리
미리보기 요청-응답 플로우
관리자: requestPreview(userId)
↓ 요청 생성
previewRequests/{userId}/{requestId}
↓ 학생 리스너 감지
학생: listenForPreviewRequests(callback)
↓ 현재 글 내용 전송
previewResponses/{requestId}
↓ 관리자 구독
관리자: Promise 해결 → Dialog 표시
```
**주요 구성 요소**:
- **WritingSessionManager** (`src/managers/WritingSessionManager.ts`):
- `startMonitoring(teamId, topicId, getStatsCallback)`: 5초 주기 통계 전송
- `stopMonitoring()`: 전송 중지 + DB 삭제
- `subscribeToTopic(teamId, topicId, callback)`: 실시간 구독 (관리자)
- `requestPreview(userId)`: 미리보기 요청 (Promise 반환)
- `listenForPreviewRequests(onRequestCallback)`: 미리보기 리스너 (학생)
- 상세 디버그 로그 (전송/수신/에러 추적)
- **LiveWritingMonitor** (`src/components/team/LiveWritingMonitor.tsx`):
- 주제 선택 Select 컴포넌트 (Chakra UI Select)
- 실시간 학생 카드 그리드 (StudentMonitorCard)
- 유저 정보와 통계 자동 결합 (userManager 활용)
- **작성 속도 실시간 계산** (클라이언트 측, 글자/분)
- **Sparkline 그래프** (Area Chart, 최근 10개 히스토리)
- **인터랙티브 툴팁** (속도 값 + 몇 초 전 데이터)
- 미리보기 Dialog
- 마지막 업데이트 시간 표시 ("N초 전")
**Realtime DB 구조**:
```json
{
"monitoring": {
"{teamId}": {
"{topicId}": {
"{userId}": {
"userId": "abc123",
"contentLength": 1500,
"wordCount": 300,
"topicId": "topic_123",
"lastUpdated": 1731400800000
}
}
}
},
"previewRequests": {
"{userId}": {
"{requestId}": {
"requestedBy": "admin_uid",
"timestamp": 1234567890,
"requestId": "req_xyz"
}
}
},
"previewResponses": {
"{requestId}": {
"content": "현재 작성 중인 글...",
"timestamp": 1234567890,
"requestId": "req_xyz"
}
}
}
```
**Security Rules** (`database.rules.json`):
```json
{
"rules": {
"monitoring": {
"$teamId": {
"$topicId": {
".read": "auth != null",
"$userId": {
".write": "auth != null && auth.uid == $userId"
}
}
}
},
"previewRequests": {
"$userId": {
".read": "auth != null && auth.uid == $userId",
".write": "auth != null"
}
},
"previewResponses": {
"$requestId": {
".read": "auth != null",
".write": "auth != null"
}
}
}
}
```
**권한 정책**:
- 통계 읽기: 인증된 모든 사용자 (팀 소유자만 UI 접근 가능)
- 통계 쓰기: 본인만
- 미리보기: 요청자와 대상자만
**작성 속도 계산 로직** (클라이언트 측):
```typescript
// 5초마다 데이터 수신
const charDiff = 현재글자수 - 이전글자수;
const speed = charDiff * 12; // 5초 * 12 = 60초(1분)
// 히스토리 저장 (최근 10개)
speedHistory.push({ speed, timestamp: Date.now() });
if (speedHistory.length > 10) speedHistory.shift();
// Sparkline 그래프로 시각화
- Area Chart (면적 그래프)
- Teal 색상, 투명도 30%
- 툴팁: 마우스 오버 시 "N자/분" + "N초 전" 표시
- 0도 표시 (작성 멈춤 시각화)
```
**비용 효율성**:
- Firebase Realtime DB Spark 플랫폼: 동시 접속 100명까지 **완전 무료**
- GB 다운로드 기반 과금 (쓰기/읽기 횟수 무관)
- 30명 × 1시간 수업 = ~1.5MB (무료 한도 1GB/day의 0.15%)
### 5. 상태 관리 원칙
- **전역 상태**: Zustand 사용 (인증, 사용자 진행 상황, 알림) - **전역 상태**: Zustand 사용 (인증, 사용자 진행 상황, 알림)
- **로컬 상태**: `useState` 사용 (폼 입력, UI 토글, 에디터 내용) - **로컬 상태**: `useState` 사용 (폼 입력, UI 토글, 에디터 내용)
- **로컬 저장소**: LocalStorage (임시 저장 글) - **로컬 저장소**: LocalStorage (임시 저장 글)
- **서버 상태**: Firestore 직접 호출 (React Query는 나중에 고려) - **서버 상태**: Firestore 직접 호출 (React Query는 나중에 고려)
### 5. 태그 입력 필드 패턴 (Tag Input Field) ### 6. 태그 입력 필드 패턴 (Tag Input Field)
CreateTopicDialog의 제목 템플릿 입력에 사용되는 고급 UI 패턴입니다. CreateTopicDialog의 제목 템플릿 입력에 사용되는 고급 UI 패턴입니다.