---
phase: 10-read-unread-status
plan: 01
type: execute
---

<objective>
Validate and test the read/unread tracking system end-to-end.

Purpose: Ensure unread badge, mark-as-read, and localStorage persistence work correctly across all chat scenarios. The Redux infrastructure (reducers, selectors, WebSocket handlers) was built in Phase 7, but comprehensive integration testing is needed to validate the complete flow.

Output: Integration tests validating unread tracking, badge behavior, and localStorage persistence. Any bugs discovered will be fixed following deviation rules.
</objective>

<execution_context>
@./.claude/get-shit-done/workflows/execute-phase.md
@./.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md

# Prior phases that established unread tracking:
@.planning/phases/07-chat-infrastructure/07-03-SUMMARY.md
@.planning/phases/08-chat-window-ui/08-03-SUMMARY.md
@.planning/phases/09-message-composition/09-02-SUMMARY.md

# Key files:
@jam-ui/src/store/features/sessionChatSlice.js
@jam-ui/src/components/client/chat/JKSessionChatButton.js
@jam-ui/src/components/client/JKSessionChatWindow.js
@jam-ui/src/hooks/useSessionWebSocket.js
@jam-ui/src/helpers/chatStorage.js

**Tech stack available:**
- Redux Toolkit with createSlice, createAsyncThunk, createSelector
- Reselect for memoized selectors
- localStorage for lastReadAt persistence
- Playwright for integration testing
- WebSocket via useSessionWebSocket hook

**Established patterns:**
- Unread increment: window closed OR viewing different channel
- Mark as read: openChatWindow action resets unread count
- localStorage: saveLastReadAt on markAsRead, load on Redux init
- Integration testing: Redux store access via window.__REDUX_STORE__ for assertions

**Constraining decisions:**
From Phase 7: Unread increment logic uses useSelector in WebSocket hook to check window state
From Phase 8: Badge shows 1-99, "99+" for 100+, hidden when count = 0
From Phase 9: Message send/receive flows validated with integration tests

**What exists:**
- Redux reducers: markAsRead, incrementUnreadCount (Phase 7)
- Selectors: selectUnreadCount, selectTotalUnreadCount (Phase 7)
- WebSocket handler with unread increment (Phase 7)
- localStorage utilities: saveLastReadAt, loadLastReadAt (Phase 7)
- JKSessionChatButton with badge display (Phase 8)
- Send/receive integration tests (Phase 9)
</context>

<tasks>

<task type="auto">
  <name>Task 1: Write integration tests for unread badge behavior</name>
  <files>jam-ui/test/chat/unread-badge.spec.ts</files>
  <action>
Create comprehensive integration tests for unread badge behavior using Playwright. Test file should validate:

1. Badge hidden when unread count is 0
2. Badge shows correct count (1-99) when messages arrive with window closed
3. Badge shows "99+" when count >= 100
4. Badge resets to 0 when window is opened (openChatWindow action)
5. Badge does NOT increment when window is open and viewing same channel
6. Badge DOES increment when window is open but viewing different channel
7. Multiple messages increment badge correctly
8. Badge persists across page reload (via localStorage)

Use pattern from send-message.spec.ts and receive-message.spec.ts:
- Login and create/join session
- Access Redux store via window.__REDUX_STORE__
- Simulate WebSocket messages via direct dispatch (addMessageFromWebSocket action)
- Assert badge visibility and text content
- Test localStorage persistence by reloading page and checking badge state

Test structure:
```typescript
describe('Chat Unread Badge', () => {
  test('badge hidden when count is 0', async ({ page }) => { ... });
  test('badge shows count when message arrives with window closed', async ({ page }) => { ... });
  test('badge shows 99+ when count >= 100', async ({ page }) => { ... });
  test('badge resets when window opened', async ({ page }) => { ... });
  test('badge does not increment when viewing active channel', async ({ page }) => { ... });
  test('badge increments when viewing different channel', async ({ page }) => { ... });
  test('badge persists across page reload', async ({ page }) => { ... });
});
```

IMPORTANT: Do NOT modify Redux code or components in this task - only write tests. If tests fail due to bugs, apply deviation rules (Rule 1: auto-fix bugs, document in Summary).
  </action>
  <verify>npx playwright test unread-badge.spec.ts passes with all tests green</verify>
  <done>7+ tests covering all unread badge scenarios, all tests passing</done>
</task>

<task type="auto">
  <name>Task 2: Write integration tests for localStorage persistence</name>
  <files>jam-ui/test/chat/localStorage-persistence.spec.ts</files>
  <action>
Create integration tests specifically for localStorage persistence behavior using Playwright. Test file should validate:

1. lastReadAt saved to localStorage when window opened (markAsRead triggered)
2. lastReadAt loaded from localStorage on Redux init (page load)
3. Unread count calculated correctly based on lastReadAt timestamp
   - Messages with createdAt > lastReadAt should contribute to unread count
   - Messages with createdAt <= lastReadAt should NOT contribute to unread count
4. localStorage survives page reload
5. Multiple channels tracked independently in localStorage
6. Error handling: localStorage quota exceeded (graceful degradation)
7. Error handling: corrupted localStorage data (returns empty object)

Use chatStorage utilities (saveLastReadAt, loadLastReadAt) and validate localStorage JSON format:
```javascript
{
  "channel-id-1": "2026-01-27T10:30:00Z",
  "channel-id-2": "2026-01-27T11:00:00Z"
}
```

Test structure:
```typescript
describe('Chat localStorage Persistence', () => {
  test('saves lastReadAt when window opened', async ({ page }) => { ... });
  test('loads lastReadAt on page init', async ({ page }) => { ... });
  test('unread count based on lastReadAt timestamp', async ({ page }) => { ... });
  test('multi-channel tracking independent', async ({ page }) => { ... });
  test('handles quota exceeded gracefully', async ({ page }) => { ... });
  test('handles corrupted data gracefully', async ({ page }) => { ... });
});
```

IMPORTANT: Do NOT modify chatStorage utilities or Redux code - only write tests. If tests fail due to bugs, apply deviation rules.
  </action>
  <verify>npx playwright test localStorage-persistence.spec.ts passes with all tests green</verify>
  <done>6+ tests covering localStorage persistence scenarios, all tests passing</done>
</task>

<task type="auto">
  <name>Task 3: Write E2E test for complete unread workflow</name>
  <files>jam-ui/test/e2e/unread-tracking-flow.spec.ts</files>
  <action>
Create comprehensive E2E test for complete unread tracking workflow using Playwright. This test validates the entire user journey:

**Happy path workflow:**
1. User logs in and joins a session
2. Chat button shows badge count = 0 (no messages yet)
3. User opens chat window → badge remains 0
4. User closes chat window
5. Simulate incoming message via WebSocket → badge shows count = 1
6. Simulate 2 more messages → badge shows count = 3
7. User opens chat window → badge resets to 0
8. Keep window open, simulate another message → badge stays 0 (viewing active channel)
9. User closes window
10. Reload page → verify lastReadAt persisted, badge calculation correct
11. Simulate message older than lastReadAt → badge stays 0 (already read)
12. Simulate message newer than lastReadAt → badge increments to 1

**Test structure:**
```typescript
test('complete unread tracking workflow', async ({ page }) => {
  // Setup: login, create session, join
  await loginToJamUI(page);
  await createAndJoinSession(page);

  // Get Redux store and session ID
  const store = await page.evaluate(() => window.__REDUX_STORE__);
  const sessionId = await page.evaluate(() => window.__REDUX_STORE__.getState().sessionState.sessionId);

  // Scenario 1: No messages, badge hidden
  const badge = page.locator('[data-testid="chat-badge"]');
  await expect(badge).toBeHidden();

  // Scenario 2: Window closed, messages arrive, badge shows count
  // ... (continue workflow)

  // Scenario 3: Page reload, localStorage persistence
  await page.reload();
  // ... (verify badge state persists)
});
```

Use helpers from existing test files (loginToJamUI, createAndJoinSession) and Redux dispatch pattern for WebSocket simulation.

IMPORTANT: This is an E2E test - it validates the complete system integration, not individual units. If bugs are discovered, apply deviation rules.
  </action>
  <verify>npx playwright test unread-tracking-flow.spec.ts passes with complete workflow validated</verify>
  <done>Single comprehensive E2E test covering 12+ steps of unread tracking workflow, test passing</done>
</task>

</tasks>

<verification>
Before declaring phase complete:
- [ ] All integration tests pass: unread-badge.spec.ts, localStorage-persistence.spec.ts, unread-tracking-flow.spec.ts
- [ ] Total test count: 14+ tests (7 badge + 6 localStorage + 1 E2E)
- [ ] Badge behavior validated: hidden, count, 99+, reset, increment logic
- [ ] localStorage persistence validated: save, load, multi-channel, error handling
- [ ] E2E workflow validated: complete user journey with page reload
- [ ] Any bugs discovered during testing fixed and documented in Summary
</verification>

<success_criteria>

- All tasks completed
- All integration tests passing (14+ tests total)
- Unread badge behavior validated across all scenarios
- localStorage persistence validated with error handling
- Complete E2E workflow validated
- Any bugs discovered fixed per deviation rules and documented in Summary
  </success_criteria>

<output>
After completion, create `.planning/phases/10-read-unread-status/10-01-SUMMARY.md`:

# Phase 10 Plan 1: Read/Unread Status Validation & Testing Summary

**[Substantive one-liner - what was validated/fixed]**

## Accomplishments

- Integration tests for unread badge behavior (7+ tests)
- Integration tests for localStorage persistence (6+ tests)
- E2E test for complete unread tracking workflow (1 comprehensive test)
- Total test coverage: 14+ tests validating read/unread system
- [Any bugs discovered and fixed]

## Files Created/Modified

**Created:**
- `jam-ui/test/chat/unread-badge.spec.ts` - Badge behavior tests
- `jam-ui/test/chat/localStorage-persistence.spec.ts` - Persistence tests
- `jam-ui/test/e2e/unread-tracking-flow.spec.ts` - Complete workflow test

**Modified (if bugs found):**
- [List any files modified to fix bugs discovered during testing]

## Decisions Made

[Document any decisions made during testing or bug fixes]

## Deviations from Plan

[If bugs were discovered and fixed, document here per deviation rules]

## Issues Encountered

[Problems discovered during testing and how they were resolved, or "None"]

## Next Phase Readiness

Phase 10 complete! Read/unread status management fully validated.

Ready for Phase 11 (Chat Finalization) - error handling, edge cases, performance optimization, final UAT.
</output>
