feat: expose spot roles and settlement status#123
Conversation
|
Warning Review limit reached
More reviews will be available in 23 minutes and 59 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughPR adds role preservation across feed-to-spot conversions, exposing member roles in chat and spot participant API responses, and enables settlement state lookup. Role origins (application role from feed or spot participant role) are resolved and mapped to a new ChangesSpot member roles and settlement lookup
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
capstone-api/src/main/java/backend/chat/service/ChatService.java (2)
286-294: 💤 Low valueRole-resolution logic duplicated across modules.
resolveSpotMemberRoleis identical toSpotParticipantResponse.resolveMemberRole. Consider extracting a single resolver (e.g. a static method onSpotMemberRoleorSpotParticipant) so both call sites stay in sync. Optional given module boundaries.🤖 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 `@capstone-api/src/main/java/backend/chat/service/ChatService.java` around lines 286 - 294, The role-resolution logic in resolveSpotMemberRole duplicates SpotParticipantResponse.resolveMemberRole; extract a single shared resolver (e.g., a static method on SpotMemberRole like SpotMemberRole.fromParticipant(SpotParticipant) or a static helper on SpotParticipant) and replace both resolveSpotMemberRole and SpotParticipantResponse.resolveMemberRole to call that new method; ensure it handles ParticipantRole.AUTHOR -> OWNER, null applicationRole -> null, and mapping via valueOf(applicationRole.name()) so both call sites remain in sync.
296-305: 💤 Low valueDuplicate parse helper — reuse existing
parseSpotId.
parseLongOrNullis functionally identical toparseSpotId(Lines 984-993): both null/blank-guard and swallowNumberFormatExceptionreturningnull. Drop one to avoid divergence.♻️ Reuse existing helper
- private Long parseLongOrNull(String value) { - if (value == null || value.isBlank()) { - return null; - } - try { - return Long.valueOf(value); - } catch (NumberFormatException e) { - return null; - } - } -Then call
parseSpotId(...)at Lines 258 and 270.🤖 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 `@capstone-api/src/main/java/backend/chat/service/ChatService.java` around lines 296 - 305, Remove the duplicate private helper parseLongOrNull and instead call the existing parseSpotId helper; delete the parseLongOrNull method definition and replace every call site that used parseLongOrNull with parseSpotId (ensure the argument types match), keeping the null/blank guard and NumberFormatException swallowing behavior provided by parseSpotId. Update ChatService so all former parseLongOrNull usages now reference parseSpotId and remove the unused method to avoid divergence.capstone-api/src/main/java/backend/spot/dto/SpotParticipantResponse.java (1)
68-76: ⚡ Quick winBrittle enum coupling via
valueOfcan throw at runtime.
SpotMemberRole.valueOf(participant.getApplicationRole().name())will throwIllegalArgumentExceptionif the application-role enum ever holds a constant name (e.g. a future role) that has no matchingSpotMemberRole. It's safe only while both enums share identical names. Consider an explicit mapping that falls back tonull/PARTNERinstead of relying on name identity.The same pattern is used in
ChatService(Lines 282, 293).Please confirm the
applicationRoletype and that all its constant names exist inSpotMemberRole:#!/bin/bash # Resolve SpotParticipant.applicationRole type and its enum constants ast-grep --pattern 'private $TYPE applicationRole;' fd -e java | rg -l 'SpotParticipant' | head # FeedApplicationRole constants fd -i 'FeedApplicationRole.java' --exec cat {} # SpotMemberRole constants fd -i 'SpotMemberRole.java' --exec cat {}🤖 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 `@capstone-api/src/main/java/backend/spot/dto/SpotParticipantResponse.java` around lines 68 - 76, The resolveMemberRole method is brittle because SpotMemberRole.valueOf(participant.getApplicationRole().name()) can throw IllegalArgumentException if enum names diverge; replace the name-based conversion with an explicit mapping (e.g., switch or map) from the applicationRole enum values to SpotMemberRole values and return a safe fallback (null or SpotMemberRole.PARTNER) for unmapped cases; update the same fragile conversions in ChatService (the occurrences around lines 282 and 293) to use the same explicit mapping method or a shared helper to avoid runtime exceptions.
🤖 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 `@capstone-api/src/main/java/backend/feed/dto/FeedItemResponse.java`:
- Around line 239-246: In calculateRemainingParticipantCount, avoid possible
integer overflow in the ceiling division by performing the computation in long
like calculateProgressPercent does: convert remainingAmount and price to long,
compute (remaining + price - 1) / price using long arithmetic, then cast the
result back to Integer (or return null/handle if result exceeds
Integer.MAX_VALUE) before returning; update the logic in
calculateRemainingParticipantCount to use these long temporaries to ensure
correctness for very large Integer inputs.
In `@capstone-api/src/main/java/backend/spot/service/SpotService.java`:
- Around line 805-811: In getSettlement, validate spot existence before checking
participant membership: call validateSpotExists(spotId,
ErrorCode.SPOT_NOT_FOUND) at the start of SpotService.getSettlement (before
calling validateParticipant) so a missing spot yields SPOT_NOT_FOUND (404)
instead of NOT_SPOT_PARTICIPANT; mirror the order used in approveSettlement to
ensure consistent error semantics.
- Around line 253-257: getSpot currently always loads the latest settlement and
exposes it to unauthenticated callers; change it to only include settlement when
the caller is an owner/participant by reusing the existing access checks: call
validateSpotExists(spotId) if not already done, then call
validateParticipant(spotId, currentUserId) or delegate to getSettlement(spotId,
currentUserId) to obtain the SpotSettlementResponse so both paths share the same
authorization logic; additionally, update getSettlement to first call
validateSpotExists(spotId) so missing spots return SPOT_NOT_FOUND consistently.
---
Nitpick comments:
In `@capstone-api/src/main/java/backend/chat/service/ChatService.java`:
- Around line 286-294: The role-resolution logic in resolveSpotMemberRole
duplicates SpotParticipantResponse.resolveMemberRole; extract a single shared
resolver (e.g., a static method on SpotMemberRole like
SpotMemberRole.fromParticipant(SpotParticipant) or a static helper on
SpotParticipant) and replace both resolveSpotMemberRole and
SpotParticipantResponse.resolveMemberRole to call that new method; ensure it
handles ParticipantRole.AUTHOR -> OWNER, null applicationRole -> null, and
mapping via valueOf(applicationRole.name()) so both call sites remain in sync.
- Around line 296-305: Remove the duplicate private helper parseLongOrNull and
instead call the existing parseSpotId helper; delete the parseLongOrNull method
definition and replace every call site that used parseLongOrNull with
parseSpotId (ensure the argument types match), keeping the null/blank guard and
NumberFormatException swallowing behavior provided by parseSpotId. Update
ChatService so all former parseLongOrNull usages now reference parseSpotId and
remove the unused method to avoid divergence.
In `@capstone-api/src/main/java/backend/spot/dto/SpotParticipantResponse.java`:
- Around line 68-76: The resolveMemberRole method is brittle because
SpotMemberRole.valueOf(participant.getApplicationRole().name()) can throw
IllegalArgumentException if enum names diverge; replace the name-based
conversion with an explicit mapping (e.g., switch or map) from the
applicationRole enum values to SpotMemberRole values and return a safe fallback
(null or SpotMemberRole.PARTNER) for unmapped cases; update the same fragile
conversions in ChatService (the occurrences around lines 282 and 293) to use the
same explicit mapping method or a shared helper to avoid runtime exceptions.
🪄 Autofix (Beta)
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: defaults
Review profile: CHILL
Plan: Pro
Run ID: a2a20510-a651-45d2-8248-ebc5cc542585
📒 Files selected for processing (15)
capstone-api/src/main/java/backend/chat/dto/ChatMemberResponse.javacapstone-api/src/main/java/backend/chat/service/ChatService.javacapstone-api/src/main/java/backend/feed/dto/FeedApplicationResponse.javacapstone-api/src/main/java/backend/feed/dto/FeedItemResponse.javacapstone-api/src/main/java/backend/feed/service/FeedItemService.javacapstone-api/src/main/java/backend/spot/controller/SpotController.javacapstone-api/src/main/java/backend/spot/dto/SpotDetailResponse.javacapstone-api/src/main/java/backend/spot/dto/SpotParticipantResponse.javacapstone-api/src/main/java/backend/spot/service/SpotService.javacapstone-api/src/test/java/backend/feed/service/FeedItemServiceTest.javacapstone-domain/src/main/java/backend/feed/entity/FeedItem.javacapstone-domain/src/main/java/backend/spot/entity/Spot.javacapstone-domain/src/main/java/backend/spot/entity/SpotMemberRole.javacapstone-domain/src/main/java/backend/spot/entity/SpotParticipant.javadocs/migrations/2026-06-02_spot_participant_application_role.sql
Summary
Closes #122
Verification
Backend API note
This PR covers the frontend visibility/control flow with existing APIs plus small response additions. One backend gap remains only if product requires settlement approval to move points automatically: current settlement approval records agreement state only, and the point domain has balance/transaction primitives but no clear settlement transfer/escrow policy yet.
구현한 것:
피드에서 “얼마나 더 모아야 스팟이 되는지” 피드백 추가
FeedItemResponse에 아래 필드 추가:
fundingGoal
fundedAmount
remainingAmount
remainingParticipantCount
프론트에서 “1명 더 필요”, “5,000P 더 필요” 같은 안내 가능.
피드가 스팟으로 전환됐는지 확인 가능하게 추가
신청 수락 API 응답 FeedApplicationResponse에:
spotConverted
spotId
전환 시 원본 FeedItem에도 spotId 보존 + MATCHED 상태 기록 후 soft delete.
오너 / 서포터 / 파트너 구분 추가
새 enum: SpotMemberRole
OWNER
SUPPORTER
PARTNER
ChatMemberResponse.role에 채팅방 멤버별 역할 노출.
SpotParticipantResponse.memberRole에 스팟 참여자별 역할 노출.
피드 신청 당시 SUPPORTER/PARTNER 역할을 스팟 전환 후에도 보존하도록 spot_participants.application_role 추가.
정산 상태 확인 API 추가
GET /api/spots/{spotId}/settlement
스팟 상세 SpotDetailResponse에도 최신 정산 상태 settlement 포함.
기존 정산 요청/승인 API는 유지:
POST /api/spots/{spotId}/settlement
POST /api/spots/{spotId}/settlement/approve
DB 마이그레이션 문서 추가
docs/migrations/2026-06-02_spot_participant_application_role.sql
spot_participants.application_role 컬럼 추가용.
검증 결과:
./gradlew compileJava testClasses :capstone-api:test --tests backend.feed.service.FeedItemServiceTest 성공
./gradlew bootJar 성공
./gradlew checkstyleMain 성공
다만 기존 코드의 checkstyle warning들은 남아 있음. 현재 프로젝트 설정상 ignoreFailures=true라 빌드는 성공.
./gradlew test 전체는 실패
원인: BackendApplicationTests.contextLoads()가 로컬 PostgreSQL 연결 실패로 깨짐.
에러: PSQLException / ConnectException
이번 변경 로직 문제는 아니고, 로컬 DB 미기동/미설정 이슈로 보입니다.
백엔드적으로 “없어서 못 만드는 것”은 하나만 있습니다:
만약 “정산 승인”이 단순 승인 기록이 아니라 실제 포인트 차감/지급/환불까지 의미한다면, 그건 아직 백엔드 정책/API가 부족합니다.
현재 settlement 코드는 합의 상태 기록만 하고, 포인트 이동은 하지 않습니다.
PointTransaction, PayService 같은 포인트 도메인 기본 요소는 있지만, 정산용 escrow/transfer/refund 정책이 명확히 없습니다.
그래서 프론트에서 “정산 요청/승인 상태 표시”는 이번 PR로 가능하지만, “승인 시 실제 포인트 이동”까지 하려면 별도 백엔드 설계가 필요합니다.
Summary by CodeRabbit
New Features