---
phase: 20-real-time-subscriptions
plan: 02
subsystem: frontend
tags: [trpc, sse, subscriptions, react-query, live-updates, splitLink]

requires:
  - phase: 20-real-time-subscriptions
    plan: 01
    provides: SSE subscription procedures (onEvent, onAgentUpdate, onTaskUpdate)
  - phase: 16-frontend-scaffold
    provides: tRPC client and React Query setup

provides:
  - splitLink routing subscriptions to httpSubscriptionLink (SSE)
  - Live update hooks on all three UI pages (dashboard, detail, inbox)
  - Automatic React Query cache invalidation on domain events

affects: [21-frontend-polish]

tech-stack:
  added: []
  patterns: [splitLink for operation-type routing, subscription-driven cache invalidation]

key-files:
  modified:
    - packages/web/src/lib/trpc.ts
    - packages/web/src/routes/initiatives/index.tsx
    - packages/web/src/routes/initiatives/$id.tsx
    - packages/web/src/routes/inbox.tsx

key-decisions:
  - "httpSubscriptionLink (stable export) over unstable_ prefix — both available in @trpc/client v11"
  - "Subscription-driven invalidation (not local state) — simplest approach, reuses existing React Query cache"
  - "Silent onError callbacks — pages degrade to manual refresh when backend is not running"
  - "No new packages needed — splitLink and httpSubscriptionLink ship with @trpc/client v11"

patterns-established:
  - "useSubscription + useUtils().invalidate for live updates on any page"

duration: 3min
completed: 2026-02-04
---

# Plan 20-02: Frontend SSE Subscription Hooks Summary

**Wire frontend tRPC client with SSE subscriptions and live update hooks on all three UI pages**

## Performance

- **Duration:** 3 min
- **Started:** 2026-02-04
- **Completed:** 2026-02-04
- **Tasks:** 2
- **Files modified:** 4

## Accomplishments
- Replaced single httpBatchLink with splitLink routing subscriptions to httpSubscriptionLink (SSE)
- Added onTaskUpdate subscription to dashboard page (invalidates listInitiatives + listPhases)
- Added onTaskUpdate + onAgentUpdate subscriptions to initiative detail page (invalidates phases, tasks, plans, agents)
- Added onAgentUpdate subscription to inbox page (invalidates listWaitingAgents + listMessages)

## Task Commits

Each task was committed atomically:

1. **Task 1: Update tRPC client with splitLink for SSE subscriptions** - `eaf3f10` (feat)
2. **Task 2: Add live update hooks to all three UI pages** - `170ac55` (feat)

## Files Modified
- `packages/web/src/lib/trpc.ts` - splitLink routing subscriptions to httpSubscriptionLink
- `packages/web/src/routes/initiatives/index.tsx` - onTaskUpdate subscription for dashboard
- `packages/web/src/routes/initiatives/$id.tsx` - onTaskUpdate + onAgentUpdate subscriptions for detail
- `packages/web/src/routes/inbox.tsx` - onAgentUpdate subscription for inbox

## Decisions Made
- 20-02: httpSubscriptionLink (stable export) used over unstable_ prefix variant
- 20-02: Subscription-driven invalidation pattern — no local event state, just invalidate React Query caches
- 20-02: Silent onError callbacks so pages degrade gracefully without backend
- 20-02: No new packages — splitLink and httpSubscriptionLink are core @trpc/client v11 exports

## Deviations from Plan

### Auto-fixed Issues

**1. [Rule 3 - Blocking] Duplicate useUtils() declaration in inbox.tsx**
- **Found during:** Task 2 (inbox page)
- **Issue:** Adding `const utils = trpc.useUtils()` for the subscription created a duplicate declaration (already existed lower in the function for mutations)
- **Fix:** Moved the existing `useUtils()` call above the subscription hook and removed the duplicate
- **Files modified:** packages/web/src/routes/inbox.tsx
- **Verification:** `npm run build` succeeds
- **Committed in:** 170ac55 (Task 2 commit)

---

**Total deviations:** 1 auto-fixed (1 blocking)
**Impact on plan:** Trivial reorder of existing code. No scope creep.

## Issues Encountered
None

## User Setup Required
None - SSE works over standard HTTP through the existing Vite dev proxy.

## Next Phase Readiness
- Phase 20 (Real-Time Subscriptions) is now complete
- All three UI pages receive live updates via SSE when domain events fire
- Phase 21 (Frontend Polish) can proceed

---
*Phase: 20-real-time-subscriptions*
*Completed: 2026-02-04*
