Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
3fa1a94
feat: 정적 리소스 추가(심화)
JunSuHwang Feb 13, 2026
c1ffd5c
feat: 프로필 이미지를 MultipartFile로 받는 기능 추가 & 엔티티 수정
JunSuHwang Feb 19, 2026
7b4a190
feat: /api context path 추가
JunSuHwang Feb 20, 2026
4722a11
revert: api context path 취소
JunSuHwang Feb 20, 2026
579151b
refactor: Google Java Style Guide 적용
JunSuHwang Feb 20, 2026
3ea1f0c
feat: /api url prefix 추가
JunSuHwang Feb 20, 2026
c1efce2
feat: api 명세에 맞게 api 추가 및 1차 수정
JunSuHwang Feb 20, 2026
ed011de
feat: swagger info 및 Tag 추가
JunSuHwang Feb 20, 2026
1fb211a
fix: spring boot 버전 수정
JunSuHwang Feb 20, 2026
f9cf827
refactor: 문서에 맞게 엔티티 및 필드 수정
JunSuHwang Feb 22, 2026
57ca135
refactor: 문서에 맞게 dto 수정 및 추가
JunSuHwang Feb 22, 2026
4788e96
feat: 메세지 생성 시 파일 첨부 기능 추가
JunSuHwang Feb 22, 2026
99479d8
refactor: updateInfo를 updateRequest로 수정
JunSuHwang Feb 23, 2026
b5a4934
feat: swagger 적용 및 dto 필드이름 변경
JunSuHwang Feb 24, 2026
e07015b
refactor: 문서에 맞게 dto 형식 수정
JunSuHwang Feb 24, 2026
c56c7e8
refactor: 문서에 맞게 응답 코드 개선
JunSuHwang Feb 24, 2026
a4a81a1
feat: 정적 리소스, 프론트엔드 통합(심화)
JunSuHwang Feb 24, 2026
60ee132
refactor: mapper 메서드 이름 수정, import 최적화
JunSuHwang Feb 24, 2026
73c3028
fix: 유저 생성시 프로필 이미지 NPE 발생 수정
JunSuHwang Feb 24, 2026
b678a4c
build: railway 배포를 위한 plain.jar 생성 방지 추가
JunSuHwang Feb 24, 2026
bab7596
feat: DB 세팅 추가
JunSuHwang Mar 4, 2026
e24d8f7
fix: ReadStatus 생성 시 id가 바뀌어 생성되는 버그 수정
JunSuHwang Mar 4, 2026
d0e6a1f
fix: MessageController의 첨부파일 예외 수정
JunSuHwang Mar 4, 2026
bf1236d
fix: 중복 검증에 null 체크 로직 추가
JunSuHwang Mar 4, 2026
ef2bb49
refactor: @RequestMapping을 단축 어노테이션으로 개선
JunSuHwang Mar 4, 2026
0cc6c46
feat: 테이블 스키마 파일 추가
JunSuHwang Mar 4, 2026
3e164f4
refactor: BaseEntity, BaseUpdatableEntity 구조로 변경
JunSuHwang Mar 4, 2026
7d0cbe5
refactor: 생성, 수정시간을 어노테이션 방식으로 변경
JunSuHwang Mar 4, 2026
765b44b
feat: Base 엔티티에 Jpa 적용
JunSuHwang Mar 4, 2026
f018a2d
feat: schema.sql에 channel type not null 누락 추가
JunSuHwang Mar 4, 2026
065d229
feat: entity에 테이블 매핑 적용
JunSuHwang Mar 4, 2026
a99e62d
refactor: BinaryContent에서 Serializable 제거 누락 수정
JunSuHwang Mar 5, 2026
3b92087
feat: entity에 영속성 전이, orphanRemoval 적용
JunSuHwang Mar 5, 2026
37acc04
feat: repository에 JpaRepository 적용
JunSuHwang Mar 5, 2026
f101c14
refactor: JpaRepository 적용에 따른 서비스, 컨트롤러 등 수정
JunSuHwang Mar 5, 2026
81651df
refactor: 트랜잭션 적용, 변경 감지 반영한 update 수정
JunSuHwang Mar 6, 2026
9b75c0f
refactor: 기존 mapper에 mapstruct 적용 & 적용에 따른 코드 수정
JunSuHwang Mar 6, 2026
949e3c3
refactor: service의 파라미터 이름 일관성 있게 개선
JunSuHwang Mar 6, 2026
b9f0b7a
refactor: message_attachments unique 추가, file_name으로 컬럼 수정
JunSuHwang Mar 6, 2026
7e90bcf
refactor: ChannelDto 작업을 mapper에서 하도록 변경
JunSuHwang Mar 6, 2026
16a27e7
fix: lastMessageAt이 오래된 메세지 시간을 반환했던 오류 수정
JunSuHwang Mar 6, 2026
3cdd775
feat: 파일 스토리지 로컬 저장 방식 구현 (#1)
JunSuHwang Mar 9, 2026
9329273
feat: message 목록 조회에 Pagination 적용 (#2)
JunSuHwang Mar 10, 2026
2cf5ece
feat: 호환 정적 리소스로 교체
JunSuHwang Mar 10, 2026
8961066
fix: ReadStatus 생성 시 request의 lastReadAt을 사용하도록 수정 (#3)
JunSuHwang Mar 10, 2026
5821db4
refactor: 불필요한 join, leave 메서드 제거 (#4)
JunSuHwang Mar 10, 2026
ea2c641
fix: MessageDto의 attachments 요소가 dto 형식으로 변환되도록 수정 (#5)
JunSuHwang Mar 10, 2026
0740d49
refactor: cursor pagination (#6)
JunSuHwang Mar 11, 2026
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
8 changes: 6 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@

## 요구사항

### 기본

- [x] 기본 항목 1
- [ ] 기본 항목 2

### 심화

- [ ] 심화 항목 1
- [ ] 심화 항목 2

## 주요 변경사항
-
-

-

## 스크린샷

![image](이미지url)

## 멘토에게

- 셀프 코드 리뷰를 통해 질문 이어가겠습니다.
-
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ bin/

### Mac OS ###
.DS_Store
/data/**
43 changes: 26 additions & 17 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,37 +1,46 @@
plugins {
id 'java'
id 'org.springframework.boot' version '4.0.2'
id 'io.spring.dependency-management' version '1.1.7'
id 'java'
id 'org.springframework.boot' version '3.4.0'
id 'io.spring.dependency-management' version '1.1.6'
}

group = 'com.sprint.mission'
version = '0.0.1-SNAPSHOT'
description = 'Sprint Mission 3'
description = 'Sprint Mission 6'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.14'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.postgresql:postgresql:42.7.3'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation 'org.mapstruct:mapstruct:1.6.3'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.6.3'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}

jar {
enabled = false
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
@SpringBootApplication
public class DiscodeitApplication {

public static void main(String[] args) {
SpringApplication.run(DiscodeitApplication.class, args);
}
public static void main(String[] args) {
SpringApplication.run(DiscodeitApplication.class, args);
}
}
49 changes: 49 additions & 0 deletions src/main/java/com/sprint/mission/discodeit/base/BaseEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.sprint.mission.discodeit.base;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import java.time.Instant;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
protected UUID id;

@CreatedDate
@Column(nullable = false, updatable = false)
protected Instant createdAt;

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
return id.equals(((BaseEntity) obj).id);
}

@Override
public int hashCode() {
return id.hashCode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.sprint.mission.discodeit.base;

import jakarta.persistence.MappedSuperclass;
import java.time.Instant;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.LastModifiedDate;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@MappedSuperclass
public abstract class BaseUpdatableEntity extends BaseEntity {

@LastModifiedDate
protected Instant updatedAt;

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
return id.equals(((BaseUpdatableEntity) obj).id);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,30 +1,98 @@
package com.sprint.mission.discodeit.binarycontent.controller;

import com.sprint.mission.discodeit.binarycontent.dto.BinaryContentInfo;
import com.sprint.mission.discodeit.binarycontent.dto.BinaryContentDto;
import com.sprint.mission.discodeit.binarycontent.dto.BinaryContentsRequest;
import com.sprint.mission.discodeit.binarycontent.service.BinaryContentService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import com.sprint.mission.discodeit.storage.BinaryContentStorage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
@RequestMapping("/binarycontents")
@RequestMapping("/api/binaryContents")
@Tag(name = "BinaryContent", description = "첨부 파일 API")
public class BinaryContentController {
private final BinaryContentService binaryContentService;

@RequestMapping(value = "/{contentId}", method = RequestMethod.GET)
public ResponseEntity<BinaryContentInfo> getBinaryContent(@PathVariable UUID contentId) {
return ResponseEntity.ok(binaryContentService.findBinaryContent(contentId));
}
private final BinaryContentService binaryContentService;
private final BinaryContentStorage storage;

@Operation(summary = "첨부 파일 조회")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200", description = "첨부 파일 조회 성공",
content = @Content(
mediaType = MediaType.ALL_VALUE,
schema = @Schema(implementation = BinaryContentDto.class)
)
),
@ApiResponse(
responseCode = "404", description = "첨부 파일을 찾을 수 없음",
content = @Content(
mediaType = MediaType.ALL_VALUE,
examples = @ExampleObject("BinaryContent with id {binaryContentId} not found")
)
)
})
@GetMapping(value = "/{binaryContentId}")
public ResponseEntity<BinaryContentDto> find(
@Parameter(description = "조회할 첨부 파일 ID") @PathVariable UUID binaryContentId
) {
return ResponseEntity.ok(binaryContentService.findBinaryContent(binaryContentId));
}

@Operation(summary = "여러 첨부 파일 조회")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200", description = "첨부 파일 목록 조회 성공",
content = @Content(
mediaType = MediaType.ALL_VALUE,
array = @ArraySchema(schema = @Schema(implementation = BinaryContentDto.class))
)
)
})
@GetMapping
public ResponseEntity<List<BinaryContentDto>> findAllByIdIn(
@Parameter(description = "조회할 첨부 파일 ID 목록",
array = @ArraySchema(schema = @Schema(implementation = UUID.class))
)
@RequestParam List<UUID> binaryContentIds
) {
BinaryContentsRequest request = new BinaryContentsRequest(binaryContentIds);
return ResponseEntity.ok(binaryContentService.findAllByIdIn(request));
}

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<List<BinaryContentInfo>> getBinaryContents(
@RequestBody BinaryContentsRequest request
) {
return ResponseEntity.ok(binaryContentService.findAllByIdIn(request));
}
@Operation(summary = "파일 다운로드")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200", description = "파일 다운로드 성공",
content = @Content(
mediaType = MediaType.ALL_VALUE,
schema = @Schema(type = "string", format = "binary")
)
)
})
@GetMapping("/{binaryContentId}/download")
public ResponseEntity<?> download(
@Parameter(description = "다운로드할 파일 ID", required = true) @PathVariable UUID binaryContentId
) {
BinaryContentDto binaryContent = binaryContentService.findBinaryContent(binaryContentId);
return storage.download(binaryContent);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.sprint.mission.discodeit.binarycontent.dto;

public record BinaryContentCreateRequest(
String fileName,
String contentType,
byte[] bytes
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.sprint.mission.discodeit.binarycontent.dto;

import java.util.UUID;

public record BinaryContentDto(
UUID id,
String fileName,
Long size,
String contentType
) {

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
import java.util.UUID;

public record BinaryContentsRequest(
List<UUID> contentIds
) {}
List<UUID> ids
) {

}
Loading