Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,9 @@ private DcaBriefEvaluationResponse getOrCreateBriefAnalysis(Long workId) {
});
}

@Transactional
public void runBriefInternal(Long workId) {
getOrCreateBriefAnalysis(workId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,9 @@ private List<DetailEval> getOrCreateDetailEvaluation(Long workId, EvaluationType
return detailEvals;
}

@Transactional
public void runDcaEvaluationInternal(Long workId) {
getOrCreateEvaluation(workId);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.susanghan_guys.server.personalwork.application;

import com.susanghan_guys.server.personalwork.domain.Evaluation;
import com.susanghan_guys.server.personalwork.domain.type.EvaluationType;
import com.susanghan_guys.server.personalwork.dto.response.ReportPipelineResponse;
import com.susanghan_guys.server.personalwork.exception.PersonalWorkException;
import com.susanghan_guys.server.personalwork.exception.code.PersonalWorkErrorCode;
import com.susanghan_guys.server.personalwork.infrastructure.persistence.DetailEvalRepository;
import com.susanghan_guys.server.personalwork.infrastructure.persistence.EvaluationRepository;
import com.susanghan_guys.server.work.domain.Work;
import com.susanghan_guys.server.work.domain.type.WorkType;
import com.susanghan_guys.server.work.exception.WorkException;
import com.susanghan_guys.server.work.exception.code.WorkErrorCode;
import com.susanghan_guys.server.work.infrastructure.persistence.WorkRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
public class ReportInternalService {

private final WorkRepository workRepository;
private final WorkSummaryService workSummaryService;
private final DcaBriefEvaluationService dcaBriefEvaluationService;
private final DcaWorkEvaluationService dcaWorkEvaluationService;
private final YccWorkEvaluationService yccWorkEvaluationService;
private final EvaluationRepository evaluationRepository;
private final DetailEvalRepository detailEvalRepository;


@Transactional
public ReportPipelineResponse runPipeline(Long workId) {
boolean summaryDone = false;
boolean briefDone = false;
boolean evaluationDone = false;

Work work = workRepository.findById(workId)
.orElseThrow(() -> new WorkException(WorkErrorCode.WORK_NOT_FOUND));

workSummaryService.runSummaryInternal(workId);
summaryDone = true;

if (work.getType() == WorkType.DCA) {
dcaBriefEvaluationService.runBriefInternal(workId);
briefDone = true;
}

runEvaluationInternal(workId);
evaluationDone = true;

return ReportPipelineResponse.builder()
.summaryDone(summaryDone)
.briefDone(briefDone)
.evaluationDone(evaluationDone)
.build();
}

@Transactional
public void deleteAllEvaluationsByWorkId(Long workId) {
// 작품 유효성
workRepository.findById(workId)
.orElseThrow(() -> new PersonalWorkException(PersonalWorkErrorCode.WORK_NOT_FOUND));

// 부모 엔티티를 엔티티 삭제(remove)로 지워야 orphanRemoval이 동작함
List<Evaluation> evaluations = evaluationRepository.findAllByWorkId(workId);
if (!evaluations.isEmpty()) {
evaluationRepository.deleteAll(evaluations); // 각 엔티티 remove -> 자식(DetailEval)도 함께 제거
}
}

@Transactional
public void deleteDetailEvalsByWorkIdAndType(Long workId, EvaluationType type) {
workRepository.findById(workId)
.orElseThrow(() -> new PersonalWorkException(PersonalWorkErrorCode.WORK_NOT_FOUND));

Evaluation evaluation = evaluationRepository.findByWorkIdAndType(workId, type)
.orElseThrow(() -> new PersonalWorkException(PersonalWorkErrorCode.EVALUATION_NOT_FOUND));

if (!evaluation.getDetails().isEmpty()) {
detailEvalRepository.deleteAll(evaluation.getDetails());
evaluation.getDetails().clear();
}
}

public void runEvaluationInternal(Long workId) {
Work work = workRepository.findById(workId)
.orElseThrow(() -> new WorkException(WorkErrorCode.WORK_NOT_FOUND));

switch (work.getType()) {
case DCA -> dcaWorkEvaluationService.runDcaEvaluationInternal(workId);
case YCC -> yccWorkEvaluationService.runYccEvaluationInternal(workId);
default -> throw new PersonalWorkException(PersonalWorkErrorCode.UNSUPPORTED_WORK_TYPE);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,16 @@ private Summary getOrCreateYccWorkSummary(Long workId) {
});
}

@Transactional
public void runSummaryInternal(Long workId) {
Work work = workRepository.findById(workId)
.orElseThrow(() -> new WorkException(WorkErrorCode.WORK_NOT_FOUND));

Summary summary = switch (work.getType()) {
case DCA -> getOrCreateDcaWorkSummary(workId);
case YCC -> getOrCreateYccWorkSummary(workId);
default -> throw new PersonalWorkException(PersonalWorkErrorCode.UNSUPPORTED_WORK_TYPE);
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,9 @@ private List<DetailEval> getOrCreateDetailEvaluation(Long workId, EvaluationType

return detailEvals;
}

@Transactional
public void runYccEvaluationInternal(Long workId) {
getOrCreateEvaluation(workId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.susanghan_guys.server.personalwork.dto.response;

import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

@Builder
@Schema(description = "리포트 생성 파이프라인 결과")
public record ReportPipelineResponse(
@Schema(description = "요약 완료 여부")
boolean summaryDone,

@Schema(description = "브리프 해석 완료 여부 (DCA만)")
boolean briefDone,

@Schema(description = "총평 완료 여부")
boolean evaluationDone
) {}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public enum PersonalWorkErrorCode implements BaseCode {
SUMMARY_NOT_FOUND(HttpStatus.NOT_FOUND, 404, "출품작 요약을 찾을 수 없습니다."),
DETAIL_EVALUATION_TYPE_NOT_FOUND(HttpStatus.NOT_FOUND, 404, "해당 타입의 세부 총평을 찾을 수 없습니다."),
BRIEF_ANALYSIS_NOT_FOUND(HttpStatus.NOT_FOUND, 404, "브리프 해석을 찾을 수 없습니다."),
UNSUPPORTED_WORK_TYPE(HttpStatus.BAD_REQUEST, 400, "실행할 수 없는 타입의 출품작입니다."),
;

private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.susanghan_guys.server.personalwork.presentation;

import com.susanghan_guys.server.global.common.CommonResponse;
import com.susanghan_guys.server.personalwork.application.ReportInternalService;
import com.susanghan_guys.server.personalwork.domain.type.EvaluationType;
import com.susanghan_guys.server.personalwork.dto.response.ReportPipelineResponse;
import com.susanghan_guys.server.personalwork.presentation.swagger.ReportInternalSwagger;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import static com.susanghan_guys.server.personalwork.presentation.response.PersonalWorkSuccessCode.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/v1/internal/reports")
public class ReportInternalController implements ReportInternalSwagger {

private final ReportInternalService reportInternalService;

@Override
@PostMapping("/{workId}/pipeline")
public CommonResponse<ReportPipelineResponse> runPipeline(@PathVariable Long workId) {
ReportPipelineResponse result = reportInternalService.runPipeline(workId);
return CommonResponse.success(REPORT_PIPELINE_SUCCESS, result);
}

@Override
@DeleteMapping("/{workId}/evaluations")
public CommonResponse<String> deleteAllEvaluations(@PathVariable Long workId) {
reportInternalService.deleteAllEvaluationsByWorkId(workId);
return CommonResponse.success(WORK_EVALUATIONS_DELETE_SUCCESS, "OK");
}

@Override
@DeleteMapping("/{workId}/evaluations/{type}/details")
public CommonResponse<String> deleteDetailEvaluations(
@PathVariable Long workId,
@PathVariable EvaluationType type
) {
reportInternalService.deleteDetailEvalsByWorkIdAndType(workId, type);
return CommonResponse.success(DETAIL_EVALUATION_DELETE_SUCCESS, "OK");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ public enum PersonalWorkSuccessCode implements BaseCode {
WORK_WEAKNESSES_SUCCESS(HttpStatus.OK, 200, "Work Weaknesses Retrieval Success"),

WORK_DETAILS_FETCH_SUCCESS(HttpStatus.OK, 200, "Work Detail Evaluation Retrieval Success"),
WORK_SUMMARY_SUCCESS(HttpStatus.OK, 200, "Work Summary Retrieval Success")
WORK_SUMMARY_SUCCESS(HttpStatus.OK, 200, "Work Summary Retrieval Success"),

WORK_EVALUATIONS_DELETE_SUCCESS(HttpStatus.OK, 200, "Work Evaluations Delete Success"),
DETAIL_EVALUATION_DELETE_SUCCESS(HttpStatus.OK, 200, "Detail Evaluations Delete Success"),
REPORT_PIPELINE_SUCCESS(HttpStatus.OK, 200, "Report Pipeline Success"),
;

private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.susanghan_guys.server.personalwork.presentation.swagger;

import com.susanghan_guys.server.global.common.CommonResponse;
import com.susanghan_guys.server.personalwork.domain.type.EvaluationType;
import com.susanghan_guys.server.personalwork.dto.response.ReportPipelineResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.PathVariable;

@Tag(name = "[백엔드 내부 - 리포트 생성 및 삭제]", description = "요약/브리프/총평을 일괄 생성 API")
public interface ReportInternalSwagger {

@Operation(
summary = "리포트 파이프라인 실행 API(workType에 따라 분기)",
description = """
### Pathvariable
`workId` : 작품 고유 ID

### 동작
- DCA: 요약 → 브리프 해석 → 총평
- YCC: 요약 → 총평
"""
)
@ApiResponse(responseCode = "200", description = "수상 리포트 생성 파이프라인이 실행되었습니다.")
CommonResponse<ReportPipelineResponse> runPipeline(@PathVariable Long workId);

@Operation(
summary = "작품 전체 총평/세부 총평 삭제 API(내부용)",
description = """
### Pathvariable
- `workId`: 작품 고유 ID

### 동작
- 해당 작품의 모든 Evaluation(전체 총평) 삭제
- 각 Evaluation에 매핑된 DetailEval도 함께 삭제
"""
)
CommonResponse<String> deleteAllEvaluations(@PathVariable Long workId);

@Operation(
summary = "작품 특정 타입 총평/세부 총평 삭제 API(내부용)",
description = """
### Pathvariable
- `workId`: 작품 고유 ID
- `type`: EvaluationType (예: TARGET_FITNESS, BRAND_UNDERSTANDING, ...)

### 동작
- 지정한 작품(workId)의 특정 타입 Evaluation은 그대로 두고,
그 Evaluation에 연결된 DetailEval(세부 총평)만 삭제합니다.
"""
)
CommonResponse<String> deleteDetailEvaluations(@PathVariable Long workId, @PathVariable EvaluationType type);
}
Loading