Skip to content

feat: 개인 알림 생성 메서드 확장 - #120

Merged
guingguing merged 10 commits into
developfrom
feature/111-notification-create-methods
Aug 5, 2026
Merged

feat: 개인 알림 생성 메서드 확장#120
guingguing merged 10 commits into
developfrom
feature/111-notification-create-methods

Conversation

@guingguing

@guingguing guingguing commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🔗 관련 이슈 (Related Issue)

Closes #111

📝 작업 내용

개인 알림 정책에 맞춰 각 도메인에서 호출할 수 있는 알림 생성 메서드를 확장했습니다.

각 도메인에서는 Notification 엔티티나 Repository를 직접 사용하지 않고, NotificationService의 메서드만 호출하면 알림 문구 생성과 notification 테이블 저장까지 처리되도록 구성했습니다.

주요 변경 사항

  • 개인 알림 타입 확장
  • 프로젝트 합류 알림 생성 메서드 추가
  • 새 일정 등록 알림 생성 메서드 추가
  • 새 공지 등록 알림 생성 메서드 추가
  • 파일 등록 알림 생성 메서드 추가
  • 영상 피드백/답글 알림 문구 생성 방식 정리
  • 새로운 지원자 알림 문구 생성 방식 정리
  • 일정 담당자 지정 알림 문구를 정책서 기준으로 수정
  • 정책에서 제외된 프로젝트 초대 알림 제거
  • 파일 등록 알림 그룹핑 제거

구현/정리 내용

  1. 프로젝트 합류 알림

프로젝트에 사용자가 합류했을 때 프로젝트 참여자에게 알림을 생성할 수 있도록 메서드를 추가했습니다.

  • type: PROJECT_JOINED
  • targetType: PROJECT
  • targetId: projectId
  • title: {프로젝트명} · 합류
  • content: {합류자명}님이 프로젝트에 합류했어요
  1. 새 일정 등록 알림

프로젝트 일정이 새로 등록되었을 때 프로젝트 참여자에게 알림을 생성할 수 있도록 메서드를 추가했습니다.

  • type: SCHEDULE_CREATED
  • targetType: SCHEDULE
  • targetId: scheduleId
  • title: {프로젝트명} · 새 일정
  • content: {등록자명}님이 [{일정명}] 일정을 등록했어요
  1. 새 공지 등록 알림

프로젝트 공지가 등록되었을 때 프로젝트 참여자에게 알림을 생성할 수 있도록 메서드를 추가했습니다.

  • type: NOTICE_CREATED
  • targetType: NOTICE
  • targetId: noticeId
  • title: {프로젝트명} · 새 공지
  • content: {등록자명}님이 새 공지를 등록했어요: {공지 제목}
  1. 파일 등록 알림

프로젝트 파일이 등록되었을 때 프로젝트 참여자에게 알림을 생성할 수 있도록 메서드를 추가했습니다.

  • type: FILE_UPLOADED
  • targetType: PROJECT_FILE
  • targetId: projectId
  • title: {프로젝트명} · 새 파일
  • content: {등록자명}님이 [{파일명}] 파일을 등록했어요

현재 파일 업로드는 단건 등록 기준이므로 그룹핑은 적용하지 않았습니다.

  1. 영상 피드백/답글 알림

영상 피드백 또는 답글이 등록되었을 때 프로젝트 참여자에게 알림을 생성할 수 있도록 정리했습니다.

  • type: VIDEO_FEEDBACK_COMMENTED
  • targetType: VIDEO
  • targetId: videoId
  • 단건 content: {작성자명}님이 [{영상명}]에 새로운 피드백을 남겼어요
  • 그룹핑 content: [{영상명}]에 새로운 피드백 {N}건이 등록되었어요

동일 영상 기준의 읽지 않은 알림이 이미 있으면 새 알림을 만들지 않고 기존 알림의 title, content, groupCount를 갱신합니다.

  1. 새로운 지원자 알림

공고에 새로운 지원자가 발생했을 때 공고 작성자에게 알림을 생성할 수 있도록 정리했습니다.

  • type: RECRUITMENT_APPLIED
  • targetType: RECRUITMENT
  • targetId: recruitmentId
  • 단건 content: {지원자명}님이 [{공고명}]에 지원했어요
  • 그룹핑 content: [{공고명}]에 새로운 지원자 {N}명이 지원했어요

동일 공고 기준의 읽지 않은 알림이 이미 있으면 새 알림을 만들지 않고 기존 알림의 title, content, groupCount를 갱신합니다.

  1. 프로젝트 초대 알림 제거

초대 링크 생성 시점에는 수신자를 특정할 수 없고, 정책이 프로젝트 합류 알림 기준으로 정리되어 기존 프로젝트 초대 알림 타입과 생성 메서드를 제거했습니다.

참고 사항

  • 각 도메인은 알림 발생 타이밍에 NotificationService 메서드만 호출하면 됩니다.
  • 알림 문구는 도메인별로 직접 만들지 않고 알림 서비스 내부에서 생성합니다.
  • 실제 도메인 연결은 각 담당 도메인에서 호출 위치 확정 후 진행하면 됩니다.
  • 그룹핑은 현재 영상 피드백/답글, 새로운 지원자 알림에만 적용됩니다.
  • 프로젝트 합류 알림은 해당 프로젝트 참여자 전체에게 보낼 수 있으며, 합류자 본인도 수신 대상에 포함할 수 있습니다.
  • 일정 담당자 지정 알림은 기존 일정 생성/수정 로직에 이미 연결되어 있습니다.

✅ PR 체크리스트

  • PR 제목은 커밋 컨벤션을 따랐습니다.
  • 관련 이슈를 연결했습니다.
  • 변경 사항에 대한 테스트를 진행했습니다.

테스트

  • ./gradlew test

Summary by CodeRabbit

  • 새 기능
    • 공지 등록 및 파일 업로드 시 관련 알림이 전송됩니다.
    • 프로젝트 합류, 일정 등록 및 일정 담당자 지정 알림이 추가되었습니다.
    • 알림 내용에 프로젝트명, 담당자명, 파일명 등 관련 정보가 표시됩니다.
  • 개선
    • 채용 지원 알림에 프로젝트명이 표시되어 더욱 명확해졌습니다.
    • 프로젝트 초대 관련 알림이 프로젝트 합류 알림으로 정리되었습니다.

@guingguing guingguing self-assigned this Aug 5, 2026
@guingguing guingguing added feature 새로운 기능 추가 refactor 기능 변경 없는 코드 개선 labels Aug 5, 2026
@guingguing guingguing linked an issue Aug 5, 2026 that may be closed by this pull request
5 tasks
@guingguing guingguing added the fix 버그 수정 label Aug 5, 2026
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4769ce4e-634e-476f-b153-7184fb9128fc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

알림 대상과 유형을 확장했습니다. NotificationService에 프로젝트 합류, 일정, 지원자, 공지, 파일 알림 생성 정책과 입력 검증을 반영했습니다.

Changes

알림 정책 및 생성 흐름

Layer / File(s) Summary
알림 계약 및 핵심 생성 흐름
src/main/java/com/slatto/domain/notification/enums/*, src/main/java/com/slatto/domain/notification/service/NotificationService.java
NOTICE, PROJECT_FILE, PROJECT_JOINED를 추가했습니다. 일정 담당자, 프로젝트 합류, 일정 등록 알림의 검증과 문구 생성을 변경했습니다.
지원자 알림 흐름
src/main/java/com/slatto/domain/notification/service/NotificationService.java
지원자 알림에 projectTitle을 추가하고 제목에 사용하도록 변경했습니다.
공지 및 파일 알림 흐름
src/main/java/com/slatto/domain/notification/service/NotificationService.java
공지 등록과 파일 업로드 알림 생성 메서드를 추가했습니다. 프로젝트 초대 fallback 제목을 제거했습니다.

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

Possibly related PRs

Suggested reviewers: sangwon02, chazy-d, young0206, kohseoyoung

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 대부분의 요구사항을 구현했지만 파일 다중 업로드 그룹핑 지원이 반영되지 않아 이슈 요구사항을 완전히 충족하지 못합니다. 파일 등록 알림에 다중 업로드 시 그룹핑 문구와 기존 미읽음 알림 갱신 로직을 추가하거나, 이슈 요구사항을 명확히 조정하세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 개인 알림 생성 메서드 확장이라는 PR의 주요 변경 사항을 간결하게 설명합니다.
Description check ✅ Passed 관련 이슈, 작업 내용, 체크리스트, 테스트 결과를 포함해 템플릿의 필수 내용을 대부분 충족합니다.
Out of Scope Changes check ✅ Passed 프로젝트 초대 제거, 영상 피드백 및 지원자 알림 정리는 연결된 이슈의 기존 알림 정책 정리 범위와 관련됩니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

🤖 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/slatto/domain/notification/service/NotificationService.java`:
- Around line 187-200: 작성자 제외 로직에 사용되는 ID가 null이 되지 않도록 검증을 추가하세요.
NotificationService.java의 187-200행에서는 writerId를 validateRequiredId로 검증하고,
253-267행·407-421행·437-450행에서는 각각 actorUserId를 validateRequiredId로 검증하세요.
- Around line 637-639: createScheduleAssignedContent 메서드의 알림 문구를 수동형으로 수정하세요.
assigneeName이 지정된 사용자로 표시되도록 현재 “담당자로 지정했어요” 표현을 “담당자로 지정되었어요”로 변경하고, 나머지 조합 형식은
유지하세요.
- Around line 197-211: Update the recipient stream in the notification creation
flow to remove duplicate recipients by recipient ID before invoking
Notification.create. Preserve the existing null filtering, writer exclusion,
notification construction, and saveAll behavior for unique recipients.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c1b8d6ce-3910-46bc-a4c1-1521051874ae

📥 Commits

Reviewing files that changed from the base of the PR and between 667e8cd and 8928c04.

📒 Files selected for processing (3)
  • src/main/java/com/slatto/domain/notification/enums/NotificationTargetType.java
  • src/main/java/com/slatto/domain/notification/enums/NotificationType.java
  • src/main/java/com/slatto/domain/notification/service/NotificationService.java

Comment on lines +187 to +200
validateRequiredId(scheduleId);
validateRequiredText(scheduleTitle);
if (recipients == null) {
throw new BaseException(CommonErrorCode.BAD_REQUEST);
}

Project notificationProject = getProjectOrNull(project != null ? project.getId() : null);
String title = createScheduleAssignedTitle(project != null ? project.getTitle() : null);
String targetType = getTargetTypeName(NotificationTargetType.SCHEDULE);

List<Notification> notifications = recipients.stream()
.filter(Objects::nonNull)
.filter(recipient -> !Objects.equals(recipient.getId(), writerId))
.map(recipient -> Notification.create(

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

작성자 제외를 보장하도록 작성자 ID를 검증하세요.

writerId 또는 actorUserId가 null이면 제외 로직이 적용되지 않습니다. 이 경우 작성자가 자신의 알림을 수신합니다.

  • src/main/java/com/slatto/domain/notification/service/NotificationService.java#L187-L200: writerIdvalidateRequiredId로 검증하세요.
  • src/main/java/com/slatto/domain/notification/service/NotificationService.java#L253-L267: actorUserIdvalidateRequiredId로 검증하세요.
  • src/main/java/com/slatto/domain/notification/service/NotificationService.java#L407-L421: actorUserIdvalidateRequiredId로 검증하세요.
  • src/main/java/com/slatto/domain/notification/service/NotificationService.java#L437-L450: actorUserIdvalidateRequiredId로 검증하세요.
📍 Affects 1 file
  • src/main/java/com/slatto/domain/notification/service/NotificationService.java#L187-L200 (this comment)
  • src/main/java/com/slatto/domain/notification/service/NotificationService.java#L253-L267
  • src/main/java/com/slatto/domain/notification/service/NotificationService.java#L407-L421
  • src/main/java/com/slatto/domain/notification/service/NotificationService.java#L437-L450
🤖 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/slatto/domain/notification/service/NotificationService.java`
around lines 187 - 200, 작성자 제외 로직에 사용되는 ID가 null이 되지 않도록 검증을 추가하세요.
NotificationService.java의 187-200행에서는 writerId를 validateRequiredId로 검증하고,
253-267행·407-421행·437-450행에서는 각각 actorUserId를 validateRequiredId로 검증하세요.

Comment on lines +197 to +211
List<Notification> notifications = recipients.stream()
.filter(Objects::nonNull)
.filter(recipient -> !Objects.equals(recipient.getId(), writerId))
.map(recipient -> Notification.create(
recipient,
notificationProject,
NotificationType.SCHEDULE_ASSIGNED,
title,
createScheduleAssignedContent(scheduleTitle, recipient.getNickname()),
targetType,
scheduleId
))
.toList();

notificationRepository.saveAll(notifications);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

중복 수신자를 제거하세요.

recipients에 동일 사용자가 두 번 있으면 알림도 두 건 저장됩니다. 이 경로는 getRecipientIds의 중복 제거를 사용하지 않습니다. Notification.create 전에 수신자 ID를 기준으로 중복을 제거하세요.

수정 예시
+        Set<Long> uniqueRecipientIds = new HashSet<>();
         List<Notification> notifications = recipients.stream()
             .filter(Objects::nonNull)
+            .filter(recipient -> recipient.getId() != null)
+            .filter(recipient -> uniqueRecipientIds.add(recipient.getId()))
             .filter(recipient -> !Objects.equals(recipient.getId(), writerId))
             .map(recipient -> Notification.create(
📝 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
List<Notification> notifications = recipients.stream()
.filter(Objects::nonNull)
.filter(recipient -> !Objects.equals(recipient.getId(), writerId))
.map(recipient -> Notification.create(
recipient,
notificationProject,
NotificationType.SCHEDULE_ASSIGNED,
title,
createScheduleAssignedContent(scheduleTitle, recipient.getNickname()),
targetType,
scheduleId
))
.toList();
notificationRepository.saveAll(notifications);
Set<Long> uniqueRecipientIds = new HashSet<>();
List<Notification> notifications = recipients.stream()
.filter(Objects::nonNull)
.filter(recipient -> recipient.getId() != null)
.filter(recipient -> uniqueRecipientIds.add(recipient.getId()))
.filter(recipient -> !Objects.equals(recipient.getId(), writerId))
.map(recipient -> Notification.create(
recipient,
notificationProject,
NotificationType.SCHEDULE_ASSIGNED,
title,
createScheduleAssignedContent(scheduleTitle, recipient.getNickname()),
targetType,
scheduleId
))
.toList();
notificationRepository.saveAll(notifications);
🤖 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/slatto/domain/notification/service/NotificationService.java`
around lines 197 - 211, Update the recipient stream in the notification creation
flow to remove duplicate recipients by recipient ID before invoking
Notification.create. Preserve the existing null filtering, writer exclusion,
notification construction, and saveAll behavior for unique recipients.

Comment on lines +637 to 639
private String createScheduleAssignedContent(String scheduleTitle, String assigneeName) {
return assigneeName + "님이 [" + scheduleTitle + "] 담당자로 지정했어요";
}

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

담당자 지정 문구를 수동형으로 수정하세요.

assigneeName은 지정한 사용자가 아니라 지정된 사용자입니다. 현재 문구는 담당자가 지정 행위를 수행한 것으로 표시합니다. "지정되었어요"를 사용하세요.

수정 예시
-        return assigneeName + "님이 [" + scheduleTitle + "] 담당자로 지정했어요";
+        return assigneeName + "님이 [" + scheduleTitle + "] 담당자로 지정되었어요";
📝 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
private String createScheduleAssignedContent(String scheduleTitle, String assigneeName) {
return assigneeName + "님이 [" + scheduleTitle + "] 담당자로 지정했어요";
}
private String createScheduleAssignedContent(String scheduleTitle, String assigneeName) {
return assigneeName + "님이 [" + scheduleTitle + "] 담당자로 지정되었어요";
}
🤖 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/slatto/domain/notification/service/NotificationService.java`
around lines 637 - 639, createScheduleAssignedContent 메서드의 알림 문구를 수동형으로 수정하세요.
assigneeName이 지정된 사용자로 표시되도록 현재 “담당자로 지정했어요” 표현을 “담당자로 지정되었어요”로 변경하고, 나머지 조합 형식은
유지하세요.

@chazy-d chazy-d 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.

수고하셨습니다! 프론트엔드 화면 라우팅을 위해서 저도 조회시 targetType, targetId를 동일하게 응답하는 구조로 만들었습니다.

@guingguing
guingguing merged commit aaca6d1 into develop Aug 5, 2026
2 checks passed
@guingguing
guingguing deleted the feature/111-notification-create-methods branch August 11, 2026 10:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature 새로운 기능 추가 fix 버그 수정 refactor 기능 변경 없는 코드 개선

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FEAT: 개인 알림 생성 메서드 확장

2 participants