1180 lines
49 KiB
Markdown
1180 lines
49 KiB
Markdown
# 🎤 Karaoke Web App — Product Requirements Document (PRD)
|
||
|
||
---
|
||
|
||
## 1️⃣ Purpose
|
||
|
||
This document defines the functional, technical, and UX requirements for the Karaoke Web App, designed for **in-home party use**.
|
||
The app leverages **Firebase Realtime Database** for real-time synchronization, with all business logic and validation handled **client-side**.
|
||
|
||
---
|
||
|
||
## 2️⃣ Scope & Business Objectives
|
||
|
||
- 🎯 Deliver a single-session karaoke experience where users connect to a controller and manage/search songs.
|
||
- ✅ Use Firebase for real-time multi-user sync of queues, history, and playback state.
|
||
- ✅ Prioritize fast performance, reusable modular architecture, and clear business logic separation.
|
||
- ✅ Enable adding songs from multiple entry points (search, history, top played, favorites, new songs, artists, song lists).
|
||
- ✅ Ensure graceful handling of Firebase sync issues using retry patterns and partial node updates.
|
||
- ✅ True Separation of Concerns - UI components only handle presentation
|
||
- ✅ Reusable Business Logic - Hooks can be used across components
|
||
- ✅ Testable Code - Business logic separated from UI
|
||
- ✅ Maintainable - Changes to logic don't affect UI
|
||
- ✅ Performance - Memoized selectors and optimized hooks
|
||
- ✅ Type Safety - Full TypeScript coverage throughout
|
||
- ✅ The codebase needs to follow the Single Responsibility Principle perfectly - each file has one clear purpose!
|
||
|
||
---
|
||
|
||
## 3️⃣ User Roles & Permissions
|
||
|
||
| Role | Search Songs | Add Songs | Delete Songs | Reorder Queue | Playback Control | Manage Singers | View All Features |
|
||
|--------------|---------------|-----------|--------------|----------------|------------------|----------------|-------------------|
|
||
| **Host/Admin** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||
| **Singer/User** | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ |
|
||
|
||
**Additional Permissions:**
|
||
- **Admin Access:** Available via URL parameter `?admin=true`
|
||
- **Queue Management:** Only admins can reorder queue items using up/down arrows
|
||
- **First Item Protection:** First queue item cannot be deleted while playing (only when stopped/paused)
|
||
- **Singer Auto-Add:** Singers are automatically added to the singers list when they join
|
||
|
||
---
|
||
|
||
## 4️⃣ Feature Overview
|
||
|
||
### **Authentication & Session Management:**
|
||
- **Login Flow:** Simple form-based authentication with Party ID and singer name
|
||
- **Admin Mode:** Special admin access via URL parameter with enhanced privileges
|
||
- **Session Persistence:** Authentication state managed in Redux with automatic logout on page reload
|
||
- **Controller Connection:** Users connect to specific controller/party sessions
|
||
|
||
### **Search:**
|
||
- **Local Search:** Redux-managed search on preloaded song catalog
|
||
- **Real-time Results:** Instant search results as user types
|
||
- **Infinite Scroll:** Paginated results with automatic loading
|
||
- **Context Actions:** Common song item view with context-based action panel
|
||
|
||
### **Queue Management:**
|
||
- **Real-time Sync:** Shared queue synchronized across all connected clients
|
||
- **Admin Controls:** Only admins can reorder using up/down arrow buttons
|
||
- **User Actions:** All users can delete songs (except first item when playing)
|
||
- **Order Management:** Sequential order system with automatic cleanup of inconsistent keys
|
||
- **Duplicate Prevention:** Based on `path` field of each song
|
||
- **Singer Attribution:** Each queue item shows which singer added it
|
||
|
||
### **Favorites:**
|
||
- **Real-time Sync:** Shared favorites list synchronized across all clients
|
||
- **Universal Access:** Anyone can add/remove favorites
|
||
- **Duplicate Prevention:** Based on `path` field of each song
|
||
- **Infinite Scroll:** Paginated display with automatic loading
|
||
|
||
### **New Songs:**
|
||
- **Latest Additions:** Shows recently added songs from the `newSongs` node
|
||
- **Real-time Updates:** Automatically syncs when new songs are added
|
||
- **Infinite Scroll:** Paginated display with automatic loading
|
||
|
||
### **Artists:**
|
||
- **Artist Browse:** Browse songs by artist with search functionality
|
||
- **Modal View:** Click artist to see all their songs in a modal
|
||
- **Song Count:** Shows number of songs per artist
|
||
- **Infinite Scroll:** Paginated artist list with automatic loading
|
||
|
||
### **Song Lists:**
|
||
- **Predefined Lists:** Curated song lists with specific themes or collections
|
||
- **Song Matching:** Automatically matches list songs to available catalog
|
||
- **Expandable View:** Click to expand and see available song versions
|
||
- **Modal Interface:** Full-screen modal for viewing list contents
|
||
- **Availability Status:** Shows which songs are available in the catalog
|
||
|
||
### **History Tracking:**
|
||
- **Play History:** Songs automatically added to history when played
|
||
- **Date Display:** Shows when each song was last played
|
||
- **Append-only:** History is append-only, shared across all clients
|
||
- **Infinite Scroll:** Paginated display with automatic loading
|
||
|
||
### **Top Played:**
|
||
- **Popular Songs:** Generated by Firebase Cloud Function based on history
|
||
- **Play Count:** Shows number of times each song has been played
|
||
- **Real-time Updates:** Automatically updates when new plays are recorded
|
||
- **Infinite Scroll:** Paginated display with automatic loading
|
||
|
||
### **Singer Management:**
|
||
- **Admin Control:** Only admins can add/remove singers
|
||
- **Auto-Add:** Singers automatically added when they join the session
|
||
- **View Access:** All users can view the current singers list
|
||
- **Last Login:** Tracks when each singer last joined
|
||
|
||
### **Playback Control:**
|
||
- **Admin Only:** Playback controls only visible to admin users
|
||
- **State Sync:** Playback state synced to all clients using the `player.state` node
|
||
- **Player States:** Playing, Paused, Stopped (mapped to PlayerState enum)
|
||
- **Queue Integration:** Controls work with the current queue
|
||
|
||
### **Error Handling & Sync:**
|
||
- **Retry Patterns:** Graceful handling of Firebase sync failures
|
||
- **Full Load:** Complete controller object loaded on initial connection
|
||
- **Incremental Updates:** Subsequent updates target specific child nodes
|
||
- **Connection Status:** Real-time connection status monitoring
|
||
- **Empty State Handling:** Graceful handling of missing or empty data
|
||
|
||
---
|
||
|
||
## 5️⃣ Data Models
|
||
|
||
Data models are defined externally in:
|
||
> [`types.ts`](./types.ts)
|
||
|
||
This file contains TypeScript interfaces describing:
|
||
- `Song` — Core song data with artist, title, path, and metadata
|
||
- `QueueItem` — Queue entries with order, singer, and song data
|
||
- `Singer` — User information with name and last login
|
||
- `SongList` — Predefined song collections with metadata
|
||
- `SongListSong` — Individual songs within a song list
|
||
- `TopPlayed` — Popular songs with play count
|
||
- `Controller` — Main object containing all app data
|
||
- `PlayerState` — Playback status enum (Playing, Paused, Stopped)
|
||
- `Authentication` — User session data with admin status
|
||
- `Settings` — Player settings (autoadvance, userpick)
|
||
|
||
**Key Data Relationships:**
|
||
- Songs are identified by their `path` field for duplicate prevention
|
||
- Queue items have sequential `order` values for proper ordering
|
||
- All data is stored as Firebase records with string keys
|
||
- History tracks play dates and counts for each song
|
||
|
||
---
|
||
|
||
## 6️⃣ Firebase Realtime Database Structure
|
||
|
||
Defined externally in:
|
||
> [`firebase_schema.json`](./firebase_schema.json)
|
||
|
||
**Complete Structure:**
|
||
```json
|
||
controllers: {
|
||
[controllerName]: {
|
||
favorites: Record<string, Song>,
|
||
history: Record<string, Song>,
|
||
topPlayed: Record<string, TopPlayed>,
|
||
newSongs: Record<string, Song>,
|
||
player: {
|
||
queue: Record<string, QueueItem>,
|
||
settings: Settings,
|
||
singers: Record<string, Singer>,
|
||
state: Player
|
||
},
|
||
songList: Record<string, SongList>,
|
||
songs: Record<string, Song>
|
||
}
|
||
}
|
||
```
|
||
|
||
**Data Flow:**
|
||
- **Initial Sync:** Loads the complete `controller` object on connection
|
||
- **Real-time Updates:** Subscribes to specific nodes for incremental updates
|
||
- **Key Management:** Uses sequential numerical keys for queue items
|
||
- **Auto-initialization:** Creates empty controller structure if none exists
|
||
|
||
---
|
||
|
||
## 7️⃣ UI/UX Behavior
|
||
|
||
### **Design System:**
|
||
- **Responsive Design:** Works on all device sizes (mobile, tablet, desktop)
|
||
- **Light/Dark Mode:** Support for both themes (implementation pending)
|
||
- **Modern UI:** Clean, intuitive interface with consistent styling
|
||
- **Accessibility:** Keyboard navigation and screen reader support
|
||
|
||
### **Navigation:**
|
||
- **Tab-based Navigation:** Horizontal navigation bar with icons
|
||
- **Active States:** Clear indication of current page
|
||
- **Breadcrumbs:** Context-aware navigation (implementation pending)
|
||
|
||
### **Common Components:**
|
||
- **Empty State View:** Consistent empty state for all lists
|
||
- **Loading States:** Spinner animations during data loading
|
||
- **Toast Notifications:** Success/error feedback for user actions
|
||
- **Action Buttons:** Consistent button styling with variants
|
||
- **Song Items:** Reusable song display with context-aware actions
|
||
- **Infinite Scroll:** Automatic loading of additional content
|
||
|
||
### **Context-Specific Behavior:**
|
||
- **Search Context:** Add to queue, toggle favorite actions
|
||
- **Queue Context:** Remove from queue, reorder (admin), toggle favorite
|
||
- **History Context:** Add to queue, toggle favorite, show play date
|
||
- **Favorites Context:** Add to queue, remove from favorites
|
||
- **Artist Context:** Modal view with all artist songs
|
||
- **Song List Context:** Expandable song matching with availability status
|
||
|
||
### **Admin-Specific UI:**
|
||
- **Playback Controls:** Only visible to admin users
|
||
- **Queue Reorder:** Up/down arrow buttons for queue management
|
||
- **Singer Management:** Add/remove singer functionality
|
||
- **Enhanced Permissions:** Visual indicators for admin capabilities
|
||
|
||
---
|
||
|
||
## 8️⃣ UI Rules & Constraints
|
||
|
||
### **Queue Management Rules:**
|
||
- **Admin-Only Reordering:** Only admin users can reorder queue items using up/down arrows
|
||
- **First Item Protection:** First queue item cannot be deleted while playing (only when stopped/paused)
|
||
- **Reorder Constraints:**
|
||
- Items with `order > 2` can move up (↑ button visible)
|
||
- Items with `order > 1` AND `order < queue.length` can move down (↓ button visible)
|
||
- First item (order = 1) cannot be moved up
|
||
- Last item cannot be moved down
|
||
- **Sequential Ordering:** Queue items must maintain sequential order (1, 2, 3, etc.)
|
||
- **Order Validation:** Automatic cleanup of inconsistent order values on queue initialization
|
||
- **Key Management:** Queue items use sequential numerical keys (0, 1, 2, etc.)
|
||
|
||
### **Playback Control Rules:**
|
||
- **Admin-Only Visibility:** Player controls only visible to admin users (`isAdmin = true`)
|
||
- **Queue Dependency:** Play button is disabled when queue is empty (`hasSongsInQueue = false`)
|
||
- **State-Based Controls:**
|
||
- When `playing`: Show pause button, hide play button
|
||
- When `paused` or `stopped`: Show play button, hide pause button
|
||
- When `playing` or `paused`: Show stop button
|
||
- When `stopped`: Hide stop button
|
||
- **State Display:** Current player state shown with color-coded badges (green=playing, yellow=paused, gray=stopped)
|
||
|
||
### **Search Rules:**
|
||
- **Minimum Search Length:** Search only activates after 2+ characters (`MIN_SEARCH_LENGTH = 2`)
|
||
- **Debounce Delay:** 300ms delay before search execution (`DEBOUNCE_DELAY = 300`)
|
||
- **Search Scope:** Searches both song title and artist fields (case-insensitive)
|
||
- **Empty Search:** When search term is empty or too short, shows all songs
|
||
- **Page Reset:** Search resets to page 1 when search term changes
|
||
|
||
### **Pagination & Infinite Scroll Rules:**
|
||
- **Items Per Page:** 20 items loaded per page (`ITEMS_PER_PAGE = 20`)
|
||
- **Load More Logic:** Only shows "load more" when there are more items than currently displayed
|
||
- **Intersection Observer:** Triggers load more when user scrolls to bottom 10% of list
|
||
- **Page State:** Each feature maintains its own page state independently
|
||
|
||
### **Mandatory List Pagination Requirements:**
|
||
- **All Lists Must Use InfiniteScrollList:** Every list in the application MUST use the `InfiniteScrollList` component to prevent UI blocking
|
||
- **No Direct Array Rendering:** Never render large arrays directly in components - always use pagination
|
||
- **Consistent Page Size:** All lists use exactly 20 items per page (`ITEMS_PER_PAGE = 20`)
|
||
- **Progressive Loading:** Items are loaded progressively as user scrolls, not all at once
|
||
- **Intersection Observer Threshold:** 10% threshold for triggering load more (`threshold: 0.1`)
|
||
- **Loading State Management:** Show loading spinner only when no items are loaded yet
|
||
- **HasMore Calculation:** Only show "load more" when `currentItems.length < totalItems.length`
|
||
- **Page Reset on Search:** Reset to page 1 when search term changes
|
||
- **Independent Page States:** Each feature (Search, History, Favorites, etc.) maintains separate page state
|
||
- **Memory Optimization:** Only render currently visible items plus buffer for smooth scrolling
|
||
- **Performance Monitoring:** Log render times and intersection detection for debugging
|
||
- **Error Handling:** Graceful handling of load more failures with retry options
|
||
- **Accessibility:** Ensure infinite scroll works with keyboard navigation and screen readers
|
||
|
||
### **InfiniteScrollList Component Rules:**
|
||
- **Required Props:** All lists must provide `items`, `isLoading`, `hasMore`, `onLoadMore`
|
||
- **Context Support:** Must support all contexts: 'search', 'queue', 'history', 'topPlayed', 'favorites'
|
||
- **Loading States:**
|
||
- Show spinner when `isLoading && items.length === 0`
|
||
- Show empty state when `items.length === 0 && !isLoading`
|
||
- Show load more trigger when `hasMore && items.length > 0`
|
||
- **Observer Management:** Automatic cleanup of intersection observers on unmount
|
||
- **Debug Information:** Optional debug info display for development
|
||
- **Extra Content Support:** Allow custom content rendering per item
|
||
- **Admin Controls:** Pass through admin status for context-specific actions
|
||
|
||
### **Toast Notification Rules:**
|
||
- **Duration Settings:**
|
||
- Success messages: 3 seconds (`SUCCESS: 3000`)
|
||
- Error messages: 5 seconds (`ERROR: 5000`)
|
||
- Info messages: 3 seconds (`INFO: 3000`)
|
||
- **Auto-dismiss:** Toasts automatically disappear after duration
|
||
- **Manual Dismiss:** Users can manually close toasts with × button
|
||
- **Stacking:** Multiple toasts can be displayed simultaneously
|
||
- **Position:** Fixed position at top-right corner with z-index 50
|
||
|
||
### **Authentication Rules:**
|
||
- **Admin Access:** Available via URL parameter `?admin=true`
|
||
- **URL Cleanup:** Admin parameter removed from URL after successful authentication
|
||
- **Session Persistence:** Authentication state lost on page reload (requires re-login)
|
||
- **Required Fields:** Both Party ID and singer name required for login
|
||
- **Admin Default:** Admin mode pre-fills singer name as "Admin"
|
||
|
||
### **Data Display Rules:**
|
||
- **Loading States:** Show spinner when data count is 0
|
||
- **Empty States:** Show empty state when data exists but filtered results are empty
|
||
- **Debug Information:** Show data counts and loading status in development
|
||
- **User Attribution:** Show "(You)" indicator for current user's queue items
|
||
- **Availability Status:** Show "Not available in catalog" for unmatched song list items
|
||
|
||
### **Action Button Rules:**
|
||
- **Context-Based Actions:** Different actions available based on context (search, queue, history, etc.)
|
||
- **Permission-Based Visibility:** Actions hidden based on user role (admin vs regular user)
|
||
- **State-Based Disabling:** Buttons disabled based on current state (e.g., play button when queue empty)
|
||
- **Confirmation Feedback:** All actions show success/error toast notifications
|
||
|
||
### **Modal & Overlay Rules:**
|
||
- **Artist Modal:** Full-screen modal for viewing artist songs
|
||
- **Song List Modal:** Full-screen modal with expandable song sections
|
||
- **Z-Index Management:** Modals use high z-index (9999) to appear above all content
|
||
- **Backdrop:** Semi-transparent black backdrop (50% opacity)
|
||
- **Close Actions:** Modal can be closed via close button or backdrop click
|
||
|
||
### **Error Handling Rules:**
|
||
- **Error Boundaries:** React error boundaries catch component-level errors
|
||
- **Graceful Degradation:** App continues to work with cached data during connection issues
|
||
- **User Feedback:** Clear error messages with recovery options
|
||
- **Retry Logic:** Automatic retry for failed Firebase operations
|
||
- **Fallback Values:** Default values provided for missing or corrupted data
|
||
|
||
### **Performance Rules:**
|
||
- **Memoization:** Expensive operations memoized with `useMemo` and `useCallback`
|
||
- **Debouncing:** Search input debounced to prevent excessive API calls
|
||
- **Incremental Loading:** Large datasets loaded in chunks via infinite scroll
|
||
- **Optimistic Updates:** UI updates immediately, with rollback on error
|
||
- **Connection Monitoring:** Real-time connection status tracking
|
||
|
||
### **Data Validation Rules:**
|
||
- **Type Safety:** All data validated against TypeScript interfaces
|
||
- **Required Fields:** Critical fields (controller name, singer name) validated before operations
|
||
- **Duplicate Prevention:** Songs identified by `path` field for duplicate checking
|
||
- **Order Validation:** Queue order automatically fixed if inconsistencies detected
|
||
- **Key Cleanup:** Inconsistent Firebase keys automatically migrated to sequential format
|
||
|
||
### **Feature Flag Rules:**
|
||
- **Configurable Features:** Features can be enabled/disabled via constants:
|
||
- `ENABLE_SEARCH: true`
|
||
- `ENABLE_QUEUE_REORDER: true`
|
||
- `ENABLE_FAVORITES: true`
|
||
- `ENABLE_HISTORY: true`
|
||
- `ENABLE_TOP_PLAYED: true`
|
||
- `ENABLE_ADMIN_CONTROLS: true`
|
||
|
||
### **Constants & Limits:**
|
||
- **Queue Limits:** Maximum 100 items (`MAX_ITEMS: 100`)
|
||
- **History Limits:** Maximum 50 items (`MAX_ITEMS: 50`)
|
||
- **Top Played Limits:** Maximum 20 items (`MAX_ITEMS: 20`)
|
||
- **Search Limits:** Minimum 2 characters, 300ms debounce
|
||
- **Toast Limits:** Success/Info 3s, Error 5s duration
|
||
|
||
---
|
||
|
||
## 9️⃣ Codebase Organization & File Structure
|
||
|
||
### **Folder Structure & Purpose:**
|
||
|
||
| Folder | Purpose | Key Files | Import Pattern |
|
||
|--------|---------|-----------|----------------|
|
||
| `/components/common` | Shared UI components | `ActionButton.tsx`, `EmptyState.tsx`, `SongItem.tsx`, `InfiniteScrollList.tsx` | `import { ComponentName } from '../components/common'` |
|
||
| `/components/Auth` | Authentication components | `AuthInitializer.tsx`, `LoginPrompt.tsx` | `import { AuthInitializer } from '../components/Auth'` |
|
||
| `/components/Layout` | Layout and navigation | `Layout.tsx`, `Navigation.tsx` | `import Layout from '../components/Layout/Layout'` |
|
||
| `/features` | Feature-specific components | `Search.tsx`, `Queue.tsx`, `History.tsx`, `Artists.tsx`, `SongLists.tsx` | `import { Search, Queue } from '../features'` |
|
||
| `/hooks` | Business logic hooks | `useQueue.ts`, `useSearch.ts`, `useSongOperations.ts` | `import { useQueue, useSearch } from '../hooks'` |
|
||
| `/redux` | State management | `controllerSlice.ts`, `authSlice.ts`, `selectors.ts` | `import { useAppDispatch, selectQueue } from '../redux'` |
|
||
| `/firebase` | Firebase services | `services.ts`, `FirebaseProvider.tsx` | `import { queueService } from '../firebase/services'` |
|
||
| `/types` | TypeScript definitions | `index.ts` (extends docs/types.ts) | `import type { Song, QueueItem } from '../types'` |
|
||
| `/utils` | Utility functions | `dataProcessing.ts` | `import { filterSongs } from '../utils/dataProcessing'` |
|
||
| `/constants` | App constants | `index.ts` | `import { UI_CONSTANTS } from '../constants'` |
|
||
|
||
### **Index File Pattern:**
|
||
Each folder uses an `index.ts` file to export all public APIs:
|
||
|
||
```typescript
|
||
// src/hooks/index.ts
|
||
export { useFirebaseSync } from './useFirebaseSync';
|
||
export { useSongOperations } from './useSongOperations';
|
||
export { useToast } from './useToast';
|
||
export { useSearch } from './useSearch';
|
||
export { useQueue } from './useQueue';
|
||
// ... all other hooks
|
||
|
||
// src/components/common/index.ts
|
||
export { default as ActionButton } from './ActionButton';
|
||
export { default as EmptyState } from './EmptyState';
|
||
export { default as Toast } from './Toast';
|
||
// ... all other components
|
||
|
||
// src/features/index.ts
|
||
export { default as Search } from './Search/Search';
|
||
export { default as Queue } from './Queue/Queue';
|
||
export { default as History } from './History/History';
|
||
// ... all other features
|
||
```
|
||
|
||
### **Import Organization Patterns:**
|
||
|
||
#### **1. Redux Imports:**
|
||
```typescript
|
||
// Always import from the main redux index
|
||
import { useAppDispatch, useAppSelector } from '../redux';
|
||
import { selectQueue, selectSongs } from '../redux';
|
||
import { setController, updateQueue } from '../redux';
|
||
|
||
// Never import directly from slice files
|
||
// ❌ import { selectQueue } from '../redux/controllerSlice';
|
||
// ✅ import { selectQueue } from '../redux';
|
||
```
|
||
|
||
#### **2. Hook Imports:**
|
||
```typescript
|
||
// Import hooks from the main hooks index
|
||
import { useQueue, useSearch, useSongOperations } from '../hooks';
|
||
|
||
// Import specific hooks when needed
|
||
import { useToast } from '../hooks/useToast';
|
||
```
|
||
|
||
#### **3. Component Imports:**
|
||
```typescript
|
||
// Import from feature index for feature components
|
||
import { Search, Queue, History } from '../features';
|
||
|
||
// Import from common index for shared components
|
||
import { ActionButton, EmptyState, SongItem } from '../components/common';
|
||
|
||
// Import layout components directly
|
||
import Layout from '../components/Layout/Layout';
|
||
```
|
||
|
||
#### **4. Type Imports:**
|
||
```typescript
|
||
// Always use type imports for TypeScript interfaces
|
||
import type { Song, QueueItem } from '../types';
|
||
|
||
// Import specific types when needed
|
||
import type { RootState } from '../types';
|
||
```
|
||
|
||
#### **5. Service Imports:**
|
||
```typescript
|
||
// Import Firebase services directly
|
||
import { queueService, favoritesService } from '../firebase/services';
|
||
|
||
// Import Firebase configuration
|
||
import { database } from '../firebase/config';
|
||
```
|
||
|
||
#### **6. Utility Imports:**
|
||
```typescript
|
||
// Import utility functions directly
|
||
import { filterSongs, objectToArray } from '../utils/dataProcessing';
|
||
```
|
||
|
||
#### **7. Constant Imports:**
|
||
```typescript
|
||
// Import constants from the main constants index
|
||
import { UI_CONSTANTS, FEATURES } from '../constants';
|
||
```
|
||
|
||
### **File Organization Principles:**
|
||
|
||
#### **Single Responsibility Principle:**
|
||
- **Each file has one clear purpose**
|
||
- **Hooks handle business logic only**
|
||
- **Components handle UI rendering only**
|
||
- **Services handle external API calls only**
|
||
- **Types define data structures only**
|
||
|
||
#### **Separation of Concerns:**
|
||
- **UI Components:** Only handle presentation and user interaction
|
||
- **Business Logic:** Extracted into custom hooks
|
||
- **State Management:** Centralized in Redux slices
|
||
- **Data Access:** Abstracted in Firebase services
|
||
- **Type Definitions:** Centralized in types folder
|
||
|
||
#### **Dependency Direction:**
|
||
```
|
||
Components → Hooks → Redux → Services → Firebase
|
||
↓ ↓ ↓ ↓ ↓
|
||
Types ← Types ← Types ← Types ← Types
|
||
```
|
||
|
||
### **Redux Architecture Pattern:**
|
||
|
||
#### **Slice Organization:**
|
||
```typescript
|
||
// src/redux/controllerSlice.ts
|
||
export const controllerSlice = createSlice({
|
||
name: 'controller',
|
||
initialState,
|
||
reducers: {
|
||
setController: (state, action) => { /* ... */ },
|
||
updateQueue: (state, action) => { /* ... */ },
|
||
// ... other reducers
|
||
},
|
||
});
|
||
|
||
// Export actions and selectors
|
||
export const { setController, updateQueue } = controllerSlice.actions;
|
||
export const selectController = (state: RootState) => state.controller.data;
|
||
```
|
||
|
||
#### **Selector Pattern:**
|
||
```typescript
|
||
// src/redux/selectors.ts
|
||
export const selectSongsArray = createSelector(
|
||
[selectSongs],
|
||
(songs) => sortSongsByArtistAndTitle(objectToArray(songs))
|
||
);
|
||
|
||
export const selectQueueWithUserInfo = createSelector(
|
||
[selectQueue, selectCurrentSinger],
|
||
(queue, currentSinger) => addUserInfoToQueue(queue, currentSinger)
|
||
);
|
||
```
|
||
|
||
#### **Hook Integration:**
|
||
```typescript
|
||
// src/hooks/useQueue.ts
|
||
export const useQueue = () => {
|
||
const queueItems = useAppSelector(selectQueueWithUserInfo);
|
||
const dispatch = useAppDispatch();
|
||
|
||
const handleRemoveFromQueue = useCallback(async (queueItemKey: string) => {
|
||
try {
|
||
await queueService.removeFromQueue(controllerName, queueItemKey);
|
||
} catch (error) {
|
||
showError('Failed to remove song from queue');
|
||
}
|
||
}, [controllerName, showError]);
|
||
|
||
return { queueItems, handleRemoveFromQueue };
|
||
};
|
||
```
|
||
|
||
### **Hook Architecture Pattern:**
|
||
|
||
#### **Hook Composition:**
|
||
```typescript
|
||
// Base operations hook
|
||
export const useSongOperations = () => {
|
||
// Common song operations (add to queue, toggle favorite)
|
||
};
|
||
|
||
// Feature-specific hooks compose base hooks
|
||
export const useQueue = () => {
|
||
const { removeFromQueue, toggleFavorite } = useSongOperations();
|
||
const { showSuccess, showError } = useToast();
|
||
// Queue-specific logic
|
||
};
|
||
|
||
export const useSearch = () => {
|
||
const { addToQueue, toggleFavorite } = useSongOperations();
|
||
const { showSuccess, showError } = useToast();
|
||
// Search-specific logic
|
||
};
|
||
```
|
||
|
||
#### **Hook Dependencies:**
|
||
```typescript
|
||
// Hooks depend on Redux state and services
|
||
export const useQueue = () => {
|
||
const queueItems = useAppSelector(selectQueueWithUserInfo);
|
||
const { removeFromQueue } = useSongOperations();
|
||
const { showError } = useToast();
|
||
|
||
// Hook logic here
|
||
};
|
||
```
|
||
|
||
### **Component Architecture Pattern:**
|
||
|
||
#### **Component Structure:**
|
||
```typescript
|
||
// Feature components are simple and focused
|
||
export const Queue = () => {
|
||
const { queueItems, handleRemoveFromQueue } = useQueue();
|
||
|
||
return (
|
||
<div>
|
||
<InfiniteScrollList
|
||
items={queueItems}
|
||
context="queue"
|
||
onRemove={handleRemoveFromQueue}
|
||
/>
|
||
</div>
|
||
);
|
||
};
|
||
```
|
||
|
||
#### **Component Dependencies:**
|
||
```typescript
|
||
// Components only depend on hooks and UI components
|
||
import { useQueue } from '../hooks';
|
||
import { InfiniteScrollList, SongItem } from '../components/common';
|
||
import type { QueueItem } from '../types';
|
||
```
|
||
|
||
### **Type Organization Pattern:**
|
||
|
||
#### **Type Definitions:**
|
||
```typescript
|
||
// src/types/index.ts
|
||
export interface Song {
|
||
artist: string;
|
||
title: string;
|
||
path: string;
|
||
favorite?: boolean;
|
||
}
|
||
|
||
export interface QueueItem {
|
||
key?: string;
|
||
order: number;
|
||
singer: Singer;
|
||
song: Song;
|
||
}
|
||
|
||
export interface RootState {
|
||
controller: ControllerState;
|
||
auth: AuthState;
|
||
}
|
||
```
|
||
|
||
#### **Type Usage:**
|
||
```typescript
|
||
// Always use type imports
|
||
import type { Song, QueueItem } from '../types';
|
||
|
||
// Use in function parameters and return types
|
||
const addToQueue = async (song: Song): Promise<void> => {
|
||
// Implementation
|
||
};
|
||
```
|
||
|
||
### **Service Architecture Pattern:**
|
||
|
||
#### **Service Organization:**
|
||
```typescript
|
||
// src/firebase/services.ts
|
||
export const queueService = {
|
||
addToQueue: async (controllerName: string, queueItem: Omit<QueueItem, 'key'>) => {
|
||
// Implementation
|
||
},
|
||
removeFromQueue: async (controllerName: string, queueItemKey: string) => {
|
||
// Implementation
|
||
},
|
||
subscribeToQueue: (controllerName: string, callback: (data: Record<string, QueueItem>) => void) => {
|
||
// Implementation
|
||
},
|
||
};
|
||
```
|
||
|
||
#### **Service Usage:**
|
||
```typescript
|
||
// Import services directly
|
||
import { queueService, favoritesService } from '../firebase/services';
|
||
|
||
// Use in hooks
|
||
const handleAddToQueue = useCallback(async (song: Song) => {
|
||
await queueService.addToQueue(controllerName, queueItem);
|
||
}, [controllerName]);
|
||
```
|
||
|
||
### **Constants Organization Pattern:**
|
||
|
||
#### **Constants Structure:**
|
||
```typescript
|
||
// src/constants/index.ts
|
||
export const UI_CONSTANTS = {
|
||
TOAST_DURATION: {
|
||
SUCCESS: 3000,
|
||
ERROR: 5000,
|
||
INFO: 3000,
|
||
},
|
||
SEARCH: {
|
||
DEBOUNCE_DELAY: 300,
|
||
MIN_SEARCH_LENGTH: 2,
|
||
},
|
||
} as const;
|
||
|
||
export const FEATURES = {
|
||
ENABLE_SEARCH: true,
|
||
ENABLE_QUEUE_REORDER: true,
|
||
} as const;
|
||
```
|
||
|
||
#### **Constants Usage:**
|
||
```typescript
|
||
// Import constants from main index
|
||
import { UI_CONSTANTS, FEATURES } from '../constants';
|
||
|
||
// Use in components and hooks
|
||
const debounceDelay = UI_CONSTANTS.SEARCH.DEBOUNCE_DELAY;
|
||
```
|
||
|
||
### **Import Order Convention:**
|
||
```typescript
|
||
// 1. React imports
|
||
import { useState, useCallback, useEffect } from 'react';
|
||
|
||
// 2. Third-party library imports
|
||
import { useAppSelector, useAppDispatch } from '../redux';
|
||
|
||
// 3. Internal imports (alphabetical by folder)
|
||
import { useSongOperations } from '../hooks';
|
||
import { queueService } from '../firebase/services';
|
||
import { UI_CONSTANTS } from '../constants';
|
||
import { filterSongs } from '../utils/dataProcessing';
|
||
|
||
// 4. Type imports
|
||
import type { Song, QueueItem } from '../types';
|
||
```
|
||
|
||
### **File Naming Conventions:**
|
||
- **Components:** PascalCase (e.g., `SongItem.tsx`, `InfiniteScrollList.tsx`)
|
||
- **Hooks:** camelCase with `use` prefix (e.g., `useQueue.ts`, `useSongOperations.ts`)
|
||
- **Services:** camelCase with `Service` suffix (e.g., `queueService`, `favoritesService`)
|
||
- **Types:** PascalCase (e.g., `Song`, `QueueItem`, `Controller`)
|
||
- **Constants:** UPPER_SNAKE_CASE (e.g., `UI_CONSTANTS`, `FEATURES`)
|
||
- **Utilities:** camelCase (e.g., `dataProcessing.ts`, `filterSongs`)
|
||
|
||
### **Critical Import Rules:**
|
||
- **Never import directly from slice files** - always use the main redux index
|
||
- **Always use type imports** for TypeScript interfaces
|
||
- **Import from index files** for organized modules (hooks, components, features)
|
||
- **Import services directly** from their service files
|
||
- **Import utilities directly** from their utility files
|
||
- **Import constants** from the main constants index
|
||
|
||
---
|
||
|
||
## 🔟 Cloud Function Design — Top Played
|
||
|
||
- **Trigger:** Firebase Cloud Function triggered when song added to `history`
|
||
- **Action:** Increments play count in `/controllers/{controllerName}/topPlayed/{songId}`
|
||
- **Benefits:** Non-blocking updates, real-time popularity tracking
|
||
- **Data Structure:** Stores artist, title, and count for each popular song
|
||
|
||
---
|
||
|
||
## 11️⃣ External Reference Files
|
||
|
||
| File | Purpose |
|
||
|------|---------|
|
||
| [`types.ts`](./types.ts) | Core TypeScript interfaces for data models |
|
||
| [`firebase_schema.json`](./firebase_schema.json) | Firebase Realtime Database structure reference |
|
||
| [`design/`](./design/) | UI/UX mockups and design specifications |
|
||
|
||
---
|
||
|
||
## 12️⃣ Data Access Model & Validation
|
||
|
||
> **Client-Controlled Access Model**
|
||
|
||
This app does **not** use Firebase Realtime Database Security Rules.
|
||
All permissions, validation, and business logic are enforced in the client application.
|
||
|
||
### **Enforced Client-Side:**
|
||
- ✅ **Admin-only permissions** for queue reorder, playback control, and singer management
|
||
- ✅ **Duplicate song prevention** enforced before adding to queue/favorites
|
||
- ✅ **Singer auto-addition** when users join the session
|
||
- ✅ **Data validation** against TypeScript interfaces before Firebase writes
|
||
- ✅ **Queue order management** with sequential numbering and cleanup
|
||
- ✅ **First item protection** preventing deletion during playback
|
||
|
||
### **Business Logic Validation:**
|
||
- **Queue Operations:** Order validation, duplicate prevention, singer attribution
|
||
- **Authentication:** Admin mode detection, session management
|
||
- **Data Integrity:** Type checking, required field validation
|
||
- **State Management:** Redux state consistency, error handling
|
||
|
||
**Assumed Environment:**
|
||
- The app is used in trusted, in-home scenarios with controlled participants
|
||
- Open Firebase access is considered acceptable for this use case
|
||
- All users are trusted participants in the karaoke session
|
||
|
||
---
|
||
|
||
## 13️⃣ Performance & Optimization
|
||
|
||
### **State Management:**
|
||
- **Redux Toolkit:** Efficient state management with immutable updates
|
||
- **Memoized Selectors:** Optimized data access with `createSelector`
|
||
- **Incremental Loading:** Pagination and infinite scroll for large datasets
|
||
- **Real-time Sync:** Efficient Firebase subscriptions with cleanup
|
||
|
||
### **UI Performance:**
|
||
- **React.memo:** Component memoization to prevent unnecessary re-renders
|
||
- **useCallback/useMemo:** Hook optimization for expensive operations
|
||
- **Virtual Scrolling:** Efficient rendering of large lists (implementation pending)
|
||
- **Lazy Loading:** Code splitting for better initial load times
|
||
|
||
### **Data Optimization:**
|
||
- **Efficient Queries:** Optimized Firebase queries with specific node subscriptions
|
||
- **Caching Strategy:** Redux state caching with timestamp-based invalidation
|
||
- **Batch Operations:** Grouped Firebase updates for better performance
|
||
- **Connection Management:** Proper cleanup of Firebase listeners
|
||
|
||
### **List Performance & UI Blocking Prevention:**
|
||
- **Mandatory Pagination:** All lists MUST use pagination to prevent UI blocking
|
||
- **Progressive Rendering:** Only render visible items plus small buffer (20 items per page)
|
||
- **Intersection Observer:** Efficient scroll detection without performance impact
|
||
- **Memory Management:** Automatic cleanup of observers and event listeners
|
||
- **Virtual Scrolling:** Future implementation for very large datasets (1000+ items)
|
||
- **Debounced Operations:** Search and filter operations debounced to prevent excessive re-renders
|
||
- **Memoized Selectors:** Redux selectors memoized to prevent unnecessary re-computations
|
||
- **Optimistic Updates:** UI updates immediately with rollback on error
|
||
- **Lazy Loading:** Images and heavy content loaded only when needed
|
||
- **Render Optimization:** React.memo and useCallback for expensive operations
|
||
- **Bundle Splitting:** Code splitting for better initial load times
|
||
|
||
---
|
||
|
||
## 14️⃣ Error Handling & Resilience
|
||
|
||
### **Firebase Connection:**
|
||
- **Connection Monitoring:** Real-time connection status tracking
|
||
- **Retry Logic:** Automatic retry for failed operations
|
||
- **Graceful Degradation:** App continues to work with cached data
|
||
- **Error Boundaries:** React error boundaries for component-level error handling
|
||
|
||
### **Data Validation:**
|
||
- **Type Safety:** TypeScript compilation-time error prevention
|
||
- **Runtime Validation:** Data structure validation before Firebase writes
|
||
- **Fallback Values:** Default values for missing or corrupted data
|
||
- **User Feedback:** Clear error messages and recovery options
|
||
|
||
### **State Recovery:**
|
||
- **Session Persistence:** Authentication state recovery
|
||
- **Data Rehydration:** Redux state restoration from Firebase
|
||
- **Conflict Resolution:** Handling concurrent user modifications
|
||
- **Data Consistency:** Automatic cleanup of inconsistent data structures
|
||
|
||
---
|
||
|
||
## 15️⃣ Testing Strategy
|
||
|
||
### **Unit Testing:**
|
||
- **Hook Testing:** Business logic hooks with isolated testing
|
||
- **Selector Testing:** Redux selector validation
|
||
- **Utility Testing:** Pure function testing for data processing
|
||
- **Type Testing:** TypeScript interface validation
|
||
|
||
### **Integration Testing:**
|
||
- **Firebase Integration:** Real-time sync testing
|
||
- **Redux Integration:** State management flow testing
|
||
- **Component Integration:** UI component interaction testing
|
||
- **API Testing:** Firebase service layer testing
|
||
|
||
### **E2E Testing:**
|
||
- **User Flow Testing:** Complete user journey validation
|
||
- **Multi-user Testing:** Concurrent user interaction testing
|
||
- **Performance Testing:** Load testing for large datasets
|
||
- **Cross-browser Testing:** Browser compatibility validation
|
||
|
||
---
|
||
|
||
## 16️⃣ Deployment & Environment
|
||
|
||
### **Build Configuration:**
|
||
- **Vite:** Fast build tool with hot module replacement
|
||
- **TypeScript:** Strict type checking and compilation
|
||
- **ESLint:** Code quality and consistency enforcement
|
||
- **Tailwind CSS:** Utility-first CSS framework
|
||
|
||
### **Environment Variables:**
|
||
- **Firebase Config:** Database connection configuration
|
||
- **Controller Name:** Default controller for development
|
||
- **Feature Flags:** Environment-specific feature toggles
|
||
|
||
### **Deployment Targets:**
|
||
- **Development:** Local development with hot reload
|
||
- **Staging:** Pre-production testing environment
|
||
- **Production:** Live karaoke app deployment
|
||
|
||
---
|
||
|
||
## 17️⃣ Firebase Implementation Patterns
|
||
|
||
### **Key Management & Data Structure:**
|
||
- **Sequential Numerical Keys:** Queue items use sequential numerical keys (0, 1, 2, etc.) instead of Firebase push IDs
|
||
- **Key Migration:** Automatic cleanup of inconsistent keys (migrate push ID keys to sequential numerical keys)
|
||
- **Order Validation:** Queue items maintain sequential order (1, 2, 3, etc.) with automatic cleanup
|
||
- **Controller Structure:** Complete controller object loaded on initial connection with empty initialization if not exists
|
||
|
||
### **Firebase Services Architecture:**
|
||
- **Service Layer Pattern:** All Firebase operations abstracted into service modules:
|
||
- `controllerService` - Controller CRUD operations
|
||
- `queueService` - Queue management with key cleanup
|
||
- `playerService` - Player state management
|
||
- `historyService` - History operations
|
||
- `favoritesService` - Favorites management
|
||
- **Subscription Pattern:** Each service provides subscribe/unsubscribe functions for real-time updates
|
||
- **Error Handling:** Service functions include try-catch blocks with console logging
|
||
|
||
### **Real-time Sync Implementation:**
|
||
- **FirebaseProvider Pattern:** Centralized sync management with connection status tracking
|
||
- **Full Controller Load:** Initial load of complete controller object on authentication
|
||
- **Empty Controller Initialization:** Creates empty controller structure if none exists
|
||
- **Connection Status:** Real-time tracking of `isConnected` and `syncStatus` states
|
||
- **Cleanup Management:** Proper cleanup of Firebase listeners on unmount
|
||
|
||
### **Queue Management Patterns:**
|
||
- **Sequential Key Generation:** Next key calculated as `Math.max(existingKeys) + 1`
|
||
- **Key Cleanup Function:** `cleanupQueueKeys()` migrates push ID keys to sequential numerical keys
|
||
- **Order Calculation:** Next order calculated as `Math.max(existingOrders) + 1`
|
||
- **Order Fixing:** Automatic queue order validation and repair in `useQueue` hook
|
||
- **Swap Operations:** Queue reordering uses Promise.all for atomic updates
|
||
|
||
### **Data Validation & Type Safety:**
|
||
- **TypeScript Interfaces:** All data validated against TypeScript interfaces before Firebase writes
|
||
- **Required Field Validation:** Critical fields (controller name, singer name) validated before operations
|
||
- **Fallback Values:** Default values provided for missing or corrupted data
|
||
- **Type Assertions:** Safe type casting with existence checks
|
||
|
||
### **Error Handling Patterns:**
|
||
- **Service-Level Error Handling:** Each service function includes try-catch with console logging
|
||
- **Hook-Level Error Handling:** Custom hooks include error handling with toast notifications
|
||
- **Graceful Degradation:** App continues to work with cached data during connection issues
|
||
- **Error Boundaries:** React error boundaries for component-level error handling
|
||
- **Connection Monitoring:** Real-time connection status with error state management
|
||
|
||
### **Performance Optimization Patterns:**
|
||
- **Efficient Queries:** Specific node subscriptions instead of full controller subscriptions
|
||
- **Listener Cleanup:** Proper cleanup of Firebase listeners to prevent memory leaks
|
||
- **Batch Operations:** Grouped Firebase updates using `update()` for better performance
|
||
- **Memoized Selectors:** Redux selectors memoized to prevent unnecessary re-computations
|
||
- **Incremental Loading:** Large datasets loaded in chunks via infinite scroll
|
||
|
||
### **Authentication Integration:**
|
||
- **Controller-Based Sessions:** Users connect to specific controller sessions
|
||
- **Admin Parameter Handling:** Admin access via URL parameter with automatic cleanup
|
||
- **Session Persistence:** Authentication state managed in Redux (lost on page reload)
|
||
- **Auto-Initialization:** Empty controller created if none exists for new sessions
|
||
|
||
### **Constants & Configuration:**
|
||
- **Environment Variables:** Firebase config loaded from environment variables with fallbacks
|
||
- **Feature Flags:** Configurable features via constants (ENABLE_SEARCH, ENABLE_QUEUE_REORDER, etc.)
|
||
- **UI Constants:** Centralized constants for toast durations, search delays, item limits
|
||
- **Error Messages:** Centralized error message constants for consistency
|
||
|
||
### **Critical Implementation Details:**
|
||
- **Queue Key Pattern:** Must use sequential numerical keys (0, 1, 2, etc.) - NOT push IDs
|
||
- **Order Management:** Queue items must maintain sequential order with automatic validation
|
||
- **Controller Initialization:** Empty controller structure created if none exists
|
||
- **Listener Management:** All Firebase listeners must be properly cleaned up
|
||
- **Error Recovery:** Graceful handling of Firebase sync failures with retry patterns
|
||
- **Type Safety:** All data must be validated against TypeScript interfaces
|
||
- **Performance:** Use specific node subscriptions instead of full controller subscriptions
|
||
- **Memory Management:** Proper cleanup of observers, listeners, and subscriptions
|
||
|
||
### **Firebase Schema Requirements:**
|
||
- **Controller Structure:** Must match the exact structure defined in `types.ts`
|
||
- **Key Format:** Queue items must use sequential numerical keys
|
||
- **Data Types:** All data must conform to TypeScript interfaces
|
||
- **Required Fields:** Critical fields must be present for operations to succeed
|
||
- **Default Values:** Empty controller must have all required fields with default values
|
||
|
||
### **Migration & Compatibility:**
|
||
- **Key Migration:** Automatic migration of push ID keys to sequential numerical keys
|
||
- **Order Fixing:** Automatic repair of inconsistent queue order values
|
||
- **Backward Compatibility:** Support for existing data with inconsistent keys
|
||
- **Data Validation:** Runtime validation of data structure integrity
|
||
|
||
---
|
||
|
||
## 18️⃣ Critical Implementation Notes
|
||
|
||
### **DO NOT CHANGE These Patterns:**
|
||
- **Queue Key Management:** Sequential numerical keys (0, 1, 2, etc.) - changing this will break queue functionality
|
||
- **Controller Structure:** Exact structure must match `types.ts` - changing will break sync
|
||
- **Service Layer Pattern:** All Firebase operations must go through service modules
|
||
- **Subscription Pattern:** Real-time updates must use subscribe/unsubscribe pattern
|
||
- **Error Handling:** Service-level error handling with console logging must be maintained
|
||
- **Type Safety:** All data validation against TypeScript interfaces must be preserved
|
||
- **Connection Management:** FirebaseProvider pattern with connection status tracking
|
||
- **Cleanup Management:** Proper cleanup of listeners and subscriptions
|
||
|
||
### **Critical Dependencies:**
|
||
- **Firebase Config:** Must be properly configured with environment variables
|
||
- **TypeScript Interfaces:** Must match exactly with Firebase data structure
|
||
- **Redux State:** Must maintain consistency with Firebase data
|
||
- **Service Functions:** Must handle all error cases and provide proper cleanup
|
||
- **Hook Dependencies:** Must include proper dependency arrays for useEffect hooks
|
||
|
||
### **Performance Requirements:**
|
||
- **List Pagination:** All lists must use infinite scroll with 20 items per page
|
||
- **Memory Management:** Proper cleanup of all listeners and observers
|
||
- **Efficient Queries:** Use specific node subscriptions, not full controller subscriptions
|
||
- **Optimistic Updates:** UI updates immediately with rollback on error
|
||
- **Debounced Operations:** Search and filter operations must be debounced
|
||
|
||
### **Error Recovery Patterns:**
|
||
- **Graceful Degradation:** App must continue working with cached data during connection issues
|
||
- **Retry Logic:** Automatic retry for failed Firebase operations
|
||
- **User Feedback:** Clear error messages with recovery options
|
||
- **Data Validation:** Runtime validation with fallback values
|
||
- **Connection Monitoring:** Real-time connection status with error state management
|
||
|
||
---
|
||
|
||
## ✅ Summary
|
||
|
||
This PRD serves as the comprehensive source of truth for application logic, Firebase data flow, and feature requirements.
|
||
It works alongside `types.ts` and `firebase_schema.json` to inform both human developers and AI tools for accurate implementation.
|
||
|
||
**Key Success Metrics:**
|
||
- ✅ **Real-time Sync:** All users see updates within 1 second
|
||
- ✅ **Performance:** App loads in under 3 seconds on mobile
|
||
- ✅ **Reliability:** 99.9% uptime with graceful error handling
|
||
- ✅ **User Experience:** Intuitive interface requiring minimal training
|
||
- ✅ **Scalability:** Supports up to 50 concurrent users per session
|
||
|
||
---
|
||
|
||
## 19️⃣ Environment Configuration & .env.local Setup
|
||
|
||
### **Environment File Structure:**
|
||
The application uses Vite's built-in environment variable support with the following file structure:
|
||
|
||
```
|
||
project-root/
|
||
├── .env.template # Template file with all required variables
|
||
├── .env.local # Local development environment (gitignored)
|
||
├── .env.production # Production environment (if needed)
|
||
└── .env.staging # Staging environment (if needed)
|
||
```
|
||
|
||
### **Required Environment Variables:**
|
||
|
||
#### **Firebase Configuration (Required):**
|
||
```bash
|
||
# Firebase Configuration
|
||
VITE_FIREBASE_API_KEY=your-api-key
|
||
VITE_FIREBASE_AUTH_DOMAIN=your-project-id.firebaseapp.com
|
||
VITE_FIREBASE_DATABASE_URL=https://your-project-id-default-rtdb.firebaseio.com
|
||
VITE_FIREBASE_PROJECT_ID=your-project-id
|
||
VITE_FIREBASE_STORAGE_BUCKET=your-project-id.appspot.com
|
||
VITE_FIREBASE_MESSAGING_SENDER_ID=123456789
|
||
VITE_FIREBASE_APP_ID=your-app-id
|
||
```
|
||
|
||
#### **App Configuration (Optional with defaults):**
|
||
```bash
|
||
# App Configuration
|
||
VITE_CONTROLLER_NAME=default
|
||
VITE_APP_TITLE=SingSalot AI
|
||
```
|
||
|
||
### **Environment Variable Usage Pattern:**
|
||
- **Vite Prefix:** All environment variables must be prefixed with `VITE_` to be accessible in the client-side code
|
||
- **Fallback Values:** All environment variables have fallback values in `src/constants/index.ts`
|
||
- **Type Safety:** Environment variables are accessed via `import.meta.env.VITE_*`
|
||
- **Build-time Injection:** Variables are injected at build time, not runtime
|
||
|
||
### **Configuration Loading Pattern:**
|
||
```typescript
|
||
// src/constants/index.ts
|
||
export const FIREBASE_CONFIG = {
|
||
apiKey: import.meta.env.VITE_FIREBASE_API_KEY || 'your-api-key',
|
||
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN || 'your-project-id.firebaseapp.com',
|
||
databaseURL: import.meta.env.VITE_FIREBASE_DATABASE_URL || 'https://your-project-id-default-rtdb.firebaseio.com',
|
||
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID || 'your-project-id',
|
||
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET || 'your-project-id.appspot.com',
|
||
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID || '123456789',
|
||
appId: import.meta.env.VITE_FIREBASE_APP_ID || 'your-app-id',
|
||
};
|
||
|
||
export const CONTROLLER_NAME = import.meta.env.VITE_CONTROLLER_NAME || 'default';
|
||
```
|
||
|
||
### **Setup Instructions:**
|
||
|
||
#### **1. Initial Setup:**
|
||
```bash
|
||
# Copy the template file
|
||
cp .env.template .env.local
|
||
|
||
# Edit .env.local with your actual Firebase configuration
|
||
nano .env.local
|
||
```
|
||
|
||
#### **2. Firebase Configuration:**
|
||
1. Go to Firebase Console → Project Settings
|
||
2. Copy the configuration values from the "General" tab
|
||
3. Replace the placeholder values in `.env.local`
|
||
|
||
#### **3. Controller Configuration:**
|
||
- `VITE_CONTROLLER_NAME`: Set to your desired controller name (default: "default")
|
||
- `VITE_APP_TITLE`: Set to your desired app title (default: "SingSalot AI")
|
||
|
||
### **Environment-Specific Configurations:**
|
||
|
||
#### **Development (.env.local):**
|
||
```bash
|
||
# Local development with hot reload
|
||
VITE_CONTROLLER_NAME=dev-controller
|
||
VITE_APP_TITLE=SingSalot AI (Dev)
|
||
```
|
||
|
||
#### **Staging (.env.staging):**
|
||
```bash
|
||
# Pre-production testing
|
||
VITE_CONTROLLER_NAME=staging-controller
|
||
VITE_APP_TITLE=SingSalot AI (Staging)
|
||
```
|
||
|
||
#### **Production (.env.production):**
|
||
```bash
|
||
# Live production environment
|
||
VITE_CONTROLLER_NAME=production-controller
|
||
VITE_APP_TITLE=SingSalot AI
|
||
```
|
||
|
||
### **Security Considerations:**
|
||
- **Client-Side Exposure:** All `VITE_*` variables are exposed in the client bundle
|
||
- **Firebase Security:** Firebase API keys are safe to expose in client-side code
|
||
- **Database Rules:** Security is enforced through Firebase Realtime Database Rules
|
||
- **Environment Isolation:** Use different Firebase projects for different environments
|
||
|
||
### **Build Process Integration:**
|
||
- **Development:** Uses `.env.local` automatically when running `npm run dev`
|
||
- **Production Build:** Uses `.env.production` when running `npm run build`
|
||
- **Environment Detection:** Vite automatically detects the correct environment file
|
||
- **Build-time Injection:** Variables are replaced at build time, not runtime
|
||
|
||
### **Error Handling for Missing Variables:**
|
||
- **Fallback Values:** All variables have sensible defaults
|
||
- **Console Warnings:** Missing required variables show console warnings
|
||
- **Graceful Degradation:** App continues to work with fallback values
|
||
- **Development Feedback:** Clear error messages for missing configuration
|
||
|
||
### **Environment Variable Validation:**
|
||
```typescript
|
||
// Validation pattern used in the app
|
||
const validateFirebaseConfig = () => {
|
||
const requiredVars = [
|
||
'VITE_FIREBASE_API_KEY',
|
||
'VITE_FIREBASE_AUTH_DOMAIN',
|
||
'VITE_FIREBASE_DATABASE_URL',
|
||
'VITE_FIREBASE_PROJECT_ID'
|
||
];
|
||
|
||
const missing = requiredVars.filter(varName => !import.meta.env[varName]);
|
||
|
||
if (missing.length > 0) {
|
||
console.warn('Missing Firebase configuration:', missing);
|
||
}
|
||
};
|
||
```
|
||
|
||
### **Deployment Considerations:**
|
||
- **CI/CD Integration:** Environment variables must be set in deployment pipeline
|
||
- **Build Commands:** Different build commands for different environments
|
||
- **Environment Files:** `.env.local` is gitignored, other files may be committed
|
||
- **Secret Management:** Use deployment platform's secret management for production
|
||
|
||
### **Troubleshooting:**
|
||
- **Variable Not Found:** Ensure variable name starts with `VITE_`
|
||
- **Build Issues:** Check that all required variables are set
|
||
- **Runtime Errors:** Verify Firebase configuration is correct
|
||
- **Environment Detection:** Ensure correct `.env` file is being used
|
||
|
||
### **Best Practices:**
|
||
- **Template File:** Always maintain `.env.template` with all required variables
|
||
- **Documentation:** Document all environment variables and their purposes
|
||
- **Validation:** Implement runtime validation for critical configuration
|
||
- **Fallbacks:** Provide sensible default values for all variables
|
||
- **Security:** Never commit sensitive values to version control
|
||
|
||
---
|
||
|
||
## 20️⃣ Development Setup & Configuration
|
||
|