12 KiB
Project State
Project Reference
See: .planning/PROJECT.md (updated 2026-01-13)
Core value: Modernize session features (Backing Track, JamTrack, Session Chat) from legacy jQuery/Rails to React patterns in jam-ui Current focus: Milestone v1.1 — Music Session Chat
Current Position
Phase: 6 of 11 (Session Chat Research & Design) Plan: 06-01 Complete Status: Ready for Plan 2 (React Architecture Design) Last activity: 2026-01-26 — Plan 1 (Legacy Analysis) complete
Progress: ██░░░░░░░░ 20% (v1.1)
Performance Metrics
v1.0 Media Players (Complete):
- Total plans completed: 13
- Total phases: 5
- Average duration: ~10-20 min per plan
- Total execution time: ~220 min
By Phase (v1.0):
| Phase | Plans | Total | Avg/Plan |
|---|---|---|---|
| 1 | 1 | 3 min | 3 min |
| 2 | 1 | 120 min | 120 min |
| 3 | 3 | TBD | TBD |
| 4 | 2 | 41 min | 20.5 min |
| 5 | 5 | 54 min | 10.8 min |
v1.1 Music Session Chat (In Progress):
- Total plans completed: 1
- Total phases: 6 (phases 6-11)
- Progress: 20% (Phase 6 Plan 1 complete)
Recent Trend:
- Last milestone: v1.0 completed 2026-01-14 with excellent velocity
- Current milestone: v1.1 started 2026-01-26
Accumulated Context
Decisions
Decisions are logged in PROJECT.md Key Decisions table. Recent decisions affecting current work:
From Phase 2 (02-backing-track-seek-controls):
- jamClient must NOT be stored in Redux state - pass as prop instead (non-serializable)
- All jamClient methods in jam-ui return Promises - always use async/await pattern
- jamClient returns string values - always parseInt() before math operations
- End-of-track position requires SessionStopPlay() reset before new playback
From Phase 3 Plan 1 (03-backing-track-finalization):
- Volume control uses mixer system:
SessionSetTrackVolumeData(mixer.id, mixer.mode, trackVolumeObject) - Loop control uses direct API:
SessionSetBackingTrackFileLoop(backingTrack.path, shouldLoop) - UAT-003 resolved with state machine workaround (stores pending seek, applies on resume)
- Remove conditional fallback code - use correct methods directly
From Phase 3 Plan 2 (03-backing-track-finalization):
- Error types: file (red), network (red), playback (yellow), general (yellow)
- Loading states: isLoadingDuration (track fetch), isOperating (prevent rapid clicks)
- Disabled logic: buttons disabled during loading/operating/error
- Cleanup on unmount: stop playback to prevent stale state
- Network resilience: stop after 3 consecutive polling failures
From Phase 3 Plan 3 (03-backing-track-finalization):
- Performance: Visibility-aware polling (500ms visible, 2000ms hidden)
- Popup mode handling: Check
(isOpen || isPopup)since popup window = open - Backing track format: Handle both string (popup) and object (modal) with getBackingTrackPath helper
- Loop handling: Check isLooping flag before stopping at track end
- React optimizations: useCallback for handlers, conditional state updates
From Phase 4 Plan 1 (04-jamtrack-research-design):
- fqId format mandatory: All JamTrack jamClient calls require
{jamTrackId}-{sampleRate}format - 8-state sync machine: no_client, initial, packaging, downloading, keying, synchronized, quiet, errored
- JMEP must load before play:
JamTrackLoadJmep(fqId, jmepData)beforeJamTrackPlay(fqId) - Mixdown selection: pickMyPackage() filters by ogg/jkz/sample_rate matching client capabilities
- Callback pattern: jamClient download callbacks passed as string names, not function references
- loadJamTrack thunk bug identified: Uses jamTrack.id instead of correct fqId format
From Phase 4 Plan 2 (04-jamtrack-research-design):
- JKSessionJamTrackPlayer follows Backing Track patterns with extensions for download/sync and mixdown selection
- Redux state split: jamTrackState (playback), downloadState (sync machine), availableMixdowns (mixdown cache)
- 6 async thunks needed: loadJamTrack (enhanced), downloadJamTrack, checkJamTrackSync, loadJMEP, seekJamTrack, closeJamTrack
- Enhanced loadJamTrack fixes existing bug: uses fqId format instead of jamTrack.id
- 6-state download/sync machine: idle → checking → downloading → keying → synchronized → error
- Phase 5 preliminary scope: 9 plans, 2.5-3x complexity of Phase 3 Backing Track
- 5 critical decisions deferred to Phase 5: popup mode support, stem control integration, error recovery strategy, download cancellation, UAT deferral threshold
- HIGH risks identified: Download/sync state machine complexity, native client race conditions
- Component architecture: 10 sub-components (PlaybackControls, SeekSlider, TimeDisplay, MixdownPicker, DownloadProgress, ErrorDisplay, SyncStatus, VolumeControl, LoadingSpinner, EmptyState)
From Phase 5 Plan 1 (05-jamtrack-implementation):
- CRITICAL BUG FIXED: loadJamTrack now uses fqId format for JamTrackPlay call, unblocking all JamTrack functionality
- fqId construction moved outside conditional block to ensure consistent availability for all jamClient calls
- State organization: Separated concerns with jamTrackState (playback), downloadState (sync machine), mixdown state (availableMixdowns)
- jamTrackState structure: 7 fields tracking real-time playback (isPlaying, isPaused, currentPositionMs, durationMs, selectedMixdownId, playbackMode, lastUpdate)
- downloadState structure: 8 fields tracking 6-state machine (jamTrackId, mixdownId, fqId, state, progress, currentStep, totalSteps, error)
- Mixdown management: availableMixdowns array, activeMixdown object, mixdownCache map for efficient package lookups
- UI preferences: openJamTrack tracks currently open player, jamTrackUI stores user preferences (lastUsedMixdownId, volume)
- Redux foundation complete: 10 new reducers and 8 new selectors across 3 slices ready for Phase 5 Plans 2-5
From Phase 5 Plan 2 (05-jamtrack-implementation):
- Enhanced loadJamTrack checks sync state and triggers download if needed before playback
- downloadJamTrack uses global window callbacks for native client integration (callbacks passed as string names)
- seekJamTrack applies UAT-003 fix pattern (pending seek while paused, applied on resume)
- WebSocket handlers parse messages correctly with parseInt for numbers
- Thunks can dispatch other thunks using dispatch().unwrap() pattern
- Global callbacks named as strings for native client callback pattern (window.jamTrackDownloadProgress, etc.)
- Component cleanup on unmount with closeJamTrack thunk prevents memory leaks
- Component initialization pattern: buildFqId → check sync → autoPlay
- 6 async thunks complete: loadJamTrack (enhanced), downloadJamTrack, checkJamTrackSync, loadJMEP, seekJamTrack, closeJamTrack
- 3 WebSocket handlers active: MIXER_CHANGES (extended for mixdowns), JAM_TRACK_CHANGES (enhanced), MIXDOWN_CHANGES (new)
From Phase 5 Plan 3 (05-jamtrack-implementation):
- Reused Phase 3 Backing Track patterns for consistency (visibility-aware polling, UAT-003 fix, error handling)
- Playback controls with jamClient: JamTrackPlay/Pause/Resume/Stop/SeekMs
- Visibility-aware polling: 500ms visible, 2000ms hidden for position/duration updates
- Conditional state updates in polling (only dispatch if values changed)
- isOperating flag prevents rapid clicks during async operations
- formatTime utility for consistent MM:SS time display
- End-of-track handling: automatic stop and reset when position >= duration
- handleSeek with UAT-003 fix: pendingSeekRef for pause-seek-resume flow
From Phase 5 Plan 4 (05-jamtrack-implementation):
- Mixdown fetching during initialization (after sync check, non-fatal if fails)
- Default mixdown selection: prefer master, fallback to first available
- Mixdown change stops and restarts playback with new mixdown if playing/paused
- Visual indicators for mixdown types: 🎵 master, 🎨 custom, 🎸 stem
- Download UI visibility: show only for active states (checking/downloading/keying/error), hide for idle/synchronized
- Step indicator conditionally rendered only when totalSteps > 0
- handleMixdownChange, handleCancelDownload, handleRetryDownload with useCallback
- 6-state download machine UI: checking, downloading (with progress), keying, error (with retry)
From Phase 5 Plan 5 (05-jamtrack-implementation):
- 5 error types with color coding: FILE/NETWORK/DOWNLOAD (red), PLAYBACK/GENERAL (yellow)
- handleRetryError with type-specific retry logic (download/file → retry download, network → re-initialize)
- Network resilience: consecutiveFailuresRef tracks failures, stop polling after 3 consecutive failures
- Edge case validation: null jamClient shows "Native client not available", invalid jamTrack data caught
- Performance optimizations: useMemo for formattedPosition/formattedDuration/progressPercent
- All 11 handlers use useCallback for memoization
- React.memo at component export for render optimization
- Clean console output: removed all diagnostic console.log, kept only console.error
- UAT validated: 40+ test cases across 9 categories (initialization, download, playback, seek, mixdown, display, errors, performance, cleanup)
From Phase 6 Plan 1 (06-session-chat-research-design):
- Legacy chat architecture: React CoffeeScript + Reflux + jQuery hybrid with multi-channel support (global, session, lesson)
- Chat API: 2 REST endpoints (POST/GET /api/chat), WebSocket Protocol Buffer messages (CHAT_MESSAGE type)
- Database: chat_messages table with channel, purpose, attachments, indexed by channel/created_at/session_id
- Read/unread tracking: Only exists for lesson chat (teacher_unread_messages, student_unread_messages flags)
- Session/global chat has NO persistent tracking (badge resets on open)
- NEW functionality needed: client-side unread tracking with Redux + localStorage
- React patterns available: WindowPortal (modeless dialog), lobbyChatMessagesSlice (lobby chat reference), useSessionWebSocket (WebSocket integration)
- Gaps identified: No sessionChatSlice, no multi-channel state, no message deduplication, no unread tracking per channel
- TDD candidates: All data layer (Redux, API, WebSocket), component behavior (send, scroll, unread badge)
- Key decisions: WindowPortal for chat window, keyed message storage by channel, client-side unread tracking, file attachments deferred
- 3 documentation files created: CHAT_LEGACY.md (679 lines), CHAT_API.md (798 lines), CHAT_REACT_PATTERNS.md (1255 lines)
Deferred Issues
From Phase 3 Plan 3 UAT:
-
End-of-track restart requires double-click (Minor)
- First click doesn't start playback, second click required
- Root cause: Race condition between component/native client state
- Needs: Investigation of native client state machine
-
Loop functionality not working (Medium)
- Loop checkbox can be enabled but track doesn't restart at end
- Root cause: Native client doesn't respect SessionSetBackingTrackFileLoop
- Needs: Verify jamClient API or implement loop manually in React
-
Volume control not working in popup mode (Medium)
- Architectural limitation: backingTrackMixers empty in popup mode
- Root cause: Mixer system not available without Redux state
- Needs: Architecture refactor or document as modal-only feature
Roadmap Evolution
- v1.0 Media Players (Phases 1-5): Completed 2026-01-14 - Backing Track and JamTrack modernization
- v1.1 Music Session Chat (Phases 6-11): Created 2026-01-26 - Real-time chat with read/unread tracking
Blockers/Concerns
None yet.
Session Continuity
Last session: 2026-01-26 Stopped at: Phase 6 Plan 1 complete (Legacy Analysis) Resume file: None
Next: Phase 6 Plan 2 (React Architecture & Implementation Roadmap) - Design Redux state, component hierarchy, API client, WebSocket integration, and TDD test plan