기능 정의서 (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)
- title 앞뒤 공백을 제거(trim)한다.
- tags 배열 내 중복 태그를 제거하고, 각 태그를 소문자로 정규화한다.
- category_id가 지정된 경우, 해당 카테고리가 존재하는지 검증한다.
- created_at, updated_at을 현재 시각(UTC)으로 설정한다.
- completed는 false로 초기화한다.
출력 (Outputs)
| 상황 |
HTTP 상태 |
응답 |
| 성공 |
201 Created |
생성된 Todo 객체 (id 포함) |
| 제목 누락/검증 실패 |
422 Unprocessable Entity |
필드별 에러 메시지 |
| 카테고리 미존재 |
404 Not Found |
{"detail": "카테고리를 찾을 수 없습니다"} |
수락 기준 (Acceptance Criteria)
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)
- 필터 조건이 복수인 경우 AND 조건으로 적용한다.
- 카테고리 필터 시 해당 category의 이름과 색상을 populate한다.
- 페이지네이션 응답에 총 개수(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)
- 카테고리가 지정된 경우, 카테고리 이름과 색상을 함께 반환한다.
출력 (Outputs)
| 상황 |
HTTP 상태 |
응답 |
| 성공 |
200 OK |
Todo 객체 (카테고리 정보 포함) |
| 미존재 |
404 Not Found |
{"detail": "할일을 찾을 수 없습니다"} |
| 잘못된 ID 형식 |
422 Unprocessable Entity |
{"detail": "유효하지 않은 ID 형식입니다"} |
수락 기준 (Acceptance Criteria)
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)
- 요청에 포함된 필드만 업데이트한다 (Partial Update).
- updated_at을 현재 시각(UTC)으로 갱신한다.
- category_id가 지정된 경우 해당 카테고리의 존재를 검증한다.
- tags 배열이 지정된 경우 중복 제거 및 소문자 정규화를 적용한다.
출력 (Outputs)
| 상황 |
HTTP 상태 |
응답 |
| 성공 |
200 OK |
수정된 Todo 객체 |
| 미존재 |
404 Not Found |
{"detail": "할일을 찾을 수 없습니다"} |
| 검증 실패 |
422 Unprocessable Entity |
필드별 에러 메시지 |
수락 기준 (Acceptance Criteria)
F-005: 할일 삭제
- 설명: 특정 할일을 영구 삭제한다.
- 우선순위: Must
입력 (Inputs)
| 필드명 |
타입 |
필수 |
검증 규칙 |
설명 |
| id |
string |
Y |
유효한 ObjectId |
할일 ID |
처리 규칙 (Business Rules)
- 물리 삭제를 수행한다.
- 삭제 전 확인 다이얼로그를 프론트엔드에서 표시한다.
출력 (Outputs)
| 상황 |
HTTP 상태 |
응답 |
| 성공 |
204 No Content |
빈 응답 |
| 미존재 |
404 Not Found |
{"detail": "할일을 찾을 수 없습니다"} |
수락 기준 (Acceptance Criteria)
F-006: 할일 완료 토글
- 설명: 할일의 완료/미완료 상태를 전환한다.
- 우선순위: Must
입력 (Inputs)
| 필드명 |
타입 |
필수 |
검증 규칙 |
설명 |
| id |
string (path) |
Y |
유효한 ObjectId |
할일 ID |
처리 규칙 (Business Rules)
- 현재 completed 값의 반대값으로 토글한다.
- 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)
- name 앞뒤 공백을 제거(trim)한다.
- 동일한 이름의 카테고리가 이미 존재하면 409 Conflict를 반환한다.
- order는 현재 최대값 + 1로 자동 설정한다.
출력 (Outputs)
| 상황 |
HTTP 상태 |
응답 |
| 성공 |
201 Created |
생성된 Category 객체 |
| 이름 중복 |
409 Conflict |
{"detail": "이미 존재하는 카테고리 이름입니다"} |
| 검증 실패 |
422 Unprocessable Entity |
필드별 에러 메시지 |
수락 기준 (Acceptance Criteria)
F-008: 카테고리 목록 조회
- 설명: 전체 카테고리 목록을 조회한다.
- 우선순위: Must
입력 (Inputs)
없음 (파라미터 없이 전체 조회)
처리 규칙 (Business Rules)
- order 필드 기준 오름차순으로 정렬한다.
- 각 카테고리에 속한 할일 수(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)
- 요청에 포함된 필드만 업데이트한다.
- 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)
- 카테고리 삭제 시, 해당 카테고리에 속한 모든 할일의 category_id를 null로 변경한다.
- 삭제 전 확인 다이얼로그에 영향받는 할일 수를 표시한다.
출력 (Outputs)
| 상황 |
HTTP 상태 |
응답 |
| 성공 |
204 No Content |
빈 응답 |
| 미존재 |
404 Not Found |
{"detail": "카테고리를 찾을 수 없습니다"} |
수락 기준 (Acceptance Criteria)
F-011: 태그 부여
- 설명: 할일 생성 또는 수정 시 태그를 부여한다. 콤마로 구분하여 다중 태그를 입력한다.
- 우선순위: Must
입력 (Inputs)
| 필드명 |
타입 |
필수 |
검증 규칙 |
설명 |
| tags |
string[] |
N |
각 1~30자, 최대 10개, 특수문자 불가 |
태그 배열 |
처리 규칙 (Business Rules)
- F-001(할일 생성), F-004(할일 수정)에서 tags 필드로 처리된다.
- 입력 태그를 소문자로 정규화하고, 중복을 제거한다.
- 기존 태그 자동완성을 위해 사용 중인 태그 목록을 제공한다.
출력 (Outputs)
F-001, F-004의 출력과 동일 (Todo 객체에 tags 포함)
수락 기준 (Acceptance Criteria)
F-012: 태그별 필터링
- 설명: 특정 태그가 부여된 할일만 필터링하여 조회한다.
- 우선순위: Must
입력 (Inputs)
| 필드명 |
타입 |
필수 |
검증 규칙 |
설명 |
| tag |
string |
Y |
존재하는 태그 |
필터링할 태그명 |
처리 규칙 (Business Rules)
- F-002(할일 목록 조회)의 tag 파라미터로 처리된다.
- 태그 뱃지 클릭 시 해당 태그로 필터링된다.
출력 (Outputs)
F-002의 출력과 동일
수락 기준 (Acceptance Criteria)
F-013: 태그 목록 조회
- 설명: 현재 사용 중인 모든 태그의 목록과 사용 횟수를 조회한다.
- 우선순위: Must
입력 (Inputs)
없음
처리 규칙 (Business Rules)
- todos 컬렉션에서 tags 필드를 distinct로 추출한다.
- 각 태그의 사용 횟수(count)를 집계한다.
- 사용 횟수 내림차순으로 정렬한다.
출력 (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)
- F-001(할일 생성), F-004(할일 수정)의 priority 필드로 처리된다.
- UI에서 색상으로 구분: high=빨강, medium=노랑, low=파랑.
출력 (Outputs)
F-001, F-004의 출력과 동일
수락 기준 (Acceptance Criteria)
F-015: 마감일 설정
- 설명: 할일에 마감일을 설정한다. 달력 UI로 날짜를 선택한다.
- 우선순위: Must
입력 (Inputs)
| 필드명 |
타입 |
필수 |
검증 규칙 |
설명 |
| due_date |
datetime |
N |
ISO 8601 형식 |
마감일 |
처리 규칙 (Business Rules)
- F-001(할일 생성), F-004(할일 수정)의 due_date 필드로 처리된다.
- null을 전송하면 마감일을 해제한다.
출력 (Outputs)
F-001, F-004의 출력과 동일
수락 기준 (Acceptance Criteria)
F-016: 마감일 알림 표시
- 설명: 마감일이 임박하거나 초과한 할일에 시각적 알림을 표시한다.
- 우선순위: Must
입력 (Inputs)
없음 (프론트엔드 렌더링 로직)
처리 규칙 (Business Rules)
- 마감일 1일 이내: 주황색 "임박" 뱃지 표시
- 마감일 초과: 빨간색 "초과" 뱃지 표시
- 마감일 3일 이내: 노란색 "곧 마감" 표시
- 완료된 할일은 알림을 표시하지 않는다.
출력 (Outputs)
UI 렌더링 (API 응답 없음)
수락 기준 (Acceptance Criteria)
F-017: 검색
- 설명: 제목, 내용, 태그를 기반으로 할일을 검색한다.
- 우선순위: Should
입력 (Inputs)
| 필드명 |
타입 |
필수 |
검증 규칙 |
설명 |
| q |
string |
Y |
1~200자 |
검색 키워드 |
| page |
integer |
N |
>= 1, 기본: 1 |
페이지 번호 |
| limit |
integer |
N |
1~100, 기본: 20 |
페이지당 항목 수 |
처리 규칙 (Business Rules)
- MongoDB text index를 활용한 전문 검색을 수행한다.
- 검색 대상: title, content, tags 필드.
- 검색 결과는 관련도(text score) 기준으로 정렬한다.
- 검색어가 태그와 정확히 일치하는 경우 해당 태그의 할일을 우선 표시한다.
출력 (Outputs)
| 상황 |
HTTP 상태 |
응답 |
| 성공 |
200 OK |
{"items": [...], "total": N, "query": "...", "page": N, "limit": N} |
| 검색어 누락 |
422 Unprocessable Entity |
{"detail": "검색어를 입력해주세요"} |
수락 기준 (Acceptance Criteria)
F-018: 대시보드 통계
- 설명: 할일 현황을 한눈에 파악할 수 있는 대시보드 통계를 제공한다.
- 우선순위: Should
입력 (Inputs)
없음
처리 규칙 (Business Rules)
- 통계 항목:
- 전체 할일 수, 완료 수, 미완료 수
- 완료율 (%)
- 카테고리별 할일 분포 (도넛 차트)
- 우선순위별 현황 (가로 막대 차트)
- 마감 임박 할일 목록 (상위 5개)
- Redis에 60초 TTL로 캐싱한다.
- 캐시 무효화: 할일 CUD 작업 시.
출력 (Outputs)
| 상황 |
HTTP 상태 |
응답 |
| 성공 |
200 OK |
아래 JSON 구조 참고 |
수락 기준 (Acceptance Criteria)
F-019: 일괄 완료 처리
- 설명: 여러 할일을 선택하여 한번에 완료 처리한다.
- 우선순위: Should
입력 (Inputs)
| 필드명 |
타입 |
필수 |
검증 규칙 |
설명 |
| action |
string |
Y |
"complete" |
작업 유형 |
| ids |
string[] |
Y |
1개 이상의 유효한 ObjectId |
대상 할일 ID 배열 |
처리 규칙 (Business Rules)
- 선택된 모든 할일의 completed를 true로 설정한다.
- 각 항목의 updated_at을 갱신한다.
- 존재하지 않는 ID는 무시하고 나머지를 처리한다.
- 처리된 수와 실패 수를 반환한다.
출력 (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)
- 선택된 모든 할일을 물리 삭제한다.
- 삭제 전 확인 다이얼로그를 표시한다.
- 존재하지 않는 ID는 무시한다.
출력 (Outputs)
| 상황 |
HTTP 상태 |
응답 |
| 성공 |
200 OK |
{"action": "delete", "processed": 3, "failed": 0} |
| ID 누락 |
422 Unprocessable Entity |
{"detail": "대상 할일을 선택해주세요"} |
수락 기준 (Acceptance Criteria)
F-021: 일괄 카테고리 변경
- 설명: 여러 할일을 선택하여 한번에 카테고리를 변경한다.
- 우선순위: Should
입력 (Inputs)
| 필드명 |
타입 |
필수 |
검증 규칙 |
설명 |
| action |
string |
Y |
"move_category" |
작업 유형 |
| ids |
string[] |
Y |
1개 이상의 유효한 ObjectId |
대상 할일 ID 배열 |
| category_id |
string | null |
Y |
유효한 카테고리 ObjectId 또는 null |
변경할 카테고리 |
처리 규칙 (Business Rules)
- 선택된 모든 할일의 category_id를 지정된 값으로 변경한다.
- category_id가 null이면 "미분류"로 설정한다.
- 대상 카테고리의 존재를 검증한다.
출력 (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 |
일괄 작업 (완료/삭제/카테고리 변경) |