# 기능 정의서 (Feature Specification) > 프로젝트: todos2 | 버전: 1.0.0 | 작성일: 2026-02-10 --- ## 1. 기능 목록 (Feature Inventory) | # | 기능명 | 우선순위 | 카테고리 | 상태 | |---|--------|---------|---------|------| | F-001 | 할일 생성 | Must | 할일 CRUD | 미개발 | | F-002 | 할일 목록 조회 | Must | 할일 CRUD | 미개발 | | F-003 | 할일 상세 조회 | Must | 할일 CRUD | 미개발 | | F-004 | 할일 수정 | Must | 할일 CRUD | 미개발 | | F-005 | 할일 삭제 | Must | 할일 CRUD | 미개발 | | F-006 | 할일 완료 토글 | Must | 할일 CRUD | 미개발 | | F-007 | 카테고리 생성 | Must | 카테고리 | 미개발 | | F-008 | 카테고리 목록 조회 | Must | 카테고리 | 미개발 | | F-009 | 카테고리 수정 | Must | 카테고리 | 미개발 | | F-010 | 카테고리 삭제 | Must | 카테고리 | 미개발 | | F-011 | 태그 부여 | Must | 태그 | 미개발 | | F-012 | 태그별 필터링 | Must | 태그 | 미개발 | | F-013 | 태그 목록 조회 | Must | 태그 | 미개발 | | F-014 | 우선순위 설정 | Must | 우선순위 | 미개발 | | F-015 | 마감일 설정 | Must | 마감일 | 미개발 | | F-016 | 마감일 알림 표시 | Must | 마감일 | 미개발 | | F-017 | 검색 | Should | 검색 | 미개발 | | F-018 | 대시보드 통계 | Should | 대시보드 | 미개발 | | F-019 | 일괄 완료 처리 | Should | 일괄 작업 | 미개발 | | F-020 | 일괄 삭제 | Should | 일괄 작업 | 미개발 | | F-021 | 일괄 카테고리 변경 | Should | 일괄 작업 | 미개발 | --- ## 2. 기능 상세 정의 --- ### F-001: 할일 생성 - **설명**: 사용자가 제목, 내용, 카테고리, 태그, 우선순위, 마감일을 입력하여 새로운 할일을 생성한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | title | string | Y | 1~200자, 공백만 불가 | 할일 제목 | | content | string | N | 최대 2000자 | 할일 상세 내용 | | category_id | string | N | 유효한 카테고리 ObjectId | 분류 카테고리 | | tags | string[] | N | 각 태그 1~30자, 최대 10개 | 태그 목록 | | priority | enum | N | high / medium / low (기본: medium) | 우선순위 | | due_date | datetime | N | 현재 시각 이후 (생성 시점 기준) | 마감일 | #### 처리 규칙 (Business Rules) 1. title 앞뒤 공백을 제거(trim)한다. 2. tags 배열 내 중복 태그를 제거하고, 각 태그를 소문자로 정규화한다. 3. category_id가 지정된 경우, 해당 카테고리가 존재하는지 검증한다. 4. created_at, updated_at을 현재 시각(UTC)으로 설정한다. 5. completed는 false로 초기화한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 201 Created | 생성된 Todo 객체 (id 포함) | | 제목 누락/검증 실패 | 422 Unprocessable Entity | 필드별 에러 메시지 | | 카테고리 미존재 | 404 Not Found | `{"detail": "카테고리를 찾을 수 없습니다"}` | #### 수락 기준 (Acceptance Criteria) - [ ] 제목만 입력하여 할일을 생성할 수 있다 - [ ] 모든 필드(제목, 내용, 카테고리, 태그, 우선순위, 마감일)를 입력하여 할일을 생성할 수 있다 - [ ] 제목 없이 생성 시 422 에러가 반환된다 - [ ] 201자 이상의 제목 입력 시 422 에러가 반환된다 - [ ] 존재하지 않는 카테고리 ID 입력 시 404 에러가 반환된다 - [ ] 생성 후 할일 목록에 즉시 반영된다 - [ ] 태그 중복이 자동으로 제거된다 --- ### F-002: 할일 목록 조회 - **설명**: 필터링, 정렬, 페이지네이션을 적용하여 할일 목록을 조회한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | page | integer | N | >= 1, 기본: 1 | 페이지 번호 | | limit | integer | N | 1~100, 기본: 20 | 페이지당 항목 수 | | completed | boolean | N | true / false | 완료 상태 필터 | | category_id | string | N | 유효한 ObjectId | 카테고리 필터 | | priority | enum | N | high / medium / low | 우선순위 필터 | | tag | string | N | - | 태그 필터 | | sort | string | N | created_at / due_date / priority | 정렬 기준 (기본: created_at) | | order | enum | N | asc / desc (기본: desc) | 정렬 방향 | #### 처리 규칙 (Business Rules) 1. 필터 조건이 복수인 경우 AND 조건으로 적용한다. 2. 카테고리 필터 시 해당 category의 이름과 색상을 populate한다. 3. 페이지네이션 응답에 총 개수(total)와 총 페이지 수(total_pages)를 포함한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | `{"items": [...], "total": N, "page": N, "limit": N, "total_pages": N}` | | 잘못된 파라미터 | 422 Unprocessable Entity | 필드별 에러 메시지 | #### 수락 기준 (Acceptance Criteria) - [ ] 필터 없이 전체 할일 목록을 조회할 수 있다 - [ ] 완료/미완료 상태로 필터링할 수 있다 - [ ] 카테고리별로 필터링할 수 있다 - [ ] 우선순위별로 필터링할 수 있다 - [ ] 태그별로 필터링할 수 있다 - [ ] 페이지네이션이 정상 동작한다 (총 개수, 총 페이지 수 포함) - [ ] 정렬 기준(생성일, 마감일, 우선순위)과 방향(오름차순/내림차순)을 지정할 수 있다 --- ### F-003: 할일 상세 조회 - **설명**: 특정 할일의 전체 정보를 조회한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | id | string | Y | 유효한 ObjectId | 할일 ID | #### 처리 규칙 (Business Rules) 1. 카테고리가 지정된 경우, 카테고리 이름과 색상을 함께 반환한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | Todo 객체 (카테고리 정보 포함) | | 미존재 | 404 Not Found | `{"detail": "할일을 찾을 수 없습니다"}` | | 잘못된 ID 형식 | 422 Unprocessable Entity | `{"detail": "유효하지 않은 ID 형식입니다"}` | #### 수락 기준 (Acceptance Criteria) - [ ] 유효한 ID로 할일 상세 정보를 조회할 수 있다 - [ ] 카테고리 정보가 함께 반환된다 - [ ] 존재하지 않는 ID로 조회 시 404가 반환된다 --- ### F-004: 할일 수정 - **설명**: 기존 할일의 제목, 내용, 카테고리, 태그, 우선순위, 마감일을 수정한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | id | string (path) | Y | 유효한 ObjectId | 할일 ID | | title | string | N | 1~200자 | 할일 제목 | | content | string | N | 최대 2000자 | 할일 상세 내용 | | category_id | string \| null | N | 유효한 ObjectId 또는 null | 카테고리 (null이면 해제) | | tags | string[] | N | 각 태그 1~30자, 최대 10개 | 태그 목록 | | priority | enum | N | high / medium / low | 우선순위 | | due_date | datetime \| null | N | null이면 해제 | 마감일 | #### 처리 규칙 (Business Rules) 1. 요청에 포함된 필드만 업데이트한다 (Partial Update). 2. updated_at을 현재 시각(UTC)으로 갱신한다. 3. category_id가 지정된 경우 해당 카테고리의 존재를 검증한다. 4. tags 배열이 지정된 경우 중복 제거 및 소문자 정규화를 적용한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | 수정된 Todo 객체 | | 미존재 | 404 Not Found | `{"detail": "할일을 찾을 수 없습니다"}` | | 검증 실패 | 422 Unprocessable Entity | 필드별 에러 메시지 | #### 수락 기준 (Acceptance Criteria) - [ ] 제목만 수정할 수 있다 - [ ] 카테고리를 변경할 수 있다 - [ ] 카테고리를 null로 설정하여 해제할 수 있다 - [ ] 태그를 추가/삭제할 수 있다 - [ ] 우선순위를 변경할 수 있다 - [ ] 마감일을 설정/해제할 수 있다 - [ ] 수정 후 updated_at이 갱신된다 - [ ] 존재하지 않는 할일 수정 시 404가 반환된다 --- ### F-005: 할일 삭제 - **설명**: 특정 할일을 영구 삭제한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | id | string | Y | 유효한 ObjectId | 할일 ID | #### 처리 규칙 (Business Rules) 1. 물리 삭제를 수행한다. 2. 삭제 전 확인 다이얼로그를 프론트엔드에서 표시한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 204 No Content | 빈 응답 | | 미존재 | 404 Not Found | `{"detail": "할일을 찾을 수 없습니다"}` | #### 수락 기준 (Acceptance Criteria) - [ ] 할일을 삭제할 수 있다 - [ ] 삭제 전 확인 다이얼로그가 표시된다 - [ ] 삭제 후 목록에서 즉시 사라진다 - [ ] 존재하지 않는 할일 삭제 시 404가 반환된다 --- ### F-006: 할일 완료 토글 - **설명**: 할일의 완료/미완료 상태를 전환한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | id | string (path) | Y | 유효한 ObjectId | 할일 ID | #### 처리 규칙 (Business Rules) 1. 현재 completed 값의 반대값으로 토글한다. 2. updated_at을 갱신한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | `{"id": "...", "completed": true/false}` | | 미존재 | 404 Not Found | `{"detail": "할일을 찾을 수 없습니다"}` | #### 수락 기준 (Acceptance Criteria) - [ ] 체크박스 클릭으로 완료/미완료를 토글할 수 있다 - [ ] 완료된 할일은 시각적으로 구분된다 (취소선, 흐림 처리 등) - [ ] 토글 후 대시보드 통계가 갱신된다 --- ### F-007: 카테고리 생성 - **설명**: 할일 분류를 위한 새 카테고리를 생성한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | name | string | Y | 1~50자, 고유 | 카테고리 이름 | | color | string | N | 유효한 hex color (기본: #6B7280) | 표시 색상 | #### 처리 규칙 (Business Rules) 1. name 앞뒤 공백을 제거(trim)한다. 2. 동일한 이름의 카테고리가 이미 존재하면 409 Conflict를 반환한다. 3. order는 현재 최대값 + 1로 자동 설정한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 201 Created | 생성된 Category 객체 | | 이름 중복 | 409 Conflict | `{"detail": "이미 존재하는 카테고리 이름입니다"}` | | 검증 실패 | 422 Unprocessable Entity | 필드별 에러 메시지 | #### 수락 기준 (Acceptance Criteria) - [ ] 이름과 색상을 지정하여 카테고리를 생성할 수 있다 - [ ] 이름만으로 생성 시 기본 색상이 적용된다 - [ ] 중복 이름 생성 시 에러가 표시된다 - [ ] 생성 후 사이드바 카테고리 목록에 즉시 반영된다 --- ### F-008: 카테고리 목록 조회 - **설명**: 전체 카테고리 목록을 조회한다. - **우선순위**: Must #### 입력 (Inputs) 없음 (파라미터 없이 전체 조회) #### 처리 규칙 (Business Rules) 1. order 필드 기준 오름차순으로 정렬한다. 2. 각 카테고리에 속한 할일 수(todo_count)를 함께 반환한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | `[{"_id": "...", "name": "...", "color": "...", "order": N, "todo_count": N}]` | #### 수락 기준 (Acceptance Criteria) - [ ] 전체 카테고리 목록을 조회할 수 있다 - [ ] 각 카테고리에 할일 수가 표시된다 - [ ] 정렬 순서대로 표시된다 --- ### F-009: 카테고리 수정 - **설명**: 기존 카테고리의 이름, 색상, 순서를 수정한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | id | string (path) | Y | 유효한 ObjectId | 카테고리 ID | | name | string | N | 1~50자, 고유 | 카테고리 이름 | | color | string | N | 유효한 hex color | 표시 색상 | | order | integer | N | >= 0 | 정렬 순서 | #### 처리 규칙 (Business Rules) 1. 요청에 포함된 필드만 업데이트한다. 2. name 변경 시 중복 검사를 수행한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | 수정된 Category 객체 | | 미존재 | 404 Not Found | `{"detail": "카테고리를 찾을 수 없습니다"}` | | 이름 중복 | 409 Conflict | `{"detail": "이미 존재하는 카테고리 이름입니다"}` | #### 수락 기준 (Acceptance Criteria) - [ ] 카테고리 이름을 변경할 수 있다 - [ ] 카테고리 색상을 변경할 수 있다 - [ ] 변경 사항이 해당 카테고리의 모든 할일 표시에 반영된다 - [ ] 중복 이름으로 변경 시 에러가 표시된다 --- ### F-010: 카테고리 삭제 - **설명**: 카테고리를 삭제한다. 해당 카테고리에 속한 할일의 category_id는 null로 초기화된다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | id | string (path) | Y | 유효한 ObjectId | 카테고리 ID | #### 처리 규칙 (Business Rules) 1. 카테고리 삭제 시, 해당 카테고리에 속한 모든 할일의 category_id를 null로 변경한다. 2. 삭제 전 확인 다이얼로그에 영향받는 할일 수를 표시한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 204 No Content | 빈 응답 | | 미존재 | 404 Not Found | `{"detail": "카테고리를 찾을 수 없습니다"}` | #### 수락 기준 (Acceptance Criteria) - [ ] 카테고리를 삭제할 수 있다 - [ ] 삭제 확인 다이얼로그에 영향받는 할일 수가 표시된다 - [ ] 삭제 후 해당 카테고리의 할일들이 "미분류"로 표시된다 - [ ] 사이드바에서 즉시 사라진다 --- ### F-011: 태그 부여 - **설명**: 할일 생성 또는 수정 시 태그를 부여한다. 콤마로 구분하여 다중 태그를 입력한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | tags | string[] | N | 각 1~30자, 최대 10개, 특수문자 불가 | 태그 배열 | #### 처리 규칙 (Business Rules) 1. F-001(할일 생성), F-004(할일 수정)에서 tags 필드로 처리된다. 2. 입력 태그를 소문자로 정규화하고, 중복을 제거한다. 3. 기존 태그 자동완성을 위해 사용 중인 태그 목록을 제공한다. #### 출력 (Outputs) F-001, F-004의 출력과 동일 (Todo 객체에 tags 포함) #### 수락 기준 (Acceptance Criteria) - [ ] 할일 생성/수정 폼에서 태그를 입력할 수 있다 - [ ] 기존 태그 자동완성이 동작한다 - [ ] 태그가 뱃지 형태로 표시된다 - [ ] 태그를 개별 삭제할 수 있다 (x 버튼) --- ### F-012: 태그별 필터링 - **설명**: 특정 태그가 부여된 할일만 필터링하여 조회한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | tag | string | Y | 존재하는 태그 | 필터링할 태그명 | #### 처리 규칙 (Business Rules) 1. F-002(할일 목록 조회)의 tag 파라미터로 처리된다. 2. 태그 뱃지 클릭 시 해당 태그로 필터링된다. #### 출력 (Outputs) F-002의 출력과 동일 #### 수락 기준 (Acceptance Criteria) - [ ] 태그 뱃지 클릭으로 해당 태그의 할일만 필터링된다 - [ ] 필터 적용 중 태그명이 표시된다 - [ ] 필터 해제 버튼으로 전체 목록으로 돌아갈 수 있다 --- ### F-013: 태그 목록 조회 - **설명**: 현재 사용 중인 모든 태그의 목록과 사용 횟수를 조회한다. - **우선순위**: Must #### 입력 (Inputs) 없음 #### 처리 규칙 (Business Rules) 1. todos 컬렉션에서 tags 필드를 distinct로 추출한다. 2. 각 태그의 사용 횟수(count)를 집계한다. 3. 사용 횟수 내림차순으로 정렬한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | `[{"name": "업무", "count": 5}, ...]` | #### 수락 기준 (Acceptance Criteria) - [ ] 사용 중인 모든 태그 목록을 조회할 수 있다 - [ ] 각 태그의 사용 횟수가 표시된다 - [ ] 할일이 없는 태그는 목록에 표시되지 않는다 --- ### F-014: 우선순위 설정 - **설명**: 할일에 높음(high), 중간(medium), 낮음(low) 3단계 우선순위를 설정한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | priority | enum | N | high / medium / low | 우선순위 (기본: medium) | #### 처리 규칙 (Business Rules) 1. F-001(할일 생성), F-004(할일 수정)의 priority 필드로 처리된다. 2. UI에서 색상으로 구분: high=빨강, medium=노랑, low=파랑. #### 출력 (Outputs) F-001, F-004의 출력과 동일 #### 수락 기준 (Acceptance Criteria) - [ ] 할일 생성/수정 시 우선순위를 선택할 수 있다 - [ ] 우선순위별 색상 구분이 된다 (high=빨강, medium=노랑, low=파랑) - [ ] 기본 우선순위는 medium이다 - [ ] 목록에서 우선순위별 필터링이 가능하다 --- ### F-015: 마감일 설정 - **설명**: 할일에 마감일을 설정한다. 달력 UI로 날짜를 선택한다. - **우선순위**: Must #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | due_date | datetime | N | ISO 8601 형식 | 마감일 | #### 처리 규칙 (Business Rules) 1. F-001(할일 생성), F-004(할일 수정)의 due_date 필드로 처리된다. 2. null을 전송하면 마감일을 해제한다. #### 출력 (Outputs) F-001, F-004의 출력과 동일 #### 수락 기준 (Acceptance Criteria) - [ ] 달력 UI로 마감일을 선택할 수 있다 - [ ] 마감일이 설정된 할일에 날짜가 표시된다 - [ ] 마감일을 해제할 수 있다 --- ### F-016: 마감일 알림 표시 - **설명**: 마감일이 임박하거나 초과한 할일에 시각적 알림을 표시한다. - **우선순위**: Must #### 입력 (Inputs) 없음 (프론트엔드 렌더링 로직) #### 처리 규칙 (Business Rules) 1. 마감일 1일 이내: 주황색 "임박" 뱃지 표시 2. 마감일 초과: 빨간색 "초과" 뱃지 표시 3. 마감일 3일 이내: 노란색 "곧 마감" 표시 4. 완료된 할일은 알림을 표시하지 않는다. #### 출력 (Outputs) UI 렌더링 (API 응답 없음) #### 수락 기준 (Acceptance Criteria) - [ ] 마감 3일 이내 할일에 "곧 마감" 표시가 된다 - [ ] 마감 1일 이내 할일에 "임박" 표시가 된다 - [ ] 마감 초과 할일에 "초과" 표시가 된다 - [ ] 완료된 할일에는 알림이 표시되지 않는다 - [ ] 뱃지 색상이 긴급도에 따라 구분된다 (노랑/주황/빨강) --- ### F-017: 검색 - **설명**: 제목, 내용, 태그를 기반으로 할일을 검색한다. - **우선순위**: Should #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | q | string | Y | 1~200자 | 검색 키워드 | | page | integer | N | >= 1, 기본: 1 | 페이지 번호 | | limit | integer | N | 1~100, 기본: 20 | 페이지당 항목 수 | #### 처리 규칙 (Business Rules) 1. MongoDB text index를 활용한 전문 검색을 수행한다. 2. 검색 대상: title, content, tags 필드. 3. 검색 결과는 관련도(text score) 기준으로 정렬한다. 4. 검색어가 태그와 정확히 일치하는 경우 해당 태그의 할일을 우선 표시한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | `{"items": [...], "total": N, "query": "...", "page": N, "limit": N}` | | 검색어 누락 | 422 Unprocessable Entity | `{"detail": "검색어를 입력해주세요"}` | #### 수락 기준 (Acceptance Criteria) - [ ] 헤더 검색바에 키워드를 입력하여 검색할 수 있다 - [ ] 제목에 포함된 키워드로 검색된다 - [ ] 내용에 포함된 키워드로 검색된다 - [ ] 태그명으로 검색된다 - [ ] 검색 결과가 관련도순으로 정렬된다 - [ ] 검색 결과가 없을 때 "결과 없음" 메시지가 표시된다 - [ ] 검색 결과에서 검색어가 하이라이트된다 --- ### F-018: 대시보드 통계 - **설명**: 할일 현황을 한눈에 파악할 수 있는 대시보드 통계를 제공한다. - **우선순위**: Should #### 입력 (Inputs) 없음 #### 처리 규칙 (Business Rules) 1. 통계 항목: - 전체 할일 수, 완료 수, 미완료 수 - 완료율 (%) - 카테고리별 할일 분포 (도넛 차트) - 우선순위별 현황 (가로 막대 차트) - 마감 임박 할일 목록 (상위 5개) 2. Redis에 60초 TTL로 캐싱한다. 3. 캐시 무효화: 할일 CUD 작업 시. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | 아래 JSON 구조 참고 | ```json { "overview": { "total": 50, "completed": 30, "incomplete": 20, "completion_rate": 60.0 }, "by_category": [ {"category_id": "...", "name": "업무", "color": "#EF4444", "count": 15} ], "by_priority": { "high": 10, "medium": 25, "low": 15 }, "upcoming_deadlines": [ {"id": "...", "title": "...", "due_date": "...", "priority": "high"} ] } ``` #### 수락 기준 (Acceptance Criteria) - [ ] 전체/완료/미완료 수가 카드 형태로 표시된다 - [ ] 완료율이 퍼센트로 표시된다 - [ ] 카테고리별 할일 분포가 도넛 차트로 표시된다 - [ ] 우선순위별 현황이 막대 차트로 표시된다 - [ ] 마감 임박 할일 상위 5개가 리스트로 표시된다 - [ ] 데이터가 없을 때 빈 상태 안내가 표시된다 --- ### F-019: 일괄 완료 처리 - **설명**: 여러 할일을 선택하여 한번에 완료 처리한다. - **우선순위**: Should #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | action | string | Y | "complete" | 작업 유형 | | ids | string[] | Y | 1개 이상의 유효한 ObjectId | 대상 할일 ID 배열 | #### 처리 규칙 (Business Rules) 1. 선택된 모든 할일의 completed를 true로 설정한다. 2. 각 항목의 updated_at을 갱신한다. 3. 존재하지 않는 ID는 무시하고 나머지를 처리한다. 4. 처리된 수와 실패 수를 반환한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | `{"action": "complete", "processed": 5, "failed": 0}` | | ID 누락 | 422 Unprocessable Entity | `{"detail": "대상 할일을 선택해주세요"}` | #### 수락 기준 (Acceptance Criteria) - [ ] 체크박스로 여러 할일을 선택할 수 있다 - [ ] "일괄 완료" 버튼으로 선택된 할일을 한번에 완료할 수 있다 - [ ] 처리 결과(성공 수)가 토스트로 표시된다 - [ ] 처리 후 목록이 갱신된다 --- ### F-020: 일괄 삭제 - **설명**: 여러 할일을 선택하여 한번에 삭제한다. - **우선순위**: Should #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | action | string | Y | "delete" | 작업 유형 | | ids | string[] | Y | 1개 이상의 유효한 ObjectId | 대상 할일 ID 배열 | #### 처리 규칙 (Business Rules) 1. 선택된 모든 할일을 물리 삭제한다. 2. 삭제 전 확인 다이얼로그를 표시한다. 3. 존재하지 않는 ID는 무시한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | `{"action": "delete", "processed": 3, "failed": 0}` | | ID 누락 | 422 Unprocessable Entity | `{"detail": "대상 할일을 선택해주세요"}` | #### 수락 기준 (Acceptance Criteria) - [ ] "일괄 삭제" 버튼으로 선택된 할일을 한번에 삭제할 수 있다 - [ ] 삭제 전 "N개의 할일을 삭제하시겠습니까?" 확인 다이얼로그가 표시된다 - [ ] 처리 결과가 토스트로 표시된다 - [ ] 삭제 후 목록이 갱신된다 --- ### F-021: 일괄 카테고리 변경 - **설명**: 여러 할일을 선택하여 한번에 카테고리를 변경한다. - **우선순위**: Should #### 입력 (Inputs) | 필드명 | 타입 | 필수 | 검증 규칙 | 설명 | |--------|------|------|-----------|------| | action | string | Y | "move_category" | 작업 유형 | | ids | string[] | Y | 1개 이상의 유효한 ObjectId | 대상 할일 ID 배열 | | category_id | string \| null | Y | 유효한 카테고리 ObjectId 또는 null | 변경할 카테고리 | #### 처리 규칙 (Business Rules) 1. 선택된 모든 할일의 category_id를 지정된 값으로 변경한다. 2. category_id가 null이면 "미분류"로 설정한다. 3. 대상 카테고리의 존재를 검증한다. #### 출력 (Outputs) | 상황 | HTTP 상태 | 응답 | |------|-----------|------| | 성공 | 200 OK | `{"action": "move_category", "processed": 4, "failed": 0}` | | 카테고리 미존재 | 404 Not Found | `{"detail": "카테고리를 찾을 수 없습니다"}` | #### 수락 기준 (Acceptance Criteria) - [ ] 카테고리 선택 드롭다운으로 일괄 변경할 수 있다 - [ ] "미분류"로 일괄 변경할 수 있다 - [ ] 처리 결과가 토스트로 표시된다 - [ ] 변경 후 목록이 갱신된다 --- ## 3. API 엔드포인트 요약 | Method | Path | 기능 ID | 설명 | |--------|------|---------|------| | POST | `/api/todos` | F-001 | 할일 생성 | | GET | `/api/todos` | F-002 | 할일 목록 조회 (필터/정렬/페이지네이션) | | GET | `/api/todos/{id}` | F-003 | 할일 상세 조회 | | PUT | `/api/todos/{id}` | F-004 | 할일 수정 | | DELETE | `/api/todos/{id}` | F-005 | 할일 삭제 | | PATCH | `/api/todos/{id}/toggle` | F-006 | 할일 완료 토글 | | POST | `/api/categories` | F-007 | 카테고리 생성 | | GET | `/api/categories` | F-008 | 카테고리 목록 조회 | | PUT | `/api/categories/{id}` | F-009 | 카테고리 수정 | | DELETE | `/api/categories/{id}` | F-010 | 카테고리 삭제 | | GET | `/api/tags` | F-013 | 태그 목록 조회 | | GET | `/api/search` | F-017 | 검색 | | GET | `/api/dashboard/stats` | F-018 | 대시보드 통계 | | POST | `/api/todos/batch` | F-019, F-020, F-021 | 일괄 작업 (완료/삭제/카테고리 변경) |