Skip to content

Commit 0eace39

Browse files
authored
Merge branch 'main' into feat/#11
2 parents a8e440d + 63aad11 commit 0eace39

24 files changed

+601
-22
lines changed

.github/labels.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,12 @@
2020

2121
- name: chore
2222
color: "3498DB"
23-
description: "빌드 업무 수정, 패키지 매니저 수정(ex .gitignore 수정 같은 경우)"
23+
description: "빌드 업무 수정, 패키지 매니저 수정(ex .gitignore 수정 같은 경우)"
24+
25+
- name: infra
26+
color: "F39C12"
27+
description: "AWS‧CI/CD‧Terraform 등 인프라·DevOps 작업"
28+
29+
- name: perf
30+
color: "1ABC9C"
31+
description: "성능 최적화(쿼리·캐시·로딩 속도 개선 등)"

.vscode/launch.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
{
22
"configurations": [
3+
{
4+
"type": "java",
5+
"name": "treaxureApplication",
6+
"request": "launch",
7+
"mainClass": "com.trip.treaxure.treaxureApplication",
8+
"projectName": ""
9+
},
310
{
411
"type": "java",
512
"name": "treaxureApplication",

.vscode/settings.json

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"C_Cpp_Runner.cCompilerPath": "gcc",
3+
"C_Cpp_Runner.cppCompilerPath": "g++",
4+
"C_Cpp_Runner.debuggerPath": "gdb",
5+
"C_Cpp_Runner.cStandard": "",
6+
"C_Cpp_Runner.cppStandard": "",
7+
"C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat",
8+
"C_Cpp_Runner.useMsvc": false,
9+
"C_Cpp_Runner.warnings": [
10+
"-Wall",
11+
"-Wextra",
12+
"-Wpedantic",
13+
"-Wshadow",
14+
"-Wformat=2",
15+
"-Wcast-align",
16+
"-Wconversion",
17+
"-Wsign-conversion",
18+
"-Wnull-dereference"
19+
],
20+
"C_Cpp_Runner.msvcWarnings": [
21+
"/W4",
22+
"/permissive-",
23+
"/w14242",
24+
"/w14287",
25+
"/w14296",
26+
"/w14311",
27+
"/w14826",
28+
"/w44062",
29+
"/w44242",
30+
"/w14905",
31+
"/w14906",
32+
"/w14263",
33+
"/w44265",
34+
"/w14928"
35+
],
36+
"C_Cpp_Runner.enableWarnings": true,
37+
"C_Cpp_Runner.warningsAsError": false,
38+
"C_Cpp_Runner.compilerArgs": [],
39+
"C_Cpp_Runner.linkerArgs": [],
40+
"C_Cpp_Runner.includePaths": [],
41+
"C_Cpp_Runner.includeSearch": [
42+
"*",
43+
"**/*"
44+
],
45+
"C_Cpp_Runner.excludeSearch": [
46+
"**/build",
47+
"**/build/**",
48+
"**/.*",
49+
"**/.*/**",
50+
"**/.vscode",
51+
"**/.vscode/**"
52+
],
53+
"C_Cpp_Runner.useAddressSanitizer": false,
54+
"C_Cpp_Runner.useUndefinedSanitizer": false,
55+
"C_Cpp_Runner.useLeakSanitizer": false,
56+
"C_Cpp_Runner.showCompilationTime": false,
57+
"C_Cpp_Runner.useLinkTimeOptimization": false,
58+
"C_Cpp_Runner.msvcSecureNoWarnings": false
59+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.trip.treaxure.common;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
9+
@Data
10+
@Builder
11+
@NoArgsConstructor
12+
@AllArgsConstructor
13+
@Schema(description = "API 표준 응답 형식")
14+
public class ApiResponse<T> {
15+
16+
@Schema(description = "응답 코드", example = "SU")
17+
private String code;
18+
19+
@Schema(description = "응답 메시지", example = "Success")
20+
private String message;
21+
22+
@Schema(description = "응답 데이터")
23+
private T data;
24+
25+
public static <T> ApiResponse<T> success(T data) {
26+
return ApiResponse.<T>builder()
27+
.code("SU")
28+
.message("Success")
29+
.data(data)
30+
.build();
31+
}
32+
33+
public static <T> ApiResponse<T> success(String message, T data) {
34+
return ApiResponse.<T>builder()
35+
.code("SU")
36+
.message(message)
37+
.data(data)
38+
.build();
39+
}
40+
41+
public static ApiResponse<?> success(String message) {
42+
return ApiResponse.builder()
43+
.code("SU")
44+
.message(message)
45+
.build();
46+
}
47+
48+
public static ApiResponse<?> error(String code, String message) {
49+
return ApiResponse.builder()
50+
.code(code)
51+
.message(message)
52+
.build();
53+
}
54+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.trip.treaxure.common;
2+
3+
import com.trip.treaxure.common.exception.ResourceNotFoundException;
4+
import io.swagger.v3.oas.annotations.Hidden;
5+
import lombok.extern.slf4j.Slf4j;
6+
import org.springframework.http.HttpStatus;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.security.access.AccessDeniedException;
9+
import org.springframework.security.core.AuthenticationException;
10+
import org.springframework.web.bind.annotation.ExceptionHandler;
11+
import org.springframework.web.bind.annotation.RestController;
12+
import org.springframework.web.bind.annotation.RestControllerAdvice;
13+
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
14+
15+
@Slf4j
16+
@Hidden
17+
@RestControllerAdvice(annotations = {RestController.class}, basePackages = {"com.trip.treaxure.*.controller"})
18+
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
19+
20+
@ExceptionHandler(ResourceNotFoundException.class)
21+
public ResponseEntity<ApiResponse<?>> handleResourceNotFoundException(ResourceNotFoundException ex) {
22+
return ResponseEntity
23+
.status(HttpStatus.NOT_FOUND)
24+
.body(ApiResponse.error("NF", ex.getMessage()));
25+
}
26+
27+
@ExceptionHandler(AuthenticationException.class)
28+
public ResponseEntity<ApiResponse<?>> handleAuthenticationException(AuthenticationException ex) {
29+
return ResponseEntity
30+
.status(HttpStatus.UNAUTHORIZED)
31+
.body(ApiResponse.error("UN", "Unauthorized."));
32+
}
33+
34+
@ExceptionHandler(AccessDeniedException.class)
35+
public ResponseEntity<ApiResponse<?>> handleAccessDeniedException(AccessDeniedException ex) {
36+
return ResponseEntity
37+
.status(HttpStatus.FORBIDDEN)
38+
.body(ApiResponse.error("FD", "Access denied."));
39+
}
40+
41+
@ExceptionHandler(Exception.class)
42+
public ResponseEntity<ApiResponse<?>> handleGlobalException(Exception ex) {
43+
return ResponseEntity
44+
.status(HttpStatus.INTERNAL_SERVER_ERROR)
45+
.body(ApiResponse.error("SE", "Server error."));
46+
}
47+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.trip.treaxure.common.exception;
2+
3+
public class ResourceNotFoundException extends RuntimeException {
4+
5+
public ResourceNotFoundException(String message) {
6+
super(message);
7+
}
8+
9+
public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) {
10+
super(String.format("%s not found with %s: '%s'", resourceName, fieldName, fieldValue));
11+
}
12+
}

src/main/java/com/trip/treaxure/config/SecurityConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
3232
http
3333
.csrf(csrf -> csrf.disable())
3434
.authorizeHttpRequests(auth -> auth
35+
.requestMatchers("/api/members/me**")
36+
.authenticated()
3537
.requestMatchers(
3638
"/", "/swagger-ui/**", "/v3/api-docs/**", "/h2-console/**", "/api/auth/**"
3739
).permitAll()

src/main/java/com/trip/treaxure/member/controller/MemberController.java

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public class MemberController {
3030

3131
private final MemberService memberService;
3232

33+
// Todo: Member 관련 확인 필요
34+
3335
@Operation(summary = "모든 회원 조회")
3436
@GetMapping
3537
public List<MemberResponseDto> getAllMembers() {
@@ -56,8 +58,64 @@ public ResponseEntity<ApiResponseDto<MemberResponseDto>> createMember(@RequestBo
5658

5759
@Operation(summary = "회원 삭제")
5860
@DeleteMapping("/{id}")
61+
@Operation(summary = "회원 삭제", description = "특정 회원을 삭제합니다 (관리자 전용)")
5962
public ResponseEntity<Void> deleteMember(@PathVariable Long id) {
6063
memberService.deleteMember(id);
6164
return ResponseEntity.noContent().build();
6265
}
63-
}
66+
67+
// Todo: Board 관련 확인 필요
68+
69+
@GetMapping("/me/boards")
70+
@Operation(
71+
summary = "내 게시글 목록 조회",
72+
description = "현재 로그인한 회원이 작성한 게시글 목록을 조회합니다"
73+
)
74+
@ApiResponses({
75+
@io.swagger.v3.oas.annotations.responses.ApiResponse(
76+
responseCode = "200",
77+
description = "조회 성공",
78+
content = @Content(schema = @Schema(implementation = BoardListResponse.class))
79+
),
80+
@io.swagger.v3.oas.annotations.responses.ApiResponse(
81+
responseCode = "401",
82+
description = "인증 실패",
83+
content = @Content(schema = @Schema(implementation = com.trip.treaxure.common.ApiResponse.class))
84+
)
85+
})
86+
public ResponseEntity<BoardListResponse> getMyBoards(
87+
@AuthenticationPrincipal UserDetails userDetails) {
88+
BoardListResponse response = memberService.getMyBoards(userDetails);
89+
return ResponseEntity.ok(response);
90+
}
91+
92+
@GetMapping("/me/boards/{boardId}")
93+
@Operation(
94+
summary = "내 게시글 상세 조회",
95+
description = "현재 로그인한 회원이, 작성한 특정 게시글의 상세 정보를 조회합니다"
96+
)
97+
@ApiResponses({
98+
@io.swagger.v3.oas.annotations.responses.ApiResponse(
99+
responseCode = "200",
100+
description = "조회 성공",
101+
content = @Content(schema = @Schema(implementation = BoardDetailResponse.class))
102+
),
103+
@io.swagger.v3.oas.annotations.responses.ApiResponse(
104+
responseCode = "401",
105+
description = "인증 실패",
106+
content = @Content(schema = @Schema(implementation = com.trip.treaxure.common.ApiResponse.class))
107+
),
108+
@io.swagger.v3.oas.annotations.responses.ApiResponse(
109+
responseCode = "404",
110+
description = "게시글을 찾을 수 없음",
111+
content = @Content(schema = @Schema(implementation = com.trip.treaxure.common.ApiResponse.class))
112+
)
113+
})
114+
public ResponseEntity<BoardDetailResponse> getMyBoardDetail(
115+
@AuthenticationPrincipal UserDetails userDetails,
116+
@Parameter(description = "조회할 게시글 ID", required = true)
117+
@PathVariable Integer boardId) {
118+
BoardDetailResponse response = memberService.getMyBoardDetail(userDetails, boardId);
119+
return ResponseEntity.ok(response);
120+
}
121+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.trip.treaxure.member.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
9+
import java.time.LocalDateTime;
10+
11+
@Data
12+
@Builder
13+
@NoArgsConstructor
14+
@AllArgsConstructor
15+
@Schema(description = "게시글 상세 정보 응답 DTO")
16+
public class BoardDetailResponse {
17+
18+
@Schema(description = "사진 ID", example = "301")
19+
private Integer photoId;
20+
21+
@Schema(description = "미션 ID", example = "101")
22+
private Integer missionId;
23+
24+
@Schema(description = "이미지 URL", example = "https://cdn.example.com/photos/301.jpg")
25+
private String imageUrl;
26+
27+
@Schema(description = "유사도 점수", example = "0.87")
28+
private Double similarityScore;
29+
30+
@Schema(description = "상태", example = "SELECTED")
31+
private String status;
32+
33+
@Schema(description = "업로드 시간", example = "2025-05-07T14:45:00")
34+
private LocalDateTime uploadedAt;
35+
36+
@Schema(description = "획득 점수", example = "20")
37+
private Integer scoreAwarded;
38+
39+
@Schema(description = "평가 시간", example = "2025-05-08T10:00:00")
40+
private LocalDateTime evaluatedAt;
41+
42+
@Schema(description = "피드백", example = "우수한 사진입니다!")
43+
private String feedback;
44+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.trip.treaxure.member.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
9+
import java.time.LocalDateTime;
10+
import java.util.List;
11+
12+
@Data
13+
@Builder
14+
@NoArgsConstructor
15+
@AllArgsConstructor
16+
@Schema(description = "회원이 작성한 게시글 목록 응답 DTO")
17+
public class BoardListResponse {
18+
19+
@Schema(description = "사진 목록")
20+
private List<PhotoDto> photos;
21+
22+
@Data
23+
@Builder
24+
@NoArgsConstructor
25+
@AllArgsConstructor
26+
@Schema(description = "사진 정보 DTO")
27+
public static class PhotoDto {
28+
29+
@Schema(description = "사진 ID", example = "301")
30+
private Integer photoId;
31+
32+
@Schema(description = "미션 ID", example = "101")
33+
private Integer missionId;
34+
35+
@Schema(description = "이미지 URL", example = "https://cdn.example.com/photos/301.jpg")
36+
private String imageUrl;
37+
38+
@Schema(description = "유사도 점수", example = "0.87")
39+
private Double similarityScore;
40+
41+
@Schema(description = "상태", example = "SELECTED")
42+
private String status;
43+
44+
@Schema(description = "업로드 시간", example = "2025-05-07T14:45:00")
45+
private LocalDateTime uploadedAt;
46+
}
47+
}

0 commit comments

Comments
 (0)