Skip to content

refactor: 내 모든 텃밭 id 조회#161

Merged
xoruddl merged 2 commits into
developfrom
leetk-refactor
Aug 28, 2025
Merged

refactor: 내 모든 텃밭 id 조회#161
xoruddl merged 2 commits into
developfrom
leetk-refactor

Conversation

@xoruddl
Copy link
Copy Markdown
Member

@xoruddl xoruddl commented Aug 28, 2025

📝 개요
이번 PR의 핵심 내용을 한 줄로 요약해 주세요.

💻 작업 내용
이번 PR에서 작업한 내용을 상세히 설명해 주세요.

작업 내용 1
작업 내용 2
...

✅ PR 체크리스트
PR을 보내기 전에 아래 체크리스트를 확인해 주세요.

커밋 메시지는 포맷에 맞게 작성했나요?
스스로 코드를 다시 한번 검토했나요?
관련 이슈를 연결했나요?
빌드 및 테스트가 로컬에서 성공했나요?

🔗 관련 이슈

스크린샷 (선택)
UI 변경 사항이 있다면 스크린샷을 첨부해 주세요.

Summary by CodeRabbit

  • Improvements
    • 내 정원 목록에서 잠금된 정원 제외 및 슬롯 순 정렬 강화.
    • 프로필 이미지 선택 로직 개선(정원 아바타 우선) 및 물주기 가능 여부 계산 정확도 향상.
    • 하루 친구 물주기 상한값 도입으로 잔여 횟수 정확히 표시.
  • Performance
    • 프로필 조회 시 N+1 쿼리 감소로 응답 속도 향상.
  • Bug Fixes
    • 음수로 표시되던 물주기 잔여 카운트 수정.
    • 아바타 업데이트 대상 및 null 안전성 문제 해결.
  • Refactor
    • 서비스로 로직 위임 및 예외를 표준화해 일관된 에러 코드 제공(새 에러 코드: AVATAR_NOT_FOUND).

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 28, 2025

Walkthrough

UserController의 getMyGardenIds가 서비스로 위임되었고, UserService 전반에서 에러 처리를 CustomApiException/ErrorCode로 통일, 친구 물주기 일일 제한 상수 도입, 프로필 조회 로직(정렬/필터링/N+1 회피/null 안전성)이 재작성되었습니다. 공개 API 시그니처는 변경되지 않았습니다.

Changes

Cohort / File(s) Change Summary
Controller 위임 정리
src/main/java/com/example/cp_main_be/domain/member/user/presentation/UserController.java
getMyGardenIds의 정원 ID 조립 로직을 userService.getMyGardenIds(user)로 위임. 관련 스트림/Comparator/Collectors import 제거 및 주석 추가. 공개 시그니처 유지.
UserService 리팩터·로직 개선
src/main/java/com/example/cp_main_be/domain/member/user/service/UserService.java
- 친구 물주기 일일 제한 상수 MAX_FRIEND_WATERING_PER_DAY = 3 도입 및 음수 방지 계산 적용
- 모든 조회/검증에서 CustomApiException(ErrorCode.*)로 예외 통일(유저/아바타/토큰 등)
- 관리 엔티티 재조회 패턴 적용 (findById 등) 및 null-가드 추가
- getMyGardenIds: 잠금된 정원 제외 후 정렬하여 ID 수집
- getUserProfile: current/profile 유저 조회 재작성, 프로필 이미지 우선순위(첫 정원의 아바타) 적용, 정원 slot 정렬, 오늘 물 준 정원셋 사전로딩으로 isWateringAbleByMe 계산하여 N+1 회피, 아바타 null-안전 처리
- import 정리 및 일부 메시지/예외 문자열 간소화
에러 코드 확장
src/main/java/com/example/cp_main_be/global/common/ErrorCode.java
AVATAR_NOT_FOUND(HttpStatus.NOT_FOUND, "E40411", "해당 아바타를 찾을 수 없습니다.") enum 값 추가.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as 클라이언트
  participant UC as UserController
  participant US as UserService
  participant UR as UserRepository

  rect rgba(224,240,255,0.5)
  C->>UC: GET /users/me/gardens/ids
  UC->>US: getMyGardenIds(user)
  US->>UR: findById(user.id) (with gardens)
  UR-->>US: Managed User(+gardens)
  US-->>UC: Sorted, unlocked gardenId list
  UC-->>C: 200 OK [ids]
  end
Loading
sequenceDiagram
  autonumber
  participant C as 클라이언트
  participant US as UserService
  participant UR as UserRepository
  participant WL as WateringLogRepo

  rect rgba(235,255,235,0.5)
  C->>US: getUserProfile(auth, profileUserId)
  US->>UR: findByUuid(auth) → currentUser
  US->>UR: findById(profileUserId) → profileUser(+gardens/avatars)
  US->>WL: preload today's watered gardenIds by currentUser
  WL-->>US: Set<gardenId>
  US-->>C: Profile DTO (image, gardens(sorted), leftWaterCount, isWateringAbleByMe)
  end

  note over US: 오류는 CustomApiException(ErrorCode.*)로 반환
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • lejuho
  • c5ln

Poem

폴짝 뛰는 토끼 한 마리, 코드를 헤집어 보니
예외는 한곳에 모이고, 아바타는 제자리를 찾았네 🐰
물은 셋까지, 오늘은 안심! 🌱
정원은 정렬되고, 잠긴 문은 살짝 닫고—
배포 전엔 당근 간식 하나로 축하해! 🥕

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a05687f and 133e762.

📒 Files selected for processing (1)
  • src/main/java/com/example/cp_main_be/global/common/ErrorCode.java (1 hunks)
🔇 Additional comments (1)
src/main/java/com/example/cp_main_be/global/common/ErrorCode.java (1)

44-45: ErrorCode(E40411) 추가 승인
E40411 중복 없음, ErrorCode에 @Enumerated(EnumType.ORDINAL)·.ordinal() 의존성 없음, AvatarNotFoundException 호출부는 모두 CustomApiException(ErrorCode.AVATAR_NOT_FOUND)로 치환됨.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch leetk-refactor

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/main/java/com/example/cp_main_be/domain/member/user/presentation/UserController.java (1)

46-51: PathVariable/RequestParam 불일치로 400/404 가능

매핑은 /me/{avatarId}인데 파라미터는 @RequestParam입니다. @PathVariable로 교체하세요.

-  @PatchMapping("/me/{avatarId}")
+  @PatchMapping("/me/{avatarId}")
   public ResponseEntity<ApiResponse<Void>> updateAvatar(
       @AuthenticationPrincipal User user,
       @RequestBody @Valid AvatarChangeRequest request,
-      @RequestParam("avatarId") Long avatarId) {
+      @PathVariable("avatarId") Long avatarId) {
src/main/java/com/example/cp_main_be/domain/member/user/service/UserService.java (3)

119-137: NPE/잘못된 Principal 대비 부족

authentication null/미인증, 잘못된 UUID 문자열에 대비해야 합니다.

   public User getCurrentUser() {
-    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+    if (authentication == null || !authentication.isAuthenticated()) {
+      throw new CustomApiException(ErrorCode.INVALID_TOKEN, "인증 정보를 찾을 수 없습니다.");
+    }
     Object principal = authentication.getPrincipal();
@@
-    if (principal instanceof String uuidString) {
-      UUID userUuid = UUID.fromString(uuidString);
+    if (principal instanceof String uuidString) {
+      UUID userUuid;
+      try {
+        userUuid = UUID.fromString(uuidString);
+      } catch (IllegalArgumentException e) {
+        throw new CustomApiException(ErrorCode.INVALID_TOKEN, "유효하지 않은 사용자 식별자입니다.");
+      }
       return userRepository
           .findByUuid(userUuid) // UUID로 최신 유저 정보를 조회합니다.
           .orElseThrow(() -> new CustomApiException(ErrorCode.USER_NOT_FOUND));
     }

145-158: 인증 주체 null 방어 및 컨트롤러 문서와의 정합성 확인

user가 null일 수 있는 경로를 방어하세요. 또한 “잠김 제외” 정책을 컨트롤러 설명과 일치시켜 주세요.

   public List<Long> getMyGardenIds(User user) {
+    if (user == null) {
+      throw new CustomApiException(ErrorCode.INVALID_TOKEN, "인증된 사용자 정보가 없습니다.");
+    }

177-193: NPE 위험: AvatarMaster가 null일 경우

avatar.getAvatarMaster()가 null이면 NPE가 발생합니다.

-                avatar -> {
-                  // AI 아바타처럼 Avatar에 직접 저장된 고유 imageUrl이 있다면 그것을 우선 사용합니다.
-                  if (avatar.getImageUrl() != null && !avatar.getImageUrl().isBlank()) {
-                    return avatar.getImageUrl();
-                  }
-                  // 없다면, AvatarMaster에 정의된 기본 이미지를 사용합니다.
-                  return avatar.getAvatarMaster().getDefaultImageUrl();
-                })
+                avatar -> {
+                  if (avatar.getImageUrl() != null && !avatar.getImageUrl().isBlank()) {
+                    return avatar.getImageUrl();
+                  }
+                  var master = avatar.getAvatarMaster();
+                  return master != null ? master.getDefaultImageUrl() : null;
+                })
🧹 Nitpick comments (1)
src/main/java/com/example/cp_main_be/domain/member/user/presentation/UserController.java (1)

83-91: 서비스 위임은 적절. 다만 문서(“모든 텃밭”)와 실제 동작(잠금 텃밭 제외) 불일치

UserService.getMyGardenIds는 잠긴 텃밭을 제외합니다. API 설명에 이를 반영하거나 서비스에서 필터링을 제거해 일관성을 맞춰주세요.

-  @Operation(
-      summary = "내 텃밭 ID 목록 조회",
-      description = "현재 로그인한 유저와 연결된 모든 텃밭의 ID 목록을 조회합니다. 텃밭 슬롯 번호 순으로 정렬됩니다.")
+  @Operation(
+      summary = "내 텃밭 ID 목록 조회",
+      description = "현재 로그인한 유저의 잠겨있지 않은 텃밭 ID 목록을 슬롯 번호 순으로 조회합니다.")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 62cb5e5 and a05687f.

📒 Files selected for processing (2)
  • src/main/java/com/example/cp_main_be/domain/member/user/presentation/UserController.java (1 hunks)
  • src/main/java/com/example/cp_main_be/domain/member/user/service/UserService.java (10 hunks)
🧰 Additional context used
🪛 GitHub Actions: Spring Boot CI/CD with AWS
src/main/java/com/example/cp_main_be/domain/member/user/service/UserService.java

[error] 59-59: Cannot find symbol AVATAR_NOT_FOUND in ErrorCode (referenced in UserService.java:59).

🔇 Additional comments (3)
src/main/java/com/example/cp_main_be/domain/member/user/service/UserService.java (3)

34-35: 매직 넘버 제거를 위한 상수 도입 좋습니다

일관된 정책 관리에 유리합니다.


168-176: 프로필 조회 시 최신 조회 로직 일원화 OK

현재/대상 사용자 조회를 서비스 규약(CustomApiException)으로 통일한 점 좋습니다.


215-221: N+1 회피를 위한 선조회(Set) 도입 좋습니다

워터링 가능 여부 판정의 성능 개선에 기여합니다.

Comment on lines 57 to 60
avatarRepository
.findById(avatarId)
.orElseThrow(() -> new AvatarNotFoundException("아바타를 찾을 수 없습니다."));
.orElseThrow(() -> new CustomApiException(ErrorCode.AVATAR_NOT_FOUND));

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

빌드 실패: ErrorCode.AVATAR_NOT_FOUND 심볼 없음

CI 오류를 막기 위해 기존 에러코드로 대체하거나(ErrorCode.NOT_FOUND 등), ErrorCode에 상수를 추가하세요. 단기해결(컴파일 우선) 패치 예시:

-            .orElseThrow(() -> new CustomApiException(ErrorCode.AVATAR_NOT_FOUND));
+            .orElseThrow(() -> new CustomApiException(ErrorCode.NOT_FOUND, "아바타를 찾을 수 없습니다.")); // ErrorCode.NOT_FOUND가 없다면 적절한 기존 코드로 교체

권장: ErrorCode에 도메인 전용 상수 추가 후 원복.

- AVATAR_NOT_FOUND
+ AVATAR_NOT_FOUND

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 GitHub Actions: Spring Boot CI/CD with AWS

[error] 59-59: Cannot find symbol AVATAR_NOT_FOUND in ErrorCode (referenced in UserService.java:59).

🤖 Prompt for AI Agents
In
src/main/java/com/example/cp_main_be/domain/member/user/service/UserService.java
around lines 57 to 60, the code references ErrorCode.AVATAR_NOT_FOUND which
doesn't exist and causes build failures; fix by either (preferred) adding a new
constant AVATAR_NOT_FOUND to the ErrorCode enum/class with an appropriate
message/code and use that here, or as a short-term compile-fix replace
ErrorCode.AVATAR_NOT_FOUND with an existing constant such as
ErrorCode.NOT_FOUND; ensure the ErrorCode file is saved/compiled and imports are
correct before committing.

Comment on lines 73 to 81
public void updateNickname(User user, String newNickname) {

user.updateProfile(newNickname, null);
// [수정] stale한 user 객체 대신, ID로 최신 정보를 조회해서 사용합니다.
User managedUser =
userRepository
.findById(user.getId())
.orElseThrow(() -> new CustomApiException(ErrorCode.USER_NOT_FOUND));
managedUser.updateProfile(newNickname, null);
userRepository.save(user);
}
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

버그: managedUser를 수정하고도 save(user) 호출

영속 엔티티가 managedUser이므로 save 대상이 잘못되었습니다.

-    managedUser.updateProfile(newNickname, null);
-    userRepository.save(user);
+    managedUser.updateProfile(newNickname, null);
+    userRepository.save(managedUser); // 또는 @Transactional에 의존해 생략
🤖 Prompt for AI Agents
In
src/main/java/com/example/cp_main_be/domain/member/user/service/UserService.java
around lines 73 to 81, the code updates the fetched managedUser but calls
userRepository.save(user) (the stale/unmanaged instance); change the save target
to the managed entity by calling userRepository.save(managedUser) (or remove the
explicit save entirely if relying on JPA dirty checking) so the persisted update
is applied to the correct entity.

Comment on lines 225 to 239
profileUser.getGardens().stream()
.sorted(Comparator.comparing(Garden::getSlotNumber))
.map(
garden -> {
// 현재 접속 유저가 이 정원에 오늘 물을 줄 수 있는지 여부
boolean isWateringAbleByMe = false;
// 조건: 1) 아직 오늘 남에게 물 줄 수 있는 횟수가 남아있어야 하고 (leftWaterCountForOthers > 0)
// 2) 오늘 이 정원에 내가 물을 준 적이 없어야 한다.
if (leftWaterCountForOthers > 0) {
boolean alreadyWateredByMe =
friendWateringLogRepository
.existsByWaterGiverAndWateredGardenAndWateredAtAfter(
currentUser, garden, startOfWateringDay);
isWateringAbleByMe = !alreadyWateredByMe;
}
// DB를 반복 조회하는 대신, 미리 조회한 Set에서 확인하여 성능을 개선합니다.
boolean alreadyWateredByMe = wateredGardenIds.contains(garden.getId());
boolean isWateringAbleByMe = leftWaterCountForOthers > 0 && !alreadyWateredByMe;

HomeResponseDto.AvatarInfo avatarInfoForGarden =
HomeResponseDto.AvatarInfo.builder()
.avatarId(garden.getAvatar().getId())
// 아바타가 없는 텃밭이 있을 수 있는 예외 케이스를 방어합니다.
.avatarId(garden.getAvatar() != null ? garden.getAvatar().getId() : null)
.avatarName(garden.getAvatar().getNickname())
.avatarImageUrl(garden.getAvatar().getAvatarMaster().getDefaultImageUrl())
.build();
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

NPE 위험: 아바타가 없는 텃밭 처리 미흡

avatarId만 null-세이프, 이름/이미지 접근은 그대로 NPE입니다. 안전하게 빌드하세요.

-                  HomeResponseDto.AvatarInfo avatarInfoForGarden =
-                      HomeResponseDto.AvatarInfo.builder()
-                          // 아바타가 없는 텃밭이 있을 수 있는 예외 케이스를 방어합니다.
-                          .avatarId(garden.getAvatar() != null ? garden.getAvatar().getId() : null)
-                          .avatarName(garden.getAvatar().getNickname())
-                          .avatarImageUrl(garden.getAvatar().getAvatarMaster().getDefaultImageUrl())
-                          .build();
+                  var avatar = garden.getAvatar();
+                  HomeResponseDto.AvatarInfo avatarInfoForGarden =
+                      HomeResponseDto.AvatarInfo.builder()
+                          .avatarId(avatar != null ? avatar.getId() : null)
+                          .avatarName(avatar != null ? avatar.getNickname() : null)
+                          .avatarImageUrl(
+                              avatar != null
+                                  ? (avatar.getImageUrl() != null && !avatar.getImageUrl().isBlank()
+                                        ? avatar.getImageUrl()
+                                        : (avatar.getAvatarMaster() != null
+                                            ? avatar.getAvatarMaster().getDefaultImageUrl()
+                                            : null))
+                                  : null)
+                          .build();
📝 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
profileUser.getGardens().stream()
.sorted(Comparator.comparing(Garden::getSlotNumber))
.map(
garden -> {
// 현재 접속 유저가 이 정원에 오늘 물을 줄 수 있는지 여부
boolean isWateringAbleByMe = false;
// 조건: 1) 아직 오늘 남에게 물 줄 수 있는 횟수가 남아있어야 하고 (leftWaterCountForOthers > 0)
// 2) 오늘 이 정원에 내가 물을 준 적이 없어야 한다.
if (leftWaterCountForOthers > 0) {
boolean alreadyWateredByMe =
friendWateringLogRepository
.existsByWaterGiverAndWateredGardenAndWateredAtAfter(
currentUser, garden, startOfWateringDay);
isWateringAbleByMe = !alreadyWateredByMe;
}
// DB를 반복 조회하는 대신, 미리 조회한 Set에서 확인하여 성능을 개선합니다.
boolean alreadyWateredByMe = wateredGardenIds.contains(garden.getId());
boolean isWateringAbleByMe = leftWaterCountForOthers > 0 && !alreadyWateredByMe;
HomeResponseDto.AvatarInfo avatarInfoForGarden =
HomeResponseDto.AvatarInfo.builder()
.avatarId(garden.getAvatar().getId())
// 아바타가 없는 텃밭이 있을 수 있는 예외 케이스를 방어합니다.
.avatarId(garden.getAvatar() != null ? garden.getAvatar().getId() : null)
.avatarName(garden.getAvatar().getNickname())
.avatarImageUrl(garden.getAvatar().getAvatarMaster().getDefaultImageUrl())
.build();
profileUser.getGardens().stream()
.sorted(Comparator.comparing(Garden::getSlotNumber))
.map(
garden -> {
// DB를 반복 조회하는 대신, 미리 조회한 Set에서 확인하여 성능을 개선합니다.
boolean alreadyWateredByMe = wateredGardenIds.contains(garden.getId());
boolean isWateringAbleByMe = leftWaterCountForOthers > 0 && !alreadyWateredByMe;
var avatar = garden.getAvatar();
HomeResponseDto.AvatarInfo avatarInfoForGarden =
HomeResponseDto.AvatarInfo.builder()
.avatarId(avatar != null ? avatar.getId() : null)
.avatarName(avatar != null ? avatar.getNickname() : null)
.avatarImageUrl(
avatar != null
? (avatar.getImageUrl() != null && !avatar.getImageUrl().isBlank()
? avatar.getImageUrl()
: (avatar.getAvatarMaster() != null
? avatar.getAvatarMaster().getDefaultImageUrl()
: null))
: null)
.build();
// ...rest of mapping logic...
})
🤖 Prompt for AI Agents
In
src/main/java/com/example/cp_main_be/domain/member/user/service/UserService.java
around lines 225 to 239, the builder assumes garden.getAvatar() (and
avatar.getAvatarMaster()) are non-null which causes NPEs; make all
avatar-derived fields null-safe by checking garden.getAvatar() before accessing
nickname and avatarMaster, and also guard avatar.getAvatarMaster() before
calling getDefaultImageUrl(), populating avatarId, avatarName and avatarImageUrl
with null (or sensible defaults) when the corresponding objects are absent.

@xoruddl xoruddl merged commit 7f4b0bd into develop Aug 28, 2025
6 checks passed
@xoruddl xoruddl deleted the leetk-refactor branch August 28, 2025 08:24
@coderabbitai coderabbitai Bot mentioned this pull request Sep 3, 2025
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.

1 participant