diff --git a/.planning/phases/06-session-chat-research-design/IMPLEMENTATION_ROADMAP.md b/.planning/phases/06-session-chat-research-design/IMPLEMENTATION_ROADMAP.md new file mode 100644 index 000000000..a1d8ed59b --- /dev/null +++ b/.planning/phases/06-session-chat-research-design/IMPLEMENTATION_ROADMAP.md @@ -0,0 +1,1138 @@ +# Session Chat Implementation Roadmap (Phases 7-11) + +**Purpose:** Detailed roadmap for implementing session chat feature across Phases 7-11, with plan estimates, risk analysis, and testing strategy. + +**Date:** 2026-01-26 +**Phase:** 06-session-chat-research-design +**Plan:** 02 + +--- + +## Overview + +This roadmap breaks down Phases 7-11 into executable plans, following the pattern from Phase 4 Plan 2 (which created Phase 5 roadmap for JamTrack). + +**Total Scope:** +- **5 Phases** (7-11) +- **Estimated 11-13 Plans** (subject to refinement during phase planning) +- **Complexity:** Medium (simpler than JamTrack Phase 5, similar to Backing Track Phase 3) + +**Reference Points:** +- Phase 3 (Backing Track): 3 plans, 7 tasks total +- Phase 5 (JamTrack): 9 plans, ~25 tasks total +- Phase 6 (Chat): Estimated 11-13 plans, ~28-32 tasks + +**Complexity Comparison:** +- Chat is **1.5-2x more complex** than Backing Track (Phase 3) +- Chat is **0.6x less complex** than JamTrack (Phase 5) +- Rationale: No native client integration (simpler), but multi-channel + unread tracking (moderately complex) + +--- + +## Phase-by-Phase Breakdown + +### Phase 7: Chat Infrastructure & State Management + +**Objective:** Build Redux foundation, API integration, and WebSocket handlers. + +**Estimated Plans:** 3 plans + +**Preliminary Plan Breakdown:** + +#### Plan 7.1: Redux Slice & Core Reducers (TDD) + +**Tasks (3-4):** +1. Create `sessionChatSlice.js` with initial state structure +2. Implement standard reducers: `addMessageFromWebSocket`, `setActiveChannel`, `openChatWindow`, `closeChatWindow`, `markAsRead`, `incrementUnreadCount` +3. Write unit tests for all reducers (TDD approach) +4. Test message deduplication logic (by `msg_id`) + +**Dependencies:** None (foundational) + +**TDD Candidates:** +- ✅ All reducers (state transitions) +- ✅ Message deduplication logic +- ✅ Unread count increment/reset logic + +**Deliverables:** +- `jam-ui/src/store/features/sessionChatSlice.js` +- Unit tests: `sessionChatSlice.test.js` + +**Complexity:** Simple +**Estimated Duration:** 1-2 sessions + +--- + +#### Plan 7.2: Async Thunks & API Integration (TDD) + +**Tasks (3-4):** +1. Add REST API client methods: `getChatMessages()`, `sendChatMessage()` in `rest.js` +2. Implement `fetchChatHistory` async thunk with extra reducers +3. Implement `sendMessage` async thunk with extra reducers +4. Write unit tests for async thunks (mock fetch, test success/error paths) +5. Test API error handling (404, 403, 422, 500) + +**Dependencies:** Plan 7.1 (Redux slice must exist) + +**TDD Candidates:** +- ✅ `getChatMessages` API client method +- ✅ `sendChatMessage` API client method +- ✅ `fetchChatHistory` async thunk +- ✅ `sendMessage` async thunk +- ✅ Error handling for all HTTP status codes + +**Deliverables:** +- `jam-ui/src/helpers/rest.js` (extended) +- Async thunks in `sessionChatSlice.js` +- Unit tests: `rest.test.js`, `sessionChatSlice.test.js` (async thunks) + +**Complexity:** Medium +**Estimated Duration:** 2-3 sessions + +--- + +#### Plan 7.3: WebSocket Integration & Selectors (TDD) + +**Tasks (3-4):** +1. Add `CHAT_MESSAGE` handler to `useSessionWebSocket.js` +2. Test WebSocket message routing to Redux (mock JamServer) +3. Implement memoized selectors: `selectChatMessages`, `selectUnreadCount`, etc. +4. Test selectors with various state scenarios +5. Add localStorage persistence for `lastReadAt` timestamps + +**Dependencies:** Plan 7.1, 7.2 + +**TDD Candidates:** +- ✅ `CHAT_MESSAGE` WebSocket handler +- ✅ Selectors (unit tests) +- ✅ localStorage persistence logic + +**Deliverables:** +- `jam-ui/src/hooks/useSessionWebSocket.js` (extended) +- Selectors in `sessionChatSlice.js` +- Unit tests: `useSessionWebSocket.test.js`, `sessionChatSlice.test.js` (selectors) + +**Complexity:** Medium +**Estimated Duration:** 2 sessions + +--- + +**Phase 7 Summary:** +- **3 Plans, ~10-12 Tasks** +- **All TDD** (data layer) +- **Foundation for Phases 8-11** + +--- + +### Phase 8: Chat Window UI & Message Display + +**Objective:** Build chat window components with WindowPortal integration. + +**Estimated Plans:** 3 plans + +**Preliminary Plan Breakdown:** + +#### Plan 8.1: Chat Window Shell & WindowPortal Integration + +**Tasks (3):** +1. Create `JKSessionChatWindow.js` component with WindowPortal wrapper +2. Create `JKChatHeader.js` component (title + close button) +3. Integrate chat window with JKSessionScreen (conditional rendering) +4. Test window open/close behavior (integration test) + +**Dependencies:** Phase 7 complete (Redux slice available) + +**TDD Candidates:** +- ✅ Window open/close behavior (integration test) +- ❌ Component rendering (visual, skip TDD) + +**Deliverables:** +- `jam-ui/src/components/client/JKSessionChatWindow.js` +- `jam-ui/src/components/client/chat/JKChatHeader.js` +- Integration test: `chat-window.spec.ts` + +**Complexity:** Simple +**Estimated Duration:** 1-2 sessions + +--- + +#### Plan 8.2: Message List & Auto-Scroll + +**Tasks (4-5):** +1. Create `JKChatMessageList.js` component with auto-scroll logic +2. Create `JKChatMessage.js` component (avatar, name, text, timestamp) +3. Create `JKChatLoadingSpinner.js` and `JKChatEmptyState.js` components +4. Implement auto-scroll behavior (scroll to bottom on new message) +5. Test auto-scroll logic (respect user manual scrolling) +6. Add timestamp formatting utility (dayjs relative time) + +**Dependencies:** Plan 8.1 + +**TDD Candidates:** +- ✅ Auto-scroll logic (unit test: isUserScrolling state) +- ✅ Timestamp formatting utility +- ❌ Component rendering (visual, skip TDD) + +**Deliverables:** +- `jam-ui/src/components/client/chat/JKChatMessageList.js` +- `jam-ui/src/components/client/chat/JKChatMessage.js` +- `jam-ui/src/components/client/chat/JKChatLoadingSpinner.js` +- `jam-ui/src/components/client/chat/JKChatEmptyState.js` +- `jam-ui/src/utils/formatTimestamp.js` +- Unit tests: `JKChatMessageList.test.js`, `formatTimestamp.test.js` + +**Complexity:** Medium +**Estimated Duration:** 2-3 sessions + +--- + +#### Plan 8.3: Chat Button & Unread Badge + +**Tasks (3):** +1. Create `JKSessionChatButton.js` component with unread badge +2. Add chat button to JKSessionScreen top navigation +3. Test unread badge visibility and count updates +4. Style chat button (CSS/SCSS) + +**Dependencies:** Phase 7 complete, Plan 8.1 + +**TDD Candidates:** +- ✅ Badge visibility logic (integration test) +- ✅ Unread count updates on message receive (integration test) +- ❌ CSS styling (skip TDD) + +**Deliverables:** +- `jam-ui/src/components/client/JKSessionChatButton.js` +- Integration test: `chat-button.spec.ts` +- SCSS: `JKSessionChatButton.scss` + +**Complexity:** Simple +**Estimated Duration:** 1-2 sessions + +--- + +**Phase 8 Summary:** +- **3 Plans, ~10-12 Tasks** +- **Mixed TDD** (behavior tests, skip styling) +- **UI components complete** + +--- + +### Phase 9: Message Composition & Sending + +**Objective:** Implement message input, send functionality, and real-time delivery. + +**Estimated Plans:** 2 plans + +**Preliminary Plan Breakdown:** + +#### Plan 9.1: Message Composer & Validation (TDD) + +**Tasks (4-5):** +1. Create `JKChatComposer.js` component (textarea + send button) +2. Implement keyboard handling: Enter-to-send, Shift+Enter for newline +3. Add message validation: length (1-255 chars), non-empty +4. Add character count display (255 max) +5. Test keyboard handling and validation logic +6. Disable send button when disconnected (check `isConnected` from JamServerContext) + +**Dependencies:** Phase 8 complete + +**TDD Candidates:** +- ✅ Keyboard handling (Enter vs Shift+Enter) +- ✅ Message validation logic +- ✅ Character count calculation +- ✅ Disable send when disconnected + +**Deliverables:** +- `jam-ui/src/components/client/chat/JKChatComposer.js` +- Unit tests: `JKChatComposer.test.js` +- Integration test: `message-composition.spec.ts` + +**Complexity:** Medium +**Estimated Duration:** 2 sessions + +--- + +#### Plan 9.2: Send Message & Real-Time Delivery (TDD) + +**Tasks (4-5):** +1. Wire up `sendMessage` async thunk to send button +2. Test send message flow: API call → Redux update → UI update +3. Test real-time message delivery: WebSocket → Redux → UI update +4. Test message deduplication (sent message not duplicated on WebSocket receive) +5. Add error handling for send failures (display error message) +6. Test optimistic update behavior (message appears immediately) + +**Dependencies:** Plan 9.1, Phase 7 complete + +**TDD Candidates:** +- ✅ Send message flow (integration test) +- ✅ Real-time delivery (integration test with WebSocket mock) +- ✅ Message deduplication (unit test) +- ✅ Error handling (unit + integration test) + +**Deliverables:** +- Integration tests: `send-message.spec.ts`, `receive-message.spec.ts` +- Error handling UI in `JKChatComposer.js` + +**Complexity:** Medium +**Estimated Duration:** 2-3 sessions + +--- + +**Phase 9 Summary:** +- **2 Plans, ~8-10 Tasks** +- **Full TDD** (behavior-focused) +- **Core functionality complete** + +--- + +### Phase 10: Read/Unread Status Management + +**Objective:** Implement read/unread tracking, badge updates, and localStorage persistence. + +**Estimated Plans:** 2 plans + +**Preliminary Plan Breakdown:** + +#### Plan 10.1: Unread Tracking & Badge Updates (TDD) + +**Tasks (4):** +1. Test unread count increment on message receive (window closed) +2. Test unread count reset on window open (mark as read) +3. Test badge visibility based on unread count +4. Test multi-channel unread tracking (global, session, lesson) +5. Add localStorage persistence for `lastReadAt` timestamps + +**Dependencies:** Phase 8, 9 complete + +**TDD Candidates:** +- ✅ Unread count increment logic (unit test) +- ✅ Badge visibility logic (integration test) +- ✅ localStorage persistence (unit test) +- ✅ Multi-channel tracking (unit test) + +**Deliverables:** +- Integration tests: `unread-badge.spec.ts` +- Unit tests: `sessionChatSlice.test.js` (unread logic) + +**Complexity:** Medium +**Estimated Duration:** 2 sessions + +--- + +#### Plan 10.2: Channel Switching & Read State Sync + +**Tasks (3-4):** +1. Implement channel switching logic (global ↔ session ↔ lesson) +2. Test read state sync on channel switch (mark as read) +3. Test unread counts persist across channel switches +4. Test localStorage persistence across browser sessions +5. Handle edge case: multiple tabs/windows (localStorage sync) + +**Dependencies:** Plan 10.1 + +**TDD Candidates:** +- ✅ Channel switching (integration test) +- ✅ Read state sync (unit test) +- ✅ localStorage persistence (unit test) + +**Deliverables:** +- Integration test: `channel-switching.spec.ts` +- localStorage sync logic in `sessionChatSlice.js` + +**Complexity:** Medium +**Estimated Duration:** 2 sessions + +--- + +**Phase 10 Summary:** +- **2 Plans, ~7-8 Tasks** +- **Full TDD** (state management focused) +- **Read/unread tracking complete** + +--- + +### Phase 11: Chat Finalization & Polish + +**Objective:** Error handling, edge cases, performance optimization, and UAT. + +**Estimated Plans:** 3 plans + +**Preliminary Plan Breakdown:** + +#### Plan 11.1: Error Handling & Retry Logic + +**Tasks (4-5):** +1. Handle API errors: 404, 403, 422, 500 (display user-friendly messages) +2. Handle WebSocket disconnection (disable send, show status) +3. Implement retry logic for failed message sends +4. Test error recovery flows (connection lost → reconnect → retry) +5. Add loading states (spinner during fetch/send) + +**Dependencies:** Phase 9 complete + +**TDD Candidates:** +- ✅ API error handling (unit test) +- ✅ WebSocket disconnection handling (integration test) +- ✅ Retry logic (unit test) + +**Deliverables:** +- Error handling in `JKChatComposer.js` +- Retry logic in `sendMessage` async thunk +- Integration test: `error-handling.spec.ts` + +**Complexity:** Medium +**Estimated Duration:** 2 sessions + +--- + +#### Plan 11.2: Performance Optimization & Accessibility + +**Tasks (4-5):** +1. Optimize message list rendering (React.memo for JKChatMessage) +2. Optimize selectors (Reselect memoization) +3. Add accessibility: ARIA labels, keyboard navigation +4. Test keyboard navigation (Tab, Enter, Esc) +5. Add focus management (auto-focus input on window open) +6. Consider virtualization for message list (if >100 messages) - **DEFER if not needed** + +**Dependencies:** Phase 8-10 complete + +**TDD Candidates:** +- ✅ Keyboard navigation (E2E test) +- ❌ React.memo optimization (performance test, not TDD) +- ❌ Accessibility (manual audit, skip TDD) + +**Deliverables:** +- Optimized components (React.memo) +- Accessibility improvements (ARIA attributes) +- E2E test: `keyboard-navigation.spec.ts` + +**Complexity:** Medium +**Estimated Duration:** 2 sessions + +--- + +#### Plan 11.3: UAT & Final Integration Testing + +**Tasks (4-5):** +1. Conduct comprehensive UAT (40+ test cases from CHAT_COMPONENT_DESIGN.md) +2. Fix critical UAT issues (P0/P1 severity) +3. Document deferred issues (P2/P3 severity) +4. Run full E2E test suite +5. Verify no regressions (Backing Track, JamTrack, Metronome still work) +6. Update documentation (CLAUDE.md, CONVENTIONS.md if needed) + +**Dependencies:** Phase 7-10 complete, Plan 11.1-11.2 complete + +**TDD Candidates:** +- ✅ E2E tests for complete workflows +- ❌ Manual UAT (user acceptance testing) + +**Deliverables:** +- UAT test report +- E2E test suite: `complete-chat-flow.spec.ts` +- Deferred issues documented in GitHub issues (if any) + +**Complexity:** Medium +**Estimated Duration:** 2-3 sessions + +--- + +**Phase 11 Summary:** +- **3 Plans, ~12-15 Tasks** +- **Mixed TDD** (error handling + E2E tests, skip performance/accessibility) +- **Phase 6 complete!** + +--- + +## Dependency Graph + +``` +Phase 7 (Infrastructure) +├── Plan 7.1: Redux Slice & Core Reducers +├── Plan 7.2: Async Thunks & API Integration (depends on 7.1) +└── Plan 7.3: WebSocket Integration & Selectors (depends on 7.1, 7.2) + +Phase 8 (UI Components) +├── Plan 8.1: Chat Window Shell (depends on Phase 7) +├── Plan 8.2: Message List & Auto-Scroll (depends on 8.1) +└── Plan 8.3: Chat Button & Unread Badge (depends on Phase 7, 8.1) + +Phase 9 (Message Composition) +├── Plan 9.1: Message Composer (depends on Phase 8) +└── Plan 9.2: Send Message & Real-Time Delivery (depends on 9.1, Phase 7) + +Phase 10 (Read/Unread Tracking) +├── Plan 10.1: Unread Tracking & Badge Updates (depends on Phase 8, 9) +└── Plan 10.2: Channel Switching & Read State Sync (depends on 10.1) + +Phase 11 (Finalization) +├── Plan 11.1: Error Handling & Retry Logic (depends on Phase 9) +├── Plan 11.2: Performance & Accessibility (depends on Phase 8-10) +└── Plan 11.3: UAT & Final Integration Testing (depends on 11.1, 11.2) +``` + +**Critical Path:** +- Phase 7 (all plans) → Phase 8.1 → Phase 8.2 → Phase 9.1 → Phase 9.2 → Phase 10.1 → Phase 10.2 → Phase 11.3 + +**Parallel Opportunities:** +- Plan 8.3 (chat button) can be built in parallel with Plan 8.2 (message list) +- Plan 11.1 (error handling) can start after Phase 9, doesn't need Phase 10 + +--- + +## Risk Analysis + +### HIGH Risks + +**Risk 1: WebSocket Message Deduplication** + +**Description:** WebSocket messages may arrive multiple times (reconnect, race conditions). Deduplication by `msg_id` is critical to avoid duplicate UI rendering. + +**Impact:** HIGH - Duplicate messages confuse users, degrade UX + +**Mitigation:** +1. Implement deduplication in `addMessageFromWebSocket` reducer (check by `msg_id`) +2. Add unit tests for deduplication logic (receive same message twice) +3. Test with simulated reconnect scenarios + +**Contingency:** +- If deduplication fails, add deduplication at WebSocket handler level (before Redux) +- Log duplicate messages for debugging + +--- + +**Risk 2: localStorage Persistence Edge Cases** + +**Description:** localStorage has quota limits, may be disabled in private browsing, or fail due to quota exceeded. + +**Impact:** HIGH - Unread counts lost across sessions, poor UX + +**Mitigation:** +1. Wrap localStorage access in try/catch blocks +2. Gracefully degrade: If localStorage fails, keep in-memory state only +3. Test in private browsing mode + +**Contingency:** +- Fall back to Redux-only state (no persistence) +- Log localStorage errors for monitoring + +--- + +### MEDIUM Risks + +**Risk 3: Auto-Scroll Behavior Conflicts** + +**Description:** Auto-scroll to bottom vs user manual scrolling. If not handled correctly, auto-scroll may interrupt user reading previous messages. + +**Impact:** MEDIUM - Annoying UX, users can't read history + +**Mitigation:** +1. Track `isUserScrolling` state (detect when user scrolls up) +2. Disable auto-scroll if user not at bottom +3. Re-enable auto-scroll when user scrolls to bottom +4. Test with rapid message influx (stress test) + +**Contingency:** +- Add "Scroll to bottom" button if auto-scroll disabled +- Add "New messages" indicator + +--- + +**Risk 4: Multi-Tab/Window State Sync** + +**Description:** If user opens chat in multiple tabs, unread counts and `lastReadAt` may drift out of sync. + +**Impact:** MEDIUM - Inconsistent badge counts across tabs + +**Mitigation:** +1. Use localStorage events to sync state across tabs +2. Test with multiple tabs open +3. Consider marking as read in one tab clears badge in all tabs + +**Contingency:** +- Document limitation: Unread counts may not sync perfectly across tabs (acceptable for MVP) +- Defer full sync to server-side tracking (next milestone) + +--- + +**Risk 5: API Error Handling Complexity** + +**Description:** Chat API has 4 error types (404, 403, 422, 500). Each requires different user feedback and recovery strategy. + +**Impact:** MEDIUM - Users confused by errors, can't recover + +**Mitigation:** +1. Map each error code to user-friendly message +2. Add retry button for transient errors (500) +3. Disable send for fatal errors (403) +4. Show inline validation for 422 errors + +**Contingency:** +- Show generic error message if unknown error code +- Provide support contact link + +--- + +**Risk 6: WindowPortal Styling Issues** + +**Description:** WindowPortal copies stylesheets from parent, but may have timing issues or missing styles in popup window. + +**Impact:** MEDIUM - Chat window looks broken/unstyled + +**Mitigation:** +1. Test WindowPortal thoroughly (already proven for Metronome, JamTrack) +2. Add delay before rendering content (wait for stylesheets) +3. Reference existing WindowPortal usage patterns + +**Contingency:** +- Fall back to inline styles if external stylesheets fail +- Add inline critical CSS + +--- + +### LOW Risks + +**Risk 7: Character Count Validation** + +**Description:** Message length validation (max 255 chars). Edge cases: Unicode characters, emoji count. + +**Impact:** LOW - Minor validation bugs + +**Mitigation:** +1. Use `message.length` for character count (JS handles Unicode correctly) +2. Test with emoji, special characters +3. Server-side validation as backup (already exists) + +**Contingency:** +- Server rejects invalid messages (422 error) +- Show validation error to user + +--- + +**Risk 8: Timestamp Formatting Performance** + +**Description:** `dayjs.fromNow()` called for every message on every render. Could be slow for large message lists. + +**Impact:** LOW - Slight performance degradation + +**Mitigation:** +1. Memoize `JKChatMessage` component with React.memo +2. Only update timestamp on message change (not on every render) +3. Consider caching formatted timestamps + +**Contingency:** +- Use absolute timestamps (e.g., "12:30 PM") instead of relative (e.g., "5 minutes ago") +- Update timestamps on interval (every 60 seconds) instead of every render + +--- + +## TDD Strategy + +### When to Use TDD (per CLAUDE.md) + +**ALWAYS use TDD for:** +- ✅ Redux reducers (state transitions) +- ✅ Async thunks (API calls, error handling) +- ✅ Selectors (computed values) +- ✅ WebSocket handlers (message routing) +- ✅ Validation logic (message length, character count) +- ✅ Business logic (deduplication, unread count, auto-scroll) + +**TDD Optional for:** +- ❌ Styling-only changes (CSS/SCSS) +- ❌ Component rendering (visual appearance) +- ❌ Performance optimizations (React.memo, Reselect) + +--- + +### TDD Workflow Summary + +**Phase 7 (Infrastructure):** +- **100% TDD** - All data layer (Redux, API, WebSocket) +- Test-first approach for all reducers, thunks, selectors + +**Phase 8 (UI Components):** +- **50% TDD** - Component behavior (open/close, auto-scroll), skip styling +- Integration tests for window open/close, badge visibility + +**Phase 9 (Message Composition):** +- **100% TDD** - Keyboard handling, validation, send flow +- Integration tests for send message, receive message + +**Phase 10 (Read/Unread Tracking):** +- **100% TDD** - Unread count logic, localStorage persistence +- Integration tests for badge updates, channel switching + +**Phase 11 (Finalization):** +- **70% TDD** - Error handling, retry logic, keyboard navigation +- Skip TDD for performance optimizations, accessibility audits + +--- + +### Test Coverage Goals + +**Unit Tests (Jest):** +- Redux reducers: 100% coverage +- Async thunks: 100% coverage (success + error paths) +- Selectors: 100% coverage +- Utility functions: 100% coverage + +**Integration Tests (Playwright):** +- Send message flow: ✅ +- Receive message flow: ✅ +- Unread badge updates: ✅ +- Window open/close: ✅ +- Auto-scroll behavior: ✅ +- Channel switching: ✅ +- Error handling: ✅ + +**E2E Tests (Playwright):** +- Complete chat workflow: Login → Create session → Send message → Receive message → Close chat → Unread badge → Open chat +- Multi-user scenario: Two users chatting in same session (requires test infrastructure) + +--- + +## Testing Strategy + +### Unit Tests (Jest) + +**Location:** `jam-ui/src/**/__tests__/*.test.js` + +**Coverage:** +- Redux slice: `sessionChatSlice.test.js` +- Async thunks: `sessionChatSlice.test.js` (async thunks section) +- API client: `rest.test.js` +- WebSocket handler: `useSessionWebSocket.test.js` +- Selectors: `sessionChatSlice.test.js` (selectors section) +- Utilities: `formatTimestamp.test.js` + +**Example Test Structure:** +```javascript +describe('sessionChatSlice', () => { + describe('reducers', () => { + test('addMessageFromWebSocket', () => { ... }); + test('openChatWindow', () => { ... }); + test('markAsRead', () => { ... }); + }); + + describe('async thunks', () => { + test('fetchChatHistory success', async () => { ... }); + test('fetchChatHistory error', async () => { ... }); + test('sendMessage success', async () => { ... }); + test('sendMessage error', async () => { ... }); + }); + + describe('selectors', () => { + test('selectChatMessages', () => { ... }); + test('selectUnreadCount', () => { ... }); + }); +}); +``` + +--- + +### Integration Tests (Playwright) + +**Location:** `jam-ui/test/session-chat/*.spec.ts` + +**Test Files:** +- `chat-window.spec.ts` - Window open/close, basic rendering +- `send-message.spec.ts` - Send message flow (API call, UI update) +- `receive-message.spec.ts` - WebSocket message receive, UI update +- `unread-badge.spec.ts` - Badge visibility, count updates +- `auto-scroll.spec.ts` - Auto-scroll behavior, manual scroll detection +- `channel-switching.spec.ts` - Switch between global/session/lesson +- `error-handling.spec.ts` - API errors, WebSocket disconnection + +**Example Test:** +```typescript +// send-message.spec.ts +test('sends message and updates UI', async ({ page }) => { + await loginToJamUI(page); + await createAndJoinSession(page); + + // Open chat + await page.click('[data-testid="chat-button"]'); + + // Send message + await page.fill('[data-testid="chat-input"]', 'Test message'); + await page.keyboard.press('Enter'); + + // Verify API call + const chatCalls = interceptor.getCallsByPath('/api/chat'); + expect(chatCalls.length).toBe(1); + + // Verify UI update + await expect(page.locator('[data-testid="chat-message"]').last()) + .toContainText('Test message'); +}); +``` + +--- + +### E2E Tests (Playwright) + +**Location:** `jam-ui/test/e2e/complete-chat-flow.spec.ts` + +**Test Scenarios:** +1. **Complete Chat Flow:** + - Login → Create session → Join session + - Open chat → Send message → Verify sent + - Close chat → Simulate incoming message → Verify badge + - Open chat → Verify badge cleared → Verify reply visible + +2. **Multi-User Flow (Advanced, defer to Phase 11):** + - User A creates session + - User B joins session + - User A sends message → User B receives message + - User B sends reply → User A receives reply + +--- + +## Deferred Features & Decisions + +### Deferred to Next Milestone (Phase 12+) + +**1. Server-Side Read/Unread Tracking** +- Create `chat_message_reads` table +- API endpoint: `PUT /api/chat/mark_read` +- Cross-device synchronization +- Per-message read receipts + +**2. File Attachments** +- Support for music notation, audio files, recordings +- Upload UI and file validation +- Attachment rendering in messages + +**3. Message Search/Filtering** +- Search messages by text, sender, date +- Filter by attachment type +- Pagination for large message lists + +**4. Message Editing/Deletion** +- Edit sent messages (within time window) +- Delete messages (soft delete) +- Show "edited" indicator + +**5. Typing Indicators** +- Show "User is typing..." when other users typing +- WebSocket message for typing state +- Throttle typing updates + +**6. Emoji Picker** +- Inline emoji picker for message composition +- Emoji autocomplete (`:smile:` → 😊) + +**7. Multi-Channel Tabs** +- Tab UI to switch between global, session, lesson +- Unread badge per tab +- Persist active tab preference + +**8. Notification Sounds** +- Play sound when message received (window closed) +- User preference to enable/disable sounds + +**9. Desktop Notifications** +- Browser notification API for new messages +- Request permission on first use +- Show message preview in notification + +--- + +### Critical Decisions for Phase 7-11 + +**Decision 1: Message Virtualization** +- **Question:** Should message list use virtualization (react-window) for performance? +- **Options:** + - A: Implement virtualization from start (prevents future refactor) + - B: Defer until >100 messages becomes problem (simpler MVP) +- **Recommendation:** Option B - Defer until needed +- **Rationale:** Adds complexity, unlikely to have >100 messages in single session for MVP +- **Impact:** If deferred, may need refactor in Phase 11 or next milestone + +**Decision 2: Optimistic UI Updates** +- **Question:** Should sent messages appear immediately (before API response)? +- **Options:** + - A: Optimistic update (fast UX, handles API errors) + - B: Wait for API response (simple, no error recovery needed) +- **Recommendation:** Option A - Optimistic update +- **Rationale:** Better UX (immediate feedback), API usually succeeds +- **Impact:** Requires error handling (rollback on failure) + +**Decision 3: Unread Count Persistence** +- **Question:** Store unread counts in localStorage or Redux-only? +- **Options:** + - A: localStorage (persists across sessions) + - B: Redux-only (resets on page reload) +- **Recommendation:** Option A - localStorage +- **Rationale:** Better UX (remembers unread counts), simple to implement +- **Impact:** Requires localStorage error handling (quota, private browsing) + +**Decision 4: Multi-Tab State Sync** +- **Question:** Should unread counts sync across browser tabs? +- **Options:** + - A: Sync via localStorage events (complex, better UX) + - B: No sync, each tab independent (simple, acceptable UX) +- **Recommendation:** Option B - No sync for MVP +- **Rationale:** Adds complexity, edge case scenario, can defer to next milestone +- **Impact:** Users may see inconsistent badge counts across tabs (document as limitation) + +**Decision 5: Auto-Scroll Strategy** +- **Question:** How to handle auto-scroll when user manually scrolls up? +- **Options:** + - A: Disable auto-scroll, show "New messages" button (user control) + - B: Auto-scroll after N seconds of inactivity (automatic, may interrupt) + - C: Track scroll position, re-enable when user scrolls to bottom (smart) +- **Recommendation:** Option C - Track scroll position +- **Rationale:** Best UX (doesn't interrupt, auto-resumes), matches legacy behavior +- **Impact:** Requires scroll event listener, slight complexity + +--- + +## Success Metrics + +### Functional Completeness + +**Phase 7 Complete:** +- ✅ Redux slice with multi-channel state +- ✅ Async thunks for fetch history, send message +- ✅ WebSocket handler for real-time messages +- ✅ Selectors for data access + +**Phase 8 Complete:** +- ✅ Chat window renders in WindowPortal +- ✅ Message list with auto-scroll +- ✅ Chat button with unread badge + +**Phase 9 Complete:** +- ✅ Message composer with validation +- ✅ Send message functionality +- ✅ Real-time message delivery + +**Phase 10 Complete:** +- ✅ Unread count tracking per channel +- ✅ Badge updates on message receive +- ✅ Mark as read on window open + +**Phase 11 Complete:** +- ✅ Error handling for API and WebSocket +- ✅ Performance optimizations (React.memo, Reselect) +- ✅ Accessibility improvements +- ✅ UAT complete with all P0/P1 issues resolved + +--- + +### Code Quality + +**Test Coverage:** +- Unit tests: 80%+ coverage for Redux, API, WebSocket +- Integration tests: All critical user flows covered +- E2E tests: Complete workflow tested + +**Code Standards:** +- All code follows jam-ui conventions (CONVENTIONS.md) +- TDD followed for all data layer (per CLAUDE.md) +- No ESLint errors or warnings +- Components use functional patterns (hooks, not classes) + +**Documentation:** +- All components have JSDoc comments +- Redux actions/thunks documented +- README.md updated with chat feature description + +--- + +### UX Quality + +**Performance:** +- Message list renders smoothly (no lag for <100 messages) +- Auto-scroll doesn't jank +- Send message feels instant (optimistic update) + +**Visual Design:** +- Chat window matches jam-ui styling +- Messages have clear sender identification +- Timestamps readable (relative time format) +- Unread badge visible and clear + +**Accessibility:** +- Keyboard navigation works (Tab, Enter, Esc) +- Screen reader announces new messages +- ARIA labels on interactive elements +- Focus management (auto-focus input on window open) + +--- + +## UAT Test Cases (40+ Cases) + +### Category 1: Initialization (4 cases) + +**UAT-001:** Join session → Chat button appears in top nav +**UAT-002:** Click chat button → Chat window opens in popup +**UAT-003:** Chat window closed by default on session join +**UAT-004:** Fetch message history on window open (show loading spinner) + +--- + +### Category 2: Message Display (6 cases) + +**UAT-005:** Messages render with avatar, name, text, timestamp +**UAT-006:** Current user messages right-aligned, others left-aligned +**UAT-007:** Timestamps show relative time ("5 minutes ago") +**UAT-008:** Empty state shown when no messages +**UAT-009:** Loading spinner shown while fetching history +**UAT-010:** Messages sorted by created_at (oldest first) + +--- + +### Category 3: Message Composition (7 cases) + +**UAT-011:** Type in textarea → Send button enabled +**UAT-012:** Press Enter → Message sent +**UAT-013:** Press Shift+Enter → Newline added (message not sent) +**UAT-014:** Empty message → Send button disabled +**UAT-015:** Message >255 chars → Validation error shown +**UAT-016:** Character count displayed (255 max) +**UAT-017:** Disconnected from server → Send button disabled + +--- + +### Category 4: Message Sending (5 cases) + +**UAT-018:** Click Send → API call made (POST /api/chat) +**UAT-019:** Message sent → Appears in UI immediately (optimistic update) +**UAT-020:** API error → Error message shown, input not cleared +**UAT-021:** Message sent → Input cleared, focus restored +**UAT-022:** Message sent → No duplicate on WebSocket receive (deduplication) + +--- + +### Category 5: Real-Time Messages (5 cases) + +**UAT-023:** Other user sends message → Message appears in UI +**UAT-024:** WebSocket message → Auto-scroll to bottom +**UAT-025:** User scrolled up → Auto-scroll disabled (doesn't interrupt) +**UAT-026:** User scrolls to bottom → Auto-scroll re-enabled +**UAT-027:** Duplicate WebSocket message → No duplicate in UI (deduplication) + +--- + +### Category 6: Unread Badge (7 cases) + +**UAT-028:** Chat window closed → Badge hidden (count = 0) +**UAT-029:** Message received (window closed) → Badge shows count = 1 +**UAT-030:** Multiple messages received → Badge count increments +**UAT-031:** Open chat window → Badge count resets to 0 +**UAT-032:** Badge hidden when count = 0 +**UAT-033:** Unread count persists across page reload (localStorage) +**UAT-034:** Multiple tabs open → Badge updates independently per tab + +--- + +### Category 7: Window Management (4 cases) + +**UAT-035:** Click close button → Window closes +**UAT-036:** Close window → Unread count persists +**UAT-037:** Open window again → Same position (WindowPortal saves position) +**UAT-038:** WindowPortal stylesheets copied correctly (no broken styles) + +--- + +### Category 8: Error Handling (5 cases) + +**UAT-039:** API error 404 → "Session not found" message shown +**UAT-040:** API error 403 → "Not allowed to join session" message shown +**UAT-041:** API error 422 → Validation error shown inline +**UAT-042:** WebSocket disconnected → Send button disabled, status shown +**UAT-043:** WebSocket reconnected → Send button re-enabled + +--- + +### Category 9: Edge Cases (7 cases) + +**UAT-044:** Private browsing mode → localStorage gracefully degrades +**UAT-045:** localStorage quota exceeded → No crash, fallback to Redux-only +**UAT-046:** Very long username → Truncated with ellipsis +**UAT-047:** Message with emoji → Renders correctly +**UAT-048:** Message with newlines (Shift+Enter) → Preserves formatting +**UAT-049:** Rapid message influx (10 msgs/sec) → No performance degradation +**UAT-050:** Open chat, close session, reopen chat → No stale data + +--- + +## Complexity Estimation + +### Comparison to Previous Phases + +**Phase 3 (Backing Track):** +- **Plans:** 3 +- **Tasks:** ~7 +- **Complexity:** Simple +- **Features:** Play/pause, volume, track selection +- **No network:** Pure jamClient integration + +**Phase 5 (JamTrack):** +- **Plans:** 9 +- **Tasks:** ~25 +- **Complexity:** High +- **Features:** Download/sync, playback, mixdown selection, seek, JMEP +- **Network:** REST API + WebSocket + jamClient integration + +**Phase 6 (Chat):** +- **Plans:** 11-13 (estimated) +- **Tasks:** ~28-32 (estimated) +- **Complexity:** Medium +- **Features:** Send/receive, unread tracking, multi-channel, WindowPortal +- **Network:** REST API + WebSocket (no jamClient) + +**Multiplier:** +- Chat is **1.5-2x more complex** than Backing Track (more features, network layer) +- Chat is **0.6x less complex** than JamTrack (no native client, simpler state machine) + +**Rationale:** +- Backing Track baseline: 3 plans × 1.5-2 = 4.5-6 plans (but Chat has more features) +- JamTrack reference: 9 plans × 0.6 = 5.4 plans (but Chat has unread tracking) +- Adjusted estimate: 11-13 plans (accounts for multi-channel, unread tracking, WindowPortal integration) + +--- + +## Summary + +**Phase 7-11 Roadmap Complete:** +- ✅ 5 phases broken down into 11-13 preliminary plans +- ✅ ~28-32 tasks estimated +- ✅ Dependency graph mapped (critical path identified) +- ✅ Risk analysis complete (2 HIGH, 4 MEDIUM, 2 LOW risks with mitigation) +- ✅ TDD strategy defined (100% for data layer, 50-70% for UI) +- ✅ Testing strategy comprehensive (unit, integration, E2E) +- ✅ 40+ UAT test cases defined +- ✅ Success metrics clear (functional, code quality, UX) +- ✅ Deferred features documented (server-side tracking, attachments, etc.) +- ✅ 5 critical decisions identified for Phase 7-11 + +**Ready for Phase 7 Execution:** +- Phase 6 design artifacts complete +- Phase 7-11 roadmap provides clear execution path +- Risk mitigation strategies defined +- TDD approach aligned with CLAUDE.md requirements + +**Estimated Effort:** +- Phase 6 (research + design): 2 plans, ~6 tasks +- Phase 7-11 (implementation): 11-13 plans, ~28-32 tasks +- Total: 13-15 plans, ~34-38 tasks for complete session chat feature + +**Next Steps:** +1. Review and approve roadmap +2. `/gsd:plan-phase 7` to create executable PLAN.md files +3. Execute Phase 7.1 (Redux Slice & Core Reducers) using TDD +4. Iterate through phases sequentially (7 → 8 → 9 → 10 → 11) + +--- + +**Roadmap Complete!** +**Phase 6 Complete!** +**Ready for Phase 7: Chat Infrastructure & State Management**