Skip to content

[FEAT] 분석 마디 선택 정보 조회 API 구현 - #161

Merged
p1001q merged 3 commits into
developfrom
feat/#156-analysis-context
Aug 6, 2026
Merged

[FEAT] 분석 마디 선택 정보 조회 API 구현#161
p1001q merged 3 commits into
developfrom
feat/#156-analysis-context

Conversation

@ownue

@ownue ownue commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📍 개요

분석 마디 선택 화면에 필요한 연주/백킹트랙 정보를 조회하는 API를 구현했습니다.

⛓️‍💥 관련 이슈


🛠️ 작업 내용

  • 분석 마디 선택 정보 조회 API 추가
  • 기존 분석 검증과 동일한 전체 마디 수 계산 로직 적용

🔥 리뷰 요청 사항

리뷰어가 중점적으로 확인해주었으면 하는 내용을 작성해주세요.

  • totalBars 계산 기준이 분석 요청의 마디 범위 검증과 일관되는지
  • 응답 필드와 소유권/완료 상태 검증 흐름이 적절한지

✅ 체크리스트

  • 코드 컨벤션을 준수했습니다.
  • 불필요한 코드 및 import를 제거했습니다.
  • 예외 처리를 적용했습니다.
  • 테스트를 완료했습니다.
  • 관련 Issue를 연결했습니다.

📎 참고 사항

  • 백킹트랙 엔티티가 없는 경우 PLAYING_404_03을 반환합니다. (추후 백킹트랙이 없어도 분석이 가능하게 디벨롭할 경우, 해당 에러를 별도로 처리해야 합니다.)
  • 연주 또는 백킹트랙 음원 URL이 없는 경우 해당 필드는 null로 반환됩니다.

Summary by CodeRabbit

  • 새 기능

    • 완료된 연주의 분석 컨텍스트를 조회할 수 있는 API를 추가했습니다.
    • 연주 정보, 백킹 트랙, MIDI 이벤트, 재생 시간 및 전체 마디 정보를 제공합니다.
    • 로컬·배포 환경별 OAuth 리다이렉트 URI 설정을 지원합니다.
    • S3 파일 업로드 및 presigned URL 관련 설정을 확장했습니다.
  • 개선

    • 박자표와 재생 정보를 기반으로 전체 마디를 일관되게 계산합니다.
    • 잘못된 박자표와 유효하지 않은 분석 요청을 명확한 오류로 처리합니다.
  • 테스트

    • 분석 마디 계산, 접근 권한, 누락된 백킹 트랙 및 API 응답 검증을 추가했습니다.

@ownue ownue self-assigned this Aug 6, 2026
@ownue ownue added the ✨feat label Aug 6, 2026
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

분석 마디 계산을 AnalysisBarCalculator로 분리했습니다. 완료된 본인 연주의 분석 컨텍스트 조회 API를 추가했습니다. 응답에는 연주·백킹트랙 메타데이터, 음원 URL, MIDI 이벤트, 전체 마디 수가 포함됩니다. 로컬 OAuth와 S3 설정도 확장했습니다.

Changes

분석 마디 계산 및 분석 요청 연계

Layer / File(s) Summary
마디 계산 컴포넌트와 요청 생성 연계
src/main/java/com/mr/domain/analysis/service/AnalysisBarCalculator.java, src/main/java/com/mr/domain/analysis/factory/AnalysisRequestFactory.java, src/test/java/com/mr/domain/analysis/service/*
AnalysisBarCalculator가 재생 정보와 박자표를 검증하고 BarMetrics를 반환합니다. AnalysisRequestFactory는 계산 결과로 분석 요청과 마디 범위를 구성합니다.

분석 컨텍스트 조회 API

Layer / File(s) Summary
분석 컨텍스트 조회 API
src/main/java/com/mr/domain/playing/controller/PlayingController.java, src/main/java/com/mr/domain/playing/service/PlayingService.java, src/main/java/com/mr/domain/playing/dto/res/AnalysisContextResponse.java, src/test/java/com/mr/domain/playing/{controller,service}/*
GET /api/playings/{playingId}/analysis-context가 추가되었습니다. 서비스는 소유자, 완료 상태, 백킹트랙을 검증한 뒤 분석 컨텍스트를 반환합니다. 관련 성공 및 예외 테스트를 추가했습니다.

로컬 OAuth 및 S3 설정

Layer / File(s) Summary
로컬 OAuth 및 S3 설정
MR_config/local/application.example.yml, src/main/resources/application.yml
OAuth 리다이렉트 URI를 목록으로 변경했습니다. S3 자격 증명, presigned URL 만료 시간, 파일 크기, 키 접두사, 허용 콘텐츠 타입 설정을 추가했습니다. 운영 설정의 공백도 정리했습니다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • Musereview/BE#84: AnalysisRequestFactory와 마디 범위 계산 흐름을 함께 수정합니다.
  • Musereview/BE#85: PlayingControllerPlayingService의 연주 세션 흐름과 연결됩니다.
  • Musereview/BE#155: 연주 및 백킹트랙 음원 URL 응답 필드와 연결됩니다.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PlayingController
  participant PlayingService
  participant AnalysisBarCalculator
  participant AnalysisContextResponse
  Client->>PlayingController: GET /api/playings/{playingId}/analysis-context
  PlayingController->>PlayingService: getAnalysisContext(userId, playingId)
  PlayingService->>AnalysisBarCalculator: calculate(playing)
  AnalysisBarCalculator-->>PlayingService: totalBars
  PlayingService->>AnalysisContextResponse: from(playing, totalBars)
  AnalysisContextResponse-->>PlayingService: 분석 컨텍스트
  PlayingService-->>PlayingController: AnalysisContextResponse
  PlayingController-->>Client: ApiResponse
Loading

Poem

박자 계산기가 마디를 세고
연주 정보가 화면에 모여
MIDI 음표는 길을 열고
백킹트랙은 곁을 지켜
분석의 시작점이 완성됩니다.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed 소유권·완료 상태 검증, 음원·MIDI·연주 정보·전체 마디 수 반환, 관련 테스트가 구현되어 이슈 #156을 충족합니다.
Out of Scope Changes check ✅ Passed 설정 변경은 로컬 명세 반영 범위로 설명되며, 나머지 변경은 이슈 #156의 API 구현과 테스트에 직접 관련됩니다.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 분석 마디 선택 화면용 조회 API 구현이라는 변경의 핵심을 정확하고 간결하게 설명합니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#156-analysis-context

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/test/java/com/mr/domain/playing/service/PlayingServiceTest.java (1)

1000-1015: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

완료되지 않은 연주 거부 경로를 테스트하세요.

현재 테스트는 성공 경로에서 validateCompleted() 호출만 확인합니다. validateCompleted()가 예외를 던질 때 getAnalysisContext가 그 예외를 반환하고 analysisBarCalculator를 호출하지 않는 테스트를 추가하세요. 이 테스트는 완료 상태 검증 순서의 회귀를 방지합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/com/mr/domain/playing/service/PlayingServiceTest.java` around
lines 1000 - 1015, PlayingServiceTest의 getAnalysisContext 테스트에
validateCompleted()가 GeneralException을 던지는 거부 경로를 추가하세요. playing 소유자 검증은 통과하도록
설정한 뒤 validateCompleted() 예외가 전파되는지 확인하고,
analysisBarCalculator.calculate(any())가 호출되지 않았는지도 검증하세요.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/mr/domain/analysis/service/AnalysisBarCalculator.java`:
- Around line 39-41: Update the value parsing in AnalysisBarCalculator to call
split with a negative limit so trailing empty tokens are preserved; continue
rejecting any result whose parts length is not exactly two, ensuring inputs such
as "4/4/" produce ANALYSIS_INVALID_REQUEST. Add coverage for the
trailing-delimiter case if tests for this parsing path exist.

---

Nitpick comments:
In `@src/test/java/com/mr/domain/playing/service/PlayingServiceTest.java`:
- Around line 1000-1015: PlayingServiceTest의 getAnalysisContext 테스트에
validateCompleted()가 GeneralException을 던지는 거부 경로를 추가하세요. playing 소유자 검증은 통과하도록
설정한 뒤 validateCompleted() 예외가 전파되는지 확인하고,
analysisBarCalculator.calculate(any())가 호출되지 않았는지도 검증하세요.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a95a3595-72fb-452e-9bd7-5eb902d44c76

📥 Commits

Reviewing files that changed from the base of the PR and between 8989c36 and 90bd082.

📒 Files selected for processing (11)
  • MR_config/local/application.example.yml
  • src/main/java/com/mr/domain/analysis/factory/AnalysisRequestFactory.java
  • src/main/java/com/mr/domain/analysis/service/AnalysisBarCalculator.java
  • src/main/java/com/mr/domain/playing/controller/PlayingController.java
  • src/main/java/com/mr/domain/playing/dto/res/AnalysisContextResponse.java
  • src/main/java/com/mr/domain/playing/service/PlayingService.java
  • src/main/resources/application.yml
  • src/test/java/com/mr/domain/analysis/service/AnalysisBarCalculatorTest.java
  • src/test/java/com/mr/domain/analysis/service/AnalysisRequestFactoryTest.java
  • src/test/java/com/mr/domain/playing/controller/PlayingControllerTest.java
  • src/test/java/com/mr/domain/playing/service/PlayingServiceTest.java

Comment on lines +39 to +41
String[] parts = value.split("/");
if (parts.length != 2) {
throw new NumberFormatException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Java String.split(String regex) trailing empty strings official Java documentation

💡 Result:

According to official Java documentation, the String.split(String regex) method discards trailing empty strings by default [1][2]. This behavior occurs because the single-argument split(String regex) method is equivalent to calling the two-argument split(String regex, int limit) method with a limit argument of zero [1][3]. When the limit parameter is set to zero, the pattern is applied as many times as possible, but trailing empty strings are discarded from the resulting array [1][4]. If you need to include trailing empty strings, you can use the overloaded split(String regex, int limit) method with a negative value for the limit parameter [1][5]. When the limit is negative, the pattern is applied as many times as possible and the array can have any length, which preserves trailing empty strings [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== find file =="
fd -a 'AnalysisBarCalculator\.java$' . || true

echo "== lines around target =="
if [ -f src/main/java/com/mr/domain/analysis/service/AnalysisBarCalculator.java ]; then
  wc -l src/main/java/com/mr/domain/analysis/service/AnalysisBarCalculator.java
  sed -n '1,120p' src/main/java/com/mr/domain/analysis/service/AnalysisBarCalculator.java | cat -n
fi

echo "== related tests/usages for AnalysisBarCalculator =="
rg -n "AnalysisBarCalculator|analyse|calculate|ANALYSIS_INVALID_REQUEST|split\\(\"/\"|--2|split\\(\"/\\)" . -g '*.java' -g '*.kt' || true

echo "== Java split behavior probe if javac/java present =="
if command -v javac >/dev/null 2>&1 && command -v java >/dev/null 2>&1; then
  tmp="$(mktemp -d)"
  cat > "$tmp/Probe.java" <<'EOF'
import java.util.Arrays;

public class Probe {
  public static void main(String[] args) {
    for (String v : new String[]{"4/4", "4/4/", "/4/4", ""}) {
      System.out.println(Arrays.toString(v.split("/")) + " :: " + Arrays.toString(v.split("/", -1)));
    }
  }
}
EOF
  javac "$tmp/Probe.java"
  java -cp "$tmp" Probe
else
  echo "javac/java not available"
fi

Repository: Musereview/BE

Length of output: 17439


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Repository files containing AnalysisBarCalculator or related error =="
git ls-files | rg 'AnalysisBarCalculator|[^/]AnalysisBar.*|.*Bar.*Calculator.*' || true
rg -n "AnalysisBarCalculator|ANALYSIS_INVALID_REQUEST|AnalysisBarCalculatorTest|analyzeBar|calculateBar" . || true

echo "== Java documentation slice from local JDK if available =="
if [ -n "${JAVA_HOME:-}" ] && [ -d "$JAVA_HOME" ]; then
  rg -n "discards trailing empty strings|limit argument of zero|Arrays.toString\(this.split.*limit" "$JAVA_HOME"/docs -g '*.html' -g '*.javadoc' 2>/dev/null | head -20 || true
fi

Repository: Musereview/BE

Length of output: 3778


끝 구분자가 있는 박자표를 거부하세요.

String.split("/")는 기본값으로 뒤에 남은 빈 토큰을 버립니다. 따라서 "4/4/"["4", "4"]로 해석되어 유효한 4/4가 됩니다. 이를 입력 값 자체의 잘못된 형식으로 처리해 ANALYSIS_INVALID_REQUEST를 반환하려면 split("/", -1)로 파싱하세요. 이 경로를 테스트도 추가하면 좋습니다. 관련 문서는 Java 기본 API의 String.split(String) 문서의 limit 설명을 참고하세요.

수정 예시
-            String[] parts = value.split("/");
+            String[] parts = value.split("/", -1);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
String[] parts = value.split("/");
if (parts.length != 2) {
throw new NumberFormatException();
String[] parts = value.split("/", -1);
if (parts.length != 2) {
throw new NumberFormatException();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/mr/domain/analysis/service/AnalysisBarCalculator.java`
around lines 39 - 41, Update the value parsing in AnalysisBarCalculator to call
split with a negative limit so trailing empty tokens are preserved; continue
rejecting any result whose parts length is not exactly two, ensuring inputs such
as "4/4/" produce ANALYSIS_INVALID_REQUEST. Add coverage for the
trailing-delimiter case if tests for this parsing path exist.

@on1yoneprivate on1yoneprivate 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.

수고하셨습니다.

[참고]
현재 recordingFileUrl은 raw S3 URL이 그대로 응답되고 있는데, private 객체인 경우 프론트에서 접근 시 AccessDenied가 발생할 수 있어요!

다만 이 부분은 제가 현재 작업 중인 presigned GET URL 발급 PR #159에서 함께 수정하고 있어 은우님 PR이 먼저 머지 후 제가 반영해서 수정할게요!

@rkdehdrbs7885-oss rkdehdrbs7885-oss 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.

수고하셨습니다!

@p1001q p1001q 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.

Presigned URL 부분은 원정님 담당이라 리뷰 스코프에서 뺐고 나머지 로직(totalBars 계산 일관성, 소유권/완료 상태 검증 흐름)은 문제없어 보이네용 바로 승인하고 머지 하겠습니다~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ Feature - 분석 마디 선택 화면의 조회용 API 구현

4 participants