Skip to content

[Feat] SSE 기반 알림 및 읽음 처리 기능 추가 (#120)#122

Merged
shinae1023 merged 3 commits into
devfrom
feat/#121-alarm
Jul 7, 2026
Merged

[Feat] SSE 기반 알림 및 읽음 처리 기능 추가 (#120)#122
shinae1023 merged 3 commits into
devfrom
feat/#121-alarm

Conversation

@shinae1023

@shinae1023 shinae1023 commented Jul 7, 2026

Copy link
Copy Markdown
Member

✨ 어떤 이유로 PR를 하셨나요?

  • feature 병합
  • 버그 수정(아래에 issue #를 남겨주세요)
  • 코드 개선
  • 코드 수정
  • 배포
  • 기타(아래에 자세한 내용 기입해주세요)

📋 세부 내용 - 왜 해당 PR이 필요한지 작업 내용을 자세하게 설명해주세요

SSE 기반 인앱 알림 기능을 추가했습니다. 알림 엔티티와 저장소를 도입하고, 목록 조회·미읽음 개수 조회·개별 읽음 처리·전체 읽음 처리 API를 구현했으며, 실시간 알림 스트림을 통해 프론트가 즉시 알림을 표시할 수 있도록 구성했습니다. 또한 async 작업 완료/실패 시 taskId, mockApplyId, jobPostingId 등 이동용 payload를 포함한 알림이 자동 생성되도록 연결했습니다.

📸 작업 화면 스크린샷

⚠️ PR하기 전에 확인해주세요

  • 로컬테스트를 진행하셨나요?
  • 머지할 브랜치를 확인하셨나요?
  • 관련 label을 선택하셨나요?

🚨 관련 이슈 번호 [#121 ]

closes #121

Summary by CodeRabbit

  • New Features

    • Added in-app notifications for async job posting and analysis results.
    • Introduced a notifications screen/API to view recent alerts, check unread counts, and mark items as read.
    • Added real-time notification updates so new alerts can arrive without refreshing.
  • Bug Fixes

    • Improved notification state handling so read/unread updates stay in sync across single-item and bulk actions.
  • Chores

    • Updated local ignore rules to exclude the Python virtual environment folder.

SSE 기반 인앱 알림 기능을 추가했습니다. 알림 엔티티와 저장소를 도입하고, 목록 조회·미읽음 개수 조회·개별 읽음 처리·전체 읽음 처리 API를 구현했으며, 실시간 알림 스트림을 통해 프론트가 즉시 알림을 표시할 수 있도록 구성했습니다. 또한 async 작업 완료/실패 시 taskId, mockApplyId, jobPostingId 등 이동용 payload를 포함한 알림이 자동 생성되도록 연결했습니다.
@shinae1023 shinae1023 self-assigned this Jul 7, 2026
@shinae1023 shinae1023 added the ✨ feat New feature or request label Jul 7, 2026
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@shinae1023, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 34 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8bc6c406-e1df-497b-a7d9-3b5cc401eb59

📥 Commits

Reviewing files that changed from the base of the PR and between b5d7ba5 and ee4af88.

📒 Files selected for processing (8)
  • README.md
  • ops/db/migrations/20260707_notifications.sql
  • src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncTaskService.java
  • src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/controller/NotificationController.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/service/NotificationService.java
  • src/main/java/com/jobdri/jobdri_api/global/sse/SseSubscriptionRegistry.java
  • src/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskServiceTest.java
📝 Walkthrough

Walkthrough

Introduces an in-app notification system: a new notifications table, Notification entity with NotificationType/NotificationTargetType enums, NotificationRepository, NotificationService/NotificationSseService for SSE-based delivery, NotificationController REST endpoints, related response DTOs, and hooks into AnalysisAsyncTaskService/JobPostingAsyncTaskService to emit success/failure notifications.

Changes

Notification feature

Layer / File(s) Summary
Schema and domain model
ops/db/migrations/20260707_notifications.sql, .../notification/entity/Notification.java, .../entity/NotificationType.java, .../entity/NotificationTargetType.java
Adds notifications table with indexes and FK, plus the Notification entity and its type/target enums.
Repository
.../notification/repository/NotificationRepository.java
Adds query methods for latest notifications, unread count, and bulk mark-as-read.
Response DTOs
.../notification/dto/response/*.java
Adds NotificationResponse, NotificationUnreadCountResponse, NotificationReadAllResponse, NotificationStreamBootstrapResponse, NotificationStreamEventResponse records.
SSE broadcast service
.../notification/service/NotificationSseService.java
Adds per-user channel subscribe/publish support via SseSubscriptionRegistry.
Notification service core
.../notification/service/NotificationService.java
Implements retrieval, unread count, subscribe, mark-read/read-all, createNotification, after-commit SSE publishing, and payload JSON serialization/deserialization.
REST controller
.../notification/controller/NotificationController.java
Adds /api/notifications endpoints for listing, unread count, SSE stream, mark-read, and mark-all-read.
Async service wiring
.../analysis/service/AnalysisAsyncTaskService.java, .../jobposting/service/JobPostingAsyncTaskService.java, .../jobposting/service/JobPostingAsyncTaskServiceTest.java
Injects NotificationService; success/failure task transitions now create notifications with payload maps; test setup updated for new constructor argument.

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

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant NotificationController
    participant NotificationService
    participant NotificationRepository
    participant NotificationSseService

    Client->>NotificationController: GET /stream
    NotificationController->>NotificationService: subscribe(user)
    NotificationService->>NotificationSseService: subscribe(userId, bootstrapSupplier)
    NotificationSseService-->>Client: SseEmitter (bootstrap event)

    Note over NotificationService: Later, async task completes
    NotificationService->>NotificationRepository: save(Notification)
    NotificationService->>NotificationService: publishAfterCommit(event)
    NotificationService->>NotificationSseService: publish(userId, event)
    NotificationSseService-->>Client: SSE event (CREATED)
Loading
sequenceDiagram
    participant AsyncTaskService
    participant NotificationService
    participant NotificationRepository
    participant NotificationSseService

    AsyncTaskService->>AsyncTaskService: markSuccess(task) / markFailed(task)
    AsyncTaskService->>NotificationService: createNotification(payload, type, target)
    NotificationService->>NotificationRepository: save(Notification.create(...))
    NotificationService->>NotificationSseService: publish(userId, streamEvent)
Loading

Possibly related PRs

  • JobDri-Developer/BackEnd#116: Refactors the same AnalysisAsyncTaskService success/failure state transition methods that this PR extends with notification creation.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: SSE-based notifications with read-state handling.
Description check ✅ Passed The description matches the template and covers purpose, changes, checks, and issue link; only screenshots are empty.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#121-alarm

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

Caution

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

⚠️ Outside diff range comments (2)
src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncTaskService.java (1)

67-73: 🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

Notification errors can roll back task completion. NotificationService.createNotification(...) is @Transactional with default REQUIRED, so markSuccess/markFailed join the same transaction. If user lookup, payload serialization, or notificationRepository.save(...) throws, the task’s SUCCEEDED/FAILED transition rolls back too, and the after-commit SSE event never fires. Isolate notification creation (REQUIRES_NEW) or catch/log notification failures.

🤖 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/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncTaskService.java`
around lines 67 - 73, Notification creation in
AnalysisAsyncTaskService.markSuccess (and the corresponding failure path) is
joining the same transaction as the task status update, so any exception from
NotificationService.createNotification can roll back the task transition and
prevent publishAfterCommit from firing. Update the notification flow so it is
isolated from the task transaction, either by moving notification creation to a
REQUIRES_NEW transaction in NotificationService/createNotification or by
wrapping createSuccessNotification/createFailureNotification in try-catch and
logging failures without rethrowing, while keeping getTask and
markSuccess/markFailed behavior unchanged.
src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.java (1)

71-86: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep notification failures off the completion path. createSuccessNotification / createFailureNotification run inside the same @Transactional method, so any exception rolls back markSuccess / markFailed and makes the worker request fail before the completed JobPostingIngestResponse is returned. Wrap them in a best-effort catch/log path or move them after commit.

🤖 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/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.java`
around lines 71 - 86, `markSuccess` in `JobPostingAsyncTaskService` currently
calls `createSuccessNotification` inside the transactional completion path, so a
notification exception can roll back the task update and fail the worker
request. Update `markSuccess` and the related `markFailed` flow to make
notifications best-effort only: either move `createSuccessNotification` /
`createFailureNotification` to an after-commit callback or wrap them in a
try-catch that logs and suppresses notification errors, while still returning
the completed `JobPostingIngestResponse`.
🧹 Nitpick comments (5)
ops/db/migrations/20260707_notifications.sql (1)

19-20: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Use a partial index for unread lookups.

countByUserIdAndReadAtIsNull and markAllAsRead only ever query rows where read_at IS NULL. A partial index limited to that condition is smaller and faster than indexing every row.

Proposed partial index
-CREATE INDEX IF NOT EXISTS idx_notifications_user_read_at
-    ON notifications (user_id, read_at);
+CREATE INDEX IF NOT EXISTS idx_notifications_user_unread
+    ON notifications (user_id) WHERE read_at IS NULL;
🤖 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 `@ops/db/migrations/20260707_notifications.sql` around lines 19 - 20, The
notifications index currently covers all rows, but
`countByUserIdAndReadAtIsNull` and `markAllAsRead` only target unread
notifications. Update the index definition in the migration to use a partial
index on `notifications` constrained to rows where `read_at IS NULL`, keeping
the existing `idx_notifications_user_read_at` name or equivalent so the query
paths can use a smaller, faster index.
src/main/java/com/jobdri/jobdri_api/domain/notification/controller/NotificationController.java (1)

53-59: 🩺 Stability & Availability | 🔵 Trivial

Consider anti-buffering headers for the SSE stream.

If this endpoint sits behind a reverse proxy (nginx, etc.), responses can be buffered unless headers like Cache-Control: no-cache and X-Accel-Buffering: no are set, which would delay "real-time" delivery — the core goal of this feature per the PR objectives. Worth confirming the deployment topology and adding these headers (or proxy-level config) if applicable.

🤖 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/jobdri/jobdri_api/domain/notification/controller/NotificationController.java`
around lines 53 - 59, The SSE stream in
NotificationController.streamNotifications should disable buffering so real-time
events are not delayed by proxies. Update the response setup for this endpoint
to include anti-buffering headers such as Cache-Control: no-cache and
X-Accel-Buffering: no, either directly in the controller response or via the
surrounding proxy configuration if that is where response headers are managed.
Make sure the change is applied where streamNotifications returns the SseEmitter
so the stream remains truly real-time behind nginx or similar reverse proxies.
src/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskServiceTest.java (2)

36-37: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use an import instead of the fully-qualified type.

Minor style nit; add an import com.jobdri.jobdri_api.domain.notification.service.NotificationService; instead of the inline fully-qualified reference.

🤖 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/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskServiceTest.java`
around lines 36 - 37, The test class uses a fully-qualified type for the
NotificationService mock instead of an import, which is a style issue. Update
JobPostingAsyncTaskServiceTest to import NotificationService and change the
`@Mock` field to use the simple class name so the test matches the surrounding
import style and is easier to read.

41-49: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No test coverage for the new notification hooks.

The mock is wired in, but no test verifies notificationService.createNotification(...) is invoked with correct arguments on markSuccess/markFailed, nor that it's not called on retry-scheduled paths. Given the transaction-coupling risk flagged in JobPostingAsyncTaskService, a test exercising markSuccess/markFailed and verifying interactions with notificationService would also help catch regressions here.

🤖 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/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskServiceTest.java`
around lines 41 - 49, Add test coverage in JobPostingAsyncTaskServiceTest for
the new notification hooks: verify that JobPostingAsyncTaskService.markSuccess
and markFailed invoke notificationService.createNotification with the expected
arguments, and add assertions that retry-scheduled paths do not call
notificationService. Use the existing setUp wiring, and target the markSuccess,
markFailed, and any retry-related methods in JobPostingAsyncTaskService so the
interaction with notificationService is explicitly covered.
src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.java (1)

267-272: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate condition computed three times.

result.getSaved() != null && result.getSaved().getJobPostingId() != null is repeated for the target type and target id. Extract to a local variable for clarity.

♻️ Suggested refactor
+        boolean hasJobPostingId = result.getSaved() != null && result.getSaved().getJobPostingId() != null;
         notificationService.createNotification(
                 task.getUserId(),
                 NotificationType.JOB_POSTING_ASYNC_SUCCEEDED,
                 "채용 공고 작업이 완료되었습니다.",
                 result.isSavedToDatabase()
                         ? "채용 공고 분석과 저장이 완료되었습니다."
                         : "채용 공고 분석이 완료되었습니다.",
-                result.getSaved() != null && result.getSaved().getJobPostingId() != null
-                        ? NotificationTargetType.JOB_POSTING_RESULT
-                        : NotificationTargetType.JOB_POSTING_TASK,
-                result.getSaved() != null && result.getSaved().getJobPostingId() != null
-                        ? String.valueOf(result.getSaved().getJobPostingId())
-                        : task.getTaskId(),
+                hasJobPostingId ? NotificationTargetType.JOB_POSTING_RESULT : NotificationTargetType.JOB_POSTING_TASK,
+                hasJobPostingId ? String.valueOf(result.getSaved().getJobPostingId()) : task.getTaskId(),
                 payload
         );
🤖 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/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.java`
around lines 267 - 272, The condition in JobPostingAsyncTaskService is repeated
multiple times when choosing the notification target type and target id, making
the expression harder to read and maintain. Extract the repeated
result.getSaved() != null && result.getSaved().getJobPostingId() != null check
into a local boolean in the method that builds the notification payload, then
reuse that variable for both the NotificationTargetType and target id selection.
🤖 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/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncTaskService.java`:
- Line 200: The failure notification body in AnalysisAsyncTaskService is
exposing worker-provided task.getError() directly to users. Update the
notification-building logic around the task.getError() fallback to always send a
generic user-facing message, and keep the detailed error text only in internal
logs or admin-only fields so the public notification body is sanitized.

In
`@src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.java`:
- Line 287: The notification in JobPostingAsyncTaskService currently exposes
worker-provided task.getError() directly to the user, so replace it with a
generic failure message and keep the detailed error only in server-side logging
or internal handling. Update the error selection logic in the notification path
that uses task.getError() so the user-facing text is always the fallback
message, while preserving the original error for logs or diagnostics elsewhere
in the service.

In
`@src/main/java/com/jobdri/jobdri_api/domain/notification/service/NotificationService.java`:
- Around line 115-149: `NotificationService.createNotification(...)` is still
participating in the caller’s transaction, so a failure in
`userService.getUser(...)` or `serializePayload(...)` can roll back
`AnalysisAsyncTaskService.markSuccess/markFailed` and
`JobPostingAsyncTaskService.markSuccess/markFailed`. Isolate this notification
side effect by moving the notification write to its own transaction boundary
(for example, a separate transactional method/service invoked from the async
task flow) so task status updates in those methods commit independently even if
notification creation fails.
- Around line 57-69: In NotificationService, guard the SSE bootstrap work in
subscribe() so repository failures don’t leave the emitter registered; move the
count/findTop50 bootstrap calls behind the notificationSseService registration
or wrap them so cleanup/error handling in subscribe() can still run if bootstrap
fails. Also isolate createNotification() from the async task-status transaction
by moving the user lookup/serialization/notification insert into a separate
best-effort transaction or helper so failures there do not roll back the task
transition.

---

Outside diff comments:
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncTaskService.java`:
- Around line 67-73: Notification creation in
AnalysisAsyncTaskService.markSuccess (and the corresponding failure path) is
joining the same transaction as the task status update, so any exception from
NotificationService.createNotification can roll back the task transition and
prevent publishAfterCommit from firing. Update the notification flow so it is
isolated from the task transaction, either by moving notification creation to a
REQUIRES_NEW transaction in NotificationService/createNotification or by
wrapping createSuccessNotification/createFailureNotification in try-catch and
logging failures without rethrowing, while keeping getTask and
markSuccess/markFailed behavior unchanged.

In
`@src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.java`:
- Around line 71-86: `markSuccess` in `JobPostingAsyncTaskService` currently
calls `createSuccessNotification` inside the transactional completion path, so a
notification exception can roll back the task update and fail the worker
request. Update `markSuccess` and the related `markFailed` flow to make
notifications best-effort only: either move `createSuccessNotification` /
`createFailureNotification` to an after-commit callback or wrap them in a
try-catch that logs and suppresses notification errors, while still returning
the completed `JobPostingIngestResponse`.

---

Nitpick comments:
In `@ops/db/migrations/20260707_notifications.sql`:
- Around line 19-20: The notifications index currently covers all rows, but
`countByUserIdAndReadAtIsNull` and `markAllAsRead` only target unread
notifications. Update the index definition in the migration to use a partial
index on `notifications` constrained to rows where `read_at IS NULL`, keeping
the existing `idx_notifications_user_read_at` name or equivalent so the query
paths can use a smaller, faster index.

In
`@src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.java`:
- Around line 267-272: The condition in JobPostingAsyncTaskService is repeated
multiple times when choosing the notification target type and target id, making
the expression harder to read and maintain. Extract the repeated
result.getSaved() != null && result.getSaved().getJobPostingId() != null check
into a local boolean in the method that builds the notification payload, then
reuse that variable for both the NotificationTargetType and target id selection.

In
`@src/main/java/com/jobdri/jobdri_api/domain/notification/controller/NotificationController.java`:
- Around line 53-59: The SSE stream in
NotificationController.streamNotifications should disable buffering so real-time
events are not delayed by proxies. Update the response setup for this endpoint
to include anti-buffering headers such as Cache-Control: no-cache and
X-Accel-Buffering: no, either directly in the controller response or via the
surrounding proxy configuration if that is where response headers are managed.
Make sure the change is applied where streamNotifications returns the SseEmitter
so the stream remains truly real-time behind nginx or similar reverse proxies.

In
`@src/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskServiceTest.java`:
- Around line 36-37: The test class uses a fully-qualified type for the
NotificationService mock instead of an import, which is a style issue. Update
JobPostingAsyncTaskServiceTest to import NotificationService and change the
`@Mock` field to use the simple class name so the test matches the surrounding
import style and is easier to read.
- Around line 41-49: Add test coverage in JobPostingAsyncTaskServiceTest for the
new notification hooks: verify that JobPostingAsyncTaskService.markSuccess and
markFailed invoke notificationService.createNotification with the expected
arguments, and add assertions that retry-scheduled paths do not call
notificationService. Use the existing setUp wiring, and target the markSuccess,
markFailed, and any retry-related methods in JobPostingAsyncTaskService so the
interaction with notificationService is explicitly covered.
🪄 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: fcc2c702-8c70-4116-ab81-a9184676c366

📥 Commits

Reviewing files that changed from the base of the PR and between 8cc51f0 and b5d7ba5.

📒 Files selected for processing (17)
  • .gitignore
  • ops/db/migrations/20260707_notifications.sql
  • src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncTaskService.java
  • src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/controller/NotificationController.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/dto/response/NotificationReadAllResponse.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/dto/response/NotificationResponse.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/dto/response/NotificationStreamBootstrapResponse.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/dto/response/NotificationStreamEventResponse.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/dto/response/NotificationUnreadCountResponse.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/entity/Notification.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/entity/NotificationTargetType.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/entity/NotificationType.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/repository/NotificationRepository.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/service/NotificationService.java
  • src/main/java/com/jobdri/jobdri_api/domain/notification/service/NotificationSseService.java
  • src/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskServiceTest.java

- async task 완료/실패 시 알림 생성이 상태 전이 트랜잭션을 롤백하지 않도록 알림 저장을 별도 트랜잭션으로 분리하고 호출부를 best-effort 처리로 변경
- 분석/채용공고 실패 알림에서 worker 에러 원문 노출을 제거하고 사용자용 메시지로 통일
- 알림 SSE 응답에 Cache-Control: no-cache, X-Accel-Buffering: no 헤더 추가
- unread 조회 경로에 맞게 notifications unread index를 partial index로 조정
- job posting async notification 호출 테스트와 import/style 정리 추가
@shinae1023 shinae1023 merged commit 2597d22 into dev Jul 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feat New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 알람 API

1 participant