Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
db19123
chore: 초기 세팅 설정
htdufhc-bit Jun 29, 2026
b6ba2cb
refactor: 공통 예외 처리 구조 도입
htdufhc-bit Jun 29, 2026
5e7b687
feat: 로그인 및 인증 정보 조회 (1 & 2단계)
htdufhc-bit Jun 29, 2026
ec6ee6d
feat: 인증 정보 기반 예약 생성 (1 & 2단계)
htdufhc-bit Jun 29, 2026
b17debb
test: 1, 2단계 테스트 추가
htdufhc-bit Jun 29, 2026
6e1c475
chore: 미사용 import 제거 및 코드 포맷 정리
htdufhc-bit Jun 29, 2026
ba98c27
refactor: 로그아웃 기능을 auth 도메인으로 이동
htdufhc-bit Jun 29, 2026
2b95ab2
feat: 회원 예외 처리를 위한 MemberErrorCode 추가 및 적용
htdufhc-bit Jun 29, 2026
1c8cfde
fix: SQL 문법 오류 해결
htdufhc-bit Jun 29, 2026
ab7f70c
docs: README.md 추가
htdufhc-bit Jun 29, 2026
eae5e9a
refactor: 예외 로깅 방식을 printStackTrace에서 Logger로 변경
htdufhc-bit Jul 2, 2026
bf6ac7b
refactor: MalformedJwtException UnsupportedJwtException 예외 처리 추가
htdufhc-bit Jul 2, 2026
fd847c1
feat: 인증 필요를 가리키는 커스텀 어노테이션 추가
htdufhc-bit Jul 2, 2026
8acaa21
refactor: bean validation을 통해 검증하도록 수정
htdufhc-bit Jul 2, 2026
787f1a6
refactor: CookieUtil의 책임 분리
htdufhc-bit Jul 2, 2026
6d4cc45
fix: 파일 끝에 개행 문자 추가
htdufhc-bit Jul 2, 2026
219413c
refactor: 사용하지 않는 import문 제거
htdufhc-bit Jul 2, 2026
5d94f7e
refactor: 예약자 name 검증을 DTO에서 service로 이동
htdufhc-bit Jul 2, 2026
7daa481
refactor: 도메인별 패키지를 계층 구조로 재구성
htdufhc-bit Jul 3, 2026
1e3fdb3
refactor: 도메인별 패키지를 계층 구조로 추가 재구성
htdufhc-bit Jul 6, 2026
aac8aa3
refactor: Member 권한(Role)을 String에서 enum으로 변경
htdufhc-bit Jul 6, 2026
4093c0b
feat: 권한 검증을 위한 인가 Interceptor 추가
htdufhc-bit Jul 6, 2026
557971d
test: 3단계 테스트 추가
htdufhc-bit Jul 6, 2026
1d58693
test: import문 재정렬
htdufhc-bit Jul 6, 2026
7c289c3
Merge remote-tracking branch 'upstream/htdufhc-bit' into roomescape-M…
htdufhc-bit Jul 6, 2026
a5fa426
style: 불필요한 개행 문자 제거
htdufhc-bit Jul 6, 2026
50a30f4
refactor: JwtTokenProvider에 name/role 추출 기능 추가 및 파싱 로직 통합
htdufhc-bit Jul 6, 2026
31bb114
refactor: LoginMember에서 email 필드 제거, JWT 기반으로 인증 정보 생성
htdufhc-bit Jul 6, 2026
4975da3
docs: README에 패키지 구조 개편과 관리자 권한 기능 반영
htdufhc-bit Jul 7, 2026
5bc54ca
fix: 회원 저장 시 Role이 ADMIN으로 고정되는 문제 수정
htdufhc-bit Jul 8, 2026
6eb6095
refactor: 로그인 실패 시 EmptyResultDataAccessException 대신 401 응답 반환
htdufhc-bit Jul 8, 2026
b400cf2
refactor: 토큰 추출 공통 로직을 TokenExtractor로 분리
htdufhc-bit Jul 8, 2026
753f82a
feat: refresh token 발급·저장 환경 추가
htdufhc-bit Jul 9, 2026
dded032
refactor: CookieUtil을 access/refresh 쿠키 지원 구조로 개선
htdufhc-bit Jul 9, 2026
5e0c8a7
feat: refresh token 기반 재발급 구현
htdufhc-bit Jul 9, 2026
ccb028c
test: createToken 메서드가 access token을 추출하도록 수정
htdufhc-bit Jul 9, 2026
e1b65c3
build: Spring Data JPA 도입
htdufhc-bit Jul 12, 2026
ce5ad9a
refactor: DAO를 JPA Repository로 전환하고 엔티티/DTO 재구성
htdufhc-bit Jul 12, 2026
0a3086e
fix: 쿠키 만료 시 path 불일치 문제 해결
htdufhc-bit Jul 12, 2026
0a7c180
refactor: refresh token을 EntityManager 기반 JPA로 전환
htdufhc-bit Jul 12, 2026
da760e9
refactor: 서비스 메서드에 Transactional 어노테이션 적용
htdufhc-bit Jul 12, 2026
b325fc5
refactor: 토큰 쿠키 설정 로직을 setTokenCookies 메서드로 추출
htdufhc-bit Jul 12, 2026
3c1f8f2
fix: 쓰기 메서드에 Transactional 어노테이션 추가
htdufhc-bit Jul 12, 2026
4108114
refactor: 엔티티의 사용되지 않는 생성자 삭제
htdufhc-bit Jul 12, 2026
f7b7531
refactor: RefreshTokenEntity.java를 RefreshToken.java로 수정
htdufhc-bit Jul 12, 2026
f16fde7
docs: README.md 업데이트
htdufhc-bit Jul 13, 2026
084d3eb
fix: 존재하지 않는 id 삭제 시 예외가 발생하는 문제 해결
htdufhc-bit Jul 13, 2026
4b53082
fix: 오타 수정 (예약` -> 예약)
htdufhc-bit Jul 13, 2026
1902301
Merge branch 'htdufhc-bit' into roomescape-JPA
htdufhc-bit Jul 14, 2026
6813feb
fix: spring.jpa.ddl-auto 오타 수정
htdufhc-bit Jul 15, 2026
fb8ea71
fix: ThemeService.create()에 @Transactional 추가
htdufhc-bit Jul 15, 2026
72a68ca
fix: refresh token 재발급 시 delete-save 쿼리 순서 문제 수정
htdufhc-bit Jul 15, 2026
0a710ce
fix: findAllByMemberId 메서드의 파라미터 오타 수정
htdufhc-bit Jul 15, 2026
5a080cf
chore: schema.sql 파일 끝 개행 추가
htdufhc-bit Jul 15, 2026
85ad22d
chore: JdbcTemplate 시절 잔여 파일 재삭제
htdufhc-bit Jul 15, 2026
363a773
fix: N+1 문제 해결 - Reservation 관련하여 LAZY 로딩 명시 및 fetch join 적용
htdufhc-bit Jul 15, 2026
436ecde
fix: RefreshToken 관련하여 LAZY 로딩 명시
htdufhc-bit Jul 15, 2026
8d117f1
refactor: EntityManager 기반 Repository를 JpaRepository로 전환
htdufhc-bit Jul 18, 2026
dc5b5e7
feat: 예약 대기열 구현
htdufhc-bit Jul 18, 2026
621f6a1
feat: Time과 Theme에 soft delete 적용
htdufhc-bit Jul 20, 2026
f81cc37
refactor: 불필요한 member의 JOIN FETCH 제거
htdufhc-bit Jul 20, 2026
322d8c1
refactor: 사용하지 않는 필드 제거
htdufhc-bit Jul 20, 2026
fa7cd36
refactor: 필드에 final 붙이도록 수정
htdufhc-bit Jul 20, 2026
787091a
test: 변경된 요구사항에 따라 기존 테스트 수정
htdufhc-bit Jul 20, 2026
2343bc4
test: 변경된 요구사항에 따른 test 추가
htdufhc-bit Jul 20, 2026
e1fac12
test: 인증과 예약 api에 대한 test 추가
htdufhc-bit Jul 20, 2026
c3bda17
Merge branch 'htdufhc-bit' into roomescape-JPA
htdufhc-bit Jul 20, 2026
6402408
refactor: 사용하지 않는 repository 제거
htdufhc-bit Jul 20, 2026
eaec41b
refactor: soft delete로 제거된 경우를 제외하고 findAll하도록 수정
htdufhc-bit Jul 20, 2026
63bc184
refactor: repository 필드를 final로 설정
htdufhc-bit Jul 20, 2026
6eaf8f3
refactor: resolveMember 메서드명을 getTargetMember로 변경하여 역할 명확화
htdufhc-bit Jul 21, 2026
ca1f694
refactor: 회원 삭제 시 연관 예약 자동 삭제를 위한 `@OnDelete` 추가
htdufhc-bit Jul 21, 2026
6e99544
refactor: config, exception, util을 global 패키지로 이동
htdufhc-bit Jul 21, 2026
f2fd69f
refactor: BaseSoftDeleteEntity를 도입해 Theme/Time의 소프트 삭제 공통화
htdufhc-bit Jul 21, 2026
4ff2550
refactor: 불필요한 import문 제거
htdufhc-bit Jul 21, 2026
795d0ad
refactor: 모든 dto를 record로 변경
htdufhc-bit Jul 21, 2026
d1da150
refactor: 객체 생성 및 DTO 변환 방식을 정적 팩토리 메서드와 record 접근자로 통일
htdufhc-bit Jul 21, 2026
1e36599
test: API 테스트를 api 패키지로 이동
htdufhc-bit Jul 22, 2026
69db99b
test: 데이터베이스 초기화를 통해 테스트 컨텍스트 재사용
htdufhc-bit Jul 22, 2026
5b1a969
test: 요청별 쿼리 카운터와 N+1 경고 기능 추가
htdufhc-bit Jul 22, 2026
72349b2
test: 리포지토리 테스트와 테스트 픽스처 추가
htdufhc-bit Jul 22, 2026
773b636
style: 대기 도메인 코드 포맷 정리
htdufhc-bit Jul 22, 2026
e385e04
test: 사용하지 않는 필드 제거
htdufhc-bit Jul 22, 2026
dfba04f
feat: DatabaseCleaner를 사용하는 테스트에 BeforeEachCallback 적용
htdufhc-bit Jul 25, 2026
bada4a5
test: Reservation과 Waiting api 테스트 추가
htdufhc-bit Jul 25, 2026
14acc26
refactor: 엔티티 생성자를 비공개로 전환하고 정적 팩토리가 요청 DTO 대신 값을 받도록 변경
htdufhc-bit Jul 25, 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
4 changes: 2 additions & 2 deletions src/main/java/roomescape/auth/controller/AuthController.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import roomescape.auth.service.AuthService;
import roomescape.auth.web.Login;
import roomescape.auth.web.TokenExtractor;
import roomescape.util.CookieUtil;
import roomescape.global.util.CookieUtil;

@RestController
public class AuthController {
Expand Down Expand Up @@ -52,7 +52,7 @@ public ResponseEntity<Void> loginByRefreshToken(HttpServletRequest request,

@GetMapping("/login/check")
public ResponseEntity<LoginCheckResponse> checkLogin(@Login LoginMember loginMember) {
return ResponseEntity.ok(new LoginCheckResponse(loginMember.name()));
return ResponseEntity.ok(LoginCheckResponse.from(loginMember));
}

@PostMapping("/logout")
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/roomescape/auth/dto/LoginCheckResponse.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package roomescape.auth.dto;

import roomescape.auth.domain.LoginMember;

public record LoginCheckResponse(
String name
) {

public static LoginCheckResponse from(LoginMember loginMember) {
return new LoginCheckResponse(loginMember.name());
}
Comment on lines +9 to +11

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

👍👍 팀마다 다르긴한데 제 팀은 DTO에 정팩메 쓰는게 암묵적 컨벤션이라 정팩메 있으니 편안하네요

}
4 changes: 4 additions & 0 deletions src/main/java/roomescape/auth/dto/TokenResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ public record TokenResponse(
String accessToken,
String refreshToken
) {

public static TokenResponse of(String accessToken, String refreshToken) {
return new TokenResponse(accessToken, refreshToken);
}
}
6 changes: 5 additions & 1 deletion src/main/java/roomescape/auth/entity/RefreshToken.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ public class RefreshToken {
public RefreshToken() {
}

public RefreshToken(Member member, String token) {
private RefreshToken(Member member, String token) {
this.member = member;
this.token = token;
}

public static RefreshToken of(Member member, String token) {
return new RefreshToken(member, token);
}

public Long getId() {
return id;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/roomescape/auth/exception/AuthErrorCode.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package roomescape.auth.exception;

import org.springframework.http.HttpStatus;
import roomescape.exception.ErrorCode;
import roomescape.global.exception.ErrorCode;

public enum AuthErrorCode implements ErrorCode {
ACCESS_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "토큰이 만료되었습니다."),
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/roomescape/auth/jwt/JwtTokenProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import io.jsonwebtoken.security.SignatureException;
import org.springframework.stereotype.Component;
import roomescape.auth.exception.AuthErrorCode;
import roomescape.exception.ApplicationException;
import roomescape.global.exception.ApplicationException;
import roomescape.member.entity.Member;

import java.security.Key;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package roomescape.auth.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import roomescape.auth.entity.RefreshToken;

import java.util.Optional;

public interface RefreshTokenRepository {

void save(RefreshToken refreshToken);
@Repository
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

시간이 좀 있으면 JpaRepository 내부 구현체가 대략적으로 어떤 클래스로 나뉘고 각각 어떤 역할을 하는지 찾아보시면 좋아보여요~

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵! 한 번 따로 공부해보겠습니다!!


Optional<RefreshToken> findByToken(String token);

Optional<RefreshToken> findByMemberId(Long memberId);

void deleteByMemberId(Long memberId);

void flush();
}
6 changes: 3 additions & 3 deletions src/main/java/roomescape/auth/service/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import roomescape.auth.exception.AuthErrorCode;
import roomescape.auth.jwt.JwtTokenProvider;
import roomescape.auth.repository.RefreshTokenRepository;
import roomescape.exception.ApplicationException;
import roomescape.global.exception.ApplicationException;
import roomescape.member.entity.Member;
import roomescape.member.exception.MemberErrorCode;
import roomescape.member.repository.MemberRepository;
Expand Down Expand Up @@ -68,8 +68,8 @@ private TokenResponse createTokens(Member member) {

refreshTokenRepository.deleteByMemberId(member.getId());
refreshTokenRepository.flush();
refreshTokenRepository.save(new RefreshToken(member, refreshToken));
refreshTokenRepository.save(RefreshToken.of(member, refreshToken));

return new TokenResponse(accessToken, refreshToken);
return TokenResponse.of(accessToken, refreshToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import roomescape.auth.domain.LoginMember;
import roomescape.auth.exception.AuthErrorCode;
import roomescape.auth.service.AuthService;
import roomescape.exception.ApplicationException;
import roomescape.global.exception.ApplicationException;

@Component
public class CheckAdminInterceptor implements HandlerInterceptor {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/roomescape/auth/web/TokenExtractor.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import jakarta.servlet.http.Cookie;
import org.springframework.stereotype.Component;
import roomescape.auth.exception.AuthErrorCode;
import roomescape.exception.ApplicationException;
import roomescape.util.CookieUtil;
import roomescape.global.exception.ApplicationException;
import roomescape.global.util.CookieUtil;

@Component
public class TokenExtractor {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package roomescape.config;
package roomescape.global.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/roomescape/global/entity/BaseSoftDeleteEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package roomescape.global.entity;

import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;
import java.time.ZoneId;

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseSoftDeleteEntity {

private static final ZoneId KST_ZONE = ZoneId.of("Asia/Seoul");

private LocalDateTime deletedAt;

public void markDeleted() {
this.deletedAt = LocalDateTime.now(KST_ZONE);
}

public LocalDateTime getDeletedAt() {
return deletedAt;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package roomescape.exception;
package roomescape.global.exception;

public class ApplicationException extends RuntimeException {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package roomescape.exception;
package roomescape.global.exception;

import org.springframework.http.HttpStatus;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package roomescape.exception;
package roomescape.global.exception;

public record ErrorResponse(String message) {
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package roomescape.exception;
package roomescape.global.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package roomescape.util;
package roomescape.global.util;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ public MemberController(MemberService memberService) {
@PostMapping("/members")
public ResponseEntity createMember(@Valid @RequestBody MemberRequest memberRequest) {
MemberResponse member = memberService.create(memberRequest);
return ResponseEntity.created(URI.create("/members/" + member.getId())).body(member);
return ResponseEntity.created(URI.create("/members/" + member.id())).body(member);
}
}
32 changes: 9 additions & 23 deletions src/main/java/roomescape/member/dto/MemberRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,13 @@
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;

public class MemberRequest {

@NotBlank(message = "이름은 필수입니다.")
private String name;

@NotBlank(message = "이메일은 필수입니다.")
@Email(message = "이메일 형식이 올바르지 않습니다.")
private String email;

@NotBlank(message = "비밀번호는 필수입니다.")
private String password;

public String getName() {
return name;
}

public String getEmail() {
return email;
}

public String getPassword() {
return password;
}
public record MemberRequest(
@NotBlank(message = "이름은 필수입니다.")
String name,
@NotBlank(message = "이메일은 필수입니다.")
@Email(message = "이메일 형식이 올바르지 않습니다.")
String email,
@NotBlank(message = "비밀번호는 필수입니다.")
String password
) {
}
27 changes: 8 additions & 19 deletions src/main/java/roomescape/member/dto/MemberResponse.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
package roomescape.member.dto;

public class MemberResponse {
private Long id;
private String name;
private String email;
import roomescape.member.entity.Member;

public MemberResponse(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}

public Long getId() {
return id;
}

public String getName() {
return name;
}
public record MemberResponse(
Long id,
String name,
String email
) {

public String getEmail() {
return email;
public static MemberResponse from(Member member) {
return new MemberResponse(member.getId(), member.getName(), member.getEmail());
}
}
7 changes: 6 additions & 1 deletion src/main/java/roomescape/member/entity/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import roomescape.member.dto.MemberRequest;

@Entity(name = "member")
public class Member {
Expand All @@ -30,13 +31,17 @@ public class Member {
public Member() {
}

public Member(String name, String email, String password, Role role) {
private Member(String name, String email, String password, Role role) {
this.name = name;
this.email = email;
this.password = password;
this.role = role;
}

public static Member of(String name, String email, String password, Role role) {
return new Member(name, email, password, role);
}

public Long getId() {
return id;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package roomescape.member.exception;

import org.springframework.http.HttpStatus;
import roomescape.exception.ErrorCode;
import roomescape.global.exception.ErrorCode;

public enum MemberErrorCode implements ErrorCode {
MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 회원입니다."),
Expand Down
Loading