docs: Sync documentation from private repository
This commit is contained in:
parent
e8d5da3866
commit
e8d98f43ff
73
API_SPEC.md
73
API_SPEC.md
@ -2,7 +2,19 @@
|
|||||||
|
|
||||||
라온누리 서버 API 명세서
|
라온누리 서버 API 명세서
|
||||||
|
|
||||||
## ⚠️ 최신 변경사항 (2025-11-12)
|
## ⚠️ 최신 변경사항 (2025-11-26)
|
||||||
|
|
||||||
|
### 🔗 익명 계정 연결 기능
|
||||||
|
- **POST /api/auth/merge-account**: 익명 계정 데이터를 정식 계정으로 마이그레이션
|
||||||
|
- Firestore 데이터 이전 (writings, topics, comments, userReactions, teams)
|
||||||
|
- Realtime DB 데이터 이전 (drafts, monitoring, previewRequests)
|
||||||
|
- 원자성 보장 (Firestore Batch, Realtime DB Transaction)
|
||||||
|
- 병합 완료 후 통계 반환
|
||||||
|
- **서비스 레이어**: `src/services/firebaseAuth.ts` (mergeAndLoginWithEmail, mergeAndLoginWithGoogle)
|
||||||
|
- **상태 관리**: `src/store/authStore.ts` (mergeWithEmail, mergeWithGoogle 액션)
|
||||||
|
- **UI 통합**: LoginForm/SignupForm mode prop, LoginDialog link 모드
|
||||||
|
|
||||||
|
## ⚠️ 변경사항 (2025-11-12)
|
||||||
|
|
||||||
### ✅ Writing API 구현 완료
|
### ✅ Writing API 구현 완료
|
||||||
- **POST /api/writing**: 글 생성 (서버에서 wordCount/charCount 자동 계산)
|
- **POST /api/writing**: 글 생성 (서버에서 wordCount/charCount 자동 계산)
|
||||||
@ -849,6 +861,65 @@ await teamManager.removeMember(teamId, currentUser.uid);
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Auth API
|
||||||
|
|
||||||
|
### POST `/auth/merge-account` - 익명 계정 데이터 병합
|
||||||
|
실제 URL: `POST /api/auth/merge-account`
|
||||||
|
|
||||||
|
**인증**: 필수 (정식 계정으로 로그인된 상태)
|
||||||
|
|
||||||
|
**Request**:
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
anonymousUid: string; // 병합할 익명 계정의 UID
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response**:
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
mergedCounts: {
|
||||||
|
writings: number; // 이전된 글 개수
|
||||||
|
topics: number; // 이전된 주제 개수
|
||||||
|
comments: number; // 이전된 댓글 개수
|
||||||
|
userReactions: number; // 이전된 반응 개수
|
||||||
|
teamMemberships: number; // 이전된 팀 멤버십 개수
|
||||||
|
drafts: number; // 이전된 초안 개수
|
||||||
|
monitoring: number; // 이전된 모니터링 세션 개수
|
||||||
|
previewRequests: number; // 이전된 미리보기 요청 개수
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**동작**:
|
||||||
|
1. **Firestore 데이터 마이그레이션** (Batch 사용):
|
||||||
|
- `writings` 컬렉션: userId 업데이트
|
||||||
|
- `topics` 컬렉션: ownerId 업데이트 (개인 주제만)
|
||||||
|
- `comments` 컬렉션: authorId 업데이트
|
||||||
|
- `userReactions` 컬렉션: userId 업데이트
|
||||||
|
- `teams` 컬렉션: members 키 변경 (anonymousUid → targetUid)
|
||||||
|
|
||||||
|
2. **Realtime DB 데이터 마이그레이션** (Transaction 사용):
|
||||||
|
- `drafts/{anonymousUid}` → `drafts/{targetUid}` 이동
|
||||||
|
- `monitoring/{topicId}/{anonymousUid}` → `monitoring/{topicId}/{targetUid}` 이동
|
||||||
|
- `previewRequests/{topicId}/{anonymousUid}` → `previewRequests/{topicId}/{targetUid}` 이동
|
||||||
|
|
||||||
|
**제약사항**:
|
||||||
|
- 익명 계정과 정식 계정은 다른 UID여야 함
|
||||||
|
- 익명 계정 데이터는 병합 후 자동 삭제되지 않음 (수동 정리 필요)
|
||||||
|
|
||||||
|
**에러 코드**:
|
||||||
|
- `400`: anonymousUid 누락
|
||||||
|
- `401`: 인증되지 않은 요청
|
||||||
|
- `500`: 마이그레이션 실패
|
||||||
|
|
||||||
|
**캐싱**: 없음 (일회성 작업)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## User API
|
## User API
|
||||||
|
|
||||||
**중요**: User vs FirestoreUser 구분
|
**중요**: User vs FirestoreUser 구분
|
||||||
|
|||||||
@ -275,10 +275,10 @@
|
|||||||
| 컴포넌트 | 파일명 | 설명 | 상태 |
|
| 컴포넌트 | 파일명 | 설명 | 상태 |
|
||||||
|---------|--------|------|------|
|
|---------|--------|------|------|
|
||||||
| **AuthInitializer** | `AuthInitializer.tsx` | Firebase 인증 상태 초기화 | ✅ 완료 |
|
| **AuthInitializer** | `AuthInitializer.tsx` | Firebase 인증 상태 초기화 | ✅ 완료 |
|
||||||
| **LoginDialog** | `LoginDialog.tsx` | 로그인/회원가입 다이얼로그 (일반/팀 코드 모드 전환) | ✅ 완료 |
|
| **LoginDialog** | `LoginDialog.tsx` | 로그인/회원가입 다이얼로그 (auth/team/link 모드 지원) | ✅ 완료 |
|
||||||
| **StudentLoginFlow** | `StudentLoginFlow.tsx` | 팀 코드 학생 로그인 플로우 (3단계) | ✅ 완료 |
|
| **StudentLoginFlow** | `StudentLoginFlow.tsx` | 팀 코드 학생 로그인 플로우 (3단계) | ✅ 완료 |
|
||||||
| **LoginForm** | `LoginForm.tsx` | 로그인 폼 컴포넌트 | ✅ 완료 |
|
| **LoginForm** | `LoginForm.tsx` | 로그인 폼 컴포넌트 (mode: auth\|link) | ✅ 완료 |
|
||||||
| **SignupForm** | `SignupForm.tsx` | 회원가입 폼 컴포넌트 | ✅ 완료 |
|
| **SignupForm** | `SignupForm.tsx` | 회원가입 폼 컴포넌트 (mode: auth\|link) | ✅ 완료 |
|
||||||
| **SocialLoginButton** | `SocialLoginButton.tsx` | 소셜 로그인 버튼 | ✅ 완료 |
|
| **SocialLoginButton** | `SocialLoginButton.tsx` | 소셜 로그인 버튼 | ✅ 완료 |
|
||||||
| **UserProfileButton** | `UserProfileButton.tsx` | 사용자 프로필/메뉴 버튼 | ✅ 완료 |
|
| **UserProfileButton** | `UserProfileButton.tsx` | 사용자 프로필/메뉴 버튼 | ✅ 완료 |
|
||||||
|
|
||||||
@ -290,6 +290,12 @@
|
|||||||
- ✅ HIBP API 연동 (유출된 비밀번호 차단)
|
- ✅ HIBP API 연동 (유출된 비밀번호 차단)
|
||||||
- ✅ 폼 검증 및 에러 애니메이션
|
- ✅ 폼 검증 및 에러 애니메이션
|
||||||
- ✅ Google OAuth 로그인
|
- ✅ Google OAuth 로그인
|
||||||
|
- ✅ 익명 계정 연결 기능
|
||||||
|
- ✅ 기존 폼 재사용 (LoginForm/SignupForm mode prop)
|
||||||
|
- ✅ 신규 계정 생성 (linkWithCredential)
|
||||||
|
- ✅ 기존 계정 병합 (API 데이터 마이그레이션)
|
||||||
|
- ✅ 3개 소셜 로그인 버튼 표시 (Naver/Kakao/Google)
|
||||||
|
- ✅ 용어 통일 ("병합" → "연결", "익명" → "임시")
|
||||||
- ✅ 팀 코드 기반 사용자 로그인 (Anonymous Auth - 단순화됨)
|
- ✅ 팀 코드 기반 사용자 로그인 (Anonymous Auth - 단순화됨)
|
||||||
- ✅ 한글 팀 코드 ("춤추는 파란 사자" 형식)
|
- ✅ 한글 팀 코드 ("춤추는 파란 사자" 형식)
|
||||||
- ✅ 사용자 이름 입력 (2단계)
|
- ✅ 사용자 이름 입력 (2단계)
|
||||||
@ -756,6 +762,7 @@ firebase functions:log --only cleanupExpiredReservations
|
|||||||
| **AI 이미지 생성** | `/api/generate-image` | POST | 🆕 **장면 기반 이미지 생성** (🆕 **AI 프롬프트 최적화**, Imagen 3.0, Firebase Storage 저장, Writing 업데이트) | ✅ 완료 |
|
| **AI 이미지 생성** | `/api/generate-image` | POST | 🆕 **장면 기반 이미지 생성** (🆕 **AI 프롬프트 최적화**, Imagen 3.0, Firebase Storage 저장, Writing 업데이트) | ✅ 완료 |
|
||||||
| **주제 CRUD** | `/api/topic` | GET, POST, PUT, DELETE | 주제 생성/조회/수정/삭제 (9개 엔드포인트) | ✅ 완료 |
|
| **주제 CRUD** | `/api/topic` | GET, POST, PUT, DELETE | 주제 생성/조회/수정/삭제 (9개 엔드포인트) | ✅ 완료 |
|
||||||
| **주제별 작성자** | `/api/topic/[topicId]/writers` | GET | 🆕 **주제로 글 쓴 학생 목록** (글 개수, Firebase Auth 결합, 글 개수 내림차순) | ✅ 완료 |
|
| **주제별 작성자** | `/api/topic/[topicId]/writers` | GET | 🆕 **주제로 글 쓴 학생 목록** (글 개수, Firebase Auth 결합, 글 개수 내림차순) | ✅ 완료 |
|
||||||
|
| **계정 병합** | `/api/auth/merge-account` | POST | 🆕 **익명 계정 데이터 병합** (Firestore + Realtime DB 마이그레이션, Batch/Transaction, 통계 반환) | ✅ 완료 |
|
||||||
| **사용자 관리** | `/api/user` | GET, POST, PUT | 사용자 조회/생성/업데이트 | ✅ 완료 |
|
| **사용자 관리** | `/api/user` | GET, POST, PUT | 사용자 조회/생성/업데이트 | ✅ 완료 |
|
||||||
|
|
||||||
**서버 레이어** (`src/lib/server/`):
|
**서버 레이어** (`src/lib/server/`):
|
||||||
@ -783,8 +790,10 @@ firebase functions:log --only cleanupExpiredReservations
|
|||||||
- ✅ **isAuthenticated** - 로그인 여부 (익명 포함)
|
- ✅ **isAuthenticated** - 로그인 여부 (익명 포함)
|
||||||
- ✅ **user.isAnonymous** - 익명/정식 계정 구분
|
- ✅ **user.isAnonymous** - 익명/정식 계정 구분
|
||||||
- ✅ **loginAsUser()** - 팀 코드 로그인 (PIN 제거)
|
- ✅ **loginAsUser()** - 팀 코드 로그인 (PIN 제거)
|
||||||
- ✅ **linkWithEmail()** - 이메일 계정 연결
|
- ✅ **linkWithEmail()** - 이메일 계정 연결 (신규 계정 생성)
|
||||||
- ✅ **linkWithGoogle()** - Google 계정 연결
|
- ✅ **linkWithGoogle()** - Google 계정 연결 (신규 계정 생성)
|
||||||
|
- ✅ **mergeWithEmail()** - 기존 이메일 계정과 병합 (데이터 마이그레이션)
|
||||||
|
- ✅ **mergeWithGoogle()** - 기존 Google 계정과 병합 (데이터 마이그레이션)
|
||||||
- ❌ ~~currentStudent~~, ~~ownedStudents~~, ~~switchStudent()~~ 제거 (복잡도 감소)
|
- ❌ ~~currentStudent~~, ~~ownedStudents~~, ~~switchStudent()~~ 제거 (복잡도 감소)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@ -115,6 +115,7 @@
|
|||||||
| **글 상세 페이지 댓글 기능 연결** | **CommentList 컴포넌트를 writing/[writingId]/page.tsx에 연결, 댓글 보기/작성/답글/삭제 기능 활성화** | **2025-11-26** |
|
| **글 상세 페이지 댓글 기능 연결** | **CommentList 컴포넌트를 writing/[writingId]/page.tsx에 연결, 댓글 보기/작성/답글/삭제 기능 활성화** | **2025-11-26** |
|
||||||
| **미사용 코드 정리** | **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** |
|
||||||
|
|
||||||
### 🚧 진행 중
|
### 🚧 진행 중
|
||||||
|
|
||||||
|
|||||||
@ -422,10 +422,11 @@ const nickname = teamManager.getMemberNickname(team, uid, user?.name);
|
|||||||
├─> isLoading
|
├─> isLoading
|
||||||
└─> 액션:
|
└─> 액션:
|
||||||
├─> login/signup/loginWithGoogle (기존)
|
├─> login/signup/loginWithGoogle (기존)
|
||||||
├─> **loginAsStudent(classCode, name, pin?)** - 팀 코드 로그인
|
├─> **loginAsUser(teamCode, name)** - 팀 코드 로그인 (익명 계정 생성)
|
||||||
├─> **switchStudent(student)** - 학생 전환
|
├─> **linkWithEmail(email, password)** - 신규 이메일 계정 생성 (linkWithCredential)
|
||||||
├─> **linkCurrentStudentWithEmail()** - 계정 연결
|
├─> **linkWithGoogle()** - 신규 Google 계정 생성 (linkWithCredential)
|
||||||
└─> **linkCurrentStudentWithGoogle()** - Google 계정 연결
|
├─> **mergeWithEmail(email, password)** - 기존 이메일 계정과 병합 (API 데이터 마이그레이션)
|
||||||
|
└─> **mergeWithGoogle()** - 기존 Google 계정과 병합 (API 데이터 마이그레이션)
|
||||||
|
|
||||||
3. 인증 기반 라우팅
|
3. 인증 기반 라우팅
|
||||||
├─> 랜딩 페이지 (/)
|
├─> 랜딩 페이지 (/)
|
||||||
@ -786,15 +787,23 @@ const [selectedPartIndex, setSelectedPartIndex] = useState<number | null>(null);
|
|||||||
├─> authStore.currentStudent 설정
|
├─> authStore.currentStudent 설정
|
||||||
└─> /team/[teamId] 멤버 페이지로 이동
|
└─> /team/[teamId] 멤버 페이지로 이동
|
||||||
|
|
||||||
2. 정식 계정 연결 (선택적, 학부모/고학년)
|
2. 정식 계정 연결 (선택적)
|
||||||
├─> 설정 → "내 계정 만들기"
|
├─> UserProfileButton → "계정 연결하기"
|
||||||
├─> 이메일 회원가입 또는 Google 로그인
|
├─> LoginDialog (link 모드)
|
||||||
├─> linkWithCredential() 호출
|
├─> 2가지 시나리오:
|
||||||
│ └─ Anonymous(anon123) → Email(user456) 전환
|
│ ├─ **신규 계정 생성** (linkWithCredential):
|
||||||
├─> Firestore 연결:
|
│ │ ├─ 이메일 회원가입 또는 Google 로그인
|
||||||
│ ├─ students/studentDoc.linkedUserId = user456
|
│ │ ├─ linkWithCredential() 호출
|
||||||
│ └─ users/user456.ownedStudentIds = [studentDoc]
|
│ │ └─ Anonymous(anon123) → Email(user456) 전환 (UID 유지)
|
||||||
└─> 이후 user456으로 로그인 가능 (currentStudent 자동 설정)
|
│ │
|
||||||
|
│ └─ **기존 계정 병합** (API 데이터 마이그레이션):
|
||||||
|
│ ├─ 이메일 로그인 또는 Google 로그인
|
||||||
|
│ ├─ POST /api/auth/merge-account 호출
|
||||||
|
│ ├─ Firestore 데이터 이전 (writings, topics, comments, teams)
|
||||||
|
│ ├─ Realtime DB 데이터 이전 (drafts, monitoring)
|
||||||
|
│ └─ 익명 계정(anon123) → 정식 계정(user456)으로 데이터 이전
|
||||||
|
│
|
||||||
|
└─> 이후 user456으로 로그인 가능 (모든 데이터 통합)
|
||||||
|
|
||||||
3. 정식 계정 로그인 (학생 자동 선택)
|
3. 정식 계정 로그인 (학생 자동 선택)
|
||||||
├─> user456으로 로그인
|
├─> user456으로 로그인
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user