Files
gh-christianlouis-quizzical…/docs/developer-guide/architecture.md
T
Christian Krakau-Louis 204941a1dc Add comprehensive documentation for Quizzical Beats
- Created a detailed database schema document outlining tables, relationships, and key fields.
- Added OAuth integration documentation covering Spotify and Dropbox authentication processes.
- Introduced a FAQ section addressing common user inquiries about the application.
- Developed a user-friendly index page for easy navigation of the documentation.
- Specified documentation dependencies in requirements.txt for building the documentation site.
- Expanded user guide with sections on account management, creating rounds, exporting rounds, getting started, importing songs, and user interface navigation.
- Updated mkdocs.yml for improved site structure and navigation.
2025-05-13 11:25:20 +02:00

285 lines
9.5 KiB
Markdown

# Architecture Overview
This document provides a comprehensive overview of the Quizzical Beats architecture, designed to help developers understand the system structure and components.
## Application Structure
Quizzical Beats follows a modular Flask application structure:
```
musicround/
├── __init__.py # Application factory
├── config.py # Configuration management
├── models.py # Database models
├── version.py # Version information
├── errors.py # Error handling
├── deezer_client.py # Deezer API integration
├── helpers/ # Utility modules
│ ├── __init__.py
│ ├── auth_helpers.py # Authentication utilities
│ ├── backup_helper.py # Backup management
│ ├── dropbox_helper.py # Dropbox integration
│ ├── email_helper.py # Email functionality
│ ├── import_helper.py # Song import utilities
│ ├── metadata.py # Song metadata processing
│ ├── spotify_direct.py # Spotify API client
│ └── utils.py # General utilities
├── mp3/ # Audio file storage
├── routes/ # Route definitions
│ ├── __init__.py
│ ├── api.py # API endpoints
│ ├── auth.py # Authentication routes
│ ├── core.py # Core application routes
│ ├── db_admin.py # Database administration
│ ├── deezer_routes.py # Deezer integration
│ ├── generate.py # Content generation
│ ├── import.py # Generic import functionality
│ ├── import_routes.py # Import interface routes
│ ├── import_songs.py # Song import functionality
│ ├── process.py # Audio processing
│ ├── rounds.py # Quiz round management
│ └── users.py # User account management
├── static/ # Static files (CSS, JS, images)
└── templates/ # Jinja2 HTML templates
├── admin/ # Admin interface templates
├── auth/ # Authentication templates
└── ... (other template categories)
```
## Key Components
### Application Factory
The application is initialized using a factory pattern in `__init__.py`. This allows for flexible configuration and testing:
```python
def create_app():
app = Flask(__name__)
# Load configuration
app.config.from_object(Config)
# Initialize extensions
db.init_app(app)
login_manager.init_app(app)
# Register blueprints
from musicround.routes import core, auth, rounds, users, import_songs, import_routes, generate, process, api, deezer_routes, db_admin
app.register_blueprint(core.bp)
app.register_blueprint(auth.bp)
app.register_blueprint(rounds.bp)
app.register_blueprint(users.bp)
app.register_blueprint(import_songs.bp)
app.register_blueprint(import_routes.bp)
app.register_blueprint(generate.bp)
app.register_blueprint(process.bp)
app.register_blueprint(api.bp)
app.register_blueprint(deezer_routes.bp)
app.register_blueprint(db_admin.bp)
return app
```
### Configuration Management
Configuration is handled in `config.py` using environment variables loaded from a `.env` file:
```python
class Config:
# Core configuration
DEBUG = os.getenv("DEBUG", "True") == "True"
SECRET_KEY = os.getenv('SECRET_KEY', 'dev-key-please-change')
# API keys for various services
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
DEEPL_API_KEY = os.getenv("DEEPL_API_KEY")
MEANINGCLOUD_API_KEY = os.getenv("MEANINGCLOUD_API_KEY")
LASTFM_API_KEY = os.getenv("LASTFM_API_KEY")
# Database configuration
SQLALCHEMY_DATABASE_URI = os.environ.get('SQLALCHEMY_DATABASE_URI', 'sqlite:///data/song_data.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
# OAuth provider configurations
SPOTIFY_CLIENT_ID = os.getenv("SPOTIFY_CLIENT_ID")
SPOTIFY_CLIENT_SECRET = os.getenv("SPOTIFY_CLIENT_SECRET")
DROPBOX_APP_KEY = os.getenv("DROPBOX_APP_KEY")
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
# ... other configuration
```
### Database Models
The data model is defined in `models.py` using SQLAlchemy ORM:
```python
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=True)
password_hash = db.Column(db.String(128))
is_admin = db.Column(db.Boolean, default=False)
rounds = db.relationship('Round', backref='author', lazy=True)
# OAuth tokens and preferences
class Song(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
artist = db.Column(db.String(200), nullable=False)
spotify_id = db.Column(db.String(50), nullable=True)
preview_url = db.Column(db.String(255), nullable=True)
year = db.Column(db.Integer, nullable=True)
# Audio features and metadata
class Round(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
songs = db.relationship('RoundSong', backref='round', lazy=True, cascade="all, delete-orphan")
# Round configuration and settings
```
### Authentication System
The authentication system supports:
1. **Local Authentication**: Username/password authentication
2. **OAuth Providers**:
- Spotify
- Google
- Authentik (OpenID Connect)
3. **Role-Based Access Control**: Admin vs. regular users
OAuth integration is handled through dedicated helper functions in `auth_helpers.py`:
```python
def get_spotify_oauth():
# Configure OAuth for Spotify
def get_google_oauth():
# Configure OAuth for Google
def get_authentik_oauth():
# Configure OAuth for Authentik
```
### External Integrations
#### Spotify Integration
The `spotify_direct.py` module provides:
- Authentication with Spotify API
- Playlist import functionality
- Track search and metadata retrieval
- Audio feature access
#### Dropbox Integration
The `dropbox_helper.py` module enables:
- OAuth authentication with Dropbox
- File export to Dropbox
- Folder management in Dropbox
- Shared link generation
#### Deezer Integration
The `deezer_client.py` and related routes provide:
- Authentication with Deezer API
- Playlist import
- Track search and preview access
#### OpenAI Integration
AI-powered features use the OpenAI API for:
- Round generation suggestions
- Lyric analysis
- Song categorization
### Backup System
The backup system in `backup_helper.py` provides:
```python
def create_backup(include_mp3=True, include_config=True, backup_name=None):
# Create ZIP archive with database and optional files
def restore_from_backup(backup_file, force=False):
# Restore system from backup archive
def list_backups():
# List available backups with metadata
def verify_backup(backup_path):
# Check backup integrity
```
Features include:
- Database dumps using SQLite backup API
- MP3 file inclusion in backups
- Configuration file backup
- Scheduled backups
- Retention policy management
## Request Flow
1. Request arrives at the Flask application
2. Blueprint routes direct to the appropriate view function
3. Authentication middleware checks for required permissions
4. View function processes the request:
- Database queries via SQLAlchemy models
- External API calls where needed
- Business logic processing
5. Response is rendered using Jinja2 templates
6. Rendered HTML is returned to the client
### Example Routes
```python
@bp.route('/rounds/<int:round_id>')
@login_required
def view_round(round_id):
round = Round.query.get_or_404(round_id)
# Check permissions
# Process data
return render_template('rounds/view.html', round=round)
@bp.route('/rounds/<int:round_id>/export-to-dropbox', methods=['POST'])
@login_required
def export_to_dropbox(round_id):
round = Round.query.get_or_404(round_id)
# Check permissions
# Export to Dropbox
return jsonify({'success': True, 'message': 'Export successful'})
```
## System Health Monitoring
The health monitoring system provides dashboards for:
1. **Database Health**: Connection status, table counts, size
2. **Storage Health**: Directory status, file counts, permissions
3. **External Service Status**: API connectivity checks
4. **Version Information**: Application version, dependencies
## Extension Points
To extend Quizzical Beats, consider these integration points:
1. **New OAuth Providers**: Add provider configuration in `auth_helpers.py`
2. **Additional Export Formats**: Implement in the rounds routes
3. **New Music Data Sources**: Create a new client module similar to `spotify_direct.py` or `deezer_client.py`
4. **Custom Audio Processing**: Extend the functionality in the `process.py` routes
5. **AI Features**: Enhance OpenAI integration for additional content generation
## Technology Stack
- **Backend**: Python 3.8+, Flask 2.x
- **Database**: SQLAlchemy 1.4+ with SQLite/PostgreSQL/MySQL
- **Frontend**: TailwindCSS, Alpine.js, vanilla JavaScript
- **Authentication**: Flask-Login, OAuth integrations
- **APIs**: Spotify, Deezer, Dropbox, OpenAI, DeepL
- **Media Processing**: FFmpeg, MP3 manipulation libraries
- **Testing**: Pytest for unit and integration tests