feat: 풀스택 할일관리 앱 구현 (통합 모달 + 간트차트)

- Backend: FastAPI + MongoDB + Redis (카테고리, 할일 CRUD, 파일 첨부, 검색, 대시보드)
- Frontend: Next.js 15 + Tailwind + React Query + Zustand
- 통합 TodoModal: 생성/수정 모달 통합, 탭 구조 (기본/태그와 첨부)
- 간트차트: 카테고리별 할일 타임라인 시각화
- TodoCard: 제목/카테고리/우선순위/태그/첨부 한줄 표시
- Docker Compose 배포 (Frontend:3010, Backend:8010, MongoDB:27021, Redis:6391)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jungwoo choi
2026-02-12 15:45:03 +09:00
parent b54811ad8d
commit 074b5133bf
81 changed files with 17027 additions and 19 deletions

312
docs/SCREEN_DESIGN.md Normal file
View File

@ -0,0 +1,312 @@
# todos2 — 화면설계서
> 자동 생성: `pptx_to_md.py` | 원본: `SCREEN_DESIGN.pptx`
> 생성 시각: 2026-02-10 07:12
> **이 파일을 직접 수정하지 마세요. PPTX를 수정 후 스크립트를 재실행하세요.**
## 페이지 목록
| ID | 페이지명 | 경로 | 설명 |
|-----|---------|------|------|
| P-001 | 대시보드 | `/` | 메인 페이지. 통계 카드, 차트, 마감 임박 목록 |
| P-002 | 할일 목록 | `/todos` | 할일 CRUD, 필터링, 정렬, 일괄 작업 |
| P-003 | 할일 상세/편집 | `/todos/[id]` | 할일 상세 보기 및 수정 폼 |
| P-004 | 카테고리 관리 | `/categories` | 카테고리 CRUD, 색상 지정 |
| P-005 | 검색 결과 | `/search` | 제목/내용/태그 기반 검색 결과 |
---
## P-001: 대시보드 (`/`)
### 레이아웃
[로고 todos2] | [검색바 _______________] | [알림]
● 대시보드
할일 목록
카테고리 관리
카테고리
업무 (12)
개인 (8)
학습 (5)
인기 태그
#긴급
#회의
#프로젝트
전체 할일 50
완료 30
미완료 20
완료율 60%
[카테고리별 분포 - 도넛 차트] 업무 40% | 개인 30% 학습 20% | 기타 10%
[우선순위별 현황 - 막대 차트] high: 10 | medium: 25 | low: 15
[마감 임박 할일] 1. API 문서 작성 (D-1) 2. 디자인 리뷰 (D-2) 3. 테스트 코드 (D-3)
| 컴포넌트 | 기능 | 상태 |
| --- | --- | --- |
| StatsCards | 전체/완료/미완료/완료율 카드 | loading, data, empty |
| CategoryChart | 카테고리별 도넛 차트 | loading, data, empty |
| PriorityChart | 우선순위별 막대 차트 | loading, data, empty |
| UpcomingDeadlines | 마감 임박 할일 Top 5 | loading, data, empty |
| Sidebar | 카테고리/태그 네비게이션 | default |
### 컴포넌트
| 컴포넌트 | Props | 상태 |
|---------|-------|------|
| `StatsCards` | stats | loading, empty, data |
| `CategoryChart` | categoryData | loading, empty, data |
| `PriorityChart` | priorityData | loading, empty, data |
| `UpcomingDeadlines` | deadlines, onItemClick | loading, empty, data |
| `Sidebar` | categories, tags, activePath | default |
### 인터랙션
| 트리거 | 동작 | 결과 |
|--------|------|------|
| 마감 임박 항목 클릭 | `router.push(/todos/{id})` | 해당 할일 상세 페이지로 이동 |
| 사이드바 카테고리 클릭 | `router.push(/todos?category_id={id})` | 해당 카테고리의 할일 목록으로 이동 |
| 사이드바 태그 클릭 | `router.push(/todos?tag={name})` | 해당 태그의 할일 목록으로 이동 |
### 반응형: sm, md, lg
---
## P-002: 할일 목록 (`/todos`)
### 레이아웃
[로고 todos2] | [검색바 _______________] | [알림]
대시보드
● 할일 목록
카테고리 관리
필터:
상태 ▾
우선순위 ▾
정렬 ▾
+ 새 할일
3개 선택됨
일괄 완료
카테고리 변경
일괄 삭제
API 문서 작성
업무
#긴급
D-1
[수정] [삭제]
회의록 정리
업무
#회의
D-5
[수정] [삭제]
Next.js 학습
학습
#학습
D-7
[수정] [삭제]
장보기 목록 작성
개인
#생활
-
[수정] [삭제]
< 1 2 3 4 5 >
| 컴포넌트 | 기능 | 상태 |
| --- | --- | --- |
| TodoFilter | 상태/우선순위/정렬 필터 | default, applied |
| TodoList | 할일 카드 리스트 | loading, empty, error, data |
| TodoCard | 개별 할일 행 | default, completed, overdue |
| BatchActions | 일괄 작업 바 | hidden, visible |
| TodoForm (Modal) | 할일 생성/수정 모달 | create, edit |
| Pagination | 페이지 네비게이션 | default |
### 컴포넌트
| 컴포넌트 | Props | 상태 |
|---------|-------|------|
| `TodoFilter` | filters, onFilterChange | default, applied |
| `TodoList` | todos, selectedIds, onToggle, onSelect, onEdit, onDelete | loading, empty, error, data |
| `TodoCard` | todo, isSelected, onToggle, onSelect, onEdit, onDelete | default, completed, overdue |
| `BatchActions` | selectedIds, categories, onBatchComplete, onBatchDelete, onBatchMove | hidden, visible |
| `TodoForm` | mode, todo, categories, tags, onSubmit, onClose | create, edit |
| `Pagination` | currentPage, totalPages, onPageChange | default |
### 인터랙션
| 트리거 | 동작 | 결과 |
|--------|------|------|
| "+ 새 할일" 버튼 클릭 | `openTodoForm(mode='create')` | 할일 생성 모달 열림 |
| 체크박스 클릭 | `toggleTodo(id)` | 완료 상태 토글 |
| 행 선택 체크박스 | `toggleSelect(id)` | 일괄 작업 대상에 추가/제거 |
| 필터 변경 | `applyFilter(filters)` | 목록 재조회 |
| "일괄 완료" 클릭 | `batchComplete(selectedIds)` | 선택된 할일 일괄 완료 |
| "일괄 삭제" 클릭 | `batchDelete(selectedIds)` | 확인 후 일괄 삭제 |
| "카테고리 변경" 클릭 | `batchMoveCategory(selectedIds, categoryId)` | 카테고리 선택 후 변경 |
| 태그 뱃지 클릭 | `applyFilter({tag: tagName})` | 해당 태그로 필터링 |
### 반응형: sm, md, lg
---
## P-003: 할일 상세/편집 (`/todos/[id]`)
### 레이아웃
[로고 todos2] | [검색바] | [알림]
(Sidebar)
할일 목록 > API 문서 작성
제목 *
API 문서 작성
내용
Swagger UI 기반 API 문서를 작성하고 엔드포인트별 요청/응답 예시를 추가한다.
카테고리
업무 ▾
우선순위
높음 ▾
마감일
2026-02-11 📅
태그
#긴급 ×
#문서 ×
태그 입력 (자동완성)...
취소
저장
| 컴포넌트 | 기능 | 상태 |
| --- | --- | --- |
| TodoDetailForm | 할일 상세 폼 | loading, view, edit, saving |
| CategorySelect | 카테고리 드롭다운 | default |
| PrioritySelect | 우선순위 드롭다운 (색상) | default |
| DatePicker | 달력 마감일 선택 | default, open |
| TagInput | 태그 입력 + 자동완성 + 뱃지 | default, suggesting |
### 컴포넌트
| 컴포넌트 | Props | 상태 |
|---------|-------|------|
| `TodoDetailForm` | todo, categories, tags, onSave, onCancel, onDelete | loading, view, edit, saving |
| `CategorySelect` | categories, selectedId, onChange | default |
| `PrioritySelect` | selectedPriority, onChange | default |
| `DatePicker` | selectedDate, onChange | default, open |
| `TagInput` | tags, suggestions, onAdd, onRemove | default, suggesting |
### 인터랙션
| 트리거 | 동작 | 결과 |
|--------|------|------|
| "저장" 버튼 클릭 | `updateTodo(id, formData)` | 할일 업데이트 후 성공 토스트 |
| "취소" 버튼 클릭 | `router.back()` | 이전 페이지로 이동 |
| 태그 입력 키워드 타이핑 | `fetchTagSuggestions(keyword)` | 자동완성 드롭다운 표시 |
| 태그 뱃지 × 클릭 | `removeTag(tagName)` | 태그 제거 |
| 달력 아이콘 클릭 | `openDatePicker()` | 달력 팝업 표시 |
### 반응형: sm, md, lg
---
## P-004: 카테고리 관리 (`/categories`)
### 레이아웃
[로고 todos2] | [검색바] | [알림]
대시보드
할일 목록
● 카테고리 관리
카테고리 관리
+ 새 카테고리
업무
12개 할일
[색상] [수정] [삭제]
개인
8개 할일
[색상] [수정] [삭제]
학습
5개 할일
[색상] [수정] [삭제]
건강
3개 할일
[색상] [수정] [삭제]
새 카테고리 이름...
추가
| 컴포넌트 | 기능 | 상태 |
| --- | --- | --- |
| CategoryList | 카테고리 목록 | loading, empty, data |
| CategoryItem | 개별 카테고리 행 | default, editing |
| CategoryForm | 카테고리 생성/수정 인라인 폼 | create, edit |
| ColorPicker | 카테고리 색상 선택기 | default, open |
### 컴포넌트
| 컴포넌트 | Props | 상태 |
|---------|-------|------|
| `CategoryList` | categories, onEdit, onDelete | loading, empty, data |
| `CategoryItem` | category, onEdit, onDelete | default, editing |
| `CategoryForm` | mode, category, onSubmit, onCancel | create, edit |
| `ColorPicker` | selectedColor, onChange | default, open |
### 인터랙션
| 트리거 | 동작 | 결과 |
|--------|------|------|
| "+ 새 카테고리" 버튼 클릭 | `showCategoryForm(mode='create')` | 인라인 생성 폼 표시 |
| "추가" 버튼 클릭 | `createCategory({name, color})` | 카테고리 생성 후 목록 갱신 |
| "수정" 클릭 | `showCategoryForm(mode='edit', category)` | 해당 행이 수정 폼으로 전환 |
| "삭제" 클릭 | `deleteCategory(id)` | 확인 다이얼로그 후 삭제 |
| 색상 변경 클릭 | `openColorPicker(category)` | 색상 선택기 팝업 |
### 반응형: sm, md, lg
---
## P-005: 검색 결과 (`/search`)
### 레이아웃
todos2
API 문서 [×]
[알림]
(Sidebar)
"API 문서" 검색 결과 (3건)
API 문서 작성
Swagger UI 기반 API 문서를 작성하고...
업무
D-1
API 문서 리뷰
팀원들과 API 문서 리뷰 미팅을...
업무
D-5
REST API 문서화 학습
OpenAPI 스펙과 자동화 도구를...
학습
D-14
* 결과 없을 때: "검색 결과가 없습니다. 다른 키워드로 검색해보세요."
| 컴포넌트 | 기능 | 상태 |
| --- | --- | --- |
| SearchBar | 헤더 내 검색 입력 + 클리어 | default, active, has_query |
| SearchResults | 검색 결과 리스트 | loading, empty, data |
| SearchResultItem | 개별 결과 (제목 하이라이트, 설명) | default |
| Pagination | 결과 페이지네이션 | default |
### 컴포넌트
| 컴포넌트 | Props | 상태 |
|---------|-------|------|
| `SearchBar` | query, onSearch, onClear | default, active, has_query |
| `SearchResults` | results, query, total, onItemClick | loading, empty, data |
| `SearchResultItem` | result, query, onClick | default |
| `Pagination` | currentPage, totalPages, onPageChange | default |
### 인터랙션
| 트리거 | 동작 | 결과 |
|--------|------|------|
| 검색바에 키워드 입력 후 Enter | `search(query)` | 검색 API 호출 후 결과 표시 |
| 검색바 × 버튼 클릭 | `clearSearch()` | 검색어 클리어, 이전 페이지로 이동 |
| 검색 결과 항목 클릭 | `router.push(/todos/{id})` | 해당 할일 상세 페이지로 이동 |
| 페이지 번호 클릭 | `search(query, page)` | 해당 페이지의 검색 결과 |
### 반응형: sm, md, lg