Files
pmomusic/Plan_d_implementation_webui_control_point.md

448 lines
12 KiB
Markdown
Raw Normal View History

# PMOControl WebUI - Design Recommendations & Implementation Plan
## Executive Summary
Based on my analysis of the existing codebase, I'm providing comprehensive recommendations for implementing a Vue.js WebUI for PMOControl. The system already has:
- A complete REST API with OpenAPI documentation (`/api/control/*`)
- SSE endpoints for real-time updates (`/api/control/events/*`)
- Vue 3 + TypeScript + Vite setup
- Existing components (GenericMusicPlayer, UpnpExplorer, Cache Managers, LogView)
---
## Design Decisions & Recommendations
### 1. State Management: **Use Pinia**
**Recommendation: Pinia (Vue 3's official state management)**
**Rationale:**
- **Centralized real-time state**: Essential for managing SSE updates from multiple sources (renderers, media servers)
- **Multi-client synchronization**: Single source of truth for renderer states, volumes, playback positions
- **TypeScript native**: Better type inference than Vuex
- **DevTools integration**: Built-in debugging for SSE event flows
- **Composition API friendly**: Matches existing Vue 3 patterns in codebase
- **Performance**: Lightweight (~1KB), modular stores
- **Official Vue 3 recommendation**: Future-proof choice
**Store Architecture:**
```typescript
// stores/renderers.ts - Renderer state (SSE updates)
// stores/mediaServers.ts - Media server state (SSE updates)
// stores/playback.ts - Current playback session
// stores/ui.ts - UI state (selected renderer, view preferences)
```
**Benefits for your use case:**
- Handle 20+ concurrent clients with shared state
- Real-time SSE event synchronization across all views
- Easy to scale with multi-renderer, multi-server, multi-session architecture
---
### 2. UI Component Library: **Headless UI + Custom Components**
**Recommendation: Hybrid approach - Headless UI components + custom styling**
**Component Library: Shadcn-vue (Headless UI primitives)**
**Rationale:**
- **Lightweight & performant**: Only import what you need
- **Full style control**: Match "carte uniforme, responsive, colorée selon statut" spec exactly
- **TypeScript-first**: Perfect type safety
- **Accessibility built-in**: ARIA compliance out of the box
- **No theme lock-in**: Complete CSS freedom
- **Composable primitives**: Card, Dialog, Dropdown, Slider components
**Why NOT a full framework (Vuetify, Element Plus)?**
- Heavy bundle size (100-500KB vs ~10KB for headless)
- Theme customization overhead
- Your spec requires custom status-based coloring
- Performance critical with 20 concurrent clients
**Alternative if you prefer pre-styled:** PrimeVue
- Good performance
- Customizable themes
- Strong TypeScript support
- But: 150KB+ bundle size
**Custom Components to Build:**
- `RendererCard` - Status-colored cards for each renderer
- `TransportControls` - Play/Pause/Stop/Next buttons
- `VolumeControl` - Slider with mute toggle
- `QueueViewer` - Playlist display with drag-drop
- `MediaServerBrowser` - Container navigation
---
### 3. Existing Components: **Reorganize into Debug Section**
**Recommendation: Keep existing components, create new PMOControl home**
**Structure:**
```
/app (root) → PMOControl Dashboard (NEW)
/app/debug → Dropdown menu
├─ /logs → LogView
├─ /upnp → UpnpExplorer
├─ /covers-cache → CoverCacheManager
├─ /audio-cache → AudioCacheManager
├─ /api-dashboard → APIDashboard
└─ /radio-paradise → RadioParadiseExplorer
```
**Rationale:**
- Existing components are valuable for development/debugging
- Don't break existing functionality
- PMOControl becomes primary interface as specified
- Debug tools remain accessible but not prominent
- Matches current App.vue dropdown pattern
**Home Screen (/) - PMOControl Dashboard:**
- Grid of renderer cards (status-colored)
- Active playback session viewer
- Quick controls (play/pause/volume)
- Media server browser panel
---
### 4. Responsive Design: **Mobile-first with 3 breakpoints**
**Recommendation: Follow existing 768px pattern + add tablet/desktop**
**Breakpoints:**
```css
/* Mobile: < 768px (existing pattern) */
- Single column layout
- Stacked renderer cards
- Bottom-fixed playback controls
- Collapsible media browser
/* Tablet: 768px - 1024px */
- Two column layout
- Grid of renderer cards (2 columns)
- Side panel for media browser
- Floating playback controls
/* Desktop: > 1024px */
- Three column layout
- Renderer cards grid (3-4 columns)
- Persistent media browser sidebar
- Always-visible playback controls
```
**Target Devices:**
- **Primary**: Desktop browsers (control station)
- **Secondary**: Tablets (remote control)
- **Tertiary**: Mobile phones (quick controls)
**Performance considerations:**
- Virtualized lists for 20+ renderers (use vue-virtual-scroller)
- Lazy load album art
- Throttle SSE position updates (max 1/sec per renderer)
---
### 5. Icons: **Lucide Icons (SVG library)**
**Recommendation: Lucide Icons (NOT emoji)**
**Rationale:**
- **Professional appearance**: Emojis inconsistent across platforms
- **Customizable**: Size, color, stroke width
- **Lightweight**: Tree-shakeable SVG imports (~1KB per icon)
- **Status coloring**: Icons can match card status colors
- **Accessibility**: Proper ARIA labels
- **Vue components**: `lucide-vue-next` package
**Icon mapping:**
```typescript
Play → PlayCircle
Pause → PauseCircle
Stop → StopCircle
Next → SkipForward
Volume → Volume2 / VolumeX (muted)
Renderer → Speaker / MonitorSpeaker
Server → Server / Database
Queue → ListMusic
```
**Alternative if you prefer minimal bundle:** Heroicons
- Smaller set (fewer icons)
- Tailwind CSS integration
- But: less comprehensive for music player needs
**Why NOT emoji:**
- Platform inconsistencies (iOS ≠ Android ≠ Windows)
- No color control
- Accessibility issues
- Unprofessional for production UI
---
## Technical Architecture
### Real-time SSE Integration
**SSE Event Handling:**
```typescript
// services/controlPointSSE.ts
class ControlPointSSE {
private eventSource: EventSource
private renderersStore: ReturnType<typeof useRenderersStore>
connect() {
this.eventSource = new EventSource('/api/control/events')
this.eventSource.addEventListener('control', (e) => {
const event = JSON.parse(e.data)
if (event.category === 'renderer') {
this.handleRendererEvent(event)
} else if (event.category === 'media_server') {
this.handleServerEvent(event)
}
})
}
handleRendererEvent(event: RendererEventPayload) {
switch (event.type) {
case 'state_changed':
this.renderersStore.updateState(event.renderer_id, event.state)
break
case 'volume_changed':
this.renderersStore.updateVolume(event.renderer_id, event.volume)
break
// ... handle all event types
}
}
}
```
**Store Integration:**
```typescript
// stores/renderers.ts
export const useRenderersStore = defineStore('renderers', () => {
const renderers = ref<Map<string, RendererState>>(new Map())
// SSE updates
function updateState(id: string, state: string) {
const renderer = renderers.value.get(id)
if (renderer) {
renderer.transport_state = state
}
}
// REST API calls
async function play(id: string) {
await fetch(`/api/control/renderers/${id}/play`, { method: 'POST' })
// SSE will update state automatically
}
return { renderers, updateState, play }
})
```
### Performance Optimizations
**For 20+ concurrent clients:**
1. **Throttle position updates**:
```typescript
const throttledPositionUpdate = throttle((id, pos) => {
store.updatePosition(id, pos)
}, 1000) // Max 1 update/second
```
2. **Virtual scrolling** for renderer lists:
```bash
npm install vue-virtual-scroller
```
3. **Lazy load album art**:
```vue
<img :src="albumArt" loading="lazy" />
```
4. **Debounce volume sliders**:
```typescript
const debouncedVolumeChange = debounce((id, vol) => {
api.setVolume(id, vol)
}, 300)
```
5. **Memoize computed properties**:
```typescript
const activeRenderers = computed(() =>
renderers.value.filter(r => r.online)
)
```
---
## Implementation Roadmap
### Phase 1: Core Infrastructure (Week 1)
1. Install Pinia + configure stores
2. Install Lucide Icons
3. Create SSE service layer
4. Setup store structure (renderers, servers, playback, ui)
5. Connect SSE events to stores
### Phase 2: UI Components (Week 2)
5. Build RendererCard component (status-colored)
6. Build TransportControls component
7. Build VolumeControl component
8. Build QueueViewer component
9. Create responsive grid layouts
### Phase 3: Dashboard Assembly (Week 3)
10. Create PMOControl home view
11. Integrate all components
12. Add media server browser panel
13. Implement responsive breakpoints
14. Add loading states & error handling
### Phase 4: Polish & Testing (Week 4)
15. Test with 20+ concurrent clients
16. Performance profiling & optimization
17. Accessibility audit (ARIA, keyboard nav)
18. Cross-browser testing
19. Mobile/tablet testing
20. Documentation
---
## Dependencies to Install
```json
{
"dependencies": {
"pinia": "^2.2.8",
"lucide-vue-next": "^0.470.0",
"vue-virtual-scroller": "^2.0.0-beta.8"
},
"devDependencies": {
// Already installed: vue, vue-router, typescript, vite
}
}
```
**Total bundle size estimate:** +15KB gzipped (Pinia + Lucide + Virtual Scroller)
---
## Status-based Coloring Scheme
Based on "carte uniforme, responsive, colorée selon statut" spec:
```css
/* Renderer Card Status Colors */
.renderer-card.playing {
border-color: #22c55e; /* green */
background: linear-gradient(135deg, #22c55e10, transparent);
}
.renderer-card.paused {
border-color: #f59e0b; /* amber */
background: linear-gradient(135deg, #f59e0b10, transparent);
}
.renderer-card.stopped {
border-color: #6b7280; /* gray */
background: linear-gradient(135deg, #6b728010, transparent);
}
.renderer-card.offline {
border-color: #ef4444; /* red */
background: linear-gradient(135deg, #ef444410, transparent);
opacity: 0.6;
}
.renderer-card.transitioning {
border-color: #3b82f6; /* blue */
background: linear-gradient(135deg, #3b82f610, transparent);
animation: pulse 2s infinite;
}
```
---
## Answers to Your Specific Questions
### 1. State Management?
**Answer: Pinia** - Vue 3 official, perfect for SSE real-time updates, TypeScript native, lightweight
### 2. UI Component Library?
**Answer: Headless UI (Shadcn-vue) + Custom Components** - Full control over status-based styling, lightweight, no theme lock-in
### 3. Keep existing components?
**Answer: Yes, reorganize into Debug section** - Keep valuable dev tools, make PMOControl the new home screen
### 4. Responsive breakpoints?
**Answer: Mobile-first with 3 breakpoints** - <768px (mobile), 768-1024px (tablet), >1024px (desktop)
### 5. Icons?
**Answer: Lucide Icons (SVG library)** - Professional, customizable, status-colored, NOT emoji
---
## Risk Mitigation
**Potential challenges:**
1. **SSE connection management across tabs**
- Solution: Use BroadcastChannel API for cross-tab sync
- Fallback: LocalStorage events
2. **20+ renderers performance**
- Solution: Virtual scrolling + throttled updates
- Monitor: Chrome DevTools Performance profiler
3. **Network reliability (SSE reconnection)**
- Solution: Exponential backoff reconnection
- UI indicator for connection status
4. **Album art loading (CORS, 404s)**
- Solution: Proxy through backend
- Fallback: Default placeholder image
5. **Browser compatibility (SSE support)**
- Chrome/Edge: Native support ✅
- Firefox: Native support ✅
- Safari: Native support ✅
- IE11: Use EventSource polyfill
---
## Success Metrics
**Performance targets:**
- Initial load: <2s (FCP)
- SSE event latency: <100ms
- UI interaction: <16ms (60fps)
- Memory usage: <50MB with 20 renderers
- Bundle size: <250KB gzipped
**Functionality checklist:**
- [ ] Display all discovered renderers in real-time
- [ ] Show accurate playback state (play/pause/stop)
- [ ] Volume control works across all renderer types
- [ ] Queue display syncs with server
- [ ] Media server browsing functional
- [ ] Playlist attachment working
- [ ] Responsive on mobile/tablet/desktop
- [ ] Accessible (WCAG AA compliance)
- [ ] 20+ concurrent clients supported
---
## Next Steps
1. **Review & approve** this plan with stakeholders
2. **Clarify any ambiguities** in requirements
3. **Set up development environment** (install dependencies)
4. **Begin Phase 1** (Core Infrastructure)
Would you like me to proceed with implementation, or do you have questions about any of these recommendations?