역할


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 반환

보안/검증 포인트