역할
- 업무(Task) 생성, 수정, 삭제 등 커맨드(Command) 작업 처리
- DB 저장, 권한 체크, 첨부파일 처리 등 수행
- 서비스에서 발생한 예외는
ApiException → 글로벌 핸들러에서 JSON 응답 처리
1. 업무 생성 (Create Task)
public TaskResponse create(TaskCreateRequest req, Long loginUserId) {
// 1. 로그인 여부 확인
if (loginUserId == null)
throw new ApiException(ErrorCode.UNAUTHORIZED, "로그인이 필요합니다.");
// 2. 제목 공백 제거 및 필수 체크
String title = req.titleTrimmed();
if (title == null || title.isEmpty()) {
throw new ApiException(ErrorCode.BAD_REQUEST, "제목은 필수입니다.");
}
// 3. 작성자 정보 조회
UserEntity creator = userRepository.findById(loginUserId)
.orElseThrow(() -> new ApiException(ErrorCode.UNAUTHORIZED, "사용자가 존재하지 않습니다."));
// 4. 담당자 존재 여부 확인 (선택 사항)
UserEntity assignee = (req.assigneeId() == null) ? null
: userRepository.findById(req.assigneeId())
.orElseThrow(() -> new ApiException(ErrorCode.NOT_FOUND, "담당자를 찾을 수 없습니다."));
// 5. 가시성/우선순위 기본값 처리
TaskVisibility visibility = req.visibilityOrDefault();
TaskPriority priority = req.priorityOrDefault();
// 6. PUBLIC 업무 생성 권한 체크
if (visibility == TaskVisibility.PUBLIC) {
Role role = creator.getRole();
if (role == null || (role != Role.MANAGER && role != Role.ADMIN)) {
throw new ApiException(ErrorCode.UNAUTHORIZED, "PUBLIC 업무는 매니저/관리자만 생성할 수 있습니다.");
}
}
// 7. 부서 결정: 소유 부서 vs 실제 처리 부서
DepartmentEntity ownerDept = creator.getDepartment();
DepartmentEntity workDept = (assignee != null) ? assignee.getDepartment() : ownerDept;
// 8. DB 저장: TaskEntity 생성
TaskEntity task = TaskEntity.builder()
.title(title)
.description(req.description()) // 초기 템프 내용
.status(TaskStatus.TODO)
.priority(priority)
.visibility(visibility)
.dueDate(req.dueDate())
.createdBy(creator)
.assignee(assignee)
.ownerDepartment(ownerDept)
.workDepartment(workDept)
.build();
taskRepository.save(task); // DB에 저장 → ID 확보
// 9. 첨부파일 처리: tmp → final/{taskId}, description URL 치환
String descriptionFinal = fileStorageService.commitEditorImagesInContent(
task.getDescription(), "tasks", task.getId());
task.setDescription(descriptionFinal);
taskRepository.save(task); // 수정된 description 재저장
// 10. DTO 변환 후 반환
return TaskResponse.from(task);
}
업무 생성 플로우
[클라이언트] POST /tasks
│
▼
[TaskCommandService.create]
│
├─ 로그인 확인 → 없으면 UNAUTHORIZED
├─ 제목 필수 체크 → 없으면 BAD_REQUEST
├─ 작성자/담당자 조회
├─ PUBLIC 업무 권한 체크 (MANAGER/ADMIN)
├─ 부서 결정 (ownerDept / workDept)
├─ TaskEntity 저장 → DB ID 확보
├─ 첨부파일 처리 (tmp → final/{taskId})
└─ TaskResponse DTO 반환
보안/검증 포인트
- 제목 필수 체크, 공백 제거
- PUBLIC 업무 생성 권한 → Role 기반
- 담당자/작성자 존재 여부 확인 → NOT_FOUND 처리
- 로그인 여부 확인 → UNAUTHORIZED 처리
- 첨부파일 처리 시 tmp 폴더 → 실제 taskId 폴더 이동
- 서비스에서 발생한 예외 →
ApiException으로 통일 → 글로벌 핸들러에서 JSON 응답