Skip to content

[Feat] 데모 시연용 트래킹 사진 조회 API 구현#143

Merged
howooyeon merged 5 commits into
developfrom
feat/#134-demo-tracking-complete
May 28, 2026
Merged

[Feat] 데모 시연용 트래킹 사진 조회 API 구현#143
howooyeon merged 5 commits into
developfrom
feat/#134-demo-tracking-complete

Conversation

@howooyeon

Copy link
Copy Markdown
Contributor

🧾 요약

  • 데모 시연 시 트래킹 세션의 사진을 조회하는 API 구현

🔗 이슈

✨ 변경 내용

  • DemoProperties 설정 프로퍼티 추가 (데모 사진 파일명 목록)
  • GET /api/demo/tracking/sessions/{sessionId}/photos API 구현
  • MinIO presigned GET URL로 사진 반환 (1시간 유효)
  • 설정된 데모 사진 중 랜덤 N개 + 해당 세션의 실제 업로드 사진을 합쳐서 반환
  • application.yaml, application-prod.yaml에 데모 사진 파일명 설정 추가

✅ 확인

  • 빌드 OK
  • 로컬 테스트 OK

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 83be9076-064c-414e-b621-9a93baefc286

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#134-demo-tracking-complete

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

본 PR은 데모 시연을 원활하게 진행하기 위한 트래킹 사진 조회 기능을 구현합니다. 시스템에 미리 등록된 데모 사진들과 해당 세션에서 실제 촬영된 사진들을 조합하여 제공함으로써, 시연 환경에서 풍부한 데이터를 보여줄 수 있도록 설계되었습니다.

Highlights

  • 데모용 사진 조회 API 구현: 특정 트래킹 세션에 대해 미리 설정된 데모 사진과 실제 업로드된 사진을 결합하여 반환하는 GET /api/demo/tracking/sessions/{sessionId}/photos API를 추가했습니다.
  • MinIO Presigned URL 적용: 보안을 위해 MinIO에 저장된 사진에 대해 1시간 동안 유효한 presigned URL을 생성하여 반환하도록 구현했습니다.
  • 설정 프로퍼티 추가: 데모 사진 파일명 목록을 관리하기 위해 DemoProperties를 도입하고, application.yaml 및 application-prod.yaml에 관련 설정을 추가했습니다.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@howooyeon howooyeon self-assigned this May 28, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a demo endpoint /api/demo/tracking/sessions/{sessionId}/photos along with its configuration properties and Swagger documentation to retrieve a combined list of random demo photos and uploaded tracking photos. Feedback highlights the need to prevent potential NullPointerException in DemoProperties by handling null values, and recommends extracting the business logic from DemoController into a dedicated DemoService to ensure proper separation of concerns and transaction management.

Comment on lines +8 to +10
public record DemoProperties(
List<String> photoFilenames
) {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

[P2] NullPointerException 방지를 위한 기본값 설정

demo.photo-filenames 설정이 누락되었거나 빈 값일 경우, demoProperties.photoFilenames()null을 반환하여 DemoController에서 NullPointerException이 발생할 위험이 있습니다.

Record의 콤팩트 생성자(Compact Constructor)를 사용하여 null인 경우 빈 리스트로 초기화하도록 방어 코드를 추가하는 것이 안전합니다.

Suggested change
public record DemoProperties(
List<String> photoFilenames
) {}
public record DemoProperties(
List<String> photoFilenames
) {
public DemoProperties {
photoFilenames = photoFilenames == null ? List.of() : photoFilenames;
}
}
References
  1. Check soft delete behavior, nullable policies, enum expansion, and DB constraints for consistency. (link)

Comment on lines +33 to +78
private final DemoProperties demoProperties;
private final MinioClient minioClient;
private final MinioProperties minioProperties;
private final TrackingPhotoRepository trackingPhotoRepository;

@GetMapping("/tracking/sessions/{sessionId}/photos")
@Override
public ResponseEntity<ApiResponse<List<String>>> getDemoPhotos(
@PathVariable Long sessionId,
@RequestParam(defaultValue = "3") int count
) {
List<String> shuffled = new ArrayList<>(demoProperties.photoFilenames());
Collections.shuffle(shuffled);
List<String> randomUrls = shuffled.subList(0, Math.min(count, shuffled.size()))
.stream()
.map(this::presignedGetUrl)
.toList();

List<String> uploadedUrls = trackingPhotoRepository
.findByTrackingSession_IdOrderByMilestoneIndexAsc(sessionId)
.stream()
.map(TrackingPhoto::getImageUrl)
.toList();

List<String> combined = new ArrayList<>(randomUrls);
combined.addAll(uploadedUrls);

return ApiResponse.success(SuccessStatus.TRACKING_PHOTO_LIST_SUCCESS, combined);
}

private String presignedGetUrl(String objectKey) {
try {
String url = minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(BUCKET)
.object(objectKey)
.expiry(1, TimeUnit.HOURS)
.build()
);
return url.replace(minioProperties.endpoint(), minioProperties.publicUrl());
} catch (Exception e) {
log.warn("Failed to generate presigned URL for {}", objectKey, e);
return minioProperties.publicUrl() + "/" + BUCKET + "/" + objectKey;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

[P2] 컨트롤러 내 비즈니스 로직 분리 및 트랜잭션 적용

현재 DemoController에서 직접 MinIO presigned URL을 생성하고, 사진 목록을 셔플하며, Repository를 호출하는 등 핵심 비즈니스 로직을 모두 처리하고 있습니다.

이는 컨트롤러와 서비스의 책임을 명확히 분리하라는 설계 원칙(Repository Style Guide 20, 21번)에 위배됩니다. 또한, 조회 전용 작업임에도 트랜잭션 경계가 설정되지 않아 성능 최적화(@Transactional(readOnly = true)) 혜택을 받지 못합니다.

개선 제안:
비즈니스 로직을 처리하는 DemoService를 추가하여 컨트롤러의 책임을 최소화하고, 서비스 메서드에 @Transactional(readOnly = true)를 적용해 주세요.

    private final DemoService demoService;

    @GetMapping("/tracking/sessions/{sessionId}/photos")
    @Override
    public ResponseEntity<ApiResponse<List<String>>> getDemoPhotos(
            @PathVariable Long sessionId,
            @RequestParam(defaultValue = "3") int count
    ) {
        List<String> combined = demoService.getDemoPhotos(sessionId, count);
        return ApiResponse.success(SuccessStatus.TRACKING_PHOTO_LIST_SUCCESS, combined);
    }
References
  1. Controller, Service, Repository, DTO, and Entity responsibilities are separated clearly. Business logic should live in the appropriate Service or domain model, not in controllers. (link)
  2. Review transaction boundaries, readOnly usage, exception propagation, and rollback behavior carefully. (link)

@howooyeon
howooyeon merged commit 4a1e521 into develop May 28, 2026
1 check passed
@howooyeon
howooyeon deleted the feat/#134-demo-tracking-complete branch June 3, 2026 15:02
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.

[feat] 시연용 트래킹 세션 사진 API 수정

1 participant