# System Architecture - SamCloud Music

**Version**: 2.0.0  
**Last Updated**: July 1, 2025  
**Purpose**: Complete technical overview of the unified music application

---

## 🏗️ High-Level Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                        SamCloud Music                          │
│                     Unified Music App                          │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Docker Container                           │
│                    (Port 6544 Exposed)                         │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐ │
│  │   Flask Web     │  │   SocketIO      │  │   Static Files  │ │
│  │   Application   │  │   WebSocket     │  │   CSS/JS/HTML   │ │
│  │   (Backend)     │  │   (Real-time)   │  │   (Frontend)    │ │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                      Service Layer                             │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐ │
│  │   Spotify       │  │   Download      │  │   Jellyfin      │ │
│  │   Service       │  │   Service       │  │   Service       │ │
│  │   (Search)      │  │   (SpotDL)      │  │   (Library)     │ │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                    External Systems                            │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐ │
│  │   Spotify API   │  │   File System   │  │   Jellyfin      │ │
│  │   (Music Data)  │  │   (Downloads)   │  │   Server        │ │
│  │                 │  │   /data/*       │  │   (Library)     │ │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```

---

## 🧩 Component Details

### Frontend Layer

#### **Single Page Application (SPA)**
- **File**: `backend/templates/index.html` (3898 lines)
- **Framework**: Vanilla JavaScript + Modern CSS
- **UI Design**: Apple Music-inspired interface
- **Features**:
  - 5-tab navigation (Listen, Library, Search, Downloads, Settings)
  - Real-time WebSocket communication
  - Responsive design for desktop/mobile
  - Dark/light theme support

#### **Tab Structure**
```
┌─────────────┬─────────────┬─────────────┬─────────────┬─────────────┐
│   Listen    │   Library   │   Search    │  Downloads  │  Settings   │
│             │             │             │             │             │
│ Music       │ Personal    │ Spotify     │ Download    │ Server      │
│ Player      │ Library     │ Search      │ Progress    │ Config      │
│ Controls    │ Browser     │ Results     │ History     │ Auth        │
│             │             │             │             │             │
└─────────────┴─────────────┴─────────────┴─────────────┴─────────────┘
```

#### **WebSocket Integration**
- **Library**: Socket.IO client
- **Connection**: `ws://localhost:6544/socket.io`
- **Events**:
  - `search_results` - Spotify search responses
  - `download_progress` - Real-time download updates
  - `download_complete` - Download completion notifications
  - `download_error` - Error handling

### Backend Layer

#### **Flask Application**
- **File**: `backend/spotspot.py` (444 lines)
- **Framework**: Flask + Flask-SocketIO
- **Port**: 6544 (mapped to container)
- **Features**:
  - RESTful API endpoints
  - WebSocket server
  - Static file serving
  - CORS enabled for development

#### **API Endpoints**

**Core Application**:
```
GET  /                     # Main application interface
GET  /static/<path>        # Static assets (CSS, JS, images)
```

**Jellyfin Integration**:
```
POST /api/jellyfin/auth    # Authenticate with Jellyfin server
GET  /api/jellyfin/library # Get library items (songs, albums, artists)
```

**Download System**:
```
GET  /api/downloads/stats  # Download statistics and history
```

**WebSocket Events**:
```
search              # Spotify search request
download_item       # Download request
get_status         # Get current download status
cancel_all         # Cancel all downloads
```

#### **Service Architecture**

**Config Service** (`backend/services/config_service.py`):
- Environment variable management
- Configuration validation
- Default value handling

**Spotify Service** (`backend/services/spotify_service.py`):
- Spotify API authentication
- Search query processing
- Result formatting

**Download Service** (`backend/services/download_service.py`):
- SpotDL integration
- Progress tracking
- File organization
- Output template management

**Jellyfin Service** (`backend/services/jellyfin_service.py`):
- Jellyfin API authentication
- Library browsing
- Stream URL generation
- Metadata processing

**Playlist Manager** (`backend/services/playlist_manager.py`):
- M3U playlist generation
- Library organization
- Metadata management

### Data Flow

#### **Search Workflow**
```
1. User Input → Frontend JavaScript
2. WebSocket Event → Flask-SocketIO
3. Spotify Service → Spotify API
4. Results Processing → Frontend Display
5. Download Request → Download Service
6. Progress Updates → WebSocket → Frontend
```

#### **Library Workflow**  
```
1. Settings Configuration → localStorage
2. Authentication Request → Jellyfin Service
3. Library Fetch → Jellyfin API
4. Data Processing → Frontend Display
5. Track Selection → Music Player
6. Stream URL → Audio Element
```

#### **Download Workflow**
```
1. Search Result Selection → Download Request
2. Download Service → SpotDL Process
3. Progress Parsing → WebSocket Updates
4. File Processing → Output Organization
5. Completion → Jellyfin Library Scan
6. Notification → Frontend Toast
```

---

## 🐳 Docker Configuration

### Container Setup

**Base Image**: Python 3.8+ with system dependencies
**Exposed Port**: 6544
**Working Directory**: `/app`

#### **Volume Mounts**
```yaml
volumes:
  - /Volumes/Jellyfin Media/Music:/data          # Final music files
  - /Volumes/Jellyfin Media/Music/temp:/temp     # Temporary processing
  - /Volumes/SamMgmt/Containers/SpotSpot/config:/config  # Configuration
  - /Volumes/SamMgmt/Containers/SamCloud Music/backend/templates:/app/backend/templates
  - /etc/localtime:/etc/localtime:ro             # Time synchronization
```

#### **Environment Variables**
```bash
# Application Configuration
PYTHONUNBUFFERED=1
HOST=0.0.0.0
PORT=6544
FLASK_ENV=production

# Download Templates
TRACK_OUTPUT='/data/{artist}/{album} - ({year})/{artist} - {title}.{output-ext}'
ALBUM_OUTPUT='/data/{artist}/{album} - ({year})/{artist} - {title}.{output-ext}'
PLAYLIST_OUTPUT='/data/{list-name}/{artist}/{title}.{output-ext}'
ARTIST_OUTPUT='/data/{artist}/{album} - ({year})/{artist} - {title}.{output-ext}'

# External Services
JELLYFIN_ADDRESS=https://jellyfin.samcloud.ca
JELLYFIN_API_KEY=dbde543b76b6475489c68aa75d835627
SPOTIFY_CLIENT_ID=e4e0acf2732b4158b3cb72e70961f8ae
SPOTIFY_CLIENT_SECRET=ab0c1626e8154ff3afcec25627877397
```

### Network Configuration

**Host Access**: `localhost:6544`
**Container Internal**: `192.168.148.2:6544`
**WebSocket**: Same port with `/socket.io` path
**CORS**: Enabled for all origins (development mode)

---

## 🗄️ Data Management

### File Organization

#### **Downloaded Music Structure**
```
/data/
├── {artist}/
│   └── {album} - ({year})/
│       ├── {artist} - {title}.mp3
│       ├── {artist} - {title}.mp3
│       └── ...
├── playlists/
│   └── {playlist-name}/
│       ├── {artist}/
│       │   └── {title}.mp3
│       └── ...
└── temp/
    └── (processing files)
```

#### **Configuration Files**
```
/config/
├── config.json          # Application settings
├── spotify_cache/       # Spotify API cache
└── download_history/    # Download tracking
```

### Database Strategy

**Current**: File-based storage
- Configuration: JSON files
- Download history: In-memory + file backup
- Library cache: localStorage (browser) + server memory

**Future Consideration**: SQLite for:
- Download history persistence
- User preferences
- Playlist management
- Analytics tracking

---

## 🔗 External Integrations

### Spotify Web API

**Authentication**: Client Credentials Flow
**Rate Limits**: 100 requests per minute
**Endpoints Used**:
- Search tracks, albums, artists, playlists
- Get track details and metadata
- Album artwork URLs

**Data Transformation**:
```javascript
// Spotify Response → Internal Format
{
  id: spotify_id,
  name: track_name,
  artist: artist_name,
  image: album_artwork_url,
  url: spotify_track_url,
  duration: duration_ms,
  explicit: explicit_flag
}
```

### Jellyfin Media Server

**Authentication**: Username/Password → Access Token
**API Version**: 10.8.x compatible
**Endpoints Used**:
- `/System/Info/Public` - Server information
- `/Users/authenticatebyname` - User authentication
- `/Users/{userId}/Items` - Library browsing
- `/Audio/{itemId}/stream` - Audio streaming

**Data Transformation**:
```javascript
// Jellyfin Response → Internal Format
{
  id: jellyfin_id,
  name: track_name,
  artist: artist_names_joined,
  album: album_name,
  duration: runtime_seconds,
  image_url: server_artwork_url,
  stream_url: server_stream_url
}
```

### SpotDL Integration

**Tool**: `spotdl` Python package
**Download Engine**: YouTube-DL backend
**Audio Quality**: 320kbps MP3 (configurable)
**Metadata**: ID3 tags with album artwork

**Progress Parsing**:
```python
# Progress Patterns Detected
"Searching for {track}" → stage: searching
"Downloading {track}" → stage: downloading  
"Converting {track}" → stage: processing
"Downloaded {track}" → stage: complete
```

---

## 🔧 Configuration Management

### Environment Files

#### **Primary Config** (`.env`)
```bash
# Spotify API (Required)
SPOTIFY_CLIENT_ID=xxx
SPOTIFY_CLIENT_SECRET=xxx

# Jellyfin Integration (Optional)
JELLYFIN_ADDRESS=https://jellyfin.samcloud.ca
JELLYFIN_API_KEY=xxx

# Application Settings
HOST=0.0.0.0
PORT=6544
DEBUG=true
```

#### **Docker Compose** (`docker-compose.yml`)
```yaml
version: '3.8'
services:
  samcloud-music:
    build: .
    container_name: samcloud-music
    ports:
      - "6544:6544"
    env_file:
      - .env
    volumes:
      - /Volumes/Jellyfin Media/Music:/data
      - /Volumes/SamMgmt/Containers/SpotSpot/config:/config
    restart: unless-stopped
```

### Runtime Configuration

**Frontend Storage** (localStorage):
```javascript
// Jellyfin Settings
musicServerType: 'jellyfin'
musicServerUrl: 'https://jellyfin.samcloud.ca'
musicServerUsername: 'user'
musicServerPassword: 'encrypted'
musicServerConnected: 'true'
musicServerName: 'server_name'
```

**Backend Storage** (JSON files):
```json
// /config/config.json
{
  "spotify": {
    "client_id": "xxx",
    "client_secret": "xxx"
  },
  "download": {
    "output_dir": "/data",
    "temp_dir": "/temp",
    "quality": "320k"
  }
}
```

---

## 🚀 Performance Considerations

### Frontend Performance

**Bundle Size**: Single HTML file (~3.9k lines)
- **Pros**: No build process, simple deployment
- **Cons**: Large initial load, no code splitting
- **Future**: Consider module bundling for production

**WebSocket Efficiency**:
- Connection pooling: Single persistent connection
- Event throttling: Progress updates limited to reasonable frequency
- Error handling: Automatic reconnection with exponential backoff

### Backend Performance

**Flask Threading**: 
- Mode: Threading (not async)
- Concurrent requests: Limited by Python GIL
- Future: Consider async/await with FastAPI

**Memory Usage**:
- Download progress: In-memory tracking
- Library cache: Temporary storage
- File processing: Streaming where possible

**Bottlenecks Identified**:
1. SpotDL download process (CPU intensive)
2. Large library loading (API response size)
3. WebSocket message frequency (progress updates)

### Scaling Considerations

**Current Limits**:
- Single user concurrent downloads: ~5
- Library size: Tested up to 1000+ tracks
- Container resources: 1CPU, 1GB RAM typical

**Future Scaling**:
- Download queue management
- Database backend for persistence  
- Load balancing for multiple users
- CDN for static assets

---

## 🔐 Security Model

### Authentication Flow

**Jellyfin Integration**:
```
1. User credentials → Frontend localStorage
2. Authentication request → Jellyfin API
3. Access token → Backend storage (memory)
4. API requests → Token-authenticated
5. Token refresh → Automatic background
```

**Security Measures**:
- Credentials stored in browser localStorage (encrypted)
- No plaintext passwords in backend logs
- API tokens have limited lifetime
- HTTPS required for external Jellyfin server

### Network Security

**Development Mode** (Current):
- CORS: Enabled for all origins
- HTTP: Acceptable for localhost
- Container isolation: Standard Docker security

**Production Considerations**:
- HTTPS: SSL/TLS certificates required
- CORS: Restricted to specific origins
- Reverse proxy: Nginx/Apache frontend
- Authentication: Session management

### Data Protection

**Personal Information**:
- No user data stored permanently
- Music files: Read-only access
- Configuration: Local storage only
- API keys: Environment variables

**External API Security**:
- Spotify: OAuth client credentials
- Jellyfin: User authentication required
- Rate limiting: Built into external services

---

**Architecture Document Version**: 2.0.0  
**Last Technical Review**: July 1, 2025  
**Next Review Scheduled**: After major feature additions or performance issues
