Agent skill
frontend__debug_sse
Debug Server-Sent Events (SSE) notification issues when real-time updates aren't working. Use this when mutations don't trigger frontend updates.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/frontend-debug-sse
SKILL.md
Use this guide to troubleshoot Server-Sent Events (SSE) issues.
Quick Path (80% of issues)
// turbo
-
Test SSE endpoint:
bashcurl -N -H "Accept: text/event-stream" http://localhost:5000/api/notifications/streamShould see:
data: {"type":"Connected",...} -
Check ProjectionCommitListener has case for your projection
-
Check QueryInvalidationService maps notification to query keys
-
Check ReactiveQuery uses matching
queryKeys
If still broken, continue to full debugging below.
Symptoms
- ✗ Frontend doesn't update after mutation
- ✗
ReactiveQuerydoesn't invalidate - ✗ SSE connection fails or disconnects
- ✗ Events not received in browser
Related Skills
Prerequisites:
/aspire__start_solution- Solution must be running to debug SSE
First Steps:
/test__verify_feature- Run basic checks (build, tests) before deep debugging
Related Debugging:
/cache__debug_cache- If issue seems cache-related instead of SSE/ops__doctor_check- Check if environment setup is correct
After Fixing:
/test__verify_feature- Confirm fix works/test__integration_scaffold- Add tests to prevent regression
Debugging Steps
1. Verify SSE Endpoint is Working
Test the SSE endpoint directly:
# Terminal 1: Connect to SSE stream
curl -N -H "Accept: text/event-stream" http://localhost:5000/api/notifications/stream
You should see:
: connected
data: {"type":"Connected","timestamp":"2026-01-15T20:00:00Z"}
If connection fails:
- ✗ Check API service is running
- ✗ Verify
/api/notifications/streamendpoint exists inNotificationEndpoints.cs - ✗ Check firewall/network issues
2. Verify Notifications Are Defined
Check src/Shared/BookStore.Shared/Notifications/DomainEventNotifications.cs:
// ✅ Correct - implements IDomainEventNotification
public record BookCreatedNotification(Guid Id, string Title) : IDomainEventNotification;
// ✗ Wrong - missing interface
public record BookCreatedNotification(Guid Id, string Title);
If notification is missing:
- Create notification in
DomainEventNotifications.cs - Implement
IDomainEventNotificationinterface - Include all data needed for frontend invalidation
3. Verify ProjectionCommitListener Configuration
Open src/BookStore.ApiService/Infrastructure/MartenCommitListener.cs:
Check if your projection has a handler:
private async Task ProcessDocumentChangeAsync(
IDocumentChange change,
CancellationToken cancellationToken)
{
switch (change)
{
case BookProjection proj:
await HandleBookChangeAsync(proj, cancellationToken);
break;
// ❌ Missing: Your projection case
case AuthorProjection proj:
await HandleAuthorChangeAsync(proj, cancellationToken);
break;
}
}
Check if handler sends notification:
private async Task HandleBookChangeAsync(
BookProjection book,
CancellationToken cancellationToken)
{
var notification = new BookUpdatedNotification(book.Id, book.Title);
// ✅ Correct - sends notification
await _notificationService.NotifyAsync(notification, cancellationToken);
// ✗ Wrong - forgot to send
// (no NotifyAsync call)
}
If handler is missing:
- Add case for your projection
- Create handler method that calls
NotifyAsync - Use appropriate notification type
4. Verify QueryInvalidationService Mapping
Open src/Web/BookStore.Web/Services/QueryInvalidationService.cs:
Check if notification maps to query keys:
IEnumerable<string> GetInvalidationKeys(IDomainEventNotification notification)
{
switch (notification)
{
case BookCreatedNotification n:
yield return "Books";
yield return $"Book:{n.EntityId}";
break;
case BookUpdatedNotification n:
yield return "Books";
yield return $"Book:{n.EntityId}";
break;
// ❌ Missing: Your notification
case AuthorUpdatedNotification n:
yield return "Authors";
yield return $"Author:{n.EntityId}";
break;
}
}
If mapping is missing:
- Add case for your notification type
- Yield return query keys that should be invalidated
- Match keys used in
ReactiveQuerysetup
5. Verify Frontend BookStoreEventsService
Check browser console for SSE connection:
In Chrome DevTools:
- Open Network tab
- Look for "events" request (type: eventsource)
- Check status is "pending" (active connection)
- View "EventStream" tab to see events
If connection is closed:
- Check
BookStoreEventsService.StartListening()is called inOnInitializedAsync - Verify base URL is correct
- Check for JavaScript errors
6. Verify ReactiveQuery Configuration
Check component using ReactiveQuery:
// ✅ Correct - query keys match invalidation mapping
bookQuery = new ReactiveQuery<PagedListDto<BookDto>>(
queryFn: FetchBooksAsync,
eventsService: BookStoreEventsService,
invalidationService: InvalidationService,
queryKeys: new[] { "Books" }, // Matches QueryInvalidationService
onStateChanged: StateHasChanged,
logger: Logger
);
// ✗ Wrong - query keys don't match
queryKeys: new[] { "AllBooks" } // Doesn't match "Books"
If query doesn't invalidate:
- Ensure
queryKeysmatchQueryInvalidationServicemapping - Verify
BookStoreEventsServiceis subscribed - Check
onStateChangedcallback is provided
7. Test End-to-End
Perform a mutation and watch the flow:
# Terminal 1: Watch SSE stream
curl -N -H "Accept: text/event-stream" http://localhost:5000/api/notifications/stream
# Terminal 2: Trigger mutation
curl -X POST http://localhost:5000/api/admin/books \
-H "Content-Type: application/json" \
-d '{"title":"Test Book",...}'
Expected flow:
- Command executed
- Event stored in Marten
ProjectionCommitListenertriggered- Notification sent via SSE
- Browser receives event
QueryInvalidationServicemaps to keysReactiveQueryinvalidates- Query refetches
- UI updates
If any step fails, locate where:
- Check logs in Aspire dashboard
- Add debug logging to
ProjectionCommitListener - Use browser console to see received events
Common Issues & Fixes
Issue: Events Not Sent
Symptom: ProjectionCommitListener not triggered
Fix:
- Ensure
ProjectionCommitListeneris registered in DI - Check Marten event store configuration
- Verify projection lifecycle (
InlinevsAsync)
Issue: Wrong Event Type
Symptom: Notification sent but frontend doesn't invalidate
Fix:
// Check notification type name matches exactly
case "BookUpdatedNotification": // ✅ Correct
case "BookUpdated": // ✗ Wrong
Issue: Multiple Tabs Don't Update
Symptom: Updates only visible in tab that made change
Fix:
- SSE works per-connection, each tab needs own connection
- Each tab should call
BookStoreEventsService.StartListening() - Verify SignalR isn't being used (project uses SSE)
Issue: SSE Connection Drops
Symptom: Connection works then stops
Fix:
- Check server-side timeout configuration
- Verify no proxy/load balancer kills long connections
- Add reconnection logic in
BookStoreEventsService
Verification Checklist
- SSE endpoint accessible at
/api/notifications/stream - Notification class implements
IDomainEventNotification -
ProjectionCommitListenerhas handler for projection - Handler calls
NotifyAsyncwith notification -
QueryInvalidationServicemaps notification to keys - Frontend
ReactiveQueryuses matching query keys -
BookStoreEventsService.StartListening()called on mount - Browser DevTools shows active EventSource connection
- End-to-end test confirms UI updates after mutation
Debugging Tools
Backend:
- Aspire Dashboard → Structured Logs → Filter by "notification"
- Add logging in
ProjectionCommitListener:_logger.LogInformation("Sending {Type}", notification.GetType().Name)
Frontend:
- Browser Console → Look for EventSource logs
- React DevTools → Check component re-renders
- Network tab → Verify EventSource connection
Related Skills
First Steps:
/test__verify_feature- Run basic checks (build, tests) before deep debugging
Related Debugging:
/cache__debug_cache- If issue seems cache-related instead of SSE/ops__doctor_check- Check if environment setup is correct
After Fixing:
/test__verify_feature- Confirm fix works/test__integration_scaffold- Add tests to prevent regression
See Also:
- wolverine__guide - SSE notification setup in ProjectionCommitListener
- frontend__feature_scaffold - Frontend SSE integration
- real-time-notifications - SSE architecture and data flow
- ApiService AGENTS.md - Backend notification patterns
- Web AGENTS.md - Frontend SSE patterns
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?