Skip to content

Commit fc7faf7

Browse files
fivedragon5Hanjaemo023-dev
authored
[RELEASE] 2025-12-29 프로덕션 배포 (#380)
* chore: Springdoc 의존성 추가 * feat: Springdoc 설정 클래스 구현 * fix: Swagger 관련 요청일 경우 body를 래핑하지 않도록 분기 처리 * refactor: 각 auth 관련 클래스를 패키지별로 관리 * feat: Swagger 공통 응답 커스터마이징 * feat: Swagger UI에서 HealthController 제외 * feat: 모든 API에 대한 Swagger 설정 * feat: 커스터마이징 과정 주석 추가 * refactor: 커스텀 어노테이션 없이도 공통 응답 포맷이 보여지도록 설정 * feat: Slack 메세지 전송 컴포넌트 설정 * feat: Swagger 에러 응답 예시 자동화를 위한 어노테이션, 커스터마이저 추가 * fix: SlackProperties, SlackConfig 통폐합 * feat: AuthApiSpec, FileApiSpec에 에러 응답 예시 추가 * refactor: ApiResponse 래핑 시 Swagger 요청 검증을 startsWith에서 contains로 변경 * refactor: 미존재 ErrorCode enum 시 렌더링 에러 대신 unknown example 명시 * feat: 인증 정보 hidden 처리 * feat: PIN 로그인 API 명세 hidden 처리 * chore: dev 브랜치로 PR 생성 시 CI 워크플로우 실행 * feat: 개발서버를 위한 continuous deployment 워크플로우 추가 * refactor: Dockerfile 변경으로 이미지 크기 최적화 및 보안 강화 * chore: .dockerignore 파일 추가하여 Docker 빌드 최적화 * fix: prod yml에서 dev yml로 수정 * fix: COPY 와일드카드로 인한 에러 방지를 위해 ject 패턴 추가 * fix: 정상 시그널 전달/그레이스풀 셧다운 보장 위해 exec 추가 * fix: 배포 워크플로우에서 불필요한 SCP 단계 제거 * 관리자 로그인 관련 더미 API 추가 (#245) * feat: 관리자 로그인 관련 더미 API 추가 * refactor: 랜덤 코드 생성 유틸 공통화 * refactor: CodeGeneratorUtil.java private 생성자 추가 * refactor: request Email 유효성 검사 추가 * refactor: continuous-deployment.yml에서 continuous-deployment-prod.yml 파일 이름 변경 (#247) * Update issue templates * Jacoco 도입 (#244) * chore: jacoco 설정 * chore: CI workflow에 jacoco report 업로드 작업 추가 * chore: jacoco report 생성 경로를 기본값으로 변경 * chore: jacoco report 업로드 확인을 위해 임시로 커버리지 기준을 60으로 설정 * chore: jacoco 커버리지 기준 70으로 설정 및 update-comment 활성화 * chore: 이전 step들의 실패 여부와 상관없이 무조건 jacoco report 실행 * chore: jacoco에서 Q클래스 제외 * test: SuccessResponseCustomizer customize 단위 테스트 * chore: 변경된 파일에 대한 커버리지 누락 확인을 위해 'update-comment:true' 임시 주석 처리 * chore: 'update-comment:true' 주석 해제 및 Q클래스 제외 규칙 변경 * chore: CI 워크플로우에 Get the Coverage info 추가 * test: jacoco 변경 파일에 대한 커버리지 체크 여부 확인을 위한 테스트 임시 주석 * test: jacoco-report v1.6.1로 다운그레이드 * test: jacoco-report v1.7.2로 업그레이드 * test: jacoco report 확인을 위한 임의 클래스 및 테스트 코드 작성 * Revert "test: jacoco report 확인을 위한 임의 클래스 및 테스트 코드 작성" This reverts commit a1f7a59. * refactor: ErrorCode에 http status 필드 추가 및 관련 코드 리팩토링 * refactor: GlobalErrorCode code 포맷 변경 * test: GlobalErrorCode code 포맷 변경에 따른 테스트 수정 * Feat/237 zero downtime deploy (#255) * refactor: continuous-deployment.yml에서 continuous-deployment-prod.yml 파일 이름 변경 * refactor: 개발 환경 continuous deployment 워크플로우 수정 * refactor: 운영 환경 continuous deployment 워크플로우 수정 * fix: s3 cp pipelone에서 prod property에서 dev property로 수정 Updated deployment workflow to use development configuration. * fix: EC2_HOST_DEV를 EC2_HOST로 수정 * [FEAT] 관리자 로그인 인증코드 발송 * refactor: 랜덤 코드 만들기 숫자, 숫자 + 영문 로직 분리 * fix: 관리자 로그인 API 스펙 수정 * feat: 관리자 회원 상세조회 Repository 추가 및 테스트코드 작성 * feat: 관리자 로그인 시도시 Slack 으로 Code 발송 기능 * feat: 관리자 로그인 - 1차 인증 Service 구현 * fix: 불필요한 코드 삭제 * fix: 테스트 코드 이름 수정 * fix: 테스트 코드의 메서드명 한글로 통일 * fix: 랜덤 코드 생성 메서드명 수정 * fix: test 메서드명에 _ 리플레이스 적용 * Swagger core/admin API 그룹화 (#253) * chore: swagger api 명세를 core와 admin으로 그룹화 * refactor: recruit, semester 어드민 API의 URL 앞에 '/admin' 추가 * refactor: 템플릿 메일 전송 API의 URL 앞에 '/admin' 추가 * refactor: Dockerfile 수정으로 실행 환경을 운영(production)으로 변경 * Change Spring profile from prod to dev in start.sh * Add GitHub Action to notify Slack on new issues * chore: swagger GroupedOpenApi에 response 커스터마이저 추가 (#261) * refactor: refreshToken api spec에서 INVALID_REFRESH_TOKEN 문서화 중복 제거 * refactor: 코드 문자열과 상수명 일치화 * test: RecruitService 단위 테스트 보완 * fix: admin error code 구조 변경 (#264) * [FEAT] 관리자 로그인 - 2차인증 (#267) * feat: 관리자 로그인 - 2차인증 구현 * feat: 관리자 로그인 - 2차인증 구현 * fix: 관리자 로그인 - 2차인증 구현 줄바꿈 추가 * fix: 인증 성공시 인증코드 삭제 처리 추가하기 * fix: 어드민 로그인 ErrorCode 수정 * 유효성 검증 실패 응답 포맷 래핑 문제 해결 (#270) * feat: HandlerMethodValidationException 핸들러 추가 & 예외 발생 시 응답에 여러 메시지를 담을 수 있도록 리팩토링 * feat: RecruitController에 @Valid 추가 * feat: 요청 실패 응답 래핑 시점에 상태 코드 세팅 * test: 요청 실패 응답 상태 코드 세팅에 따른 통합 테스트 수정 * refactor: HandlerMethodValidationException 메서드명 통일화 * test: 원인 불명 실패 테스트 임시 주석 처리 * Flyway 도입 (#273) * feat: Flyway 의존성 추가 및 코드 주석 * feat: 초기 데이터베이스 마이그레이션 스크립트 추가 * feat: project 테이블에 semester_id 외래 키 제약 조건 추가 * feat: project_intro 테이블에 전이 및 순서 유니크 제약 추가 * feat: 테스트 환경 변수에서 flyway 미적용 설정 추가 * feat: 마이그레이션 스크립트 제약 조건 및 컬럼 정의 변경 * feat: 마이그레이션 스크립트 제약 조건 및 컬럼 정의 변경 * refactor: datetime을 datatime(6)으로 수정 * 테스트코드용 공통 추상클래스 도입 (#274) * refactor: 테스트 지원용 추상 클래스 추가(257) * refactor: recruit 모듈 유닛 테스트 클래스에 공통 추상 클래스 상속 적용(257) * refactor: 테스트 지원용 추상 클래스 추가 * refactor: recruit 모듈 유닛 테스트 클래스에 공통 추상 클래스 상속 적용 * refactor: project 모듈 유닛 테스트 클래스에 공통 추상 클래스 상속 적용 * refactor: member 모듈 유닛 테스트 클래스에 공통 추상 클래스 상속 적용 * test: MemberController 통합 테스트 분리 * refactor: admin 모듈 유닛 테스트 클래스에 공통 추상 클래스 상속 적용 * refactor: auth 모듈 유닛 테스트 클래스에 공통 추상 클래스 상속 적용 * refactor: s3 모듈 유닛 테스트 클래스에 공통 추상 클래스 상속 적용 * refactor: jwt 모듈 유닛 테스트 클래스에 공통 추상 클래스 상속 적용 * fix: import문 추가 * fix: MemberControllerTest 롤백 및 공통 클래스 적용 * 관리자 2차 로그인 - 계정 잠금 처리 추가 (#276) * member 테이블에 Member Status 추가 * fix: Member테이블에 상태 컬럼 추가에 따른 코드 수정 * refactor: 관리자 공통 코드 분리 및 코드 수정 * fix: Slack Rate Limiter 값 조정 * refactor: 파일 마지막 밑줄 추가 * fix: test에서도 redis키 동일하게 맞추기 * fix: 잘못된 테스트 코드 수정 * fix: Member Entity의 MemberStatus Default 값 추가 * fix: member의 상태 변경시 현재 상태와 같은 값으로 변경할 경우 그대로 return 처리 추가 * MemberRole type명 변경 USER -> SEMESTER, TEMP -> APPLY (#277) * fix: MemberRole type명 변경하기 USER -> SEMESTER, TEMP -> APPLY * fix: 권한 변경 누락 수정 * feat: project 테이블의 semester_id 컬럼을 team 테이블로 마이그레이션 및 코드 수정 (#279) * feat: project 테이블의 semester_id 컬럼을 team 테이블로 마이그레이션 및 코드 수정 * feat: semester_id 마이그레이션 초기값 1로 설정 * feat: 이슈 알림 워크플로우 비활성화 * [FEAT] 구성원 관리 (#283) * feat: 회원 API에 구성원 관리 기능 추가 * feat: 회원 API에 관리자 전용 조회, 등록, 수정, 삭제 기능 추가 * feat: 회원 DTO 추가하여 회원 관리 로직 지원 * feat: 회원 서비스에 CRUD 로직 기능 추가 * feat: 회원 Entity에 soft delete 및 update 기능 추가 * feat: 회원 조회 로직에 페이징 및 필터링 기능 추가 * feat: 구성원 관리 API 분리 및 MemberManagementController 구현 * refactor: 사용하지 않는 import 제거 * test: MemberManagementController 테스트 추가 * test: MemberService 테스트에 회원 CRUD 및 조회 로직 추가 * test: MemberQueryRepositoryTest에 회원 조회 테스트 케이스 추가 및 개선 * feat: 회원 테이블에 is_deleted 컬럼 추가 * feat: 회원 테이블에 is_deleted 컬럼 추가 * fix: updateMember 메서드의 파라미터 이름 수정 * fix: deleteMember 파라미터 이름 수정 * fix: 회원 엔티티의 is_deleted 컬럼에 nullable 속성 추가 * refactor: 회원 등록 시 PIN 코드 생성 로직 수정 * test: MemberServiceTest에 passwordEncoder 양식 검증 로직 수정 * refactor: MemberDetailResponse에 semesterName 대신 semesterId 사용하도록 수정 * refactor: Member 엔티티 PIN 컬럼 nullable 처리 및 관련 로직 수정 * refactor: deleteMembers 메서드에서 불필요한 스트림 로직 제거 * refactor: updateMember 메서드 editMember로 이름 변경 및 MemberEditor 빌더 패턴 도입 * test: updateMember에 editMember 변경 반영 및 데이터 필드 수정 * test: editMember 메서드명 및 데이터 필드 변경 반영 * refactor: MemberEditor 빌더 패턴 레코드 추가 * refactor: Member 수정 시 semesterId 필수값 제거 및 검증 로직 수정 * [REFACTOR] 구성원 관리 (#284) * feat: 회원 API에 구성원 관리 기능 추가 * feat: 회원 API에 관리자 전용 조회, 등록, 수정, 삭제 기능 추가 * feat: 회원 DTO 추가하여 회원 관리 로직 지원 * feat: 회원 서비스에 CRUD 로직 기능 추가 * feat: 회원 Entity에 soft delete 및 update 기능 추가 * feat: 회원 조회 로직에 페이징 및 필터링 기능 추가 * feat: 구성원 관리 API 분리 및 MemberManagementController 구현 * refactor: 사용하지 않는 import 제거 * test: MemberManagementController 테스트 추가 * test: MemberService 테스트에 회원 CRUD 및 조회 로직 추가 * test: MemberQueryRepositoryTest에 회원 조회 테스트 케이스 추가 및 개선 * feat: 회원 테이블에 is_deleted 컬럼 추가 * feat: 회원 테이블에 is_deleted 컬럼 추가 * fix: updateMember 메서드의 파라미터 이름 수정 * fix: deleteMember 파라미터 이름 수정 * fix: 회원 엔티티의 is_deleted 컬럼에 nullable 속성 추가 * refactor: 회원 등록 시 PIN 코드 생성 로직 수정 * test: MemberServiceTest에 passwordEncoder 양식 검증 로직 수정 * refactor: MemberDetailResponse에 semesterName 대신 semesterId 사용하도록 수정 * refactor: Member 엔티티 PIN 컬럼 nullable 처리 및 관련 로직 수정 * refactor: deleteMembers 메서드에서 불필요한 스트림 로직 제거 * refactor: updateMember 메서드 editMember로 이름 변경 및 MemberEditor 빌더 패턴 도입 * test: updateMember에 editMember 변경 반영 및 데이터 필드 수정 * test: editMember 메서드명 및 데이터 필드 변경 반영 * refactor: MemberEditor 빌더 패턴 레코드 추가 * refactor: Member 수정 시 semesterId 필수값 제거 및 검증 로직 수정 * refactor: semesterId에서 semesterName 변경 및 관련 로직 수정 * refactor: semesterName 입력 형식 변경 및 Swagger 문서 설명 보강 * Apply 테이블 추가 및 지원-모집 관련 테이블 관계 개선 (#285) * refactor: apply 모듈 분리 * refactor: Apply 엔티티 추가, Member-Apply-Recruit 관계 연결 * refactor: ApplicationForm과 Recruit 간의 관계 제거 * refactor: Recruit-Semester 관계 연결 * refactor: Member 엔터티에서 semesterId 제거 * style: 주석 제거 * doc: sql 스크립트 작성 1. application_form 테이블에서 member, recruit 테이블에 대한 외래키 제약조건 제거 2. application_form 테이블에서 member_id, recruit_id 컬럼 제거 3. apply 테이블 생성 4. application_form 테이블에 apply_id 컬럼 추가 및 외래키 설정 5. recruit 테이블에 semester_id 컬럼 추가 및 외래키 설정 * refactor: ApplicationForm의 Apply 관계 매핑을 @OnetoOne으로 변경 * refactor: ApplicationFormRepository의 existsByMemberId 메서드를 네이티브 쿼리로 변경 * refactor: 테스트 코드에서 기수 ID를 하드코딩하지 않도록 수정 * refactor: V7 DB 마이그레이션 순서 변경 * refactor: 오타 수정 * refactor: 사용되지 않는 OngoingSemesterProvider 제거 * test: ApplyService 단위 테스트 작성 * style: 중복 import 제거 * 지원서 임시 저장소 리디자인 (NoSQL → RDB) (#288) * refactor: 지원서 임시 저장 시 RDB에 저장되도록 변경 * test: ApplyControllerTest.java 주석 처리 * test: 지원서 임시 저장 기능 단위 테스트 * refactor: 임시 저장한 지원서 조회 기능 DB를 NoSQL에서 RDB로 변경 * refactor: 지원서 제출 로직에서 apply 엔터티를 memberId로 조회하도록 개선 * refactor: 변경된 지원 플로우와 DB 리디자인에 따라 지원서 초기화 기능 리팩토링 * test: ApplyServiceTest에서 사용되지 않는 코드 제거 * refactor: RemindApplyService#remindApply 메서드 내 임시 저장한 지원자 ID 조회 시 applyRepository에서 조회하도록 변경 * doc: dynamodb를 사용하던 지원서 임시저장 개념의 클래스에 @deprecated 명시 * feat: 임시 회원 저장 시 semesterId도 함께 저장 * test: 임시 회원 저장 서비스 로직 단위 테스트에 semesterRepository 모킹 * feat: String2MapSerializer null, blank 입력 방어 * test: findByRecruitAndStatus 결과가 정렬을 보장하지 않도록 변경 * test: recruit 필드 초기화 구문 제거 * test: 임시 저장한 지원서 조회 서비스 로직 단위 테스트 * test: '임시 저장한 지원서가 없는 상태에서 지원서 조회 시 실패' 로직 단위 테스트 * test: String2MapSerializer 테스트 * test: Jacoco 리포트 범위에서 controller 클래스 제외 * chore: Jacoco 리포트 범위에서 tempapply 모듈 제외 * [FEAT] 개선된 지원 플로우에 따른 리팩토링 (#290) * refactor: 회원 등록 엔드포인트를 /apply 업데이트 * refactor: 지원 상태 확인 기능 개선 및 ApplyStatusResponse 추가 * refactor: 개선된 프로필 작성에 따른 직군 및 관심 도메인 선택 enum 클래스 리팩토링 * feat: 지원 과정에서 프로필 저장 기능 추가 생성 * feat: 지원서 제출 시 임시 저장한 지원서가 있을 경우 생성 대신 수정하는 로직 추가 * feat: 임시 회원 등록 시 Apply 엔티티 생성 및 저장 기능 추가 * fix: 전화번호 입력 검증 메시지 오타 수정 * refactor: Apply 엔티티 생성 시 중복 체크 로직 추가 * fix: InterestedDomain enum 오타 수 * fix: InterestedDomain enum 오타 수정 * refactor: 제거된 TempMemberRegisteredEvent 관련 로직 및 불필요한 의존성 정리 * refactor: 프로필 작성 시 apply 생성 로직 추가 * fix: 파일 끝에 개행 추가 * refactor: 의미없는 주석 제거 * fix: 파일 끝에 개행 추가 * refactor: saveProfile 메서드에 @OverRide 어노테이션 추가 * refactor: saveProfile 멱등성 보장 리팩토링 * 개선된 지원 플로우에 따른 리팩토링 (추가 개선) (#303) * refactor: ApplyService의 checkApplySubmit 메서드 네이밍 개선 * feat: ApplyProfileRequest의 interestedDomains 필드에 최대 개수 검증 어노테이션 추가 * clean: TempMemberRegisteredEvent 제거 * refactor: MemberService의 registerMember 메서드 네이밍 개선 * [FEAT] 제출된 지원서 삭제 (#306) * feat: 제출된 지원서 삭제 API 엔드포인트 추가 * feat: 다수의 제출된 지원서 삭제를 위한 dto 구현 * feat: 제출된 지원서 삭제 비즈니스 로직 구현 * feat: 제출된 지원서 조회를 위한 레포지토리 메서드 추가 * feat: Apply 엔티티에 지원서 삭제 및 상태 검증 메서드 추가 * feat: 제출된 지원서 검증 관련 에러 코드 추가 * test: 제출된 지원서 삭제 기능 테스트 추가 * refactor: 사용하지 않는 Mock 제거 * refactor: 사용하지 않는 import 제거 * fix: 파일의 끝에 개행 추가 * refactor: 지원서 삭제 시 상태 업데이트 코드 제거 * refactor: 필드명을 클래스명과 일치 * refactor: ApplicationForm 검증 로직 최소화 * feat: 제출된 지원서 다건 조회 메소드 수정 * refactor: 불필요한 주석 수정 * refactor: 중복되지 않는 apply id들로 처리 되게끔 수정 * refactor: 바인딩 오류를 방지하지 하기 위한 @Param 어노테이션 추가 * [FEAT] 제출 완료된 지원서 수 조회 (#307) * feat: 제출된 지원서 수 조회 DTO 구 * feat: 제출된 지원서 수 조회 쿼리 메서드 구 * feat: 제출된 지원서 수 조회 비즈니스 로직 구 * test: 제출된 지원서 수 조회 비즈니스 로직 테스트 * feat: 제출된 지원서 수 조회 API 스펙 추가 * feat: 제출된 지원서 수 조회 API 엔드포인 추가 * [FEAT] 임시 저장된 지원서 상세조회 * refactor: 사용하지 않는 코드 삭제 * refactor: DateTimeUtil 추가 및 공통화 * feat: 임시 저장된 지원서 상세 조회 * add: AdminTempApplyService Test Code 작성 * fix: 날짜 데이터 포멧 수정 * refactor: 지원서 상세 조회 Repository 메소드 수정 * fix: 불필요한 테스트 코드 삭제 * [FEAT] 제출 완료된 지원서 목록 조회 (#308) * feat: 제출된 지원서 수 목록 조회 DTO 구현 * feat: 제출된 지원서 수 목록 조회 쿼리 메서드 구현 * feat: 제출된 지원서 수 목록 조회 쿼리 메서드 구현 * refactor: 카운트 쿼리 메서드의 대소문자 통일 * feat: 제출된 지원서 목록 조회 API 스펙 구현 * feat: 제출된 지원서 목록 조회 서비스 로직 구현 * feat: 제출된 지원서 목록 조회 API 엔드포인트 추가 * refactor: 제출된 지원서 수 조회 메서드에 트랜잭션 읽기 전용 설정 추가 * refactor: 카운트 쿼리에 member 조인 추가 * refactor: NPE 방지를 위한 null 체크 로직 추가 * refactor: 컬렉션 불변화 및 null safety를 위한 로직 추가 * refactor: JPAQueryFactory로 변경 * refactor: NPE 방지를 위한 null safe 처리 로직 추가 * feat: 임시 저장한 지원서 수 조회 기능 추가 * [FEAT] 제출 완료된 지원서 상세 조회 (#310) * feat: 제출된 지원서 상세 조회 DTO 추가 * feat: 제출된 지원서 상세 조회 API 스펙 추가 * feat: 제출된 지원서 상세 조회 API 엔트포인트 추가 * feat: 제출된 지원서 상세 조회 비즈니스 로직 구 * test: 제출된 지원서 상세 조회 비즈니스 로직 테스트 추가 * style: 제출된 지원서 상세 조회 API 설명 수정 * style: 테스트 이름을 실제 동작과 일치하게 수 * style: 불필요한 주석 제거 * test: 제출된 지원서 상세 조회 시 예외 코드 검증 추가 * fix: 개행 처 * style: 테스트 메서드 이름을 명확하게 수정 * [FEAT] 임시 저장된 지원서 삭제 * feat: 임시 저장된 지원서 삭제 기능 추가 * feat: 임시 저장된 지원서 삭제(HardDelete) * feat: Member 정보 수정 추가 * [FEAT] 제출 완료된 지원서 수정 (#313) * feat: 제출된 지원서 수정 DTO 추 * feat: 제출된 지원서 수정 기능 비즈니스 로직 구현 * test: 제출된 지원서 수정 기능 테스트 * feat: 제출된 지원서 수정 API 스펙 추가 * feat: 제출된 지원서 수정 API 엔드포인트 추가 * style: private method을 하단으로 배치 * feat: 제출된 지원서 다수 삭제 기능에서 삭제한 수 반환 추가 * test: 제출된 지원서 수정 테스트에서 전화번호 형식 변경 * feat: 제출된 지원서 수정 API에 관리자 권한 인증 추가 * feat: 제출된 지원서 수정 API의 경로 수정 * test: 제출된 지원서 수정 테스트에서 전화번호 형식 통일 * feat: 임시 저장된 지원서 목록 조회 * feat: 임시 저장된 지원서 목록 조회 기능 * feat: 지원서의 상태로 조회 하기 메서드 이름 변경 * 지원자 합격 처리(구성원 승인) API 개발 (#311) * feat: 지원자 합격 처리 (구성원 승인) API 개발 * test: 지원자 합격 처리 (구성원 승인) 서비스 로직 단위 테스트 * clean: 줄바꿈 추가 * refactor: 무분별한 어드민 승격 방지를 위해 메서드 파라미터 제거 및 내부 주입으로 변경 * refactor: applyIds로 지원 정보 리스트 조회 시 N+1 문제가 발생하지 않도록 개선 * [REFACTOR] 에러코드 개선 (#316) * refactor: Apply 도메인 에러 코드를 문자열 형태로 수정 * refactor: Auth 도메인 에러 코드를 문자열 형태로 수정 * refactor: File 도메인 에러 코드를 문자열 형태로 수정 * style: 클래스 끝에 개행 추가 * refactor: Member 도메인 에러 코드를 문자열 형태로 수정 * refactor: Project 도메인 에러 코드를 문자열 형태로 수정 * refactor: Question 도메인 에러 코드를 문자열 형태로 수정 * refactor: Recruit 도메인 에러 코드를 문자열 형태로 수정 * refactor: Semester 도메인 에러 코드를 문자열 형태로 수정 * test: 테스트 코드에서 에러 코드를 문자열이 아닌 상수로 변경 * test: hasSize(0)에서 isEmpty로 개선 * refactor: Global 에러 코드를 문자열 형태로 수정 * chore: 사용하지 않는 슬랙 알림 워크플로우 제거 (#319) * fix: swagger config 수정 * [REFACTOR] 구성원 관리 기능 리팩토링 (#321) * refactor: 구성원 관리 기능 리팩토링 및 관리자 패키지 구조 변경 - `@PathVariable` 및 `@PageableDefault` 명시 - 다수 삭제 메서드 삭제 수 반환 * refactor: 구성원 관리 기능 관련 DTO 관리자 패키지로 이동 및 테스트 코드 수정 * refactor: 관리자 구성원 관리 서비스 및 테스트 클래스 분리 - 기존 서비스 클래스에서 관리자 전용 구성원 관리 로직 분리하여 `MemberManagementService` 추가 * fix: 구성원 삭제 시 중복 ID 처리 로직 추가 - 중복 ID로 인한 불일치 문제 해결을 위해 ID 목록에서 중복 제거 * chore: 테스트 환경 설정 파일 S3 버킷 및 CloudFront 도메인 수정 (#326) * [FIX] 개발 서버 CORS 문제 수정 (#327) * feat: Swagger 개발 환경을 위한 CORS 설정 추가 * feat: Swagger 서버 정보 추가 * Revert "feat: Swagger 개발 환경을 위한 CORS 설정 추가" This reverts commit 4f12c3c. * chore: 테스트 환경 설정 파일 S3 버킷 및 CloudFront 도메인 수정 (#326) --------- Co-authored-by: 023-dev <0_2_3@naver.com> Co-authored-by: 023 <rhdgmltkd88@gmail.com> * [FEAT] DEV 환경용 AccessToken 발급 API 구현 및 Swagger 문서화 (#330) * feat: 개발 환경을 위한 access token 발급 API 추가 * feat: access token 발급 API에 유효성 검사 추가 * chore: JWT 쿠키 생성 로직을 ResponseCookie로 변경 및 SameSite 속성 추가 (#333) * chore: JWT 쿠키 생성 로직을 ResponseCookie로 변경 및 SameSite 속성 추가 * 테스트 코드 수정 * [CHORE] 관리자 로그인 인증 Slack -> Discord 변경 (#331) * chore: 슬랙 인증 코드 전송 및 검증 기능을 디스코드로 변경 * test: 인증 코드 검증 관련 테스트 메서드 이름 변경 * feat: Discord 메시지 전송 기능을 WebClient로 변경 및 개선 * feat: Discord 메시지 전송 기능을 논블로킹 방식으로 개선 * feat: WebClient 설정에 연결 및 응답 타임아웃 추가 * feat: Discord webhook URL 유효성 검사 개선 및 불필요한 메서드 제거 * feat: Discord 메시지 전송 성공 로그 개선 및 오류 로그 메시지 수정 * feat: DiscordComponent에서 prefix 초기화 방식 개선 * feat: Discord 메시지 전송 실패 로그에 오류 메시지 추가 * fix: JWT 예외 처리 시 HTTP 상태 코드 설정 추가 (#335) * feat: 개발 환경 전용 모집 관리 컨트롤러 추가 (#344) * refactor: 이메일 전송 그룹 코드를 문자열에서 Enum 으로 변경 (#345) * feat: 이메일 전송 그룹 코드를 문자열에서 Enum 으로 변경 * feat: 이메일 전송 메서드의 매개변수 명을 toEmail로 통일 * refactor: 이메일 전송 그룹 관련 코드 및 테이블 삭제 (#346) * refactor: 이메일 전송 그룹 관련 코드 및 테이블 삭제 * refactor: 이메일 전송 실패 처리 로직 추가 및 관련 예외 코드 정의 * refactor: 이메일 전송 실패 로그 메시지 개선 및 불필요한 에러 코드 제거 * [CHORE] 개발 서버 모니터링 구축 (#347) * feat: 개발 환경용 logback 설정 파일 추가 * chore: .gitignore에 개발 환경 설정 파일 추가 * feat: logback 설정에 maxFlushTimeMillis와 maxBatchLogEvents 옵션 추가 * fix: Logback 설정 오류(%clr 변환기 누락) 수정 및 필터 제거 (#354) * [FEAT] 지원서 프로필 작성 단계에서 거주지역 추가 (#349) * feat: 거주 지역 정보를 위한 Region enum 클래스 추가 * feat: Member 엔티티에 Region 필드 추가 및 관련 로직 반영 * feat: MemberEditRequest에 Region 필드 추가 및 유효성 검증 로직 반영 * feat: MemberRegisterRequest에 Region 필드 추가 및 유효성 검증 로직 반영 * feat: MemberDetailResponse에 Region 필드 추가 및 매핑 로직 반영 * feat: MemberManagementService에서 Member 생성 시 Region 필드 매핑 로직 추가 * feat: ApplyProfileRequest에 Region 필드 추가 및 유효성 검증 로직 반영 * feat: ApplyRepository에 memberId 중복 여부 확인 메서드 추가 * feat: ApplyService에 Region 필드 매핑 로직 추가 및 applyRepository 중복 확인 로직 개선 * test: Member 관련 테스트에 Region 필드 검증 로직 추가 * test: MemberManagementControllerTest에 Region 필드 관련 테스트 추가 * test: MemberManagementServiceTest에 Region 필드 관련 테스트 추가 * test: ApplyServiceTest에 Region 필드 관련 테스트 로직 추가 * test: MemberManagementControllerTest에 Region 필드 관련 테스트 추가 * chore: member 테이블에 region 컬럼 추가 * refactor: ApplyService의 중복 확인 로직 리팩토링 및 불필요한 코드 제거 * chore: apply 테이블에 member_id와 recruit_id에 대한 유니크 제약 조건 추가 * fix: ApplyService에 멱등성 보 로직 추가 * test: ApplyServiceTest에 applyRepository의 존재 여부 검증 로직 추가 * feat: 지원 상태 확인 로직 개선 및 프로필 작성 미완료 상태 추가 (#355) * feat: 지원 상태 확인 로직 개선 및 프로필 작성 미완료 상태 추가 * fix: 불필요한 공백 제거 * feat: 프로필 완성 여부 확인 로직 개선 및 테스트 추가 * feat: 현재 로그인한 회원 정보 조회 API 추가 (#356) * feat: 현재 로그인한 회원 정보 조회 API 추가 * fix: 지원 내역 조회 로직 개선 및 임시 저장 상태 반환 추가 * refactor: MemberProfileResponse에서 지역 변수 이름 변경 * refactor: MemberProfileResponse에서 지역 변수 이름 변경 * feat: 현재 로그인한 회원 프로필 조회 API 설명 수정 * [FEAT] 지원서 제출 시 특정 직군에 대한 정책 추가 (#357) * feat: JobFamily에 portfolioRequired 필드 추가 * feat: ApplyErrorCode에 포트폴리오 필수 에러 추가 * feat: ApplicationForm에 포트폴리오 존재 여부 확인 메서드 추가 * test: ApplyServiceTest에 PD 직군의 포트폴리오 제출 여부 검증 테스트 추가 * feat: Apply 엔티티에 지원 제출 기능 추가 및 제출 시 예외 처리 로직 구현 * refactor: ApplyService 내 지원서 제출 로직 리팩토링 및 코드 간결화 * test: ApplyTest에 지원서 제출 관련 테스트 케이스 추가 * fix: ApplyErrorCode에 제출 완료되지 않은 상태 에러 코드 롤백 * feat: 프로젝트 테이블에 badges 컬럼 추가 및 ProjectDetailResponse에 badges 필드 추가 (#360) * refactor: 지원 상태 조회 API email 기반 로직으로 변경 (#361) * refactor: checkApplyStatus 파라미터를 memberId에서 email로 변경 및 이메일 유효성 검증 추가 * refactor: checkApplyStatus 파라미터를 memberId에서 email로 변경 * test: checkApplyStatus 테스트를 memberId에서 email 기반으로 수정 * feat : 프로젝트 목록 요약 API 추가 (#363) * feat: 전체 프로젝트 요약 조회 기능 추가 * feat: 전체 프로젝트 요약 조회 기능 추가 * feat: 프로젝트 조회, 상세조회 API 수정 (#365) * feat: 프로젝트 상세 응답에 배너 이미지, 샘플 이미지, 소개 이미지 필드 추가 및 카테고리 마이그레이션 * feat : 프로젝트 목록 요약 API 추가 (#363) * feat: 전체 프로젝트 요약 조회 기능 추가 * feat: 프로젝트 소개서 카테고리 수정 및 서비스 타입 필드 추가 * feat: 프로젝트 조회 API에서 학기 ID 파라미터 제거 및 카테고리 기반 조회로 변경 * feat: 프로젝트 목록 조회 API 설명에서 기수 ID 언급 제거 * feat: 프로젝트 조회 API 캐시 키에서 학기 ID 파라미터 제거 * fix: 프로젝트 상세 조회 응답에서 썸네일 URL 필드 제거 (#369) * feat: 이메일 인증번호 발송 시 전송 횟수 제한 기능 추가 (#370) * feat: 이메일 전송 요청 횟수 제한 예외 처리 및 RateLimitException 추가 * feat: 이메일 인증 코드 발송 Rate Limit 추가 * test: UnitTestSupport 상속 적용 * fix: 이메일 인증 코드 발송 시 Rate Limit 남은 시간 계산 로직 수정 * feat: 이전 기수 지원 이력이 있으면 신규 지원이 불가능한 오류 (#372) * feat: 지원자가 현재 진행 중인 모집에 지원했는지 확인하는 메서드 추가 * fix: 지원서 조회 시 활성 모집에 한정되도록 쿼리 수정 * fix: 지원 상태 확인 및 임시저장/삭제 테스트에서 활성 모집 한정 로직 반영 - 지원 상태 확인 시 지원 내역이 없을 때 신규 지원 가능 테스트 추가 * refactor: 불필요한 import 제거 * fix: @Valid 어노테이션 프로필 저장 요청 유효성 검사 정상화 (#373) * fix: Apply 상태값(JOINED) 의미 불일치 해결 및 checkApplyStatus 로직 개선 (#375) * fix: 지원 상태 설명에서 JOINED 상태의 정의 수정 * refactor: ApplyStatusResponse에서 step 필드 및 관련 팩토리 메서드 제거 * refactor: 지원 상태 조회 로직 간소화 및 예외 처리 추가 * test: 지원 상태 조회 시 프로필 미작성 예외 처리 테스트 추가 및 기존 테스트 수정 * refactor: 지원 상태 확인 API 파라미터 변경 (#377) * refactor: 이메일 대신 memberId를 사용하도록 checkApplyStatus를 수 * refactor: checkApplyStatus 메서드 파라미터를 email에서 memberId로 수정 * test: checkApplyStatus 테스트 메서드 파라미터를 email에서 memberId로 수정 * feat: 임시저장 지원서 조회 시 직군(JobFamily) 정보 추가 (#379) * feat: JobFamily 정보 포함하도록 ApplyService 수정 * test: ApplyServiceTest에 JobFamily 검증 추가 * fix: CI 설정에서 캐시 읽기 전용 옵션을 false로 변경 (#382) * fix: CI 설정에서 캐시 읽기 전용 옵션을 false로 변경 * fix: SpringdocConfig에서 불필요한 API 그룹 제거 * feat: 회원 프로필 응답에 전화번호 필드 추가 및 CI 설정 수정 --------- Co-authored-by: Hanjaemo <110653660+Hanjaemo@users.noreply.github.com> Co-authored-by: 023-dev <0_2_3@naver.com> Co-authored-by: 023 <rhdgmltkd88@gmail.com>
1 parent f070dcf commit fc7faf7

233 files changed

Lines changed: 8758 additions & 1750 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/continuous-intergration.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
uses: gradle/gradle-build-action@v3
3434
with:
3535
arguments: build
36-
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}
36+
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/dev' }}
3737

3838
- name: Build with Gradle
3939
run: ./gradlew build -x test

build.gradle

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ dependencies {
3838
// DevTools
3939
compileOnly 'org.projectlombok:lombok'
4040
annotationProcessor 'org.projectlombok:lombok'
41-
// developmentOnly 'org.springframework.boot:spring-boot-devtools'
4241
implementation 'org.mapstruct:mapstruct:1.5.5.Final'
4342
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
4443

@@ -107,7 +106,7 @@ dependencies {
107106
// redis
108107
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
109108

110-
// jackon
109+
// jackson
111110
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.0'
112111

113112
// monitoring
@@ -125,8 +124,12 @@ dependencies {
125124
// Swagger
126125
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0'
127126

128-
// Slack
129-
implementation 'com.slack.api:slack-api-client:1.45.3'
127+
// Flyway
128+
implementation 'org.flywaydb:flyway-core'
129+
implementation 'org.flywaydb:flyway-mysql'
130+
131+
// WebFlux
132+
implementation 'org.springframework.boot:spring-boot-starter-webflux'
130133
}
131134

132135
configurations {
@@ -139,7 +142,9 @@ configurations {
139142
def jacocoExcludes = [
140143
'**/Q*', // QueryDSL Q*
141144
'**/exception/**',
142-
'**/dto/**'
145+
'**/dto/**',
146+
'**/controller/**',
147+
'**/tempapply/**'
143148
]
144149

145150
test {

scripts/start.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ cp $PROJECT_ROOT/build/libs/ject-home.jar $JAR_FILE
1515

1616
# jar 파일 실행
1717
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
18-
nohup java -Dspring.profiles.active=prod -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &
18+
nohup java -Dspring.profiles.active=dev -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &
1919

2020
CURRENT_PID=$(pgrep -f $JAR_FILE)
2121
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
package org.ject.support.common.exception;
22

3+
import org.springframework.http.HttpStatus;
4+
35
public interface ErrorCode {
46
String name();
7+
8+
HttpStatus getHttpStatus();
9+
510
String getCode();
11+
612
String getMessage();
713
}

src/main/java/org/ject/support/common/exception/GlobalErrorCode.java

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,36 @@
22

33
import lombok.AllArgsConstructor;
44
import lombok.Getter;
5+
import org.springframework.http.HttpStatus;
6+
7+
import static org.springframework.http.HttpStatus.BAD_REQUEST;
8+
import static org.springframework.http.HttpStatus.CONFLICT;
9+
import static org.springframework.http.HttpStatus.FORBIDDEN;
10+
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
11+
import static org.springframework.http.HttpStatus.METHOD_NOT_ALLOWED;
12+
import static org.springframework.http.HttpStatus.NOT_FOUND;
13+
import static org.springframework.http.HttpStatus.UNAUTHORIZED;
514

615
@Getter
716
@AllArgsConstructor
817
public enum GlobalErrorCode implements ErrorCode {
9-
UNSUPPORTED_PARAMETER_TYPE("G-01", "Unsupported parameter type"),
10-
RESOURCE_NOT_FOUND("G-02", "Resource not found"),
11-
METHOD_NOT_ALLOWED("G-03", "Method not allowed"),
12-
TEMPLATE_NOT_FOUND("G-04", "Template file not found"),
13-
JSON_MARSHALLING_FAILURE("G-05", "Json marshalling failure"),
14-
EMPTY_ACCESS_TOKEN("G-06", "Empty access token"),
15-
INVALID_ACCESS_TOKEN("G-07", "Invalid access token"),
16-
INVALID_PERMISSION("G-08", "Invalid permission"),
17-
AUTHENTICATION_REQUIRED("G-09", "Authentication is required"),
18-
INTERNAL_SERVER_ERROR("G-10", "Internal server error"),
19-
OVER_PERIOD("G-11", "모집 기간이 아닙니다."),
20-
MISS_REQUIRED_REQUEST_PARAMETER("G-12", "Missing required parameter"),
21-
MISS_REQUEST_BODY("G-13", "Missing request body"),
22-
MISS_REQUIRED_JOB_FAMILY_PARAMETER("G-14", "Missing required JobFamily parameter"),;
18+
UNSUPPORTED_PARAMETER_TYPE(BAD_REQUEST, "GLOBAL-1", "Unsupported parameter type"),
19+
RESOURCE_NOT_FOUND(NOT_FOUND, "GLOBAL-2", "Resource not found"),
20+
TEMPLATE_NOT_FOUND(NOT_FOUND, "GLOBAL-3", "Template file not found"),
21+
JSON_MARSHALLING_FAILURE(INTERNAL_SERVER_ERROR, "GLOBAL-4", "Json marshalling failure"),
22+
EMPTY_ACCESS_TOKEN(UNAUTHORIZED, "GLOBAL-5", "Empty access token"),
23+
INVALID_ACCESS_TOKEN(UNAUTHORIZED, "GLOBAL-6", "Invalid access token"),
24+
INVALID_PERMISSION(FORBIDDEN, "GLOBAL-7", "Invalid permission"),
25+
AUTHENTICATION_REQUIRED(UNAUTHORIZED, "GLOBAL-8", "Authentication is required"),
26+
OVER_PERIOD(CONFLICT, "GLOBAL-9", "모집 기간이 아닙니다."),
27+
MISS_REQUIRED_REQUEST_PARAMETER(BAD_REQUEST, "GLOBAL-10", "Missing required parameter"),
28+
MISS_REQUEST_BODY(BAD_REQUEST, "GLOBAL-11", "Missing request body"),
29+
MISS_REQUIRED_JOB_FAMILY_PARAMETER(BAD_REQUEST, "GLOBAL-12", "Missing required JobFamily parameter"),
30+
AUTHENTICATION_PROCESSING_ERROR(INTERNAL_SERVER_ERROR, "GLOBAL-13", "인증 처리 중 오류가 발생했습니다."),
31+
REQUEST_METHOD_NOT_ALLOWED(METHOD_NOT_ALLOWED, "GLOBAL-14", "Method not allowed"),
32+
METHOD_VALIDATION_FAILED(BAD_REQUEST, "GLOBAL-15", "Method validation failed");
2333

34+
private final HttpStatus httpStatus;
2435
private final String code;
2536
private final String message;
2637
}
Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,148 @@
11
package org.ject.support.common.exception;
22

33
import lombok.extern.slf4j.Slf4j;
4+
import org.ject.support.common.response.ErrorResponse;
5+
import org.ject.support.external.email.exception.RateLimitException;
6+
import org.springframework.context.MessageSourceResolvable;
7+
import org.springframework.http.HttpStatus;
8+
import org.springframework.http.ResponseEntity;
49
import org.springframework.http.converter.HttpMessageNotReadableException;
510
import org.springframework.web.HttpRequestMethodNotSupportedException;
11+
import org.springframework.web.bind.MethodArgumentNotValidException;
612
import org.springframework.web.bind.MissingServletRequestParameterException;
713
import org.springframework.web.bind.annotation.ExceptionHandler;
14+
import org.springframework.web.bind.annotation.ResponseStatus;
815
import org.springframework.web.bind.annotation.RestControllerAdvice;
16+
import org.springframework.web.method.annotation.HandlerMethodValidationException;
917
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
1018
import org.springframework.web.servlet.resource.NoResourceFoundException;
1119

20+
import java.util.List;
21+
1222
@Slf4j
1323
@RestControllerAdvice
14-
public class GlobalExceptionHandler{
24+
public class GlobalExceptionHandler {
1525
private static final String LOG_FORMAT = "\nException Class = {}\nResponse Code = {}\nMessage = {}";
1626

1727
/**
1828
* 비즈니스 로직에서 정의한 예외가 발생할 때 처리
1929
*/
2030
@ExceptionHandler(BusinessException.class)
21-
protected ErrorCode handleBusinessException(BusinessException e) {
31+
protected ErrorResponse handleBusinessException(BusinessException e) {
2232
ErrorCode errorCode = e.getErrorCode();
2333
logException(e, errorCode);
24-
return errorCode;
34+
return ErrorResponse.of(errorCode);
35+
}
36+
37+
/**
38+
* 횟수 제한 예외 처리 (Retry-After 헤더 추가)
39+
*/
40+
@ExceptionHandler(RateLimitException.class)
41+
protected ResponseEntity<ErrorResponse> handleRateLimitException(RateLimitException e) {
42+
ErrorCode errorCode = e.getErrorCode();
43+
logException(e, errorCode);
44+
45+
return ResponseEntity
46+
.status(HttpStatus.TOO_MANY_REQUESTS)
47+
.header("Retry-After", String.valueOf(e.getRetryAfter()))
48+
.body(ErrorResponse.of(errorCode));
2549
}
2650

2751
/**
2852
* 애플리케이션 전역에 문제되는 예외가 발생할 때 처리
2953
*/
3054
@ExceptionHandler(GlobalException.class)
31-
protected ErrorCode handleGlobalException(GlobalException e) {
55+
protected ErrorResponse handleGlobalException(GlobalException e) {
3256
GlobalErrorCode errorCode = e.getErrorCode();
3357
logException(e, errorCode);
34-
return errorCode;
58+
return ErrorResponse.of(errorCode);
3559
}
3660

3761
/**
3862
* 요청 매개변수의 타입이 잘못된 경우 발생
3963
*/
4064
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
41-
protected ErrorCode handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
65+
protected ErrorResponse handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
4266
GlobalErrorCode errorCode = GlobalErrorCode.UNSUPPORTED_PARAMETER_TYPE;
4367
logException(e, errorCode);
44-
return errorCode;
68+
return ErrorResponse.of(errorCode);
4569
}
4670

4771
/**
4872
* 잘못된 HTTP Method의 API를 호출할 때 발생
4973
*/
5074
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
51-
protected ErrorCode handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
52-
GlobalErrorCode errorCode = GlobalErrorCode.METHOD_NOT_ALLOWED;
75+
protected ErrorResponse handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
76+
GlobalErrorCode errorCode = GlobalErrorCode.REQUEST_METHOD_NOT_ALLOWED;
5377
logException(e, errorCode);
54-
return errorCode;
78+
return ErrorResponse.of(errorCode);
5579
}
5680

5781
/**
5882
* 존재하지 않는 API를 호출할 때 발생
5983
*/
6084
@ExceptionHandler(NoResourceFoundException.class)
61-
protected ErrorCode handleNoResourceFoundException(NoResourceFoundException e) {
85+
protected ErrorResponse handleNoResourceFoundException(NoResourceFoundException e) {
6286
GlobalErrorCode errorCode = GlobalErrorCode.RESOURCE_NOT_FOUND;
6387
logException(e, errorCode);
64-
return errorCode;
88+
return ErrorResponse.of(errorCode);
6589
}
6690

6791
/**
6892
* 필수 파라미터가 누락되었을 때 발생
6993
*/
7094
@ExceptionHandler(MissingServletRequestParameterException.class)
71-
protected ErrorCode handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
95+
protected ErrorResponse handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
7296
GlobalErrorCode errorCode = GlobalErrorCode.MISS_REQUIRED_REQUEST_PARAMETER;
7397
logException(e, errorCode);
74-
return errorCode;
98+
return ErrorResponse.of(errorCode);
7599
}
76100

77101
/**
78102
* 요청 body가 누락되었을 때 발생
79103
*/
80104
@ExceptionHandler(HttpMessageNotReadableException.class)
81-
protected ErrorCode handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
105+
protected ErrorResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
82106
GlobalErrorCode errorCode = GlobalErrorCode.MISS_REQUEST_BODY;
83107
logException(e, errorCode);
84-
return errorCode;
108+
return ErrorResponse.of(errorCode);
109+
}
110+
111+
/**
112+
* 요청 파라미터에 대한 유효성 검증 실패 시 발생
113+
*/
114+
@ExceptionHandler(HandlerMethodValidationException.class)
115+
public ErrorResponse handleHandlerMethodValidationException(HandlerMethodValidationException e) {
116+
GlobalErrorCode errorCode = GlobalErrorCode.METHOD_VALIDATION_FAILED;
117+
logException(e, errorCode);
118+
119+
List<String> errorMessages = e.getAllErrors().stream()
120+
.map(MessageSourceResolvable::getDefaultMessage)
121+
.toList();
122+
123+
return ErrorResponse.of(errorCode, errorMessages);
124+
}
125+
126+
/**
127+
* RequestBody에 대한 유효성 검증 실패 시 발생
128+
*/
129+
@ResponseStatus(HttpStatus.BAD_REQUEST)
130+
@ExceptionHandler(MethodArgumentNotValidException.class)
131+
public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
132+
GlobalErrorCode errorCode = GlobalErrorCode.METHOD_VALIDATION_FAILED;
133+
logException(e, errorCode);
134+
135+
List<String> errorMessages = e.getAllErrors().stream()
136+
.map(MessageSourceResolvable::getDefaultMessage)
137+
.toList();
138+
139+
return ErrorResponse.of(errorCode, errorMessages);
85140
}
86141

87142
/**
88143
* 예외 정보를 로깅 (ErrorCode 메시지 사용)
89144
*/
90145
private void logException(final Exception e, final ErrorCode errorCode) {
91-
log.error(LOG_FORMAT,
92-
e.getClass(),
93-
errorCode.getCode(),
94-
errorCode.getMessage());
146+
log.error(LOG_FORMAT, e.getClass(), errorCode.getCode(), errorCode.getMessage());
95147
}
96148
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.ject.support.common.response;
2+
3+
import lombok.AccessLevel;
4+
import lombok.AllArgsConstructor;
5+
import org.ject.support.common.exception.ErrorCode;
6+
import org.springframework.http.HttpStatus;
7+
8+
import java.util.List;
9+
10+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
11+
public class ErrorResponse {
12+
private ErrorCode code;
13+
private List<String> messages;
14+
15+
public static ErrorResponse of(ErrorCode code) {
16+
return new ErrorResponse(code, List.of(code.getMessage()));
17+
}
18+
19+
public static ErrorResponse of(ErrorCode code, List<String> messages) {
20+
return new ErrorResponse(code, messages);
21+
}
22+
23+
public HttpStatus getStatus() {
24+
return code.getHttpStatus();
25+
}
26+
27+
public String getCode() {
28+
return code.getCode();
29+
}
30+
31+
public List<String> getMessages() {
32+
return messages;
33+
}
34+
}

src/main/java/org/ject/support/common/response/ResponseWrapper.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.ject.support.common.response;
22

3-
import org.ject.support.common.exception.ErrorCode;
43
import org.springframework.core.MethodParameter;
54
import org.springframework.http.MediaType;
65
import org.springframework.http.converter.HttpMessageConverter;
@@ -30,8 +29,9 @@ public Object beforeBodyWrite(final Object body, final MethodParameter returnTyp
3029
}
3130

3231
// Error Response 반환
33-
if (body instanceof ErrorCode errorCode) {
34-
return new ApiResponse<>(errorCode.getCode(),errorCode.getMessage());
32+
if (body instanceof ErrorResponse errorResponse) {
33+
response.setStatusCode(errorResponse.getStatus());
34+
return new ApiResponse<>(errorResponse.getCode(), errorResponse.getMessages());
3535
}
3636

3737
// Success Response 반환

src/main/java/org/ject/support/common/security/CustomSuccessHandler.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import lombok.RequiredArgsConstructor;
66
import org.ject.support.common.security.jwt.JwtCookieProvider;
77
import org.ject.support.common.security.jwt.JwtTokenProvider;
8+
import org.springframework.http.HttpHeaders;
89
import org.springframework.security.core.Authentication;
910
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
1011
import org.springframework.stereotype.Component;
@@ -24,8 +25,8 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
2425
String accessToken = jwtTokenProvider.createAccessToken(authentication, customUserDetails.getMemberId());
2526
String refreshToken = jwtTokenProvider.createRefreshToken(authentication, customUserDetails.getMemberId());
2627

27-
response.addCookie(jwtCookieProvider.createRefreshCookie(refreshToken));
28-
response.addCookie(jwtCookieProvider.createAccessCookie(accessToken));
28+
response.addHeader(HttpHeaders.SET_COOKIE, jwtCookieProvider.createRefreshCookie(refreshToken).toString());
29+
response.addHeader(HttpHeaders.SET_COOKIE, jwtCookieProvider.createAccessCookie(accessToken).toString());
2930
}
3031

3132
/**
@@ -36,7 +37,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
3637
public void onAuthenticationSuccess(HttpServletResponse response, String email) {
3738
String verificationToken = jwtTokenProvider.createVerificationToken(email);
3839

39-
response.addCookie(jwtCookieProvider.createVerificationCookie(verificationToken));
40+
response.addHeader(HttpHeaders.SET_COOKIE, jwtCookieProvider.createVerificationCookie(verificationToken).toString());
4041
}
4142

4243
/**
@@ -48,6 +49,6 @@ public void onAuthenticationSuccess(HttpServletResponse response, String email)
4849
public void onAuthenticationSuccess(HttpServletResponse response, String refreshToken, Long memberId) {
4950
String newAccessToken = jwtTokenProvider.reissueAccessToken(refreshToken, memberId);
5051

51-
response.addCookie(jwtCookieProvider.createAccessCookie(newAccessToken));
52+
response.addHeader(HttpHeaders.SET_COOKIE, jwtCookieProvider.createAccessCookie(newAccessToken).toString());
5253
}
5354
}

0 commit comments

Comments
 (0)