Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c63158d
feat(#5): AssignmentEntity 제작 완료
Jul 8, 2025
24993bb
feat(#5): assignment create
Jul 9, 2025
f5af57a
faet(#5) : 중간 저장:
Jul 9, 2025
1ee0253
feat(#5): Entity 수정
Jul 9, 2025
d362b11
feat(#5): timetable merge
Jul 9, 2025
f9a11e9
feat(#5): 선생님 과제 API
Jul 9, 2025
40a81e2
feat(#5):chore: remove tracked postgres-data and ignore it
Jul 9, 2025
ebe472f
feat(#5): 중간 저장
Jul 9, 2025
dc565d3
feat(#5): 충돌 해결
Jul 9, 2025
6243f22
feat(#5): gitignore 수정
Jul 9, 2025
79d27e3
feat(#5): 학생 과제 기능 제작
Jul 10, 2025
e74ac06
feat(#5): 모든 과제 조회 controller 코드 완성
Jul 11, 2025
0aa96d8
feat(#5): create
Jul 13, 2025
0223e30
Merge branch 'develop' into feat/#5
Jul 14, 2025
45526b2
feat(#5): merge conflict resolve
Jul 14, 2025
8e92b66
feat(#5): 과제 생성 기능 중간 저장
Jul 14, 2025
7b03283
feat(#5): 과제 생성 기능 중간 저장
Jul 14, 2025
c6a20c4
feat(#6): add get /{classId}/all api
Hgyeol Jul 14, 2025
c35fe2f
feat(#6): add get /api/document/download/{documentId} api
Hgyeol Jul 15, 2025
c537661
feat(#6): add patch /api/document api
Hgyeol Jul 15, 2025
f5f7665
feat(#6): fix patch /api/document api
Hgyeol Jul 15, 2025
c52212a
feat(#6): fix errors
Hgyeol Jul 15, 2025
a44dde9
feat(#5): 과제 생성
Jul 15, 2025
00ae37d
feat(#5): 과제 생성 확인 완료
Jul 15, 2025
73bd190
feat(#5): S3 파일 다운 받기
Jul 16, 2025
94e095d
feat(#5): 학생 과제 일자 받기
Jul 16, 2025
2c942b8
feat(#6): fix cors
Hgyeol Jul 16, 2025
3d089be
feat(#6): last commit
Hgyeol Jul 16, 2025
25dd720
Merge remote-tracking branch 'origin/feat/#5' into feat/#6
Hgyeol Jul 16, 2025
6467264
feat(#6): fix merge feat/#5
Hgyeol Jul 16, 2025
d485e24
feat(#6): postgre-data 파일 제거
Jul 16, 2025
6f27830
feat(#6): fix errors(s3, builder)
Hgyeol Jul 16, 2025
913c04b
feat(#6): fix parameter error
Hgyeol Jul 16, 2025
2a9e16c
feat(#6): fix S3 config
Hgyeol Jul 16, 2025
ef1a5a1
feat(#6): fix file uploading
Hgyeol Jul 31, 2025
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
Binary file modified .DS_Store
Binary file not shown.
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
testImplementation 'io.projectreactor:reactor-test'
annotationProcessor 'org.projectlombok:lombok:1.18.30'

Expand Down Expand Up @@ -62,6 +63,11 @@ dependencies {
testImplementation 'org.mockito:mockito-junit-jupiter'

implementation 'me.paulschwarz:spring-dotenv:4.0.0'

//AWS S3
// implementation 'software.amazon.awssdk:s3'
implementation 'software.amazon.awssdk:s3:2.32.1'
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
Comment on lines +69 to +70
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Spring Cloud AWS 버전을 업데이트해야 합니다.

AWS S3 SDK는 최신 버전(2.32.1)을 사용하고 있지만, Spring Cloud AWS 버전(2.2.6.RELEASE)이 너무 오래되었습니다. 이는 Spring Boot 3.x와 호환성 문제를 일으킬 수 있습니다.

다음과 같이 최신 버전으로 업데이트하는 것을 권장합니다:

-    implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
+    implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3:3.1.1'

Spring Cloud AWS의 최신 버전 확인을 위해 다음을 검색해주세요:


🌐 Web query:

What is the latest version of Spring Cloud AWS that is compatible with Spring Boot 3.x?

💡 Result:

The latest version of Spring Cloud AWS compatible with Spring Boot 3.x is 3.4.0, which works with Spring Boot 3.5.x, while 3.3.x supports Spring Boot 3.4.x, 3.2.x supports 3.2.x–3.3.x, and 3.0.x supports 3.0.x–3.1.x[1][4][6][7].

Compatibility Table

Spring Cloud AWS Spring Boot Compatibility Spring Framework AWS Java SDK
3.0.x 3.0.x, 3.1.x 6.0.x 2.x
3.1.x 3.2.x 6.1.x 2.x
3.2.x 3.2.x, 3.3.x 6.1.x 2.x
3.3.x 3.4.x 6.2.x 2.x
3.4.x 3.5.x 6.2.x 2.x
  • Spring Cloud AWS 3.4.0 is the release for Spring Boot 3.5.x[1].
  • Older 3.x versions are for earlier 3.x releases of Spring Boot: for example, 3.2.x is intended for 3.2.x–3.3.x[4][6][7].

Additional Details

  • The Spring Cloud AWS project migrated to supporting Spring Boot 3.x starting with 3.0.0-M3 (milestone 3)[1][4].
  • Each major/minor version in the 3.x series is paired with the corresponding Spring Boot version (e.g., 3.3.x with Spring Boot 3.4.x)[1].
  • To use the most recent Spring Boot 3.x (i.e., 3.5.x), select Spring Cloud AWS 3.4.0[1].

Reference Links (For Internal Team)

  • [Spring Cloud AWS GitHub Releases][6]
  • [Spring Cloud AWS Compatibility Table][1]

If you are targeting a specific 3.x release of Spring Boot, match the Spring Cloud AWS version accordingly using the table above to ensure full compatibility[1][4][7].

Citations:


Spring Cloud AWS 버전을 Spring Boot 3.x 호환 최신(3.4.0)으로 업그레이드하세요

다음 위치를 수정해 주세요:

  • build.gradle (69–70줄)
-    implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
+    implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3:3.4.0'

Spring Boot 3.5.x 사용 시 Spring Cloud AWS 3.4.0이 호환되므로 해당 버전으로 변경이 필요합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
implementation 'software.amazon.awssdk:s3:2.32.1'
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
implementation 'software.amazon.awssdk:s3:2.32.1'
implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3:3.4.0'
🤖 Prompt for AI Agents
In build.gradle at lines 69 to 70, update the Spring Cloud AWS dependency
version from 2.2.6.RELEASE to 3.4.0 to ensure compatibility with Spring Boot
3.x. Replace the existing version string with '3.4.0' for the
'org.springframework.cloud:spring-cloud-starter-aws' dependency.

}

ext {
Expand Down
Binary file removed postgres-data/base/1/1259
Binary file not shown.
Binary file removed postgres-data/base/1/2619
Binary file not shown.
Binary file removed postgres-data/base/1/2619_fsm
Binary file not shown.
Binary file removed postgres-data/base/1/2619_vm
Binary file not shown.
Binary file removed postgres-data/base/1/2696
Binary file not shown.
Binary file removed postgres-data/base/1/2840
Binary file not shown.
Binary file removed postgres-data/base/1/2841
Binary file not shown.
Binary file removed postgres-data/base/1/pg_internal.init
Binary file not shown.
Binary file removed postgres-data/base/16384/1247
Binary file not shown.
Binary file removed postgres-data/base/16384/1247_vm
Binary file not shown.
Binary file removed postgres-data/base/16384/1249
Binary file not shown.
Binary file removed postgres-data/base/16384/1249_fsm
Binary file not shown.
Binary file removed postgres-data/base/16384/1249_vm
Binary file not shown.
Binary file removed postgres-data/base/16384/1259
Binary file not shown.
Binary file removed postgres-data/base/16384/1259_vm
Binary file not shown.
Binary file removed postgres-data/base/16384/2224
Binary file not shown.
Binary file removed postgres-data/base/16384/2579
Binary file not shown.
Binary file removed postgres-data/base/16384/2604
Binary file not shown.
Binary file removed postgres-data/base/16384/2606
Binary file not shown.
Binary file removed postgres-data/base/16384/2606_vm
Binary file not shown.
Binary file removed postgres-data/base/16384/2608
Binary file not shown.
Binary file removed postgres-data/base/16384/2608_fsm
Binary file not shown.
Binary file removed postgres-data/base/16384/2608_vm
Binary file not shown.
Binary file removed postgres-data/base/16384/2610
Binary file not shown.
Binary file removed postgres-data/base/16384/2610_vm
Binary file not shown.
Binary file removed postgres-data/base/16384/2656
Binary file not shown.
Binary file removed postgres-data/base/16384/2657
Binary file not shown.
Binary file removed postgres-data/base/16384/2658
Binary file not shown.
Binary file removed postgres-data/base/16384/2659
Binary file not shown.
Binary file removed postgres-data/base/16384/2662
Binary file not shown.
Binary file removed postgres-data/base/16384/2663
Binary file not shown.
Binary file removed postgres-data/base/16384/2664
Binary file not shown.
Binary file removed postgres-data/base/16384/2665
Binary file not shown.
Binary file removed postgres-data/base/16384/2666
Binary file not shown.
Binary file removed postgres-data/base/16384/2667
Binary file not shown.
Binary file removed postgres-data/base/16384/2673
Binary file not shown.
Binary file removed postgres-data/base/16384/2674
Binary file not shown.
Binary file removed postgres-data/base/16384/2678
Binary file not shown.
Binary file removed postgres-data/base/16384/2679
Binary file not shown.
Binary file removed postgres-data/base/16384/2703
Binary file not shown.
Binary file removed postgres-data/base/16384/2704
Binary file not shown.
Binary file removed postgres-data/base/16384/3455
Binary file not shown.
Binary file removed postgres-data/base/16384/5002
Binary file not shown.
Binary file removed postgres-data/base/5/pg_internal.init
Binary file not shown.
Binary file removed postgres-data/global/1260
Binary file not shown.
Binary file removed postgres-data/global/pg_control
Binary file not shown.
Binary file removed postgres-data/global/pg_internal.init
Binary file not shown.
Binary file removed postgres-data/pg_wal/000000010000000000000001
Binary file not shown.
Binary file removed postgres-data/pg_xact/0000
Binary file not shown.
Binary file modified src/main/.DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package hello.cluebackend.domain.assignment.domain;

import hello.cluebackend.domain.assignment.presentation.dto.AssignmentAttachmentDto;
import hello.cluebackend.domain.classroom.domain.ClassRoom;
import hello.cluebackend.domain.user.domain.UserEntity;
import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDateTime;

@Entity
@Table(name = "assignments")
@Getter @Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Assignment {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "assignment_id")
private Long assignmentId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "class_room_id")
private ClassRoom classRoom;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "creator_id")
private UserEntity user;

@Column(name = "title")
private String title;

@Column(name = "content")
private String content;

@Column(name = "start_date")
private LocalDateTime startDate;

@Column(name = "due_date")
private LocalDateTime dueDate;
Comment on lines +30 to +40
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

필수 필드에 대한 검증 어노테이션 추가 권장

제목이나 내용 같은 필수 필드에 대한 검증이 없어 데이터 무결성 문제가 발생할 수 있습니다.

Bean Validation 어노테이션을 추가하세요:

+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;

  @Column(name = "title")
+  @NotBlank(message = "제목은 필수입니다")
  private String title;

  @Column(name = "content")
+  @NotBlank(message = "내용은 필수입니다")
  private String content;

  @Column(name = "start_date")
+  @NotNull(message = "시작일은 필수입니다")
  private LocalDateTime startDate;

  @Column(name = "due_date")
+  @NotNull(message = "마감일은 필수입니다")
  private LocalDateTime dueDate;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Column(name = "title")
private String title;
@Column(name = "content")
private String content;
@Column(name = "start_date")
private LocalDateTime startDate;
@Column(name = "due_date")
private LocalDateTime dueDate;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@Column(name = "title")
@NotBlank(message = "제목은 필수입니다")
private String title;
@Column(name = "content")
@NotBlank(message = "내용은 필수입니다")
private String content;
@Column(name = "start_date")
@NotNull(message = "시작일은 필수입니다")
private LocalDateTime startDate;
@Column(name = "due_date")
@NotNull(message = "마감일은 필수입니다")
private LocalDateTime dueDate;
🤖 Prompt for AI Agents
In src/main/java/hello/cluebackend/domain/assignment/domain/Assignment.java
around lines 30 to 40, the fields title and content lack validation annotations,
risking data integrity issues. Add Bean Validation annotations such as @NotNull
or @NotBlank to these fields to enforce that they are mandatory and not empty
when persisted.

🛠️ Refactor suggestion

필드 검증 어노테이션 및 제약 조건 추가 권장

과제 데이터의 무결성을 위해 검증 어노테이션을 추가하는 것을 권장합니다.

+ import jakarta.validation.constraints.NotBlank;
+ import jakarta.validation.constraints.Size;
+ import jakarta.validation.constraints.Future;

  @Column(name = "title")
+ @NotBlank(message = "과제 제목은 필수입니다")
+ @Size(max = 200, message = "제목은 200자를 초과할 수 없습니다")
  private String title;

  @Column(name = "content")
+ @Size(max = 5000, message = "내용은 5000자를 초과할 수 없습니다")
  private String content;

  @Column(name = "start_date")
  private LocalDateTime startDate;

  @Column(name = "due_date")
+ @Future(message = "마감일은 현재 시간 이후여야 합니다")
  private LocalDateTime dueDate;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Column(name = "title")
private String title;
@Column(name = "content")
private String content;
@Column(name = "start_date")
private LocalDateTime startDate;
@Column(name = "due_date")
private LocalDateTime dueDate;
// Add these imports at the top of the file
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import jakarta.validation.constraints.Future;
@Column(name = "title")
@NotBlank(message = "과제 제목은 필수입니다")
@Size(max = 200, message = "제목은 200자를 초과할 수 없습니다")
private String title;
@Column(name = "content")
@Size(max = 5000, message = "내용은 5000자를 초과할 수 없습니다")
private String content;
@Column(name = "start_date")
private LocalDateTime startDate;
@Column(name = "due_date")
@Future(message = "마감일은 현재 시간 이후여야 합니다")
private LocalDateTime dueDate;
🤖 Prompt for AI Agents
In src/main/java/hello/cluebackend/domain/assignment/domain/Assignment.java
between lines 30 and 40, the entity fields lack validation annotations to ensure
data integrity. Add appropriate validation annotations such as @NotNull,
@NotBlank, or @Size to the fields title, content, startDate, and dueDate to
enforce constraints like non-nullability and length limits. This will help
maintain the consistency and validity of assignment data.

Comment on lines +36 to +40
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

과제 날짜 검증 로직 추가 필요

시작일이 마감일보다 늦는 경우를 방지하는 검증이 필요합니다.

엔티티에 검증 메서드를 추가하거나 서비스 레이어에서 검증하세요:

@PrePersist
@PreUpdate
private void validateDates() {
  if (startDate != null && dueDate != null && startDate.isAfter(dueDate)) {
    throw new IllegalArgumentException("시작일은 마감일보다 늦을 수 없습니다");
  }
}
🤖 Prompt for AI Agents
In src/main/java/hello/cluebackend/domain/assignment/domain/Assignment.java
around lines 36 to 40, add a validation method to ensure the startDate is not
after the dueDate. Implement a private method annotated with @PrePersist and
@PreUpdate that checks if both dates are non-null and throws an
IllegalArgumentException if startDate is after dueDate. This validation can be
added inside the entity class to enforce date consistency before saving or
updating.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package hello.cluebackend.domain.assignment.domain;

import hello.cluebackend.domain.assignment.presentation.dto.AssignmentAttachmentDto;
import hello.cluebackend.domain.user.domain.UserEntity;
import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDateTime;

@Entity
@Table(name = "assignment_attachment")
@Getter @Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AssignmentAttachment {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long assignmentAttachmentId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="assignment_id")
private Assignment assignment;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private UserEntity user;

@Column(name = "original_file_name")
private String originalFileName;

@Column(name = "stored_file_name")
private String storedFileName;

@Column(name = "file_path")
private String filePath;

@Column(name = "file_size")
private Integer fileSize;
Comment on lines +37 to +38
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

파일 크기 데이터 타입을 Long으로 변경하는 것을 권장합니다.

Integer 타입으로는 약 2GB까지만 표현 가능하여, 큰 파일의 경우 오버플로우가 발생할 수 있습니다.

  @Column(name = "file_size")
- private Integer fileSize;
+ private Long fileSize;

해당 DTO 클래스에서도 동일하게 수정이 필요합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Column(name = "file_size")
private Integer fileSize;
@Column(name = "file_size")
private Long fileSize;
🤖 Prompt for AI Agents
In
src/main/java/hello/cluebackend/domain/assignment/domain/AssignmentAttachment.java
at lines 37-38, change the data type of the fileSize field from Integer to Long
to support file sizes larger than 2GB and prevent overflow. Also, update the
corresponding DTO class to use Long for the file size field to maintain
consistency.


@Enumerated(EnumType.STRING)
@Column(name = "submit_type")
private SubmitType submitType;

@Column(name = "update_date")
private LocalDateTime updateDate;

public AssignmentAttachmentDto toDto() {
return AssignmentAttachmentDto.builder()
.assignmentAttachmentId(assignmentAttachmentId)
.assignment(assignment)
.user(user)
.originalFileName(originalFileName)
.storedFileName(storedFileName)
.filePath(filePath)
.fileSize(fileSize)
.submitType(submitType)
.updateDate(updateDate)
.build();
}
Comment on lines +47 to +59
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

toDto() 메서드에서 지연 로딩 엔티티 직접 노출

toDto() 메서드에서 assignmentuser 엔티티를 직접 반환하면 세션이 닫힌 후 LazyInitializationException이 발생할 수 있습니다.

DTO에서는 필요한 ID만 포함하도록 수정하세요:

  public AssignmentAttachmentDto toDto() {
    return AssignmentAttachmentDto.builder()
            .assignmentAttachmentId(assignmentAttachmentId)
-            .assignment(assignment)
-            .user(user)
+            .assignmentId(assignment != null ? assignment.getAssignmentId() : null)
+            .userId(user != null ? user.getUserId() : null)
            .originalFileName(originalFileName)
            .storedFileName(storedFileName)
            .filePath(filePath)
            .fileSize(fileSize)
            .submitType(submitType)
            .updateDate(updateDate)
            .build();
  }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
src/main/java/hello/cluebackend/domain/assignment/domain/AssignmentAttachment.java
between lines 47 and 59, the toDto() method currently returns the full
assignment and user entities, which can cause LazyInitializationException after
the session is closed. Modify the toDto() method to include only the IDs of
assignment and user in the DTO instead of the entire entities to avoid lazy
loading issues.

⚠️ Potential issue

toDto 메서드에서 엔티티 객체 직접 노출 문제

DTO에 엔티티 객체(assignment, user)를 직접 전달하면 지연 로딩 문제와 순환 참조 위험이 있습니다.

엔티티 대신 ID나 필요한 필드만 전달하도록 수정해주세요:

  public AssignmentAttachmentDto toDto() {
    return AssignmentAttachmentDto.builder()
            .assignmentAttachmentId(assignmentAttachmentId)
-           .assignment(assignment)
-           .user(user)
+           .assignmentId(assignment != null ? assignment.getAssignmentId() : null)
+           .userId(user != null ? user.getUserId() : null)
            .originalFileName(originalFileName)
            .storedFileName(storedFileName)
            .filePath(filePath)
            .fileSize(fileSize)
            .submitType(submitType)
            .updateDate(updateDate)
            .build();
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public AssignmentAttachmentDto toDto() {
return AssignmentAttachmentDto.builder()
.assignmentAttachmentId(assignmentAttachmentId)
.assignment(assignment)
.user(user)
.originalFileName(originalFileName)
.storedFileName(storedFileName)
.filePath(filePath)
.fileSize(fileSize)
.submitType(submitType)
.updateDate(updateDate)
.build();
}
public AssignmentAttachmentDto toDto() {
return AssignmentAttachmentDto.builder()
.assignmentAttachmentId(assignmentAttachmentId)
.assignmentId(assignment != null ? assignment.getAssignmentId() : null)
.userId(user != null ? user.getUserId() : null)
.originalFileName(originalFileName)
.storedFileName(storedFileName)
.filePath(filePath)
.fileSize(fileSize)
.submitType(submitType)
.updateDate(updateDate)
.build();
}
🤖 Prompt for AI Agents
In
src/main/java/hello/cluebackend/domain/assignment/domain/AssignmentAttachment.java
lines 47 to 59, the toDto method currently passes entire entity objects
assignment and user directly to the DTO, which risks lazy loading issues and
circular references. Modify the method to pass only the necessary fields such as
assignmentId and userId (or other required primitive fields) instead of the full
entity objects to the DTO builder, ensuring safer and cleaner data transfer.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package hello.cluebackend.domain.assignment.domain;

import hello.cluebackend.domain.user.domain.UserEntity;
import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDateTime;

@Entity
@Table(name="assignment_check")
@Getter @Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AssignmentCheck {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long assignmentCheckId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private UserEntity user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "assignment_id")
private Assignment assignment;
Comment on lines +19 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

중복 제출 체크 방지를 위한 유니크 제약조건 추가 권장

동일한 사용자가 같은 과제에 대해 여러 개의 체크 레코드를 생성할 수 있어 데이터 무결성 문제가 발생할 수 있습니다.

테이블 레벨에서 유니크 제약조건을 추가하세요:

  @Entity
- @Table(name="assignment_check")
+ @Table(name="assignment_check", 
+        uniqueConstraints = @UniqueConstraint(
+          columnNames = {"user_id", "assignment_id"}))
  @Getter @Setter
🤖 Prompt for AI Agents
In src/main/java/hello/cluebackend/domain/assignment/domain/AssignmentCheck.java
around lines 19 to 25, add a unique constraint at the table level to prevent
duplicate submissions by the same user for the same assignment. Modify the
entity's table annotation to include a unique constraint on the combination of
user_id and assignment_id columns to enforce data integrity and avoid multiple
check records for the same user-assignment pair.

🛠️ Refactor suggestion

유니크 제약 조건 추가 권장

같은 사용자가 같은 과제에 대해 중복된 체크 레코드를 가질 수 없도록 유니크 제약 조건을 추가해야 합니다.

@Entity
@Table(name="assignment_check",
+      uniqueConstraints = @UniqueConstraint(
+          name = "uk_assignment_check_user_assignment",
+          columnNames = {"user_id", "assignment_id"}
+      ))
🤖 Prompt for AI Agents
In src/main/java/hello/cluebackend/domain/assignment/domain/AssignmentCheck.java
around lines 19 to 25, add a unique constraint to the entity to prevent
duplicate check records for the same user and assignment. Modify the class-level
annotation to include a unique constraint on the combination of user_id and
assignment_id columns, ensuring that the database enforces uniqueness for these
pairs.


@Column(name="is_submitted")
private Boolean isSubmitted;
Comment on lines +27 to +28
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Boolean 필드 기본값 설정

isSubmitted 필드에 기본값을 설정하여 null 상태를 방지하세요.

  @Column(name="is_submitted")
+ @Builder.Default
- private Boolean isSubmitted;
+ private Boolean isSubmitted = false;

또는 데이터베이스 레벨에서도 기본값을 설정할 수 있습니다:

- @Column(name="is_submitted")
+ @Column(name="is_submitted", nullable = false, columnDefinition = "BOOLEAN DEFAULT FALSE")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Column(name="is_submitted")
private Boolean isSubmitted;
@Column(name="is_submitted")
@Builder.Default
private Boolean isSubmitted = false;
🤖 Prompt for AI Agents
In src/main/java/hello/cluebackend/domain/assignment/domain/AssignmentCheck.java
at lines 27-28, the Boolean field isSubmitted lacks a default value, which can
lead to null issues. Initialize isSubmitted with a default value, such as false,
directly in the field declaration or set a default value at the database column
level using the appropriate annotation or schema definition to prevent null
states.


@Column(name="submitted_at")
private LocalDateTime submittedAt;
Comment on lines +27 to +31
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

제출 상태 필드 개선 권장

isSubmitted 필드가 null일 수 있어 비즈니스 로직에서 예상치 못한 동작이 발생할 수 있습니다. 또한 제출 시간과 제출 상태 간의 일관성 검증이 필요합니다.

다음과 같이 개선하세요:

  @Column(name="is_submitted")
+  @Builder.Default
  private Boolean isSubmitted;

  @Column(name="submitted_at")
  private LocalDateTime submittedAt;
+
+  @PrePersist
+  @PreUpdate
+  private void validateSubmission() {
+    if (isSubmitted == null) {
+      isSubmitted = false;
+    }
+    if (Boolean.TRUE.equals(isSubmitted) && submittedAt == null) {
+      submittedAt = LocalDateTime.now();
+    }
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Column(name="is_submitted")
private Boolean isSubmitted;
@Column(name="submitted_at")
private LocalDateTime submittedAt;
@Column(name="is_submitted")
@Builder.Default
private Boolean isSubmitted;
@Column(name="submitted_at")
private LocalDateTime submittedAt;
@PrePersist
@PreUpdate
private void validateSubmission() {
if (isSubmitted == null) {
isSubmitted = false;
}
if (Boolean.TRUE.equals(isSubmitted) && submittedAt == null) {
submittedAt = LocalDateTime.now();
}
}
🤖 Prompt for AI Agents
In src/main/java/hello/cluebackend/domain/assignment/domain/AssignmentCheck.java
around lines 27 to 31, the isSubmitted field is a Boolean that can be null,
which may cause unexpected behavior in business logic. Change the isSubmitted
field to a primitive boolean to avoid null values, and implement validation
logic to ensure consistency between isSubmitted and submittedAt fields, such as
submittedAt being non-null only if isSubmitted is true.

🛠️ Refactor suggestion

제출 상태와 제출 시간 간의 일관성 보장 필요

isSubmittedtrue일 때 submittedAt이 반드시 설정되어야 하고, false일 때는 null이어야 합니다.

비즈니스 로직 검증을 위한 메서드를 추가하세요:

+ import jakarta.persistence.PrePersist;
+ import jakarta.persistence.PreUpdate;

  @Column(name="is_submitted")
+ @Builder.Default
  private Boolean isSubmitted;

  @Column(name="submitted_at")
  private LocalDateTime submittedAt;

+ @PrePersist
+ @PreUpdate
+ private void validateSubmissionStatus() {
+   if (Boolean.TRUE.equals(isSubmitted) && submittedAt == null) {
+     submittedAt = LocalDateTime.now();
+   } else if (Boolean.FALSE.equals(isSubmitted)) {
+     submittedAt = null;
+   }
+ }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/hello/cluebackend/domain/assignment/domain/AssignmentCheck.java
around lines 27 to 31, ensure consistency between isSubmitted and submittedAt
fields by adding a validation method. Implement a method that checks if
isSubmitted is true, then submittedAt must be non-null, and if isSubmitted is
false, submittedAt must be null. This method will enforce the business logic
consistency between submission status and submission time.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package hello.cluebackend.domain.assignment.domain;

import hello.cluebackend.domain.user.domain.UserEntity;
import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDateTime;

@Entity
@Table(name = "assignment_content")
@Getter @Setter
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

엔티티에 @Setter 사용을 재고하세요.

JPA 엔티티에 @Setter를 사용하면 캡슐화가 깨지고 불변성을 보장하기 어렵습니다. 필요한 필드에만 개별 setter 메서드를 생성하거나 빌더 패턴을 활용하는 것이 좋습니다.

-@Getter @Setter
+@Getter
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Getter @Setter
@Getter
🤖 Prompt for AI Agents
In
src/main/java/hello/cluebackend/domain/assignment/domain/AssignmentContent.java
at line 11, remove the class-level @Setter annotation to avoid breaking
encapsulation and immutability in the JPA entity. Instead, create individual
setter methods only for fields that require modification or implement a builder
pattern to manage object construction and updates safely.

@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AssignmentContent {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="assignment_content_id")
private Long assignmentContentId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="user_id")
private UserEntity user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="assignment_id")
private Assignment assignment;

@JoinColumn(name="original_file_name")
private String originalFileName;
Comment on lines +28 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

잘못된 어노테이션 사용을 수정하세요.

@JoinColumn은 외래 키 관계에 사용됩니다. 일반 컬럼에는 @Column을 사용해야 합니다.

-  @JoinColumn(name="original_file_name")
+  @Column(name="original_file_name")
   private String originalFileName;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@JoinColumn(name="original_file_name")
private String originalFileName;
@Column(name="original_file_name")
private String originalFileName;
🤖 Prompt for AI Agents
In
src/main/java/hello/cluebackend/domain/assignment/domain/AssignmentContent.java
at lines 28 to 29, the field originalFileName incorrectly uses the @JoinColumn
annotation, which is meant for foreign key relationships. Replace @JoinColumn
with @Column to properly annotate this regular column.


@Column(name="stored_file_name")
private String storedFileName;

@Column(name="file_path")
private String filePath;

@Column(name="file_size")
private int fileSize;

@Enumerated(EnumType.STRING)
@Column(name = "submit_type")
private SubmitType submitType; // 1. 랑크 , 2. 파일

@Column(name="update_date")
private LocalDateTime updateDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package hello.cluebackend.domain.assignment.domain;

public enum SubmitType {
FILE,
LINK,
IMAGE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package hello.cluebackend.domain.assignment.domain.repository;

import hello.cluebackend.domain.assignment.domain.Assignment;
import hello.cluebackend.domain.assignment.domain.AssignmentAttachment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface AssignmentAttachmentRepository extends JpaRepository<AssignmentAttachment,Long> {
List<AssignmentAttachment> findAllByAssignment(Assignment assignment);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package hello.cluebackend.domain.assignment.domain.repository;

import hello.cluebackend.domain.assignment.domain.Assignment;
import hello.cluebackend.domain.assignment.domain.AssignmentCheck;
import io.lettuce.core.dynamic.annotation.Param;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

잘못된 @param 어노테이션 import

Lettuce Redis 클라이언트의 @Param 어노테이션을 import하고 있습니다. Spring Data JPA의 @Param을 사용해야 합니다.

다음과 같이 수정하세요:

-import io.lettuce.core.dynamic.annotation.Param;
+import org.springframework.data.repository.query.Param;
🤖 Prompt for AI Agents
In
src/main/java/hello/cluebackend/domain/assignment/domain/repository/AssignmentCheckRepository.java
at line 5, the import statement incorrectly imports the @Param annotation from
io.lettuce.core.dynamic.annotation. Replace this import with the correct Spring
Data JPA @Param annotation by importing
org.springframework.data.repository.query.Param instead.

⚠️ Potential issue

잘못된 @param 어노테이션 import

Lettuce Redis 클라이언트의 @Param 대신 Spring Data JPA의 @Param을 사용해야 합니다.

- import io.lettuce.core.dynamic.annotation.Param;
+ import org.springframework.data.repository.query.Param;
🤖 Prompt for AI Agents
In
src/main/java/hello/cluebackend/domain/assignment/domain/repository/AssignmentCheckRepository.java
at line 5, the import statement uses the incorrect @Param annotation from
io.lettuce.core.dynamic.annotation.Param. Replace this import with the correct
Spring Data JPA @Param annotation by importing
org.springframework.data.repository.query.Param instead.

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface AssignmentCheckRepository extends JpaRepository<AssignmentCheck,Long> {
@Query("""
SELECT ac.assignment
FROM AssignmentCheck ac
JOIN ac.assignment a
JOIN a.classRoom cr
JOIN cr.classRoomUserList cru
WHERE ac.user.userId = :userId
AND ac.isSubmitted = false
""")
List<Assignment> findUnsubmittedAssignmentsByUserId(@Param("userId") Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package hello.cluebackend.domain.assignment.domain.repository;

import hello.cluebackend.domain.assignment.domain.AssignmentContent;
import org.springframework.data.jpa.repository.JpaRepository;

public interface AssignmentContentRepository extends JpaRepository<AssignmentContent, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package hello.cluebackend.domain.assignment.domain.repository;

import hello.cluebackend.domain.assignment.domain.Assignment;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface AssignmentRepository extends JpaRepository<Assignment, Long> {
List<Assignment> findAllByClassRoom_ClassRoomId(Long classId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package hello.cluebackend.domain.assignment.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.NOT_FOUND) // 404 Not Found 응답
public class AssignmentNotFoundException extends RuntimeException {
public AssignmentNotFoundException() {
super("해당 과제를 찾을 수 없습니다.");
}

public AssignmentNotFoundException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package hello.cluebackend.domain.assignment.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.FORBIDDEN) // 403 Forbidden 응답
public class UnauthorizedException extends RuntimeException {
public UnauthorizedException() {
super("접근 권한이 없습니다.");
}

public UnauthorizedException(String message) {
super(message);
}
}
Loading
Loading