docs: Sync documentation from private repository

This commit is contained in:
Documentation Bot 2025-11-13 04:14:56 +00:00
parent d09f99a0cc
commit 03256b411b
4 changed files with 393 additions and 59 deletions

View File

@ -655,6 +655,7 @@ interface MonitoringData extends WritingStats {
displayName: string; // 표시 이름
speedHistory: SpeedDataPoint[]; // 속도 히스토리 (최근 10개)
currentSpeed: number; // 현재 속도 (글자/분)
isActive: boolean; // 활성 상태 (false면 나간 상태)
preview?: string; // 미리보기 (선택적)
}
```
@ -696,6 +697,7 @@ interface MonitoringData extends WritingStats {
lastUpdated: 1731398400000,
displayName: "철수",
currentSpeed: 420, // 글자/분 (클라이언트 계산)
isActive: true, // 활성 상태 (30초 타임아웃 체크)
speedHistory: [ // 최근 10개 (클라이언트 계산)
{ speed: 480, timestamp: 1731398370000 },
{ speed: 420, timestamp: 1731398375000 },
@ -708,6 +710,21 @@ interface MonitoringData extends WritingStats {
}
```
**활성 상태 판단 로직**:
```typescript
// 1. Firebase에서 데이터 수신 → isActive: true
// 2. 30초 타임아웃 체크
const timeSinceUpdate = Date.now() - lastUpdated;
if (timeSinceUpdate > 30000) {
isActive = false; // 30초 이상 업데이트 없음 → 나감
}
// 3. Firebase에서 삭제되어도 마지막 통계 유지
if (!newData[userId] && prevData[userId]) {
keep prevData[userId] with isActive: false;
}
```
#### 9.2. previewRequests (미리보기 요청)
**경로**: `previewRequests/{userId}/{requestId}`

View File

@ -1,23 +1,42 @@
# 라온누리 - 프로젝트 구조
> 최종 업데이트: 2025-11-12 (실시간 글쓰기 모니터링 시스템)
> 최종 업데이트: 2025-11-13 (다국어 지원 시스템)
초등학생을 위한 창작 글쓰기 교육 플랫폼
**최신 업데이트** (2025-11-13):
- 🌏 **다국어 지원 시스템 (i18n)**
- next-intl 라이브러리 기반
- 한국어(ko), 영어(en) 지원
- **[locale] 라우팅**: URL에 언어 코드 표시 (`/ko/home`, `/en/home`)
- **브라우저 언어 자동 감지**: `Accept-Language` 헤더 기반 자동 리다이렉트
- **언어 전환 버튼**: LocaleSwitcher 컴포넌트 (Navbar 우측)
- **번역 파일**: `messages/ko.json`, `messages/en.json`
- **완성된 페이지**: Navbar, Landing 페이지, Home 페이지 전체 번역 완료
- **타입 안전**: useTranslations 훅으로 타입 체크
- **쿠키 저장**: 사용자가 선택한 언어 기억 (`NEXT_LOCALE`)
- **site.ts 텍스트 이동**: 사이트 메타데이터도 번역 파일로 관리
**최신 업데이트** (2025-11-12 PM):
- 📡 **실시간 글쓰기 모니터링 시스템**
- Firebase Realtime Database 기반 실시간 통신 (Redis Pub/Sub 방식)
- 팀 주제 선택 시 해당 주제로 작성 중인 학생 실시간 표시
- **모든 팀 멤버 표시** (getUsersByTeam)
- **3가지 상태 관리 및 자동 정렬**:
- 🟢 작성 중 (isActive: true, lastUpdated < 30초) - 초록 배지, 핑크 테두리
- 🟠 나감 (isActive: false, 마지막 통계 유지) - 주황 배지, 주황 테두리
- ⚪ 대기 중 (한 번도 작성 안 함) - 회색 배지, 투명도 60%
- 5초 주기 자동 업데이트 (글자 수, 단어 수, lastUpdated 타임스탬프)
- **작성 속도 계산** (클라이언트 측, 글자/분 단위)
- **Sparkline 그래프** (Area Chart, 최근 10개 데이터 포인트)
- **인터랙티브 툴팁** (마우스 오버 시 속도 + 몇 초 전 데이터인지 표시)
- 미리보기 요청-응답 시스템 (관리자 클릭 → 학생 응답 → Dialog 표시)
- onDisconnect() 자동 정리 (페이지 이탈 시 세션 자동 삭제)
- LiveWritingMonitor 컴포넌트 (주제 Select, 실시간 카드 그리드)
- **작성 속도 계산** (클라이언트 측, charDiff * 12 = 글자/분)
- **Sparkline 그래프** (Area Chart, 최근 10개 데이터 포인트, 0 표시)
- **인터랙티브 툴팁** (마우스 오버 시 속도 + 몇 초 전 데이터)
- 미리보기 요청-응답 (관리자 클릭 → 학생 응답 → Dialog, 작성 중만)
- **30초 타임아웃**: 업데이트 없으면 "나감" 처리
- **마지막 통계 유지**: Firebase 삭제되어도 클라이언트 상태 유지
- onDisconnect() 자동 정리 (페이지 이탈 시 세션 삭제)
- LiveWritingMonitor 컴포넌트 (주제 Select, StudentMonitorCard)
- WritingSessionManager (Realtime DB 작업, 상세 디버그 로그)
- 완전 무료 (동시 접속 100명까지, 1GB/day)
- Security Rules로 권한 관리 (본인 쓰기, 인증된 사용자 읽기)
- Security Rules (본인 쓰기, 인증된 사용자 읽기)
**최신 업데이트** (2025-11-12 AM):
- ✅ **Writing API 구현 완료**
@ -113,25 +132,39 @@
## 페이지 구조
### 🌏 다국어 라우팅 (2025-11-13)
모든 페이지는 `[locale]` 세그먼트를 통해 다국어를 지원합니다:
- **한국어**: `/ko/*` (기본값)
- **영어**: `/en/*`
- **자동 감지**: 브라우저 언어 설정에 따라 첫 방문 시 자동 리다이렉트
- **언어 전환**: Navbar의 지구본 버튼(🌐 KO/EN) 클릭
**URL 예시**:
- 랜딩: `/ko`, `/en`
- 홈: `/ko/home`, `/en/home`
- 글쓰기: `/ko/write`, `/en/write`
- 팀: `/ko/team`, `/en/team`
### ✅ 구현 완료
| 페이지 | 경로 | 설명 | 주요 기능 |
|-------|------|------|---------|
| **랜딩 페이지** | `/` | 서비스 소개 및 홍보 (비로그인 전용) | Hero, Features, How It Works, CTA, Footer<br>로그인 시 `/home`으로 자동 리다이렉트 |
| **유저 홈** | `/home` | 인증된 사용자 대시보드 | 환영 메시지, 빠른 시작 대시보드, 최근 활동<br>비로그인 시 `/`로 자동 리다이렉트<br>정식 계정은 "내 팀" 카드 추가 표시 |
| **글쓰기** | `/write` | Tiptap 기반 순수 텍스트 에디터 + 주제 선택 | 주제 선택 (자유 주제/개인 주제/팀 주제)<br>🆕 **주제 변경 경고** (작성 중 내용 초기화 알림, 임시 저장 안내)<br>제목 입력 (Editable), 순수 텍스트 에디터 (포맷팅 없음)<br>🆕 **다중 글조각 관리** (최대 10개), "새 글쓰기" / "저장된 글조각" 버튼<br>🆕 **강화된 자동 저장** (2초 debounce, 저장 상태 표시: 저장 중/저장됨)<br>템플릿 미리채우기 (제목/내용), Firestore 저장<br>비로그인도 접근 가능 (저장 시 로그인 유도) |
| **테스트** | `/test` | 팀 코드 시스템 테스트 페이지 | 팀 코드 생성/검증 테스트<br>팀/학생 생성 테스트<br>학생 로그인 테스트<br>authStore 상태 확인 |
| **팀 목록** | `/team` | 내가 만든 팀 목록 (정식 계정 전용) | 팀 카드 그리드, 팀 정보 (코드, 멤버 수, 보안 설정)<br>"새 팀 만들기" 버튼 |
| **팀 생성** | `/team/create` | 새 팀 만들기 (정식 계정 전용) | 팀 이름 입력, 팀 코드 자동 생성<br>🆕 **5단계 보안 레벨 선택** (RadioCard, 애니메이션)<br>🆕 **명단 관리 (Level 2/4)**: TagsInput으로 Enter/쉼표 입력<br>생성 후 `/team/[teamId]`로 이동 |
| **팀 멤버 페이지** | `/team/[teamId]` | 팀 멤버용 페이지 (멤버/소유자 모두 접근) | 팀 정보, 팀 코드 복사, 멤버 목록<br>소유자는 "팀 관리" 버튼 표시<br>팀 코드 로그인 후 기본 이동 페이지 |
| **팀 관리** | `/team/[teamId]/manage` | 팀 관리 페이지 (소유자 전용) | 팀 정보 및 코드, 보안 설정 표시<br>**팀 주제 관리 (생성/삭제)**<br>🆕 **주제별 학생 분석** (TopicMemberAnalysisSection)<br>멤버 목록 및 관리<br>🆕 **멤버 메뉴 - 팀 내 글 분석** (by-team)<br>"멤버 페이지 보기" 버튼 |
| 페이지 | 경로 | 설명 | 주요 기능 | 다국어 |
|-------|------|------|---------|--------|
| **랜딩 페이지** | `/[locale]` | 서비스 소개 및 홍보 (비로그인 전용) | Hero, Features, How It Works, CTA, Footer<br>로그인 시 `/home`으로 자동 리다이렉트<br>🆕 **전체 번역 완료** (사이트명, 태그라인, 모든 섹션) | ✅ 완료 |
| **유저 홈** | `/[locale]/home` | 인증된 사용자 대시보드 | 환영 메시지, 빠른 시작 대시보드, 최근 활동<br>비로그인 시 `/`로 자동 리다이렉트<br>정식 계정은 "내 팀" 카드 추가 표시<br>🆕 **전체 번역 완료** (웰컴 메시지, 모든 액션 카드) | ✅ 완료 |
| **글쓰기** | `/[locale]/write` | Tiptap 기반 순수 텍스트 에디터 + 주제 선택 | 주제 선택 (자유 주제/개인 주제/팀 주제)<br>🆕 **주제 변경 경고** (작성 중 내용 초기화 알림, 임시 저장 안내)<br>제목 입력 (Editable), 순수 텍스트 에디터 (포맷팅 없음)<br>🆕 **다중 글조각 관리** (최대 10개), "새 글쓰기" / "저장된 글조각" 버튼<br>🆕 **강화된 자동 저장** (2초 debounce, 저장 상태 표시: 저장 중/저장됨)<br>템플릿 미리채우기 (제목/내용), Firestore 저장<br>비로그인도 접근 가능 (저장 시 로그인 유도) | 🔜 예정 |
| **테스트** | `/[locale]/test` | 팀 코드 시스템 테스트 페이지 | 팀 코드 생성/검증 테스트<br>팀/학생 생성 테스트<br>학생 로그인 테스트<br>authStore 상태 확인 | 🔜 예정 |
| **팀 목록** | `/[locale]/team` | 내가 만든 팀 목록 (정식 계정 전용) | 팀 카드 그리드, 팀 정보 (코드, 멤버 수, 보안 설정)<br>"새 팀 만들기" 버튼 | 🔜 예정 |
| **팀 생성** | `/[locale]/team/create` | 새 팀 만들기 (정식 계정 전용) | 팀 이름 입력, 팀 코드 자동 생성<br>🆕 **5단계 보안 레벨 선택** (RadioCard, 애니메이션)<br>🆕 **명단 관리 (Level 2/4)**: TagsInput으로 Enter/쉼표 입력<br>생성 후 `/team/[teamId]`로 이동 | 🔜 예정 |
| **팀 멤버 페이지** | `/[locale]/team/[teamId]` | 팀 멤버용 페이지 (멤버/소유자 모두 접근) | 팀 정보, 팀 코드 복사, 멤버 목록<br>소유자는 "팀 관리" 버튼 표시<br>팀 코드 로그인 후 기본 이동 페이지 | 🔜 예정 |
| **팀 관리** | `/[locale]/team/[teamId]/manage` | 팀 관리 페이지 (소유자 전용) | 팀 정보 및 코드, 보안 설정 표시<br>**팀 주제 관리 (생성/삭제)**<br>🆕 **주제별 학생 분석** (TopicMemberAnalysisSection)<br>멤버 목록 및 관리<br>🆕 **멤버 메뉴 - 팀 내 글 분석** (by-team)<br>"멤버 페이지 보기" 버튼 | 🔜 예정 |
### 🚧 구현 예정
| 페이지 | 경로 | 설명 | 상태 |
|-------|------|------|------|
| **학습하기** | `/learn` | 레슨/코스 학습 | ❌ 미구현 (Navbar 링크만 존재) |
| **스티커** | `/stickers` | 스티커 컬렉션 | ❌ 미구현 (Navbar 링크만 존재) |
| **학습하기** | `/[locale]/learn` | 레슨/코스 학습 | ❌ 미구현 (Navbar 링크만 존재) |
| **스티커** | `/[locale]/stickers` | 스티커 컬렉션 | ❌ 미구현 (Navbar 링크만 존재) |
| **마이페이지** | Dialog (별도 페이지 없음) | 사용자 대시보드 다이얼로그 | 🔜 계획 중 (UserProfileButton에서 열림) |
---
@ -185,15 +218,21 @@
| 컴포넌트 | 파일명 | 설명 | 상태 |
|---------|--------|------|------|
| **Navbar** | `Navbar.tsx` | 상단 네비게이션 바 | ✅ 완료 |
| **Navbar** | `Navbar.tsx` | 상단 네비게이션 바 (다국어 지원) | ✅ 완료 |
| **LocaleSwitcher** | `LocaleSwitcher.tsx` | 🆕 **언어 전환 버튼** (KO ↔ EN, 지구본 아이콘) | ✅ 완료 |
**네비게이션 링크**:
- 홈 (`/` 또는 `/home`) - 인증 상태에 따라 동적 변경
- 비로그인: `/` (랜딩 페이지)
- 로그인: `/home` (유저 대시보드)
- 글쓰기 (`/write`) - 미구현
- 학습하기 (`/learn`) - 미구현
- 스티커 (`/stickers`) - 미구현
**네비게이션 링크** (다국어 지원):
- 홈 (`/[locale]` 또는 `/[locale]/home`) - 인증 상태에 따라 동적 변경
- 비로그인: `/[locale]` (랜딩 페이지)
- 로그인: `/[locale]/home` (유저 대시보드)
- 글쓰기 (`/[locale]/write`) - 미구현
- 학습하기 (`/[locale]/learn`) - 미구현
- 스티커 (`/[locale]/stickers`) - 미구현
**주요 기능** (2025-11-13):
- ✅ next-intl 타입 안전 Link 사용
- ✅ useTranslations 훅으로 번역 텍스트 관리
- ✅ LocaleSwitcher로 실시간 언어 전환
---
@ -310,6 +349,11 @@
**주요 기능**:
- ✅ **LiveWritingMonitor** (2025-11-12):
- 주제 선택 드롭다운 (Chakra UI Select)
- **모든 팀 멤버 표시** (getUsersByTeam)
- **3가지 상태 관리 및 정렬**:
- 🟢 작성 중 (isActive: true, lastUpdated < 30초)
- 🟠 나감 (isActive: false, 마지막 통계 유지)
- ⚪ 대기 중 (한 번도 작성 안 함)
- StudentMonitorCard 컴포넌트 (개별 학생 카드)
- 실시간 통계: 글자 수, 단어 수, 마지막 업데이트 시간 ("N초 전")
- **작성 속도 계산** (클라이언트 측, charDiff * 12 = 글자/분)
@ -320,9 +364,11 @@
- **인터랙티브 툴팁** (Recharts Tooltip)
- 속도 값 ("N자/분")
- 시간 정보 ("N초 전")
- 미리보기 버튼 (Dialog로 현재 작성 중인 글 표시)
- 미리보기 버튼 (작성 중인 학생만)
- **30초 타임아웃**: 업데이트 없으면 "나감" 처리
- **마지막 통계 유지**: 나간 학생도 통계 표시
- 실시간 구독/구독 해제 (useEffect cleanup)
- 빈 상태 UI (작성 중인 학생 없을 때)
- 시각적 구분 (색상별 테두리, 아바타, 배지)
- ✅ SecurityLevelSelector: RadioCard 기반, 선택 시 추가 UI 애니메이션으로 표시
- ✅ AllowListManager: Level 2/4용 명단 관리, Enter/쉼표로 구분 입력
- ✅ 그라데이션 배경 (RadioCard와 자연스럽게 연결)
@ -514,35 +560,45 @@
project_w/
├── database.rules.json # 🆕 Firebase Realtime DB Security Rules
├── messages/ # 🆕 다국어 번역 파일
│ ├── ko.json # 한국어 번역
│ └── en.json # 영어 번역
├── src/
├── i18n/ # 🆕 다국어 설정
│ ├── routing.ts # 라우팅 설정 (locales, defaultLocale)
│ └── request.ts # 번역 메시지 로더
├── middleware.ts # 🆕 next-intl 미들웨어 (언어 감지, 리다이렉트)
├── app/ # Next.js App Router
│ ├── layout.tsx # 루트 레이아웃
│ ├── page.tsx # 랜딩 페이지 (/) - 로그인 시 /home 리다이렉트
│ ├── home/
│ │ └── page.tsx # ✅ 유저 홈 페이지 (/home)
│ ├── write/
│ │ └── page.tsx # ✅ 글쓰기 페이지 (/write) - 🆕 실시간 모니터링 전송
│ ├── test/
│ │ └── page.tsx # ✅ 테스트 페이지 (/test) - 팀 코드 시스템 테스트
├── globals.css
├── favicon.ico
├── team/ # ✅ 팀 관리 페이지들
│ │ ├── page.tsx # ✅ 팀 목록 (/team)
│ ├── layout.tsx # 루트 레이아웃 (메타데이터만)
│ ├── [locale]/ # 🆕 다국어 라우팅
│ ├── layout.tsx # locale별 레이아웃 (Provider, Navbar, Auth)
│ │ ├── page.tsx # ✅ 랜딩 페이지 (/[locale]) - 🆕 전체 번역 완료
│ ├── home/
│ │ │ └── page.tsx # ✅ 유저 홈 페이지 (/[locale]/home) - 🆕 전체 번역 완료
│ ├── write/
│ │ │ └── page.tsx # ✅ 글쓰기 페이지 (/[locale]/write) - 🆕 실시간 모니터링
│ ├── test/
│ │ └── page.tsx # ✅ 테스트 페이지 (/[locale]/test)
│ └── team/ # ✅ 팀 관리 페이지들
│ │ ├── page.tsx # ✅ 팀 목록 (/[locale]/team)
│ │ ├── create/
│ │ │ └── page.tsx # ✅ 팀 생성 (/team/create)
│ │ │ └── page.tsx # ✅ 팀 생성 (/[locale]/team/create)
│ │ └── [teamId]/
│ │ ├── page.tsx # ✅ 팀 멤버 페이지 (/team/[teamId])
│ │ ├── page.tsx # ✅ 팀 멤버 페이지 (/[locale]/team/[teamId])
│ │ └── manage/
│ │ └── page.tsx # ✅ 팀 관리 페이지 (/team/[teamId]/manage)
│ └── [미구현 페이지들]
│ ├── learn/ # 학습 페이지
│ ├── stickers/ # 스티커 페이지
│ └── admin/ # 관리자
│ │ └── page.tsx # ✅ 팀 관리 페이지 (/[locale]/team/[teamId]/manage)
│ ├── globals.css
│ └── favicon.ico
├── components/ # React 컴포넌트
│ ├── auth/ # ✅ 인증 (로그인, 프로필, 팀 코드)
│ ├── landing/ # ✅ 랜딩 페이지 카드들
│ ├── navigation/ # ✅ 네비게이션 바
│ ├── landing/ # ✅ 랜딩 페이지 카드들 (다국어 지원)
│ ├── navigation/ # ✅ 네비게이션 바 (다국어 지원)
│ │ ├── Navbar.tsx # 다국어 링크 텍스트
│ │ └── LocaleSwitcher.tsx # 🆕 언어 전환 버튼
│ ├── seo/ # ✅ SEO 컴포넌트
│ ├── ui/ # ✅ Chakra UI 기본
│ ├── writing/ # ✅ 글쓰기 에디터

View File

@ -1,6 +1,6 @@
# 라온누리 - 개발 로드맵
> 최종 업데이트: 2025-11-12 (실시간 글쓰기 모니터링 시스템)
> 최종 업데이트: 2025-11-13 (다국어 지원 시스템)
초등학생을 위한 창작 글쓰기 교육 플랫폼 개발 계획
@ -83,7 +83,8 @@
| **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 기반 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** |
| **실시간 글쓰기 모니터링** | **Firebase Realtime Database 기반 실시간 통신 (Redis Pub/Sub 방식), WritingSessionManager (5초 주기 통계 전송, 미리보기 요청-응답, 상세 디버그 로그), LiveWritingMonitor (주제 Select, 모든 팀 멤버 표시, StudentMonitorCard), 3가지 상태 관리 (작성 중/나감/대기 중, 정렬 순서, 색상별 시각화), 글쓰기 페이지 모니터링 (contentRef 최적화), onDisconnect() 자동 정리, 작성 속도 계산 (클라이언트, 글자/분, charDiff*12), Sparkline 그래프 (Area Chart, 최근 10개, 0 표시), 인터랙티브 툴팁 (속도+시간), 30초 타임아웃 체크 (lastUpdated), 마지막 통계 유지 (Firebase 삭제되어도 유지), database.rules.json (topicId 레벨 읽기), @chakra-ui/charts+recharts, 완전 무료 (100명)** | **2025-11-12** |
| **다국어 지원 시스템 (i18n)** | **next-intl 라이브러리 설치 및 설정, [locale] 라우팅 구조 변경 (/ko/*, /en/*), middleware.ts 생성 (브라우저 언어 자동 감지, Accept-Language 헤더), 번역 파일 생성 (messages/ko.json, messages/en.json), Navbar 번역 적용 (useTranslations 훅), LocaleSwitcher 컴포넌트 (지구본 아이콘 + KO/EN 토글), Landing 페이지 전체 번역 (Hero, Features, Steps, CTA, Footer), Home 페이지 전체 번역 (Welcome, QuickStart 9개 액션 카드, RecentActivity), site.ts 텍스트를 번역 파일로 이동 (사이트명, 태그라인, 저작권), localeDetection: true 설정, NEXT_LOCALE 쿠키 저장, next.config.ts에 next-intl 플러그인 추가, i18n/routing.ts + i18n/request.ts 설정, 타입 체크 통과** | **2025-11-13** |
### 🚧 진행 중

View File

@ -1,6 +1,6 @@
# 라온누리 - 기술 스택 및 개발 환경
> 최종 업데이트: 2025-11-12 (실시간 글쓰기 모니터링 시스템)
> 최종 업데이트: 2025-11-13 (다국어 지원 시스템)
---
@ -25,6 +25,7 @@
| **Framer Motion** | 12.23.24 | 애니메이션 라이브러리 |
| **React Icons** | 5.5.0 | 아이콘 세트 |
| **Tiptap** | latest | 리치 텍스트 에디터 |
| **next-intl** | latest | 🆕 **다국어 지원 (i18n)** |
### Backend & Database
@ -526,12 +527,20 @@ LiveWritingMonitor 컴포넌트
- **LiveWritingMonitor** (`src/components/team/LiveWritingMonitor.tsx`):
- 주제 선택 Select 컴포넌트 (Chakra UI Select)
- 실시간 학생 카드 그리드 (StudentMonitorCard)
- **모든 팀 멤버 표시** (getUsersByTeam)
- **3가지 상태 관리**:
- 🟢 작성 중 (isActive: true, lastUpdated < 30초) - 초록 배지, 핑크 테두리
- 🟠 나감 (isActive: false, 마지막 통계 유지) - 주황 배지, 주황 테두리
- ⚪ 대기 중 (한 번도 작성 안 함) - 회색 배지, 투명도 60%
- **정렬 순서**: 작성 중 → 나감 → 대기 중
- StudentMonitorCard 컴포넌트 (개별 학생 카드)
- 유저 정보와 통계 자동 결합 (userManager 활용)
- **작성 속도 실시간 계산** (클라이언트 측, 글자/분)
- **Sparkline 그래프** (Area Chart, 최근 10개 히스토리)
- **인터랙티브 툴팁** (속도 값 + 몇 초 전 데이터)
- 미리보기 Dialog
- 미리보기 Dialog (작성 중인 학생만)
- **30초 타임아웃**: 업데이트 없으면 "나감" 처리
- **마지막 통계 유지**: Firebase 삭제되어도 클라이언트 상태 유지
- 마지막 업데이트 시간 표시 ("N초 전")
**Realtime DB 구조**:
@ -1162,6 +1171,257 @@ interface Draft {
---
### 12. 다국어 지원 시스템 (i18n)
#### 핵심 개념
**목적**: 한국어/영어 사용자 모두 접근 가능한 글로벌 플랫폼 구축
**라이브러리**: next-intl (Next.js App Router 표준 i18n 라이브러리)
**지원 언어**:
- 한국어 (ko) - 기본값
- 영어 (en)
#### 아키텍처
```
브라우저 요청 (/)
Middleware (src/middleware.ts)
├─> Accept-Language 헤더 확인
├─> NEXT_LOCALE 쿠키 확인
└─> 적절한 locale로 리다이렉트
├─> 한국어 우선: /ko
└─> 영어 우선: /en
[locale] 라우팅 (src/app/[locale]/*)
├─> layout.tsx (locale별 레이아웃)
│ ├─> NextIntlClientProvider (번역 메시지 주입)
│ ├─> Provider (Chakra UI)
│ ├─> Navbar (다국어 메뉴)
│ └─> AuthInitializer
└─> page.tsx (각 페이지)
└─> useTranslations('namespace') 훅 사용
└─> {t('key')} 형태로 번역 표시
```
#### 번역 파일 구조
**파일 위치**: `messages/{locale}.json`
```json
// messages/ko.json
{
"site": {
"name": "라온누리",
"tagline": "재미있게 글쓰기를 배워보자!",
"subtitle": "친구들과 함께 신나는 글쓰기 모험을 떠나요"
},
"navbar": {
"home": "홈",
"write": "글쓰기",
"learn": "학습하기",
"stickers": "스티커"
},
"landing": {
"hero": {
"cta": "지금 시작하기",
"teamCode": "팀 코드로 참여"
},
"features": {...},
"howItWorks": {...}
},
"home": {
"hero": {
"welcome": "환영합니다, {name}님!", // 파라미터 지원
"subtitle": "오늘도 멋진 글쓰기를 시작해볼까요?"
},
"quickStart": {...}
}
}
```
#### 설정 파일
**i18n/routing.ts** - 라우팅 설정:
```typescript
export const routing = defineRouting({
locales: ['ko', 'en'],
defaultLocale: 'ko',
localePrefix: 'always', // URL에 항상 표시 (/ko/*, /en/*)
localeDetection: true // 브라우저 언어 자동 감지
});
// next-intl 타입 안전 내비게이션 API
export const {Link, redirect, usePathname, useRouter} = createNavigation(routing);
```
**i18n/request.ts** - 번역 메시지 로더:
```typescript
export default getRequestConfig(async ({requestLocale}) => {
let locale = await requestLocale;
if (!locale || !routing.locales.includes(locale)) {
locale = routing.defaultLocale;
}
return {
locale,
messages: (await import(`../../messages/${locale}.json`)).default
};
});
```
**middleware.ts** - 자동 언어 감지:
```typescript
import createMiddleware from 'next-intl/middleware';
import {routing} from './i18n/routing';
export default createMiddleware(routing);
export const config = {
matcher: ['/', '/(ko|en)/:path*']
};
```
#### 컴포넌트 사용 패턴
**Server Component** (기본):
```typescript
import {useTranslations} from 'next-intl';
export default function Page() {
const t = useTranslations('namespace');
return <h1>{t('key')}</h1>;
}
```
**Client Component**:
```typescript
"use client";
import {useTranslations} from 'next-intl';
export default function ClientComponent() {
const t = useTranslations('namespace');
return <p>{t('key')}</p>;
}
```
**파라미터가 있는 번역**:
```typescript
const t = useTranslations('home');
// messages/ko.json: "welcome": "환영합니다, {name}님!"
<h1>{t('hero.welcome', {name: userName})}</h1>
// → "환영합니다, 홍길동님!"
```
**타입 안전 Link** (locale 자동 처리):
```typescript
import {Link} from '@/i18n/routing';
<Link href="/home">홈으로</Link>
// 현재 locale이 ko면 → /ko/home
// 현재 locale이 en이면 → /en/home
```
#### 언어 전환 버튼
**LocaleSwitcher** (`src/components/navigation/LocaleSwitcher.tsx`):
```typescript
const locale = useLocale(); // 현재 언어
const router = useRouter();
const pathname = usePathname();
const toggleLocale = () => {
const nextLocale = locale === 'ko' ? 'en' : 'ko';
router.replace(pathname, {locale: nextLocale});
};
return (
<Button onClick={toggleLocale}>
<LuGlobe /> {locale.toUpperCase()}
</Button>
);
```
**동작**:
- `/ko/home`에서 버튼 클릭 → `/en/home`으로 이동
- `NEXT_LOCALE` 쿠키에 저장 (다음 방문 시 기억)
#### 브라우저 언어 자동 감지
**첫 방문 시나리오**:
```
1. 사용자가 / 접속 (쿠키 없음)
2. Middleware가 Accept-Language 헤더 확인
- "en-US,en;q=0.9" → /en/으로 리다이렉트
- "ko-KR,ko;q=0.9" → /ko/로 리다이렉트
- 지원하지 않는 언어 → /ko/ (기본값)
3. NEXT_LOCALE 쿠키 저장
다음 방문 시:
1. 쿠키에서 저장된 언어 확인
2. 해당 언어로 바로 리다이렉트
```
#### 완성된 다국어 페이지
| 페이지 | 경로 | 상태 | 번역 항목 |
|-------|------|------|-----------|
| **Navbar** | 모든 페이지 | ✅ 완료 | 홈, 글쓰기, 학습하기, 스티커 (4개) |
| **Landing** | `/[locale]` | ✅ 완료 | Hero(사이트명, 태그라인, CTA 버튼), Features(4개 카드), Steps(3단계), CTA 섹션, Footer (총 20+ 항목) |
| **Home** | `/[locale]/home` | ✅ 완료 | 웰컴 메시지, QuickStart(9개 액션 카드), RecentActivity (총 15+ 항목) |
| **Write** | `/[locale]/write` | 🔜 예정 | - |
| **Team** | `/[locale]/team/*` | 🔜 예정 | - |
#### next.config.ts 설정
```typescript
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts');
const nextConfig = {
reactCompiler: true,
};
export default withNextIntl(nextConfig);
```
#### 참고 파일
**설정**:
- `src/i18n/routing.ts` - 라우팅 설정
- `src/i18n/request.ts` - 번역 로더
- `src/middleware.ts` - 언어 감지 미들웨어
- `messages/ko.json`, `messages/en.json` - 번역 파일
**컴포넌트**:
- `src/components/navigation/LocaleSwitcher.tsx` - 언어 전환 버튼
- `src/components/navigation/Navbar.tsx` - 다국어 메뉴
- `src/app/[locale]/page.tsx` - Landing 페이지 (전체 번역)
- `src/app/[locale]/home/page.tsx` - Home 페이지 (전체 번역)
**타입 안전성**:
- next-intl은 타입 추론을 지원하지만, JSON 구조에 따라 자동 완성됨
- 없는 키 사용 시 런타임 에러 (개발 모드에서는 경고)
#### 장점
**타입 안전**: useTranslations 훅으로 타입 체크
**Server/Client 지원**: RSC에서도 번역 가능
**자동 코드 스플리팅**: 필요한 번역만 로드
**SEO 친화적**: locale별 URL (/ko/*, /en/*)
**쿠키 기반 기억**: 사용자 선택 언어 저장
**브라우저 자동 감지**: Accept-Language 헤더
---
## 참고 문서
- [PROJECT_STRUCTURE.md](./PROJECT_STRUCTURE.md) - 프로젝트 구조