증상상품 이미지 업로드 시 POST/PUT 요청이 403으로 실패. S3 에러 바디에는 SignatureDoesNotMatch 표기.원인presign 시 >(캐시 제어)을 포함해 서명했지만, 실제 PUT 업로드 요청 헤더에 동일 헤더를 넣지 않아 서명에 사용한 헤더와 실제 요청 헤더가 불일치.해결 방법presigned PUT URL을 내려줄 때 클라이언트가 반드시 포함해야 하는 모든 헤더(예: >, >, 필요한 헤더)를 함께 반환하고, 프론트는 해당 헤더를 그대로 넣어 업로드 수행.결과동일 키/파일에서도 403 재발 없음. 업로드 후 객체 조회 정상.
오늘 한 일 요약상품 등록: ⟨⟨name, price, categoryId, imageKey, status(on_sale|stop), initialQuantity⟩⟩를 받아 ⟨⟨Product⟩⟩·⟨⟨Inventory⟩⟩·⟨⟨InventoryLog(INIT, delta=+initialQuantity)⟩⟩를 한 트랜잭션으로 생성했다.이미지 등록: 프론트가 ⟨⟨GET /api/images/presign?contentType={MIME}⟩⟩으로 presigned PUT URL을 받아 S3에 직접 업로드하며, 키는 ⟨⟨{prefix}/{yyyy}/{MM}/{uuidNoHyphen}.{ext}⟩⟩ 규칙·만료 5분·헤더(Content-Type/Cache-Control) 일치로 운영한다. 상품 등록개요관리자 전용 상품..
오늘 한 일 요약> AOP로 모든 서비스 C · U · D 메서드 성공 시 audit.log에 기록하고, MDC에 userId 저장카테고리 삭제 시 하위가 있으면 > (409) 반환, 단건 · flat · tree 조회 완료 (2단계 트리는 id-map 방식)감사로그 시스템 구축 개요AOP 기반 ⟨⟨AuditLogger⟩⟩를 도입해 도메인에 상관없이 모든 서비스 레이어의 C/U/D 메서드 실행 결과를 단일 파일 (audit.log) 로 기록한다. 로그마다 MDC에 userId를 넣어 **‘누가 무엇을 했는지’**를 즉시 추적할 수 있다.고민한 점컨트롤러가 호출한 public 서비스 메서드만 선별하는 방법메서드 명 패턴(C/U/D)으로 대상 필터링 시 누락·과포착 방지감사로그 전용 파일만 별도로 남기면서 ..
서비스 계층에서 create · update · delete가 끝날 때마다 “” 로그를 남기는 전략을 AOP와 MDC 두 가지만으로 구현한다.기술핵심 역할Spring AOP (AspectJ)메서드 실행을 가로채 로깅 로직 주입MDC (Mapped Diagnostic Context)로그마다 사용자 ID 등 컨텍스트 유지Spring AOP - 메서드 가로채기Pointcut> 같이 메서드 시그니처 패턴으로 타깃 지정 세 가지 메서드만 잡는다Advice> : 정상 리턴 시점에만 동작—예외가 터지면 실행하지 않는다핵심 코드@AfterReturning( pointcut = "execution(public * com.khmall..*Service.create*(..)) || " + "e..
오늘 한 일 요약 카테고리 생성 — > 구현, 상위 존재·이름 중복 검증 후 > 기본 0으로 저장.카테고리 수정 — > 구현, > 로 부분 업데이트 지원·깊이 / 중복 예외 처리.테스트 환경 분리 — > 베이스 + JUnit 확장으로 모든 테스트를 > 프로필로 강제. 카테고리 생성개요> 엔드포인트를 구현해 최상위·하위(1 단계) 카테고리를 등록할 수 있게 했다.입력 필드: >, > (nullable), > (nullable·기본값 0).고민한 점전달된 >가 실제로 존재하는지 서비스 레이어에서 검증할 방법.카테고리 이름 중복을 어떤 범위(전역 vs 동일 부모)에서 제한할지 기준 설정.검증 실패 시 예외를 어디서 던지고 어떤 HTTP 상태로 변환할지.>를 요청에 포함하지 않으면 어떤 값으로 저장할지(디폴트 ..
JsonNullable 이란?RESTful API에서 ⟨⟨PATCH⟩⟩ 요청을 사용할 때, 필드의 “명시적 null”과 “미입력”을 구분해야 할 때가 많다.⟨⟨JsonNullable⟩⟩은 바로 이 문제를 해결하는 Java용 제네릭 래퍼 클래스다.일반적인 DTO 필드는 null이면 “값을 비우는 것”과 “아예 값을 건드리지 않는 것”이 구분되지 않는다.⟨⟨JsonNullable⟩⟩을 사용하면입력 없음: ⟨⟨JsonNullable.undefined()⟩⟩입력값 있음: ⟨⟨JsonNullable.of(값)⟩⟩명시적 null: ⟨⟨JsonNullable.of(null)⟩⟩식으로 3가지 상태를 구분할 수 있다. 특징DTO 필드의 "입력 없음"과 "명시적 null"을 완전히 분리주요 메서드⟨⟨isPresent()..