jam-cloud/.planning/STATE.md

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) before JamTrackPlay(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:

  1. 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
  2. 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
  3. 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