docs(1): create phase plan

Phase 1: Backing Track Playback Monitoring
- 1 plan created
- 3 total tasks defined
- Ready for execution
This commit is contained in:
Nuwan 2026-01-13 20:19:19 +05:30
parent 19115cf121
commit cee0bf05f5
1 changed files with 215 additions and 0 deletions

View File

@ -0,0 +1,215 @@
---
phase: 01-backing-track-playback-monitoring
type: execute
---
<objective>
Implement real-time playback monitoring for the backing track player by adding 500ms polling of the native client and displaying current position and duration in M:SS format.
Purpose: Complete the player's time display functionality, matching the legacy web implementation's polling pattern while using modern React hooks. This establishes the monitoring foundation that Phase 2 (seek controls) will build upon.
Output: Backing track player with live-updating time displays showing current position and total duration while track plays.
</objective>
<execution_context>
@./.claude/get-shit-done/workflows/execute-phase.md
@./.claude/get-shit-down/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/01-backing-track-playback-monitoring/1-CONTEXT.md
@jam-ui/src/components/client/JKSessionBackingTrackPlayer.js
**Codebase conventions:**
- React functional components with hooks (React 16.13.1)
- camelCase for functions and variables
- Single quotes for strings (Prettier enforced)
- 2-space indentation
**Legacy implementation reference:**
- web/app/assets/javascripts/playbackControls.js: 500ms polling via setTimeout (lines 301-337)
- web/app/assets/javascripts/utils.js: prettyPrintSeconds() time formatting (lines 885-906)
- jamClient methods: SessionCurrrentPlayPosMs(), SessionGetTracksPlayDurationMs(), isSessionTrackPlaying()
**Current state:**
- JKSessionBackingTrackPlayer.js has currentTime and duration state hardcoded to "0:00" (lines 20-21)
- Play/pause/stop controls work via jamClient (lines 34-58)
- UI structure already in place with time displays (lines 207, 217 for popup; lines 302, 312 for modal)
**Vision from CONTEXT.md:**
- Functional parity with legacy web (500ms polling, accurate time display)
- UI layout: Current time (M:SS) on left of slider, duration (M:SS) on right
- No padding on single-digit minutes (1:02 not 01:02)
</context>
<tasks>
<task type="auto">
<name>Task 1: Add formatTime utility function</name>
<files>jam-ui/src/components/client/JKSessionBackingTrackPlayer.js</files>
<action>Add a formatTime utility function to convert milliseconds to M:SS format (matching legacy web prettyPrintSeconds behavior). Place it inside the component before the useEffect hooks.
Implementation:
- Accept milliseconds as parameter
- Convert to seconds (Math.floor(ms / 1000))
- Calculate minutes: Math.floor(seconds / 60)
- Calculate remaining seconds: seconds % 60
- Pad seconds with "0" if less than 10 (e.g., "1:05" not "1:5")
- NO padding on minutes (single digit is fine: "1:02" not "01:02")
- Return formatted string: `${minutes}:${seconds.toString().padStart(2, '0')}`
Example outputs:
- formatTime(62000) → "1:02"
- formatTime(313000) → "5:13"
- formatTime(3605000) → "60:05"
Do NOT implement hours formatting (tracks are < 60 minutes).</action>
<verify>Add console.log tests:
- formatTime(62000) should output "1:02"
- formatTime(313000) should output "5:13"
- formatTime(0) should output "0:00"</verify>
<done>formatTime function exists, converts milliseconds to M:SS format with proper padding (seconds only)</done>
</task>
<task type="auto">
<name>Task 2: Add playback monitoring with 500ms polling</name>
<files>jam-ui/src/components/client/JKSessionBackingTrackPlayer.js</files>
<action>Add useEffect hook for playback monitoring with 500ms polling interval matching legacy web implementation (web/app/assets/javascripts/playbackControls.js lines 301-337).
Implementation:
- Add useEffect that runs when isPlaying changes
- When isPlaying is true, start polling:
- Use setInterval (not setTimeout recursion) with 500ms interval
- In interval callback:
1. Check if jamClient exists (guard against undefined)
2. Call jamClient.SessionCurrrentPlayPosMs() → current position in ms
3. Call jamClient.SessionGetTracksPlayDurationMs() → total duration in ms
4. Call jamClient.isSessionTrackPlaying() → boolean for playing state
5. Update setCurrentTime(formatTime(positionMs))
6. Update setDuration(formatTime(durationMs))
7. Sync setIsPlaying(isPlaying) if state changed
- When isPlaying is false, clear the interval
- Return cleanup function that clears interval
Error handling:
- Wrap jamClient calls in try/catch
- On error, log to console but don't crash
- Continue polling even if one poll fails
Dependencies: [isPlaying, jamClient, backingTrack]
IMPORTANT: Use setInterval (not setTimeout recursion) for consistent 500ms timing. Store intervalId in a variable to clear on cleanup.</action>
<verify>Check console logs show:
1. When play clicked: Polling starts, position/duration update every 500ms
2. When pause clicked: Polling stops, interval cleared
3. When stop clicked: Polling stops, position resets to 0:00
4. No errors logged during playback</verify>
<done>Playback monitoring polls jamClient every 500ms when playing, updates currentTime and duration state with formatted values, cleans up interval on pause/stop</done>
</task>
<task type="auto">
<name>Task 3: Initialize duration on track load</name>
<files>jam-ui/src/components/client/JKSessionBackingTrackPlayer.js</files>
<action>Modify the existing useEffect (lines 25-32) that runs when track opens to fetch and set initial duration immediately, not waiting for playback to start.
Current code:
```javascript
useEffect(() => {
if (isOpen && backingTrack) {
setIsPlaying(false);
setCurrentTime('0:00');
setDuration('0:00');
}
}, [isOpen, backingTrack]);
```
Change to:
```javascript
useEffect(() => {
if (isOpen && backingTrack && jamClient) {
setIsPlaying(false);
setCurrentTime('0:00');
// Fetch and set duration immediately when track loads
try {
const durationMs = jamClient.SessionGetTracksPlayDurationMs();
setDuration(formatTime(durationMs));
} catch (error) {
console.error('Error fetching track duration:', error);
setDuration('0:00');
}
}
}, [isOpen, backingTrack, jamClient]);
```
This ensures the duration appears immediately when the player opens, matching the UI in the reference screenshot where "5:13" is visible before playback starts.</action>
<verify>Open backing track player without playing:
- Duration displays actual track length (e.g., "5:13") immediately
- Current time shows "0:00"
- No errors in console</verify>
<done>Duration fetched and displayed when track loads (before play starts), matching legacy web behavior</done>
</task>
</tasks>
<verification>
Before declaring phase complete:
- [ ] Open backing track player, verify duration shows immediately (e.g., "5:13")
- [ ] Click play, verify current time updates every ~500ms (1:00 → 1:01 → 1:02)
- [ ] Verify time format matches reference: M:SS (no leading zero on minutes)
- [ ] Click pause, verify polling stops (time freezes)
- [ ] Click play again, verify polling resumes from paused position
- [ ] Click stop, verify time resets to "0:00"
- [ ] Check browser console for errors (should be none)
- [ ] Verify both modal and popup versions work identically
</verification>
<success_criteria>
- formatTime utility converts milliseconds to M:SS format correctly
- Playback monitoring polls jamClient every 500ms when playing
- Current time display updates smoothly during playback
- Duration displays immediately when track loads
- Polling stops cleanly when paused/stopped
- No console errors during playback
- Functional parity with legacy web monitoring behavior
</success_criteria>
<output>
After completion, create `.planning/phases/01-backing-track-playback-monitoring/01-01-SUMMARY.md`:
# Phase 1 Plan 1: Backing Track Playback Monitoring Summary
**Real-time backing track playback monitoring with 500ms polling and M:SS time display**
## Accomplishments
- Added formatTime utility for milliseconds → M:SS conversion
- Implemented 500ms polling with setInterval matching legacy web pattern
- Wired up currentTime and duration displays to live jamClient data
- Duration fetches immediately on track load (before play)
## Files Created/Modified
- `jam-ui/src/components/client/JKSessionBackingTrackPlayer.js` - Added formatTime, polling useEffect, duration initialization
## Decisions Made
- Used setInterval (not setTimeout recursion) for consistent 500ms timing
- Polling runs only when isPlaying=true to avoid unnecessary jamClient calls
- Error handling: log errors but continue polling (don't crash on transient failures)
## Issues Encountered
(None expected - straightforward polling implementation)
## Next Phase Readiness
Phase 2 (Backing Track Seek Controls) can now proceed. The monitoring useEffect will need slight modification to support seeking:
- When user drags slider, pause polling briefly
- After seek, resume polling from new position
- This is handled in Phase 2, not here
</output>