Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
import com.susanghan_guys.server.feedback.exception.code.FeedbackErrorCode;
import com.susanghan_guys.server.feedback.infrastructure.mapper.FeedbackMapper;
import com.susanghan_guys.server.feedback.infrastructure.persistence.FeedbackRepository;
import com.susanghan_guys.server.global.security.CurrentUserProvider;
import com.susanghan_guys.server.user.domain.User;
import com.susanghan_guys.server.work.domain.Work;
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.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -21,18 +24,21 @@ public class FeedbackService {

private final WorkRepository workRepository;
private final FeedbackRepository feedbackRepository;
private final CurrentUserProvider currentUserProvider;

@Transactional
public void createFeedback(Long workId, FeedbackRequest request) {
User user = currentUserProvider.getCurrentUser();

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

if (feedbackRepository.existsByWorkId(workId)) {
Feedback feedback = FeedbackMapper.toEntity(request.score(), request.content(), user, work);

try {
feedbackRepository.save(feedback);
} catch (DataIntegrityViolationException e) {
throw new FeedbackException(FeedbackErrorCode.FEEDBACK_ALREADY_EXIST);
}

Feedback feedback = FeedbackMapper.toEntity(request.score(), request.content(), work);

feedbackRepository.save(feedback);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.susanghan_guys.server.feedback.domain;

import com.susanghan_guys.server.global.domain.BaseEntity;
import com.susanghan_guys.server.user.domain.User;
import com.susanghan_guys.server.work.domain.Work;
import jakarta.persistence.*;
import lombok.AccessLevel;
Expand All @@ -9,6 +10,12 @@
import lombok.NoArgsConstructor;

@Entity
@Table(uniqueConstraints = {
@UniqueConstraint(
name = "UK_feedback_user_work",
columnNames = {"user_id", "work_id"}
)
})
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Feedback extends BaseEntity {
Expand All @@ -24,18 +31,24 @@ public class Feedback extends BaseEntity {
@Column(name = "content", nullable = false)
private String content;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "work_id", nullable = false, unique = true)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "work_id", nullable = false)
private Work work;

@Builder
public Feedback(
Integer score,
String content,
User user,
Work work
) {
this.score = score;
this.content = content;
this.user = user;
this.work = work;
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package com.susanghan_guys.server.feedback.infrastructure.mapper;

import com.susanghan_guys.server.feedback.domain.Feedback;
import com.susanghan_guys.server.user.domain.User;
import com.susanghan_guys.server.work.domain.Work;

public class FeedbackMapper {

public static Feedback toEntity(Integer score, String content, Work work) {
public static Feedback toEntity(Integer score, String content, User user, Work work) {
return Feedback.builder()
.score(score)
.content(content)
.user(user)
.work(work)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.susanghan_guys.server.feedback.infrastructure.persistence;

import com.susanghan_guys.server.feedback.domain.Feedback;
import com.susanghan_guys.server.user.domain.User;
import com.susanghan_guys.server.work.domain.Work;
import org.springframework.data.jpa.repository.JpaRepository;

public interface FeedbackRepository extends JpaRepository<Feedback, Long> {
boolean existsByWorkId(Long workId);
boolean existsByWorkAndUser(Work work, User user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,16 @@ public static OpenAiPrompt buildDcaDetailEvaluationPrompt(
2. Output "score": INTEGER (0-10).

Scoring rule:
- Baseline: 4 points
- 10-8 points: The work fully and clearly meets the criterion, going beyond expectations with concrete and persuasive execution. (e.g. a heavy theme reframed into a light participatory idea that feels fresh and positive)
- 7-6 points: The work sufficiently meets the criterion but shows some lack of clarity, specificity, or persuasiveness. (e.g. a perception shift is attempted but remains limited or predictable)
- 5 or below: The work fails to meet the core requirement of the criterion. (e.g. participation exists but the structure lacks potential to expand into a true public campaign)
- If the score is 7 or below, and there is a clear reason for the lower score, add at least one limitation, weakness, or risk factor to justify it. \s
- If no meaningful reason is apparent, you may omit this part instead of forcing a generic remark.

- Baseline guideline: 6 points
- 9 points: Allowed, but only if the rationale is very specific, concrete, and clearly persuasive.\s
→ Do NOT overuse; should be rare, but possible.
- 10 points: Practically impossible. Use only in extraordinary, near-perfect cases.
- 7–8 points: Solid and well-justified executions.
- 6 points: Baseline / average quality. If you assign 6, you must provide one clear weakness/limitation.
- 5 points or below: Strongly discouraged. Only use if the campaign is clearly and fundamentally flawed.
If you assign ≤5, you must justify with one clear weakness/risk factor (do not list more than one).
- Below 5: Not allowed.

Conservativeness:
- Do NOT inflate scores without clear evidence.
- Be conservative: most scores should be 8 or below.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ private void sendWorkMembers(Work work, String template) {
), template);

for (WorkMember workMember : work.getWorkMembers()) {
if (work.getUser().getEmail().equals(workMember.getTeamMember().getEmail())) {
continue;
}
personalizeMail(new MailRequest(
workMember.getTeamMember().getEmail(),
workMember.getTeamMember().getName(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import com.susanghan_guys.server.personalwork.infrastructure.persistence.EvaluationRepository;
import com.susanghan_guys.server.user.domain.User;
import com.susanghan_guys.server.work.domain.Work;
import com.susanghan_guys.server.work.domain.type.ReportStatus;
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;
Expand Down Expand Up @@ -98,7 +97,6 @@ private List<Evaluation> getOrCreateEvaluation(Long workId) {
List<DetailEval> detailEvals = getOrCreateDetailEvaluation(workId, evaluation.getType());
evaluation.updateScore(detailEvals);
}
work.updateReportStatus(ReportStatus.COMPLETED);

return evaluations;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
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.ReportStatus;
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;
Expand All @@ -17,6 +18,7 @@
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

@Service
@RequiredArgsConstructor
Expand All @@ -30,7 +32,6 @@ public class ReportInternalService {
private final EvaluationRepository evaluationRepository;
private final DetailEvalRepository detailEvalRepository;


@Transactional
public ReportPipelineResponse runPipeline(Long workId) {
boolean summaryDone = false;
Expand All @@ -51,6 +52,11 @@ public ReportPipelineResponse runPipeline(Long workId) {
runEvaluationInternal(workId);
evaluationDone = true;

if (work.getCode() == null) {
work.updateCode(UUID.randomUUID().toString().substring(0, 6).toUpperCase());
}
work.updateReportStatus(ReportStatus.COMPLETED);

return ReportPipelineResponse.builder()
.summaryDone(summaryDone)
.briefDone(briefDone)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import com.susanghan_guys.server.personalwork.infrastructure.persistence.EvaluationRepository;
import com.susanghan_guys.server.user.domain.User;
import com.susanghan_guys.server.work.domain.Work;
import com.susanghan_guys.server.work.domain.type.ReportStatus;
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;
Expand Down Expand Up @@ -108,7 +107,6 @@ private List<Evaluation> getOrCreateEvaluation(Long workId) {
List<DetailEval> detailEvals = getOrCreateDetailEvaluation(workId, evaluation.getType());
evaluation.updateScore(detailEvals);
}
work.updateReportStatus(ReportStatus.COMPLETED);

return evaluations;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.susanghan_guys.server.work.application;

import com.susanghan_guys.server.feedback.infrastructure.persistence.FeedbackRepository;
import com.susanghan_guys.server.global.security.CurrentUserProvider;
import com.susanghan_guys.server.user.domain.User;
import com.susanghan_guys.server.work.application.validator.ReportValidator;
Expand All @@ -26,7 +27,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;

@Service
@RequiredArgsConstructor
Expand All @@ -35,6 +35,7 @@ public class ReportService {

private final CurrentUserProvider currentUserProvider;
private final WorkRepository workRepository;
private final FeedbackRepository feedbackRepository;
private final WorkVisibilityRepository workVisibilityRepository;
private final ReportValidator reportValidator;

Expand Down Expand Up @@ -64,9 +65,11 @@ public ReportInfoResponse getReportInfo(Long workId) {
Work work = workRepository.findById(workId)
.orElseThrow(() -> new WorkException(WorkErrorCode.WORK_NOT_FOUND));

boolean hasFeedback = feedbackRepository.existsByWorkAndUser(work, user);

reportValidator.validateReportInfo(user, work);

return ReportInfoResponse.from(work);
return ReportInfoResponse.from(work, hasFeedback);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ public record ReportInfoResponse(
Brand brand,

@Schema(description = "공모전 팀원", example = "[\"김철수\", \"주정빈\", \"강수진\"]")
List<String> workMembers
List<String> workMembers,

boolean hasFeedback
) {
public static ReportInfoResponse from(Work work) {
public static ReportInfoResponse from(Work work, boolean hasFeedback) {
return ReportInfoResponse.builder()
.workName(work.getTitle())
.contestName(work.getContest().getTitle())
Expand All @@ -32,6 +34,7 @@ public static ReportInfoResponse from(Work work) {
.map(workMember -> workMember.getTeamMember().getName())
.toList()
)
.hasFeedback(hasFeedback)
.build();
}
}
Loading