Skip to content

[web-33] 관리자 메인 로고 수정 API 구현#40

Open
Chunwol wants to merge 5 commits into
developfrom
feature/web-33
Open

[web-33] 관리자 메인 로고 수정 API 구현#40
Chunwol wants to merge 5 commits into
developfrom
feature/web-33

Conversation

@Chunwol
Copy link
Copy Markdown
Member

@Chunwol Chunwol commented May 24, 2026

이전 PR 리뷰 참고: #14

작업 내용

관리자 페이지에서 메인 페이지 로고 이미지를 수정할 수 있는 API를 구현합니다.
파일 업로드는 클라이언트가 Presigned PUT URL로 MinIO에 직접 업로드하는 방식을 사용합니다.
서버는 파일을 받지 않고, 업로드 완료 후 전달받은 objectKey로 URL을 저장합니다.

변경 사항

  • FileController 추가: GET /api/v1/files/upload-url — Presigned PUT URL 발급
  • PresignedUploadResponseDto 추가: uploadUrl, objectKey 필드
  • MinioConfig 추가: application.ymlminio.* 프로퍼티 바인딩, MinioClient Bean 등록
  • MinioService 추가: generateUploadUrl(), generateDownloadUrl(), getObjectUrl(), deleteFile(), extractObjectKey()
  • PATCH /api/v1/admin/main/logo 엔드포인트 구현 (JSON body)
  • MainPageConfig 엔티티 정리 (description, recruitmentStart/End 제거)
  • MainLogoResponseDto, MainLogoUpdateRequestDto(objectKey) 추가
  • MainPageConfigRepository 추가 (getConfig() — Singleton 엔티티 ID 고정 1)
  • AdminMainController, AdminMainService 추가

파일 업로드 흐름

1. GET /api/v1/files/upload-url?type=logo
   → { uploadUrl, objectKey } 수령

2. PUT {uploadUrl}  ← 브라우저에서 MinIO로 직접 전송 (서버 경유 없음)
   Body: 파일 바이너리

3. PATCH /api/v1/admin/main/logo
   Body: { "objectKey": "logo/uuid" }
   → 서버가 objectKey로 URL 구성 후 DB 저장

API

1. Presigned 업로드 URL 발급

GET /api/v1/files/upload-url?type=logo

Response: 200 OK

{
  "success": true,
  "data": {
    "uploadUrl": "http://minio:9000/one-bucket/logo/uuid?X-Amz-Signature=...",
    "objectKey": "logo/550e8400-e29b-41d4-a716-446655440000"
  }
}

type 파라미터: logologo/uuid, projectprojects/uuid 경로로 생성

2. 메인 로고 수정

PATCH /api/v1/admin/main/logo

Content-Type: application/json

Request Body:

{
  "objectKey": "logo/550e8400-e29b-41d4-a716-446655440000"
}

Response: 200 OK

{
  "success": true,
  "data": {
    "logoUrl": "http://minio:9000/one-bucket/logo/550e8400-e29b-41d4-a716-446655440000"
  }
}

프론트엔드 요청 예시 (JavaScript):

// 1. Presigned URL 발급
const { uploadUrl, objectKey } = await axios
  .get('/api/v1/files/upload-url?type=logo')
  .then(res => res.data.data);

// 2. MinIO에 직접 업로드 (서버 경유 없음)
await axios.put(uploadUrl, logoFile, {
  headers: { 'Content-Type': logoFile.type }
});

// 3. objectKey를 서버에 전달해 DB 저장
await axios.patch('/api/v1/admin/main/logo', { objectKey });

테스트

  • GET /api/v1/files/upload-url?type=logo → 200 OK, uploadUrl + objectKey 반환
  • PUT uploadUrl 로 파일 직접 업로드 → MinIO 저장 확인
  • PATCH /api/v1/admin/main/logo → 200 OK, logoUrl 반환
  • 기존 로고 있을 때 새 로고 저장 시 기존 파일 MinIO에서 삭제 확인

Chunwol added 3 commits May 24, 2026 23:42
- FileController: GET /api/v1/files/upload-url 엔드포인트 추가 (Presigned PUT URL 발급)
- PresignedUploadResponseDto: uploadUrl, objectKey 필드
- MinioService: getObjectUrl(objectKey) 메서드 추가
- AdminMainController: MultipartFile 제거 → @RequestBody MainLogoUpdateRequestDto
- AdminMainService: 서버 업로드 제거 → objectKey 받아 URL 저장
- MainLogoUpdateRequestDto: logoUrl → objectKey 필드로 변경
- MainLogoUpdateRequestDto.objectKey에 @notblank 추가
- AdminMainService.update()에 logo/ 경로 prefix 검증 추가
@Chunwol
Copy link
Copy Markdown
Member Author

Chunwol commented May 24, 2026

src/main/java/org/one/domain/dto/request/MainLogoUpdateRequestDto.java
MainLogoUpdateRequestDto @notblank도 추가

src/main/java/org/one/domain/service/AdminMainService.java
public MainLogoResponseDto update(String objectKey) 부분 object key 검증 예외 처리 추가

Chunwol added 2 commits May 25, 2026 00:53
- ErrorCode: INVALID_DATE_RANGE / PHOTO_LIMIT_EXCEEDED / INVALID_OBJECT_KEY 추가
- MinioService: uploadFile / deleteFile / getPresignedUrl catch에 error 로그 추가
- AdminMainService.validateObjectKey(): INVALID_OBJECT_KEY 적용
- AdminMainService.update(): DB 먼저 갱신 후 MinIO 삭제, 실패 시 경고 로그 처리
- FileController: logo/project 외 type 값 입력 시 INVALID_INPUT 예외 처리
@Chunwol Chunwol self-assigned this May 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant