Skip to content

Commit 6892f6e

Browse files
Darren4641kooscodarren
authored
staging -> main merge commit
* chore: spotless plugin 추가 * feat: build, format make 명령어 추가 * chore: makefile PHONY에 stop 명령어 추가 * chore: jpa, flyway 의존성 추가 * fix: make run, start SPRING_PROFILES 인자 추가 * feat: clear-h2 명령어 추가 * chore: app url, version 설정 추가 * chore: swagger config 추가 * feat: test용 controller 추가 * chore : swagger 메서드 파라미터 오타 수정 * Revert "feat: test용 controller 추가" This reverts commit 7efaebe. * Revert "chore : swagger 메서드 파라미터 오타 수정" This reverts commit bf91a99. * Revert "feat: test용 controller 추가" * chore: jdbc 의존성 제거 및 r2dbc 의존성 추가 * chore: local 개발용 postgres docker compose 추가 * chore: make h2-clear 명령어 삭제 * infra : terraform s3 module 추가 * infra : terraform aws provider 추가 * infra : terraform staging workspace 추가 * feat/#9 -> staging: Squash Merge * feat: User Entity 생성 및 UserPrincipal 세팅 * feat: ExceptionHandler 및 BaseResponse 세팅 * feat: Swagger 403/500 이슈 해결 및 auth 패키지 분리 * fix: spotlessApply * fix: @repository 제거 * fix: security 관련 설정 user 패키지로 이동 * fix: User Entity 및 repository 관련 파일 user 패키지로 이동 * fix: spotless 적용 --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * fix: Referer 보안 이슈 방지를 위해 Ip 기반 조건 설정 * apply code formatter * fix: s3 private preset versioning 비활성화 * fix: S3 public access 제거 * feat: transactionRunner 추가 * chore: S3 의존성 추가 * chore: local s3 test용 local stack container 추가 * feat: image storage 인터페이스 추가 * feat: S3 storage 구현체 추가 * feat: Cors 설정 추가 * test: local test용 object CRD API 추가 * fix: S3 초기화 로그 제거 * ref: cors 중복 설정 제거 * chore: api 계층으로 cors 설정 이동 * chore: code quality check pipeline 추가 * feat: 폴더, 포토 이미지 엔티티 추가 * feat: Jpa Auditing 설정 추가 * feat: Usecase 식별용 annotation 추가 * feat: jpa folder 영속성 Port 추가 * feat: folder 기본 API * docs: file API swagger schema 추가 * feat/#14 -> staging mrege commit * feat: User Entity 생성 및 UserPrincipal 세팅 * feat: ExceptionHandler 및 BaseResponse 세팅 * feat: Swagger 403/500 이슈 해결 및 auth 패키지 분리 * fix: spotlessApply * fix: @repository 제거 * fix: security 관련 설정 user 패키지로 이동 * fix: User Entity 및 repository 관련 파일 user 패키지로 이동 * fix: spotless 적용 * feat: Jasypt 설정 추가 * fix: application jasypt 적용 * fix: 암호화 알고리즘 변경 및 JasyptUtil 클래스 제거 * fix: spotlessApply --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * feat: 로컬 회원가입 api * fix: UserPrincipal 사용자 id 추가 * feat: PasswordEncoder config * chore: SecurityConfig 네이밍 변경 * feat: 로그인, 토큰 발급 api * feat: folder api converter 추가 * chore: 폴더명 변경 photobooth -> photo * apply spotless * feat: E2E Test용 Base 클래스 * feat: Folder E2E Test용 Base 클래스 * fix: test jasypt 설정 제거 * feat: test Media 구현체 추가 * ref: application layer에 맞게 Folder Port 메서드 시그니처 수정 * fix: 폴더 생성 중복 검사 로직 * fix: 폴더명 변경 중복 검사 * fix: 폴더 목록 조회 메서드 시그니처 변경 * fix: 폴더 목록 삭제 원자성 검증 * fix: 폴더 생성 응답 추가 * fix: 폴더 jpa 조회 메서드 추가 * fix: 일관성을 위해 ExceptionDto code 변수명 resultCode로 변경 * test: Folder API E2E Test 추가 * feat: 폴더 conflict code 추가 * fix: JasyptTest Spring 의존성 제거 * fix: r2dbc 설정 제거 * fix: jasypt 환경변수를 생성자 주입으로 변경 * chore: Media Aggregate 분리 * fix: DeleteFolder n+1 문제 해결 * fix: RequiresSecurity class Target 추가 * fix: Media 엔티티 추가 * Feat/#7 (#18) * feat: User Entity 생성 및 UserPrincipal 세팅 * feat: ExceptionHandler 및 BaseResponse 세팅 * feat: Swagger 403/500 이슈 해결 및 auth 패키지 분리 * fix: spotlessApply * fix: @repository 제거 * fix: security 관련 설정 user 패키지로 이동 * fix: User Entity 및 repository 관련 파일 user 패키지로 이동 * fix: spotless 적용 * feat: Jasypt 설정 추가 * feat: kakao oauth idToken 발급 로직 추가 (테스트용) * fix: UseCase 어노테이션 추가 및 디렉토리 구조 변경 * feat: kakao oauth oidc 추출 * feat: k3s 배포를 위한 Dockerfile 생성 * feat: 카카오 OIDC 회원가입 기능 구현 * feat: 예외 addMessage 메서드 제거 * refactor: signup -> register 네이밍 변경 * fix: transactionRunner 추가 * fix: spotless 적용 * fix: login 기능 구현 1차 * fix: refreshToken 발행 추가 * fix: refreshToken을 통해 accessToken 갱신 API 추가 * fix: JasyptConfig profile 지정 * feat: CustomerUserDetailService 제거 (불필요) * feat: spotless 적용 * feat: converter 적용 * feat: E2E TEST 코드 추가 * feat: E2E TEST 코드 추가 * fix: JasyptTest 테스트코드 yml 의존성 제거 * feat: ci discord 알림 추가 * ci: 빌드 최적화 * ci: k3s 강제 재시작 적용 * fix: kakao oauth nativeID로 변경 * ci: 배포후 downtime 0로 변경 (health check 추가) * fix: app.version 공통 application.yaml로 이동 * fix: JasyptUtil 파일 제거 * fix: RestClientConfig 파일 infra 디렉토리로 이동 * fix: OIDCPublicKeysResponse 변수 var -> val 변경 * fix: KakaoClientResponse 주석 제거 * fix: Valid 어노테이션 @field로 변경 * fix: contract 디렉토리 생성 후 response 이동 * fix: ci yaml staging 브랜치로 변경 * fix: spotlessApply 적용 --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * fix: oauth로그인 정책 변경 * fix: login관련 e2e 테스트코드 제거 * fix: spotless 적용 * fix: test코드 임시 제거 * test: HttpStatus 변경 * fix: acceess, refresh Token 만료 시간 변경 * chore: querydsl 설정 * chore: flyway 비활성화 * Feat/#23 (#24) * chore: logstach encoder 의존성 * chore: logback 설정 * feat: 요청 MDC Filter * feat: 인증 MDC Filter * chore: SecurityFilterChain MDC Filter 추가 * fix: RequestMdcFilter가 가장 먼저 오도록 순서 보장 * fix: AuthMdcFilter name 대신 userId 로깅 * fix: 로그에 Ip 정보 추가 * fix: 로그에 Ip 정보 삭제 * Fix/#44 카카오 OIDC 공개키 캐싱 처리 (#46) * fix: 카카오 OIDC PublicKey Cache 적용 * fix: spotless 적용 * fix: Cache 관련 클래스 Adapter 적용 * fix: spotless 적용 * refactor: cachePort 도메인 하위 infra 레이어로 이동 * fix: spotless 적용 --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * fix: AuthFilter Authentication type 변경, 테스트 수정 * feat/#28 -> staging merge commit * feat: base time entity * feat: photo domain entity 추가 * feat: jpa auditing config 추가 * feat: PhotoImage UseCase 추가 * feat: PhotoImage persist jpa 구현체 추가 * feat: Local Media Client 구현체 추가 * feat: Media UseCase 추가 * feat: Media infra 계층 구현체 추가 * feat: RequiresSecurity class level target 추가 * feat: file upload fail result code 추가 * feat: usecase 애노테이션 추가 * feat: folder, photo, media flyway schema * chore: S3 구현체를 infra/storage/s3로 분리 * fix: jasypt config test profile 비활성화 * test: test profile 지정 * fix: S3 presigned 만료시간, contentType 추가 * test: PhotoImage E2E Test 추가 * fix: PhotoController bean validation 추가 * test: PhotoImageE2ETestBase 추가 * chore: rest assured 의존성 추가 * fix: AuthTokenProvider jwt에 providerType String을 저장하도록 수정 * feat: FakeMediaStorage 구현체 추가 * feat: JpaPhotoImage 목록 조회 구현 * fix: Jwt 검증 실패시에도 계속 진행되도록 수정 * fix: mediaId null이 0으로 casting되는 오류 수정 * docs: media swagger 추가 * chore: GenerateUploadTicketUseCase 불필요 주석 삭제 * fix: DeleteMediaUseCase cache 무효화 로직 추가 * ref: DeleteFolder 검증 로직 개선 * fix: testcode resultCode 수정 * fix: 401 E2ETest 삭제 * fix: memo 추가 * apply spotless * chore: 사용하지 않는 메서드 제거 * fix: UploadPhotoE2ETest memo 추가 * feat: photoImage Patch API * ref: 사진 목록 조회 paging 처리 * ref: Folder 삭제 query를 querydsl로 변경 * chore: 사용하지 않는 메서드 정리 * ref: photo domain contract 파일 분리 * feat: PhotoImage dynamic update 추가 * fix: 사진 등록 후 INITIAL media를 포함하여 조회 * test: 사진 업로드 e2e test * fix: 사진 extension이 저장되지 않는 문제 수정 * fix: photo 저장 실패시 롤백 * chore: staging S3 bucket 변경 * fix: 이미지 조회 contentType 필드 추가 * feat/#47 -> staging merge commit * feat: Apple OIDC 로그인 추가 * fix: staging merge * fix: 스웨거 주석 수정 * fix: oidc 검증 로직 Port로 분리 * fix: Port 제거 후 infra Layer에서 interface로 타입 통일 * fix: User엔티티 email Unique 제거 * fix: BaseResponse 공통 규격화 * fix: oauth 최초 로그인시만 DB저장 --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * test: e2e 테스트 코드 BaseResponse success 체킹 제거 * feat/#56 -> staging merge commit * docs: CLAUDE.md 추가 * docs: TESTING.md 추가 * chore: 사용하지 않는 문서 제거 * feat/#59 -> staging merge commit * fix: AppProperties를 common 패키지로 이동 * fix: photo image 조회시 url을 내려주도록 수정 * feat: 이미지 조회 endpoint 추가 * test: 이미지 조회 endpoint 테스트 * chore: 클로드가 하위 문서를 반드시 읽도록 CLAUDE.md 수정 * fix/#29 -> staging merge commit fix: 폴더명 validation 적용 * feat/#43 -> merge commit * fix: 카카오맵 기반 위경도 수집 API 1차 개발 완료 (리펙토링 전) * fix: 애플로그인으로 인핸 oid Type String 으로 변경 * fix: 그리드방식으로 좌표 수집 * fix: Port, Adapter 적용 * fix: API 제한을 방지한 Delay 코드 추가 * fix: 내 위치기준 부스 조회, 다각형 내 부스 조회 개발 (브랜드 필터링은 추후 추가) * fix: 부스 위치 조회(다각형, 내위치) brandId 별 필터링 추가 * feat: Brand 조회 API 추가 * test: E2E Test 코드 추가 * fix: spotless 적용 * fix: 클래스명 변경 KakaoApiClient -> MapApiClient * fix: media queryDsl 제거 * fix: MediaType LOGO 추가 * fix: collectPhotoBooths API 컨벤션 * fix: collectPhotoBooths API Hidden 처리 * fix: 메서드명 변경 kakaoSearchByKeyword -> searchByKeyword * fix: SQL code formatter 적용 * fix: MapApiClient 구조 Clean Architecture 적용 * fix: postgis docker-compose 실행 추가 * fix: MapContract 클래스 Kakao 네이밍 hidden 처리 * fix: 한국 위경도 domain layer vo로 이동 * fix: CollectPhotoBoothLocationUseCase 트랜잭션 분리 * refactor: CollectPhotoBoothLocationUseCase 로직 분리 * refactor: 이미지 경로 Converter 수행 * fix: MediaClientPort 추가 * refactor: VO 클래스 수정 * refactor: MapVo 리펙토링 * refactor: 클래스명 명확화 * fix: KakaoApiRateLimitConfig -> KakaoApiRateLimitProperties 클래스명 수정 * fix: 부스 조회 API Coordinate 타입으로 변경 * fix: spotless 적용 * fix: 네이밍에 VO 키워드 제거 * fix: jasyptGeneratTest -> jasyptGenerateTest 오타 수정 --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * feat/#35 -> staging merge commit * feat: 즐겨찾기 기능 및 페이징/정렬 구현 - 사진 즐겨찾기 추가/삭제/조회 API 구현 - 사진 목록 페이징 처리 - 정렬 순서(ASC/DESC) 지원 - E2E 테스트 추가 * fix: CLAUDE.md success 필드 삭제 * feat: 즐겨찾기 summary API 추가 * fix: 사진 삭제시 즐겨찾기 사진도 함께 삭제 * docs: CLAUDE.md batch delete에 대한 지침 추가 * docs: test base와 tear down 지침 추가 * fix: photo image command 페이징 기본값 삭제 * fix: 즐겨찾기 중복 저장 멱등성 로직 수정 * chore: apply spotlessApp * chore/#63 -> staging merge commit fix: entity 테이블명 대문자로 변경 * fix/#66 -> staging merge commit * fix: 부스 위치 조회 Paging 삭제 * fix: getPhotoBoothsByPoint API 좌표 nullable 기본값=강남역 * fix: 지도 응답 변수명 수정 brandId -> brandName, name -> branchName * fix: test 코드 Page 관련 변수 제거 * fix: Native Query 테이블명 대문자로 수정 * fix: getPhotoBoothsByPoint API Default 값 Converter에서 수행 * feat/#58 -> staging merge commit * ref: Media api Dto 파일 통합 * test : 사진 여러 장 업로드 테스트 * feat : Media application dto * ref : presigned upload ticket api 통합 * ref : UploadTicket 계약을 별도 파일로 분리 * test : 벌크 presigned e2e test 단일 테스트로 통합 * ref : PhotoImage 생성 로직 통합 (개별 + 벌크) * fix : UploadTicket test 변수명 동기화 * fix : 사진 생성시 하나의 folderId만 받도록 수정 * ref : 통합된 UploadTicket 결과 반환 방식 수정 * refactor : media upload 엔드포인트 수정 * ref : ConfirmMediaUploadedUseCase 벌크 처리로 수정 * ref : GenerateUploadTicketUseCase.kt transactional 애노테이션 추가 * chore: github-ci 추가, deploy 단계 test 제거 * feat/#74 -> staging merge commit * feat: 사진 상세 조회 API * fix : 이미지 목록 조회 folderId 삭제 * ref : 사진 목록 조회 쿼리 개선 * chore: code formatter * chore: 즐겨찾기용 조회 dto 추가 * feat: PhotoMediaClient 미디어 단건 조회 메서드 추가 * fix: 사진 상세 순환 호출 문제 수정 * test : 사진 상세 조회 api e2e test 추가 * ref : PhotoImageQueryRepository.kt query 개선 * fix : 사진 업로드 시 폴더 소유권 검사 * fix/#65 -> staging merge commit * ref/#69-> staging merge commit * fix: Json 날짜 포맷 통일 * ref: 사진 삭제 API 통합 (단건, 다중) * ref: 폴더 삭제 API 통합 (단건, 다중) * fix : 사용하지 않는 folder delete 관련 메서드 제거 * fix : folder 삭제시 image의 folder_id null 처리 * fix : photo 도메인 usecase 이름을 복수형으로 수정 * docs : 사용하지 않는 DeleteMediaUseCase.kt 주석 추가 * docs/#71 -> staging merge commit * docs: Swagger 공통 예외 문구 수정 * docs: Swagger 공통 예외 문구 수정 (500 Code 문서 제거) * fix: Response 값 @Schema 어노테이션 추가 * fix: Response 값 @Schema 어노테이션 추가 * fix: Spotless 적용 * fix: 토큰 MISSING 예외 처리 및 EntryPoint 컴포넌트 클래스 생성, ObjectMapper 사용하여 Error메시지 반환 --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * fix/#77 -> staging merge commit * fix: Validate 검증 활성화를 위해 Request 객체 ? 인자 추가 * fix: security handler 추가 * fix: TestCode 수정사항 반영 * fix: TestCode 수정사항 반영 --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * fix/#83 -> staging merge commit * chore: UpdatePhotoFavoriteRequest.kt 파일 통합 * fix : 폴더 목록 API에 사진 개수, 커버 사진 포함 * fix : 사진 삭제, 생성 시 폴더 커버 사진 업데이트 * chore : 폴더 커버 flyway schema 반영 * fix : 사진 목록 조회시 폴더 조건 추가 * ref : 폴더 목록 조회 쿼리 개선 * test : 폴더 커버 갱신 test 추가 * docs: presigned url 주석의 api endpoint 수정 * fix: folder 커버 이미지 생성 시간 제거 * fix: 조회 시점에 앨범 커버 이미지를 조인하도록 수정 * fix: 사용하지 않는 메서드 제거 * fix: 즐겨찾기 이미지 url을 usecase에서 분리 * fix: Folder storageKey 변수명 통일 * fix: PhotoImageQueryRepository.kt 미사용 코드 제거 * fix/#82-> staging merge commit * feat: Pose 업로드 (ADMIN 권한 체크) * feat: MediaType POSE 항목 추가 * feat: 포즈 목록 API 개발 * feat: 인원수 필터링 추가 * fix: 이미지 업로드 시 userId 필수로 설정 * feat: 포즈 스크랩 기능 개발 * feat: 포즈 스크랩 기능 개발 Swagger desc 추가 * feat: 포즈 상세보기 기능 개발 * feat: 랜덤 포즈 기능 개발 * refactor: rollbackIfFailed private method 분리 * test: 포즈 관련 E2E 테스트 코드 작성 * feature: 개발 admin cors 추가 * fix: ScrapPoseController 주석 name 변경 * fix: 변수명 수정 isScrap -> isScraped * fix: PoseMediaClient 주석 이름 수정 * fix: Pose 어그거트에서 사용할 Media Contract 생생 * fix: flyway TB_SCRAP_POSE DDL 쿼리 추가 * fix: UseCase Random추출 메서드 분리 * fix: Pose DTO 파일명 수정 GetPoseResponse * fix: upload만 admin 권한 * fix: toGetPoseResponse 객체 재사용 --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * fix/#92 -> staging merge commit * fix: 즐겨찾기 요약이 즐겨찾기한 최근 사진을 조회하도록 수정 * ref: 폴더 목록 조회 쿼리 개선 * ref: 폴더 목록 조회 쿼리 롤백 * feat/#84 -> staging merge commit * chore: UpdatePhotoFavoriteRequest.kt 파일 통합 * fix : 폴더 목록 API에 사진 개수, 커버 사진 포함 * fix : 사진 삭제, 생성 시 폴더 커버 사진 업데이트 * chore : 폴더 커버 flyway schema 반영 * fix : 사진 목록 조회시 폴더 조건 추가 * ref : 폴더 목록 조회 쿼리 개선 * test : 폴더 커버 갱신 test 추가 * docs: presigned url 주석의 api endpoint 수정 * fix: folder 커버 이미지 생성 시간 제거 * feat: 폴더에서 사진 제외 기능 추가 * fix: 사용하지 않는 메서드 제거 * test: 사진 삭제 후 조회 시점에서 커버 사진을 확인하도록 테스트 수정 * ref: 폴더 삭제시 사진을 삭제하지 않는 경우 분기 처리 * feat/#89 -> staging merge commit * feat: 앱 버전 관리 API 기능 개발 * feat: 클래스 주석 추가 * fix: spotless 적용 * feat/#93 -> staging merge commit * fix: 포즈 추천시 인원수 필터링 * test: test 코드 수정 * feat: 1차 작업 * fix: 포즈 스크랩 오동작 수정 및 포즈 스크랩 목록 조회 개발 --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * feat/#85 -> staging merge commit * chore: user domain dto 패키지명 통일 * feat: media domain 이미지 조회 후 업로드 usecase 추가 * feat: 사용자 정보 갱신 API * feat: 회원가입시 임의 닉네임 생성 * fix: 이미지 업로드 제거 * fix: 사용자 정보 조회 API 프로필 이미지 포함 * docs: user 도메인 swagger 스키마 추가 * fix: 사용자 프로필 이미지 검증 로직 추가 * fix: 사용자 프로필 이미지가 storageKey를 사용하게 수정 * fix: 기본 프로필 이미지 설정 추가 * docs: 사용자 정보 갱신 swagger docs 수정 * feat#/97 -> staging merge commit * feat#/96 -> staging merge commit * feat: application-prod.yaml 생성 및 flyway 싱크 * fix: user 테이블 email, oid nullable flyway 적용 및 code formmater 적용 * fix/#100 -> staging merge commit * chore: local profile kakak api key 추가 * chore: user domain request 파일 병합 * chore: 사용하지 않는 메서드, 파일 삭제 * fix: 사용자 정보 수정, 프로필 이미지 수정 API 분리 * fix: 사용자 프로필 기본 이미지 설정 로직 추가 * fix: 사용자 프로필 수정 멱등성 반영 * test: 사용자 프로필 변경 테스트 추가 * fix/#102 -> staging merge commit * fix: 소셜로그인 providerType 타입 String으로 변경 (대소문자 모두 허용을 위해) * fix: enum클래스 from 메서드 추가 * fix: staging flyway 활성화 * fix/#106 -> staging merge commit * fix: 카카오 로그인 시 platform 파람 추가 할당 * fix: 프론트 검증을 위해 임시 배포 * fix: spotless 적용 * fix: 엑세스, 리프레쉬 토큰 expiry 변경 * fix: deploy-staging.yml fix/#106 브랜치 제거 * fix: auth Platform enum으로 타입 세이프 --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * fix/#109 -> staging merge commit fix: Brand 목록조회 id 오름차순으로 변경 * chore/#104 -> staging merge commit * chore: Prod 환경 자동화 배포 추가 * chore: 프로메테우스 적용 * feat: cors 추가 * fix: deploy-prod.yml chore/#104 브런치 제거 * fix: healchcheck 인증된 사용자만 상세 정보 확인 * fix: actuator 사용하는 경로만 허용 * fix: deploy-prod.yml chore/#104 브랜치 제거 * fix/#105 -> staging merge commit * fix: 사용자 닉네임 최대 글자 수정 * fix: 사용자 닉네임 제약 조건 추가 * fix: 닉네임 제약 조건 메시지 수정 * chore: 닉네임 flyway 제약 조건 버전 추가 * feat: 포즈목록 조회시 scrap 여부 반환 * fix/#116 -> staging merge commit * feat: 약관 목록 및 약관 동의 개발 * fix: 약관 목록 조회시 버전 컬럼 제거 * fix: Gemini 성능 개선 반영 * fix: 중복 정렬 코드 제거 * fix/#119 -> staging merge commit * fix: 랜덤포즈 조회시 excludeIds 추가 * fix: 랜덤포즈 조회할 포즈 없을 시 문구 수정 * test: 테스트 코드 수정 * chore/#122 -> staging merge commit Co-authored-by: darren <darren@darrenui-MacBookPro.local> * fix/#125 -> staging merge commit * fix: media 생성시 width, height 입력 받기 * fix: 포즈 상세 및 랜덤포즈 오동작 문제 해결 (관리자 계정만 동작했었음) --------- Co-authored-by: darren <darren@darrenui-MacBookPro.local> * fix/#128 -> staging merge commit fix: : presignedURL 업로드 시 media 엔티티 size 추가 저장 (#129) * chore/#130 -> staging merge commit chore: iOS 개발/상용 키 분리 (#131) * feat/#120 -> staging merge commit * feat: 이미지 조회를 위한 분산락 추가 * feat: redis media 캐시 어댑터 추가 * ref: 메서드 시그니처 변경에 따른 media fake 구현체 메서드 수정 * chore: 사용하지 않는 클래스 제거 * feat: media 조회 usecase 분산락 추가 * feat: redis binary template 추가 * feat: async config 추가 * fix: Redis 분산락 test profile 추가 * fix: media S3 fallback 후 cache 재확인 * fix: RedisMediaBinaryCacheAdapter nullable type 수정 * fix: media 캐시 ttl 만료 전 expire로 갱신하도록 수정 * fix: async 설정 제거 * fix: media type별 캐시 ttl 적용 * fix: 분산락 single-flight 제거 --------- Co-authored-by: Koo <koosco136@gmail.com> Co-authored-by: Teahyung Koo <150074724+koosco@users.noreply.github.com> Co-authored-by: darren <darren@darrenui-MacBookPro.local>
1 parent f738a89 commit 6892f6e

File tree

57 files changed

+1339
-107
lines changed

Some content is hidden

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

57 files changed

+1339
-107
lines changed

src/main/kotlin/com/yapp2app/auth/infra/oauth/OidcTokenValidator.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,10 @@ class OidcTokenValidator(
4242
// 1차 시도: 캐시된 공개키로 토큰 검증
4343
validateTokenWithPublicKeys(idToken, oidcAdapter, oauthHelperAdapter, platform)
4444
} catch (e: BusinessException) {
45-
log.info("Kakao OIDC token expired. 갱신 로직")
4645
// 캐시 무효화 후 재시도
4746
authRedisCacheAdapter.clearPublicKeys(AuthCacheKeys.KAKAO_OIDC_KEY)
4847
validateTokenWithPublicKeys(idToken, oidcAdapter, oauthHelperAdapter, platform)
4948
} catch (e: Exception) {
50-
e.printStackTrace() // TODO 인증 실패 예외 로그 모니터링용
5149
throw e
5250
}
5351
}

src/main/kotlin/com/yapp2app/common/config/RedisCacheConfig.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.springframework.context.annotation.Configuration
66
import org.springframework.data.redis.connection.RedisConnectionFactory
77
import org.springframework.data.redis.core.RedisTemplate
88
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer
9+
import org.springframework.data.redis.serializer.RedisSerializer
910
import org.springframework.data.redis.serializer.StringRedisSerializer
1011

1112
/**
@@ -48,4 +49,31 @@ class RedisCacheConfig(private val objectMapper: ObjectMapper) {
4849

4950
return template
5051
}
52+
53+
/**
54+
* 이미지 바이너리 데이터 전용 RedisTemplate
55+
* - Key: String 직렬화
56+
* - Value: ByteArray 직렬화 (JSON 직렬화 시 타입 변환 문제 발생)
57+
*
58+
* ByteArrayRedisSerializer 사용으로:
59+
* - 바이너리 데이터를 그대로 저장/조회
60+
* - 타입 변환 없이 ByteArray로 직접 반환
61+
* - 캐시 정상 동작
62+
*/
63+
@Bean
64+
fun binaryRedisTemplate(redisConnectionFactory: RedisConnectionFactory): RedisTemplate<String, ByteArray> {
65+
val template = RedisTemplate<String, ByteArray>()
66+
template.connectionFactory = redisConnectionFactory
67+
68+
// Key는 String으로 직렬화
69+
template.keySerializer = StringRedisSerializer()
70+
template.hashKeySerializer = StringRedisSerializer()
71+
72+
// Value는 ByteArray로 직렬화 (이미지 바이너리 데이터)
73+
val byteArraySerializer = RedisSerializer.byteArray()
74+
template.valueSerializer = byteArraySerializer
75+
template.hashValueSerializer = byteArraySerializer
76+
77+
return template
78+
}
5179
}

src/main/kotlin/com/yapp2app/common/exception/handler/ExceptionHandler.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class ExceptionHandler {
3030

3131
@ExceptionHandler(BusinessException::class)
3232
fun businessExceptionHandler(ex: BusinessException): ResponseEntity<ExceptionMsg> {
33-
log.error("{} message = {}", ex.resultCode.code, ex.resultCode.message)
33+
log.error("[BUSINESS_ERROR] code={} | message={}", ex.resultCode.code, ex.resultCode.message)
3434

3535
if (ex.resultCode == ResultCode.INVALID_TOKEN_ERROR) {
3636
return ResponseEntity(
@@ -55,7 +55,7 @@ class ExceptionHandler {
5555

5656
@ExceptionHandler(Exception::class)
5757
fun exceptionHandler(ex: Exception): ResponseEntity<ExceptionMsg> {
58-
log.error("No Handler ex message = {}", ex)
58+
log.error("[SYSTEM_ERROR] unhandled exception", ex)
5959

6060
val temp = ResponseEntity(
6161
ExceptionMsg(
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.yapp2app.common.filter
2+
3+
import jakarta.servlet.FilterChain
4+
import jakarta.servlet.http.HttpServletRequest
5+
import jakarta.servlet.http.HttpServletResponse
6+
import org.slf4j.LoggerFactory
7+
import org.slf4j.MDC
8+
import org.springframework.web.filter.OncePerRequestFilter
9+
10+
/**
11+
* API 요청의 수명주기(응답 시간, 상태 코드)를 로깅하는 필터.
12+
* RequestMdcFilter 이후에 실행되어 MDC 컨텍스트(requestId, userId)를 활용한다.
13+
*
14+
* JSON 로그: message는 간결하게, 상세 정보는 MDC 필드(durationMs, responseStatus, logCategory)로 분리.
15+
* 콘솔 로그: [API_REQUEST] POST /api/auth/kakao/login | status=200 | duration=342ms
16+
*/
17+
class RequestLoggingFilter : OncePerRequestFilter() {
18+
19+
private val log = LoggerFactory.getLogger(javaClass)
20+
21+
override fun doFilterInternal(
22+
request: HttpServletRequest,
23+
response: HttpServletResponse,
24+
filterChain: FilterChain,
25+
) {
26+
val startTime = System.currentTimeMillis()
27+
28+
try {
29+
filterChain.doFilter(request, response)
30+
} finally {
31+
val duration = System.currentTimeMillis() - startTime
32+
val status = response.status
33+
34+
MDC.put("logCategory", "API_REQUEST")
35+
MDC.put("durationMs", duration.toString())
36+
MDC.put("responseStatus", status.toString())
37+
38+
log.info("[API_REQUEST]")
39+
40+
MDC.remove("logCategory")
41+
MDC.remove("durationMs")
42+
MDC.remove("responseStatus")
43+
}
44+
}
45+
46+
override fun shouldNotFilter(request: HttpServletRequest): Boolean {
47+
val uri = request.requestURI
48+
return uri.startsWith("/actuator") ||
49+
uri.startsWith("/swagger-ui") ||
50+
uri.startsWith("/v3/api-docs") ||
51+
uri.startsWith("/file")
52+
}
53+
}

src/main/kotlin/com/yapp2app/common/filter/ServletFilterConfig.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ class ServletFilterConfig {
1919

2020
@Bean
2121
fun requestMdcFilterRegistration(filter: RequestMdcFilter): FilterRegistrationBean<RequestMdcFilter> =
22+
FilterRegistrationBean(filter).apply {
23+
order = SecurityProperties.DEFAULT_FILTER_ORDER - 2
24+
}
25+
26+
@Bean
27+
fun requestLoggingFilter(): RequestLoggingFilter = RequestLoggingFilter()
28+
29+
@Bean
30+
fun requestLoggingFilterRegistration(filter: RequestLoggingFilter): FilterRegistrationBean<RequestLoggingFilter> =
2231
FilterRegistrationBean(filter).apply {
2332
order = SecurityProperties.DEFAULT_FILTER_ORDER - 1
2433
}

src/main/kotlin/com/yapp2app/media/api/converter/MediaCommandConverter.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class MediaCommandConverter {
2121
filename = item.filename!!,
2222
contentType = item.contentType!!,
2323
mediaType = item.mediaType!!,
24+
width = item.width,
25+
height = item.height,
26+
size = item.size,
2427
)
2528
},
2629
)

src/main/kotlin/com/yapp2app/media/api/dto/UploadTicketRequest.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.yapp2app.media.api.dto
22

33
import com.yapp2app.media.domain.MediaType
4+
import io.swagger.v3.oas.annotations.media.Schema
45
import jakarta.validation.Valid
56
import jakarta.validation.constraints.NotBlank
67
import jakarta.validation.constraints.NotEmpty
@@ -20,13 +21,25 @@ data class UploadTicketRequest(
2021
val items: List<UploadTicketItem>,
2122
) {
2223
data class UploadTicketItem(
24+
@field:Schema(description = "파일명", example = "abc.png")
2325
@field:NotBlank(message = "파일명은 필수 입력값입니다.")
2426
val filename: String?,
2527

28+
@field:Schema(description = "ContentType", example = "image/png")
2629
@field:NotBlank(message = "Content type은 필수 입력값입니다.")
2730
val contentType: String?,
2831

32+
@field:Schema(description = "미디어타입", example = "PHOTO_BOOTH")
2933
@field:NotNull(message = "미디어 타입은 필수 입력값입니다.")
3034
val mediaType: MediaType?,
35+
36+
@field:Schema(description = "너비", example = "1920")
37+
val width: Int? = null,
38+
39+
@field:Schema(description = "높이", example = "1080")
40+
val height: Int? = null,
41+
42+
@field:Schema(description = "byte 단위", example = "2048576")
43+
val size: Long? = null,
3144
)
3245
}

src/main/kotlin/com/yapp2app/media/application/command/MediaCommand.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ import com.yapp2app.media.domain.MediaType
1111
data class ConfirmMediasUploadedCommand(val ownerId: Long, val mediaIds: List<Long>)
1212

1313
data class GenerateUploadTicketCommand(val ownerId: Long, val items: List<UploadTicketItem>) {
14-
data class UploadTicketItem(val filename: String, val contentType: String, val mediaType: MediaType)
14+
data class UploadTicketItem(
15+
val filename: String,
16+
val contentType: String,
17+
val mediaType: MediaType,
18+
val width: Int? = null,
19+
val height: Int? = null,
20+
val size: Long? = null,
21+
)
1522
}
1623

1724
data class DeleteMediaCommand(val ownerId: Long, val mediaId: Long)
@@ -22,6 +29,6 @@ data class GetMediasCommand(val ownerId: Long, val mediaIds: List<Long>)
2229

2330
data class GetImageByKeyCommand(val objectKey: String)
2431

25-
data class GetMediaStorageInfoCommand(val ownerId: Long, val mediaId: Long)
32+
data class GetMediaStorageInfoCommand(val ownerId: Long?, val mediaId: Long)
2633

2734
data class GetMediaStorageInfosCommand(val ownerId: Long?, val mediaIds: List<Long>)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.yapp2app.media.application.port
2+
3+
import java.time.Duration
4+
5+
/**
6+
* 분산 락 포트
7+
*
8+
* 여러 인스턴스 간 동시성 제어를 위한 분산 락 인터페이스입니다.
9+
*/
10+
interface DistributedLockPort {
11+
12+
fun <T> executeWithLock(key: String, ttl: Duration, action: () -> T): T?
13+
}

src/main/kotlin/com/yapp2app/media/application/port/MediaBinaryCachePort.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.yapp2app.media.application.port
22

3+
import java.time.Duration
4+
35
/**
46
* fileName : MediaBinaryCachePort
57
* author : koo
@@ -10,7 +12,7 @@ interface MediaBinaryCachePort {
1012

1113
fun get(key: String): ByteArray?
1214

13-
fun put(key: String, value: ByteArray)
15+
fun put(key: String, value: ByteArray, ttl: Duration)
1416

1517
fun evict(key: String)
1618
}

0 commit comments

Comments
 (0)