singsalot/docs/platforms/web/PRD-web.md

25 KiB

Web Platform Implementation Guide

Platform: Web (React + Ionic + TypeScript)
Core Business Logic: See ../../PRD.md for platform-agnostic requirements

This document contains web-specific implementation details for the Karaoke App. All business logic, data models, and core requirements are defined in the main PRD.


Quick Reference

Section Purpose
UI/UX Behavior Web-specific UI patterns and interactions
Component Architecture React/Ionic component structure
State Management Redux Toolkit implementation
Development Setup Web project configuration
Design Assets Web-specific visual references
Toolset Choices Web technology rationale

UI/UX Behavior

Web-Specific Requirements:

Responsive Design:

  • Mobile-first approach with touch-friendly interface
  • Progressive Web App (PWA) capabilities for app-like experience
  • Responsive breakpoints for tablet and desktop views
  • Touch gestures for queue reordering and navigation

Ionic React Components:

  • IonApp as root container with proper theming
  • IonRouterOutlet for navigation between pages
  • IonList and IonItem for song and queue displays
  • IonButton with proper touch targets (44px minimum)
  • IonSearchbar for song search with debounced input
  • IonModal for singer selection and settings
  • IonToast for user feedback and notifications

Navigation Patterns:

  • Tab-based navigation for main sections (Queue, Search, History, etc.)
  • Stack navigation for detail views (song info, artist pages)
  • Modal overlays for quick actions (singer selection, settings)
  • Deep linking support for direct page access

Real-time Updates:

  • Live queue updates with visual indicators for changes
  • Playback state synchronization across all connected devices
  • User presence indicators showing who's currently active
  • Optimistic UI updates with rollback on errors

Codebase Organization & File Structure

Web Project Structure:

src/
├── components/          # Reusable UI components
│   ├── Auth/           # Authentication components
│   ├── common/         # Shared components (SongItem, ActionButton, etc.)
│   ├── Layout/         # Layout and navigation components
│   └── Navigation/     # Navigation components
├── features/           # Feature-specific components
│   ├── Artists/        # Artist browsing feature
│   ├── Favorites/      # Favorites management
│   ├── History/        # Play history
│   ├── NewSongs/       # New songs feature
│   ├── Queue/          # Queue management
│   ├── Search/         # Song search
│   ├── Settings/       # Settings and admin features
│   ├── Singers/        # Singer management
│   ├── SongLists/      # Song lists feature
│   └── TopPlayed/      # Top played songs
├── firebase/           # Firebase configuration and services
│   ├── config.ts       # Firebase configuration
│   ├── services.ts     # Firebase service layer
│   └── useFirebase.ts  # Firebase hooks
├── hooks/              # Custom React hooks
│   ├── useQueue.ts     # Queue management hooks
│   ├── useSearch.ts    # Search functionality hooks
│   ├── useFavorites.ts # Favorites management hooks
│   └── ...            # Other feature hooks
├── redux/              # State management
│   ├── store.ts        # Redux store configuration
│   ├── slices/         # Redux slices
│   ├── selectors.ts    # Memoized selectors
│   └── hooks.ts        # Redux hooks
├── types/              # TypeScript type definitions
└── utils/              # Utility functions

File Organization Rules:

Folder Purpose Key Files Import Pattern
/components Reusable UI components SongItem.tsx, ActionButton.tsx import { SongItem } from '../components/common'
/features Feature-specific pages Queue.tsx, Search.tsx import { Queue } from '../features/Queue'
/firebase Firebase integration services.ts, config.ts import { queueService } from '../firebase/services'
/hooks Custom business logic useQueue.ts, useSearch.ts import { useQueue } from '../hooks/useQueue'
/redux State management controllerSlice.ts, authSlice.ts, selectors.ts import { useAppDispatch, selectQueue } from '../redux'
/types TypeScript definitions index.ts (extends docs/types.ts) import type { Song, QueueItem } from '../types'

Import Patterns:

1. Redux Imports:

// Always import from the main redux index
import { useAppDispatch, useAppSelector } from '../redux';
import { selectQueue, selectSongs } from '../redux';
import { setController, updateQueue } from '../redux';

// ❌ Don't import directly from slice files
// ❌ import { selectQueue } from '../redux/controllerSlice';
// ✅ Always use the main redux index
// ✅ import { selectQueue } from '../redux';

2. Firebase Service Imports:

// Import services from the main services file
import { queueService, searchService } from '../firebase/services';

// ❌ Don't import directly from individual service files
// ❌ import { addToQueue } from '../firebase/queueService';
// ✅ Always use the main services file
// ✅ import { queueService } from '../firebase/services';

3. Type Imports:

// Always use type imports for TypeScript interfaces
import type { Song, QueueItem, Singer } from '../types';

// ❌ Don't import types from individual files
// ❌ import { Song } from '../types/Song';
// ✅ Always use the main types index
// ✅ import type { Song } from '../types';

4. Hook Imports:

// Import hooks from their specific files
import { useQueue } from '../hooks/useQueue';
import { useSearch } from '../hooks/useSearch';
import { useFavorites } from '../hooks/useFavorites';

// ❌ Don't import from a general hooks index
// ❌ import { useQueue } from '../hooks';
// ✅ Import from specific hook files
// ✅ import { useQueue } from '../hooks/useQueue';

5. Component Imports:

// Import components from their specific folders
import { SongItem } from '../components/common/SongItem';
import { ActionButton } from '../components/common/ActionButton';
import { Layout } from '../components/Layout/Layout';

// ❌ Don't import from general component indices
// ❌ import { SongItem } from '../components';
// ✅ Import from specific component files
// ✅ import { SongItem } from '../components/common/SongItem';

Architecture Flow:

UI Components → Custom Hooks → Redux State → Firebase Services → Firebase Database

Separation of Concerns:

  • Components: Only handle UI presentation and user interactions
  • Hooks: Contain business logic and data management
  • Redux: Manage global application state
  • Services: Handle Firebase operations and data persistence
  • Types: Define data structures and interfaces

Component Architecture

React Component Structure:

Page Components:

// src/features/Queue/Queue.tsx
interface QueueProps {
  // Props interface
}

const Queue: React.FC<QueueProps> = () => {
  // Component implementation
}

Common Components:

// src/components/common/SongItem.tsx
interface SongItemProps {
  song: Song;
  onAddToQueue: (song: Song) => void;
  onAddToFavorites: (song: Song) => void;
  showAddButton?: boolean;
  showFavoriteButton?: boolean;
}

Layout Components:

// src/components/Layout/Layout.tsx
interface LayoutProps {
  children: React.ReactNode;
  title?: string;
  showBackButton?: boolean;
}

Ionic Integration:

  • IonPage wrapper for all page components
  • IonHeader with dynamic titles and action buttons
  • IonContent with proper scrolling behavior
  • IonFooter for player controls and queue management
  • IonLoading for async operations and data fetching

State Management

Redux Architecture Pattern:

The web implementation uses Redux Toolkit for predictable state management with excellent TypeScript support.

Store Structure:

// src/redux/store.ts
export const store = configureStore({
  reducer: {
    auth: authSlice,
    player: playerSlice,
    queue: queueSlice,
    controller: controllerSlice,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: ['persist/PERSIST'],
      },
    }),
});

Slice Patterns:

// src/redux/controllerSlice.ts
const controllerSlice = createSlice({
  name: 'controller',
  initialState,
  reducers: {
    setController: (state, action) => {
      state.data = action.payload;
    },
    updateQueue: (state, action) => {
      state.data.player.queue = action.payload;
    },
  },
});

Selectors:

// src/redux/selectors.ts
export const selectQueue = (state: RootState) => state.controller.data?.player?.queue || {};
export const selectQueueLength = createSelector(
  [selectQueue],
  (queue) => Object.keys(queue).length
);

Redux Toolkit Implementation:

Store Structure:

// src/redux/store.ts
export const store = configureStore({
  reducer: {
    auth: authSlice,
    player: playerSlice,
    queue: queueSlice,
    controller: controllerSlice,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: ['persist/PERSIST'],
      },
    }),
});

Slice Patterns:

// src/redux/queueSlice.ts
const queueSlice = createSlice({
  name: 'queue',
  initialState,
  reducers: {
    addToQueue: (state, action) => {
      // Implementation
    },
    removeFromQueue: (state, action) => {
      // Implementation
    },
  },
});

Selectors:

// src/redux/selectors.ts
export const selectQueue = (state: RootState) => state.queue.items;
export const selectQueueLength = createSelector(
  [selectQueue],
  (queue) => queue.length
);

Development Setup

Project Configuration:

Package.json Dependencies:

{
  "dependencies": {
    "@ionic/react": "^7.0.0",
    "@reduxjs/toolkit": "^1.9.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-redux": "^8.0.0",
    "firebase": "^9.0.0"
  },
  "devDependencies": {
    "@types/react": "^18.0.0",
    "@types/react-dom": "^18.0.0",
    "typescript": "^4.9.0",
    "vite": "^4.0.0"
  }
}

Vite Configuration:

// vite.config.ts
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
  build: {
    outDir: 'dist',
    sourcemap: true,
  },
});

TypeScript Configuration:

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  }
}

Environment Setup:

# .env.local
VITE_FIREBASE_API_KEY=your_api_key
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
VITE_FIREBASE_APP_ID=your_app_id
VITE_FIREBASE_DATABASE_URL=https://your_project-default-rtdb.firebaseio.com

Design Assets

Web-Specific Mockups:

Located in design/ with 30+ mockups covering all features:

Core Navigation & Layout:

  • 00-web-layout.JPG - Overall web layout structure
  • 01-Login.png - Login screen design
  • 02-menu.jpeg, 02a-menu.jpeg, 02b-menu.png, 02c-menu.jpeg - Navigation menu variations

Queue Management:

  • 02-queue.png - Main queue view
  • 02-queue-delete.png - Queue with delete functionality
  • 02-queue-drag.png - Queue reordering with drag and drop
  • 02-queue-sorting.png - Queue sorting interface

Search & Discovery:

  • 04-search.png - Main search interface
  • 04-search typing .png - Search with typing interaction
  • 04-search-song info.png - Search results with song information

User Management:

  • 05-singers.png - Singer list view
  • 05-singers add.png - Singer management interface

Content Browsing:

  • 06-artists .png - Artist browse interface
  • 06-artists (not admin).png - Non-admin artist view
  • 06-artists search.png - Artist search functionality
  • 06-artists songs.png - Artist songs list

User Features:

  • 07-favorites.png - Favorites management
  • 08-history.png - Play history view
  • 09-songs list.png - Main song lists view
  • 09-song lists - songs.png - Song lists with song details
  • 09- song lists songs expand.png - Song lists with expandable sections

Admin Features:

  • 10-Settings.png - Settings interface
  • 11-top 100.png - Top played songs
  • 12-favorites .png - Favorites view
  • 12-favorite lists.png - Favorite lists management

Menu States:

  • 03-menu.png - General menu layout
  • 03-menu current page and non-admin.png - Navigation with current page indicators
  • 03-menu playing (admin).png - Admin view during playback

Design System:

  • Ionic Design System for consistent UI components
  • Custom CSS variables for theming and branding
  • Responsive grid system for layout consistency
  • Touch-friendly spacing and sizing guidelines

Toolset Choices

Current Web Implementation Toolset:

Core Framework: React 18 + TypeScript

  • Why: Chosen for its component-based architecture, strong ecosystem, and excellent TypeScript support
  • Migration Note: Can be replaced with any other component-based framework (e.g., Vue, Svelte)

State Management: Redux Toolkit

  • Why: Provides predictable state management with excellent TypeScript support and dev tools
  • Migration Note: Can be replaced with Context API, Zustand, or other state management solutions

UI Framework: Ionic React

  • Why: Provides mobile-first UI components with excellent touch support and PWA capabilities
  • Migration Note: Can be replaced with Material-UI, Chakra UI, or custom components

Build Tool: Vite

  • Why: Fast development server and optimized builds with excellent TypeScript support
  • Migration Note: Can be replaced with Webpack, Parcel, or other build tools

Backend: Firebase Realtime Database

  • Why: Real-time synchronization, simple setup, and excellent React integration
  • Migration Note: Can be replaced with any real-time database (Supabase, AWS AppSync, etc.)

Development Tools:

  • TypeScript: Type safety and better developer experience
  • ESLint: Code quality and consistency
  • Prettier: Code formatting
  • React DevTools: Component debugging
  • Redux DevTools: State management debugging

Web-Specific Implementation Details

Authentication & Session Management:

  • Admin Access: Triggered by URL parameter (?admin=true), removed after login
  • Session Persistence: Lost on browser reload (no persistent storage)
  • Admin Mode: Pre-fills singer name as "Admin" for convenience
  • URL Handling: Admin parameter automatically removed from URL after authentication

Search Implementation:

  • Pagination: Uses Ionic InfiniteScrollList component for efficient loading
  • Debouncing: Search input debounced to prevent excessive API calls
  • Real-time Results: Instant search results as user types
  • Context Actions: Add to queue, favorite, and other actions available per song

Queue Management:

  • UI Controls: Reordering and deletion exposed via UI controls only visible to admins
  • Drag & Drop: Uses Ionic drag handles and swipe actions for reordering
  • Visual Feedback: Clear indicators for admin-only actions
  • State Synchronization: Real-time updates across all connected clients

Favorites Implementation:

  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Real-time Sync: Shared favorites list synchronized across all clients
  • Duplicate Prevention: Prevents duplicates using song path field
  • User Actions: Anyone can add/remove favorites

New Songs Implementation:

  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Real-time Updates: Shows recently added songs from newSongs node
  • Automatic Loading: Progressive loading as user scrolls

Artists Implementation:

  • Modal Views: Uses Ionic modals for artist song lists
  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Search Integration: Artist search functionality included
  • Song Counts: Displays song count per artist

Song Lists Implementation:

  • Modal Interface: Uses Ionic modals for viewing list contents
  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Expandable Views: Available versions shown with expandable sections
  • Availability Status: Shows which songs are available in catalog

History Implementation:

  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Automatic Tracking: Songs automatically added when played
  • Timestamp Display: Shows when each song was last played
  • Append-only: History is append-only, shared across all clients

Top Played Implementation:

  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Play Count Display: Shows play count for each song
  • Real-time Updates: Popular songs generated by backend
  • Backend Integration: Based on history data

Singer Management:

  • Admin-only UI: Singer management available only to admins via settings page
  • Unique Names: Singer names must be unique and non-empty
  • Auto-addition: Singers automatically added when they join
  • Last Join Tracking: Tracks when each singer last joined

Playback Control:

  • Admin-only Controls: Player controls only rendered for admins
  • State-based UI: Play/pause/stop buttons shown/hidden based on current state
  • Queue Validation: Play button disabled when queue is empty
  • Real-time Sync: Playback state synchronized across all clients

Error Handling & Sync:

  • Toast Notifications: Uses web-specific toast notifications for user feedback
  • Error Boundaries: React error boundaries for component-level error handling
  • Retry Patterns: Automatic retry for failed Firebase operations
  • Connection Monitoring: Real-time connection status tracking

Disabled Songs:

  • Modal Management: Disabled songs managed via modal dialog
  • Search & Filter: Search and filter capabilities in management interface
  • Hash Storage: Disabled songs stored using hash of song path
  • Admin-only Access: Only admins can disable or enable songs

Settings Implementation:

  • Debug Logging: Web-only feature, toggled via settings page
  • Admin-only Access: Only admins can change player settings
  • Real-time Updates: Settings changes synchronized across all clients
  • UI Controls: Settings interface with toggle switches and controls

Navigation Implementation:

  • Admin-based Navigation: Navigation adapts based on admin status
  • Hidden Pages: Settings page only visible to admins
  • Role-based UI: Different navigation options for different user roles
  • Dynamic Menus: Menu items shown/hidden based on permissions

UI/UX Implementation:

  • Ionic React: Uses Ionic React and Tailwind CSS for UI
  • Component Library: Infinite scroll, swipe actions, modals, and toasts using Ionic components
  • Responsive Design: Mobile-first approach with touch-friendly interface
  • Theme Support: Light/dark mode support with consistent styling

Implementation Notes

Critical Web-Specific Patterns:

Firebase Integration:

// src/firebase/services.ts
export const queueService = {
  addToQueue: async (song: Song, singerId: string) => {
    const newKey = await getNextKey('queue');
    await set(ref(database, `queue/${newKey}`), {
      songId: song.id,
      singerId,
      timestamp: Date.now(),
      key: newKey,
    });
  },
};

Real-time Listeners:

// src/hooks/useQueue.ts
useEffect(() => {
  const queueRef = ref(database, 'queue');
  const unsubscribe = onValue(queueRef, (snapshot) => {
    const data = snapshot.val();
    if (data) {
      const queueItems = Object.values(data) as QueueItem[];
      dispatch(setQueue(queueItems));
    }
  });
  return () => unsubscribe();
}, [dispatch]);

Error Handling:

// src/hooks/useFirebaseSync.ts
const retryOperation = async (operation: () => Promise<void>, maxRetries = 3) => {
  for (let i = 0; i < maxRetries; i++) {
    try {
      await operation();
      return;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
    }
  }
};

Hook Implementation Patterns:

Custom Hook Structure:

// src/hooks/useQueue.ts
export const useQueue = () => {
  const dispatch = useAppDispatch();
  const queue = useAppSelector(selectQueue);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const addToQueue = useCallback(async (song: Song, singerId: string) => {
    try {
      setLoading(true);
      setError(null);
      await queueService.addToQueue(song, singerId);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to add to queue');
    } finally {
      setLoading(false);
    }
  }, []);

  return {
    queue,
    loading,
    error,
    addToQueue,
  };
};

Hook Dependencies:

  • Hooks depend on Redux state and services
  • Business logic implemented in hooks, not components
  • Error handling and loading states managed in hooks
  • Memoization used for expensive operations

Hook Usage in Components:

// src/features/Queue/Queue.tsx
const Queue: React.FC = () => {
  const { queue, loading, error, addToQueue } = useQueue();
  const { songs } = useSongs();

  const handleAddToQueue = useCallback((song: Song) => {
    addToQueue(song, currentSingerId);
  }, [addToQueue, currentSingerId]);

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage message={error} />;

  return (
    <IonList>
      {Object.values(queue).map((item) => (
        <SongItem
          key={item.key}
          song={songs[item.songId]}
          onAddToQueue={handleAddToQueue}
        />
      ))}
    </IonList>
  );
};

Performance Optimizations:

  • React.memo for expensive components
  • useMemo and useCallback for expensive calculations
  • Redux selectors with memoization
  • Lazy loading for route-based code splitting
  • Service worker for PWA caching

Critical Implementation Rules:

  • Never import directly from slice files - always use the main redux index
  • Always use type imports for TypeScript interfaces
  • Implement business logic in hooks, not components
  • Use memoization for expensive operations
  • Handle loading and error states in all async operations

Migration Guide

To Other Web Frameworks:

Vue.js Migration:

  • Replace React components with Vue components
  • Replace Redux with Pinia or Vuex
  • Replace Ionic React with Ionic Vue
  • Keep all business logic and Firebase integration

Svelte Migration:

  • Replace React components with Svelte components
  • Replace Redux with Svelte stores
  • Replace Ionic React with Ionic Svelte
  • Keep all business logic and Firebase integration

To Mobile Platforms:

React Native Migration:

  • Replace Ionic components with React Native components
  • Replace web-specific APIs with React Native APIs
  • Keep Redux state management
  • Keep all business logic and Firebase integration

Native iOS/Android Migration:

  • Replace React components with native UI components
  • Replace Redux with native state management
  • Keep all business logic and Firebase integration
  • Adapt UI patterns to platform conventions

This document contains web-specific implementation details. For core business logic and platform-agnostic requirements, see the main ../../PRD.md.