Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
e133082
docs: 기능별 구현 목록 및 전략
seokjun-ko Feb 26, 2026
e48940c
docs: 수행해야할 기능 목록과 그에 해당하는 전략을 Readme에 추가
seokjun-ko Feb 26, 2026
64bd193
feat: claude 삭제 스킬 cleanup 추가
gspear18 Feb 26, 2026
7bc4c5b
feat: cleanup skill 업데이트
gspear18 Feb 26, 2026
5e5abe8
docs: 삭제 대상에 해당하지 않는 요소 README에서 제거
gspear18 Feb 26, 2026
8a55b86
docs: 삭제할 필요가 없는 코드, 리드미에서 제거
seokjun-ko Feb 26, 2026
1285011
refactor: @Autowired 삭제
seokjun-ko Feb 26, 2026
dfb33aa
refactor: @Autowired 삭제
gspear18 Feb 26, 2026
79fabdb
refactor: @Autowired 삭제
gspear18 Feb 26, 2026
2c8ca5e
refactor: @Autowired 삭제
seokjun-ko Feb 26, 2026
a1b68e0
refactor: OrderController에서 미사용 WishRepository 제거
seokjun-ko Feb 26, 2026
973e617
docs: import가 사용중이어서 제외
gspear18 Feb 26, 2026
89ef3a7
refactor: getOptions 안정성 강화
gspear18 Feb 26, 2026
3343766
feat: e2e 테스트 작성하는 스킬 추가
seokjun-ko Feb 26, 2026
fd77c4e
feat: 리팩토링 필요가 있는 컨트롤러를 파악하고 그렇다면 e2e 테스트를 진행하는 스킬 생성
seokjun-ko Feb 26, 2026
32ca034
feat: OrderController 테스트 코드 추가, 정상 작동
gspear18 Feb 26, 2026
706d288
test: 카테고리 컨트롤러 e2e 테스트 추가
seokjun-ko Feb 26, 2026
8f80d4a
test: MemberController 테스트 코드 추가, 정상 작동
gspear18 Mar 3, 2026
0c4880e
test: AdminMemberController e2e Test 추가
seokjun-ko Mar 3, 2026
ed82140
test: add KakaoAuthController e2e-test 추가
gspear18 Mar 3, 2026
f305ecb
Test: OptionController e2e Test 추가
seokjun-ko Mar 3, 2026
e9494e0
test: Add ProductController e2e-test
gspear18 Mar 3, 2026
b5c576f
Test: AdminProductController e2e Test 추가
seokjun-ko Mar 3, 2026
97c391c
test: add WishController e2e-test
gspear18 Mar 3, 2026
ca3b3db
test + docs: OrderControllerTest에서 Get 테스트가 없던 것 추가 / README 체크 추가
seokjun-ko Mar 3, 2026
4ddc0ea
feat: controller 경량화 스킬 추가
gspear18 Mar 3, 2026
f310585
Merge branch 'main' of github.com:seokjun-ko/spring-gift-refactoring-…
gspear18 Mar 3, 2026
7a4cfd8
feat: spilt-controller 스킬 컨트롤러 지정해서 하도록 수정
gspear18 Mar 3, 2026
62afaee
refactor: add KakaoAuthService
gspear18 Mar 3, 2026
a86d544
refactor: OrderController의 비즈니스 로직 OrderService로 분리
seokjun-ko Mar 3, 2026
45da0d7
Merge branch 'main' of https://github.com/seokjun-ko/spring-gift-refa…
seokjun-ko Mar 3, 2026
99a3263
refactor: add CategoryService.java
gspear18 Mar 3, 2026
9a6575e
Merge branch 'main' of github.com:seokjun-ko/spring-gift-refactoring-…
gspear18 Mar 3, 2026
0e31463
refactor: add CategoryService.java
gspear18 Mar 3, 2026
07ef12a
refactor: add MemberService.java
gspear18 Mar 3, 2026
f92c18f
refactor: update MemberService
gspear18 Mar 3, 2026
493880a
refactor: AdminProductController 비즈니스로직 ProductService에 이관
seokjun-ko Mar 3, 2026
e48f22b
refactor: add src/main/java/gift/option/OptionController.java
gspear18 Mar 3, 2026
e1544ba
Merge branch 'main' of https://github.com/seokjun-ko/spring-gift-refa…
seokjun-ko Mar 3, 2026
d655718
Merge branch 'main' of https://github.com/seokjun-ko/spring-gift-refa…
seokjun-ko Mar 3, 2026
f81a193
refactor: 코드 에러 수정
seokjun-ko Mar 3, 2026
8e93d9b
refactor: ProductController의 비즈니스 로직 ProductService로 분리
seokjun-ko Mar 3, 2026
43129f8
refactor: WishController의 비즈니스 로직 WishService로 분리
seokjun-ko Mar 3, 2026
3791561
feat: 코드 스타일 통일 스킬 추가
seokjun-ko Mar 3, 2026
12f1603
style: 전체 도메인 코드 스타일 통일
seokjun-ko Mar 3, 2026
a1dc82e
docs: add step1 prompt docs
gspear18 Mar 3, 2026
a6c21c2
feat(commands): add safe-change command for safe code modification wo…
seokjun-ko Mar 4, 2026
f23026c
refactor(member): MemberService에 deductPoint 메서드 추가
seokjun-ko Mar 4, 2026
401ee14
test(order): 주문 성공 시 포인트 잔액 재조회 검증 추가
seokjun-ko Mar 4, 2026
e18e4df
refactor(order): 포인트 차감을 MemberService를 통해 수행하도록 변경
seokjun-ko Mar 4, 2026
e851e39
feat(commands): safe-change 커맨드에 커밋 메시지 규칙과 실행 단계 추가
seokjun-ko Mar 4, 2026
c960b32
fix(member): 회원 이메일 수정 시 중복 검증 추가
seokjun-ko Mar 4, 2026
d0422a5
test(member): 회원 이메일 수정 시 중복 검증 테스트 추가
seokjun-ko Mar 4, 2026
7432c85
refactor(member): email 필드에 @Column(unique = true) 추가
seokjun-ko Mar 4, 2026
544b7a8
refactor(member): findByEmail, create(email), updateKakaoAccessToken …
seokjun-ko Mar 4, 2026
6036286
test(member): findByEmail, create(email), updateKakaoAccessToken 테스트 추가
seokjun-ko Mar 4, 2026
0137c8a
refactor(auth): KakaoAuthService가 MemberService를 통해 회원 접근
seokjun-ko Mar 4, 2026
49d454e
refactor(auth): AuthenticationResolver가 MemberService를 통해 회원 접근
seokjun-ko Mar 4, 2026
9f91603
test(member): 이메일만으로 생성 시 중복 이메일 검증 테스트 추가
seokjun-ko Mar 4, 2026
8f5f975
feat(member): create(email)에 중복 이메일 검사 추가
seokjun-ko Mar 4, 2026
128cb22
test(member): 회원 삭제 검증 테스트 추가
seokjun-ko Mar 5, 2026
e554fa7
feat(member): 존재하지 않는 회원 삭제 시 예외 발생 추가
seokjun-ko Mar 5, 2026
ac592bd
test(category): findEntityById 검증 테스트 추가
seokjun-ko Mar 5, 2026
22831f9
refactor(category): findEntityById 메서드 추가
seokjun-ko Mar 5, 2026
8d5105c
refactor(product): CategoryRepository 의존을 CategoryService로 교체
seokjun-ko Mar 5, 2026
8c7fc2a
feat(product): 카테고리 목록 조회 책임을 CategoryService로 이동
seokjun-ko Mar 5, 2026
2d32202
test(category): 카테고리 삭제 후 재조회 검증 추가
seokjun-ko Mar 5, 2026
1aa42b1
refactor(category): delete()를 findEntityById + delete 패턴으로 통일
seokjun-ko Mar 5, 2026
9c1f79e
test(auth): 인증 실패/성공 시나리오 통합 테스트 추가
seokjun-ko Mar 5, 2026
a4f4557
refactor(auth): UnauthorizedException과 글로벌 예외 핸들러 추가
seokjun-ko Mar 5, 2026
34bb231
refactor(auth): 인증 실패 시 null 반환 대신 UnauthorizedException 던지기
seokjun-ko Mar 5, 2026
4ddba5b
Merge branch 'seokjun-ko' into main
seokjun-ko Mar 5, 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
2 changes: 1 addition & 1 deletion src/main/java/gift/auth/AuthenticationResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public Member extractMember(String authorization) {
final String email = jwtProvider.getEmail(token);
return memberService.findByEmail(email).orElse(null);
} catch (Exception e) {
return null;
throw new UnauthorizedException("유효하지 않은 토큰입니다");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

작동 변경은 반드시 증거와 함께 제출한다.

라는 요구사항에 맞게 근거를 추가해주시면 어떨까요?

}
}
}
14 changes: 14 additions & 0 deletions src/main/java/gift/auth/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package gift.auth;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(UnauthorizedException.class)
public ResponseEntity<Void> handleUnauthorized(UnauthorizedException e) {
return ResponseEntity.status(401).build();
}
}
7 changes: 7 additions & 0 deletions src/main/java/gift/auth/UnauthorizedException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gift.auth;

public class UnauthorizedException extends RuntimeException {
public UnauthorizedException(String message) {
super(message);
}
}
75 changes: 75 additions & 0 deletions src/test/java/gift/auth/AuthenticationResolverTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package gift.auth;

import gift.member.MemberService;
import io.restassured.RestAssured;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.test.context.jdbc.Sql;

import static org.hamcrest.Matchers.notNullValue;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class AuthenticationResolverTest {

@LocalServerPort
int port;

@Autowired
JwtProvider jwtProvider;

@Autowired
MemberService memberService;

@BeforeEach
void setUp() {
RestAssured.port = port;
}

@Test
@Sql(scripts = "/data/truncate.sql",
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
void 잘못된_토큰으로_요청하면_401() {
RestAssured
.given()
.header("Authorization", "Bearer invalid-token")
.when()
.get("/api/wishes")
.then()
.statusCode(401);
}

@Test
@Sql(scripts = "/data/truncate.sql",
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
void 유효한_토큰이지만_회원이_없으면_401() {
String token = jwtProvider.createToken("nonexistent@example.com");

RestAssured
.given()
.header("Authorization", "Bearer " + token)
.when()
.get("/api/wishes")
.then()
.statusCode(401);
}

@Test
@Sql(scripts = "/data/truncate.sql",
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
void 유효한_토큰과_회원이_존재하면_200() {
memberService.create("valid@example.com");
String token = jwtProvider.createToken("valid@example.com");

RestAssured
.given()
.header("Authorization", "Bearer " + token)
.when()
.get("/api/wishes")
.then()
.statusCode(200)
.body(notNullValue());
}
}
40 changes: 40 additions & 0 deletions src/test/java/gift/category/CategoryServiceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package gift.category;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;

import java.util.NoSuchElementException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

@SpringBootTest
class CategoryServiceTest {

@Autowired
CategoryService categoryService;

@Test
@Sql(scripts = {"/data/truncate.sql", "/data/seed/find_category_by_id.sql"},
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
void 존재하는_ID로_엔티티를_조회하면_카테고리를_반환한다() {
Category category = categoryService.findEntityById(1L);

assertThat(category.getId()).isEqualTo(1L);
assertThat(category.getName()).isEqualTo("전자기기");
assertThat(category.getColor()).isEqualTo("#1E90FF");
assertThat(category.getImageUrl()).isEqualTo("https://example.com/images/electronics.jpg");
assertThat(category.getDescription()).isEqualTo("전자기기 카테고리");
}

@Test
@Sql(scripts = {"/data/truncate.sql"},
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
void 존재하지_않는_ID로_엔티티를_조회하면_예외가_발생하고_메시지에_ID가_포함된다() {
assertThatThrownBy(() -> categoryService.findEntityById(999L))
.isInstanceOf(NoSuchElementException.class)
.hasMessageContaining("999");
}
}
3 changes: 3 additions & 0 deletions src/test/resources/data/seed/delete_member_success.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- seed for: delete_member_success
INSERT INTO member (id, email, password, point)
VALUES (1, 'delete-target@example.com', 'password123', 0);
2 changes: 2 additions & 0 deletions src/test/resources/data/seed/find_category_by_id.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INSERT INTO category (id, name, color, image_url, description)
VALUES (1, '전자기기', '#1E90FF', 'https://example.com/images/electronics.jpg', '전자기기 카테고리');