Feat/#9 개인 미션 조회 API 추가 - #10
Conversation
📝 WalkthroughWalkthroughAdds custom mission creation constraints and track association, repository filtering, and an authenticated endpoint that returns the user’s custom missions with today’s completion status. ChangesCustom mission flow
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
actor User
participant MissionController
participant MissionService
participant MissionRepository
User->>MissionController: GET /api/missions/custom
MissionController->>MissionService: getCustomMissions(user)
MissionService->>MissionRepository: findByUserAndTrackAndType(user, track, USER_CUSTOM)
MissionRepository-->>MissionService: custom missions
MissionService-->>MissionController: MissionListResponse with completion flags
MissionController-->>User: ApiResponse with custom mission list
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/java/com/team4/hackerton/domain/mission/service/MissionService.java (1)
93-94: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate
UserTracklookup pattern.The
userTrackRepository.findByUserAndIsCurrentTrue(user).orElseThrow(...)block is now repeated across five methods in this service. Extracting a private helper (e.g.,getCurrentTrack(User user)) would reduce duplication and centralize theUSER_TRACK_NOT_FOUNDhandling.♻️ Proposed helper extraction
+ private Track getCurrentTrack(User user) { + return userTrackRepository.findByUserAndIsCurrentTrue(user) + .orElseThrow(() -> new AppException(MissionErrorCode.USER_TRACK_NOT_FOUND)) + .getTrack(); + } + public MissionListResponse getCustomMissions(User user) { - UserTrack userTrack = userTrackRepository.findByUserAndIsCurrentTrue(user) - .orElseThrow(() -> new AppException(MissionErrorCode.USER_TRACK_NOT_FOUND)); - - Track track = userTrack.getTrack(); + Track track = getCurrentTrack(user); LocalDate today = LocalDate.now();Also applies to: 112-113
🤖 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/team4/hackerton/domain/mission/service/MissionService.java` around lines 93 - 94, Extract the repeated current-track lookup into a private helper such as getCurrentTrack(User user) in MissionService, using userTrackRepository.findByUserAndIsCurrentTrue(user) and throwing USER_TRACK_NOT_FOUND when absent. Replace the duplicated lookup blocks across all affected methods with calls to this helper.
🤖 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/team4/hackerton/domain/mission/service/MissionService.java`:
- Around line 102-107: Make custom mission creation atomic in MissionService by
synchronizing the count check and Mission.ofUserCustom save operation: lock the
relevant UserTrack row through the repository query (with a transactional
boundary) or enforce an equivalent database-level constraint, so concurrent
requests cannot exceed the two-mission cap.
---
Nitpick comments:
In
`@src/main/java/com/team4/hackerton/domain/mission/service/MissionService.java`:
- Around line 93-94: Extract the repeated current-track lookup into a private
helper such as getCurrentTrack(User user) in MissionService, using
userTrackRepository.findByUserAndIsCurrentTrue(user) and throwing
USER_TRACK_NOT_FOUND when absent. Replace the duplicated lookup blocks across
all affected methods with calls to this helper.
🪄 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 Plus
Run ID: f084e2b9-760d-46cf-bcf0-c1e27f383eff
📒 Files selected for processing (6)
src/main/java/com/team4/hackerton/domain/mission/code/MissionErrorCode.javasrc/main/java/com/team4/hackerton/domain/mission/code/MissionSuccessCode.javasrc/main/java/com/team4/hackerton/domain/mission/controller/MissionController.javasrc/main/java/com/team4/hackerton/domain/mission/entity/Mission.javasrc/main/java/com/team4/hackerton/domain/mission/repository/MissionRepository.javasrc/main/java/com/team4/hackerton/domain/mission/service/MissionService.java
| long customCount = missionRepository.countByUserAndTrackAndType(user, track, MissionType.USER_CUSTOM); | ||
| if (customCount >= 2) { | ||
| throw new AppException(MissionErrorCode.CUSTOM_MISSION_LIMIT_EXCEEDED); | ||
| } | ||
|
|
||
| Mission mission = missionRepository.save(Mission.ofUserCustom(user, track, request.getTitle())); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## MissionService outline\n'
ast-grep outline src/main/java/com/team4/hackerton/domain/mission/service/MissionService.java --view expanded || true
printf '\n## Relevant MissionService slice\n'
sed -n '1,220p' src/main/java/com/team4/hackerton/domain/mission/service/MissionService.java | cat -n
printf '\n## Mission repository search\n'
rg -n "countByUserAndTrackAndType|save\\(|`@Lock`|PESSIMISTIC|UserTrack|custom mission|CUSTOM_MISSION_LIMIT_EXCEEDED" src/main/java -S
printf '\n## Mission entity / related constraints search\n'
rg -n "`@Table`|uniqueConstraints|`@Column`\\(|`@Index`|`@Check`|`@Version`|`@OneToOne`|`@ManyToOne`|`@NaturalId`" src/main/java/com/team4/hackerton/domain -S
printf '\n## UserTrack / Mission entity files\n'
fd -a "Mission.java|UserTrack.java|MissionRepository.java|UserTrackRepository.java" src/main/javaRepository: 8th-COKERTHON/server-team4
Length of output: 15509
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## MissionRepository\n'
cat -n src/main/java/com/team4/hackerton/domain/mission/repository/MissionRepository.java
printf '\n## Mission entity\n'
cat -n src/main/java/com/team4/hackerton/domain/mission/entity/Mission.java
printf '\n## UserTrack entity\n'
cat -n src/main/java/com/team4/hackerton/domain/track/entity/UserTrack.java
printf '\n## MissionLog entity (for comparison on constraints)\n'
cat -n src/main/java/com/team4/hackerton/domain/mission/entity/MissionLog.java
printf '\n## Search for transaction isolation / locking annotations in mission & track packages\n'
rg -n "`@Transactional`\\(|`@Lock`|Isolation|PESSIMISTIC|OPTIMISTIC|uniqueConstraints|`@Version`|`@Check`" src/main/java/com/team4/hackerton/domain/{mission,track} -SRepository: 8th-COKERTHON/server-team4
Length of output: 8373
Make the custom-mission cap atomic src/main/java/com/team4/hackerton/domain/mission/service/MissionService.java:102-107
countByUserAndTrackAndType(...) and save(...) are separate steps, so concurrent requests can both pass the >= 2 check and insert a third custom mission. Lock the UserTrack row or add a DB-level guard instead of relying on count-then-insert.
🤖 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/team4/hackerton/domain/mission/service/MissionService.java`
around lines 102 - 107, Make custom mission creation atomic in MissionService by
synchronizing the count check and Mission.ofUserCustom save operation: lock the
relevant UserTrack row through the repository query (with a transactional
boundary) or enforce an equivalent database-level constraint, so concurrent
requests cannot exceed the two-mission cap.
Summary by CodeRabbit