Big commit whatever
This commit is contained in:
+595
@@ -0,0 +1,595 @@
|
||||
# 🏗️ Jukebox Project Architecture
|
||||
|
||||
## System Overview Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ JUKEBOX MUSIC APPLICATION │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌──────────────────────────────┐ ┌──────────────────────────────┐
|
||||
│ 📱 MOBILE APP (EXPO) │ │ 🌐 WEB ADMIN PANEL │
|
||||
│ React Native 0.81.5 │ │ React 19.2.0 + Vite │
|
||||
└──────────────────────────────┘ └──────────────────────────────┘
|
||||
│ │
|
||||
│ HTTP/REST API │
|
||||
│ (Bearer Token Auth) │
|
||||
└────────────────┬────────────────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ 🔌 LARAVEL │
|
||||
│ API │
|
||||
│ Backend │
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ 🗄️ MySQL │
|
||||
│ Database │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mobile App Architecture (React Native)
|
||||
|
||||
```
|
||||
App.js (Root)
|
||||
│
|
||||
├─ PlayerProvider Context
|
||||
│ └─ { currentTrack, isPlaying, ... }
|
||||
│
|
||||
└─ LibraryProvider Context
|
||||
├─ albums (state from mock data)
|
||||
├─ likedTracks (computed)
|
||||
├─ toggleLike() (function)
|
||||
│
|
||||
└─ SafeAreaProvider
|
||||
│
|
||||
└─ AppNavigator (Stack Navigator)
|
||||
│
|
||||
├─ HomeScreen
|
||||
│ ├─ Header (with icons)
|
||||
│ ├─ Liked Tracks Preview (top 5)
|
||||
│ └─ Albums Grid (2 columns)
|
||||
│
|
||||
├─ AlbumScreen
|
||||
│ ├─ Album Info (cover, title, artist)
|
||||
│ └─ TrackRow List
|
||||
│ └─ TrackRow Component (with heart)
|
||||
│
|
||||
├─ LikedTracksScreen
|
||||
│ ├─ Search Input
|
||||
│ ├─ Sort Controls
|
||||
│ └─ FlatList of Tracks
|
||||
│
|
||||
├─ LoginScreen
|
||||
│ ├─ Email Input
|
||||
│ ├─ Password Input
|
||||
│ └─ Navigation Links
|
||||
│
|
||||
├─ SignUpScreen
|
||||
├─ PasswordResetScreen
|
||||
└─ SettingsScreen
|
||||
├─ Notification Toggle
|
||||
├─ Audio Quality Toggle
|
||||
└─ Logout Button
|
||||
|
||||
MediaPlayer Component (Floating)
|
||||
└─ Shows current track + play controls
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Flow (Current - Mock Data)
|
||||
|
||||
```
|
||||
app.json (expo config)
|
||||
│
|
||||
index.js → App.js
|
||||
│
|
||||
├─ PlayerProvider
|
||||
│ └─ { currentTrack, isPlaying }
|
||||
│
|
||||
└─ LibraryProvider
|
||||
│
|
||||
├─ useState(initialLibrary)
|
||||
│ └─ src/data/library.js ◄─── MOCK DATA
|
||||
│ ├─ Album 1: Swans (26 tracks)
|
||||
│ └─ Album 2: Daft Punk (14 tracks)
|
||||
│
|
||||
├─ useMemo(likedTracks)
|
||||
│ └─ Filters albums.flatMap(album.tracks).filter(liked)
|
||||
│
|
||||
└─ toggleLike(albumId, trackId)
|
||||
└─ Updates album.tracks[].liked status
|
||||
|
||||
HomeScreen ──┐
|
||||
AlbumScreen ├─► useLibrary() ──► Read-only access to:
|
||||
LikedTracks │ • albums
|
||||
LoginScreen ─┘ • likedTracks
|
||||
• Call toggleLike()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Flow (Future - With API Integration)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ BACKEND API (Laravel) │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ GET /api/albums │
|
||||
│ GET /api/albums/{id} │
|
||||
│ GET /api/tracks │
|
||||
│ POST /api/login │
|
||||
│ POST /api/tracks/{id}/like │
|
||||
│ GET /api/me/likes │
|
||||
└─────────────────────────────────────────────┘
|
||||
▲
|
||||
│
|
||||
LibraryContext (FUTURE)
|
||||
├─ useEffect(() => {
|
||||
│ fetch('/api/albums')
|
||||
│ .then(data => setAlbums(data))
|
||||
│ }, [])
|
||||
│
|
||||
├─ toggleLike() → API call instead
|
||||
│
|
||||
└─ All screens read from state
|
||||
(same as before, but data from API)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Hierarchy
|
||||
|
||||
```
|
||||
App.js
|
||||
│
|
||||
└─ AppNavigator (Stack)
|
||||
│
|
||||
├─ HomeScreen
|
||||
│ ├─ Header
|
||||
│ │ ├─ Title
|
||||
│ │ └─ Icon buttons (Person, Settings)
|
||||
│ │
|
||||
│ ├─ Pressable (navigate to LikedTracks)
|
||||
│ │ └─ Section title
|
||||
│ │
|
||||
│ ├─ Map (liked tracks)
|
||||
│ │ └─ TrackRow ✕ 5
|
||||
│ │
|
||||
│ └─ FlatList (albums grid)
|
||||
│ └─ Album Item ✕ N
|
||||
│
|
||||
├─ AlbumScreen
|
||||
│ ├─ Back Button
|
||||
│ ├─ Album Header
|
||||
│ │ ├─ Image (album cover)
|
||||
│ │ ├─ Title
|
||||
│ │ ├─ Artist
|
||||
│ │ └─ Meta (date, label, duration)
|
||||
│ │
|
||||
│ └─ FlatList (tracks)
|
||||
│ └─ TrackRow ✕ N
|
||||
│
|
||||
├─ LikedTracksScreen
|
||||
│ ├─ Back Button
|
||||
│ ├─ Header
|
||||
│ ├─ TextInput (search)
|
||||
│ ├─ Sort Controls
|
||||
│ │ ├─ Dropdown (sortBy)
|
||||
│ │ └─ Toggle (direction)
|
||||
│ │
|
||||
│ └─ FlatList
|
||||
│ └─ TrackRow ✕ N
|
||||
│
|
||||
├─ LoginScreen
|
||||
├─ SignUpScreen
|
||||
├─ PasswordResetScreen
|
||||
└─ SettingsScreen
|
||||
|
||||
└─ MediaPlayer (Floating)
|
||||
├─ Track info (text)
|
||||
├─ Progress bar (Slider)
|
||||
│ └─ Time stamps
|
||||
│
|
||||
└─ Play/Pause button
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## State Management Strategy
|
||||
|
||||
### Global State (Contexts)
|
||||
|
||||
```javascript
|
||||
// 1. PlayerProvider (App.js)
|
||||
{
|
||||
currentTrack: Track | null,
|
||||
isPlaying: boolean,
|
||||
setCurrentTrack: (track) => void,
|
||||
setIsPlaying: (bool) => void
|
||||
}
|
||||
|
||||
// 2. LibraryProvider (LibraryContext.js)
|
||||
{
|
||||
albums: Album[],
|
||||
likedTracks: Track[] (computed),
|
||||
toggleLike: (albumId, trackId) => void
|
||||
}
|
||||
```
|
||||
|
||||
### Local State (Components)
|
||||
|
||||
```javascript
|
||||
// HomeScreen
|
||||
None (all from context)
|
||||
|
||||
// AlbumScreen
|
||||
None (all from context & route params)
|
||||
|
||||
// LikedTracksScreen
|
||||
{
|
||||
query: string (search),
|
||||
sortBy: 'dateAdded' | 'name' | 'length',
|
||||
sortDir: 'asc' | 'desc',
|
||||
showSortMenu: boolean
|
||||
}
|
||||
|
||||
// LoginScreen
|
||||
{
|
||||
email: string,
|
||||
password: string
|
||||
}
|
||||
|
||||
// SettingsScreen
|
||||
{
|
||||
notificationsEnabled: boolean,
|
||||
highQuality: boolean
|
||||
}
|
||||
|
||||
// MediaPlayer
|
||||
{
|
||||
isPlaying: boolean,
|
||||
progress: number (0-100)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Navigation Stack
|
||||
|
||||
```
|
||||
┌────────────────────────────────────┐
|
||||
│ React Navigation Stack │
|
||||
├────────────────────────────────────┤
|
||||
│ Navigator: createNativeStackNavigator()
|
||||
│ Options: headerShown = false
|
||||
│
|
||||
├─ Screen: "Home" → HomeScreen
|
||||
├─ Screen: "LikedTracks" → LikedTracksScreen
|
||||
├─ Screen: "Album" → AlbumScreen
|
||||
│ params: { album: Album }
|
||||
├─ Screen: "SignUp" → SignUpScreen
|
||||
├─ Screen: "Login" → LoginScreen
|
||||
├─ Screen: "PasswordReset"→ PasswordResetScreen
|
||||
└─ Screen: "Settings" → SettingsScreen
|
||||
```
|
||||
|
||||
### Navigation Methods
|
||||
|
||||
```javascript
|
||||
// From any screen with useNavigation hook:
|
||||
|
||||
navigation.navigate('Album', { album })
|
||||
navigation.navigate('LikedTracks')
|
||||
navigation.navigate('Login')
|
||||
navigation.navigate('Settings')
|
||||
navigation.goBack()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Admin Panel Architecture (React Web)
|
||||
|
||||
```
|
||||
admin_panel/
|
||||
│
|
||||
├─ main.jsx
|
||||
│ └─ ReactDOM.createRoot()
|
||||
│ │
|
||||
│ └─ BrowserRouter
|
||||
│ │
|
||||
│ └─ App.jsx
|
||||
│ │
|
||||
│ ├─ AuthProvider
|
||||
│ │ ├─ token (from localStorage)
|
||||
│ │ ├─ user (from localStorage)
|
||||
│ │ ├─ login() function
|
||||
│ │ └─ logout() function
|
||||
│ │
|
||||
│ └─ Routes
|
||||
│ │
|
||||
│ ├─ Route: "/login"
|
||||
│ │ └─ LoginPage
|
||||
│ │
|
||||
│ └─ ProtectedRoute (requires token)
|
||||
│ │
|
||||
│ ├─ Route: "/albums"
|
||||
│ │ └─ AlbumsPage (stub)
|
||||
│ │
|
||||
│ ├─ Route: "/albums/:albumId/tracks"
|
||||
│ │ └─ AlbumTracksPage (stub)
|
||||
│ │
|
||||
│ └─ Route: "/users"
|
||||
│ └─ UsersPage (stub)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Integration Layer
|
||||
|
||||
### Admin Panel API Client (`services/api.js`)
|
||||
|
||||
```javascript
|
||||
const api = {
|
||||
// Albums (all return Promise)
|
||||
getAlbums(), // GET /albums
|
||||
getAlbumById(id), // GET /albums/{id}
|
||||
addAlbum(data), // POST /albums
|
||||
updateAlbum(id, data), // PUT /albums/{id}
|
||||
deleteAlbum(id), // DELETE /albums/{id}
|
||||
|
||||
// Tracks
|
||||
addTrack(data), // POST /tracks
|
||||
updateTrack(id, data), // PUT /tracks/{id}
|
||||
deleteTrack(id), // DELETE /tracks/{id}
|
||||
reorderTracks(albumId, positions),
|
||||
|
||||
// Upload
|
||||
uploadImage(file), // POST /upload/image
|
||||
uploadAudio(file), // POST /upload/audio
|
||||
|
||||
// Artists & Genres
|
||||
getArtists(), addArtist(),
|
||||
getGenres(), addGenre(),
|
||||
|
||||
// Users (admin only)
|
||||
getUsers(),
|
||||
updateUser(id, data),
|
||||
deleteUser(id)
|
||||
}
|
||||
```
|
||||
|
||||
### Authentication Flow
|
||||
|
||||
```
|
||||
1. User inputs email/password
|
||||
↓
|
||||
2. POST /api/login
|
||||
├─ Response: { token: "1|abc...", user: {...} }
|
||||
↓
|
||||
3. Store in localStorage
|
||||
├─ token: "1|abc..."
|
||||
├─ user: {...}
|
||||
↓
|
||||
4. Include in all requests
|
||||
└─ Header: "Authorization: Bearer 1|abc..."
|
||||
|
||||
5. On 401 response
|
||||
└─ Clear localStorage & redirect to /login
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Database Schema (Simplified)
|
||||
|
||||
```
|
||||
Users
|
||||
├─ id (PK)
|
||||
├─ name
|
||||
├─ email (unique)
|
||||
├─ password_hash
|
||||
├─ role_id (FK)
|
||||
├─ created_at
|
||||
└─ updated_at
|
||||
├─ has_many: Likes (through likes table)
|
||||
└─ belongs_to: Role
|
||||
|
||||
Albums
|
||||
├─ id (PK)
|
||||
├─ title
|
||||
├─ cover_path
|
||||
├─ release_date
|
||||
├─ duration_seconds
|
||||
├─ label_id (FK)
|
||||
└─ has_many: Tracks
|
||||
|
||||
Tracks
|
||||
├─ id (PK)
|
||||
├─ title
|
||||
├─ file_path
|
||||
├─ duration_seconds
|
||||
├─ album_id (FK)
|
||||
├─ belongs_to_many: Artists
|
||||
├─ belongs_to_many: Genres
|
||||
└─ belongs_to_many: Users (likes table)
|
||||
|
||||
Artists
|
||||
├─ id (PK)
|
||||
├─ name
|
||||
├─ label_id (FK)
|
||||
└─ belongs_to_many: Tracks
|
||||
|
||||
Genres
|
||||
├─ id (PK)
|
||||
├─ name
|
||||
└─ belongs_to_many: Tracks
|
||||
|
||||
Labels
|
||||
├─ id (PK)
|
||||
├─ name
|
||||
├─ has_many: Artists
|
||||
└─ has_many: Albums
|
||||
|
||||
Roles
|
||||
├─ id (PK)
|
||||
├─ name ('admin' or 'user')
|
||||
└─ has_many: Users
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependency Tree
|
||||
|
||||
```
|
||||
Mobile App (React Native)
|
||||
├─ react 19.1.0
|
||||
├─ react-native 0.81.5
|
||||
├─ expo 54.0.33
|
||||
│ ├─ expo-linear-gradient
|
||||
│ ├─ expo-vector-icons
|
||||
│ ├─ expo-status-bar
|
||||
│ ├─ expo-av (NOT YET INSTALLED - needed for audio)
|
||||
│ └─ ...
|
||||
├─ @react-navigation/native 7.1.31
|
||||
│ ├─ @react-navigation/native-stack 7.14.2
|
||||
│ └─ @react-navigation/stack 7.8.2
|
||||
├─ react-native-reanimated 4.1.1
|
||||
├─ react-native-safe-area-context 5.6.0
|
||||
├─ rn-inkpad 1.1.0
|
||||
└─ react-native-vector-icons 10.3.0
|
||||
|
||||
Admin Panel (React Web)
|
||||
├─ react 19.2.0
|
||||
├─ react-dom 19.2.0
|
||||
├─ react-router-dom 7.13.1
|
||||
├─ vite 7.3.1
|
||||
└─ tailwindcss 4.0.0
|
||||
|
||||
Backend (Laravel)
|
||||
├─ laravel/framework
|
||||
├─ laravel/sanctum (authentication)
|
||||
├─ composer (PHP dependency manager)
|
||||
└─ mysql (database)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Current Issues
|
||||
```
|
||||
❌ No pagination - all albums/tracks loaded at once
|
||||
❌ No caching - re-fetches on every mount
|
||||
❌ No image optimization - full-res images
|
||||
❌ No lazy loading - all screens bundled
|
||||
❌ No code splitting - entire app in one JS bundle
|
||||
```
|
||||
|
||||
### Optimization Opportunities
|
||||
```
|
||||
✅ Add pagination to API (limit: 20, offset)
|
||||
✅ Implement React Query / SWR for caching
|
||||
✅ Use Image.cache() or similar for images
|
||||
✅ Code split screens with React.lazy()
|
||||
✅ Use FlatList/VirtualizedList keyExtractor efficiently
|
||||
✅ Memoize expensive computations (useMemo)
|
||||
✅ Debounce search input
|
||||
✅ Cache API responses in AsyncStorage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment Architecture (Future)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Apple App Store / Google Play │
|
||||
│ (Built from React Native) │
|
||||
└──────────────────┬──────────────────────┘
|
||||
│
|
||||
│ HTTPS API calls
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Production API Server (Laravel) │
|
||||
├─────────────────────────────────────────┤
|
||||
│ - Environment: Ubuntu/CentOS Linux │
|
||||
│ - Server: Nginx + PHP-FPM │
|
||||
│ - Database: MySQL 8.0 │
|
||||
│ - Cache: Redis (optional) │
|
||||
│ - SSL: Let's Encrypt HTTPS │
|
||||
└────────────┬────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────┐
|
||||
│ MySQL DB │
|
||||
└────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Current
|
||||
```
|
||||
✅ Bearer token authentication (Sanctum)
|
||||
✅ Password hashing
|
||||
✅ HTTPS ready (needs SSL cert in production)
|
||||
```
|
||||
|
||||
### Missing
|
||||
```
|
||||
❌ CORS configuration (using Sanctum defaults)
|
||||
❌ Rate limiting
|
||||
❌ API request validation/sanitization
|
||||
❌ SQL injection prevention (use Eloquent ORM - good!)
|
||||
❌ XSS prevention headers
|
||||
❌ Token refresh mechanism
|
||||
❌ Logout from all devices feature
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Checklist
|
||||
|
||||
```
|
||||
PHASE 1: API Integration
|
||||
[ ] Connect HomeScreen to GET /api/albums
|
||||
[ ] Connect AlbumScreen to GET /api/albums/{id}
|
||||
[ ] Connect LoginScreen to POST /api/login
|
||||
[ ] Store token & user in AsyncStorage
|
||||
[ ] Add error handling for API failures
|
||||
|
||||
PHASE 2: Authentication
|
||||
[ ] Implement token refresh logic
|
||||
[ ] Add logout functionality
|
||||
[ ] Persist login state across app restart
|
||||
[ ] Redirect to login on 401 response
|
||||
|
||||
PHASE 3: Audio Playback
|
||||
[ ] Install expo-av package
|
||||
[ ] Implement TrackPlayer service
|
||||
[ ] Connect MediaPlayer to real playback
|
||||
[ ] Handle audio focus on mobile
|
||||
|
||||
PHASE 4: Admin Panel
|
||||
[ ] Implement AlbumsPage.jsx
|
||||
[ ] Implement AlbumTracksPage.jsx
|
||||
[ ] Implement UsersPage.jsx
|
||||
[ ] Add file upload handling
|
||||
|
||||
PHASE 5: Polish
|
||||
[ ] Add loading indicators
|
||||
[ ] Add error boundaries
|
||||
[ ] Implement search/filter on backend
|
||||
[ ] Add pagination
|
||||
[ ] Add offline mode
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Architecture Version**: 1.0
|
||||
**Last Updated**: May 12, 2026
|
||||
**Status**: Pre-integration phase
|
||||
Reference in New Issue
Block a user