Skip to content

[Feature] RAGOps Dashboard WebSocket 실시간 push - #139

Merged
kangcheolung merged 9 commits into
developfrom
feature/137
Aug 10, 2026
Merged

[Feature] RAGOps Dashboard WebSocket 실시간 push#139
kangcheolung merged 9 commits into
developfrom
feature/137

Conversation

@kangcheolung

@kangcheolung kangcheolung commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary

  • /ws(SockJS) STOMP endpoint와 /topic/dashboard Message Broker 추가
  • 인증은 HTTP 핸드셰이크가 아니라 STOMP CONNECT 프레임에서 처리 — 네이티브 websocket Transport가 Upgrade 요청에 커스텀 헤더를 못 싣는 제약 때문에, SecurityConfig/ws/**를 permitAll로 열고 StompAuthChannelInterceptor가 CONNECT 시점에 JWT를 검증
  • /topic/dashboard SUBSCRIBE는 DashboardSubscriptionAuthorizationInterceptor가 ROLE_ADMIN을 별도로 재검증 (CONNECT 검증 하나에만 의존하지 않는 이중 방어)
  • DashboardWebSocketController.sendDashboardUpdate() — 순수 전송 계층, 집계는 직접 하지 않고 호출자가 계산해서 넘김 (후속 이슈가 재사용할 지점)

설계 변경 사항 (구현 중 발견)

  • 원래 SUBSCRIBE 인가를 Spring Security @EnableWebSocketSecurity DSL로 구현하려 했으나, 이 DSL이 STOMP endpoint 등록을 감지하면 세션 기반 CSRF 토큰을 무조건 요구하는 CsrfChannelInterceptor를 자동으로 붙임. 이 앱은 stateless JWT라 세션이 없어 CSRF 토큰이 존재할 수 없고, 그 결과 ADMIN 여부와 무관하게 모든 CONNECT가 MissingCsrfTokenException으로 거부됨. 원인을 바이트코드까지 확인 후 해당 DSL을 걷어내고 순수 ChannelInterceptor로 직접 구현 (spring-security-messaging 의존성도 함께 제거)
  • 상세 원인과 재발 방지 근거는 docs/design/kangcheolung-#137-ragops-dashboard-websocket-push.md 4장 참고

Test plan

  • StompAuthChannelInterceptorTest 단위 테스트 4건 (유효 토큰/헤더 없음/무효 토큰/CONNECT 아닌 프레임)
  • DashboardWebSocketIntegrationTest — 실제 STOMP Client로 서버에 직접 연결하는 통합 테스트 3건 (ADMIN 구독 후 push 수신, 토큰 없이 CONNECT 거부, USER 토큰으로 SUBSCRIBE 거부)
  • ./gradlew build 전체 회귀 테스트 통과 — 총 733개, failures 0, errors 0

상세 설계

docs/design/kangcheolung-#137-ragops-dashboard-websocket-push.md

closes #137

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 새 기능

    • 대시보드 요약 정보를 실시간으로 전달하는 WebSocket/STOMP 기능을 추가했습니다.
    • 관리자만 대시보드 실시간 구독 채널에 접근할 수 있습니다.
    • WebSocket 연결 시 JWT 인증과 권한 검증을 지원합니다.
  • 문서

    • 대시보드 요약 조회 API와 응답 항목을 구체화했습니다.
    • 실시간 대시보드 전송 구조와 인증·인가 흐름을 문서화했습니다.
    • 실제 데이터 전송 트리거 등 후속 구현 범위를 명확히 했습니다.
  • 테스트

    • WebSocket 연결, 인증, 관리자 권한 및 대시보드 메시지 수신 시나리오를 검증했습니다.

kangcheolung and others added 8 commits August 10, 2026 18:52
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 41 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 86bb290f-0af9-4974-afc7-2d3e16afeb49

📥 Commits

Reviewing files that changed from the base of the PR and between b93bf91 and f716fc9.

📒 Files selected for processing (5)
  • docs/design/kangcheolung-#137-ragops-dashboard-websocket-push.md
  • src/main/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardSubscriptionAuthorizationInterceptor.java
  • src/main/java/com/opensource/docgrid/global/config/SecurityConfig.java
  • src/main/java/com/opensource/docgrid/global/config/WebSocketConfig.java
  • src/test/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardWebSocketIntegrationTest.java
📝 Walkthrough

Walkthrough

대시보드 요약 조회 설계를 구체화하고, /ws SockJS 기반 STOMP WebSocket을 추가했습니다. CONNECT JWT 인증과 /topic/dashboard 관리자 구독 인가를 구현했으며, 대시보드 push 전송과 단위·통합 테스트를 추가했습니다.

Changes

대시보드 WebSocket 기능

Layer / File(s) Summary
대시보드 요약 조회 설계
docs/design/kangcheolung-#134-ragops-dashboard-summary.md
Repository 집계, 4개 응답 DTO, DashboardQueryService, GET /admin/dashboard/summary API 설계를 구체화했습니다.
WebSocket 전송 및 보안 배선
build.gradle, src/main/java/com/opensource/docgrid/global/config/*, docs/design/kangcheolung-#137-ragops-dashboard-websocket-push.md
/ws SockJS endpoint, /topic broker, 공유 CORS origin, /ws/** permitAll() 설정과 inbound interceptor 배선을 추가했습니다.
STOMP JWT 인증 및 관리자 구독 인가
src/main/java/com/opensource/docgrid/domain/auth/jwt/StompAuthChannelInterceptor.java, src/main/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardSubscriptionAuthorizationInterceptor.java, src/test/java/com/opensource/docgrid/domain/auth/jwt/StompAuthChannelInterceptorTest.java, docs/design/kangcheolung-#137-ragops-dashboard-websocket-push.md
CONNECT Bearer JWT를 검증해 Principal을 설정하고, /topic/dashboard SUBSCRIBE에 ROLE_ADMIN 권한을 요구합니다. 인증 및 권한 실패와 비CONNECT 프레임 동작을 테스트합니다.
대시보드 push 및 통합 검증
src/main/java/com/opensource/docgrid/domain/dashboard/controller/DashboardWebSocketController.java, src/test/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardWebSocketIntegrationTest.java, docs/design/kangcheolung-#137-ragops-dashboard-websocket-push.md
DashboardSummaryResponse/topic/dashboard로 전송합니다. 관리자 수신, 토큰 없는 CONNECT 거부, 비관리자 SUBSCRIBE 거부를 통합 테스트로 검증합니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant WebSocketConfig
  participant StompAuthChannelInterceptor
  participant DashboardSubscriptionAuthorizationInterceptor
  participant DashboardWebSocketController
  participant TopicBroker
  Client->>WebSocketConfig: /ws SockJS 연결
  Client->>StompAuthChannelInterceptor: JWT 포함 CONNECT
  StompAuthChannelInterceptor->>Client: Principal 설정 또는 연결 거부
  Client->>DashboardSubscriptionAuthorizationInterceptor: /topic/dashboard SUBSCRIBE
  DashboardSubscriptionAuthorizationInterceptor->>Client: ROLE_ADMIN 확인 또는 구독 거부
  DashboardWebSocketController->>TopicBroker: DashboardSummaryResponse 전송
  TopicBroker->>Client: 대시보드 요약 push
Loading

Possibly related PRs

  • DocGrid/backend#13: 기존 JWT provider와 인증·역할 모델을 STOMP CONNECT 인증 및 관리자 구독 인가에 재사용합니다.
  • DocGrid/backend#121: 대시보드가 사용하는 indexing job 데이터와 관련된 관리자 Job/Attempt/Event 조회 API를 추가합니다.
  • DocGrid/backend#136: 동일한 대시보드 요약 DTO와 집계 설계를 기반으로 WebSocket push 계층을 추가합니다.

Suggested labels: ✨ Feature

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 제목은 RAGOps 대시보드의 WebSocket 실시간 push 기능이라는 주요 변경 사항을 명확하게 요약합니다.
Description check ✅ Passed 템플릿과 일부 제목은 다르지만 변경 내용, 설계 이유, 테스트 계획, 연결 이슈를 구체적으로 포함해 설명은 대부분 충족합니다.
Linked Issues check ✅ Passed 직접 연결된 [#137]의 WebSocket endpoint, STOMP 인증, 관리자 구독 인가, push 전송 계층과 테스트 요구를 구현했습니다.
Out of Scope Changes check ✅ Passed 의존성, 보안 설정, WebSocket 구성, 인증·인가, 전송 계층, 문서와 테스트가 모두 [#137]의 범위와 직접 관련됩니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/137

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

🧹 Nitpick comments (1)
src/main/java/com/opensource/docgrid/global/config/SecurityConfig.java (1)

42-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

순차 보안 흐름 주석에 단계 번호를 사용하세요.

  • src/main/java/com/opensource/docgrid/global/config/SecurityConfig.java#L42-L45: HTTP handshake permitAll, CONNECT 인증, SUBSCRIBE 인가를 1., 2., 3.으로 구분하세요.
  • src/main/java/com/opensource/docgrid/global/config/WebSocketConfig.java#L42-L45: CONNECT 인증 후 SUBSCRIBE 인가가 실행되는 순서를 번호 주석으로 표시하세요.

As per coding guidelines, "For sequential execution flows, add numbered comments such as 1., 2., 3., and 4. at the relevant steps."

🤖 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/opensource/docgrid/global/config/SecurityConfig.java`
around lines 42 - 45, Add numbered sequential-flow comments in
SecurityConfig.java lines 42-45: mark HTTP handshake permitAll as 1., STOMP
CONNECT authentication as 2., and destination-specific SUBSCRIBE authorization
as 3.; also update WebSocketConfig.java lines 42-45 to number the CONNECT
authentication and subsequent SUBSCRIBE authorization steps in execution order.

Source: Coding guidelines

🤖 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 `@docs/design/kangcheolung-`#137-ragops-dashboard-websocket-push.md:
- Around line 17-20: Update the success criterion describing non-ADMIN access so
it states that users are rejected when subscribing to /topic/dashboard, rather
than at connection or subscription generally. Keep the existing JWT and
WebSocket connection behavior unchanged.

In
`@src/main/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardSubscriptionAuthorizationInterceptor.java`:
- Around line 37-44: Update
DashboardSubscriptionAuthorizationInterceptor.preSend() to reject
StompCommand.SEND frames targeting DASHBOARD_TOPIC, while preserving the
existing isAdmin() authorization for SUBSCRIBE frames. In
DashboardWebSocketIntegrationTest.java:127-149, add an integration test
verifying a USER send to /topic/dashboard fails and an ADMIN subscriber receives
no payload.

In
`@src/test/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardWebSocketIntegrationTest.java`:
- Line 54: Update DashboardWebSocketIntegrationTest to separate the connection
timeout from the delivery timeout: keep TIMEOUT_SECONDS for connection setup,
add or reuse a distinct 1-second timeout for dashboard receipt assertions near
the delivery verification, and ensure the delivery wait cannot succeed after the
1-second SLA.
- Around line 85-92: Update the subscribeDashboard flow in
DashboardWebSocketIntegrationTest to wait for the session.subscribe(...) receipt
before calling dashboardWebSocketController.sendDashboardUpdate(summary). Expose
or return the Subscription so the test can register a receipt task and trigger
the push only after subscription completion; do not use a fixed sleep.

---

Nitpick comments:
In `@src/main/java/com/opensource/docgrid/global/config/SecurityConfig.java`:
- Around line 42-45: Add numbered sequential-flow comments in
SecurityConfig.java lines 42-45: mark HTTP handshake permitAll as 1., STOMP
CONNECT authentication as 2., and destination-specific SUBSCRIBE authorization
as 3.; also update WebSocketConfig.java lines 42-45 to number the CONNECT
authentication and subsequent SUBSCRIBE authorization steps in execution order.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 36b57662-6636-42b4-9a5d-d7c3d2bff861

📥 Commits

Reviewing files that changed from the base of the PR and between 2b1483f and b93bf91.

📒 Files selected for processing (11)
  • build.gradle
  • docs/design/kangcheolung-#134-ragops-dashboard-summary.md
  • docs/design/kangcheolung-#137-ragops-dashboard-websocket-push.md
  • src/main/java/com/opensource/docgrid/domain/auth/jwt/StompAuthChannelInterceptor.java
  • src/main/java/com/opensource/docgrid/domain/dashboard/controller/DashboardWebSocketController.java
  • src/main/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardSubscriptionAuthorizationInterceptor.java
  • src/main/java/com/opensource/docgrid/global/config/CorsConfig.java
  • src/main/java/com/opensource/docgrid/global/config/SecurityConfig.java
  • src/main/java/com/opensource/docgrid/global/config/WebSocketConfig.java
  • src/test/java/com/opensource/docgrid/domain/auth/jwt/StompAuthChannelInterceptorTest.java
  • src/test/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardWebSocketIntegrationTest.java

Comment thread docs/design/kangcheolung-#137-ragops-dashboard-websocket-push.md
Comment on lines +85 to +92
subscribeDashboard(session, received);

// When
DashboardSummaryResponse summary = sampleSummary();
dashboardWebSocketController.sendDashboardUpdate(summary);

// Then
DashboardSummaryResponse result = received.poll(TIMEOUT_SECONDS, TimeUnit.SECONDS);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Spring Framework StompSession.Subscription에서 SUBSCRIBE receipt를 요청하고 receipt 수신을 대기하는 공식 권장 API를 확인해 주세요.

💡 Result:

Spring Framework에서 StompSession을 통해 구독(SUBSCRIBE) 시 receipt를 요청하고 이를 처리하는 공식적인 방법은 다음과 같습니다 [1][2][3]. 1. Receipt 요청 설정 STOMP 프로토콜의 receipt 기능을 사용하려면 SUBSCRIBE 프레임에 receipt 헤더를 추가해야 합니다 [1][3]. 이를 위해 두 가지 방식을 사용할 수 있습니다. - 자동 설정: StompSession.setAutoReceipt(true)를 호출하면 이후 발생하는 모든 send 및 subscribe 작업에 자동으로 receipt 헤더가 추가됩니다 [2][4][5]. - 수동 설정: subscribe 메서드를 호출할 때 StompHeaders 객체를 직접 생성하여 "receipt" 헤더를 추가할 수 있습니다 [1][2][4]. 2. Receipt 수신 및 처리 (Receiptable API) subscribe 메서드는 StompSession.Subscription 객체를 반환하며, 이는 StompSession.Receiptable 인터페이스를 상속받습니다 [6][2][7]. 이 Receiptable 인터페이스가 제공하는 API를 통해 receipt 수신을 대기하고 처리할 수 있습니다 [7][4]. 주요 API: - addReceiptTask(Runnable task): receipt가 성공적으로 수신되었을 때 실행할 작업을 등록합니다 [7][4]. - addReceiptTask(Consumer task): receipt가 수신되었을 때 해당 RECEIPT 프레임의 헤더 정보를 처리할 수 있는 Consumer를 등록합니다 [7][4]. - addReceiptLostTask(Runnable task): 설정된 제한 시간 내에 receipt가 수신되지 않았을 때(실패 시) 실행할 작업을 등록합니다 [7][4]. 참고 사항: 이 기능을 사용하려면 클라이언트 설정 시 TaskScheduler가 구성되어 있어야 하며, receipt가 만료되기까지의 시간 제한(기본값 15초)을 고려해야 합니다 [1][3][5]. 예시 코드 패턴: StompHeaders headers = new StompHeaders; headers.setDestination("/topic/my-destination"); headers.setReceipt("my-receipt-id"); // 수동 설정 시 StompSession.Subscription subscription = session.subscribe(headers, handler); subscription.addReceiptTask( -> System.out.println("구독 성공!")); subscription.addReceiptLostTask( -> System.err.println("구독 실패 (Receipt 미수신)"));

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the target test file and related websocket controller/config without modifying or running repo code.
target="src/test/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardWebSocketIntegrationTest.java"
printf '--- target file line count ---\n'
wc -l "$target" 2>/dev/null || true
printf '\n--- target outline ---\n'
ast-grep outline "$target" --view compact || true
printf '\n--- relevant target lines 1-130 ---\n'
sed -n '1,130p' "$target" | nl -ba
printf '\n--- websocket-related files ---\n'
git ls-files | rg 'websocket|dashboard|WebSocket|Stomp|Socket' | sed -n '1,120p'

Repository: DocGrid/backend

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect WebSocket configuration/controller and build files to establish broker ordering and library expectations.
printf '%s\n' '--- dashboard websocket controller candidates ---'
git ls-files | rg 'DashboardWebSocket*|.*WebSocket.*' | sed -n '1,200p'

printf '%s\n' '--- websocket server config examples ---'
for f in $(git ls-files | rg 'websocket|WebSocket|Sock|Stomp' | sed -n '1,80p'); do
  echo "### $f"
  wc -l "$f"
  rg -n "getBroker|setDestination|SimpleBroker|WebSocket|Stomp|messageBroker|channelMapping|INTERCEPT" "$f" || true
  echo
done

printf '%s\n' '--- build deps mentioning stomp/websocket ---'
for f in build.gradle* pom.xml gradle.properties settings.gradle*; do
  [ -f "$f" ] && { echo "### $f"; sed -n '1,220p' "$f"; }
done

Repository: DocGrid/backend

Length of output: 18877


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the target test file without modifying repository code.
target="src/test/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardWebSocketIntegrationTest.java"
printf '%s\n' '--- target file exists and size ---'
wc -l "$target" 2>/dev/null || (printf 'target file missing\n' && exit 1)
printf '%s\n' '--- target relevant lines 1-140 ---'
sed -n '1,140p' "$target" | nl -ba
printf '%s\n' '--- target relevant subscribe/send lines ---'
rg -n "subscribeDashboard|sendDashboardUpdate|timeout|sleep|receipt|subscribe\(|send\(" "$target" -C 3

Repository: DocGrid/backend

Length of output: 372


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect WebSocket controller/config to establish timing context without running repository code.
printf '%s\n' '--- websocket-related candidate files ---'
git ls-files | rg 'websocket|WebSocket|Stomp|Sock|dashboard' | sed -n '1,200p'

printf '%s\n' '--- WebSocket config/controller excerpts ---'
for f in $(git ls-files | rg 'websocket|WebSocket|Stomp|Sock|dashboard' | sed -n '1,80p'); do
  echo "### $f"
  wc -l "$f"
  rg -n "SimpleBroker|getBroker|messageBroker|channelMapping|WebSocket|Stomp|sendDashboardUpdate|dashboardUpdate|broadcast|SUBSCRIBE|SEND|INTERCEPT" "$f" || true
  echo
done

Repository: DocGrid/backend

Length of output: 16612


🏁 Script executed:

#!/bin/bash
set -euo pipefail

target="src/test/java/com/opensource/docgrid/domain/dashboard/websocket/DashboardWebSocketIntegrationTest.java"
# Use printf -- explicitly after a no-op argument to avoid the "invalid option" shell bug.
printf '%s\n' '--- target file exist and size ---'
wc -l "$target" || { printf 'target missing\n'; exit 1; }

printf '\n%s\n' '--- target lines 70-110 ---'
awk '{printf "%5d  %s\n", NR, $0}' "$target" | sed -n '70,110p'

printf '\n%s\n' '--- target lines 170-190 ---'
awk '{printf "%5d  %s\n", NR, $0}' "$target" | sed -n '170,190p'

printf '%s\n' '--- controller excerpt ---'
awk '{printf "%5d  %s\n", NR, $0}' src/main/java/com/opensource/docgrid/domain/dashboard/controller/DashboardWebSocketController.java | sed -n '25,45p'

Repository: DocGrid/backend

Length of output: 3267


구독 완료 후 push를 전송하세요.

subscribeDashboard() 뒤 바로 sendDashboardUpdate(summary)를 호출하면 STOMP 브로커가 SUBSCRIBE 처리를 마치기 전에 전송이 발생할 수 있습니다. session.subscribe(...)의 반환 Subscription에서 receipt 작업을 등록하고, receipt 수신 후 push를 보내는 방식으로 구독 활성状态的 확인을 추가하세요. 고정 sleep은 사용하세요.

🤖 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/opensource/docgrid/domain/dashboard/websocket/DashboardWebSocketIntegrationTest.java`
around lines 85 - 92, Update the subscribeDashboard flow in
DashboardWebSocketIntegrationTest to wait for the session.subscribe(...) receipt
before calling dashboardWebSocketController.sendDashboardUpdate(summary). Expose
or return the Subscription so the test can register a receipt task and trigger
the push only after subscription completion; do not use a fixed sleep.

@kangcheolung
kangcheolung merged commit a00368d into develop Aug 10, 2026
1 check passed
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.

[Feat] RAGOps Dashboard WebSocket 실시간 push

1 participant