Skip to content

fix(feed): Spot 전환 조건 — 서포터 1명 + 파트너 1명 이상 수락 시 MATCHED#121

Open
ThonApple wants to merge 2 commits into
developfrom
fix/spot-matching-condition
Open

fix(feed): Spot 전환 조건 — 서포터 1명 + 파트너 1명 이상 수락 시 MATCHED#121
ThonApple wants to merge 2 commits into
developfrom
fix/spot-matching-condition

Conversation

@ThonApple
Copy link
Copy Markdown
Collaborator

@ThonApple ThonApple commented May 29, 2026

요약

  • acceptApplication()appliedRole을 무시하고 있어 Spot 전환이 동작하지 않던 문제 수정
  • 서포터(SUPPORTER) 1명 + 파트너(PARTNER) 1명 이상 수락 완료 시 Spot 전환되도록 조건 교체

Closes #120

변경 파일

FeedItem.java (capstone-domain)

변경 내용
confirmedSupporterCount 필드 추가 서포터 수락 카운트 전용, DEFAULT 0
confirmedPartnerCount 재정의 파트너 전용 카운트 (기존 필드 재사용)
canAcceptMoreSupporters() 추가 confirmedSupporterCount < 1 체크
recordSupporterAccepted() / recordPartnerAccepted() role별 카운트 증가
isReadyToMatch() 추가 서포터 ≥ 1 AND 파트너 ≥ 1
canAcceptMore() / accumulateFunding() / isFundingGoalMet() 제거 사용처 없어짐

FeedItemService.java (capstone-api)

  • acceptApplication()appliedRole 분기 추가
  • SUPPORTER: canAcceptMoreSupporters() 체크 후 recordSupporterAccepted()
  • PARTNER: recordPartnerAccepted() (횟수 제한 없음)
  • isFundingGoalMet()isReadyToMatch()로 교체

테스트 플랜

  • ./gradlew compileJava 통과
  • ./gradlew checkstyleMain 변경 파일 위반 0건
  • 서포터 1명 수락 → Spot 미전환 확인
  • 파트너 1명 수락 → Spot 미전환 확인
  • 서포터 1명 + 파트너 1명 수락 → Spot 전환 + MATCHED 상태 확인
  • 서포터 1명 수락 후 서포터 2번째 수락 시도 → 400 에러 확인

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor
    • Updated the application acceptance workflow to properly distinguish between and manage different types of applications with separate capacity limits for each
    • Refined feed item readiness determination to require confirmed acceptance from all necessary application categories before the matching process can proceed
    • Improved tracking of accepted applications by role for more accurate processing

Review Change Stack

- FeedItem에 confirmedSupporterCount 필드 추가
- role별 카운트 분리: recordSupporterAccepted / recordPartnerAccepted
- isReadyToMatch()로 전환 조건 교체 (isFundingGoalMet 제거)
- acceptApplication()에서 appliedRole 분기 처리

Closes #120

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ThonApple ThonApple requested review from ca5tlechan and hoTan35 May 29, 2026 10:09
@ThonApple
Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

Warning

Review limit reached

@ThonApple, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 47 minutes and 42 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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bd1c7625-df04-4f63-b156-359ad40c99b6

📥 Commits

Reviewing files that changed from the base of the PR and between af9de64 and 01677e6.

📒 Files selected for processing (4)
  • capstone-api/src/main/java/backend/feed/controller/FeedController.java
  • capstone-api/src/main/java/backend/feed/service/FeedItemService.java
  • capstone-domain/src/main/java/backend/feed/entity/FeedApplication.java
  • capstone-domain/src/main/java/backend/feed/entity/FeedItem.java
📝 Walkthrough

Walkthrough

The PR refactors feed application acceptance to distinguish between supporters and partners. FeedItem gains a confirmedSupporterCount field and new role-specific methods to enforce single-supporter capacity and separately track partner acceptances. FeedItemService.acceptApplication() becomes role-aware, applying capacity checks only to supporters and using a two-counter readiness predicate to trigger spot conversion.

Changes

Role-aware application acceptance and matching readiness

Layer / File(s) Summary
FeedItem entity: supporter/partner tracking
capstone-domain/src/main/java/backend/feed/entity/FeedItem.java
confirmedSupporterCount field added with DB default 0. Methods canAcceptMore(), accumulateFunding(), and isFundingGoalMet() replaced with canAcceptMoreSupporters(), recordSupporterAccepted(), recordPartnerAccepted(), and isReadyToMatch() to track and validate role-specific acceptance counters.
FeedItemService: role-aware acceptance logic
capstone-api/src/main/java/backend/feed/service/FeedItemService.java
acceptApplication() branches on application.getAppliedRole(), enforces canAcceptMoreSupporters() only for SUPPORTER role, records role-specific acceptance state, and replaces isFundingGoalMet() with isReadyToMatch() to determine spot conversion eligibility.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • spot-platform/backend#84: Both PRs adjust FeedItem/FeedItemService.acceptApplication() to prevent accepting more than the allowed single supporter by enforcing a cap via feed acceptance-counter logic (with the main PR refactoring it into role-aware confirmedSupporterCount/confirmedPartnerCount methods).

Suggested labels

refactor

Suggested reviewers

  • ca5tlechan

Poem

🐰 A feed awaits its two-fold fate—
One support, one partner to truly mate,
No more by gold, but by heads we count,
When both roles gather, the spots amount! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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
Title check ✅ Passed The title clearly describes the main change: updating Spot conversion condition to require 1 supporter + 1 partner acceptance, with state transition to MATCHED.
Description check ✅ Passed The description includes summary, changes by file, and test plan. All template sections (Summary, Describe your changes, Issue number) are adequately covered.
Linked Issues check ✅ Passed The code changes fully address issue #120 requirements: role-aware acceptance with separate supporter/partner counters, capacity limits per role, and Spot conversion triggered by isReadyToMatch().
Out of Scope Changes check ✅ Passed All changes directly support the stated objective: removing funding-based logic, adding role-aware acceptance handling, and implementing role-specific counter methods align with issue #120 requirements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/spot-matching-condition

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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 and usage tips.

- isReadyToMatch(): maxParticipants null이면 자동 전환 없음, 설정 시 서포터1+파트너>=maxParticipants
- earlyStartRequested 필드: 작성자 조기 시작 요청 상태
- earlyStartConsented 필드: 참여자 개별 동의 상태
- POST /feeds/{feedId}/early-start: 작성자 조기 시작 요청
- POST /feeds/{feedId}/early-start/consent: 참여자 동의, 전원 동의 시 Spot 전환
- convertFeedToSpot() 추출로 자동/수동 전환 로직 공통화

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ThonApple
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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-domain/src/main/java/backend/feed/entity/FeedItem.java`:
- Around line 199-204: The current isReadyToMatch() only checks
confirmedSupporterCount/confirmedPartnerCount and ignores FeedItem.authorRole so
it can block conversion when the author already holds one role; update
isReadyToMatch() to treat the author as already occupying their role: compute
supporters = (confirmedSupporterCount != null ? confirmedSupporterCount : 0) and
partners = (confirmedPartnerCount != null ? confirmedPartnerCount : 0), then if
authorRole == SUPPORTER return partners >= 1, if authorRole == PARTNER return
supporters >= 1, otherwise return supporters >= 1 && partners >= 1; use the
existing field names (isReadyToMatch, confirmedSupporterCount,
confirmedPartnerCount, authorRole) and keep null-safety.
🪄 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: 22bbabfe-522b-489d-93fd-9c18fbda1684

📥 Commits

Reviewing files that changed from the base of the PR and between 1d0463b and af9de64.

📒 Files selected for processing (2)
  • capstone-api/src/main/java/backend/feed/service/FeedItemService.java
  • capstone-domain/src/main/java/backend/feed/entity/FeedItem.java

Comment on lines 199 to 204
/** Spot 전환 조건: 서포터 1명 이상 + 파트너 1명 이상 수락 완료. */
public boolean isReadyToMatch() {
int supporters = this.confirmedSupporterCount != null ? this.confirmedSupporterCount : 0;
int partners = this.confirmedPartnerCount != null ? this.confirmedPartnerCount : 0;
return supporters >= 1 && partners >= 1;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== FeedApplicationRole enum values ==="
fd -t f 'FeedApplicationRole.java' --exec cat {}
echo "=== is applied role constrained by feed type anywhere? ==="
rg -nP 'appliedRole|getAppliedRole|FeedApplicationRole\.' --type=java -C2
echo "=== how a Spot is formed from a feed (roles) ==="
ast-grep --pattern 'public static Spot fromFeedItem($$$) { $$$ }'
echo "=== participant roles ==="
fd -t f 'ParticipantRole.java' --exec cat {}

Repository: spot-platform/backend

Length of output: 10280


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Locate confirmedSupporterCount / confirmedPartnerCount / authorRole in FeedItem ==="
fd -t f 'FeedItem.java' --exec rg -n "confirmedSupporterCount|confirmedPartnerCount|authorRole|isReadyToMatch" {}

echo "=== Show FeedItem fields + isReadyToMatch implementation context ==="
fd -t f 'FeedItem.java' --exec bash -lc 'nl -ba {} | sed -n "1,260p"' 2>/dev/null | sed -n '1,260p'

echo "=== Find where recordSupporterAccepted / recordPartnerAccepted increment counts ==="
rg -n "recordSupporterAccepted|recordPartnerAccepted|confirmedSupporterCount|confirmedPartnerCount" -S capstone-*/src/main/java

echo "=== Inspect FeedItemService acceptance paths around those methods ==="
rg -n "recordSupporterAccepted|recordPartnerAccepted|isReadyToMatch|MATCHED|create.*Spot|fromFeedItem" capstone-*/src/main/java/backend/feed capstone-*/src/main/java/backend/spot

echo "=== Inspect Spot creation / conversion conditions from feeds ==="
rg -n "isReadyToMatch\\(" -S capstone-*/src/main/java
rg -n "MATCHED|fromFeedItem\\(" -S capstone-*/src/main/java/backend

Repository: spot-platform/backend

Length of output: 7895


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect FeedItem entity around fields, builder/constructors, and the ready/match logic
fd -t f 'FeedItem.java' --exec bash -lc 'echo "===== {} ====="; nl -ba {} | sed -n "60,240p"' {} 

# 2) Find where authorRole is assigned / derived from feed type (OFFER/REQUEST)
rg -n "authorRole\\s*=" -S capstone-domain/src/main/java/backend/feed/entity/FeedItem.java
rg -n "authorRole\\s*=" -S capstone-domain/src/main/java/backend/feed
rg -n "getAuthorRole|FeedAuthorRole" -S capstone-domain/src/main/java/backend/feed/entity/FeedItem.java capstone-api/src/main/java/backend/feed -S

# 3) Inspect feed application acceptance and Spot creation condition
fd -t f 'FeedItemService.java' --exec bash -lc 'echo "===== {} ====="; nl -ba {} | sed -n "240,380p"' {} 

# 4) Inspect FeedItemService where FeedItem is created (look for confirmed*Count initialization)
rg -n "new FeedItem|FeedItem\\.builder\\(" -S capstone-api/src/main/java/backend/feed/service/FeedItemService.java
fd -t f 'FeedItemService.java' --exec bash -lc 'nl -ba {} | sed -n "1,260p"' {} 

# 5) Locate FeedAuthorRole enum definition
fd -t f 'FeedAuthorRole.java' --exec bash -lc 'echo "===== {} ====="; nl -ba {} | sed -n "1,200p"' {}

Repository: spot-platform/backend

Length of output: 357


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FEED_ITEM="capstone-domain/src/main/java/backend/feed/entity/FeedItem.java"
FEED_ITEM_SERVICE="capstone-api/src/main/java/backend/feed/service/FeedItemService.java"
FEED_AUTHOR_ROLE="$(fd -t f 'FeedAuthorRole.java' capstone-*/src/main/java | head -n 1 || true)"

echo "=== FeedItem.java (key sections) ==="
sed -n '1,140p' "$FEED_ITEM"
echo "---"
sed -n '140,240p' "$FEED_ITEM"

echo "=== FeedItemService.java (accept + match conversion) ==="
sed -n '260,360p' "$FEED_ITEM_SERVICE"

echo "=== FeedAuthorRole.java (if found) ==="
if [ -n "${FEED_AUTHOR_ROLE:-}" ]; then
  sed -n '1,200p' "$FEED_AUTHOR_ROLE"
else
  echo "FeedAuthorRole.java not found"
fi

echo "=== Where FeedItem.authorRole is set/derived ==="
rg -n "authorRole" "$FEED_ITEM" capstone-*/src/main/java/backend/feed -S

Repository: spot-platform/backend

Length of output: 9789


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FEED_ITEM_SERVICE="capstone-api/src/main/java/backend/feed/service/FeedItemService.java"

echo "=== FeedItemService: feed creation blocks (authorRole + types) ==="
nl -ba "$FEED_ITEM_SERVICE" | sed -n '160,320p'

echo "=== registerSpotParticipants(...) usage + role mapping ==="
rg -n "registerSpotParticipants\\(" -S "$FEED_ITEM_SERVICE"
# print method body area if found
METHOD_LINE="$(rg -n "registerSpotParticipants\\(" "$FEED_ITEM_SERVICE" | head -n1 | cut -d: -f1)"
if [ -n "$METHOD_LINE" ]; then
  start=$((METHOD_LINE-40))
  end=$((METHOD_LINE+120))
  nl -ba "$FEED_ITEM_SERVICE" | sed -n "${start},${end}p"
fi

echo "=== Any constraints preventing applying roles depending on feed type/authorRole ==="
rg -n "authorRole|getAuthorRole|FeedAuthorRole" -S "$FEED_ITEM_SERVICE"
rg -n "appliedRole|FeedApplicationRole\\.(SUPPORTER|PARTNER)" -S "$FEED_ITEM_SERVICE"

Repository: spot-platform/backend

Length of output: 193


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FEED_ITEM_SERVICE="capstone-api/src/main/java/backend/feed/service/FeedItemService.java"

echo "=== FeedItemService: feed creation (types + authorRole) around FeedCreate/AI create) ==="
# show a few strategic ranges
sed -n '180,320p' "$FEED_ITEM_SERVICE"
echo "-----"
sed -n '1,220p' "$FEED_ITEM_SERVICE"

echo "=== registerSpotParticipants(...) area ==="
# locate method and print around it
method_line="$(rg -n "registerSpotParticipants\\(" "$FEED_ITEM_SERVICE" | head -n1 | cut -d: -f1)"
echo "registerSpotParticipants first use at line: ${method_line:-"(not found)"}"
if [ -n "${method_line:-}" ]; then
  start=$((method_line-60))
  end=$((method_line+180))
  [ $start -lt 1 ] && start=1
  sed -n "${start},${end}p" "$FEED_ITEM_SERVICE"
fi

echo "=== Role constraints for accepting applications (accepted roles) ==="
rg -n "appliedRole|FeedApplicationRole\\.(SUPPORTER|PARTNER)|recordSupporterAccepted|recordPartnerAccepted|isReadyToMatch" "$FEED_ITEM_SERVICE" -S

Repository: spot-platform/backend

Length of output: 23165


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== FeedApplyRequest definition ==="
fd -t f 'FeedApplyRequest.java' capstone-*/src/main/java --exec sed -n '1,220p' {}

echo "=== Find where appliedRole is validated/derived (controllers) ==="
rg -n "FeedApplyRequest|applyToFeed\\(|FeedApplicationRole" capstone-api/src/main/java -S

echo "=== Any checks tying appliedRole to feed type/authorRole ==="
rg -n "FeedType\\.(OFFER|REQUEST)|authorRole|getAuthorRole|FeedAuthorRole" capstone-api/src/main/java -S

echo "=== Check FeedApplication entity semantics ==="
fd -t f 'FeedApplication.java' capstone-domain/src/main/java --exec sed -n '1,220p' {}

echo "=== Locate any service logic that limits partner counts / applies role-specific max ==="
rg -n "canAcceptMoreSupporters\\(|maxParticipants|getMaxPartnerCount|confirmedPartnerCount" capstone-*/src/main/java/backend/feed -S

Repository: spot-platform/backend

Length of output: 9661


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FEED_CONTROLLER="capstone-api/src/main/java/backend/feed/controller/FeedController.java"
sed -n '70,140p' "$FEED_CONTROLLER"

Repository: spot-platform/backend

Length of output: 2801


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FEED_ITEM_RESPONSE="capstone-api/src/main/java/backend/feed/dto/FeedItemResponse.java"
FEED_DETAIL_RESPONSE="capstone-api/src/main/java/backend/feed/dto/FeedDetailResponse.java"
USER_SERVICE="capstone-api/src/main/java/backend/user/service/UserService.java"
FEED_ITEM_SERVICE="capstone-api/src/main/java/backend/feed/service/FeedItemService.java"

echo "=== FeedItemResponse: partnerCount/applicantCount logic ==="
rg -n "partnerCount\\(|applicantCount\\(|calculateProgressPercent\\(" "$FEED_ITEM_RESPONSE"
sed -n '130,260p' "$FEED_ITEM_RESPONSE"

echo "=== FeedItemService: resolveConfirmedPartnerProfiles + resolveApplicantCount semantics ==="
rg -n "resolveConfirmedPartnerProfiles\\(|resolveApplicantCount\\(" "$FEED_ITEM_SERVICE"
# show around each
perl -ne 'print if $.>=380 && $.<=520' "$FEED_ITEM_SERVICE" 2>/dev/null || true

# safer: print ranges known from earlier snippet: we already saw resolveConfirmedPartnerProfiles near end; reprint that region
sed -n '360,520p' "$FEED_ITEM_SERVICE"

echo "=== UserService: lines about applicantCount (if relevant) ==="
sed -n '250,340p' "$USER_SERVICE"

Repository: spot-platform/backend

Length of output: 17558


🏁 Script executed:

#!/bin/bash
set -euo pipefail
TEST_FILE="capstone-api/src/test/java/backend/feed/service/FeedItemServiceTest.java"
if [ -f "$TEST_FILE" ]; then
  sed -n '1,260p' "$TEST_FILE"
else
  echo "Test file not found: $TEST_FILE"
fi

Repository: spot-platform/backend

Length of output: 9572


🏁 Script executed:

#!/bin/bash
set -euo pipefail
TEST_FILE="capstone-api/src/test/java/backend/feed/service/FeedItemServiceTest.java"
# print bottom where helper methods likely defined
sed -n '260,520p' "$TEST_FILE"

Repository: spot-platform/backend

Length of output: 1134


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "confirmedSupporterCount|supporterCount" -S capstone-*/src/main/java

Repository: spot-platform/backend

Length of output: 677


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "maxParticipants|canAcceptMoreSupporters\\(|confirmedPartnerCount|confirmedSupporterCount" -S capstone-api/src/main/java/backend

Repository: spot-platform/backend

Length of output: 918


isReadyToMatch()는 피드 작성자 역할을 반영하지 않아서 변환 조건이 어긋날 수 있음

FeedItem.authorRole(OFFER=SUpportER, REQUEST=PARTNER)은 있지만 isReadyToMatch()는 오직 confirmedSupporterCount/confirmedPartnerCount만 보고, 두 카운트는 FeedItemService.acceptApplication()에서 **수락된 FeedApplication.appliedRole**에 따라서만 증가합니다. 또한 acceptApplication()appliedRolefeedItem.type/authorRole과 정합성 있게 제한하지 않으므로, 현재 로직은 SUPPORTER와 PARTNER 애플리케이션이 모두 1건 이상 수락되어야 Spot 전환이 됩니다(작성자는 한 역할을 이미 갖는 모델이라면 전환이 막힐 수 있음).

🤖 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-domain/src/main/java/backend/feed/entity/FeedItem.java` around lines
199 - 204, The current isReadyToMatch() only checks
confirmedSupporterCount/confirmedPartnerCount and ignores FeedItem.authorRole so
it can block conversion when the author already holds one role; update
isReadyToMatch() to treat the author as already occupying their role: compute
supporters = (confirmedSupporterCount != null ? confirmedSupporterCount : 0) and
partners = (confirmedPartnerCount != null ? confirmedPartnerCount : 0), then if
authorRole == SUPPORTER return partners >= 1, if authorRole == PARTNER return
supporters >= 1, otherwise return supporters >= 1 && partners >= 1; use the
existing field names (isReadyToMatch, confirmedSupporterCount,
confirmedPartnerCount, authorRole) and keep null-safety.

Copy link
Copy Markdown
Collaborator

@ca5tlechan ca5tlechan left a comment

Choose a reason for hiding this comment

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

❌ Changes Requested — Blocking 1건 (CodeRabbit 동의)

✅ 좋은 점

  • confirmedSupporterCount 분리, recordSupporterAccepted / recordPartnerAccepted 도메인 메서드 ✅
  • convertFeedToSpot() 추출로 중복 제거 ✅
  • earlyStart 플로우(request → consent → allMatch → 전환) 로직 명확 ✅
  • findByIdAndDeletedFalseForUpdate 비관적 락 사용 ✅

🔴 Blocking — authorRole이 supporter/partner 카운트에서 누락

FeedItem.authorRole 필드(line 108)가 접근 가능하지만, 아래 세 메서드 모두 수락된 APPLICATION 카운트만 집계해 작성자 역할이 이미 한 슬롯을 차지한다는 사실을 무시합니다.

  1. canAcceptMoreSupporters()authorRole = SUPPORTER인 피드에서 confirmedSupporterCount = 0 < 1true 반환. 외부 SUPPORTER 신청을 추가 수락하게 됨.
  2. isReadyToMatch()authorRole = SUPPORTER인 피드에서 supporters = 0 → 파트너가 maxParticipants만큼 수락돼도 자동 전환 미발생.
  3. canRequestEarlyStart() — 동일 문제로 supporters >= 1 조건 미충족.

수정안 (isReadyToMatch 예시):

int supporters = (confirmedSupporterCount != null ? confirmedSupporterCount : 0)
    + (this.authorRole == FeedAuthorRole.SUPPORTER ? 1 : 0);
int partners   = (confirmedPartnerCount  != null ? confirmedPartnerCount  : 0)
    + (this.authorRole == FeedAuthorRole.PARTNER   ? 1 : 0);
return supporters >= 1 && partners >= this.maxParticipants;

canAcceptMoreSupporters / canRequestEarlyStart도 동일하게 authorRole 반영 필요합니다.

인라인 코멘트 참고.

* 자동 Spot 전환 조건: 서포터 1명 + 파트너 수락 수 >= maxParticipants.
* maxParticipants 미설정 시 자동 전환 없음 — 작성자가 수동 진행 요청해야 함.
*/
public boolean isReadyToMatch() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

authorRole이 반영되지 않아 authorRole = SUPPORTER인 피드에서 supporters가 항상 0 → 자동 전환이 절대 발생하지 않습니다.

public boolean isReadyToMatch() {
    if (this.maxParticipants == null) return false;
    int supporters = (confirmedSupporterCount != null ? confirmedSupporterCount : 0)
        + (this.authorRole == FeedAuthorRole.SUPPORTER ? 1 : 0);
    int partners = (confirmedPartnerCount != null ? confirmedPartnerCount : 0)
        + (this.authorRole == FeedAuthorRole.PARTNER ? 1 : 0);
    return supporters >= 1 && partners >= this.maxParticipants;
}

public boolean canAcceptMore() {
int confirmed = this.confirmedPartnerCount != null ? this.confirmedPartnerCount : 0;
/** 서포터 추가 수락 가능 여부. 서포터는 1명으로 고정. */
public boolean canAcceptMoreSupporters() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

authorRole = SUPPORTER인 피드에서 confirmedSupporterCount = 0 < 1true 반환. 작성자가 이미 서포터 슬롯을 차지했으므로 외부 SUPPORTER 수락이 허용돼서는 안 됩니다.

public boolean canAcceptMoreSupporters() {
    int authorSupplied = (this.authorRole == FeedAuthorRole.SUPPORTER) ? 1 : 0;
    int confirmed = (this.confirmedSupporterCount != null ? this.confirmedSupporterCount : 0);
    return (confirmed + authorSupplied) < MAX_SUPPORTERS_PER_FEED;
}

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.

fix(feed): Spot 전환 조건 — 서포터 1명 + 파트너 1명 이상 수락 시 MATCHED

2 participants